perlsky is a Perl 5 implementation of an AT Protocol Personal Data Server.
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

Cache repeated repo resolution within requests

alice 9f139292 aa7b206a

+63 -6
+38 -5
lib/ATProto/PDS/API/Util.pm
··· 53 53 } 54 54 55 55 sub resolve_did_account ($c, $did) { 56 - my $account = $c->store->get_account_by_did($did); 57 - return $account if $account; 58 56 my $target = lc($did // q()); 59 57 $target =~ s/%3a/:/ig; 58 + my $cache = $c->can('stash') ? ($c->stash('resolve_did_account_cache') || {}) : {}; 59 + return $cache->{$target} if exists $cache->{$target}; 60 + 61 + my $account = $c->store->get_account_by_did($did); 62 + if ($account) { 63 + $cache->{$target} = $account if $c->can('stash'); 64 + $c->stash(resolve_did_account_cache => $cache) if $c->can('stash'); 65 + return $account; 66 + } 67 + 60 68 for my $row (@{ $c->store->list_accounts }) { 61 69 my $candidate = lc($row->{did} // q()); 62 70 $candidate =~ s/%3a/:/ig; 63 - return $row if $candidate eq $target; 71 + if ($candidate eq $target) { 72 + if ($c->can('stash')) { 73 + $cache->{$target} = $row; 74 + $c->stash(resolve_did_account_cache => $cache); 75 + } 76 + return $row; 77 + } 78 + } 79 + if ($c->can('stash')) { 80 + $cache->{$target} = undef; 81 + $c->stash(resolve_did_account_cache => $cache); 64 82 } 65 83 return undef; 66 84 } 67 85 68 86 sub resolve_repo ($c, $repo) { 69 87 return undef unless defined $repo && length $repo; 88 + my $cache = $c->can('stash') ? ($c->stash('resolve_repo_cache') || {}) : {}; 89 + my $cache_key = lc($repo); 90 + return $cache->{$cache_key} if exists $cache->{$cache_key}; 91 + 70 92 if ($repo !~ /\Adid:/i) { 71 93 my $normalized = normalize_handle($repo, $c->config_value('service_handle_domain', 'localhost')); 72 - return $c->store->get_account_by_handle($repo) 94 + my $account = $c->store->get_account_by_handle($repo) 73 95 || (defined($normalized) ? $c->store->get_account_by_handle($normalized) : undef); 96 + if ($c->can('stash')) { 97 + $cache->{$cache_key} = $account; 98 + $cache->{ lc($normalized) } = $account if defined $normalized && length $normalized; 99 + $c->stash(resolve_repo_cache => $cache); 100 + } 101 + return $account; 74 102 } 75 - return resolve_did_account($c, $repo); 103 + my $account = resolve_did_account($c, $repo); 104 + if ($c->can('stash')) { 105 + $cache->{$cache_key} = $account; 106 + $c->stash(resolve_repo_cache => $cache); 107 + } 108 + return $account; 76 109 } 77 110 78 111 sub subscription_start_seq ($c, %args) {
+25 -1
t/api-util.t
··· 28 28 29 29 sub get_account_by_handle { 30 30 my ($self, $handle) = @_; 31 + $self->{get_account_by_handle_calls}{$handle}++; 31 32 return $self->{accounts_by_handle}{$handle}; 32 33 } 33 34 34 35 sub get_account_by_did { 35 36 my ($self, $did) = @_; 37 + $self->{get_account_by_did_calls}{$did}++; 36 38 return $self->{accounts_by_did}{$did}; 37 39 } 38 40 39 41 sub list_accounts { 40 42 my ($self) = @_; 43 + $self->{list_accounts_calls}++; 41 44 return $self->{list_accounts} // []; 42 45 } 43 46 } ··· 59 62 my ($self, $key, $default) = @_; 60 63 return exists $self->{config}{$key} ? $self->{config}{$key} : $default; 61 64 } 65 + 66 + sub stash { 67 + my ($self, @args) = @_; 68 + $self->{stash} //= {}; 69 + return $self->{stash}{$args[0]} if @args == 1; 70 + if (@args == 2) { 71 + $self->{stash}{$args[0]} = $args[1]; 72 + return $self; 73 + } 74 + die 'unsupported stash arity'; 75 + } 62 76 } 63 77 64 78 is_deeply( ··· 86 100 is(resolve_repo($c, 'alice.test')->{did}, 'did:plc:alice', 'resolve_repo finds handles directly'); 87 101 is(resolve_repo($c, 'Alice.Test')->{did}, 'did:plc:alice', 'resolve_repo normalizes mixed-case handles'); 88 102 is(resolve_repo($c, 'did:plc:alice')->{handle}, 'alice.test', 'resolve_repo finds plain DIDs directly'); 89 - is(resolve_did_account($c, 'did%3Aplc%3Aalice')->{handle}, 'alice.test', 'resolve_did_account accepts percent-encoded DIDs'); 90 103 is(resolve_repo($c, undef), undef, 'resolve_repo returns undef for empty input'); 104 + is(resolve_repo($c, 'alice.test')->{did}, 'did:plc:alice', 'repeat resolve_repo handle lookup still resolves'); 105 + is($store->{get_account_by_handle_calls}{'alice.test'}, 1, 'repeat resolve_repo handle lookup reuses the request cache'); 106 + 107 + $store->{list_accounts_calls} = 0; 108 + my $encoded_c = ApiUtilTestContext->new($store, config => { 109 + service_handle_domain => 'test', 110 + }); 111 + is(resolve_did_account($encoded_c, 'did%3Aplc%3Aalice')->{handle}, 'alice.test', 'resolve_did_account accepts percent-encoded DIDs'); 112 + is(resolve_did_account($encoded_c, 'did%3Aplc%3Aalice')->{handle}, 'alice.test', 'repeat resolve_did_account still resolves percent-encoded DIDs'); 113 + is($store->{get_account_by_did_calls}{'did%3Aplc%3Aalice'}, 1, 'repeat percent-encoded DID lookup avoids another exact DID miss'); 114 + is($store->{list_accounts_calls}, 1, 'repeat percent-encoded DID lookup reuses the request cache'); 91 115 92 116 done_testing;