X-Git-Url: http://gb7djk.dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXCommandmode.pm;h=3d5ce0c9f6fb5fa9744939c7e121b8429b06b706;hb=refs%2Fheads%2Fnewdisc;hp=ad9baad05832ed2d087ee479f1d9a84a52acb519;hpb=9fc2ec17088fbff22e825133a4b9b3efe5384df3;p=spider.git diff --git a/perl/DXCommandmode.pm b/perl/DXCommandmode.pm index ad9baad0..3d5ce0c9 100644 --- a/perl/DXCommandmode.pm +++ b/perl/DXCommandmode.pm @@ -13,6 +13,8 @@ package DXCommandmode; @ISA = qw(DXChannel); +require 5.10.1; + use POSIX qw(:math_h); use DXUtil; use DXChannel; @@ -37,6 +39,12 @@ use DB_File; use VE7CC; use DXXml; use AsyncMsg; +use JSON; +use Time::HiRes qw(gettimeofday tv_interval); + +use Mojo::IOLoop; +use Mojo::IOLoop::Subprocess; +use Mojo::UserAgent; use strict; use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase %nothereslug @@ -65,7 +73,7 @@ sub new my $pkg = shift; my $call = shift; # my @rout = $main::routeroot->add_user($call, Route::here(1)); - DXProt::_add_thingy($main::routeroot, [$call, 0, 0, 1, undef, undef, $self->{conn}->peerhost], ); + DXProt::_add_thingy($main::routeroot, [$call, 0, 0, 1, undef, undef, $self->hostname], ); # ALWAYS output the user my $ref = Route::User::get($call); @@ -92,7 +100,7 @@ sub start my $host = $self->{conn}->peerhost; $host ||= "AGW Port #$self->{conn}->{agwport}" if exists $self->{conn}->{agwport}; $host ||= "unknown"; - LogDbg('DXCommand', "$call connected from $host"); + $self->{hostname} = $host; $self->{name} = $name ? $name : $call; $self->send($self->msg('l2',$self->{name})); @@ -103,9 +111,20 @@ sub start $pagelth = $default_pagelth unless defined $pagelth; $self->{pagelth} = $pagelth; ($self->{width}) = $line =~ /width=(\d+)/; $line =~ s/\s*width=\d+\s*//; + if ($line =~ /host=/) { + my ($h) = $line =~ /host=(\d+\.\d+\.\d+\.\d+)/; + $line =~ s/\s*host=\d+\.\d+\.\d+\.\d+// if $h; + unless ($h) { + ($h) = $line =~ /host=([\da..fA..F:]+)/; + $line =~ s/\s*host=[\da..fA..F:]+// if $h; + } + $self->{hostname} = $h if $h; + } $self->{width} = 80 unless $self->{width} && $self->{width} > 80; $self->{consort} = $line; # save the connection type - + + LogDbg('DXCommand', "$call connected from $self->{hostname}"); + # set some necessary flags on the user if they are connecting $self->{beep} = $user->wantbeep; $self->{ann} = $user->wantann; @@ -118,6 +137,7 @@ sub start $self->{ann_talk} = $user->wantann_talk; $self->{here} = 1; $self->{prompt} = $user->prompt if $user->prompt; + $self->{lastmsgpoll} = 0; # sort out new dx spot stuff $user->wantdxcq(0) unless defined $user->{wantdxcq}; @@ -137,7 +157,7 @@ sub start $self->send_motd; # sort out privilege reduction - $self->{priv} = 0 if $line =~ /^(ax|te)/ && !$self->conn->{usedpasswd}; + $self->{priv} = 0 unless $self->{hostname} eq '127.0.0.1' || $self->{hostname} eq '::1' || $self->conn->{usedpasswd}; # get the filters my $nossid = $call; @@ -470,7 +490,7 @@ sub send_ans } # -# this is the thing that runs the command, it is done like this for the +# this is the thing that preps for running the command, it is done like this for the # benefit of remote command execution # @@ -560,7 +580,7 @@ sub process my $dxchan; foreach $dxchan (@dxchan) { - next if $dxchan->sort ne 'U'; + next unless $dxchan->is_user; # send a outstanding message prompt if required if ($t >= $dxchan->lastmsgpoll + $msgpolltime) { @@ -654,7 +674,7 @@ sub broadcast my $s = shift; # the line to be rebroadcast foreach my $dxchan (DXChannel::get_all()) { - next unless $dxchan->{sort} eq 'U'; # only interested in user channels + next unless $dxchan->is_user; # only interested in user channels next if grep $dxchan == $_, @_; $dxchan->send($s); # send it } @@ -663,7 +683,7 @@ sub broadcast # gimme all the users sub get_all { - return grep {$_->{sort} eq 'U'} DXChannel::get_all(); + return grep {$_->is_user} DXChannel::get_all(); } # run a script for this user @@ -793,7 +813,7 @@ sub find_cmd_name { #we have compiled this subroutine already, #it has not been updated on disk, nothing left to do #print STDERR "already compiled $package->handler\n"; - ; + dbg("find_cmd_name: $package cached") if isdbg('command'); } else { my $sub = readfilestr($filename); @@ -1086,7 +1106,7 @@ sub broadcast_debug { my $s = shift; # the line to be rebroadcast - foreach my $dxchan (DXChannel::get_all) { + foreach my $dxchan (DXChannel::get_all_users) { next unless $dxchan->{enhanced} && $dxchan->{senddbg}; if ($dxchan->{gtk}) { $dxchan->send_later('L', dd(['db', $s])); @@ -1162,6 +1182,9 @@ sub import_cmd my @names = readdir(DIR); closedir(DIR); my $name; + + return unless @names; + foreach $name (@names) { next if $name =~ /^\./; @@ -1194,7 +1217,7 @@ sub import_cmd $dxchan->{priv} = $u->priv; $dxchan->{user} = $u; @out = $s->run($dxchan, 1); - $dxchan->{call} = $call; + $dxchan->{call} = $old; $dxchan->{priv} = $priv; $dxchan->{user} = $user; } else { @@ -1241,5 +1264,81 @@ sub send_motd } $self->send_file($motd) if -e $motd; } + + +# Punt off a long running command into a separate process +# +# This is called from commands to run some potentially long running +# function. The process forks and then runs the function and returns +# the result back to the cmd. +# +# NOTE: this merely forks the current process and then runs the cmd in that (current) context. +# IT DOES NOT START UP SOME NEW PROGRAM AND RELIES ON THE FACT THAT IT IS RUNNING DXSPIDER +# THE CURRENT CONTEXT!! +# +# call: $self->spawn_cmd($original_cmd_line, \, [cb => sub{...}], [prefix => "cmd> "], [progress => 0|1], [args => [...]]); +sub spawn_cmd +{ + my $self = shift; + my $line = shift; + my $cmdref = shift; + my $call = $self->{call}; + my %args = @_; + my @out; + + my $cb = delete $args{cb}; + my $prefix = delete $args{prefix}; + my $progress = delete $args{progress}; + my $args = delete $args{args} || []; + my $t0 = [gettimeofday]; + + no strict 'refs'; + + # just behave normally if something has set the "one-shot" _nospawn in the channel + return ($cmdref->(@$args)) if $self->{_nospawn}; + + my $fc = Mojo::IOLoop::Subprocess->new; +# $fc->serializer(\&encode_json); +# $fc->deserializer(\&decode_json); + $fc->run( + sub { + my $subpro = shift; + if (isdbg('spawn_cmd')) { + my $s = "line: $line"; + $s .= ", args: " . join(', ', @$args) if $args && @$args; + } + my @res = $cmdref->(@$args); +# diffms("rcmd from $call 1", $line, $t0, scalar @res) if isdbg('chan'); + return @res; + }, +# $args, + sub { + my ($fc, $err, @res) = @_; + my $dxchan = DXChannel::get($call); + return unless $dxchan; + + if ($err) { + my $s = "DXProt::spawn_cmd: call $call error $err"; + dbg($s) if isdbg('chan'); + $dxchan->send($s); + return; + } + if ($cb) { + # transform output if required + @res = $cb->($dxchan, @res); + } + if (@res) { + if (defined $prefix) { + $dxchan->send(map {"$prefix$_"} @res); + } else { + $dxchan->send(@res); + } + } + diffms("by $call", $line, $t0, scalar @res) if isdbg('chan'); + }); + + return @out; +} + 1; __END__