# Thingy handling
#
# This is the new fundamental protocol engine handler
+#
+# This is where all the new things (and eventually all the old things
+# as well) happen.
#
# $Id$
#
# Copyright (c) 2004 Dirk Koopman G1TLH
#
+use strict;
+
package Thingy;
-use vars qw($VERSION $BRANCH);
+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));
+$BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /^\d+\.\d+(?:\.(\d+)\.(\d+))?$/ || (0,0));
$main::build += $VERSION;
$main::branch += $BRANCH;
+@queue = (); # the input / processing queue
+
+#
+# these are set up using the Thingy->add_second_process($addr, $name)
+# and Thingy->add_minute_process($addr, $name)
+#
+# They replace the old cycle in cluster.pl
+#
+
+@persec = (); # this replaces the cycle in cluster.pl
+@permin = (); # this is an extra per minute cycle
+
+my $lastsec = time;
+my $lastmin = time;
use DXChannel;
use DXDebug;
-use vars qw(@queue);
-@queue = (); # the thingy queue
-
# we expect all thingies to be subclassed
sub new
{
my $class = shift;
- my $self = {@_};
+ my $thing = {@_};
- bless $self, $class;
- return $self;
+ bless $thing, $class;
+ return $thing;
+}
+
+# send it out in the format asked for, if available
+sub send
+{
+ my $thing = shift;
+ my $dxchan = shift;
+ my $class;
+ if (@_) {
+ $class = shift;
+ } elsif ($dxchan->isa('DXChannel')) {
+ $class = ref $dxchan;
+ }
+
+ # do output filtering
+ if ($thing->can('out_filter')) {
+ return unless $thing->out_filter;
+ }
+
+ # generate the line which may (or not) be cached
+ my @out;
+ if (my $ref = $thing->{class}) {
+ push @out, ref $ref ? @$ref : $ref;
+ } else {
+ no strict 'refs';
+ my $sub = "gen_$class";
+ push @out, $thing->$sub($dxchan) if $thing->can($sub);
+ }
+ $dxchan->send(@out) if @out;
}
-# add the Thingy to the queue
-sub add
+# broadcast to all except @_
+sub broadcast
{
- push @queue, shift;
+ my $thing = shift;
+ dbg("Thingy::broadcast: " . $thing->ascii) if isdbg('thing');
+
+ foreach my $dxchan (DXChannel::get_all()) {
+ next if $dxchan == $main::me;
+ next if grep $dxchan == $_, @_;
+ $thing->send($dxchan);
+ }
+}
+
+# queue this thing for processing
+sub queue
+{
+ my $thing = shift;
+ my $dxchan = shift;
+ $thing->{dxchan} = $dxchan->call;
+ push @queue, $thing;
}
-# dispatch Thingies to action it.
+# this is the main commutator loop. In due course it will
+# become the *only* commutator loop
sub process
{
- my $t = pop @queue if @queue;
+ my $thing;
+ while (@queue) {
+ $thing = shift @queue;
+ my $dxchan = DXChannel->get($thing->{dxchan});
+ if ($dxchan) {
+ if ($thing->can('in_filter')) {
+ next unless $thing->in_filter($dxchan);
+ }
+ $thing->handle($dxchan);
+ }
+ }
- $t->process if $t;
+ # per second and per minute processing
+ if ($main::systime != $lastsec) {
+ if ($main::systime >= $lastmin+60) {
+ foreach my $r (@permin) {
+ &{$r->[0]}();
+ }
+ $lastmin = $main::systime;
+ }
+ foreach my $r (@persec) {
+ &{$r->[0]}();
+ }
+ $lastsec = $main::systime;
+ }
+}
+
+sub add_minute_process
+{
+ my $pkg = shift;
+ my $addr = shift;
+ my $name = shift;
+ dbg('Adding $name to Thingy per minute queue');
+ push @permin, [$addr, $name];
}
+sub add_second_process
+{
+ my $pkg = shift;
+ my $addr = shift;
+ my $name = shift;
+ dbg('Adding $name to Thingy per second queue');
+ push @persec, [$addr, $name];
+}
+
+
+sub ascii
+{
+ my $thing = shift;
+ my $dd = new Data::Dumper([$thing]);
+ $dd->Indent(0);
+ $dd->Terse(1);
+ $dd->Sortkeys(1);
+ $dd->Quotekeys($] < 5.005 ? 1 : 0);
+ return $dd->Dumpxs;
+}
1;