c91edc0ce3d0d1d1429d7365338988884f796f94
[spider.git] / perl / Thingy.pm
1 #
2 # Thingy handling
3 #
4 # This is the new fundamental protocol engine handler
5
6 # This is where all the new things (and eventually all the old things
7 # as well) happen.
8 #
9 # $Id$
10 #
11 # Copyright (c) 2004 Dirk Koopman G1TLH
12 #
13
14 use strict;
15
16 package Thingy;
17
18 use vars qw($VERSION $BRANCH @queue @permin @persec);
19 $VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
20 $BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /^\d+\.\d+(?:\.(\d+)\.(\d+))?$/  || (0,0));
21 $main::build += $VERSION;
22 $main::branch += $BRANCH;
23
24 @queue = ();                                    # the input / processing queue
25
26 #
27 # these are set up using the Thingy->add_second_process($addr, $name)
28 # and Thingy->add_minute_process($addr, $name)
29 #
30 # They replace the old cycle in cluster.pl
31 #
32
33 @persec = ();                                   # this replaces the cycle in cluster.pl
34 @permin = ();                                   # this is an extra per minute cycle
35
36 my $lastsec = time;
37 my $lastmin = time;
38
39 use DXChannel;
40 use DXDebug;
41
42 # we expect all thingies to be subclassed
43 sub new
44 {
45         my $class = shift;
46         my $thing = {@_};
47         
48         bless $thing, $class;
49         return $thing;
50 }
51
52 # send it out in the format asked for, if available
53 sub send
54 {
55         my $thing = shift;
56         my $dxchan = shift;
57         my $class;
58         if (@_) {
59                 $class = shift;
60         } elsif ($dxchan->isa('DXChannel')) {
61                 $class = ref $dxchan;
62         }
63
64         # do output filtering
65         if ($thing->can('out_filter')) {
66                 return unless $thing->out_filter($dxchan);
67         }
68
69         # generate the line which may (or not) be cached
70         my @out;
71         if (my $ref = $thing->{class}) {
72                 push @out, ref $ref ? @$ref : $ref;
73         } else {
74                 no strict 'refs';
75                 my $sub = "gen_$class";
76                 push @out, $thing->$sub($dxchan) if $thing->can($sub);
77         }
78         $dxchan->send(@out) if @out;
79 }
80
81 # broadcast to all except @_
82 sub broadcast
83 {
84         my $thing = shift;
85         dbg("Thingy::broadcast: " . $thing->ascii) if isdbg('thing'); 
86
87         foreach my $dxchan (DXChannel::get_all()) {
88                 next if $dxchan == $main::me;
89                 next if grep $dxchan == $_, @_;
90                 $thing->send($dxchan); 
91         }
92 }
93
94 # queue this thing for processing
95 sub queue
96 {
97         my $thing = shift;
98         my $dxchan = shift;
99         $thing->{dxchan} = $dxchan->call;
100         push @queue, $thing;
101 }
102
103 # this is the main commutator loop. In due course it will
104 # become the *only* commutator loop
105 sub process
106 {
107         my $thing;
108         while (@queue) {
109                 $thing = shift @queue;
110                 my $dxchan = DXChannel->get($thing->{dxchan});
111                 if ($dxchan) {
112                         if ($thing->can('in_filter')) {
113                                 next unless $thing->in_filter($dxchan);
114                         }
115
116                         # remember any useful routes
117                         RouteDB::update($thing->{origin}, $dxchan->{call}, $thing->{hopsaway});
118                         RouteDB::update($thing->{user}, $dxchan->{call}, $thing->{hopsaway}) if exists $thing->{user};
119                 
120                         $thing->handle($dxchan);
121                 }
122         }
123
124         # per second and per minute processing
125         if ($main::systime != $lastsec) {
126                 if ($main::systime >= $lastmin+60) {
127                         foreach my $r (@permin) {
128                                 &{$r->[0]}();
129                         }
130                         $lastmin = $main::systime;
131                 }
132                 foreach my $r (@persec) {
133                         &{$r->[0]}();
134                 }
135                 $lastsec = $main::systime;
136         }
137 }
138
139 sub add_minute_process
140 {
141         my $pkg = shift;
142         my $addr = shift;
143         my $name = shift;
144         dbg('Adding $name to Thingy per minute queue');
145         push @permin, [$addr, $name];
146 }
147
148 sub add_second_process
149 {
150         my $pkg = shift;
151         my $addr = shift;
152         my $name = shift;
153         dbg('Adding $name to Thingy per second queue');
154         push @persec, [$addr, $name];
155 }
156
157
158 sub ascii
159 {
160         my $thing = shift;
161         my $dd = new Data::Dumper([$thing]);
162         $dd->Indent(0);
163         $dd->Terse(1);
164         $dd->Sortkeys(1);
165     $dd->Quotekeys($] < 5.005 ? 1 : 0);
166         return $dd->Dumpxs;
167 }
168 1;
169