File Coverage

blib/lib/PAUSE/Permissions/MetaCPAN.pm
Criterion Covered Total %
statement 20 84 23.8
branch 0 18 0.0
condition 0 8 0.0
subroutine 7 10 70.0
pod 2 2 100.0
total 29 122 23.7


line stmt bran cond sub pod time code
1             package PAUSE::Permissions::MetaCPAN v1.0.0;
2 1     1   112756 use v5.24;
  1         4  
3 1     1   6 use warnings;
  1         3  
  1         66  
4 1     1   6 use experimental qw(lexical_subs signatures);
  1         3  
  1         8  
5              
6             our $TRIAL = 0;
7              
8 1     1   229 use Carp ();
  1         4  
  1         58  
9 1     1   910 use HTTP::Tiny 0.055;
  1         70953  
  1         64  
10 1     1   1147 use IO::Socket::SSL 1.42;
  1         60094  
  1         6  
11 1     1   887 use JSON::PP ();
  1         15337  
  1         897  
12              
13 0     0 1   sub new ($class, %args) {
  0            
  0            
  0            
14 0   0       my $http = $args{http} || do {
15             my $agent = sprintf "%s/%s", $class =~ s/::/-/gr, $class->VERSION;
16             HTTP::Tiny->new(verify_SSL => 1, agent => $agent);
17             };
18 0   0       my $url = $args{url} || "https://fastapi.metacpan.org/v1/permission/_search";
19 0           bless { http => $http, url => $url }, $class;
20             }
21              
22 0     0 1   sub get ($self, %args) {
  0            
  0            
  0            
23              
24 0 0 0       Carp::croak "either author or modules is required" if !$args{author} && !$args{modules};
25              
26 0 0         if (my $author = $args{author}) {
27 0           my $hit = $self->_query(%args);
28 0           my %hit = (owner => [], co_maintainer => []);
29 0           for my $module ($hit->@*) {
30 0 0         if ($module->{owner} eq $author) {
31 0           push @{$hit{owner}}, $module;
  0            
32             } else {
33 0           push @{$hit{co_maintainer}}, $module;
  0            
34             }
35             }
36 0           return \%hit;
37             }
38              
39 0           my @hit;
40 0           my @module = @{$args{modules}}; # must copy
  0            
41             # elasticsearch may return "too_many_clauses: maxClauseCount is set to 1024"
42 0           while (my @m = splice @module, 0, 1024) {
43 0           my $hit = $self->_query(modules => \@m);
44 0           push @hit, $hit->@*;
45             }
46 0           my %hit;
47 0           for my $module (@{$args{modules}}) {
  0            
48 0           my ($found) = grep { $_->{module_name} eq $module} @hit;
  0            
49 0           $hit{$module} = $found;
50             }
51 0           return \%hit;
52             }
53              
54 0     0     sub _query ($self, %args) {
  0            
  0            
  0            
55              
56 0           my %bool;
57 0 0         if (my $author = $args{author}) {
    0          
58             $bool{should} = [
59 0           { term => { owner => $author } },
60             { term => { co_maintainers => $author } },
61             ];
62 0           $bool{minimum_should_match} = 1;
63             } elsif (my $modules = $args{modules}) {
64             $bool{should} = [
65 0           map +{ term => { module_name => $_ } }, $modules->@*
66             ];
67 0           $bool{minimum_should_match} = 1;
68             }
69              
70 0           my $from = 0;
71 0           my $times = 0;
72 0           my @hit;
73 0           while (1) {
74 0           $times++;
75 0 0         Carp::croak "too many request for $self->{url}" if $times > 6;
76 0           my $payload = {
77             query => { bool => \%bool },
78             sort => [ { module_name => 'asc' } ],
79             size => 2000,
80             from => $from,
81             };
82 0           my $body = JSON::PP::encode_json $payload;
83             my $res = $self->{http}->post($self->{url}, {
84 0           'content-type' => 'application/json',
85             'content-length' => length $body,
86             content => $body,
87             });
88 0 0         if ($res->{status} == 404) {
    0          
89 0           last;
90             } elsif (!$res->{success}) {
91 0           Carp::croak "$res->{status} $res->{reason}, $self->{url}\n$res->{content}";
92             }
93 0           my $json = JSON::PP::decode_json $res->{content};
94 0           my $total = $json->{hits}{total};
95 0           push @hit, map $_->{_source}, @{$json->{hits}{hits}};
  0            
96 0 0         last if @hit >= $total;
97 0           $from = @hit;
98             }
99 0           \@hit;
100             }
101              
102             1;
103             __END__