File Coverage

lib/UR/Service/RPC/Server.pm
Criterion Covered Total %
statement 39 47 82.9
branch 7 14 50.0
condition n/a
subroutine 7 7 100.0
pod 3 3 100.0
total 56 71 78.8


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