Ferreteria/v0.6/clade/IO/Aspect/Connx/Stream/Native/SSH2
Jump to navigation
Jump to search
| ||||||||||||||||||||||||||
About
- Purpose: handles streams created by ssh2* library functions
History
Code
interface iSSH2 extends BaseIface {
#function IsEoF() : bool;
function ErrorStream() : StreamIface;
}
class cSSH2 extends BaseClass implements iSSH2 {
// ++ CONFIG ++ //
const OBUFF_SIZE = 1024*64; // 64k output buffer
public function SType() : string { return 'ssh2 stream'; }
// -- CONFIG -- //
// ++ SETTINGS ++ //
private $bEoSWorks = TRUE;
public function UseEoS(?bool $b=NULL) : bool { return is_bool($b) ? ($this->bEoSWorks = $b) : $this->bEoSWorks; }
// ++ ADMIN: lifecycle ++ //
protected function ActualOpen() : OpOpenIface { return OpOpenClass::AsOkay(); }
protected function ActualShut() : OpShutIface { return OpShutClass::AsOkay(); }
// ++ ADMIN: state ++ //
/*
// NEW
protected function IsEoS() : bool {
if ($this->UseEoS()) {
return feof($this->RNative());
} else {
return $this->GotEmpty();
}
}
*/
#public function IsEoF() : bool { return $this->IsEoS(); }
private $bGotEmpty = FALSE;
protected function GotEmpty(?bool $b=NULL) : bool { return is_bool($b) ? ($this->bGotEmpty = $b) : $this->bGotEmpty; }
// OVERRIDE
#public function HasEnded() : bool { return $this->IsEoF(); }
#public function HasMore() : bool { return !$this->IsEoS(); }
public function HasMore() : bool {
if ($this->UseEoS()) {
$isEoS = feof($this->RNative());
} else {
$isEoS = $this->GotEmpty();
}
return !$isEoS;
}
// ++ ADMIN: aux streams ++ //
public function ErrorStream() : StreamIface {
$rMain = $this->RNative();
// 2026/02/06 there are complications with this, apparently; see docs for ssh2_exec()
$rAux = ssh2_fetch_stream($rMain, SSH2_STREAM_STDERR);
$oStream = StreamClass::FromNative($rAux);
return $oStream;
}
public function InOutStream() : StreamIface {
$rMain = $this->RNative();
$rAux = ssh2_fetch_stream($rMain, SSH2_STREAM_STDIO);
$oStream = StreamClass::FromNative($rAux);
return $oStream;
}
// -- ADMIN -- //
// ++ I/O ++ //
public function PullBytes(int $nMax=NULL) : OpDataIface {
if ($this->HasMore()) {
$r = $this->RNative();
$sRead = @stream_get_contents($r,$nMax);
}
$oOp = $this->OOpData();
$ok = is_string($sRead);
$oOp->SetOkay($ok);
if ($ok) {
if ($sRead === '') {
$oOp->QData()->ZapIt();
$this->GotEmpty(TRUE);
#$this->AmHere('GOT EMPTY STRING; GotEmpty(): ['.$this->GotEmpty().'] UseEoS()=['.$this->UseEoS().'] IsEoS=['.$this->IsEoS().']');
} else {
$oOp->QData()->SetIt($sRead);
$this->nPulled += strlen($sRead);
}
}
return $oOp;
}
/* 2026-03-06 These assume an internal buffer, which now seems like a bad idea.
public function PullBytes(int $nMax=NULL) : OpDataIface {
// If buffer empty, try to read more:
#$this->AmHereShort('BUFFER EMPTY? ['.$this->IsBufferEmpty().']');
if ($this->IsBufferEmpty()) {
$this->ReadBytes($nMax);
}
// Buffer contents represents what we know we have available:
$sBuff = $this->sBuff;
$oOp = $this->OOpData();
$oOp->SetOkay(is_string($sBuff));
if (is_string($sBuff)) {
if ($sBuff === '') {
$oOp->QData()->ZapIt();
} else {
$oOp->QData()->SetIt($sBuff);
$this->nPulled += strlen($sBuff);
#$this->AmHereShort('PULLING ['.strlen($sBuff).'] -> ['.$this->nPulled.']');
$this->sBuff = NULL;
}
} else {
$this->IsEoS(TRUE);
}
return $oOp;
}
protected function ReadBytes(int $nMax=NULL) : void {
if ($this->HasMore()) {
$r = $this->RNative();
$sRead = @stream_get_contents($r,$nMax);
$this->sBuff = $sRead;
#$this->AmHereShort("READ ≤ [$nMax] BYTES");
$this->IsEoS(empty($sRead));
}
}
*/
// 2025-12-25 This may not work for all stream-types. (Was this re-copied back from SSH2?)
public function PushBytes(string $s) : OpDataIface {
//* 2026-01-02 buffering version -- buffering functionality has been moved to Stream\Buffer\Sender
$sRem = $s;
$r = $this->RNative();
$ok = TRUE;
while ($ok && ($sRem !== '')) {
$sNow = substr($sRem,0,self::OBUFF_SIZE); // get burst to send
$ok = fwrite($r,$s); // try to send it
$n = strlen($s); // how much got sent?
$sRem = substr($sRem,$n); // remove bytes-sent from local buffer
}
//* /
$ok = fwrite($r,$s); // try to send it
// 2026-01-17 fwrite() supposedly works on non-file streams too.
$oOp = $this->OOpData();
$oOp->SetOkay($ok);
return $oOp;
}
// -- I/O -- //
// ++ DISPLAY ++ //
/* 2026-03-06 moved to Stream parent
public function DescribeInline() : string {
$oPanel = CableAdmin::OPanel();
$sID = $this->ObjectID();
$nPull = $this->NPulledCount();
$nPush = $this->NPushedCount();
$sPull = number_format($nPull);
$sPush = number_format($nPush);
$sEoS = 'EoS:'.(isset($this->isEoS) ? ($this->isEoS ? 'Y' : 'n') : 'n/a');
$sType = $this->SType();
return "(id$sID) bytes: $sPull -> $sPush $sEoS [$sType]";
}
*/
public function VIEW_Readout() : string { return $this->DescribeInline(); }
/* 2026-03-05 old version
public function VIEW_Readout() : string {
$nTot = $this->NPulledCount();
$oPanel = CableAdmin::OPanel();
$sTot = $oPanel->FormatOfInt()->format($nTot);
$sS = (($nTot === 1) ? '' : 's');
$sType = $this->SType();
return "[$sType] $nTot byte$sS spent";
}
*/
// -- DISPLAY -- //
}