File Coverage

blib/lib/Net/Snarl.pm
Criterion Covered Total %
statement 15 55 27.2
branch 0 28 0.0
condition 0 12 0.0
subroutine 5 11 45.4
pod 3 3 100.0
total 23 109 21.1


line stmt bran cond sub pod time code
1             ## no critic
2             package Net::Snarl;
3             {
4             $Net::Snarl::VERSION = '1.09'; # TRIAL
5             }
6             ## use critic
7              
8 1     1   13111 use strict;
  1         1  
  1         23  
9 1     1   3 use warnings;
  1         1  
  1         25  
10              
11 1     1   562 use IO::Socket;
  1         15963  
  1         3  
12 1     1   337 use Carp;
  1         1  
  1         38  
13              
14             =head1 NAME
15              
16             Net::Snarl - Snarl network protocol
17              
18             =head1 VERSION
19              
20             version 1.09
21              
22             =cut
23              
24 1     1   458 use Readonly;
  1         2851  
  1         535  
25             Readonly my $SNARL_PORT => 9887;
26             Readonly my $SNARL_PROTO_VERSION => '1.1';
27              
28             =head1 SYNOPSIS
29              
30             use Net::Snarl;
31              
32             # connect to localhost and register Net::Snarl application
33             my $snarl = Net::Snarl->register('Net::Snarl');
34             $snarl->add_class('Test'); # add Test notification class
35             $snarl->notify('Test', 'Hello', 'World', 5); # show hello world for 5 seconds
36              
37             =head1 DESCRIPTION
38              
39             A simple interface to send Snarl notifications across the network. Snarl must
40             be running on the target machine.
41              
42             =cut
43              
44             sub _send {
45 0     0     my ($self, %param) = @_;
46              
47             my $data = 'type=SNP#?version=' . $SNARL_PROTO_VERSION . '#?' .
48 0           join('#?', map { "$_=$param{$_}" } keys %param);
  0            
49              
50 0           $self->{socket}->print("$data\x0d\x0a");
51 0           return $self->_recv;
52             }
53              
54             sub _recv {
55 0     0     my ($self) = @_;
56              
57 0           my $data = $self->{socket}->getline();
58 0           chomp $data;
59              
60 0           my ($header, $version, $code, $desc, @rest) = split '/', $data;
61              
62 0 0         die "Unexpected response: $data" unless $header eq 'SNP';
63              
64             # hackishly disregard responses above 300
65 0 0         if ($code >= 300) {
66 0           push @{$self->{queue}}, [$code, $desc, @rest];
  0            
67 0           return $self->_recv;
68             }
69              
70 0           return $code, $desc, @rest;
71             }
72              
73             =head1 INTERFACE
74              
75             =head2 register($application, $host, $port)
76              
77             Connects to Snarl and register an application. Host defaults to localhost and
78             port defaults to C<$Net::Snarl::SNARL_PORT>.
79              
80             =cut
81              
82             sub register {
83 0     0 1   my ($class, $application, $host, $port) = @_;
84              
85 0 0         croak 'Cannot call register as an instance method' if ref $class;
86 0 0         croak 'Application name required' unless $application;
87              
88 0 0 0       my $socket = IO::Socket::INET->new(
      0        
89             PeerAddr => $host || 'localhost',
90             PeerPort => $port || $SNARL_PORT,
91             Proto => 'tcp',
92             ) or die "Unable to create socket: $!";
93              
94 0           my $self = bless { socket => $socket, application => $application }, $class;
95              
96 0           my ($result, $text) = $self->_send(
97             action => 'register',
98             app => $application,
99             );
100              
101 0 0         die "Unable to register: $text" if $result;
102              
103 0           return $self;
104             }
105              
106             =head2 add_class($class, $title)
107              
108             Registers a notification class with your application. Title is the optional
109             friendly name for the class.
110              
111             =cut
112              
113             sub add_class {
114 0     0 1   my ($self, $class, $title) = @_;
115              
116 0 0         croak 'Cannot call add_class as a class method' unless ref $self;
117 0 0         croak 'Class name required' unless $class;
118              
119             my ($result, $text) = $self->_send(
120             action => 'add_class',
121             app => $self->{application},
122 0   0       class => $class,
123             title => $title || $class,
124             );
125              
126 0 0         die "Unable to add class: $text" if $result;
127              
128 0           return 1;
129             }
130              
131             =head2 notify($class, $title, $text, $timeout, $icon)
132              
133             Displays a notification of the specified class. Timeout defaults to 0 (sticky)
134             and icon defaults to nothing.
135              
136             =cut
137              
138             sub notify {
139 0     0 1   my ($self, $class, $title, $text, $timeout, $icon) = @_;
140              
141 0 0         croak 'Cannot call notify as a class method' unless ref $self;
142 0 0         croak 'Class name required' unless $class;
143 0 0         croak 'Title required' unless $title;
144 0 0         croak 'Text required' unless $text;
145              
146             my ($result, $rtext) = $self->_send(
147             action => 'notification',
148             app => $self->{application},
149 0   0       class => $class,
      0        
150             title => $title,
151             text => $text,
152             timeout => $timeout || 0,
153             icon => $icon || '',
154             );
155              
156 0 0         die "Unable to send notification: $rtext" if $result;
157              
158 0           return 1;
159             }
160              
161             sub DESTROY {
162 0     0     my ($self) = @_;
163              
164             $self->_send(
165             action => 'unregister',
166             app => $self->{application},
167 0           );
168              
169 0           return;
170             }
171              
172             =head1 BUGS
173              
174             Please report and bugs or feature requests on GitHub
175             L
176              
177             =head1 TODO
178              
179             Later versions of Snarl report interactions with the notifications back to the
180             socket. Currently these are stored in a private queue. Eventually, I will
181             expose an interface for triggering callbacks on these events but that will most
182             likely require threading so I'm a little reluctant to implement it.
183              
184             =head1 AUTHOR
185              
186             Alan Berndt, C<< >>
187              
188             =head1 LICENSE AND COPYRIGHT
189              
190             Copyright 2013 Alan Berndt.
191              
192             This program is free software; you can redistribute it and/or modify it under
193             the terms of either: the GNU General Public License as published by the Free
194             Software Foundation; or the Artistic License.
195              
196             See http://dev.perl.org/licenses/ for more information.
197              
198              
199             =cut
200              
201             1; # End of Net::Snarl