File Coverage

blib/lib/PAUSE/Permissions/MetaCPAN.pm
Criterion Covered Total %
statement 18 73 24.6
branch 0 18 0.0
condition 0 8 0.0
subroutine 6 9 66.6
pod 2 2 100.0
total 26 110 23.6


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