215 lines
6.7 KiB
PHP
215 lines
6.7 KiB
PHP
<?php
|
|
/**
|
|
* FuzeWorks Async Library
|
|
*
|
|
* The FuzeWorks PHP FrameWork
|
|
*
|
|
* Copyright (C) 2013-2020 TechFuze
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
* @author TechFuze
|
|
* @copyright Copyright (c) 2013 - 2020, TechFuze. (http://techfuze.net)
|
|
* @license https://opensource.org/licenses/MIT MIT License
|
|
*
|
|
* @link http://techfuze.net/fuzeworks
|
|
* @since Version 1.0.0
|
|
*
|
|
* @version Version 1.0.0
|
|
*/
|
|
|
|
namespace FuzeWorks\Async;
|
|
use FuzeWorks\Async\Events\TaskHandleEvent;
|
|
use FuzeWorks\Event\HaltExecutionEvent;
|
|
use FuzeWorks\Events;
|
|
use FuzeWorks\Exception\EventException;
|
|
use FuzeWorks\Logger;
|
|
use FuzeWorks\Priority;
|
|
|
|
class ShellWorker
|
|
{
|
|
|
|
/**
|
|
* @var TaskStorage
|
|
*/
|
|
protected $taskStorage;
|
|
|
|
/**
|
|
* @var Task
|
|
*/
|
|
protected $task;
|
|
|
|
/**
|
|
* @var bool
|
|
*/
|
|
protected $post;
|
|
|
|
public function __construct(TaskStorage $taskStorage)
|
|
{
|
|
$this->taskStorage = $taskStorage;
|
|
Events::addListener([$this, 'fatalHandler'], 'haltExecutionEvent', Priority::HIGH);
|
|
}
|
|
|
|
/**
|
|
* Run a task by finding its ID
|
|
*
|
|
* @param string $taskId
|
|
* @param bool $post
|
|
* @throws EventException
|
|
* @throws TasksException
|
|
*/
|
|
public function runTaskById(string $taskId, bool $post = false)
|
|
{
|
|
// First fetch the task
|
|
try {
|
|
$task = $this->taskStorage->getTaskById($taskId);
|
|
} catch (TasksException $e) {
|
|
throw new TasksException("Could not run worker. Task not found.");
|
|
}
|
|
|
|
$this->run($task, $post);
|
|
}
|
|
|
|
/**
|
|
* @param Task $task
|
|
* @param bool $post
|
|
* @throws EventException
|
|
* @throws TasksException
|
|
*/
|
|
public function run(Task $task, bool $post = false)
|
|
{
|
|
// Fire a taskHandleEvent
|
|
/** @var TaskHandleEvent $event */
|
|
$event = Events::fireEvent(new TaskHandleEvent(), $task);
|
|
|
|
// Set task to this worker
|
|
$this->task = $event->getTask();
|
|
$this->post = $post;
|
|
|
|
// Fetch the callable
|
|
$handler = $this->task->getHandler();
|
|
|
|
// Execute the handler and all its parent handlers
|
|
$success = $this->executeHandler($this->task, $handler, $post);
|
|
|
|
// Fetch the output and errors
|
|
$output = $post ? $handler->getPostOutput() : $handler->getOutput();
|
|
$output = is_null($output) ? '' : $output;
|
|
$errors = $this->getErrors();
|
|
|
|
// If the task failed, write so to task storage, based on whether this is a post request or not
|
|
if (!$success && $post)
|
|
$this->taskStorage->writePostOutput($this->task, $output, $errors, Task::FAILED);
|
|
elseif (!$success && !$post)
|
|
$this->taskStorage->writeTaskOutput($this->task, $output, $errors, Task::FAILED);
|
|
elseif ($success && $post)
|
|
$this->taskStorage->writePostOutput($this->task, $output, $errors, Task::SUCCESS);
|
|
else
|
|
$this->taskStorage->writeTaskOutput($this->task, $output, $errors, Task::SUCCESS);
|
|
|
|
// And write the final output
|
|
$this->output((string) $output, $errors);
|
|
}
|
|
|
|
protected function executeHandler(Task $task, Handler $handler, bool $usePost = false): bool
|
|
{
|
|
// First check to see if there is a parent handler
|
|
$parent = $handler->getParentHandler();
|
|
if (!is_null($parent)) {
|
|
// Execute the parent
|
|
if ($this->executeHandler($task, $parent, $usePost) === false)
|
|
return false;
|
|
|
|
// Fetch the output of the parent
|
|
$output = $usePost ? $parent->getPostOutput() : $parent->getOutput();
|
|
|
|
// And insert it as input into the child handler
|
|
$handler->setParentInput($output);
|
|
}
|
|
|
|
return $usePost ? $handler->postHandler($task) : $handler->primaryHandler($task);
|
|
}
|
|
/**
|
|
* In case a fatal error or exception occurs, the errors shall be redirected to stderr
|
|
*
|
|
* @param HaltExecutionEvent $event
|
|
*/
|
|
public function fatalHandler(HaltExecutionEvent $event)
|
|
{
|
|
// Cancel further execution by FuzeWorks
|
|
$event->setCancelled(true);
|
|
|
|
// Collect all error logs
|
|
$errors = $this->getErrors();
|
|
$this->output('', $errors);
|
|
|
|
// If no task is set yet, abort error logging to task
|
|
if (is_null($this->task))
|
|
return;
|
|
|
|
try {
|
|
// Write to TaskStorage
|
|
if (!$this->post)
|
|
$this->taskStorage->writeTaskOutput($this->task, '', $errors, Task::FAILED);
|
|
else
|
|
$this->taskStorage->writePostOutput($this->task, '', $errors, Task::FAILED);
|
|
} catch (TasksException $e) {
|
|
// Ignore
|
|
}
|
|
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Get all errors, exceptions and warnings from runtime and turn them into a string
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function getErrors(): string
|
|
{
|
|
$output = [];
|
|
foreach (Logger::$logs as $log)
|
|
{
|
|
if ($log['type'] !== 'ERROR' && $log['type'] !== 'EXCEPTION' && $log['type'] !== 'WARNING')
|
|
continue;
|
|
|
|
$output[] = strtoupper($log['type']) . ' ' .
|
|
(!empty($log['logFile']) && !empty($log['logLine']) ? $log['logFile'] . ':' . $log['logLine'] . " '" : "'") . $log['message'] . "'";
|
|
}
|
|
|
|
return implode("\n", $output);
|
|
}
|
|
|
|
/**
|
|
* Output the results to stdout and stderr
|
|
*
|
|
* @param string $output
|
|
* @param string $errors
|
|
*/
|
|
protected function output(string $output, string $errors)
|
|
{
|
|
// First write to stderr
|
|
if (!empty($errors))
|
|
fwrite(STDERR, $errors . PHP_EOL);
|
|
|
|
// Afterwards write to stdout
|
|
if (!empty($output))
|
|
echo $output . PHP_EOL;
|
|
}
|
|
} |