X-Git-Url: http://dxcluster.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXUser.pm;h=2c562ac70ed538d12373150fd08b2e15944a1b4f;hb=1006337e105ab06a0e468bc483332fd385dd5240;hp=2bd140348cf1994163ace77be621310475c0c0fd;hpb=6c38bca91e6b75002e15cce29c45a894f675e22e;p=spider.git diff --git a/perl/DXUser.pm b/perl/DXUser.pm index 2bd14034..2c562ac7 100644 --- a/perl/DXUser.pm +++ b/perl/DXUser.pm @@ -8,22 +8,31 @@ package DXUser; -require Exporter; -@ISA = qw(Exporter); - use DXLog; use DB_File; use Data::Dumper; use Fcntl; use IO::File; use DXDebug; +use DXUtil; +use LRU; use strict; -use vars qw(%u $dbm $filename %valid); + +use vars qw($VERSION $BRANCH); +$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; + +use vars qw(%u $dbm $filename %valid $lastoperinterval $lasttime $lru $lrusize); %u = (); $dbm = undef; $filename = undef; +$lastoperinterval = 60*24*60*60; +$lasttime = 0; +$lrusize = 2000; # hash of valid elements and a simple prompt %valid = ( @@ -34,10 +43,11 @@ $filename = undef; lat => '0,Latitude,slat', long => '0,Longitude,slong', qra => '0,Locator', - email => '0,E-mail Address', + email => '0,E-mail Address,parray', priv => '9,Privilege Level', lastin => '0,Last Time in,cldatetime', - passwd => '9,Password', + passwd => '9,Password,yesno', + passphrase => '9,Pass Phrase,yesno', addr => '0,Full Address', 'sort' => '0,Type of User', # A - ak1a, U - User, S - spider cluster, B - BBS xpert => '0,Expert Status,yesno', @@ -47,43 +57,61 @@ $filename = undef; lockout => '9,Locked out?,yesno', # won't let them in at all dxok => '9,Accept DX Spots?,yesno', # accept his dx spots? annok => '9,Accept Announces?,yesno', # accept his announces? - reg => '0,Registered?,yesno', # is this user registered? lang => '0,Language', hmsgno => '0,Highest Msgno', group => '0,Access Group,parray', # used to create a group of users/nodes for some purpose or other isolate => '9,Isolate network,yesno', - wantbeep => '0,Rec Beep,yesno', - wantann => '0,Rec Announce,yesno', - wantwwv => '0,Rec WWV,yesno', - wantwcy => '0,Rec WCY,yesno', - wantecho => '0,Rec Echo,yesno', - wanttalk => '0,Rec Talk,yesno', - wantwx => '0,Rec WX,yesno', - wantdx => '0,Rec DX Spots,yesno', + wantbeep => '0,Req Beep,yesno', + wantann => '0,Req Announce,yesno', + wantwwv => '0,Req WWV,yesno', + wantwcy => '0,Req WCY,yesno', + wantecho => '0,Req Echo,yesno', + wanttalk => '0,Req Talk,yesno', + wantwx => '0,Req WX,yesno', + wantdx => '0,Req DX Spots,yesno', + wantemail => '0,Req Msgs as Email,yesno', pagelth => '0,Current Pagelth', pingint => '9,Node Ping interval', nopings => '9,Ping Obs Count', wantlogininfo => '9,Login info req,yesno', - wantgrid => '0,DX Grid Info,yesno', + wantgrid => '0,DX Grid Info,yesno', + wantann_talk => '0,Talklike Anns,yesno', + wantpc90 => '1,Req PC90,yesno', + wantnp => '1,Req New Protocol,yesno', + wantpc16 => '9,Want Users from node,yesno', + wantsendpc16 => '9,Send users to node,yesno', lastoper => '9,Last for/oper,cldatetime', + nothere => '0,Not Here Text', + registered => '9,Registered?,yesno', + prompt => '0,Required Prompt', + version => '1,Version', + build => '1,Build', ); -no strict; +#no strict; sub AUTOLOAD { my $self = shift; + no strict; my $name = $AUTOLOAD; return if $name =~ /::DESTROY$/; - $name =~ s/.*:://o; + $name =~ s/^.*:://o; confess "Non-existant field '$AUTOLOAD'" if !$valid{$name}; - if (@_) { - $self->{$name} = shift; - } - return $self->{$name}; + # this clever line of code creates a subroutine which takes over from autoload + # from OO Perl - Conway + *$AUTOLOAD = sub {@_ > 1 ? $_[0]->{$name} = $_[1] : $_[0]->{$name}}; + &$AUTOLOAD($self, @_); +# *{$AUTOLOAD} = sub {@_ > 1 ? $_[0]->{$name} = $_[1] : $_[0]->{$name}} ; +# if (@_) { +# $self->{$name} = shift; +# } +# return $self->{$name}; } +#use strict; + # # initialise the system # @@ -100,9 +128,28 @@ sub init } $filename = $fn; + $lru = LRU->newbase("DXUser", $lrusize); } -use strict; +sub del_file +{ + my ($pkg, $fn) = @_; + + confess "need a filename in User" if !$fn; + $fn .= ".v2"; + unlink $fn; +} + +# +# periodic processing +# +sub process +{ + if ($main::systime > $lasttime + 15) { + $dbm->sync; + $lasttime = $main::systime; + } +} # # close the system @@ -142,18 +189,19 @@ sub get { my $pkg = shift; my $call = uc shift; - # $call =~ s/-\d+$//o; # strip ssid - my $s = $u{$call}; - return $s ? decode($s) : undef; -} - -# -# get all callsigns in the database -# - -sub get_all_calls -{ - return (sort keys %u); + my $data; + + # is it in the LRU cache? + my $ref = $lru->get($call); + return $ref if $ref; + + # search for it + unless ($dbm->get($call, $data)) { + $ref = decode($data); + $lru->put($call, $ref); + return $ref; + } + return undef; } # @@ -168,11 +216,21 @@ sub get_current { my $pkg = shift; my $call = uc shift; - # $call =~ s/-\d+$//o; # strip ssid my $dxchan = DXChannel->get($call); return $dxchan->user if $dxchan; - return get($pkg, $call); + my $rref = Route::get($call); + return $rref->user if $rref && exists $rref->{user}; + return $pkg->get($call); +} + +# +# get all callsigns in the database +# + +sub get_all_calls +{ + return (sort keys %u); } # @@ -185,13 +243,15 @@ sub put confess "Trying to put nothing!" unless $self && ref $self; my $call = $self->{call}; # delete all instances of this - for ($dbm->get_dup($call)) { - $dbm->del_dup($call, $_); - } +# for ($dbm->get_dup($call)) { +# $dbm->del_dup($call, $_); +# } + $dbm->del($call); delete $self->{annok} if $self->{annok}; delete $self->{dxok} if $self->{dxok}; - $u{$call} = $self->encode(); - $dbm->sync; + $lru->put($call, $self); + my $ref = $self->encode; + $dbm->put($call, $ref); } # @@ -214,10 +274,12 @@ sub decode { my $s = shift; my $ref; - $s = '$ref = ' . $s; - eval $s; - Log('DXUser', $@) if $@; - $ref = undef if $@; + eval '$ref = ' . $s; + if ($@) { + dbg($@); + Log('err', $@); + $ref = undef; + } return $ref; } @@ -230,10 +292,11 @@ sub del my $self = shift; my $call = $self->{call}; # delete all instances of this - for ($dbm->get_dup($call)) { - $dbm->del_dup($call, $_); - } - $dbm->sync; +# for ($dbm->get_dup($call)) { +# $dbm->del_dup($call, $_); +# } + $lru->remove($call); + $dbm->del($call); } # @@ -247,6 +310,15 @@ sub close $self->put(); } +# +# sync the database +# + +sub sync +{ + $dbm->sync; +} + # # return a list of valid elements # @@ -273,33 +345,100 @@ sub export rename "$fn", "$fn.o" if -e "$fn"; my $count = 0; + my $err = 0; my $fh = new IO::File ">$fn" or return "cannot open $fn ($!)"; if ($fh) { - my $ref; - my $key; + my $key = 0; + my $val = undef; my $action; my $t = scalar localtime; - print $fh "#!/usr/bin/perl + print $fh q{#!/usr/bin/perl # # The exported userfile for a DXSpider System # # Input file: $filename # Time: $t # + +package main; + +# search local then perl directories +BEGIN { + umask 002; + + # root of directory tree for this system + $root = "/spider"; + $root = $ENV{'DXSPIDER_ROOT'} if $ENV{'DXSPIDER_ROOT'}; + + unshift @INC, "$root/perl"; # this IS the right way round! + unshift @INC, "$root/local"; + + # try to detect a lockfile (this isn't atomic but + # should do for now + $lockfn = "$root/perl/cluster.lck"; # lock file name + if (-e $lockfn) { + open(CLLOCK, "$lockfn") or die "Can't open Lockfile ($lockfn) $!"; + my $pid = ; + chomp $pid; + die "Lockfile ($lockfn) and process $pid exists - cluster must be stopped first\n" if kill 0, $pid; + close CLLOCK; + } +} package DXUser; -%u = ( -"; +use DXVars; +use DXUser; - for ($action = R_FIRST; !$dbm->seq($key, $ref, $action); $action = R_NEXT) { - print $fh "'$key' => $ref,\n"; - ++$count; +if (@ARGV) { + $main::userfn = shift @ARGV; + print "user filename now $userfn\n"; +} + +DXUser->del_file($main::userfn); +DXUser->init($main::userfn, 1); +%u = (); +my $count = 0; +my $err = 0; +while () { + chomp; + my @f = split /\t/; + my $ref = decode($f[1]); + if ($ref) { + $ref->put(); + $count++; + } else { + print "# Error: $f[0]\t$f[1]\n"; + $err++ + } +} +DXUser->sync; DXUser->finish; +print "There are $count user records and $err errors\n"; +}; + print $fh "__DATA__\n"; + + for ($action = R_FIRST; !$dbm->seq($key, $val, $action); $action = R_NEXT) { + if (!is_callsign($key) || $key =~ /^0/) { + Log('DXCommand', "Export Error1: $key\t$val"); + eval {$dbm->del($key)}; + dbg(carp("Export Error1: $key\t$val\n$@")) if $@; + ++$err; + next; + } + my $ref = decode($val); + if ($ref) { + print $fh "$key\t" . $ref->encode . "\n"; + ++$count; + } else { + Log('DXCommand', "Export Error2: $key\t$val"); + eval {$dbm->del($key)}; + dbg(carp("Export Error2: $key\t$val\n$@")) if $@; + ++$err; + } } - print $fh ");\n#\n# there were $count records\n#\n"; - $fh->close; - } - return $count; + $fh->close; + } + return "$count Users $err Errors ('sh/log Export' for details)"; } # @@ -436,12 +575,32 @@ sub wantgrid return _want('grid', @_); } +sub wantemail +{ + return _want('email', @_); +} + +sub wantann_talk +{ + return _want('ann_talk', @_); +} + +sub wantpc16 +{ + return _want('pc16', @_); +} + +sub wantsendpc16 +{ + return _want('sendpc16', @_); +} + sub wantlogininfo { my $self = shift; - my $n = shift; - $self->{wantlogininfo} = $n if $n; - return exists $self->{wantlogininfo} ? $self->{wantlogininfo} : 0; + my $val = shift; + $self->{wantlogininfo} = $val if defined $val; + return $self->{wantlogininfo}; } sub is_node @@ -491,6 +650,18 @@ sub is_ak1a my $self = shift; return $self->{sort} eq 'A'; } + +sub unset_passwd +{ + my $self = shift; + delete $self->{passwd}; +} + +sub unset_passphrase +{ + my $self = shift; + delete $self->{passphrase}; +} 1; __END__