File Coverage

lib/Net/EGTS/Simple.pm
Criterion Covered Total %
statement 57 118 48.3
branch 0 30 0.0
condition n/a
subroutine 19 25 76.0
pod 5 5 100.0
total 81 178 45.5


line stmt bran cond sub pod time code
1 1     1   73722 use utf8;
  1         5  
  1         5  
2              
3             package Net::EGTS::Simple;
4 1     1   43 use Mouse;
  1         1  
  1         3  
5              
6 1     1   274 use Carp;
  1         1  
  1         50  
7 1     1   406 use IO::Socket::INET;
  1         15818  
  1         4  
8              
9 1     1   611 use Net::EGTS::Util;
  1         3  
  1         65  
10 1     1   268 use Net::EGTS::Types;
  1         89  
  1         28  
11 1     1   328 use Net::EGTS::Codes;
  1         58  
  1         212  
12              
13 1     1   309 use Net::EGTS::Packet;
  1         73  
  1         24  
14 1     1   4 use Net::EGTS::Record;
  1         2  
  1         22  
15 1     1   4 use Net::EGTS::SubRecord;
  1         1  
  1         15  
16              
17 1     1   259 use Net::EGTS::Packet::Appdata;
  1         77  
  1         26  
18 1     1   285 use Net::EGTS::SubRecord::Auth::DispatcherIdentity;
  1         51  
  1         24  
19 1     1   298 use Net::EGTS::SubRecord::Teledata::PosData;
  1         63  
  1         27  
20              
21             =head1 NAME
22              
23             Net::EGTS::Simple - simple blocking socket transport
24              
25             =cut
26              
27             # Timeout, sec. (0 .. 255)
28 1     1   4 use constant EGTS_SL_NOT_AUTH_TO => 6;
  1         1  
  1         39  
29              
30             # Response timeout
31 1     1   3 use constant EGTS_TL_RESPONSE_TO => 5;
  1         1  
  1         34  
32             # Resend attempts if timeout EGTS_TL_RESPONSE_TO
33 1     1   3 use constant EGTS_TL_RESEND_ATTEMPTS => 3;
  1         2  
  1         42  
34             # Connection timeout
35 1     1   4 use constant EGTS_TL_RECONNECT_TO => 30;
  1         1  
  1         518  
36              
37             has host => is => 'ro', isa => 'Str', required => 1;
38             has port => is => 'ro', isa => 'Int', required => 1;
39              
40             has timeout => is => 'ro', isa => 'Int', default => EGTS_TL_RECONNECT_TO;
41             has attempts => is => 'ro', isa => 'Int', default => EGTS_TL_RESEND_ATTEMPTS;
42             has rtimeout => is => 'ro', isa => 'Int', default => EGTS_TL_RESPONSE_TO;
43              
44             has did => is => 'ro', isa => 'Int', required => 1;
45             has type => is => 'ro', isa => 'Int', default => 0;
46             has description => is => 'ro', isa => 'Maybe[Str]';
47              
48             has socket =>
49             is => 'ro',
50             isa => 'Object',
51             lazy => 1,
52             clearer => 'socket_drop',
53             builder => sub {
54             my ($self) = @_;
55             my $socket = IO::Socket::INET->new(
56             PeerAddr => $self->host,
57             PeerPort => $self->port,
58             Proto => 'tcp',
59             Timeout => $self->timeout,
60             );
61             die "Open socket error: $!\n" unless $socket;
62             return $socket;
63             }
64             ;
65              
66             =head2 reset
67              
68             Reset internal counters for new connection
69              
70             =cut
71              
72             sub reset {
73 0     0 1   $Net::EGTS::Packet::PID = 0;
74 0           $Net::EGTS::Record::RN = 0;
75             }
76              
77             =head2 connect
78              
79             =cut
80              
81             sub connect {
82 0     0 1   my ($self) = @_;
83 0 0         $self->disconnect if $self->socket;
84 0           $self->reset;
85 0           return $self;
86             }
87              
88             =head2 disconnect
89              
90             =cut
91              
92             sub disconnect {
93 0     0 1   my ($self) = @_;
94 0           $self->socket->shutdown(2);
95 0           $self->socket_drop;
96 0           $self->reset;
97 0           return $self;
98             }
99              
100             # Get packet response
101             sub _response {
102 0     0     my ($self, $packet) = @_;
103              
104 0           my $response;
105 0           my $start = time;
106 0           while (1) {
107 0           my $in = '';
108 0           my $res = sysread $self->socket, $in, 65536;
109 0 0         return 'Recv error' unless defined $res;
110              
111 0           my ($p) = Net::EGTS::Packet->stream( \$in );
112 0 0         if( $p ) {
113 0 0         next unless $p->PT eq EGTS_PT_RESPONSE;
114 0 0         next unless $p->RPID eq $packet->PID;
115              
116 0           $response = $p;
117 0           last;
118             }
119              
120 0 0         last if time > $start + $self->rtimeout;
121             }
122 0 0         return 'Response timeout' unless $response;
123              
124 0           my $record = $response->records->[0];
125 0 0         return 'No records' unless $record;
126              
127 0           my $subrecord = $record->subrecords->[0];
128 0 0         return 'No subrecords' unless $subrecord;
129 0 0         return "Error on packet @{[ $subrecord->CRN ]}"
  0            
130             unless $subrecord->RST eq EGTS_PC_OK;
131              
132 0           return $self;
133             }
134              
135             =head2 auth
136              
137             Athorization
138              
139             =cut
140              
141             sub auth {
142 0     0 1   my ($self) = @_;
143 1     1   6 use bytes;
  1         1  
  1         3  
144              
145 0           my $result;
146 0           for(my $i = $self->attempts; $i > 0; $i-- ) {
147 0           my $auth = Net::EGTS::Packet::Appdata->new(
148             PRIORITY => 0b11,
149             SDR => Net::EGTS::Record->new(
150             SST => EGTS_AUTH_SERVICE,
151             RST => EGTS_AUTH_SERVICE,
152             RD => Net::EGTS::SubRecord::Auth::DispatcherIdentity->new(
153             DT => $self->type,
154             DID => $self->did,
155             DSCR => $self->description,
156             )->encode,
157             )->encode,
158             );
159 0 0         unless( my $res = print {$self->socket} $auth->encode ) {
  0            
160 0           return 'Send error';
161             }
162              
163 0 0         unless( my $res = $self->_response($auth) ) {
164 0           $result = $res;
165 0           next;
166             }
167              
168 0           $result = $self;
169 0           last;
170             }
171              
172 0           return $result;
173             }
174              
175             =head2 posdata $data
176              
177             Send telemetry data
178              
179             =cut
180              
181             sub posdata {
182 0     0 1   my ($self, $data) = @_;
183 1     1   162 use bytes;
  1         2  
  1         2  
184              
185 0           my $oid = delete $data->{id};
186 0 0         croak "id required" unless $oid;
187              
188 0           my $result;
189 0           for(my $i = $self->attempts; $i > 0; $i-- ) {
190              
191 0           my $pd = Net::EGTS::Packet::Appdata->new(
192             PRIORITY => 0b11,
193             SDR => Net::EGTS::Record->new(
194             OID => $oid,
195             SST => EGTS_TELEDATA_SERVICE,
196             RST => EGTS_TELEDATA_SERVICE,
197             RD => Net::EGTS::SubRecord::Teledata::PosData->new(
198             %$data,
199             )->encode,
200             )->encode,
201             );
202 0 0         unless( my $res = print {$self->socket} $pd->encode ) {
  0            
203 0           return 'Send error';
204             }
205              
206 0 0         unless( my $res = $self->_response($pd) ) {
207 0           $result = $res;
208 0           next;
209             }
210              
211 0           $result = $self;
212 0           last;
213             }
214              
215 0           return $result;
216             }
217              
218             __PACKAGE__->meta->make_immutable();