Ferreteria/v0.6/clade/IO/Aspect/Connx/run/Starter/Remote/SSH2/@fx/DoCommand

From Woozle Writes Code
< Ferreteria‎ | v0.6‎ | clade‎ | IO‎ | Aspect‎ | Connx‎ | run/Starter‎ | Remote‎ | SSH2
Jump to navigation Jump to search

History

  • 2026-01-09 THINKING: It doesn't really make sense to pass in a Stream here, since ssh2_exec() creates one.
    • Also, $oItWent has two Str objects for receiving data -- one for regular replies, one for errors.
    • So: we could either create an ItWent podling that encapsulates reply & error streams, or...
      ...we could just PullBytes() from the returned stream, and stuff them into the reply QStr.
      ...ohbutwait! That must be what $oItWent = $oStream->PullBytes() does, except we need to create & set up $oStream.
  • 2026-01-17 disabled, with the note "This is actually an OVERRIDE -- and the parent properly creates a Process..." -- but it turns out I was confused
  • 2026-01-20 Re-enabled, because Process only executes locally -- so either the command needs to be wrapped, or we need to execute it with ssh2.
    • I guess we need different versions of SSH depending on which way we want to do things. Note that the ssh2 library functions cannot wrap more than once, i.e. you can't use this class to build a chain of ssh connections (A connecting to B and then connecting to C).
  • 2026-03-06 Currently works for schema-list-retrieval, but EoF() reporting fails for schema-export. See 2026/03/06 for work in progress.
  • 2026-03-16 Moved the Canals loop to its own function in Runner: DoInOutLoop().

Code: Current

as of 2026-03-17 (might or might not be working reliably):

#
    public function DoCommand(CLineIface $oCmd) : OpCmdIface {
        $oCmd->QORunner()->SetIt($this);
        $this->Open();  // make sure connection is open (sets RNative())

        $oHints = $oCmd->Hints();
        $sEndHint = $oHints->GetItNz('eos',NULL);
        $useEmpty = ($sEndHint === 'empty'); // TODO: class constant

        $oOpCmd = $this->OOpCmd();
        $oOpCmd->Clear();

        $oProcLecture = $this->StreamFromCommmand($oCmd);
        $oProcLecture->UseEoS(!$useEmpty);
        $this->LectureStream($oProcLecture);

        if (is_object($oProcLecture)) {

            $oCanals = CanalsClass::FromVoid();

            $qoCmdListen = $oCmd->QOListener();  // stream to receive data
            if ($qoCmdListen->HasIt()) {
                $oCodeListen = $qoCmdListen->GetIt();

                $oCanalRecv = ConveyClass::FromPair($oProcLecture,$oCodeListen);
                $oCanals->AddIt($oCanalRecv);

            } else {
                stream_set_blocking($rRecv, TRUE);  // wait for entire output when reading
                $oItWent = $oLecture->PullBytes();
                #echo '** OUTCOME: '.CRLF.$oItWent->VIEW_AsBlock();
            }
            $this->OCanals($oCanals); // make the Canals object publicly available

            $oOpConvey = NULL;

        }
        $this->Shut(); // done with connection for now

        return $oOpCmd;
    }

Code: Removed

2026-03-17

Commented out yesterday, from just under $oOpConvey = NULL:

#
            #$doLoop = $oCmd->DoWait();

            // 2026-03-16 Caller is now responsible for this.
            $doLoop = $oCmd->HasIt();
            $oCanals->Open();

            while ($doLoop) {
                $isGoing = $this->IsRunning();
                if ($isGoing) {
                    $oOpNew = $oCanals->ConveyCheck();
                    if (is_object($oOpConvey)) {
                        $oOpNew->Assimilate($oOpConvey);
                    }
                    $oOpConvey = $oOpNew;

                    $this->OnIterate();
                }
                $doLoop = $isGoing;
            }
            $oCanals->Shut();

            if (is_object($oOpConvey)) {
                $oOpCmd->Assimilate($oOpConvey); // TODO 2026-02-22 review this logic. Maybe CopyFrom() instead?
            }
            $oOpCmd->SetOkay(TRUE); // 2026-03-05 not sure what error conditions might exist here; for now, assume ok

On 2026-03-03, just before rewrite using Canals object (I renamed it instead of commenting it out):

#
    // 2026-03-03 old version, before rewriting to use Canals:
    public function DoCommandV1(CLineIface $oCmd) : OpCmdIface {
        $this->Open();  // make sure connection is open

        $rStrm = $this->RNative();

        $rRecv = ssh2_exec($rStrm, $oCmd->AsString());

        #$doWait = $oCmd->DoWait();
        $doWait = $oCmd->HasIt();
        // 2026-02-25 TODO: implement some way to access the streams from outside when $doWait is FALSE

        $oLecture = StreamClass::FromNative($rRecv);
        #$rErrs = ssh2_fetch_stream($rRecv, SSH2_STREAM_STDERR);  // 2026/02/06 there are complications with this, apparently; see docs for ssh2_exec()

        $qoListen = $oCmd->QOListener();  // stream to receive data
        if ($qoListen->HasIt()) {
            $oListen = $qoListen->GetIt();
            $oConvey = new ConveyClass;
            stream_set_blocking($rRecv, TRUE);  // wait for entire output when reading - TESTING
            $oItWent = $oConvey->ConveyNow($oLecture,$oListen);
        } else {
            stream_set_blocking($rRecv, TRUE);  // wait for entire output when reading
            $oItWent = $oLecture->PullBytes();
            #echo '** OUTCOME: '.CRLF.$oItWent->VIEW_AsBlock();
        }

        $oProcOp = $this->OOpCmd();
        $oProcOp->CopyFrom($oItWent);

        $this->Shut(); // done with connection for now

        return $oProcOp;
    }