Documented Commands.State & Commands.System
This commit is contained in:
31
FAQ.md
31
FAQ.md
@@ -275,22 +275,21 @@ $ docker exec -ti watchstate console system:env
|
||||
|
||||
These environment variables relates to the tool itself, you can load them via the recommended methods.
|
||||
|
||||
| Key | Type | Description | Default |
|
||||
|--------------------------|---------|-------------------------------------------------------------------------|--------------------|
|
||||
| WS_DATA_PATH | string | Where to store main data. (config, db). | `${BASE_PATH}/var` |
|
||||
| WS_TMP_DIR | string | Where to store temp data. (logs, cache) | `${WS_DATA_PATH}` |
|
||||
| WS_TZ | string | Set timezone. | `UTC` |
|
||||
| WS_CRON_{TASK} | bool | Enable {task} task. Value casted to bool. | `false` |
|
||||
| WS_CRON_{TASK}_AT | string | When to run {task} task. Valid Cron Expression Expected. | `*/1 * * * *` |
|
||||
| WS_CRON_{TASK}_ARGS | string | Flags to pass to the {task} command. | `-v` |
|
||||
| WS_LOGS_CONTEXT | bool | Add context to console output messages. | `false` |
|
||||
| WS_LOGGER_FILE_ENABLE | bool | Save logs to file. | `true` |
|
||||
| WS_LOGGER_FILE_LEVEL | string | File Logger Level. | `ERROR` |
|
||||
| WS_WEBHOOK_DUMP_REQUEST | bool | If enabled, will dump all received requests. | `false` |
|
||||
| WS_EPISODES_DISABLE_GUID | bool | Disable external id parsing for episodes and rely on relative ids. | `true` |
|
||||
| WS_TRUST_PROXY | bool | Trust `WS_TRUST_HEADER` ip. Value casted to bool. | `false` |
|
||||
| WS_TRUST_HEADER | string | Which header contain user true IP. | `X-Forwarded-For` |
|
||||
| WS_LIBRARY_SEGMENT | integer | Paginate backend library items request. Per request get total X number. | `1000` |
|
||||
| Key | Type | Description | Default |
|
||||
|-------------------------|---------|-------------------------------------------------------------------------|--------------------|
|
||||
| WS_DATA_PATH | string | Where to store main data. (config, db). | `${BASE_PATH}/var` |
|
||||
| WS_TMP_DIR | string | Where to store temp data. (logs, cache) | `${WS_DATA_PATH}` |
|
||||
| WS_TZ | string | Set timezone. | `UTC` |
|
||||
| WS_CRON_{TASK} | bool | Enable {task} task. Value casted to bool. | `false` |
|
||||
| WS_CRON_{TASK}_AT | string | When to run {task} task. Valid Cron Expression Expected. | `*/1 * * * *` |
|
||||
| WS_CRON_{TASK}_ARGS | string | Flags to pass to the {task} command. | `-v` |
|
||||
| WS_LOGS_CONTEXT | bool | Add context to console output messages. | `false` |
|
||||
| WS_LOGGER_FILE_ENABLE | bool | Save logs to file. | `true` |
|
||||
| WS_LOGGER_FILE_LEVEL | string | File Logger Level. | `ERROR` |
|
||||
| WS_WEBHOOK_DUMP_REQUEST | bool | If enabled, will dump all received requests. | `false` |
|
||||
| WS_TRUST_PROXY | bool | Trust `WS_TRUST_HEADER` ip. Value casted to bool. | `false` |
|
||||
| WS_TRUST_HEADER | string | Which header contain user true IP. | `X-Forwarded-For` |
|
||||
| WS_LIBRARY_SEGMENT | integer | Paginate backend library items request. Per request get total X number. | `1000` |
|
||||
|
||||
> [!IMPORTANT]
|
||||
> for environment variables that has `{TASK}` tag, you **MUST** replace it with one
|
||||
|
||||
@@ -17,13 +17,19 @@ use App\Libs\Routable;
|
||||
use App\Libs\Stream;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class ExportCommand
|
||||
*
|
||||
* Command for exporting play state to backends.
|
||||
*
|
||||
* @package App\Console\Commands\State
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
class ExportCommand extends Command
|
||||
{
|
||||
@@ -31,6 +37,14 @@ class ExportCommand extends Command
|
||||
|
||||
public const TASK_NAME = 'export';
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param iDB $db The instance of the iDB class.
|
||||
* @param DirectMapper $mapper The instance of the DirectMapper class.
|
||||
* @param QueueRequests $queue The instance of the QueueRequests class.
|
||||
* @param iLogger $logger The instance of the iLogger class.
|
||||
*/
|
||||
public function __construct(
|
||||
private iDB $db,
|
||||
private DirectMapper $mapper,
|
||||
@@ -43,6 +57,9 @@ class ExportCommand extends Command
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -100,15 +117,30 @@ class ExportCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the command is not running in parallel.
|
||||
*
|
||||
* @param InputInterface $input The input object containing the command data.
|
||||
* @param OutputInterface $output The output object for displaying command output.
|
||||
*
|
||||
* @return int The exit code of the command execution.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
return $this->single(fn(): int => $this->process($input, $output), $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the command by pulling and comparing status and then pushing.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function process(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (null !== ($logfile = $input->getOption('logfile')) && true === ($this->logger instanceof Logger)) {
|
||||
$this->logger->pushHandler(new StreamLogHandler(new Stream(fopen($logfile, 'a')), $output));
|
||||
$this->logger->pushHandler(new StreamLogHandler(new Stream($logfile, 'a'), $output));
|
||||
}
|
||||
|
||||
// -- Use Custom servers.yaml file.
|
||||
@@ -116,7 +148,7 @@ class ExportCommand extends Command
|
||||
try {
|
||||
$custom = true;
|
||||
Config::save('servers', Yaml::parseFile($this->checkCustomBackendsFile($config)));
|
||||
} catch (RuntimeException $e) {
|
||||
} catch (\App\Libs\Exceptions\RuntimeException $e) {
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
return self::FAILURE;
|
||||
}
|
||||
@@ -448,13 +480,22 @@ class ExportCommand extends Command
|
||||
copy($config, $config . '.bak');
|
||||
}
|
||||
|
||||
file_put_contents($config, Yaml::dump(Config::get('servers', []), 8, 2));
|
||||
$stream = new Stream($config, 'w');
|
||||
$stream->write(Yaml::dump(Config::get('servers', []), 8, 2));
|
||||
$stream->close();
|
||||
}
|
||||
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push entities to backends if applicable.
|
||||
*
|
||||
* @param array $backends An array of backends.
|
||||
* @param array $entities An array of entities to be pushed.
|
||||
*
|
||||
* @return int The success status code.
|
||||
*/
|
||||
protected function push(array $backends, array $entities): int
|
||||
{
|
||||
$this->logger->notice('Push mode start.', [
|
||||
@@ -477,10 +518,10 @@ class ExportCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull and compare status and then push.
|
||||
* Fallback to export mode if push mode is not supported for the backend.
|
||||
*
|
||||
* @param array $backends
|
||||
* @param InputInterface $input
|
||||
* @param array $backends An array of backends to export data to.
|
||||
* @param InputInterface $input The input containing export options.
|
||||
*/
|
||||
protected function export(array $backends, InputInterface $input): void
|
||||
{
|
||||
|
||||
@@ -20,7 +20,6 @@ use App\Libs\Routable;
|
||||
use App\Libs\Stream;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -30,6 +29,11 @@ use Symfony\Component\Yaml\Yaml;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class ImportCommand
|
||||
*
|
||||
* This command imports metadata and play state of items from backends and updates the local database.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
class ImportCommand extends Command
|
||||
{
|
||||
@@ -37,6 +41,13 @@ class ImportCommand extends Command
|
||||
|
||||
public const TASK_NAME = 'import';
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param iDB $db The database interface object.
|
||||
* @param iImport $mapper The import interface object.
|
||||
* @param iLogger $logger The logger interface object.
|
||||
*/
|
||||
public function __construct(private iDB $db, private iImport $mapper, private iLogger $logger)
|
||||
{
|
||||
set_time_limit(0);
|
||||
@@ -45,6 +56,9 @@ class ImportCommand extends Command
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the method.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -201,15 +215,31 @@ class ImportCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the command is not running in parallel.
|
||||
*
|
||||
* @param InputInterface $input The input interface object.
|
||||
* @param OutputInterface $output The output interface object.
|
||||
*
|
||||
* @return int The status code of the command execution.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
return $this->single(fn(): int => $this->process($input, $output), $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the state from the backends.
|
||||
*
|
||||
* @param InputInterface $input The input interface object.
|
||||
* @param OutputInterface $output The output interface object.
|
||||
*
|
||||
* @return int The return status code.
|
||||
*/
|
||||
protected function process(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (null !== ($logfile = $input->getOption('logfile')) && true === ($this->logger instanceof Logger)) {
|
||||
$this->logger->pushHandler(new StreamLogHandler(new Stream(fopen($logfile, 'a')), $output));
|
||||
$this->logger->pushHandler(new StreamLogHandler(new Stream($logfile, 'a'), $output));
|
||||
}
|
||||
|
||||
// -- Use Custom servers.yaml file.
|
||||
@@ -217,7 +247,7 @@ class ImportCommand extends Command
|
||||
try {
|
||||
$custom = true;
|
||||
Config::save('servers', Yaml::parseFile($this->checkCustomBackendsFile($config)));
|
||||
} catch (RuntimeException $e) {
|
||||
} catch (\App\Libs\Exceptions\RuntimeException $e) {
|
||||
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
|
||||
return self::FAILURE;
|
||||
}
|
||||
@@ -482,7 +512,9 @@ class ImportCommand extends Command
|
||||
copy($config, $config . '.bak');
|
||||
}
|
||||
|
||||
file_put_contents($config, Yaml::dump(Config::get('servers', []), 8, 2));
|
||||
$stream = new Stream($config, 'w');
|
||||
$stream->write(Yaml::dump(Config::get('servers', []), 8, 2));
|
||||
$stream->close();
|
||||
}
|
||||
|
||||
if ($input->getOption('show-messages')) {
|
||||
|
||||
@@ -13,11 +13,21 @@ use App\Libs\QueueRequests;
|
||||
use App\Libs\Routable;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Psr\SimpleCache\CacheInterface as iCache;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class ProgressCommand
|
||||
*
|
||||
* This command is used to push user watch progress to export enabled backends.
|
||||
* It should not be run manually and should be scheduled to run as a task.
|
||||
*
|
||||
* This command requires the watch progress metadata to be already saved in the database.
|
||||
* If no metadata is available for a backend,
|
||||
* the watch progress update won't be sent to that backend
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
class ProgressCommand extends Command
|
||||
{
|
||||
@@ -25,6 +35,14 @@ class ProgressCommand extends Command
|
||||
|
||||
public const TASK_NAME = 'progress';
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param iLogger $logger The logger instance.
|
||||
* @param iCache $cache The cache instance.
|
||||
* @param iDB $db The database instance.
|
||||
* @param QueueRequests $queue The queue requests instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private iLogger $logger,
|
||||
private iCache $cache,
|
||||
@@ -37,6 +55,9 @@ class ProgressCommand extends Command
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -69,10 +90,12 @@ class ProgressCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the command is not running in parallel.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Psr\Cache\InvalidArgumentException if the cache key is not a legal value
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
@@ -80,7 +103,12 @@ class ProgressCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
* Run the command.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
* @return int Returns the status code.
|
||||
* @throws \Psr\Cache\InvalidArgumentException if the cache key is not a legal value
|
||||
*/
|
||||
protected function process(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
@@ -219,7 +247,7 @@ class ProgressCommand extends Command
|
||||
...$context,
|
||||
'status_code' => $response->getStatusCode(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error(
|
||||
message: 'SYSTEM: Exception [{error.kind}] was thrown unhandled during [{backend}] request to change watch progress of {item.type} [{item.title}]. Error [{error.message} @ {error.file}:{error.line}].',
|
||||
context: [
|
||||
@@ -266,12 +294,13 @@ class ProgressCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* List Items.
|
||||
* Renders and displays a list of items based on the specified output mode.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @param array<iState> $items
|
||||
* @return int
|
||||
* @param InputInterface $input The input interface object.
|
||||
* @param OutputInterface $output The output interface object.
|
||||
* @param array $items An array of items to be listed.
|
||||
*
|
||||
* @return int The status code indicating the success of the method execution.
|
||||
*/
|
||||
private function listItems(InputInterface $input, OutputInterface $output, array $items): int
|
||||
{
|
||||
|
||||
@@ -14,11 +14,17 @@ use App\Libs\QueueRequests;
|
||||
use App\Libs\Routable;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Psr\SimpleCache\CacheInterface as iCache;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class PushCommand
|
||||
*
|
||||
* This class represents a command that pushes webhook queued events.
|
||||
* It sends change play state requests to the supported backends.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
class PushCommand extends Command
|
||||
{
|
||||
@@ -26,6 +32,16 @@ class PushCommand extends Command
|
||||
|
||||
public const TASK_NAME = 'push';
|
||||
|
||||
/**
|
||||
* Constructor for the given class.
|
||||
*
|
||||
* @param iLogger $logger The logger instance.
|
||||
* @param iCache $cache The cache instance.
|
||||
* @param iDB $db The database instance.
|
||||
* @param QueueRequests $queue The queue instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
private iLogger $logger,
|
||||
private iCache $cache,
|
||||
@@ -38,6 +54,9 @@ class PushCommand extends Command
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -68,10 +87,13 @@ class PushCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
* @throws InvalidArgumentException
|
||||
* Make sure the command is not running in parallel.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int Returns the process result status code.
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException if the cache key is not a legal value.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
@@ -79,7 +101,12 @@ class PushCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
* Process the queue items and send change play state requests to the supported backends.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
*
|
||||
* @return int Returns the process result status code.
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException if the cache key is not a legal value.
|
||||
*/
|
||||
protected function process(InputInterface $input): int
|
||||
{
|
||||
@@ -197,7 +224,7 @@ class PushCommand extends Command
|
||||
}
|
||||
|
||||
$this->logger->notice('SYSTEM: Marked [{backend}] [{item.title}] as [{play_state}].', $context);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error(
|
||||
message: 'SYSTEM: Exception [{error.kind}] was thrown unhandled during [{backend}] request to change play state of {item.type} [{item.title}]. Error [{error.message} @ {error.file}:{error.line}].',
|
||||
context: [
|
||||
|
||||
@@ -12,13 +12,19 @@ use App\Libs\Options;
|
||||
use App\Libs\Routable;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Psr\SimpleCache\CacheInterface as iCache;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class RequestsCommand
|
||||
*
|
||||
* This class is responsible for processing queued HTTP requests.
|
||||
*
|
||||
* @package Your\Namespace
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
class RequestsCommand extends Command
|
||||
{
|
||||
@@ -26,6 +32,13 @@ class RequestsCommand extends Command
|
||||
|
||||
public const TASK_NAME = 'requests';
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param iLogger $logger The logger object.
|
||||
* @param iCache $cache The cache object.
|
||||
* @param DirectMapper $mapper The DirectMapper object.
|
||||
*/
|
||||
public function __construct(private iLogger $logger, private iCache $cache, private DirectMapper $mapper)
|
||||
{
|
||||
set_time_limit(0);
|
||||
@@ -34,6 +47,9 @@ class RequestsCommand extends Command
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -46,10 +62,13 @@ class RequestsCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
* @throws InvalidArgumentException
|
||||
* Make sure the command is not running in parallel.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int The exit code of the command.
|
||||
* @throws \Psr\Cache\InvalidArgumentException if the $key string is not a legal value
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
@@ -57,7 +76,13 @@ class RequestsCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
* Run the command.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int The exit code of the command.
|
||||
* @throws \Psr\Cache\InvalidArgumentException if the $key string is not a legal value
|
||||
*/
|
||||
protected function process(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
@@ -155,12 +180,13 @@ class RequestsCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* List Items.
|
||||
* Lists items based on the provided input and output.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @param array $requests
|
||||
* @return int
|
||||
* @param InputInterface $input The input interface object.
|
||||
* @param OutputInterface $output The output interface object.
|
||||
* @param array $requests The array of requests.
|
||||
*
|
||||
* @return int Returns the success status code.
|
||||
*/
|
||||
private function listItems(InputInterface $input, OutputInterface $output, array $requests): int
|
||||
{
|
||||
|
||||
@@ -10,11 +10,19 @@ use App\Libs\Routable;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class EnvCommand
|
||||
*
|
||||
* This command displays the environment variables that were loaded during the execution of the tool.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class EnvCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:env';
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -78,13 +86,21 @@ final class EnvCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the command.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int The exit code.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$mode = $input->getOption('output');
|
||||
$keys = [];
|
||||
|
||||
foreach (getenv() as $key => $val) {
|
||||
if (false === str_starts_with($key, 'WS_')) {
|
||||
if (false === str_starts_with($key, 'WS_') && $key !== 'HTTP_PORT') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,11 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class IndexCommand
|
||||
*
|
||||
* This command ensures that the database has correct indexes.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class IndexCommand extends Command
|
||||
{
|
||||
@@ -19,11 +24,21 @@ final class IndexCommand extends Command
|
||||
|
||||
public const TASK_NAME = 'indexes';
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param iDB $db An instance of the iDB class.
|
||||
*/
|
||||
public function __construct(private iDB $db)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -56,6 +71,14 @@ final class IndexCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a command.
|
||||
*
|
||||
* @param InputInterface $input An instance of the InputInterface interface.
|
||||
* @param OutputInterface $output An instance of the OutputInterface interface.
|
||||
*
|
||||
* @return int The status code indicating the success or failure of the command execution.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->db->ensureIndex([
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace App\Commands\System;
|
||||
|
||||
use App\Command;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Routable;
|
||||
use Exception;
|
||||
use LimitIterator;
|
||||
use SplFileObject;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
@@ -17,19 +17,33 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
|
||||
/**
|
||||
* Class LogsCommand.
|
||||
*
|
||||
* This class is used to view and clear log files.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class LogsCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:logs';
|
||||
|
||||
/**
|
||||
* @var array Constant array containing names of supported log files.
|
||||
*/
|
||||
private const LOG_FILES = [
|
||||
'app',
|
||||
'access',
|
||||
'task'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var int The default limit of how many lines to show.
|
||||
*/
|
||||
public const DEFAULT_LIMIT = 50;
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$defaultDate = makeDate()->format('Ymd');
|
||||
@@ -121,7 +135,15 @@ final class LogsCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* Run the command.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int The exit code of the command.
|
||||
*
|
||||
* @throws InvalidArgumentException If the log type is not one of the supported log files.
|
||||
* @throws InvalidArgumentException If the log date is not in the correct format.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
@@ -132,7 +154,7 @@ final class LogsCommand extends Command
|
||||
$type = $input->getOption('type');
|
||||
|
||||
if (false === in_array($type, self::LOG_FILES)) {
|
||||
throw new \RuntimeException(
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('Log type has to be one of the supported log files [%s].', implode(', ', self::LOG_FILES))
|
||||
);
|
||||
}
|
||||
@@ -140,12 +162,15 @@ final class LogsCommand extends Command
|
||||
$date = $input->getOption('date');
|
||||
|
||||
if (1 !== preg_match('/^\d{8}$/', $date)) {
|
||||
throw new \RuntimeException('Log date must be in [YYYYMMDD] format. For example [20220622].');
|
||||
throw new InvalidArgumentException('Log date must be in [YYYYMMDD] format. For example [20220622].');
|
||||
}
|
||||
|
||||
$limit = (int)$input->getOption('limit');
|
||||
|
||||
$file = sprintf(Config::get('tmpDir') . '/logs/%s.%s.log', $type, $date);
|
||||
$file = r(text: Config::get('tmpDir') . '/logs/{type}.{date}.log', context: [
|
||||
'type' => $type,
|
||||
'date' => $date
|
||||
]);
|
||||
|
||||
if (false === file_exists($file) || filesize($file) < 1) {
|
||||
$output->writeln(
|
||||
@@ -226,6 +251,14 @@ final class LogsCommand extends Command
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the logs.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int The exit code.
|
||||
*/
|
||||
private function listLogs(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$path = fixPath(Config::get('tmpDir') . '/logs');
|
||||
@@ -259,6 +292,15 @@ final class LogsCommand extends Command
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the contents of a log file.
|
||||
*
|
||||
* @param SplFileObject $file The log file object.
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int The exit code.
|
||||
*/
|
||||
private function handleClearLog(SplFileObject $file, InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$logfile = after($file->getRealPath(), Config::get('tmpDir') . '/');
|
||||
@@ -310,6 +352,12 @@ final class LogsCommand extends Command
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the suggestions for the given input.
|
||||
*
|
||||
* @param CompletionInput $input The completion input.
|
||||
* @param CompletionSuggestions $suggestions The completion suggestions.
|
||||
*/
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
parent::complete($input, $suggestions);
|
||||
@@ -329,6 +377,11 @@ final class LogsCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the types of log files.
|
||||
*
|
||||
* @return array The array of available log file types.
|
||||
*/
|
||||
public static function getTypes(): array
|
||||
{
|
||||
return self::LOG_FILES;
|
||||
|
||||
@@ -10,16 +10,29 @@ use App\Libs\Routable;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class MaintenanceCommand
|
||||
*
|
||||
* Runs maintenance tasks on the database.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class MaintenanceCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:db:maintenance';
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param iDB $db The database connection object.
|
||||
*/
|
||||
public function __construct(private iDB $db)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -35,6 +48,14 @@ final class MaintenanceCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command.
|
||||
*
|
||||
* @param InputInterface $input The input interface object.
|
||||
* @param OutputInterface $output The output interface object.
|
||||
*
|
||||
* @return int Returns the exit code.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->db->maintenance();
|
||||
|
||||
@@ -11,16 +11,29 @@ use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class MakeCommand
|
||||
*
|
||||
* This class represents a command to create a database schema migration file.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class MakeCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:db:make';
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param iDB $db The iDB object used for database operations.
|
||||
*/
|
||||
public function __construct(private iDB $db)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -46,16 +59,21 @@ final class MakeCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a command.
|
||||
*
|
||||
* @param InputInterface $input The input object containing command arguments and options.
|
||||
* @param OutputInterface $output The output object used for displaying messages.
|
||||
*
|
||||
* @return int The exit code of the command execution. Returns "SUCCESS" constant value.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$file = $this->db->makeMigration($input->getArgument('filename'));
|
||||
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
'<info>Created new migration at \'%s\'.</info>',
|
||||
after(realpath($file), ROOT_PATH),
|
||||
)
|
||||
);
|
||||
$output->writeln(r(text: "<info>Created new migration file at '{file}'.</info>", context: [
|
||||
'file' => after(realpath($file), ROOT_PATH),
|
||||
]));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
@@ -11,16 +11,30 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class MigrationsCommand
|
||||
*
|
||||
* Database migrations runner.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class MigrationsCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:db:migrations';
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param iDB $db The database connection object.
|
||||
*
|
||||
*/
|
||||
public function __construct(private iDB $db)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -37,7 +51,27 @@ final class MigrationsCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the command is not running in parallel.
|
||||
*
|
||||
* @param InputInterface $input The input object containing the command data.
|
||||
* @param OutputInterface $output The output object for displaying command output.
|
||||
*
|
||||
* @return int The exit code of the command execution.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
return $this->single(fn(): int => $this->process($input), $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the command to migrate the database.
|
||||
*
|
||||
* @param InputInterface $input The input object representing the command inputs.
|
||||
*
|
||||
* @return int The exit code of the command execution.
|
||||
*/
|
||||
protected function process(InputInterface $input): int
|
||||
{
|
||||
$opts = [];
|
||||
|
||||
|
||||
@@ -11,11 +11,22 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class PHPCommand
|
||||
*
|
||||
* This command is used to generate expected values for php.ini and fpm pool worker.
|
||||
* To generate fpm values, use the "--fpm" option.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class PHPCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:php';
|
||||
|
||||
/**
|
||||
* Configures the command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -40,11 +51,25 @@ final class PHPCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command based on the input options.
|
||||
*
|
||||
* @param InputInterface $input The input options.
|
||||
* @param OutputInterface $output The output interface for displaying messages.
|
||||
* @return int The exit code of the command execution.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
return $input->getOption('fpm') ? $this->makeFPM($output) : $this->makeConfig($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the php.ini configuration.
|
||||
*
|
||||
* @param OutputInterface $output The OutputInterface object to write the configuration to.
|
||||
*
|
||||
* @return int The status code indicating the success of the method.
|
||||
*/
|
||||
protected function makeConfig(OutputInterface $output): int
|
||||
{
|
||||
$config = Config::get('php.ini', []);
|
||||
@@ -56,6 +81,13 @@ final class PHPCommand extends Command
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the PHP-FPM configuration.
|
||||
*
|
||||
* @param OutputInterface $output The OutputInterface object to write the configuration to.
|
||||
*
|
||||
* @return int The status code indicating the success of the method.
|
||||
*/
|
||||
protected function makeFPM(OutputInterface $output): int
|
||||
{
|
||||
$config = Config::get('php.fpm', []);
|
||||
@@ -70,6 +102,13 @@ final class PHPCommand extends Command
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape the given value.
|
||||
*
|
||||
* @param mixed $val The value to escape.
|
||||
*
|
||||
* @return mixed The escaped value.
|
||||
*/
|
||||
private function escapeValue(mixed $val): mixed
|
||||
{
|
||||
if (is_bool($val) || is_int($val)) {
|
||||
|
||||
@@ -13,6 +13,12 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class PruneCommand
|
||||
*
|
||||
* This command removes automatically generated files like logs and backups.
|
||||
* It provides an option to run in dry-run mode to see what files will be removed without actually removing them.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class PruneCommand extends Command
|
||||
{
|
||||
@@ -20,11 +26,19 @@ final class PruneCommand extends Command
|
||||
|
||||
public const TASK_NAME = 'prune';
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger implementation used for logging.
|
||||
*/
|
||||
public function __construct(private LoggerInterface $logger)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -49,6 +63,14 @@ final class PruneCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command.
|
||||
*
|
||||
* @param InputInterface $input The input interface.
|
||||
* @param OutputInterface $output The output interface.
|
||||
*
|
||||
* @return int The exit status code.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$time = time();
|
||||
@@ -139,5 +161,4 @@ final class PruneCommand extends Command
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ use App\Libs\Entity\StateEntity;
|
||||
use App\Libs\Extends\Date;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Routable;
|
||||
use App\Libs\Stream;
|
||||
use Cron\CronExpression;
|
||||
use Exception;
|
||||
use LimitIterator;
|
||||
use SplFileObject;
|
||||
use Symfony\Component\Console\Input\InputInterface as iInput;
|
||||
@@ -20,16 +20,31 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface as iOutput;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class ReportCommand
|
||||
*
|
||||
* Show basic information for diagnostics.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class ReportCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:report';
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param iDB $db An instance of the iDB class used for database operations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(private iDB $db)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -54,6 +69,14 @@ final class ReportCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display basic information for diagnostics.
|
||||
*
|
||||
* @param iInput $input An instance of the iInput class used for command input.
|
||||
* @param iOutput $output An instance of the iOutput class used for command output.
|
||||
*
|
||||
* @return int Returns the command execution status code.
|
||||
*/
|
||||
protected function runCommand(iInput $input, iOutput $output): int
|
||||
{
|
||||
$output->writeln('<info>[ Basic Report ]</info>' . PHP_EOL);
|
||||
@@ -82,7 +105,7 @@ final class ReportCommand extends Command
|
||||
}
|
||||
|
||||
try {
|
||||
$pid = trim(file_get_contents($pidFile));
|
||||
$pid = trim((string)(new Stream($pidFile)));
|
||||
} catch (Throwable $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
@@ -111,6 +134,14 @@ final class ReportCommand extends Command
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get backends and display information about each backend.
|
||||
*
|
||||
* @param iInput $input An instance of the iInput class used for input operations.
|
||||
* @param iOutput $output An instance of the iOutput class used for output operations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function getBackends(iInput $input, iOutput $output): void
|
||||
{
|
||||
$includeSample = (bool)$input->getOption('include-db-sample');
|
||||
@@ -239,6 +270,13 @@ final class ReportCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the tasks and displays information about each task.
|
||||
*
|
||||
* @param iOutput $output An instance of the iOutput class used for displaying output.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function getTasks(iOutput $output): void
|
||||
{
|
||||
foreach (Config::get('tasks.list', []) as $task) {
|
||||
@@ -274,7 +312,7 @@ final class ReportCommand extends Command
|
||||
'answer' => gmdate(Date::ATOM, $timer->getNextRunDate()->getTimestamp()),
|
||||
])
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
} catch (Throwable $e) {
|
||||
$output->writeln(
|
||||
r('Next Run scheduled failed. <error>{answer}</error>', [
|
||||
'answer' => $e->getMessage(),
|
||||
@@ -288,6 +326,12 @@ final class ReportCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get logs.
|
||||
*
|
||||
* @param iInput $input An instance of the iInput class used for input operations.
|
||||
* @param iOutput $output An instance of the iOutput class used for output operations.
|
||||
*/
|
||||
private function getLogs(iInput $input, iOutput $output): void
|
||||
{
|
||||
$todayAffix = makeDate()->format('Ymd');
|
||||
@@ -307,6 +351,16 @@ final class ReportCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last X lines from log file.
|
||||
*
|
||||
* @param iOutput $output An instance of the iOutput class used for displaying output.
|
||||
* @param string $type The type of the log.
|
||||
* @param string|int $date The date of the log file.
|
||||
* @param int|string $limit The maximum number of lines to display.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function handleLog(iOutput $output, string $type, string|int $date, int|string $limit): void
|
||||
{
|
||||
$logFile = Config::get('tmpDir') . '/logs/' . r(
|
||||
|
||||
@@ -9,11 +9,19 @@ use App\Libs\Routable;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class RoutesCommand
|
||||
*
|
||||
* This command is used to generate routes for commands. It is automatically run on container startup.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class RoutesCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:routes';
|
||||
|
||||
/**
|
||||
* Configures the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -28,6 +36,14 @@ final class RoutesCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command to generate routes.
|
||||
*
|
||||
* @param InputInterface $input The input interface object.
|
||||
* @param OutputInterface $output The output interface object.
|
||||
*
|
||||
* @return int The exit code of the command execution.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
generateRoutes();
|
||||
|
||||
@@ -11,16 +11,35 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class ServerCommand
|
||||
*
|
||||
* This class represents a command that starts a minimal HTTP server.
|
||||
*
|
||||
* @package YourPackage
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class ServerCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'system:server';
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param Server $server The server object to be injected.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(private Server $server)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command options and description.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName(self::ROUTE)
|
||||
@@ -37,6 +56,14 @@ final class ServerCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs Server.
|
||||
*
|
||||
* @param InputInterface $input The input interface object containing command input options.
|
||||
* @param OutputInterface $output The output interface object used to display command output.
|
||||
*
|
||||
* @return int Returns the exit code of the command.
|
||||
*/
|
||||
protected function runCommand(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$host = $input->getOption('interface');
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Command;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Extends\ConsoleOutput;
|
||||
use App\Libs\Routable;
|
||||
use App\Libs\Stream;
|
||||
use Cron\CronExpression;
|
||||
use Exception;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
@@ -17,7 +18,13 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface as iOutput;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class TasksCommand
|
||||
*
|
||||
* Automates the runs of scheduled tasks.
|
||||
*/
|
||||
#[Routable(command: self::ROUTE)]
|
||||
final class TasksCommand extends Command
|
||||
{
|
||||
@@ -26,6 +33,9 @@ final class TasksCommand extends Command
|
||||
private array $logs = [];
|
||||
private array $taskOutput = [];
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
set_time_limit(0);
|
||||
@@ -34,6 +44,9 @@ final class TasksCommand extends Command
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the command.
|
||||
*/
|
||||
protected function configure(): void
|
||||
{
|
||||
$tasksName = implode(
|
||||
@@ -109,7 +122,12 @@ final class TasksCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* If the run option is set, run the tasks, otherwise list available tasks.
|
||||
*
|
||||
* @param iInput $input The input instance.
|
||||
* @param iOutput $output The output instance.
|
||||
*
|
||||
* @return int Returns the exit code of the command.
|
||||
*/
|
||||
protected function runCommand(iInput $input, iOutput $output): int
|
||||
{
|
||||
@@ -117,10 +135,34 @@ final class TasksCommand extends Command
|
||||
return $this->runTasks($input, $output);
|
||||
}
|
||||
|
||||
$this->listTasks($input, $output);
|
||||
$list = [];
|
||||
|
||||
$mode = $input->getOption('output');
|
||||
|
||||
foreach ($this->getTasks() as $task) {
|
||||
$list[] = [
|
||||
'name' => $task['name'],
|
||||
'command' => $task['command'],
|
||||
'options' => $task['args'] ?? '',
|
||||
'timer' => $task['timer']->getExpression(),
|
||||
'description' => $task['description'] ?? '',
|
||||
'NextRun' => $task['next'],
|
||||
];
|
||||
}
|
||||
|
||||
$this->displayContent($list, $output, $mode);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the tasks.
|
||||
*
|
||||
* @param iInput $input The input object.
|
||||
* @param iOutput $output The output object.
|
||||
*
|
||||
* @return int The exit code of the command.
|
||||
*/
|
||||
private function runTasks(iInput $input, iOutput $output): int
|
||||
{
|
||||
$run = [];
|
||||
@@ -232,15 +274,35 @@ final class TasksCommand extends Command
|
||||
}
|
||||
|
||||
if ($input->getOption('save-log') && count($this->logs) >= 1) {
|
||||
if (false !== ($fp = @fopen(Config::get('tasks.logfile'), 'a'))) {
|
||||
fwrite($fp, preg_replace('#\R+#', PHP_EOL, implode(PHP_EOL, $this->logs)) . PHP_EOL . PHP_EOL);
|
||||
fclose($fp);
|
||||
try {
|
||||
$stream = new Stream(Config::get('tasks.logfile'), 'a');
|
||||
$stream->write(preg_replace('#\R+#', PHP_EOL, implode(PHP_EOL, $this->logs)) . PHP_EOL . PHP_EOL);
|
||||
$stream->close();
|
||||
} catch (Throwable $e) {
|
||||
$this->write(r('<error>Failed to open log file [{file}]. Error [{message}].</error>', [
|
||||
'file' => Config::get('tasks.logfile'),
|
||||
'message' => $e->getMessage(),
|
||||
]), $input, $output);
|
||||
|
||||
return self::INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write method.
|
||||
*
|
||||
* Writes a given text to the output with the specified level.
|
||||
* Optionally if the 'save-log' option is set to true, the output will be saved to the logs array.
|
||||
* The logs array will be saved to the log file at the end of the command execution.
|
||||
*
|
||||
* @param string $text The text to write to output.
|
||||
* @param iInput $input The input object.
|
||||
* @param iOutput $output The output object.
|
||||
* @param int $level The level of the output (default: iOutput::OUTPUT_NORMAL).
|
||||
*/
|
||||
private function write(string $text, iInput $input, iOutput $output, int $level = iOutput::OUTPUT_NORMAL): void
|
||||
{
|
||||
assert($output instanceof ConsoleOutput);
|
||||
@@ -252,28 +314,10 @@ final class TasksCommand extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* Get the list of tasks.
|
||||
*
|
||||
* @return array<string, array{name: string, command: string, args: string, description: string, enabled: bool, timer: CronExpression, next: string }> The list of tasks.
|
||||
*/
|
||||
private function listTasks(iInput $input, iOutput $output): void
|
||||
{
|
||||
$list = [];
|
||||
|
||||
$mode = $input->getOption('output');
|
||||
|
||||
foreach ($this->getTasks() as $task) {
|
||||
$list[] = [
|
||||
'name' => $task['name'],
|
||||
'command' => $task['command'],
|
||||
'options' => $task['args'] ?? '',
|
||||
'timer' => $task['timer']->getExpression(),
|
||||
'description' => $task['description'] ?? '',
|
||||
'NextRun' => $task['next'],
|
||||
];
|
||||
}
|
||||
|
||||
$this->displayContent($list, $output, $mode);
|
||||
}
|
||||
|
||||
private function getTasks(): array
|
||||
{
|
||||
$list = [];
|
||||
@@ -302,6 +346,12 @@ final class TasksCommand extends Command
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the input with suggestions if necessary.
|
||||
*
|
||||
* @param CompletionInput $input The completion input object.
|
||||
* @param CompletionSuggestions $suggestions The completion suggestions object.
|
||||
*/
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
parent::complete($input, $suggestions);
|
||||
|
||||
Reference in New Issue
Block a user