mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-04-02 01:52:10 +09:00
Merge branch 'rhymix:develop' into develop
This commit is contained in:
commit
88b5281094
111 changed files with 2542 additions and 405 deletions
|
|
@ -463,7 +463,9 @@ class DB
|
|||
|
||||
if ($this->isError())
|
||||
{
|
||||
return $this->getError();
|
||||
$output = $this->getError();
|
||||
$output->add('_count', $query_string);
|
||||
return $output;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -474,11 +476,13 @@ class DB
|
|||
catch (Exceptions\DBError $e)
|
||||
{
|
||||
$output = $this->setError(-1, $e->getMessage());
|
||||
$output->add('_count', $query_string);
|
||||
return $output;
|
||||
}
|
||||
catch (\PDOException $e)
|
||||
{
|
||||
$output = $this->setError(-1, $e->getMessage());
|
||||
$output->add('_count', $query_string);
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -560,6 +560,13 @@ class Mail
|
|||
*/
|
||||
public function send(): bool
|
||||
{
|
||||
// If queue is enabled, send asynchronously.
|
||||
if (config('queue.enabled') && !defined('RXQUEUE_CRON'))
|
||||
{
|
||||
Queue::addTask(self::class . '::' . 'sendAsync', $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get caller information.
|
||||
$backtrace = debug_backtrace(0);
|
||||
if(count($backtrace) && isset($backtrace[0]['file']))
|
||||
|
|
@ -600,6 +607,17 @@ class Mail
|
|||
return $this->sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email asynchronously (for Queue integration).
|
||||
*
|
||||
* @param self $mail
|
||||
* @return void
|
||||
*/
|
||||
public static function sendAsync(self $mail): void
|
||||
{
|
||||
$mail->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the message was sent.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -402,6 +402,13 @@ class Push
|
|||
*/
|
||||
public function send(): bool
|
||||
{
|
||||
// If queue is enabled, send asynchronously.
|
||||
if (config('queue.enabled') && !defined('RXQUEUE_CRON'))
|
||||
{
|
||||
Queue::addTask(self::class . '::' . 'sendAsync', $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get caller information.
|
||||
$backtrace = debug_backtrace(0);
|
||||
if(count($backtrace) && isset($backtrace[0]['file']))
|
||||
|
|
@ -464,6 +471,17 @@ class Push
|
|||
return $this->sent > 0 ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send asynchronously (for Queue integration).
|
||||
*
|
||||
* @param self $sms
|
||||
* @return void
|
||||
*/
|
||||
public static function sendAsync(self $push): void
|
||||
{
|
||||
$push->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the device token
|
||||
*
|
||||
|
|
|
|||
302
common/framework/Queue.php
Normal file
302
common/framework/Queue.php
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The Queue class.
|
||||
*/
|
||||
class Queue
|
||||
{
|
||||
/**
|
||||
* Static properties.
|
||||
*/
|
||||
protected static $_drivers = [];
|
||||
|
||||
/**
|
||||
* Add a custom Queue driver.
|
||||
*
|
||||
* @param string $name
|
||||
* @param object $driver
|
||||
* @return void
|
||||
*/
|
||||
public static function addDriver(string $name, Drivers\QueueInterface $driver): void
|
||||
{
|
||||
self::$_drivers[$name] = $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default driver.
|
||||
*
|
||||
* @param string $name
|
||||
* @return ?Drivers\QueueInterface
|
||||
*/
|
||||
public static function getDriver(string $name): ?Drivers\QueueInterface
|
||||
{
|
||||
if (isset(self::$_drivers[$name]))
|
||||
{
|
||||
return self::$_drivers[$name];
|
||||
}
|
||||
|
||||
$driver_class = '\Rhymix\Framework\Drivers\Queue\\' . $name;
|
||||
if (class_exists($driver_class))
|
||||
{
|
||||
$driver_config = config('queue.' . $name) ?: [];
|
||||
return self::$_drivers[$name] = $driver_class::getInstance($driver_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of supported Queue drivers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getSupportedDrivers(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach (Storage::readDirectory(__DIR__ . '/drivers/queue', false) as $filename)
|
||||
{
|
||||
$driver_name = substr($filename, 0, -4);
|
||||
$class_name = '\Rhymix\Framework\Drivers\Queue\\' . $driver_name;
|
||||
if ($class_name::isSupported())
|
||||
{
|
||||
$result[$driver_name] = [
|
||||
'name' => $class_name::getName(),
|
||||
'required' => $class_name::getRequiredConfig(),
|
||||
'optional' => $class_name::getOptionalConfig(),
|
||||
];
|
||||
}
|
||||
}
|
||||
foreach (self::$_drivers as $driver_name => $driver)
|
||||
{
|
||||
if ($driver->isSupported())
|
||||
{
|
||||
$result[$driver_name] = [
|
||||
'name' => $driver->getName(),
|
||||
'required' => $driver->getRequiredConfig(),
|
||||
'optional' => $driver->getOptionalConfig(),
|
||||
];
|
||||
}
|
||||
}
|
||||
ksort($result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task.
|
||||
*
|
||||
* The handler can be in one of the following formats:
|
||||
* - Global function, e.g. myHandler
|
||||
* - ClassName::staticMethodName
|
||||
* - ClassName::getInstance()->methodName
|
||||
* - new ClassName()->methodName
|
||||
*
|
||||
* Once identified and/or instantiated, the handler will be passed $args
|
||||
* and $options, in that order. Each of them must be a single object.
|
||||
*
|
||||
* It is strongly recommended that you write a dedicated method to handle
|
||||
* queued tasks, rather than reusing an existing method with a potentially
|
||||
* incompatible structure. If you must to call an existing method,
|
||||
* you should consider writing a wrapper.
|
||||
*
|
||||
* Any value returned by the handler will be discarded. If you throw an
|
||||
* exception, it may be logged, but it will not cause a fatal error.
|
||||
*
|
||||
* @param string $handler
|
||||
* @param ?object $args
|
||||
* @param ?object $options
|
||||
* @return int
|
||||
*/
|
||||
public static function addTask(string $handler, ?object $args = null, ?object $options = null): int
|
||||
{
|
||||
$driver_name = config('queue.driver');
|
||||
if (!$driver_name)
|
||||
{
|
||||
throw new Exceptions\FeatureDisabled('Queue not configured');
|
||||
}
|
||||
|
||||
$driver = self::getDriver($driver_name);
|
||||
if (!$driver)
|
||||
{
|
||||
throw new Exceptions\FeatureDisabled('Queue not configured');
|
||||
}
|
||||
|
||||
return $driver->addTask($handler, $args, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first task to execute immediately.
|
||||
*
|
||||
* If no tasks are pending, this method will return null.
|
||||
* Detailed scheduling of tasks will be handled by each driver.
|
||||
*
|
||||
* @param int $blocking
|
||||
* @return ?object
|
||||
*/
|
||||
public static function getTask(int $blocking = 0): ?object
|
||||
{
|
||||
$driver_name = config('queue.driver');
|
||||
if (!$driver_name)
|
||||
{
|
||||
throw new Exceptions\FeatureDisabled('Queue not configured');
|
||||
}
|
||||
|
||||
$driver = self::getDriver($driver_name);
|
||||
if (!$driver)
|
||||
{
|
||||
throw new Exceptions\FeatureDisabled('Queue not configured');
|
||||
}
|
||||
|
||||
return $driver->getTask($blocking);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the process key.
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkKey(string $key): bool
|
||||
{
|
||||
return config('queue.key') === $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the queue.
|
||||
*
|
||||
* This will usually be called by a separate script, run every minute
|
||||
* through an external scheduler such as crontab or systemd.
|
||||
*
|
||||
* If you are on a shared hosting service, you may also call a URL
|
||||
* using a "web cron" service provider.
|
||||
*
|
||||
* @param int $timeout
|
||||
* @return void
|
||||
*/
|
||||
public static function process(int $timeout): void
|
||||
{
|
||||
// This part will run in a loop until timeout.
|
||||
$process_start_time = microtime(true);
|
||||
while (true)
|
||||
{
|
||||
// Get a task from the driver.
|
||||
$loop_start_time = microtime(true);
|
||||
$task = self::getTask(1);
|
||||
|
||||
// Wait 1 second and loop back.
|
||||
if ($task)
|
||||
{
|
||||
// Find the handler for the task.
|
||||
$task->handler = trim($task->handler, '\\()');
|
||||
$handler = null;
|
||||
try
|
||||
{
|
||||
if (preg_match('/^(?:\\\\)?([\\\\\\w]+)::(\\w+)$/', $task->handler, $matches))
|
||||
{
|
||||
$class_name = '\\' . $matches[1];
|
||||
$method_name = $matches[2];
|
||||
if (class_exists($class_name) && method_exists($class_name, $method_name))
|
||||
{
|
||||
$handler = [$class_name, $method_name];
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('RxQueue: task handler not found: ' . $task->handler);
|
||||
}
|
||||
}
|
||||
elseif (preg_match('/^(?:\\\\)?([\\\\\\w]+)::(\\w+)(?:\(\))?->(\\w+)$/', $task->handler, $matches))
|
||||
{
|
||||
$class_name = '\\' . $matches[1];
|
||||
$initializer_name = $matches[2];
|
||||
$method_name = $matches[3];
|
||||
if (class_exists($class_name) && method_exists($class_name, $initializer_name))
|
||||
{
|
||||
$obj = $class_name::$initializer_name();
|
||||
if (method_exists($obj, $method_name))
|
||||
{
|
||||
$handler = [$obj, $method_name];
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('RxQueue: task handler not found: ' . $task->handler);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('RxQueue: task handler not found: ' . $task->handler);
|
||||
}
|
||||
}
|
||||
elseif (preg_match('/^new (?:\\\\)?([\\\\\\w]+)(?:\(\))?->(\\w+)$/', $task->handler, $matches))
|
||||
{
|
||||
$class_name = '\\' . $matches[1];
|
||||
$method_name = $matches[2];
|
||||
if (class_exists($class_name) && method_exists($class_name, $method_name))
|
||||
{
|
||||
$obj = new $class_name();
|
||||
$handler = [$obj, $method_name];
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('RxQueue: task handler not found: ' . $task->handler);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (function_exists('\\' . $task->handler))
|
||||
{
|
||||
$handler = '\\' . $task->handler;
|
||||
}
|
||||
else
|
||||
{
|
||||
error_log('RxQueue: task handler not found: ' . $task->handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Throwable $th)
|
||||
{
|
||||
error_log(vsprintf('RxQueue: task handler %s could not be accessed: %s in %s:%d', [
|
||||
$task->handler,
|
||||
get_class($th),
|
||||
$th->getFile(),
|
||||
$th->getLine(),
|
||||
]));
|
||||
}
|
||||
|
||||
// Call the handler.
|
||||
try
|
||||
{
|
||||
if ($handler)
|
||||
{
|
||||
call_user_func($handler, $task->args, $task->options);
|
||||
}
|
||||
}
|
||||
catch (\Throwable $th)
|
||||
{
|
||||
error_log(vsprintf('RxQueue: task handler %s threw %s in %s:%d', [
|
||||
$task->handler,
|
||||
get_class($th),
|
||||
$th->getFile(),
|
||||
$th->getLine(),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
// If the timeout is imminent, break the loop.
|
||||
$process_elapsed_time = microtime(true) - $process_start_time;
|
||||
if ($process_elapsed_time > $timeout - 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// If there was no task, wait 1 second to make sure that the loop isn't too tight.
|
||||
$loop_elapsed_time = microtime(true) - $loop_start_time;
|
||||
if (!$task && $loop_elapsed_time < 1)
|
||||
{
|
||||
usleep(intval((1 - $loop_elapsed_time) * 1000000));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -511,6 +511,13 @@ class SMS
|
|||
*/
|
||||
public function send(): bool
|
||||
{
|
||||
// If queue is enabled, send asynchronously.
|
||||
if (config('queue.enabled') && !defined('RXQUEUE_CRON'))
|
||||
{
|
||||
Queue::addTask(self::class . '::' . 'sendAsync', $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get caller information.
|
||||
$backtrace = debug_backtrace(0);
|
||||
if(count($backtrace) && isset($backtrace[0]['file']))
|
||||
|
|
@ -566,6 +573,17 @@ class SMS
|
|||
return $this->sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SMS asynchronously (for Queue integration).
|
||||
*
|
||||
* @param self $sms
|
||||
* @return void
|
||||
*/
|
||||
public static function sendAsync(self $sms): void
|
||||
{
|
||||
$sms->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the message was sent.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ class UA
|
|||
}
|
||||
|
||||
// Look for common search engine names and the 'bot' keyword.
|
||||
if (preg_match('/bot|spider|crawler|archiver|wget|curl|php|slurp|wordpress|facebook|teoma|yeti|daum|apachebench|mediapartners-google|[(<+]https?:|@/i', $ua))
|
||||
if (preg_match('/bot|spider|crawler|archiver|wget|curl|php|slurp|wordpress|facebook|external(agent|fetcher)|teoma|yeti|daum|apachebench|googleother|mediapartners-google|[(<+]https?:|@/i', $ua))
|
||||
{
|
||||
return self::$_robot_cache[$ua] = true;
|
||||
}
|
||||
|
|
|
|||
71
common/framework/drivers/QueueInterface.php
Normal file
71
common/framework/drivers/QueueInterface.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers;
|
||||
|
||||
/**
|
||||
* The Queue driver interface.
|
||||
*/
|
||||
interface QueueInterface
|
||||
{
|
||||
/**
|
||||
* Create a new instance of the current Queue driver, using the given settings.
|
||||
*
|
||||
* @param array $config
|
||||
* @return QueueInterface
|
||||
*/
|
||||
public static function getInstance(array $config): QueueInterface;
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this Queue driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName(): string;
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields required by this Queue driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getRequiredConfig(): array;
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields optionally used by this Queue driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getOptionalConfig(): array;
|
||||
|
||||
/**
|
||||
* Check if this driver is supported on this server.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported(): bool;
|
||||
|
||||
/**
|
||||
* Validate driver configuration.
|
||||
*
|
||||
* @param mixed $config
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateConfig($config): bool;
|
||||
|
||||
/**
|
||||
* Add a task.
|
||||
*
|
||||
* @param string $handler
|
||||
* @param ?object $args
|
||||
* @param ?object $options
|
||||
* @return int
|
||||
*/
|
||||
public function addTask(string $handler, ?object $args = null, ?object $options = null): int;
|
||||
|
||||
/**
|
||||
* Get the first task.
|
||||
*
|
||||
* @param int $blocking
|
||||
* @return ?object
|
||||
*/
|
||||
public function getTask(int $blocking = 0): ?object;
|
||||
}
|
||||
131
common/framework/drivers/queue/db.php
Normal file
131
common/framework/drivers/queue/db.php
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers\Queue;
|
||||
|
||||
use Rhymix\Framework\DB as RFDB;
|
||||
use Rhymix\Framework\Drivers\QueueInterface;
|
||||
|
||||
/**
|
||||
* The DB queue driver.
|
||||
*/
|
||||
class DB implements QueueInterface
|
||||
{
|
||||
/**
|
||||
* Create a new instance of the current Queue driver, using the given settings.
|
||||
*
|
||||
* @param array $config
|
||||
* @return QueueInterface
|
||||
*/
|
||||
public static function getInstance(array $config): QueueInterface
|
||||
{
|
||||
return new self($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this Queue driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'DB';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields required by this Queue driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getRequiredConfig(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields optionally used by this Queue driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getOptionalConfig(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this driver is supported on this server.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate driver configuration.
|
||||
*
|
||||
* @param mixed $config
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateConfig($config): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task.
|
||||
*
|
||||
* @param string $handler
|
||||
* @param ?object $args
|
||||
* @param ?object $options
|
||||
* @return int
|
||||
*/
|
||||
public function addTask(string $handler, ?object $args = null, ?object $options = null): int
|
||||
{
|
||||
$oDB = RFDB::getInstance();
|
||||
$stmt = $oDB->prepare('INSERT INTO task_queue (handler, args, options) VALUES (?, ?, ?)');
|
||||
$result = $stmt->execute([$handler, serialize($args), serialize($options)]);
|
||||
return $result ? $oDB->getInsertID() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first task.
|
||||
*
|
||||
* @param int $blocking
|
||||
* @return ?object
|
||||
*/
|
||||
public function getTask(int $blocking = 0): ?object
|
||||
{
|
||||
$oDB = RFDB::getInstance();
|
||||
$oDB->beginTransaction();
|
||||
$stmt = $oDB->query('SELECT * FROM task_queue ORDER BY id LIMIT 1 FOR UPDATE');
|
||||
$result = $stmt->fetchObject();
|
||||
$stmt->closeCursor();
|
||||
|
||||
if ($result)
|
||||
{
|
||||
$stmt = $oDB->prepare('DELETE FROM task_queue WHERE id = ?');
|
||||
$stmt->execute([$result->id]);
|
||||
$oDB->commit();
|
||||
|
||||
$result->args = unserialize($result->args);
|
||||
$result->options = unserialize($result->options);
|
||||
return $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDB->commit();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
119
common/framework/drivers/queue/dummy.php
Normal file
119
common/framework/drivers/queue/dummy.php
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers\Queue;
|
||||
|
||||
use Rhymix\Framework\Drivers\QueueInterface;
|
||||
|
||||
/**
|
||||
* The Dummy queue driver.
|
||||
*/
|
||||
class Dummy implements QueueInterface
|
||||
{
|
||||
/**
|
||||
* Dummy queue for testing.
|
||||
*/
|
||||
protected $_dummy_queue;
|
||||
|
||||
/**
|
||||
* Create a new instance of the current Queue driver, using the given settings.
|
||||
*
|
||||
* @param array $config
|
||||
* @return QueueInterface
|
||||
*/
|
||||
public static function getInstance(array $config): QueueInterface
|
||||
{
|
||||
return new self($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this Queue driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'Dummy';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields required by this Queue driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getRequiredConfig(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields optionally used by this Queue driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getOptionalConfig(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this driver is supported on this server.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate driver configuration.
|
||||
*
|
||||
* @param mixed $config
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateConfig($config): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task.
|
||||
*
|
||||
* @param string $handler
|
||||
* @param ?object $args
|
||||
* @param ?object $options
|
||||
* @return int
|
||||
*/
|
||||
public function addTask(string $handler, ?object $args = null, ?object $options = null): int
|
||||
{
|
||||
$this->_dummy_queue = (object)[
|
||||
'handler' => $handler,
|
||||
'args' => $args,
|
||||
'options' => $options,
|
||||
];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first task.
|
||||
*
|
||||
* @param int $blocking
|
||||
* @return ?object
|
||||
*/
|
||||
public function getTask(int $blocking = 0): ?object
|
||||
{
|
||||
$result = $this->_dummy_queue;
|
||||
$this->_dummy_queue = null;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
197
common/framework/drivers/queue/redis.php
Normal file
197
common/framework/drivers/queue/redis.php
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers\Queue;
|
||||
|
||||
use Rhymix\Framework\Drivers\QueueInterface;
|
||||
|
||||
/**
|
||||
* The Redis queue driver.
|
||||
*/
|
||||
class Redis implements QueueInterface
|
||||
{
|
||||
/**
|
||||
* The Redis connection is stored here.
|
||||
*/
|
||||
protected $_conn;
|
||||
protected $_key;
|
||||
|
||||
/**
|
||||
* Create a new instance of the current Queue driver, using the given settings.
|
||||
*
|
||||
* @param array $config
|
||||
* @return QueueInterface
|
||||
*/
|
||||
public static function getInstance(array $config): QueueInterface
|
||||
{
|
||||
return new self($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this Queue driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'Redis';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields required by this Queue driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getRequiredConfig(): array
|
||||
{
|
||||
return ['host', 'port'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields optionally used by this Queue driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getOptionalConfig(): array
|
||||
{
|
||||
return ['dbnum', 'user', 'pass'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this driver is supported on this server.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return class_exists('\\Redis');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate driver configuration.
|
||||
*
|
||||
* @param mixed $config
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateConfig($config): bool
|
||||
{
|
||||
try
|
||||
{
|
||||
$test = new \Redis;
|
||||
$test->connect($config['host'], $config['port'] ?? 6379);
|
||||
if (isset($config['user']) || isset($config['pass']))
|
||||
{
|
||||
$auth = [];
|
||||
if (isset($config['user']) && $config['user']) $auth[] = $config['user'];
|
||||
if (isset($config['pass']) && $config['pass']) $auth[] = $config['pass'];
|
||||
$test->auth(count($auth) > 1 ? $auth : $auth[0]);
|
||||
}
|
||||
if (isset($config['dbnum']))
|
||||
{
|
||||
$test->select(intval($config['dbnum']));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (\Throwable $th)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->_conn = new \Redis;
|
||||
$this->_conn->connect($config['host'], $config['port'] ?? 6379);
|
||||
if (isset($config['user']) || isset($config['pass']))
|
||||
{
|
||||
$auth = [];
|
||||
if (isset($config['user']) && $config['user']) $auth[] = $config['user'];
|
||||
if (isset($config['pass']) && $config['pass']) $auth[] = $config['pass'];
|
||||
$this->_conn->auth(count($auth) > 1 ? $auth : $auth[0]);
|
||||
}
|
||||
if (isset($config['dbnum']))
|
||||
{
|
||||
$this->_conn->select(intval($config['dbnum']));
|
||||
}
|
||||
$this->_key = 'rxQueue_' . substr(hash_hmac('sha1', 'rxQueue_', config('crypto.authentication_key')), 0, 24);
|
||||
}
|
||||
catch (\RedisException $e)
|
||||
{
|
||||
$this->_conn = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task.
|
||||
*
|
||||
* @param string $handler
|
||||
* @param ?object $args
|
||||
* @param ?object $options
|
||||
* @return int
|
||||
*/
|
||||
public function addTask(string $handler, ?object $args = null, ?object $options = null): int
|
||||
{
|
||||
$value = serialize((object)[
|
||||
'handler' => $handler,
|
||||
'args' => $args,
|
||||
'options' => $options,
|
||||
]);
|
||||
|
||||
if ($this->_conn)
|
||||
{
|
||||
$result = $this->_conn->rPush($this->_key, $value);
|
||||
return intval($result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first task.
|
||||
*
|
||||
* @param int $blocking
|
||||
* @return ?object
|
||||
*/
|
||||
public function getTask(int $blocking = 0): ?object
|
||||
{
|
||||
if ($this->_conn)
|
||||
{
|
||||
if ($blocking > 0)
|
||||
{
|
||||
$result = $this->_conn->blpop($this->_key, $blocking);
|
||||
if (is_array($result) && isset($result[1]))
|
||||
{
|
||||
return unserialize($result[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = $this->_conn->lpop($this->_key);
|
||||
if ($result)
|
||||
{
|
||||
return unserialize($result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -132,6 +132,11 @@ class SolAPI extends Base implements \Rhymix\Framework\Drivers\SMSInterface
|
|||
}
|
||||
}
|
||||
|
||||
foreach ($original->getExtraVars() as $key => $value)
|
||||
{
|
||||
$options->$key = $value;
|
||||
}
|
||||
|
||||
$data['messages'][] = $options;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ class FilenameFilter
|
|||
*/
|
||||
public static function clean(string $filename): string
|
||||
{
|
||||
// Clean up unnecessary encodings.
|
||||
$filename = strtr($filename, ['&' => '&', ''' => "'"]);
|
||||
|
||||
// Replace dangerous characters with safe alternatives, maintaining meaning as much as possible.
|
||||
$illegal = array('\\', '/', '<', '>', '{', '}', ':', ';', '|', '"', '~', '`', '$', '%', '^', '*', '?');
|
||||
$replace = array('', '', '(', ')', '(', ')', '_', ',', '_', '', '_', '\'', '_', '_', '_', '', '');
|
||||
|
|
@ -31,9 +34,6 @@ class FilenameFilter
|
|||
$filename = preg_replace('/__+/', '_', $filename);
|
||||
$filename = preg_replace('/\.\.+/', '.', $filename);
|
||||
|
||||
// Clean up unnecessary encodings.
|
||||
$filename = strtr($filename, array('&' => '&'));
|
||||
|
||||
// Change .php files to .phps to make them non-executable.
|
||||
if (strtolower(substr($filename, strlen($filename) - 4)) === '.php')
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue