2 # Node routing routines
4 # Copyright (c) 2001 Dirk Koopman G1TLH
17 use vars qw($VERSION $BRANCH);
18 $VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
19 $BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/ || (0,0));
20 $main::build += $VERSION;
21 $main::branch += $BRANCH;
23 use vars qw(%list %valid @ISA $max $filterdef);
27 dxchan => '0,DXChannel List,parray',
28 nodes => '0,Nodes,parray',
29 users => '0,Users,parray',
30 usercount => '0,User Count',
31 version => '0,Version',
32 newroute => '0,New Routing?,yesno',
35 $filterdef = $Route::filterdef;
41 my $n = scalar (keys %list);
42 $max = $n if $n > $max;
52 # link a node to this node and mark the route as available thru
53 # this dxchan, any users must be linked separately
55 # call as $node->link_node($neighbour, $dxchan);
60 my ($self, $neighbour, $dxchan) = @_;
62 my $r = $neighbour->is_empty('dxchan');
63 $self->_addlist('nodes', $neighbour);
64 $neighbour->_addlist('nodes', $self);
65 $neighbour->_addlist('dxchan', $dxchan);
66 return $r ? ($neighbour) : ();
69 # unlink a node from a neighbour and remove any
70 # routes, if this node becomes orphaned (no routes
71 # and no nodes) then return it
76 my ($self, $neighbour, $dxchan) = @_;
77 $self->_dellist('nodes', $neighbour);
78 $neighbour->_dellist('nodes', $self);
79 $neighbour->_dellist('dxchan', $dxchan) if $dxchan;
80 return $neighbour->is_empty('dxchan') ? ($neighbour) : ();
85 my ($self, $neighbour, $dxchan) = @_;
90 push @rout, $self->unlink_node($neighbour, $dxchan);
91 dbg("Orphanning $neighbour->{call}") if isdbg('routelow');
93 # then run down the tree removing this dxchan link from
94 # all the referenced nodes that use this interface
96 my @in = map { Route::Node::get($_) } $neighbour->nodes;
99 next if $visited{$r->call};
100 my ($o) = $r->del_dxchan($self);
102 dbg("Orphanning $_->{call}") if isdbg('routelow');
105 push @in, map{ Route::Node::get($_) } $r->nodes;
106 $visited{$r->call} = $r;
109 # in @rout there should be a list of orphaned (in dxchan terms)
110 # nodes. Now go thru and make sure that all their links are
111 # broken (they should be, but this is to check).
113 foreach my $r (@rout) {
114 my @nodes = map { Route::Node::get($_)} $r->nodes;
117 dbg("Orphaned node $_->{call}: breaking link to $_->{call}") if isdbg('routelow');
124 # add a user to this node
125 # returns Route::User if it is a new user;
128 my ($self, $uref) = @_;
129 my $r = $uref->is_empty('nodes');
130 $self->_addlist('users', $uref);
131 $uref->_addlist('nodes', $self);
132 $self->{usercount} = scalar @{$self->{users}};
133 return $r ? ($uref) : ();
136 # delete a user from this node
139 my ($self, $uref) = @_;
141 $self->_dellist('users', $uref);
142 $uref->_dellist('nodes', $self);
143 $self->{usercount} = scalar @{$self->{users}};
144 return $uref->is_empty('nodes') ? ($uref) : ();
147 # add a single dxchan link
150 my ($self, $dxchan) = @_;
151 return $self->_addlist('dxchan', $dxchan);
154 # remove a single dxchan link
157 my ($self, $dxchan) = @_;
158 return $self->_dellist('dxchan', $dxchan);
164 if (@_ && @{$self->{users}} == 0) {
165 $self->{usercount} = shift;
167 return $self->{usercount};
173 return @{$self->{users}};
179 return @{$self->{nodes}};
186 foreach my $u (${$self->{users}}) {
187 my $uref = Route::User::get($u);
188 push @rout, $self->del_user($uref) if $uref;
198 confess "already have $call in $pkg" if $list{$call};
200 my $self = $pkg->SUPER::new($call);
201 $self->{dxchan} = ref $pkg ? [ $pkg->{call} ] : [ ];
202 $self->{version} = shift || 5000;
203 $self->{flags} = shift || Route::here(1);
207 $list{$call} = $self;
208 dbg("creating Route::Node $self->{call}") if isdbg('routelow');
216 dbg("deleting Route::Node $self->{call}") if isdbg('routelow');
217 delete $list{$self->{call}};
223 $call = shift if ref $call;
224 my $ref = $list{uc $call};
225 dbg("Failed to get Node $call" ) if !$ref && isdbg('routerr');
238 my $call = $self->{call} || "Unknown";
240 dbg("destroying $pkg with $call") if isdbg('routelow');
241 $self->unlink_all_users if @{$self->{users}};
245 # generic AUTOLOAD for accessors
251 my $name = $AUTOLOAD;
252 return if $name =~ /::DESTROY$/;
255 confess "Non-existant field '$AUTOLOAD'" unless $valid{$name} || $Route::valid{$name};
257 # this clever line of code creates a subroutine which takes over from autoload
258 # from OO Perl - Conway
259 *$AUTOLOAD = sub {$_[0]->{$name} = $_[1] if @_ > 1; return $_[0]->{$name}};