first commit

This commit is contained in:
Mr.Qin
2022-08-19 19:48:37 +08:00
commit afdd648b65
3275 changed files with 631084 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\RedisQueue;
use Workerman\RedisQueue\Client as RedisClient;
/**
* Class RedisQueue
* @package support
*
* Strings methods
* @method static void send($queue, $data, $delay=0)
*/
class Client
{
/**
* @var Client[]
*/
protected static $_connections = null;
/**
* @param string $name
* @return RedisClient
*/
public static function connection($name = 'default') {
if (!isset(static::$_connections[$name])) {
$config = config('redis_queue', config('plugin.webman.redis-queue.redis', []));
if (!isset($config[$name])) {
throw new \RuntimeException("RedisQueue connection $name not found");
}
$host = $config[$name]['host'];
$options = $config[$name]['options'];
$client = new RedisClient($host, $options);
static::$_connections[$name] = $client;
}
return static::$_connections[$name];
}
/**
* @param $name
* @param $arguments
* @return mixed
*/
public static function __callStatic($name, $arguments)
{
return static::connection('default')->{$name}(... $arguments);
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace Webman\RedisQueue\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Webman\Console\Util;
class MakeConsumerCommand extends Command
{
protected static $defaultName = 'redis-queue:consumer';
protected static $defaultDescription = 'Make redis-queue consumer';
/**
* @return void
*/
protected function configure()
{
$this->addArgument('name', InputArgument::REQUIRED, 'Consumer name');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
$output->writeln("Make consumer $name");
$path = '';
$namespace = 'app\\queue\\redis';
if ($pos = strrpos($name, DIRECTORY_SEPARATOR)) {
$path = substr($name, 0, $pos + 1);
$name = substr($name, $pos + 1);
$namespace .= '\\' . str_replace(DIRECTORY_SEPARATOR, '\\', trim($path, DIRECTORY_SEPARATOR));
}
$class = Util::nameToClass($name);
$queue = Util::classToName($name);
$file = app_path() . "/queue/redis/{$path}$class.php";
$this->createConsumer($namespace, $class, $queue, $file);
return self::SUCCESS;
}
/**
* @param $class
* @param $queue
* @param $file
* @return void
*/
protected function createConsumer($namspace, $class, $queue, $file)
{
$path = pathinfo($file, PATHINFO_DIRNAME);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
$controller_content = <<<EOF
<?php
namespace $namspace;
use Webman\\RedisQueue\\Consumer;
class $class implements Consumer
{
// 要消费的队列名
public \$queue = '$queue';
// 连接名,对应 plugin/webman/redis-queue/redis.php 里的连接`
public \$connection = 'default';
// 消费
public function consume(\$data)
{
// 无需反序列化
var_export(\$data);
}
}
EOF;
file_put_contents($file, $controller_content);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\RedisQueue;
/**
* Interface Consumer
* @package Webman\RedisQueue
*/
interface Consumer
{
public function consume($data);
}

View File

@@ -0,0 +1,72 @@
<?php
namespace Webman\RedisQueue;
class Install
{
const WEBMAN_PLUGIN = true;
/**
* @var array
*/
protected static $pathRelation = array (
'config/plugin/webman/redis-queue' => 'config/plugin/webman/redis-queue',
);
/**
* Install
* @return void
*/
public static function install()
{
static::installByRelation();
if (!is_dir(app_path() . '/queue/redis')){
mkdir(app_path() . '/queue/redis', 0777, true);
}
}
/**
* Uninstall
* @return void
*/
public static function uninstall()
{
self::uninstallByRelation();
}
/**
* installByRelation
* @return void
*/
public static function installByRelation()
{
foreach (static::$pathRelation as $source => $dest) {
if ($pos = strrpos($dest, '/')) {
$parent_dir = base_path().'/'.substr($dest, 0, $pos);
if (!is_dir($parent_dir)) {
mkdir($parent_dir, 0777, true);
}
}
//symlink(__DIR__ . "/$source", base_path()."/$dest");
copy_dir(__DIR__ . "/$source", base_path()."/$dest");
}
}
/**
* uninstallByRelation
* @return void
*/
public static function uninstallByRelation()
{
foreach (static::$pathRelation as $source => $dest) {
$path = base_path()."/$dest";
if (!is_dir($path) && !is_file($path)) {
continue;
}
/*if (is_link($path) {
unlink($path);
}*/
remove_dir($path);
}
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\RedisQueue\Process;
use support\Container;
use Webman\RedisQueue\Client;
/**
* Class Consumer
* @package process
*/
class Consumer
{
/**
* @var string
*/
protected $_consumerDir = '';
/**
* StompConsumer constructor.
* @param string $consumer_dir
*/
public function __construct($consumer_dir = '')
{
$this->_consumerDir = $consumer_dir;
}
/**
* onWorkerStart.
*/
public function onWorkerStart()
{
if (!is_dir($this->_consumerDir)) {
echo "Consumer directory {$this->_consumerDir} not exists\r\n";
return;
}
$dir_iterator = new \RecursiveDirectoryIterator($this->_consumerDir);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
foreach ($iterator as $file) {
if (is_dir($file)) {
continue;
}
$fileinfo = new \SplFileInfo($file);
$ext = $fileinfo->getExtension();
if ($ext === 'php') {
$class = str_replace('/', "\\", substr(substr($file, strlen(base_path())), 0, -4));
if (is_a($class, 'Webman\RedisQueue\Consumer', true)) {
$consumer = Container::get($class);
$connection_name = $consumer->connection ?? 'default';
$queue = $consumer->queue;
$connection = Client::connection($connection_name);
$connection->subscribe($queue, [$consumer, 'consume']);
}
}
}
}
}

78
vendor/webman/redis-queue/src/Redis.php vendored Normal file
View File

@@ -0,0 +1,78 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\RedisQueue;
use Workerman\Timer;
/**
* Class RedisQueue
* @package support
*
* Strings methods
* @method static void send($queue, $data, $delay=0)
*/
class Redis
{
/**
* @var RedisConnection[]
*/
protected static $_connections = [];
/**
* @param string $name
* @return RedisConnection
*/
public static function connection($name = 'default') {
if (!isset(static::$_connections[$name])) {
$configs = config('redis_queue', config('plugin.webman.redis-queue.redis', []));
if (!isset($configs[$name])) {
throw new \RuntimeException("RedisQueue connection $name not found");
}
$config = $configs[$name];
static::$_connections[$name] = static::connect($config);
}
return static::$_connections[$name];
}
protected static function connect($config)
{
if (!extension_loaded('redis')) {
throw new \RuntimeException('Please make sure the PHP Redis extension is installed and enabled.');
}
$redis = new RedisConnection();
$address = $config['host'];
$config = [
'host' => parse_url($address, PHP_URL_HOST),
'port' => parse_url($address, PHP_URL_PORT),
'db' => $config['options']['database'] ?? $config['options']['db'] ?? 0,
'auth' => $config['options']['auth'] ?? '',
'timeout' => $config['options']['timeout'] ?? 2,
'ping' => $config['options']['ping'] ?? 55,
'prefix' => $config['options']['prefix'] ?? '',
];
$redis->connectWithConfig($config);
return $redis;
}
/**
* @param $name
* @param $arguments
* @return mixed
*/
public static function __callStatic($name, $arguments)
{
return static::connection('default')->{$name}(... $arguments);
}
}

View File

@@ -0,0 +1,99 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Webman\RedisQueue;
use Workerman\Timer;
use Workerman\Worker;
class RedisConnection extends \Redis
{
/**
* @var array
*/
protected $config = [];
/**
* @param array $config
* @return void
*/
public function connectWithConfig(array $config = [])
{
static $timer;
if ($config) {
$this->config = $config;
}
if (false === $this->connect($this->config['host'], $this->config['port'], $this->config['timeout'] ?? 2)) {
throw new \RuntimeException("Redis connect {$this->config['host']}:{$this->config['port']} fail.");
}
if (!empty($this->config['auth'])) {
$this->auth($this->config['auth']);
}
if (!empty($this->config['db'])) {
$this->select($this->config['db']);
}
if (!empty($this->config['prefix'])) {
$this->setOption(\Redis::OPT_PREFIX, $this->config['prefix']);
}
if (Worker::getAllWorkers() && !$timer) {
$timer = Timer::add($this->config['ping'] ?? 55, function () {
$this->execCommand('ping');
});
}
}
/**
* @param $command
* @param ...$args
* @return mixed
* @throws \Throwable
*/
protected function execCommand($command, ...$args)
{
try {
return $this->{$command}(...$args);
} catch (\Throwable $e) {
$msg = strtolower($e->getMessage());
if ($msg === 'connection lost' || strpos($msg, 'went away')) {
$this->connectWithConfig();
return $this->{$command}(...$args);
}
throw $e;
}
}
/**
* @param $queue
* @param $data
* @param $delay
* @return bool
*/
public function send($queue, $data, $delay = 0)
{
$queue_waiting = '{redis-queue}-waiting';
$queue_delay = '{redis-queue}-delayed';
$now = time();
$package_str = json_encode([
'id' => time().rand(),
'time' => $now,
'delay' => $delay,
'attempts' => 0,
'queue' => $queue,
'data' => $data
]);
if ($delay) {
return (bool)$this->execCommand('zAdd' ,$queue_delay, $now + $delay, $package_str);
}
return (bool)$this->execCommand('lPush', $queue_waiting.$queue, $package_str);
}
}

View File

@@ -0,0 +1,4 @@
<?php
return [
'enable' => true,
];

View File

@@ -0,0 +1,7 @@
<?php
use Webman\RedisQueue\Command\MakeConsumerCommand;
return [
MakeConsumerCommand::class
];

View File

@@ -0,0 +1,11 @@
<?php
return [
'consumer' => [
'handler' => Webman\RedisQueue\Process\Consumer::class,
'count' => 8, // 可以设置多进程同时消费
'constructor' => [
// 消费者类目录
'consumer_dir' => app_path() . '/queue/redis'
]
]
];

View File

@@ -0,0 +1,13 @@
<?php
return [
'default' => [
'host' => 'redis://127.0.0.1:6379',
'options' => [
'auth' => null, // 密码,字符串类型,可选参数
'db' => 0, // 数据库
'prefix' => '', // key 前缀
'max_attempts' => 5, // 消费失败后,重试次数
'retry_seconds' => 5, // 重试间隔,单位秒
]
],
];