scopeConfig->getValue(self::XML_SCRIPT_PATH)); if ($configured !== '') { return $configured; } return BP . '/' . self::DEFAULT_SCRIPT_REL; } /** * @return array{ok: bool, pid?: int, error?: string} */ public function start(int $port, bool $secure): array { if ($this->tunnelStatus->isRunning()) { return ['ok' => false, 'error' => 'already_running']; } if (!\in_array($port, [80, 443], true)) { return ['ok' => false, 'error' => 'invalid_port']; } $scriptDir = $this->getScriptDir(); $keyFile = $this->tunnelStatus->getKeyFilePath(); $logFile = $this->tunnelStatus->getLogFilePath(); $pidFile = $this->tunnelStatus->getPidFilePath(); $jsArgs = json_encode([ 'port' => $port, 'secure' => $secure, 'keyfile' => $keyFile, 'logfile' => $logFile, ], JSON_THROW_ON_ERROR); $arg = escapeshellarg($jsArgs); $dir = escapeshellarg($scriptDir); $log = escapeshellarg($logFile); $fullCmd = "cd $dir && nohup node start-server.js $arg > $log 2>&1 & echo \$!"; try { $output = $this->shell->execute($fullCmd); $pid = (int) trim($output); if ($pid > 0) { file_put_contents($pidFile, (string) $pid); $this->eventManager->dispatch('magesail_tunnel_start_after', [ 'pid' => $pid, 'port' => $port, 'secure' => $secure, ]); return ['ok' => true, 'pid' => $pid]; } return ['ok' => false, 'error' => 'pid_capture_failed', 'detail' => $output]; } catch (\Throwable $e) { return ['ok' => false, 'error' => $e->getMessage()]; } } /** * @return array{ok: bool, error?: string} */ public function stop(): array { $pidFile = $this->tunnelStatus->getPidFilePath(); $keyFile = $this->tunnelStatus->getKeyFilePath(); if (!\is_file($pidFile)) { return ['ok' => false, 'error' => 'not_running']; } $pid = (int) trim((string) file_get_contents($pidFile)); if ($pid <= 0 || !$this->tunnelStatus->isProcessAlive($pid)) { @unlink($pidFile); if (\is_file($keyFile)) { @unlink($keyFile); } return ['ok' => false, 'error' => 'not_running']; } try { $this->shell->execute('kill %s', [$pid]); @unlink($pidFile); if (\is_file($keyFile)) { @unlink($keyFile); } $this->eventManager->dispatch('magesail_tunnel_stop_after', ['pid' => $pid]); return ['ok' => true]; } catch (\Throwable $e) { return ['ok' => false, 'error' => $e->getMessage()]; } } }