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 |