File Coverage

blib/lib/Spread/Client.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Spread::Client;
2              
3 3     3   79581 use 5.006;
  3         11  
  3         134  
4 3     3   16 use strict;
  3         6  
  3         119  
5 3     3   34 use warnings;
  3         11  
  3         125  
6              
7 3     3   3906 use bytes;
  3         36  
  3         14  
8 3     3   1348 use Spread::Client::Constant ':all';
  0            
  0            
9             use Spread::Client::Frame;
10             use List::Util qw(reduce);
11             use Socket;
12              
13             our $VERSION = '0.03_02';
14              
15             sub connect {
16             my %args = @_;
17              
18             my ($port, $host) = split /@/, $args{spread_name};
19            
20             die "Bad/missing SPREAD NAME.\n"
21             unless defined $port;
22              
23             my $connect_class = $args{connect_class} ? "Spread::Client::Connection::$args{connect_class}"
24             : "Spread::Client::Connection::Sync";
25              
26             eval "require $connect_class";
27              
28             die $@
29             if $@;
30              
31             my $conn = $connect_class->new( @_ )
32             or die "Could not connect to spread daemon: $!\n";
33              
34             my $sock = $conn->sock;
35              
36             # In case connection class sets socket to non-blocking
37             # we will set this to non-blocking again below
38             unless( defined $sock->blocking( 1 ) ) {
39             die "could not set blocking on handle: $!\n";
40             }
41              
42             # CONNECT ROUTINE
43             unless( $conn->is_unix ) {
44              
45             my $addr = sockaddr_in($port, inet_aton( $host ));
46             connect( $sock, $addr)
47             or die "Could not connect to host: $host\n";
48             }
49              
50             # TODO revisit this at a later date
51             my $connect_message = build_connect_message( private_name => $args{private_name} || 0);
52            
53             # Send connect message
54             $conn->write( \$connect_message );
55            
56             # read buffer
57             my $buffer;
58              
59             # Get auth methods length, to find what auth methods we have available
60             $buffer = $conn->read( 1 );
61             my $authlen = ord( $$buffer );
62            
63             die "Bad authentication length: $authlen\n"
64             if $authlen == -1 or $authlen >= 128;
65            
66             # Get auth methods
67             my $auth_method = $conn->read( $authlen );
68            
69             # Send auth message
70             my $auth_method_message = build_auth_message( auth_method => $$auth_method );
71             $conn->write( \$auth_method_message );
72            
73             # Pull down accept and versions and grouplen
74             $buffer = $conn->read( 5 );
75            
76             my (@versions, $accept, $full_version);
77              
78             # Get accept
79             $accept = unpack('c', $$buffer);
80              
81             die "Did not get accept: $accept\n"
82             unless $accept == 1;
83             #
84              
85             $versions[0] = substr( $$buffer, 1, 1); # Major
86             $versions[1] = substr( $$buffer, 2, 1); # Minor
87             $versions[2] = substr( $$buffer, 3, 1); # Patch
88              
89             {
90             no warnings 'once';
91             $full_version = unpack('c', reduce { $a | $b } (@versions));
92             }
93              
94             die "Full version is a problem: $full_version\n"
95             if $full_version == -1;
96              
97             # Get private group info
98             # Get group length
99             my $grouplen = unpack('c', substr($$buffer, 4, 1));
100            
101             die "We had an issue with the group length\n"
102             if $grouplen == -1;
103              
104             # Get actual name private group name
105             $buffer = $conn->read( $grouplen );
106             my $private_group = unpack("a*", $$buffer);
107             $conn->private_group( $private_group );
108              
109             if( $conn->is_async ) {
110             $sock->blocking( 0 );
111             $conn->listen_for_messages;
112             $conn->session_connected( 1 );
113             }
114              
115             return $conn;
116             }
117              
118             sub receive {
119             my %args = @_;
120              
121             if( $args{conn}->is_async ) {
122              
123             $args{conn}->receive;
124              
125             unless( $args{conn}->message_callback ) {
126             return $args{conn}->get_queued_messages;
127             }
128             }
129             else {
130             my $buffer;
131            
132             # pull down message header
133             $buffer = $args{conn}->read( 48 );
134            
135             # define variables we need
136             my ($mess_type, $endian);
137            
138             # unpack header data
139             my ($service_type, $sender, $num_members, $hint, $data_len) = parse_message_header( $buffer );
140            
141             # Get group data
142             my $pull_bytes = $num_members * 32;
143             $buffer = $args{conn}->read( $pull_bytes );
144              
145             my $groups = parse_message_groups( $buffer, $num_members);
146            
147             # pull down message body
148             $buffer = $args{conn}->read( $data_len );
149            
150             my $message = parse_message_body( $buffer, $service_type);
151            
152             return ($service_type, $sender, $groups, $mess_type, $endian, $message);
153             }
154             }
155              
156             sub multicast {
157             my %args = @_;
158              
159             my $private_group = $args{conn}->private_group;
160              
161             my $multi_message = build_standard_message( type => $args{type} || DEFAULT_SEND_MESS,
162             from_group => $private_group,
163             to_groups => $args{groups},
164             data => $args{message},
165             );
166              
167             my $ret = $args{conn}->write( \$multi_message );
168              
169             return $ret;
170             }
171              
172             sub join {
173             my %args = @_;
174              
175             my $private_group = $args{conn}->private_group;
176              
177             my $join_message = build_standard_message( type => JOIN_MESS,
178             from_group => $private_group,
179             to_groups => $args{groups},
180             );
181              
182             my $ret = $args{conn}->write( \$join_message );
183              
184             return $ret;
185             }
186              
187             sub leave {
188             my %args = @_;
189              
190             my $private_group = $args{conn}->private_group;
191              
192             my $leave_message = build_standard_message( type => LEAVE_MESS,
193             from_group => $private_group,
194             to_groups => $args{groups},
195             );
196              
197             my $ret = $args{conn}->write( \$leave_message );
198              
199             return $ret;
200             }
201              
202             sub disconnect {
203             my %args = @_;
204              
205             my $private_group = $args{conn}->private_group;
206              
207             my $disconnect_message = build_standard_message( type => KILL_MESS,
208             from_group => $private_group,
209             to_groups => [ $private_group ],
210             );
211             # write close message to daemon
212             $args{conn}->write( \$disconnect_message );
213              
214             # close socket
215             $args{conn}->close();
216             }
217              
218             1;
219             __END__