X-Git-Url: http://gb7djk.dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FThingy.pm;h=afc2129b913641eaaaf641330781de873bc535cd;hb=4c60d18d0d58ece2406680d4afd4ff016532c11c;hp=0921abd818414d2c2dac083fd5aab6033224cedc;hpb=5764cc1c0f79b56fdf5389d2b0dcb2ab7e54723d;p=spider.git diff --git a/perl/Thingy.pm b/perl/Thingy.pm index 0921abd8..afc2129b 100644 --- a/perl/Thingy.pm +++ b/perl/Thingy.pm @@ -16,10 +16,8 @@ use strict; package Thingy; use vars qw($VERSION $BRANCH @queue @permin @persec); -$VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ ); -$BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /^\d+\.\d+(?:\.(\d+)\.(\d+))?$/ || (0,0)); -$main::build += $VERSION; -$main::branch += $BRANCH; + +main::mkver($VERSION = q$Revision$); @queue = (); # the input / processing queue @@ -38,14 +36,19 @@ my $lastmin = time; use DXChannel; use DXDebug; +use DXUtil; + # we expect all thingies to be subclassed sub new { my $class = shift; + my $pkg = ref $class || $class; my $thing = {@_}; + + $thing->{origin} ||= $main::mycall; - bless $thing, $class; + bless $thing, $pkg; return $thing; } @@ -55,38 +58,80 @@ sub send my $thing = shift; my $dxchan = shift; my $class; + my $sub; + if (@_) { $class = shift; } elsif ($dxchan->isa('DXChannel')) { $class = ref $dxchan; } + # BEWARE!!!!! + no strict 'refs'; + # do output filtering if ($thing->can('out_filter')) { - return unless $thing->out_filter; + return unless $thing->out_filter($dxchan); + } + + # before send (and line generation) things + # function must return true to make the send happen + $sub = "before_send_$class"; + if ($thing->can($sub)) { + return unless $thing->$sub($dxchan); + } + + # generate the protocol line which may (or not) be cached + my $ref; + unless ($ref = $thing->{class}) { + $sub = "gen_$class"; + $ref = $thing->$sub($dxchan) if $thing->can($sub); } + $dxchan->send(ref $ref ? @$ref : $ref) if $ref; - # generate the line which may (or not) be cached - my @out; - if (my $ref = $thing->{class}) { - push @out, ref $ref ? @$ref : $ref; + # after send + if ($thing->can('after_send_all')) { + $thing->after_send_all($dxchan); } else { - no strict 'refs'; - my $sub = "gen_$class"; - push @out, $thing->$sub($dxchan) if $thing->can($sub); + $sub = "after_send_$class"; + $thing->$sub($dxchan) if $thing->can($sub); } - $dxchan->send(@out) if @out; } -# broadcast to all except @_ +# +# This is the main routing engine for the new protocol. Broadcast is a slight +# misnomer, because if it thinks it can route it down one or interfaces, it will. +# +# It handles anything it recognises as a callsign, sees if it can find it in a +# routing table, and if it does, then routes the message. +# +# If it can't then it will broadcast it. +# sub broadcast { my $thing = shift; dbg("Thingy::broadcast: " . $thing->ascii) if isdbg('thing'); - foreach my $dxchan (DXChannel::get_all()) { + my @dxchan; + my $to ||= $thing->{route}; + $to ||= $thing->{touser}; + $to ||= $thing->{group}; + if ($to && is_callsign($to) && (my $ref = Route::get($to))) { + dbg("Thingy::broadcast: routing for $to") if isdbg('thing'); + @dxchan = $ref->alldxchan; + } else { + @dxchan = DXChannel::get_all(); + } + + dbg("Thingy::broadcast: offered " . join(',', map {$_->call} @dxchan)) if isdbg('thing'); + + foreach my $dxchan (@dxchan) { next if $dxchan == $main::me; next if grep $dxchan == $_, @_; + next if $dxchan->{call} eq $thing->{origin}; + next if $thing->{user} && !$dxchan->is_user && $dxchan->{call} eq $thing->{user}; + + dbg("Thingy::broadcast: sending to $dxchan->{call}") if isdbg('thing'); $thing->send($dxchan); } } @@ -100,18 +145,35 @@ sub queue push @queue, $thing; } +# # this is the main commutator loop. In due course it will -# become the *only* commutator loop +# become the *only* commutator loop, This can be called in one +# of two ways: either with 2 args or with none. +# +# The two arg form is an immediate "queue and handle" and does +# a full cycle, immediately +# sub process { my $thing; + + if (@_ == 2) { + $thing = shift; + $thing->queue(shift); + } + while (@queue) { $thing = shift @queue; - my $dxchan = DXChannel->get($thing->{dxchan}); + my $dxchan = DXChannel::get($thing->{dxchan}); if ($dxchan) { if ($thing->can('in_filter')) { next unless $thing->in_filter($dxchan); } + + # remember any useful routes + RouteDB::update($thing->{origin}, $dxchan->{call}, $thing->{hopsaway}); + RouteDB::update($thing->{user}, $dxchan->{call}, $thing->{hopsaway}) if exists $thing->{user}; + $thing->handle($dxchan); } } @@ -156,9 +218,41 @@ sub ascii my $dd = new Data::Dumper([$thing]); $dd->Indent(0); $dd->Terse(1); - $dd->Sortkeys(1); + #$dd->Sortkeys(1); $dd->Quotekeys($] < 5.005 ? 1 : 0); return $dd->Dumpxs; } + +sub add_auth +{ + my $thing = shift; + my $s = $thing->{'s'} = sprintf "%X", int(rand() * 100000000); + my $auth = Verify->new("DXSp,$main::mycall,$s,$thing->{v},$thing->{b}"); + $thing->{auth} = $auth->challenge($main::me->user->passphrase); +} + +# +# create a generalised reply to a passed thing, if it isn't replyable +# to then undef is returned +# +sub new_reply +{ + my $thing = shift; + my $out; + + if ($thing->{group} eq $main::mycall) { + $out = $thing->new; + $out->{touser} = $thing->{user} if $thing->{user}; + $out->{group} = $thing->{origin}; + } elsif (DXChannel::get($thing->{group})) { + $out = $thing->new(user => $thing->{group}); + $out->{touser} = $thing->{user} if $thing->{user}; + $out->{group} = $thing->{origin}; + } elsif ($thing->{touser} && DXChannel::get($thing->{touser})) { + $out = $thing->new(user => $thing->{touser}); + $out->{group} = $thing->{group}; + } + return $out; +} 1;