File Coverage

lib/Net/EGTS/Simple.pm
Criterion Covered Total %
statement 86 99 86.8
branch 8 20 40.0
condition n/a
subroutine 22 25 88.0
pod 5 5 100.0
total 121 149 81.2


line stmt bran cond sub pod time code
1 2     2   148850 use utf8;
  2         12  
  2         9  
2              
3             package Net::EGTS::Simple;
4 2     2   59 use Mouse;
  2         2  
  2         14  
5              
6 2     2   528 use Carp;
  2         2  
  2         92  
7 2     2   784 use IO::Socket::INET;
  2         31086  
  2         8  
8              
9 2     2   1190 use Net::EGTS::Util;
  2         3  
  2         130  
10 2     2   536 use Net::EGTS::Types;
  2         249  
  2         62  
11 2     2   584 use Net::EGTS::Codes;
  2         123  
  2         431  
12              
13 2     2   606 use Net::EGTS::Packet;
  2         133  
  2         93  
14 2     2   12 use Net::EGTS::Record;
  2         3  
  2         41  
15 2     2   8 use Net::EGTS::SubRecord;
  2         2  
  2         31  
16              
17 2     2   691 use Net::EGTS::Packet::Appdata;
  2         126  
  2         52  
18 2     2   560 use Net::EGTS::SubRecord::Auth::DispatcherIdentity;
  2         147  
  2         54  
19 2     2   599 use Net::EGTS::SubRecord::Teledata::PosData;
  2         136  
  2         69  
20              
21             =head1 NAME
22              
23             Net::EGTS::Simple - simple socket transport
24              
25             =cut
26              
27             # Timeout, sec. (0 .. 255)
28 2     2   10 use constant EGTS_SL_NOT_AUTH_TO => 6;
  2         2  
  2         125  
29              
30             # Response timeout
31 2     2   9 use constant EGTS_TL_RESPONSE_ТО => 5;
  2         2  
  2         77  
32             # Resend attempts if timeout TL_RESPONSE_ТО
33 2     2   8 use constant EGTS_TL_RESEND_ATTEMPTS => 3;
  2         1  
  2         59  
34             # Connection timeout
35 2     2   8 use constant EGTS_TL_RECONNECT_ТО => 30;
  2         1  
  2         1001  
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_ТО;
41             has attempt => is => 'ro', isa => 'Int', default => EGTS_TL_RESEND_ATTEMPTS;
42             has rtimeout => is => 'ro', isa => 'Int', default => EGTS_TL_RESPONSE_ТО;
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 0 $Net::EGTS::Packet::PID = 0;
74 0         0 $Net::EGTS::Record::RN = 0;
75             }
76              
77             =head2 connect
78              
79             =cut
80              
81             sub connect {
82 0     0 1 0 my ($self) = @_;
83 0 0       0 $self->disconnect if $self->socket;
84 0         0 $self->reset;
85 0         0 return $self;
86             }
87              
88             =head2 disconnect
89              
90             =cut
91              
92             sub disconnect {
93 0     0 1 0 my ($self) = @_;
94 0         0 $self->socket->shutdown(2);
95 0         0 $self->socket_drop;
96 0         0 $self->reset;
97 0         0 return $self;
98             }
99              
100             # Get packet response
101             sub _response {
102 3     3   5 my ($self, $packet) = @_;
103              
104 3         2 my $response;
105 3         4 my $start = time;
106 3         3 while (1) {
107 3         4 my $in = '';
108 3         8 $self->socket->recv($in, 65536);
109              
110 3         24 my ($p) = Net::EGTS::Packet->stream( \$in );
111 3 50       20 if( $p ) {
112 3 50       8 next unless $p->PT eq EGTS_PT_RESPONSE;
113 3 50       9 next unless $p->RPID eq $packet->PID;
114              
115 3         3 $response = $p;
116 3         6 last;
117             }
118              
119 0 0       0 last if time > $start + $self->rtimeout;
120             }
121 3 50       4 return 'Response timeout' unless $response;
122              
123 3         14 my $record = $response->records->[0];
124 3 50       5 return 'No records' unless $record;
125              
126 3         10 my $subrecord = $record->subrecords->[0];
127 3 50       5 return 'No subrecords' unless $subrecord;
128 3 50       7 return "Error on packet @{[ $subrecord->CRN ]}"
  0         0  
129             unless $subrecord->RST eq EGTS_PC_OK;
130              
131 3         32 return $self;
132             }
133              
134             =head2 auth
135              
136             Athorization
137              
138             =cut
139              
140             sub auth {
141 1     1 1 2316 my ($self) = @_;
142 2     2   33 use bytes;
  2         3  
  2         5  
143              
144 1         25 my $auth = Net::EGTS::Packet::Appdata->new(
145             PRIORITY => 0b11,
146             SDR => Net::EGTS::Record->new(
147             SST => EGTS_AUTH_SERVICE,
148             RST => EGTS_AUTH_SERVICE,
149             RD => Net::EGTS::SubRecord::Auth::DispatcherIdentity->new(
150             DT => $self->type,
151             DID => $self->did,
152             DSCR => $self->description,
153             )->encode,
154             )->encode,
155             );
156 1         13 $self->socket->send( $auth->encode );
157              
158 1         7 return $self->_response($auth);
159             }
160              
161             =head2 posdata $data
162              
163             Send telemetry data
164              
165             =cut
166              
167             sub posdata {
168 2     2 1 6632 my ($self, $data) = @_;
169 2     2   219 use bytes;
  2         2  
  2         5  
170              
171 2         5 my $oid = delete $data->{id};
172 2 50       3 croak "id required" unless $oid;
173              
174 2         19 my $pd = Net::EGTS::Packet::Appdata->new(
175             PRIORITY => 0b11,
176             SDR => Net::EGTS::Record->new(
177             OID => $oid,
178             SST => EGTS_TELEDATA_SERVICE,
179             RST => EGTS_TELEDATA_SERVICE,
180             RD => Net::EGTS::SubRecord::Teledata::PosData->new(
181             %$data,
182             )->encode,
183             )->encode,
184             );
185 2         23 $self->socket->send( $pd->encode );
186              
187 2         9 return $self->_response($pd);
188             }
189              
190             __PACKAGE__->meta->make_immutable();