| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Respite::Base; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# Respite::Base - base class for Respite related modules that can be used from a server or commandline |
|
4
|
|
|
|
|
|
|
|
|
5
|
5
|
|
|
5
|
|
122075
|
use strict; |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
176
|
|
|
6
|
5
|
|
|
5
|
|
21
|
use warnings; |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
245
|
|
|
7
|
5
|
|
|
5
|
|
24
|
use base 'Respite::Common'; # Default _configs and config |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
2355
|
|
|
8
|
5
|
|
|
5
|
|
2042
|
use autouse 'Respite::Validate' => qw(validate); |
|
|
5
|
|
|
|
|
4055
|
|
|
|
5
|
|
|
|
|
41
|
|
|
9
|
5
|
|
|
5
|
|
359
|
use Scalar::Util qw(blessed weaken); |
|
|
5
|
|
|
|
|
11
|
|
|
|
5
|
|
|
|
|
294
|
|
|
10
|
5
|
|
|
5
|
|
39
|
use Time::HiRes (); |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
91
|
|
|
11
|
5
|
|
|
5
|
|
14
|
use Throw qw(throw); |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
26
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $max_recurse = 10; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
13
|
0
|
|
sub SHARE {} |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
###----------------------------------------------------------------### |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub run_method { |
|
20
|
0
|
|
|
0
|
0
|
0
|
my ($self, $meth, $args, $extra) = @_; |
|
21
|
0
|
|
0
|
|
|
0
|
my $meta = $self->api_meta || {}; |
|
22
|
0
|
0
|
|
|
|
0
|
my $begin = $meta->{'log_prefix'} ? Time::HiRes::time() : undef; |
|
23
|
0
|
|
|
|
|
0
|
$meth =~ tr|/.-|___|; |
|
24
|
0
|
0
|
|
|
|
0
|
throw "Cannot call method", {class => ref($self), meth => $meth} if $self->_restrict($meth); |
|
25
|
0
|
|
0
|
|
|
0
|
my $code = $self->find_method($meth) || throw "Invalid Respite method", {class => ref($self), method => $meth}; |
|
26
|
0
|
|
|
|
|
0
|
my $utf8 = $meta->{'utf8_encoded'}; |
|
27
|
0
|
|
0
|
|
|
0
|
my $enc = $utf8 && (!ref($utf8) || $utf8->{$meth}); |
|
28
|
0
|
|
0
|
|
|
0
|
my $trp = $self->{'transport'} || ''; |
|
29
|
0
|
0
|
|
|
|
0
|
if ($enc) { # consistently handle args from json, form, or commandline |
|
30
|
0
|
0
|
|
|
|
0
|
_encode_utf8_recurse($args) if $trp eq 'json'; |
|
31
|
|
|
|
|
|
|
} else { |
|
32
|
0
|
0
|
0
|
|
|
0
|
_decode_utf8_recurse($args) if $trp && $trp ne 'json'; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
0
|
|
0
|
|
|
0
|
my $resp = eval { $self->$code($args, $extra) } || do { |
|
35
|
|
|
|
|
|
|
my $resp = $@; |
|
36
|
|
|
|
|
|
|
$resp = eval { throw 'Trouble dispatching', {method => $meth, msg => $resp} } || $@ if !ref($resp) || !$resp->{'error'}; |
|
37
|
|
|
|
|
|
|
warn $resp if $trp ne 'cmdline'; |
|
38
|
|
|
|
|
|
|
$resp; |
|
39
|
|
|
|
|
|
|
}; |
|
40
|
|
|
|
|
|
|
$self->log_request({ |
|
41
|
|
|
|
|
|
|
method => $meth, |
|
42
|
|
|
|
|
|
|
request => $args, |
|
43
|
|
|
|
|
|
|
response => $resp, |
|
44
|
|
|
|
|
|
|
api_ip => $self->{'api_ip'}, |
|
45
|
|
|
|
|
|
|
api_brand => $self->{'api_brand'}, |
|
46
|
|
|
|
|
|
|
remote_ip => $self->{'remote_ip'}, |
|
47
|
|
|
|
|
|
|
remote_user => $self->{'remote_user'}, |
|
48
|
|
|
|
|
|
|
admin_user => $self->{'admin_user'}, |
|
49
|
0
|
0
|
|
|
|
0
|
caller => $self->{'caller'}, |
|
50
|
|
|
|
|
|
|
elapsed => (Time::HiRes::time() - $begin), |
|
51
|
|
|
|
|
|
|
}) if $begin; |
|
52
|
0
|
0
|
0
|
|
|
0
|
_decode_utf8_recurse($resp) if ref($resp) eq 'HASH' && exists($resp->{'_utf8_encoded'}) ? delete($resp->{'_utf8_encoded'}) : $enc; |
|
|
|
0
|
|
|
|
|
|
|
53
|
0
|
|
|
|
|
0
|
return $resp; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub _restrict { |
|
57
|
0
|
|
|
0
|
|
0
|
my ($class, $meth) = @_; |
|
58
|
0
|
0
|
|
|
|
0
|
return 0 if __PACKAGE__->SUPER::can($meth); # any of the inherited methods from Respite::Base are not Respite methods |
|
59
|
0
|
|
|
|
|
0
|
return $meth =~ /^_/; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub AUTOLOAD { |
|
63
|
31
|
|
|
31
|
|
8987
|
my $self = shift; |
|
64
|
31
|
50
|
|
|
|
160
|
my $meth = $Respite::Base::AUTOLOAD =~ /::(\w+)$/ ? $1 : throw "Invalid method", {method => $Respite::Base::AUTOLOAD}; |
|
65
|
31
|
50
|
|
|
|
68
|
throw "Self was not passed while looking up method", {method => $meth, trace => 1} if ! blessed $self; |
|
66
|
31
|
|
50
|
|
|
118
|
local $self->{'_autoload'}->{$meth} = ($self->{'_autoload'}->{$meth} || 0) + 1; |
|
67
|
31
|
50
|
|
|
|
78
|
throw "Recursive method lookup", {class => ref($self), method => $meth} if $self->{'_autoload'}->{$meth} > $max_recurse; |
|
68
|
31
|
|
66
|
|
|
67
|
my $code = $self->find_method($meth) || throw "Invalid Respite method during AUTOLOAD", {class => ref($self), method => $meth}, 1; |
|
69
|
30
|
|
|
|
|
64
|
return $self->$code(@_); |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
0
|
|
|
sub DESTROY {} |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub api_meta { |
|
75
|
9
|
|
|
9
|
0
|
9
|
my $self = shift; |
|
76
|
9
|
|
|
|
|
13
|
my $ref = ref $self; |
|
77
|
5
|
|
|
5
|
|
4229
|
no strict 'refs'; ## no critic |
|
|
5
|
|
|
|
|
6
|
|
|
|
5
|
|
|
|
|
8360
|
|
|
78
|
9
|
50
|
|
|
|
8
|
return ${"${ref}::api_meta"} if ${"${ref}::api_meta"}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
9
|
|
|
|
|
26
|
|
|
79
|
9
|
0
|
33
|
|
|
30
|
return $self->{'api_meta'} ||= ($ref eq __PACKAGE__ ? throw "No api_meta defined", {class => $self, type => 'no_meta'} : {}); |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
0
|
|
|
0
|
1
|
0
|
sub api_preload { shift->find_method; return 1 } |
|
|
0
|
|
|
|
|
0
|
|
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub _encode_utf8_recurse { |
|
85
|
0
|
|
|
0
|
|
0
|
my $d = shift; |
|
86
|
0
|
0
|
|
|
|
0
|
if (UNIVERSAL::isa($d, 'HASH')) { |
|
|
|
0
|
|
|
|
|
|
|
87
|
0
|
0
|
0
|
|
|
0
|
for my $k (keys %$d) { my $v = $d->{$k}; (ref $v) ? _encode_utf8_recurse($v) : $v and utf8::is_utf8($v) and utf8::encode($d->{$k}) } |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
88
|
|
|
|
|
|
|
} elsif (UNIVERSAL::isa($d, 'ARRAY')) { |
|
89
|
0
|
0
|
0
|
|
|
0
|
for my $v (@$d) { (ref $v) ? _encode_utf8_recurse($v) : $v and utf8::is_utf8($v) and utf8::encode($v) } |
|
|
0
|
0
|
|
|
|
0
|
|
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub _decode_utf8_recurse { |
|
94
|
0
|
|
|
0
|
|
0
|
my $d = shift; |
|
95
|
0
|
|
0
|
|
|
0
|
my $seen = shift || {}; |
|
96
|
0
|
0
|
|
|
|
0
|
return if $seen->{$d}++; |
|
97
|
0
|
0
|
|
|
|
0
|
if (UNIVERSAL::isa($d, 'HASH')) { |
|
|
|
0
|
|
|
|
|
|
|
98
|
0
|
0
|
0
|
|
|
0
|
for my $k (keys %$d) { my $v = $d->{$k}; (ref $v) ? _decode_utf8_recurse($v, $seen) : $v and !utf8::is_utf8($v) and utf8::decode($d->{$k}) } |
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
99
|
|
|
|
|
|
|
} elsif (UNIVERSAL::isa($d, 'ARRAY')) { |
|
100
|
0
|
0
|
0
|
|
|
0
|
for my $v (@$d) { (ref $v) ? _decode_utf8_recurse($v, $seen) : $v and !utf8::is_utf8($v) and utf8::decode($v) } |
|
|
0
|
0
|
|
|
|
0
|
|
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
###----------------------------------------------------------------### |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub validate_args { |
|
107
|
3
|
|
|
3
|
1
|
2528
|
my ($self, $args, $val_hash) = @_; |
|
108
|
3
|
|
33
|
|
|
33
|
my $sub = (caller(my $n = 1))[3]; $sub = (caller ++$n)[3] while $sub eq '(eval)' || $sub =~ /::validate_args$/; |
|
|
3
|
|
|
|
|
22
|
|
|
109
|
3
|
50
|
|
|
|
9
|
if (! $val_hash) { |
|
110
|
3
|
50
|
|
|
|
24
|
my $code = $self->can("${sub}__meta") or throw "Could not find meta information.", {method => $sub}, 1; |
|
111
|
3
|
|
|
|
|
8
|
my $meta = $code->($self); |
|
112
|
3
|
|
33
|
|
|
23
|
$val_hash = $meta->{'args'} || throw "Missing args in meta information", {method => $sub}, 1; |
|
113
|
3
|
0
|
0
|
|
|
12
|
if (my $ra = $meta->{'requires_admin'} and (eval { $self->api_meta->{'enforce_requires_admin'} } || do { my $e = $@; die $e if $e && (!ref($e) || $e->{'type'} ne 'no_meta'); 0 })) { |
|
|
|
|
33
|
|
|
|
|
|
114
|
0
|
0
|
|
|
|
0
|
$self->require_admin(ref($ra) eq 'CODE' ? $ra->($self, $sub, $args) : ref($ra) eq 'HASH' ? $ra : {$ra => 1, method => $sub}); |
|
|
|
0
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
} |
|
117
|
3
|
|
100
|
|
|
11
|
my $error_hash = validate($args || {}, $val_hash) || return 1; |
|
118
|
|
|
|
|
|
|
throw "Failed to validate args", { |
|
119
|
|
|
|
|
|
|
errors => $error_hash, |
|
120
|
|
|
|
|
|
|
type => 'validation', |
|
121
|
1
|
50
|
|
|
|
9
|
($args->{'_no_trace'} ? () : (trace => 1)), |
|
122
|
|
|
|
|
|
|
}, 1; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
1
|
0
|
|
1
|
1
|
3
|
sub api_ip { $_[0]->{'api_ip'} || ($_[0]->{'base'} ? $_[0]->{'base'}->api_ip : throw "Missing api_ip",0,1) } |
|
|
|
50
|
|
|
|
|
|
|
126
|
1
|
50
|
33
|
1
|
1
|
7
|
sub api_brand { $_[0]->{'api_brand'} || ($_[0]->{'base'} ? $_[0]->{'base'}->api_brand : ($_[0]->is_local && $ENV{'PROV'}) || throw "Missing api_brand",0,1) } |
|
|
|
50
|
|
|
|
|
|
|
127
|
0
|
0
|
|
0
|
1
|
0
|
sub remote_ip { $_[0]->{'remote_ip'} || ($_[0]->{'base'} ? $_[0]->{'base'}->remote_ip : throw "Missing remote_ip",0,1) } |
|
|
|
0
|
|
|
|
|
|
|
128
|
0
|
0
|
|
0
|
1
|
0
|
sub remote_user { $_[0]->{'remote_user'} || ($_[0]->{'base'} ? $_[0]->{'base'}->remote_user : throw "Missing remote_user",0,1) } |
|
|
|
0
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
|
|
130
|
0
|
0
|
|
0
|
1
|
0
|
sub admin_user { $_[0]->{'admin_user'} || ($_[0]->{'base'} ? $_[0]->{'base'}->admin_user : throw "Not authenticated",0,1) } |
|
|
|
0
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
|
|
132
|
1
|
50
|
|
1
|
1
|
20
|
sub transport { $_[0]->{'transport'} || ($_[0]->{'base'} ? $_[0]->{'base'}->transport : '') } |
|
|
|
50
|
|
|
|
|
|
|
133
|
0
|
0
|
0
|
0
|
1
|
0
|
sub is_server { exists($_[0]->{'is_server'}) ? $_[0]->{'is_server'} : ($_[0]->{'base'} && $_[0]->{'base'}->is_server) } |
|
134
|
|
|
|
|
|
|
|
|
135
|
0
|
0
|
|
0
|
1
|
0
|
sub is_authed { eval { shift->admin_user } ? 1 : 0 } |
|
|
0
|
|
|
|
|
0
|
|
|
136
|
|
|
|
|
|
|
|
|
137
|
1
|
50
|
|
1
|
1
|
4
|
sub is_local { $_[0]->transport =~ /^(?:cmdline|gui)$/ ? 1 : 0 } |
|
138
|
0
|
|
|
0
|
0
|
0
|
sub who { shift->remote_user } |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub base { |
|
141
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
142
|
0
|
0
|
|
|
|
0
|
if (! $self->{'base'}) { |
|
143
|
0
|
0
|
|
|
|
0
|
throw "Could not find base when called_from_base",0,1 if $self->{'called_from_base'}; |
|
144
|
0
|
|
0
|
|
|
0
|
my $class = $self->base_class || throw "Could not find a base_class when accessing base from direct source",0,1; |
|
145
|
0
|
0
|
|
|
|
0
|
return $self if ref($self) eq $class; |
|
146
|
0
|
|
|
|
|
0
|
(my $file = "$class.pm") =~ s|::|/|g; |
|
147
|
0
|
0
|
|
|
|
0
|
eval { require $file } || throw "Could not load base_class", {msg => $@, class => $class}; |
|
|
0
|
|
|
|
|
0
|
|
|
148
|
0
|
|
|
|
|
0
|
$self->{'base'} = $class->new({$self->SHARE, map {$_ => $self->{$_}} qw(api_ip api_brand remote_ip remote_user admin_user is_server)}); |
|
|
0
|
|
|
|
|
0
|
|
|
149
|
|
|
|
|
|
|
} |
|
150
|
0
|
|
|
|
|
0
|
return $self->{'base'}; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
0
|
|
|
0
|
1
|
0
|
sub base_class { shift->{'base_class'} } |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
###----------------------------------------------------------------### |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub find_method { |
|
158
|
40
|
|
|
40
|
0
|
111
|
my ($self, $meth, $opt) = @_; |
|
159
|
40
|
|
50
|
|
|
89
|
my $meta = $self->api_meta || {}; |
|
160
|
|
|
|
|
|
|
|
|
161
|
40
|
100
|
100
|
|
|
199
|
my $cache = $meta->{'_cache'}->{ref($self)} ||= {%{ $meta->{'methods'} || {} }}; |
|
|
13
|
|
|
|
|
74
|
|
|
162
|
40
|
100
|
|
|
|
157
|
if ($meth) { |
|
|
|
50
|
|
|
|
|
|
|
163
|
31
|
100
|
|
|
|
88
|
return $cache->{$meth} if exists $cache->{$meth}; |
|
164
|
8
|
50
|
|
|
|
12
|
return $cache->{$meth} if exists $cache->{$meth}; |
|
165
|
8
|
|
|
|
|
9
|
my $code; |
|
166
|
8
|
50
|
33
|
|
|
29
|
return $cache->{$meth} = $code if $code = $self->can($meth) and $code ne \&{__PACKAGE__."::$meth"}; |
|
|
0
|
|
|
|
|
0
|
|
|
167
|
8
|
100
|
|
|
|
40
|
return $cache->{$meth} = $code if $code = $self->can("__$meth"); |
|
168
|
|
|
|
|
|
|
} elsif (!$cache->{'--load--'}->{'builtin'}++) { |
|
169
|
5
|
|
|
5
|
|
42
|
no strict 'refs'; ## no critic |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
3309
|
|
|
170
|
9
|
|
|
|
|
24
|
my @search = ref($self); |
|
171
|
9
|
|
|
|
|
25
|
while (my $pkg = shift @search) { |
|
172
|
16
|
100
|
|
|
|
30
|
unshift @search, @{"${pkg}::ISA"} if $pkg ne __PACKAGE__; |
|
|
7
|
|
|
|
|
26
|
|
|
173
|
16
|
|
|
|
|
17
|
for my $meth (keys %{"${pkg}::"}) { |
|
|
16
|
|
|
|
|
101
|
|
|
174
|
466
|
100
|
|
|
|
433
|
next if ! defined &{"${pkg}::$meth"}; |
|
|
466
|
|
|
|
|
867
|
|
|
175
|
320
|
100
|
|
|
|
588
|
next if ($pkg eq __PACKAGE__) ? $meth !~ /^__/ : defined &{__PACKAGE__."::$meth"}; |
|
|
32
|
100
|
|
|
|
105
|
|
|
176
|
54
|
50
|
|
|
|
85
|
next if $pkg =~ /^_[a-z]/; |
|
177
|
54
|
50
|
100
|
|
|
186
|
next if $meth !~ /__meta$/ && $meth !~ /^__/ && !defined &{"${pkg}::${meth}__meta"}; |
|
|
9
|
|
66
|
|
|
29
|
|
|
178
|
54
|
|
|
|
|
97
|
(my $name = $meth) =~ s/^__//; |
|
179
|
54
|
|
66
|
|
|
186
|
$cache->{$name} ||= "${pkg}::$meth"; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
|
|
184
|
14
|
|
|
|
|
23
|
foreach my $type ('namespaces', 'lib_dirs') { |
|
185
|
24
|
|
100
|
|
|
47
|
my $NS = $meta->{$type} || next; |
|
186
|
15
|
100
|
66
|
|
|
40
|
$NS = $cache->{'--load--'}->{'lib_dirs'} ||= $self->_load_lib_dir($NS) if $type eq 'lib_dirs'; |
|
187
|
15
|
|
|
|
|
46
|
foreach my $ns (sort keys %$NS) { |
|
188
|
27
|
|
|
|
|
36
|
my $opt = $NS->{$ns}; |
|
189
|
27
|
100
|
|
|
|
65
|
$opt = {match => $opt} if ref($opt) ne 'HASH'; |
|
190
|
27
|
50
|
|
|
|
411
|
my $name = !$meth ? undef : ($meth !~ /^${ns}_*(\w+)$/) ? next : $opt->{'full_name'} ? $meth : $1; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
191
|
21
|
|
33
|
|
|
97
|
my $pkg = $opt->{'pkg'} || $opt->{'package'} || do { (my $pkg = $ns) =~ s/(?:_|\b)([a-z])/\u$1/g; $pkg }; |
|
192
|
21
|
100
|
|
|
|
150
|
if (! $pkg->can('new')) { |
|
193
|
1
|
|
|
|
|
4
|
(my $file = "$pkg.pm") =~ s|::|/|g; |
|
194
|
1
|
50
|
33
|
|
|
3
|
if (! eval { require ($opt->{'file'} ||= $file) }) { |
|
|
1
|
|
|
|
|
887
|
|
|
195
|
0
|
|
|
|
|
0
|
warn "Failed to load listed module $pkg ($opt->{'file'}): $@"; |
|
196
|
0
|
|
|
|
|
0
|
next; |
|
197
|
|
|
|
|
|
|
} |
|
198
|
1
|
50
|
|
|
|
248
|
$INC{$file} = $INC{$opt->{'file'}} if $opt->{'file'} ne $file; |
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# TODO - faster lookup if we know the method |
|
202
|
21
|
|
100
|
|
|
47
|
my $qr = $opt->{'match'} || 1; |
|
203
|
21
|
100
|
66
|
|
|
139
|
$qr = ($qr eq '1' || $qr eq '*') ? qr{.} : qr{^$qr} if $qr && !ref $qr; |
|
|
|
50
|
33
|
|
|
|
|
|
204
|
5
|
|
|
5
|
|
52
|
no strict 'refs'; ## no critic |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
7479
|
|
|
205
|
21
|
|
|
|
|
32
|
for my $meth (keys %{"${pkg}::"}) { |
|
|
21
|
|
|
|
|
109
|
|
|
206
|
111
|
100
|
|
|
|
126
|
next if ! defined &{"${pkg}::$meth"}; |
|
|
111
|
|
|
|
|
238
|
|
|
207
|
53
|
50
|
|
|
|
83
|
next if ($pkg eq __PACKAGE__) ? $meth !~ /^__/ : defined &{__PACKAGE__."::$meth"}; |
|
|
53
|
100
|
|
|
|
179
|
|
|
208
|
49
|
50
|
|
|
|
103
|
next if $meth =~ /^_[a-z]/; |
|
209
|
49
|
50
|
33
|
|
|
283
|
next if $qr && $meth !~ $qr; |
|
210
|
49
|
100
|
100
|
|
|
149
|
next if $meth !~ /__meta$/ && $meth !~ /^__/ && !defined &{"${pkg}::${meth}__meta"}; |
|
|
26
|
|
100
|
|
|
98
|
|
|
211
|
33
|
|
|
|
|
65
|
(my $name = $meth) =~ s/^__//; |
|
212
|
33
|
50
|
33
|
|
|
368
|
$name = "${ns}_${name}" if !$opt->{'full_name'} && $name !~ /^\Q$ns\E_/; |
|
213
|
33
|
|
100
|
|
|
103
|
my $dt = $opt->{'dispatch_type'} || $meta->{'dispatch_type'} || 'new'; |
|
214
|
4
|
|
|
4
|
|
5
|
$cache->{$name} ||= ($dt eq 'new') ? sub { my $base = shift; $pkg->new({base => $base, called_from_base => 1, $base->SHARE})->$meth(@_) } |
|
|
4
|
|
|
|
|
10
|
|
|
215
|
|
|
|
|
|
|
: ($dt eq 'morph') ? sub { |
|
216
|
1
|
|
|
1
|
|
2
|
my $base = shift; |
|
217
|
1
|
|
|
|
|
3
|
my $prev = ref $base; |
|
218
|
1
|
|
33
|
|
|
6
|
local $base->{'base'} = $base->{'base'} || $base; weaken($base->{'base'}); |
|
|
1
|
|
|
|
|
2
|
|
|
219
|
1
|
50
|
|
|
|
1
|
my $resp; my $ok = eval { bless $base, $pkg; $resp = $base->$meth(@_); 1 }; my $err = $@; bless $base, $prev; die $err if ! $ok; return $resp; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
8
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
12
|
|
|
|
1
|
|
|
|
|
4
|
|
|
220
|
|
|
|
|
|
|
} |
|
221
|
13
|
|
66
|
13
|
|
17
|
: ($dt eq 'cache') ? sub { my $base = shift; ($base->{$pkg} ||= do { my $s = $pkg->new({base => $base, $base->SHARE}); weaken $s->{'base'}; $s })->$meth(@_) } |
|
|
13
|
|
|
|
|
40
|
|
|
|
7
|
|
|
|
|
69
|
|
|
|
7
|
|
|
|
|
35
|
|
|
|
7
|
|
|
|
|
25
|
|
|
222
|
33
|
50
|
66
|
|
|
252
|
: throw "Unknown dispatch_type", {dispatch_type => $dt}, 1; |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
} |
|
224
|
21
|
50
|
66
|
|
|
127
|
if (($meta->{'allow_nested'} || $opt->{'allow_nested'}) && defined(&{"${pkg}::api_meta"}) && $pkg->can('find_method')) { |
|
|
2
|
|
66
|
|
|
13
|
|
|
|
|
|
66
|
|
|
|
|
|
225
|
2
|
|
|
|
|
5
|
my $c2 = $pkg->new({$self->SHARE})->find_method; # TODO - pass them in |
|
226
|
2
|
|
|
|
|
10
|
for my $meth (keys %$c2) { |
|
227
|
18
|
50
|
33
|
|
|
54
|
next if $qr && $meth !~ $qr; |
|
228
|
18
|
50
|
33
|
|
|
54
|
$name = (!$opt->{'full_name'} && $meth !~ /^\Q$ns\E_/) ? "${ns}_${meth}" : $meth; |
|
229
|
18
|
|
|
|
|
37
|
$cache->{$name} = $c2->{$meth}; |
|
230
|
|
|
|
|
|
|
} |
|
231
|
|
|
|
|
|
|
} |
|
232
|
21
|
50
|
66
|
|
|
86
|
return $cache->{$meth} if $meth && $cache->{$meth}; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
} |
|
235
|
|
|
|
|
|
|
|
|
236
|
10
|
100
|
|
|
|
26
|
return $cache->{$meth} = 0 if $meth; |
|
237
|
9
|
|
|
|
|
38
|
return $cache; |
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub _load_lib_dir { |
|
241
|
3
|
|
|
3
|
|
7
|
my ($self, $NS) = @_; |
|
242
|
3
|
50
|
|
|
|
10
|
if ($NS eq '1') { |
|
243
|
0
|
0
|
|
|
|
0
|
throw "lib_dirs cannot be 1 when accessed from Respite::Base directly" if ref($self) eq __PACKAGE__; |
|
244
|
0
|
|
|
|
|
0
|
(my $file = ref($self).".pm") =~ s|::|/|g; |
|
245
|
0
|
0
|
0
|
|
|
0
|
(my $dir = $INC{$file} || '') =~ s|\.pm$|| or throw "Could not determine library path location for lib_dirs", {file => $file}; |
|
246
|
0
|
|
|
|
|
0
|
$NS = {$dir => {pkg_prefix => ref($self)}}; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
3
|
|
|
|
|
3
|
my %h; |
|
249
|
3
|
|
|
|
|
6
|
foreach my $dir (keys %$NS) { |
|
250
|
3
|
50
|
|
|
|
214
|
opendir my $dh, $dir or do { warn "Failed to opendir $dir: $!"; next }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
251
|
3
|
|
|
|
|
11
|
my $opt = $NS->{$dir}; |
|
252
|
3
|
50
|
|
|
|
14
|
$opt = {match => $opt} if ref($opt) ne 'HASH'; |
|
253
|
3
|
50
|
|
|
|
9
|
my $prefix = $opt->{'pkg_prefix'} ? "$opt->{'pkg_prefix'}::" : ''; |
|
254
|
3
|
|
|
|
|
80
|
foreach my $sub (readdir $dh) { |
|
255
|
12
|
100
|
|
|
|
75
|
next if $sub !~ /^([a-zA-Z]\w*)\.pm$/; # TODO - possibly handle dirs |
|
256
|
3
|
|
|
|
|
8
|
my $pkg = $1; |
|
257
|
3
|
50
|
33
|
|
|
19
|
next if $opt->{'pkg_exclude'} && $pkg =~ $opt->{'pkg_exclude'}; |
|
258
|
3
|
|
|
|
|
34
|
(my $name = $pkg) =~ s/(?: (?<=[a-z])(?=[A-Z]) | (?<=[A-Z])(?=[A-Z][a-z]) )/_/xg; # FooBar => Foo_Bar, RespiteUser => Respite_User |
|
259
|
3
|
|
|
|
|
25
|
$h{lc $name} = {%$opt, pkg => "$prefix$pkg", file => "$dir/$sub"}; |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
} |
|
262
|
3
|
|
|
|
|
13
|
return \%h; |
|
263
|
|
|
|
|
|
|
} |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
###----------------------------------------------------------------### |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
sub __methods__meta { |
|
268
|
3
|
|
33
|
3
|
|
9
|
my $class = ref($_[0]) || $_[0]; |
|
269
|
|
|
|
|
|
|
return { |
|
270
|
3
|
|
|
|
|
22
|
desc => "Return a list of all known $class methods. Optionally return all meta information as well", |
|
271
|
|
|
|
|
|
|
args => { |
|
272
|
|
|
|
|
|
|
meta => {desc => 'If true, returns all meta information for the method instead of just the description'}, |
|
273
|
|
|
|
|
|
|
method => {desc => 'If passed will be used to filter the available methods - can contain * as a wildcard'}, |
|
274
|
|
|
|
|
|
|
}, |
|
275
|
|
|
|
|
|
|
resp => {methods => 'hashref of available method/description pairs. Will return method/metainfo pairs if meta => 1 is passed.'}, |
|
276
|
|
|
|
|
|
|
}; |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
sub __methods { |
|
280
|
2
|
|
|
2
|
|
4
|
my ($self, $args) = @_; |
|
281
|
5
|
|
|
5
|
|
38
|
no strict 'refs'; ## no critic |
|
|
5
|
|
|
|
|
10
|
|
|
|
5
|
|
|
|
|
2679
|
|
|
282
|
2
|
|
33
|
|
|
5
|
my $pkg = ref($self) || $self; |
|
283
|
2
|
|
|
|
|
3
|
my %m; |
|
284
|
2
|
50
|
|
|
|
5
|
my $qr = !$args->{'method'} ? undef : do { (my $p = $args->{'method'}) =~ s/\*/.*/g; qr/^$p$/i }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
285
|
2
|
|
|
|
|
5
|
my $meths = $self->find_method(); # will load all |
|
286
|
2
|
|
|
|
|
6
|
foreach my $meth (keys %$meths) { |
|
287
|
36
|
100
|
|
|
|
87
|
next if $meth !~ /^(\w+)__meta$/; |
|
288
|
14
|
|
|
|
|
20
|
my $name = $1; |
|
289
|
14
|
50
|
33
|
|
|
24
|
next if $qr && $name !~ $qr; |
|
290
|
14
|
|
66
|
|
|
16
|
my $meta = eval { $self->$meth() } || do { (my $err = $@ || '') =~ s/ at \/.*//s; {desc => "Not documented".($err ? ": $err" : '')} }; |
|
291
|
14
|
0
|
33
|
|
|
74
|
next if $ENV{'REQUEST_METHOD'} && $meta->{'no_listing'}; |
|
292
|
14
|
50
|
|
|
|
33
|
$m{$name} = $args->{'meta'} ? $meta : $meta->{'no_listing'} ? "(Not listed in Web Respite) $meta->{'desc'}" : $meta->{'desc'}; |
|
|
|
50
|
|
|
|
|
|
|
293
|
14
|
|
|
|
|
34
|
delete $meta->{'api_enum'}; |
|
294
|
|
|
|
|
|
|
} |
|
295
|
2
|
|
|
|
|
9
|
return {methods => \%m}; |
|
296
|
|
|
|
|
|
|
} |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
sub __hello__meta { |
|
299
|
|
|
|
|
|
|
return { |
|
300
|
3
|
|
|
3
|
|
30
|
desc => 'Basic call to test connection', |
|
301
|
|
|
|
|
|
|
args => {test_auth => {validate_if => 'test_auth', enum => ['', 0, 1], desc => 'Optional - if passed it will require authentication'}}, |
|
302
|
|
|
|
|
|
|
resp => { |
|
303
|
|
|
|
|
|
|
server_time => "Server epoch time", |
|
304
|
|
|
|
|
|
|
args => "Echo of the passed in args", |
|
305
|
|
|
|
|
|
|
api_ip => 'IP', |
|
306
|
|
|
|
|
|
|
api_brand => 'Which brand is in use (if any)', |
|
307
|
|
|
|
|
|
|
admin_user => 'Returned if test_auth is passed', |
|
308
|
|
|
|
|
|
|
}, |
|
309
|
|
|
|
|
|
|
}; |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub __hello { |
|
313
|
1
|
|
|
1
|
|
3
|
my ($self, $args) = @_; |
|
314
|
1
|
50
|
|
|
|
3
|
sleep $args->{'sleep'} if $args->{'sleep'}; |
|
315
|
1
|
50
|
|
|
|
3
|
throw delete($args->{'fail'}), {args => $args} if $args->{'fail'}; |
|
316
|
|
|
|
|
|
|
return { |
|
317
|
|
|
|
|
|
|
args => $args, |
|
318
|
|
|
|
|
|
|
server_time => time(), |
|
319
|
|
|
|
|
|
|
api_ip => $self->api_ip, |
|
320
|
|
|
|
|
|
|
api_brand => eval { $self->api_brand } || undef, |
|
321
|
|
|
|
|
|
|
($args->{'test_auth'} && $self->require_admin ? ( |
|
322
|
|
|
|
|
|
|
admin_user => $self->admin_user, |
|
323
|
1
|
50
|
50
|
|
|
5
|
token => $self->{'new_token'}, |
|
|
|
|
33
|
|
|
|
|
|
324
|
|
|
|
|
|
|
) : ()), |
|
325
|
|
|
|
|
|
|
}; |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
1; |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
###----------------------------------------------------------------### |
|
331
|
|
|
|
|
|
|
__END__ |