4 # This is the new fundamental protocol engine handler
6 # This is where all the new things (and eventually all the old things
11 # Copyright (c) 2004 Dirk Koopman G1TLH
18 use vars qw($VERSION $BRANCH @queue @permin @persec);
20 main::mkver($VERSION = q$Revision$);
22 @queue = (); # the input / processing queue
25 # these are set up using the Thingy->add_second_process($addr, $name)
26 # and Thingy->add_minute_process($addr, $name)
28 # They replace the old cycle in cluster.pl
31 @persec = (); # this replaces the cycle in cluster.pl
32 @permin = (); # this is an extra per minute cycle
40 # we expect all thingies to be subclassed
46 $thing->{origin} ||= $main::mycall;
52 # send it out in the format asked for, if available
62 } elsif ($dxchan->isa('DXChannel')) {
70 if ($thing->can('out_filter')) {
71 return unless $thing->out_filter($dxchan);
74 # before send (and line generation) things
75 # function must return true to make the send happen
76 $sub = "before_send_$class";
77 return unless $thing->can($sub) && $thing->$sub($dxchan);
79 # generate the protocol line which may (or not) be cached
81 unless ($ref = $thing->{class}) {
83 $ref = $thing->$sub($dxchan) if $thing->can($sub);
85 $dxchan->send(ref $ref ? @$ref : $ref) if $ref;
88 if ($thing->can('after_send_all')) {
89 $thing->after_send_all($dxchan);
91 $sub = "after_send_$class";
92 $thing->$sub($dxchan) if $thing->can($sub);
96 # broadcast to all except @_
100 dbg("Thingy::broadcast: " . $thing->ascii) if isdbg('thing');
102 foreach my $dxchan (DXChannel::get_all()) {
103 next if $dxchan == $main::me;
104 next if grep $dxchan == $_, @_;
105 $thing->send($dxchan);
109 # queue this thing for processing
114 $thing->{dxchan} = $dxchan->call;
119 # this is the main commutator loop. In due course it will
120 # become the *only* commutator loop, This can be called in one
121 # of two ways: either with 2 args or with none.
123 # The two arg form is an immediate "queue and handle" and does
124 # a full cycle, immediately
131 $thing->queue(shift);
134 $thing = shift @queue;
135 my $dxchan = DXChannel::get($thing->{dxchan});
137 if ($thing->can('in_filter')) {
138 next unless $thing->in_filter($dxchan);
141 # remember any useful routes
142 RouteDB::update($thing->{origin}, $dxchan->{call}, $thing->{hopsaway});
143 RouteDB::update($thing->{user}, $dxchan->{call}, $thing->{hopsaway}) if exists $thing->{user};
145 $thing->handle($dxchan);
149 # per second and per minute processing
150 if ($main::systime != $lastsec) {
151 if ($main::systime >= $lastmin+60) {
152 foreach my $r (@permin) {
155 $lastmin = $main::systime;
157 foreach my $r (@persec) {
160 $lastsec = $main::systime;
164 sub add_minute_process
169 dbg('Adding $name to Thingy per minute queue');
170 push @permin, [$addr, $name];
173 sub add_second_process
178 dbg('Adding $name to Thingy per second queue');
179 push @persec, [$addr, $name];
186 my $dd = new Data::Dumper([$thing]);
190 $dd->Quotekeys($] < 5.005 ? 1 : 0);
197 my $s = $thing->{'s'} = sprintf "%X", int(rand() * 100000000);
198 my $auth = Verify->new("DXSp,$main::mycall,$s,$main::version,$main::build");
199 $thing->{auth} = $auth->challenge($main::me->user->passphrase);