3 # Database Handler module for DXSpider
5 # Copyright (c) 1999 Dirk Koopman G1TLH
18 use vars qw($opentime $dbbase %avail %valid $lastprocesstime $nextstream %stream);
20 $opentime = 5*60; # length of time a database stays open after last access
21 $dbbase = "$main::root/db"; # where all the databases are kept;
22 %avail = (); # The hash contains a list of all the databases
24 accesst => '9,Last Access Time,atime',
25 createt => '9,Create Time,atime',
26 lastt => '9,Last Update Time,atime',
28 db => '9,DB Tied hash',
29 remote => '0,Remote Database',
32 $lastprocesstime = time;
36 # allocate a new stream for this request
40 my $n = ++$nextstream;
41 $stream{$n} = { n=>$n, call=>$call, t=>$main::systime };
59 # load all the database descriptors
62 my $s = readfilestr($dbbase, "dbs", "pl");
70 # save all the database descriptors
73 my $date = cldatetime($main::systime);
75 writefilestr($dbbase, "dbs", "pl", \%avail, "#\n# database descriptor file\n# Don't alter this by hand unless you know what you are doing\n# last modified $date\n#\n");
78 # get the descriptor of the database you want.
81 return undef unless %avail;
84 my $r = $avail{$name};
86 # search for a partial if not found direct
89 if ($_->{name} =~ /^$name/) {
102 $self->{accesst} = $main::systime;
103 return $self->{db} if $self->{db};
105 $self->{db} = tie %hash, 'DB_File', "$dbbase/$self->{name}";
123 for (values %avail) {
129 # get a value from the database
136 # make sure we are open
139 my $s = $self->{db}->get($key, $value);
140 return $s ? undef : $value;
145 # put a value to the database
152 # make sure we are open
155 my $s = $self->{db}->put($key, $value);
156 return $s ? undef : 1;
161 # create a new database params: <name> [<remote node call>]
167 $self->{name} = lc $name;
168 $self->{remote} = uc $remote if $remote;
169 $self->{accesst} = $self->{createt} = $self->{lastt} = $main::systime;
170 $avail{$self->{name}} = $self;
171 mkdir $dbbase, 02775 unless -e $dbbase;
180 unlink "$dbbase/$self->{name}";
181 delete $avail{$self->{name}};
186 # process intermediate lines for an update
187 # NOTE THAT THIS WILL BE CALLED FROM DXCommandmode and the
188 # object will be a DXChannel (actually DXCommandmode)
196 # periodic maintenance
198 # just close any things that haven't been accessed for the default
204 my ($dxchan, $line) = @_;
206 # this is periodic processing
207 if (!$dxchan || !$line) {
208 if ($main::systime - $lastprocesstime >= 60) {
210 for (values %avail) {
211 if ($main::systime - $_->{accesst} > $opentime) {
216 $lastprocesstime = $main::systime;
221 my @f = split /\^/, $line;
222 my ($pcno) = $f[0] =~ /^PC(\d\d)/; # just get the number
224 # route out ones that are not for us
225 if ($f[1] eq $main::mycall) {
228 $dxchan->route($f[1], $line);
233 if ($pcno == 37) { # probably obsolete
237 if ($pcno == 44) { # incoming DB Request
238 my $db = getdesc($f[4]);
241 sendremote($dxchan, $f[2], $f[3], $dxchan->msg('dx1', $db->{remote}));
243 my $value = $db->getkey($f[5]);
245 my @out = split /\n/, $value;
246 sendremote($dxchan, $f[2], $f[3], @out);
248 sendremote($dxchan, $f[2], $f[3], $dxchan->msg('dx2', $f[5], $db->{name}));
252 sendremote($dxchan, $f[2], $f[3], $dxchan->msg('dx3', $f[4]));
257 if ($pcno == 45) { # incoming DB Information
258 my $n = getstream($f[3]);
260 my $mchan = DXChannel->get($n->{call});
261 $mchan->send($f[2] . ":$f[4]");
266 if ($pcno == 46) { # incoming DB Complete
271 if ($pcno == 47) { # incoming DB Update request
275 if ($pcno == 48) { # incoming DB Update request
281 # send back a trache of data to the remote
282 # remember $dxchan is a dxchannel
290 $dxchan->send(DXProt::pc45($main::mycall, $tonode, $stream, $_));
292 $dxchan->send(DXProt::pc46($main::mycall, $tonode, $stream));
295 # various access routines
298 # return a list of valid elements
307 # return a prompt for a field
312 my ($self, $ele) = @_;
320 my $name = $AUTOLOAD;
321 return if $name =~ /::DESTROY$/;
324 confess "Non-existant field '$AUTOLOAD'" if !$valid{$name};
325 @_ ? $self->{$name} = shift : $self->{$name} ;