extend the Web interface protocol further
[spider.git] / perl / DXCommandmode.pm
index 35c92341d17cbc896a0a64d6941e9a3d156dea77..9a00febbf44ca90c58afabacf49980e10afedb97 100644 (file)
@@ -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,13 @@ use DB_File;
 use VE7CC;
 use DXXml;
 use AsyncMsg;
+use JSON;
+use Time::HiRes qw(gettimeofday tv_interval);
+use Regexp::IPv6 qw($IPv6_re);
+
+use Mojo::IOLoop;
+use Mojo::IOLoop::ForkCall;
+use Mojo::UserAgent;
 
 use strict;
 use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase %nothereslug
@@ -103,6 +112,13 @@ 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=/) {
+               ($self->{hostname}) = $line =~ /host=(\d+\.\d+\.\d+\.\d+)/; $line =~ s/\s*host=\d+\.\d+\.\d+\.\d+//;
+               unless ($self->{hostname}) {
+                       ($self->{hostname}) = $line =~ /host=($IPv6_re)/; 
+            $line =~ s/\s*host=$IPv6_re//;
+               }
+       }
        $self->{width} = 80 unless $self->{width} && $self->{width} > 80;
        $self->{consort} = $line;       # save the connection type
        
@@ -118,6 +134,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};
@@ -560,7 +577,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 +671,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 +680,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 +810,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 +1103,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 +1179,9 @@ sub import_cmd
        my @names = readdir(DIR);
        closedir(DIR);
        my $name;
+
+       return unless @names;
+       
        foreach $name (@names) {
                next if $name =~ /^\./;
 
@@ -1241,5 +1261,84 @@ sub send_motd
        }
        $self->send_file($motd) if -e $motd;
 }
+
+sub _diffms
+{
+       return unless isdbg('chan');
+       my $call = shift;
+       my $line = shift;
+       my $ta = shift;
+       my $tb = shift || [gettimeofday];
+
+       my $a = int($ta->[0] * 1000) + int($ta->[1] / 1000); 
+       my $b = int($tb->[0] * 1000) + int($tb->[1] / 1000);
+       my $msecs = $b - $a;
+
+       my $s = "forkcall stats: $call '$line' ";
+       $s .= "${msecs}mS";
+       dbg($s);
+}
+
+# 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, \<function>, [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';
+               
+       my $fc = Mojo::IOLoop::ForkCall->new;
+       $fc->serializer(\&encode_json);
+       $fc->deserializer(\&decode_json);
+       $fc->run(
+                        sub {my @args = @_; my @res = $cmdref->(@args); return @res},
+                        $args,
+                        sub {
+                                my ($fc, $err, @res) = @_; 
+                                my $dxchan = DXChannel::get($call);
+                                return unless $dxchan;
+
+                                if (defined $err) {
+                                        my $s = "DXCommand::spawn_cmd: call $call error $err";
+                                        dbg($s) if isdbg('chan');
+                                        $dxchan->send($s);
+                                        return;
+                                }
+                                if ($cb) {
+                                        $cb->($dxchan, @res);
+                                } else {
+                                        return unless @res;
+                                        if (defined $prefix) {
+                                                $dxchan->send(map {"$prefix$_"} @res);
+                                        } else {
+                                                $dxchan->send(@res);
+                                        }
+                                }
+                                _diffms($call, $line, $t0);
+                        });
+       
+       return @out;
+}
+
 1;
 __END__