| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package UR::Service::RPC::Server; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
35
|
use UR; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
6
|
|
|
4
|
1
|
|
|
1
|
|
416
|
use IO::Select; |
|
|
1
|
|
|
|
|
1300
|
|
|
|
1
|
|
|
|
|
44
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
4
|
use strict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
15
|
|
|
7
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
|
1
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
|
337
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = "0.46"; # UR $VERSION; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# We're going to be essentially reimplementing an Event queue here. :( |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
class UR::Service::RPC::Server { |
|
13
|
|
|
|
|
|
|
has => [ |
|
14
|
|
|
|
|
|
|
'select' => { is => 'IO::Select' }, |
|
15
|
|
|
|
|
|
|
timeout => { is => 'Float', default_value => undef }, |
|
16
|
|
|
|
|
|
|
executers => { is => 'HASH', doc => 'maps file handles to the UR::Service::RPC::Executer objects we are working with' }, |
|
17
|
|
|
|
|
|
|
], |
|
18
|
|
|
|
|
|
|
}; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub create { |
|
21
|
1
|
|
|
1
|
1
|
100
|
my($class, %args) = @_; |
|
22
|
|
|
|
|
|
|
|
|
23
|
1
|
50
|
|
|
|
3
|
unless ($args{'executers'}) { |
|
24
|
1
|
|
|
|
|
3
|
$args{'executers'} = {}; |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
1
|
50
|
|
|
|
3
|
unless ($args{'select'}) { |
|
28
|
1
|
|
|
|
|
2
|
my @fh = map { $_->fh } values %{$args{'executers'}}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
1
|
|
|
|
|
3
|
|
|
29
|
1
|
|
|
|
|
7
|
$args{'select'} = IO::Select->new(@fh); |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
1
|
|
|
|
|
15
|
my $self = $class->SUPER::create(%args); |
|
33
|
|
|
|
|
|
|
|
|
34
|
1
|
|
|
|
|
5
|
return $self; |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub add_executer { |
|
38
|
1
|
|
|
1
|
1
|
335
|
my($self,$executer,$fh) = @_; |
|
39
|
|
|
|
|
|
|
|
|
40
|
1
|
50
|
|
|
|
4
|
unless ($fh) { |
|
41
|
1
|
50
|
|
|
|
5
|
if ($executer->can('fh')) { |
|
42
|
1
|
|
|
|
|
18
|
$fh = $executer->fh; |
|
43
|
|
|
|
|
|
|
} else { |
|
44
|
0
|
|
|
|
|
0
|
$self->error_message("Cannot determine file handle for RPC executer $executer"); |
|
45
|
0
|
|
|
|
|
0
|
return; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
|
|
49
|
1
|
|
|
|
|
4
|
$self->{'executers'}->{$fh} = $executer; |
|
50
|
1
|
|
|
|
|
4
|
$self->select->add($fh); |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub loop { |
|
54
|
6
|
|
|
6
|
1
|
216
|
my $self = shift; |
|
55
|
|
|
|
|
|
|
|
|
56
|
6
|
|
|
|
|
8
|
my $timeout; |
|
57
|
6
|
50
|
|
|
|
18
|
if (@_) { |
|
58
|
6
|
|
|
|
|
9
|
$timeout = shift; |
|
59
|
|
|
|
|
|
|
} else { |
|
60
|
0
|
|
|
|
|
0
|
$timeout = $self->timeout; |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
|
|
63
|
6
|
|
|
|
|
29
|
my @ready = $self->select->can_read($timeout); |
|
64
|
|
|
|
|
|
|
|
|
65
|
6
|
|
|
|
|
1001295
|
my $count = 0; |
|
66
|
6
|
|
|
|
|
16
|
foreach my $fh ( @ready ) { |
|
67
|
5
|
|
|
|
|
24
|
my $executer = $self->{'executers'}->{$fh}; |
|
68
|
5
|
50
|
|
|
|
29
|
unless ($executer) { |
|
69
|
0
|
|
|
|
|
0
|
$self->error_message("Cannot determine RPC executer for file handle $fh fileno ",$fh->fileno); |
|
70
|
0
|
|
|
|
|
0
|
return; |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
|
|
73
|
5
|
|
|
|
|
7
|
$count++; |
|
74
|
5
|
50
|
|
|
|
40
|
unless ($executer->execute($self) ) { |
|
75
|
|
|
|
|
|
|
# they told us they were done |
|
76
|
0
|
|
|
|
|
0
|
$self->select->remove($fh); |
|
77
|
0
|
|
|
|
|
0
|
delete $self->{'executers'}->{$fh}; |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
6
|
|
|
|
|
24
|
return $count; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
1; |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=pod |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=head1 NAME |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
UR::Service::RPC::Server - Class for implementing RPC servers |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my $executer = Some::Exec::Class->create(fh => $fh); |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
my $server = UR::Service::RPC::Server->create(); |
|
98
|
|
|
|
|
|
|
$server->add_executer($executer); |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
$server->loop(5); # Process messages for 5 seconds |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
The RPC server implementation isn't fleshed out very well yet, and may change |
|
105
|
|
|
|
|
|
|
in the future. |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head1 METHODS |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=over 4 |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=item add_executer |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
$server->add_executer($exec); |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
Incorporate a new UR::Service::RPC::Executer instance to this server. It |
|
116
|
|
|
|
|
|
|
adds the Executer's filehandle to its own internal IO::Select object. |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=item loop |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
$server->loop(); |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
$server->loop(0); |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
$server->loop($timeout); |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
Enter the Server's event loop for the given number of seconds. If the timeout |
|
127
|
|
|
|
|
|
|
is undef, it will stay in the loop forever. If the timeout is 0, it will make |
|
128
|
|
|
|
|
|
|
a single pass though the readable filehandles and call C on their |
|
129
|
|
|
|
|
|
|
Executer objects. |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
If the return value of an Executer's C method is false, that Executer's |
|
132
|
|
|
|
|
|
|
file handle is removed from the internal Select object. |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=back |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
UR::Service::RPC::Executer, UR::Service::RPC::Message |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=cut |