Updates: Allow automatic display of keys/Copy button ack
This commit is contained in:
@@ -26,50 +26,13 @@ class Index extends Action
|
||||
public function execute()
|
||||
{
|
||||
$action = $this->getRequest()->getParam('action');
|
||||
$isRunning = $this->tunnelStatus->isRunning();
|
||||
$wantJson = $this->isTunnelAjaxRequest();
|
||||
|
||||
if ($action === 'start') {
|
||||
if ($isRunning) {
|
||||
$this->messageManager->addErrorMessage(__('Tunnel is already running.'));
|
||||
return $this->_redirect('*/*/index');
|
||||
}
|
||||
$secure = (bool) $this->scopeConfig->getValue('magesail/settings/mode');
|
||||
$port = $this->scopeConfig->getValue('magesail/settings/port') ?: 80;
|
||||
$port = filter_var($port, FILTER_VALIDATE_INT);
|
||||
if (!$port || !\in_array($port, [80, 443], true)) {
|
||||
$this->messageManager->addErrorMessage(__('Invalid port. Must be 80 or 443.'));
|
||||
return $this->_redirect('*/*/index');
|
||||
}
|
||||
$result = $this->tunnelManager->start((int) $port, $secure);
|
||||
if ($result['ok']) {
|
||||
$this->magesailLog->add(sprintf('Tunnel started PID %s port %s', $result['pid'], $port));
|
||||
$this->messageManager->addSuccessMessage(__(
|
||||
'Tunnel started (PID: %1). Key will appear once ready. Logs: %2',
|
||||
$result['pid'],
|
||||
$this->tunnelStatus->getLogFilePath()
|
||||
));
|
||||
} else {
|
||||
$msg = match ($result['error'] ?? '') {
|
||||
'already_running' => __('Tunnel is already running.'),
|
||||
'invalid_port' => __('Invalid port. Must be 80 or 443.'),
|
||||
'pid_capture_failed' => __('Failed to capture PID: %1', $result['detail'] ?? ''),
|
||||
default => __('Error starting tunnel: %1', $result['error'] ?? 'unknown'),
|
||||
};
|
||||
$this->messageManager->addErrorMessage($msg);
|
||||
$this->magesailLog->add('Start failed: ' . ($result['error'] ?? 'unknown'));
|
||||
}
|
||||
} elseif ($action === 'stop') {
|
||||
$stop = $this->tunnelManager->stop();
|
||||
if ($stop['ok']) {
|
||||
$this->magesailLog->add('Tunnel stopped');
|
||||
$this->messageManager->addSuccessMessage(__('Tunnel stopped.'));
|
||||
} else {
|
||||
if (($stop['error'] ?? '') === 'not_running') {
|
||||
$this->messageManager->addNoticeMessage(__('No tunnel running.'));
|
||||
} else {
|
||||
$this->messageManager->addErrorMessage(__('Error stopping tunnel: %1', $stop['error'] ?? ''));
|
||||
}
|
||||
}
|
||||
return $this->handleStart($wantJson);
|
||||
}
|
||||
if ($action === 'stop') {
|
||||
return $this->handleStop($wantJson);
|
||||
}
|
||||
|
||||
$resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE);
|
||||
@@ -78,6 +41,94 @@ class Index extends Action
|
||||
return $resultPage;
|
||||
}
|
||||
|
||||
private function isTunnelAjaxRequest(): bool
|
||||
{
|
||||
return strtolower((string) $this->getRequest()->getHeader('X-Requested-With')) === 'xmlhttprequest'
|
||||
|| (string) $this->getRequest()->getParam('ajax') === '1';
|
||||
}
|
||||
|
||||
private function jsonPayload(bool $ok, string $message = '', array $extra = [])
|
||||
{
|
||||
$json = $this->resultFactory->create(ResultFactory::TYPE_JSON);
|
||||
$json->setData(array_merge([
|
||||
'success' => $ok,
|
||||
'message' => $message,
|
||||
'status' => $this->tunnelStatus->getStatus(),
|
||||
], $extra));
|
||||
return $json;
|
||||
}
|
||||
|
||||
private function handleStart(bool $wantJson)
|
||||
{
|
||||
if ($this->tunnelStatus->isRunning()) {
|
||||
if ($wantJson) {
|
||||
return $this->jsonPayload(false, (string) __('Tunnel is already running.'));
|
||||
}
|
||||
$this->messageManager->addErrorMessage(__('Tunnel is already running.'));
|
||||
return $this->_redirect('*/*/index');
|
||||
}
|
||||
$secure = (bool) $this->scopeConfig->getValue('magesail/settings/mode');
|
||||
$port = filter_var($this->scopeConfig->getValue('magesail/settings/port') ?: 80, FILTER_VALIDATE_INT);
|
||||
if (!$port || !\in_array($port, [80, 443], true)) {
|
||||
if ($wantJson) {
|
||||
return $this->jsonPayload(false, (string) __('Invalid port. Must be 80 or 443.'));
|
||||
}
|
||||
$this->messageManager->addErrorMessage(__('Invalid port. Must be 80 or 443.'));
|
||||
return $this->_redirect('*/*/index');
|
||||
}
|
||||
$result = $this->tunnelManager->start((int) $port, $secure);
|
||||
if ($result['ok']) {
|
||||
$this->magesailLog->add(sprintf('Tunnel started PID %s port %s', $result['pid'], $port));
|
||||
$msg = (string) __(
|
||||
'Tunnel started (PID: %1). Key will appear once ready.',
|
||||
$result['pid']
|
||||
);
|
||||
if ($wantJson) {
|
||||
return $this->jsonPayload(true, $msg);
|
||||
}
|
||||
$this->messageManager->addSuccessMessage($msg);
|
||||
return $this->_redirect('*/*/index');
|
||||
} else {
|
||||
$msg = match ($result['error'] ?? '') {
|
||||
'already_running' => (string) __('Tunnel is already running.'),
|
||||
'invalid_port' => (string) __('Invalid port. Must be 80 or 443.'),
|
||||
'pid_capture_failed' => (string) __('Failed to capture PID: %1', $result['detail'] ?? ''),
|
||||
default => (string) __('Error starting tunnel: %1', $result['error'] ?? 'unknown'),
|
||||
};
|
||||
$this->magesailLog->add('Start failed: ' . ($result['error'] ?? 'unknown'));
|
||||
if ($wantJson) {
|
||||
return $this->jsonPayload(false, $msg);
|
||||
}
|
||||
$this->messageManager->addErrorMessage($msg);
|
||||
return $this->_redirect('*/*/index');
|
||||
}
|
||||
}
|
||||
|
||||
private function handleStop(bool $wantJson)
|
||||
{
|
||||
$stop = $this->tunnelManager->stop();
|
||||
if ($stop['ok']) {
|
||||
$this->magesailLog->add('Tunnel stopped');
|
||||
if ($wantJson) {
|
||||
return $this->jsonPayload(true, (string) __('Tunnel stopped.'));
|
||||
}
|
||||
$this->messageManager->addSuccessMessage(__('Tunnel stopped.'));
|
||||
} else {
|
||||
if (($stop['error'] ?? '') === 'not_running') {
|
||||
if ($wantJson) {
|
||||
return $this->jsonPayload(true, (string) __('No tunnel running.'), ['status' => $this->tunnelStatus->getStatus()]);
|
||||
}
|
||||
$this->messageManager->addNoticeMessage(__('No tunnel running.'));
|
||||
} else {
|
||||
if ($wantJson) {
|
||||
return $this->jsonPayload(false, (string) __('Error stopping tunnel: %1', $stop['error'] ?? ''));
|
||||
}
|
||||
$this->messageManager->addErrorMessage(__('Error stopping tunnel: %1', $stop['error'] ?? ''));
|
||||
}
|
||||
}
|
||||
return $wantJson ? $this->jsonPayload($stop['ok'], '') : $this->_redirect('*/*/index');
|
||||
}
|
||||
|
||||
protected function _isAllowed()
|
||||
{
|
||||
return $this->_authorization->isAllowed('MageSail_Magesail::tunnel');
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MageSail\Magesail\Controller\Adminhtml\Tunnel;
|
||||
|
||||
use Magento\Backend\App\Action;
|
||||
use Magento\Backend\App\Action\Context;
|
||||
use Magento\Framework\Controller\ResultFactory;
|
||||
use MageSail\Magesail\Model\TunnelStatus;
|
||||
|
||||
class Logtail extends Action
|
||||
{
|
||||
private const BYTES = 8192;
|
||||
private const LINES = 40;
|
||||
|
||||
public function __construct(
|
||||
Context $context,
|
||||
private readonly TunnelStatus $tunnelStatus
|
||||
) {
|
||||
parent::__construct($context);
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$path = $this->tunnelStatus->getLogFilePath();
|
||||
$lines = [];
|
||||
if (\is_readable($path)) {
|
||||
$size = filesize($path);
|
||||
if ($size !== false && $size > 0) {
|
||||
$fp = fopen($path, 'rb');
|
||||
if ($fp) {
|
||||
$start = max(0, $size - self::BYTES);
|
||||
fseek($fp, $start);
|
||||
if ($start > 0) {
|
||||
fgets($fp);
|
||||
}
|
||||
$chunk = stream_get_contents($fp) ?: '';
|
||||
fclose($fp);
|
||||
$lines = preg_split('/\R/', $chunk) ?: [];
|
||||
$lines = array_values(array_filter($lines, static fn ($l) => $l !== ''));
|
||||
if (\count($lines) > self::LINES) {
|
||||
$lines = \array_slice($lines, -self::LINES);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$json = $this->resultFactory->create(ResultFactory::TYPE_JSON);
|
||||
$json->setData(['lines' => $lines]);
|
||||
return $json;
|
||||
}
|
||||
|
||||
protected function _isAllowed()
|
||||
{
|
||||
return $this->_authorization->isAllowed('MageSail_Magesail::tunnel');
|
||||
}
|
||||
}
|
||||
@@ -19,13 +19,7 @@ class Status extends Action
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$formKey = $this->getRequest()->getParam('form_key');
|
||||
if (!$formKey || $formKey !== $this->_formKey->getFormKey()) {
|
||||
return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData([
|
||||
'error' => true,
|
||||
'message' => 'Invalid form key.',
|
||||
])->setHttpResponseCode(403);
|
||||
}
|
||||
// ACL + admin session protect this; form_key in query was breaking AJAX (encoding / secret key).
|
||||
$resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON);
|
||||
$resultJson->setData($this->tunnelStatus->getStatus());
|
||||
return $resultJson;
|
||||
|
||||
Reference in New Issue
Block a user