File Coverage

blib/lib/Net/Analysis/Listener/Base.pm
Criterion Covered Total %
statement 41 74 55.4
branch 3 10 30.0
condition 0 5 0.0
subroutine 11 16 68.7
pod 2 9 22.2
total 57 114 50.0


line stmt bran cond sub pod time code
1             package Net::Analysis::Listener::Base;
2             # $Id: Base.pm 131 2005-10-02 17:24:31Z abworrall $
3              
4 1     1   762 use 5.008000;
  1         4  
  1         46  
5             our $VERSION = '0.01';
6 1     1   4 use strict;
  1         2  
  1         26  
7 1     1   5 use warnings;
  1         10  
  1         56  
8 1     1   6 use overload q("") => sub { $_[0]->as_string() }; # OO style stringify
  1     1   1  
  1         11  
  1         5  
9              
10 1     1   64 use Carp qw(carp croak);
  1         7  
  1         53  
11              
12 1     1   5 use Params::Validate qw(:all);
  1         2  
  1         1052  
13              
14             # {{{ POD
15              
16             =head1 NAME
17              
18             Net::Analysis::Listener::Base - base class for event listeners
19              
20             =head1 SYNOPSIS
21              
22             This module should be subclassed as follows:
23              
24             package Net::Analysis::Listener::MyThing;
25              
26             use base 'Net::Analysis::Listener::Base';
27              
28             sub event_listener {
29             my ($self, $args_hash) = @_;
30             ... do something ...
31              
32             if (event_is_exciting($args_hash)) {
33             $self->emit (name => 'my_event',
34             args => {what => 'listeners to this event will get'});
35             }
36             }
37              
38             =head1 DESCRIPTION
39              
40             This module is a virtual base class for Listeners. To create a new listener,
41             just subclass this, and add methods. If you want to listen to an event, create
42             a method with the name of that event - the dispatcher takes care of the rest.
43              
44             If you want to store state between events (such as a hash of open sessions),
45             stuff it into C<$self>. Any configuration for your listener will also be
46             exploded all over $<$self>, so take care. Subclasses can use anything in $self
47             they want, except the key '_', which contains private stuff used by the base
48             class.
49              
50             You can emit events if you like; if you add new types of event, take care not
51             to collide with existing ones (e.g. tcp_blah, http_blah). The best way to do
52             this is to select a prefix for your event names based on your protocol.
53              
54             =head1 INHERITED METHODS
55              
56             B, you don't need to implement them.
57             They're documented here for reference, so don't be put off - they can be safely
58             ignored :)
59              
60             =cut
61              
62             # }}}
63              
64             # These should not be overridden
65             # XXXX Create a DESTROY method that breaks all the circular refs.
66             # {{{ new
67              
68             # {{{ POD
69              
70             =head2 new (dispatcher => $obj [, config => $hash] [, pos => 'first|last'])
71              
72             Mandatory argument is the dispatcher object which will dispatch any events
73             that originate from this module, or any that subclass from it.
74              
75             Note that we immediately register this new object with the dispatcher; this
76             will create circular references.
77              
78             The config hash is optional. Standard key/val pairs are:
79              
80             * v => 0..3 (verbosity; 0==silent, 9==noisy)
81              
82             The pos parameter is optional. It specifies if the listener sould catch events
83             first, or last. Only one listener can be first, or last.
84              
85             The rest of the hash varies on a per-listener basis.
86              
87             The returned object has one reserved field: C<$self->{_}>. This is used for the
88             behind-the-scenes plumbing. All other fields in C<$self> are free for the
89             subclass to use.
90              
91             Note that the config hash is exploded over C<$self>; that is, C<$self->{v}>
92             will contain the verbosity value passed in via the config hash (or a
93             default, if no config is passed in.)
94              
95             =cut
96              
97             # }}}
98              
99             sub new {
100 1     1 1 905 my ($class) = shift;
101              
102 1         98 my %args = validate (@_, {
103             dispatcher => { can => 'emit_event' },
104             pos => { regex => qr/^(first|last)$/,
105             optional => 1},
106             config => { type => HASHREF,
107             default => {v => 0}, },
108             }
109             );
110              
111             # Place the dispatcher into our private subhash
112 1         14 my %h = ('_' => {dispatcher => $args{dispatcher}});
113              
114 1         5 my ($self) = bless (\%h, $class);
115              
116             # Allow the module to validate the configuration, if it wants
117 1         2 my $cnf = $self->validate_configuration (%{$args{config}});
  1         6  
118 1 50       6 if (! defined $cnf) {
119 0         0 carp "no configuration, despite default setting above ?";
120 0         0 return undef;
121             }
122              
123             # Explode the config all over self, provided we haven't already used it
124 1         2 foreach my $k (keys %{$cnf}) {
  1         5  
125 1 50       6 croak "bad config '$k': '$k' is reserved !\n" if (exists $h{$k});
126 1         3 $h{$k} = $cnf->{$k};
127             }
128              
129             # If a position was specified, put it where the dispatcher will look for it
130 1 50       7 $self->{pos} = $args{pos} if (exists $args{pos});
131              
132 1         6 $h{_}{dispatcher}->add_listener (listener => $self); # Circular ref joy
133              
134 1         5 return $self;
135             }
136              
137             # }}}
138             # {{{ emit
139              
140             =head2 emit (...)
141              
142             This is a convenience wrapper on top of
143             L. It takes exactly the same arguments.
144             Please refer to that module for documentation.
145              
146             =cut
147              
148             sub emit {
149 1     1 1 11 my ($self) = shift;
150 1         5 $self->{_}{dispatcher}->emit_event (@_);
151             }
152              
153             # }}}
154             # {{{ trace
155              
156             sub trace {
157 0     0 0 0 my ($self) = shift;
158              
159 0         0 foreach (@_) {
160 0         0 my $l = $_; # Skip 'Modification of a read-only value' errors
161 0         0 chomp ($l);
162 0         0 print "$l\n";
163             }
164             }
165              
166             # }}}
167              
168             # These can (should) be overridden
169             # {{{ as_string
170              
171             # This should really be overridden by our subclass
172              
173             sub as_string {
174 1     1 0 2 my ($self) = @_;
175 1         2 my $s = '';
176              
177 1         4 $s .= "[".ref($self)."]";
178              
179 1         10 return $s;
180             }
181              
182             # }}}
183 1     1 0 2 sub validate_configuration { my $self=shift; return {@_}; }
  1         35  
184              
185             #sub setup {}
186             #sub teardown {}
187              
188              
189             # Utilities for viewing binary data
190             # {{{ sanitize_raw
191              
192             sub sanitize_raw {
193 0     0 0   my ($self, $raw, $max, $append_binary) = @_;
194 0 0 0       $raw = substr($raw,0,$max) if ($max && length($raw) > $max);
195              
196 0           my $s = $raw;
197 0           $s =~ s {([^\x20-\x7e])} {.}g;
198 0 0         $s .= " ".$self->map2bin($raw) if ($append_binary);
199 0           return "{$s}";
200             }
201              
202             # }}}
203             # {{{ map2bin
204              
205             sub map2bin {
206 0     0 0   my ($self,$raw) = @_;
207 0           my $bin = unpack("B*", $raw);
208 0           $bin =~ s{([^ ]{8})(?! )}{ $1}g;
209 0           $bin =~ s{(^ *| *$)}{}g;
210 0           return "<$bin>";
211             }
212              
213             # }}}
214             # {{{ map2hex
215              
216             sub map2hex {
217 0     0 0   my ($self,$raw, $prefix, $append_binary) = @_;
218              
219 0   0       $prefix ||= '';
220 0           my $hex = unpack("H*", $raw);
221              
222 0           $hex =~ s {([0-9a-f]{2}(?! ))} { $1}mg;
223              
224 0           $hex =~ s {(( [0-9a-f]{2}){16})}
225 0           {"$1 ".$self->hex2saferaw($1,$append_binary)."\n"}emg;
226              
227             # Unfinished last line
228 0           $hex =~ s {(( [0-9a-f]{2})*)$}
229 0           {sprintf("%-47.47s ",$1) .$self->hex2saferaw($1,$append_binary)."\n"}es;
230              
231 0           chomp($hex);
232              
233 0           $hex =~ s/^/$prefix/msg;
234              
235 0           return $hex."\n";
236             }
237              
238             sub hex2saferaw {
239 0     0 0   my ($self, $hex, $append_binary) = @_;
240              
241 0           $hex =~ s {\s+} {}mg;
242 0           my $raw = pack("H*", $hex);
243              
244 0           return $self->sanitize_raw($raw,undef,$append_binary);
245             }
246              
247             # }}}
248              
249             1;
250             __END__