File Coverage

blib/lib/Net/Friends.pm
Criterion Covered Total %
statement 22 67 32.8
branch 1 12 8.3
condition 1 5 20.0
subroutine 6 12 50.0
pod 3 4 75.0
total 33 100 33.0


line stmt bran cond sub pod time code
1             package Net::Friends;
2              
3 1     1   27969 use 5.008;
  1         4  
  1         38  
4 1     1   6 use strict;
  1         2  
  1         31  
5 1     1   4 use warnings;
  1         6  
  1         38  
6 1     1   6 use Carp;
  1         1  
  1         190  
7 1     1   5073 use IO::Socket::INET;
  1         29501  
  1         8  
8              
9             require Exporter;
10              
11             our @ISA = qw(Exporter);
12              
13             our %EXPORT_TAGS = ( 'all' => [ qw( query report ) ] );
14              
15             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
16              
17             our @EXPORT = qw( ); # none by default
18              
19             our $VERSION = '1.03';
20              
21 0     0 1 0 sub Version { $VERSION }
22              
23             sub new {
24 1     1 0 12 my ($class, $host, $port);
25              
26 1         2 $class = shift;
27              
28 1 50       5 ($host = shift) || croak "Hostname must be specified in call to new.";
29              
30 1   50     8 $port = shift || 50123;
31              
32 1         14 my $self = {host => $host, port => $port, others => {}, name => 'Query',
33             lat => '90.000000', lon => '0.000000', speed => 0, dir => 0,
34             last_update => 0, last_report => 0, max_update_freq => 60,
35             id => 'queryqueryqueryqueryqu'};
36              
37 1         3 bless $self, $class;
38              
39 1         3 return $self;
40             }
41              
42             # makes sure update isn't called more than once per max_update_freq seconds
43             sub _maybe_update {
44 0     0     my $self = shift;
45              
46 0 0         if ($self->{last_update} + $self->{max_update_freq} > time) {
47 0           return; # updated too recently
48             }
49 0           $self->_update;
50             }
51              
52             # give our position and get positions of others
53             sub _update {
54 0     0     my $self = shift;
55              
56 0           $self->{last_update} = time;
57              
58 0           my $sock = IO::Socket::INET->new(PeerAddr => $self->{host},
59             PeerPort => $self->{port}, Proto => 'udp');
60              
61 0           send $sock, (join ' ', ('POS:', $self->{id}, $self->{name}, $self->{lat},
62             $self->{lon}, $self->{last_report}, $self->{speed}, $self->{dir})), 0;
63              
64 0           my %friends = ();
65              
66 0           my $val;
67              
68 0   0       do {
69 0           recv $sock, $val, 1024, 0;
70 0           chomp $val;
71 0 0         if ($val =~ m/^POS:\s+(\S{22})\s+(\S+)\s+([\d\.-]+)\s+([\d\.-]+)\s+
72             (\d+)\s+(\d+)\s+(\d+)/x) {
73 0           my %entry;
74 0           %entry = ();
75 0           $entry{'name'} = $2;
76 0 0         next if ($entry{'id'} eq 'queryqueryqueryqueryqu'); # skip lookups
77 0           $entry{'lat'} = $3;
78 0           $entry{'lon'} = $4;
79 0           $entry{'time'} = $5;
80 0           $entry{'speed'} = $6;
81 0           $entry{'dir'} = $7;
82 0           $friends{$2} = \%entry;
83             }
84             } while ($val ne '$END:$' && $val ne '');
85              
86 0           $self->{others} = \%friends;
87             }
88              
89             # internally and remotely update our position information
90             sub report {
91 0     0 1   my $self = shift;
92 0           while (@_) { # push named parameters into object
93 0           my $key = shift;
94 0           $self->{$key} = shift;
95             }
96 0           $self->{last_report} = time;
97              
98             # set the 'id' randomly if it's still queryqueryqueryquery
99 0 0         if ($self->{id} eq 'queryqueryqueryqueryqu') {
100 0           $self->{id} = $self->_random_id;
101             }
102              
103 0           $self->_update;
104             }
105              
106             sub _random_id {
107 0     0     my @chars = ('A' .. 'Z', 'a' .. 'z', 0, 1 .. 9);
108 0           my @slice;
109 0           foreach (1 .. 22) {
110 0           push @slice, int rand @chars;
111             }
112 0           return join '', @chars[@slice];
113             }
114              
115             # get last known position information about us and others
116             sub query {
117 0     0 1   my $self = shift;
118 0           my $who = shift;
119            
120 0           $self->_maybe_update;
121            
122 0 0         if (defined $who) {
123 0           return $self->{others}->{$who}
124             } else {
125 0           return $self->{others}
126             }
127             }
128              
129             1;
130             __END__