+
+
+# 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';
+
+ # just behave normally if something has set the "one-shot" _nospawn in the channel
+ if ($self->{_nospawn}) {
+ eval { @out = $cmdref->(@$args); };
+ if ($@) {
+ DXDebug::dbgprintring(25);
+ push @out, DXDebug::shortmess($@);
+ }
+ return @out;
+ }
+
+ my $fc = Mojo::IOLoop::Subprocess->new;
+# $fc->serializer(\&encode_json);
+# $fc->deserializer(\&decode_json);
+ $fc->run(
+ sub {
+ my $subpro = shift;
+ if (isdbg('progress')) {
+ my $s = qq{line: "$line"};
+ $s .= ", args: " . join(', ', map { defined $_ ? qq{'$_'} : q{'undef'} } @$args) if $args && @$args;
+ dbg($s);
+ }
+ eval { @out = $cmdref->(@$args); };
+ if ($@) {
+ DXDebug::dbgprintring(25);
+ push @out, DXDebug::shortmess($@);
+ }
+ return @out;
+ },
+# $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('progress');
+ });
+
+ return @out;
+}
+
+sub user_count
+{
+ return ($users, $maxusers);
+}