File Coverage

blib/lib/WebService/GrowthBook/FeatureRepository.pm
Criterion Covered Total %
statement 83 95 87.3
branch 6 8 75.0
condition 0 3 0.0
subroutine 17 20 85.0
pod 0 5 0.0
total 106 131 80.9


line stmt bran cond sub pod time code
1             package WebService::GrowthBook::FeatureRepository;
2 5     5   386295 use strict;
  5         13  
  5         244  
3 5     5   30 use warnings;
  5         10  
  5         273  
4 5     5   873 no indirect;
  5         2523  
  5         31  
5 5     5   381 use Scalar::Util qw(blessed);
  5         13  
  5         358  
6 5     5   1404 use Object::Pad;
  5         22130  
  5         34  
7 5     5   4755 use HTTP::Tiny;
  5         486562  
  5         441  
8 5     5   458 use Log::Any qw($log);
  5         9943  
  5         54  
9 5     5   3528 use Digest::MD5 qw(md5_base64);
  5         16  
  5         551  
10 5     5   3392 use Syntax::Keyword::Try;
  5         10017  
  5         37  
11 5     5   1607 use JSON::MaybeUTF8 qw(decode_json_utf8);
  5         23405  
  5         472  
12 5     5   3083 use WebService::GrowthBook::InMemoryFeatureCache;
  5         20  
  5         1251  
13              
14             our $VERSION = '0.003'; ## VERSION
15              
16             class WebService::GrowthBook::FeatureRepository {
17 0     0 0 0 field $http :param :writer //= HTTP::Tiny->new();
18 0         0 field $cache :param //= WebService::GrowthBook::InMemoryFeatureCache->singleton();
19 0     0 0 0 method set_cache($new_cache){
  0         0  
  0         0  
  0         0  
20 0 0 0     0 die "Invalid cache object $new_cache" unless blessed($new_cache) && $new_cache->isa('WebService::GrowthBook::AbstractFeatureCache');
21 0         0 $cache = $new_cache;
22             }
23              
24 0     0 0 0 method clear_cache(){
  0         0  
  0         0  
25 0         0 $cache->clear();
26             }
27 8     8 0 8653 method load_features($api_host, $client_key, $ttl = 60) {
  8         37  
  8         22  
  8         19  
  8         19  
  8         12  
28 8         32 my $key = get_cache_key($api_host, $client_key);
29 8         71 my $features = $cache->get($key);
30 8 100       30 if($features){
31 1         6 $log->debug("Features loaded from cache");
32 1         7 return $features;
33             }
34 7         29 $features = $self->_fetch_features($api_host, $client_key);
35 7 100       24 if($features){
36 2         16 $cache->set($key, $features, $ttl);
37 2         27 $log->debug("Features loaded from GrowthBook API, set in cache");
38             }
39              
40 7         117 return $features;
41             }
42              
43 7     7   16 method _fetch_features($api_host, $client_key){
  7         20  
  7         15  
  7         13  
  7         15  
44 7         28 my $decoded = $self->_fetch_and_decode($api_host, $client_key);
45              
46             # TODO decrypt here
47 7 100       70 if(exists $decoded->{features}){
48 2         10 return $decoded->{features};
49             }
50             else {
51 5         22 $log->warn("GrowthBook API response missing features");
52             return
53 5         237 }
54             }
55              
56 7     7   16 method _fetch_and_decode($api_host, $client_key){
  7         15  
  7         15  
  7         15  
  7         15  
57             try {
58             my $r = $self->_get($self->_get_features_url($api_host, $client_key));
59             if($r->{status} >= 400){
60             $log->warnf("Failed to fetch features, received status code %d", $r->{status});
61             return;
62             }
63             my $decoded = decode_json_utf8($r->{content});
64             return $decoded;
65             }
66 7         25 catch ($e){
67             $log->warnf("Failed to decode feature JSON from GrowthBook API: %s", $e);
68             }
69 2         246 return;
70             }
71 7     7   11 method _get($url){
  7         21  
  7         14  
  7         13  
72 7         29 my $headers = {
73             'Content-Type' => 'application/json',
74             };
75              
76 7         44 return $http->get($url, {headers => $headers});
77             }
78              
79 7     7   13 method _get_features_url($api_host, $client_key){
  7         18  
  7         18  
  7         14  
  7         12  
80 7         63 return "$api_host/api/features/$client_key";
81             }
82             }
83              
84 8     8 0 15 sub get_cache_key($api_host, $client_key){
  8         15  
  8         17  
  8         17  
85 8         69 return md5_base64($api_host . '::' . $client_key);
86             }
87             1;