add proxy server command and update lowest version of PHP >= 8.0

This commit is contained in:
crazywhalecc 2022-11-03 10:18:17 +08:00
parent 6b34427855
commit 35dec947df
49 changed files with 826 additions and 301 deletions

View File

@ -13,7 +13,7 @@
}
],
"require": {
"php": "^7.4 || ^8.0 || ^8.1",
"php": "^8.0 || ^8.1",
"ext-json": "*",
"doctrine/dbal": "^2.13.1",
"dragonmantank/cron-expression": "^3.3",
@ -47,7 +47,7 @@
"ext-redis": "If you use Redis in framework, you will need this extension",
"league/climate": "Display columns and status in terminal"
},
"minimum-stability": "stable",
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {

View File

@ -7,7 +7,9 @@ use Psr\Log\LogLevel;
use ZM\Logger\ConsoleLogger;
return [
// 设置默认的log等级
'level' => LogLevel::INFO,
// logger自定义回调
'logger' => static function (string $prefix = null): LoggerInterface {
if ($prefix) {
$prefix = strtoupper($prefix);
@ -16,7 +18,7 @@ return [
$prefix = app()->has('worker_id') ? '#' . app('worker_id') : 'MST';
}
$logger = new ConsoleLogger(zm_config('logging.level'));
$logger = new ConsoleLogger(config('logging.level'));
$logger::$format = "[%date%] [%level%] [{$prefix}] %body%";
$logger::$date_format = 'Y-m-d H:i:s';
// 如果你喜欢旧版的日志格式,请取消下行注释

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
$plugin = new \ZM\Plugin\InstantPlugin(__DIR__);
$plugin = new InstantPlugin(__DIR__);
/*
* 发送 "测试 123",回复 "你好123"

View File

@ -12,3 +12,4 @@ class_alias(\ZM\Annotation\OneBot\BotCommand::class, 'BotCommand');
class_alias(\ZM\Annotation\OneBot\BotEvent::class, 'BotEvent');
class_alias(\ZM\Annotation\OneBot\CommandArgument::class, 'CommandArgument');
class_alias(\ZM\Annotation\Closed::class, 'Closed');
class_alias(\ZM\Plugin\InstantPlugin::class, 'InstantPlugin');

View File

@ -57,8 +57,10 @@ if (Phar::running() !== '') {
define('FRAMEWORK_ROOT_DIR', realpath(zm_dir(__DIR__ . '/../../')));
}
define('ZM_INIT_TIME', microtime(true));
/* 定义用于存放框架运行状态的目录Windows 可用) */
define('ZM_STATE_DIR', TMP_DIR . '/.zm_' . sha1(FRAMEWORK_ROOT_DIR));
define('ZM_STATE_DIR', TMP_DIR . '/.zm_' . sha1(ZM_INIT_TIME . FRAMEWORK_ROOT_DIR));
/* 对 global.php 在 Windows 下的兼容性考虑,因为 Windows 或者无 Swoole 环境时候无法运行 */
!defined('SWOOLE_BASE') && define('SWOOLE_BASE', 1) && define('SWOOLE_PROCESS', 2);

View File

@ -4,17 +4,12 @@ declare(strict_types=1);
namespace ZM\Annotation;
use ArrayIterator;
use Closure;
use IteratorAggregate;
use Traversable;
abstract class AnnotationBase implements IteratorAggregate
abstract class AnnotationBase implements \IteratorAggregate
{
public string $method = '';
/**
* @var Closure|string
* @var \Closure|string
*/
public $class = '';
@ -33,7 +28,7 @@ abstract class AnnotationBase implements IteratorAggregate
$str .= ($v ? 'TRUE' : 'FALSE');
} elseif (is_array($v)) {
$str .= json_encode($v, JSON_UNESCAPED_UNICODE);
} elseif ($v instanceof Closure) {
} elseif ($v instanceof \Closure) {
$str .= '@AnonymousFunction';
} elseif (is_null($v)) {
$str .= 'NULL';
@ -47,7 +42,7 @@ abstract class AnnotationBase implements IteratorAggregate
/**
* InstantPlugin 下调用,设置回调或匿名函数
*
* @param Closure|string $method
* @param \Closure|string $method
*/
public function on($method): AnnotationBase
{
@ -55,9 +50,9 @@ abstract class AnnotationBase implements IteratorAggregate
return $this;
}
public function getIterator(): Traversable
public function getIterator(): \Traversable
{
return new ArrayIterator($this);
return new \ArrayIterator($this);
}
public function isInGroup(string $name): bool

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM\Annotation;
use Throwable;
use ZM\Exception\InterruptException;
/**
@ -90,7 +89,7 @@ class AnnotationHandler
* 此处会遍历所有注册了当前注解的函数,并支持中间件插入
*
* @param mixed ...$params 传入的参数们
* @throws Throwable
* @throws \Throwable
*/
public function handleAll(...$params)
{
@ -113,7 +112,7 @@ class AnnotationHandler
// InterruptException 用于中断,这里必须 catch并标记状态
$this->return_val = $e->return_var;
$this->status = self::STATUS_INTERRUPTED;
} catch (Throwable $e) {
} catch (\Throwable $e) {
// 其他类型的异常就顺势再抛出到外层,此层不做处理
$this->status = self::STATUS_EXCEPTION;
throw $e;
@ -124,7 +123,7 @@ class AnnotationHandler
* 调用单个注解
*
* @throws InterruptException
* @throws Throwable
* @throws \Throwable
*/
public function handle(AnnotationBase $v, ?callable $rule_callback = null, ...$args): bool
{
@ -144,7 +143,7 @@ class AnnotationHandler
} catch (InterruptException $e) {
// 这里直接抛出这个异常的目的就是给上层handleAll()捕获
throw $e;
} catch (Throwable $e) {
} catch (\Throwable $e) {
// 其余的异常就交给中间件的异常捕获器过一遍,没捕获的则继续抛出
$this->status = self::STATUS_EXCEPTION;
throw $e;

View File

@ -7,8 +7,6 @@ namespace ZM\Annotation;
use Doctrine\Common\Annotations\AnnotationReader;
use Koriym\Attributes\AttributeReader;
use Koriym\Attributes\DualReader;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use ZM\Annotation\Http\Controller;
use ZM\Annotation\Http\Route;
@ -78,7 +76,7 @@ class AnnotationParser
/**
* 注册各个模块类的注解和模块level的排序
*
* @throws ReflectionException
* @throws \ReflectionException
* @throws ConfigException
*/
public function parseAll()
@ -112,8 +110,8 @@ class AnnotationParser
logger()->debug('正在检索 ' . $v);
// 通过反射实现注解读取
$reflection_class = new ReflectionClass($v);
$methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC);
$reflection_class = new \ReflectionClass($v);
$methods = $reflection_class->getMethods(\ReflectionMethod::IS_PUBLIC);
$class_annotations = $reader->getClassAnnotations($reflection_class);
// 这段为新加的:start
// 这里将每个类里面所有的类注解、方法注解通通加到一颗大树上,后期解析

View File

@ -14,7 +14,7 @@ use Doctrine\Common\Annotations\Annotation\Target;
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_ALL)]
class Closed extends AnnotationBase
{
}

View File

@ -20,7 +20,7 @@ use ZM\Annotation\Interfaces\Level;
* @Target("METHOD")
* @since 3.0.0
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
class BindEvent extends AnnotationBase implements Level
{
/**

View File

@ -16,7 +16,7 @@ use ZM\Annotation\AnnotationBase;
* @Target("METHOD")
* @since 3.0.0
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
class Init extends AnnotationBase
{
/** @var int */

View File

@ -16,7 +16,7 @@ use ZM\Annotation\AnnotationBase;
* @Target("METHOD")
* @since 3.0.0
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
class Setup extends AnnotationBase
{
}

View File

@ -17,7 +17,7 @@ use ZM\Annotation\Interfaces\ErgodicAnnotation;
* @NamedArgumentConstructor()
* @Target("CLASS")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS)]
class Controller extends AnnotationBase implements ErgodicAnnotation
{
/**

View File

@ -16,7 +16,7 @@ use ZM\Annotation\AnnotationBase;
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
class Route extends AnnotationBase
{
/**

View File

@ -17,7 +17,7 @@ use ZM\Annotation\Interfaces\ErgodicAnnotation;
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_ALL)]
class Middleware extends AnnotationBase implements ErgodicAnnotation
{
/**

View File

@ -20,7 +20,7 @@ use ZM\Exception\ZMKnownException;
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
class BotCommand extends AnnotationBase implements Level
{
/** @var string */

View File

@ -16,7 +16,7 @@ use ZM\Annotation\AnnotationBase;
* @Target("METHOD")
* @NamedArgumentConstructor()
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class BotEvent extends AnnotationBase
{
public ?string $type;

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM\Annotation\OneBot;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use ZM\Annotation\AnnotationBase;
@ -18,7 +17,7 @@ use ZM\Exception\ZMKnownException;
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_ALL)]
class CommandArgument extends AnnotationBase implements ErgodicAnnotation
{
/**

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM\Command;
use Phar;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -92,7 +91,7 @@ class InitCommand extends Command
return 0;
}
if (LOAD_MODE === 2) { // 从phar启动的框架包初始化的模式
$phar_link = new Phar(__DIR__);
$phar_link = new \Phar(__DIR__);
$current_dir = pathinfo($phar_link->getPath())['dirname'];
chdir($current_dir);
$phar_link = 'phar://' . $phar_link->getPath();

View File

@ -0,0 +1,561 @@
<?php
declare(strict_types=1);
namespace ZM\Command;
use OneBot\Driver\Workerman\Worker;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Workerman\Connection\AsyncTcpConnection;
use Workerman\Connection\AsyncUdpConnection;
use Workerman\Timer;
use ZM\Logger\ConsoleLogger;
class ProxyServerCommand extends Command
{
// the name of the command (the part after "bin/console")
protected static $defaultName = 'proxy';
private array $config = [];
public function onSocksMessage($connection, $buffer)
{
switch ($connection->stage) {
// 初始化环节
case STAGE_INIT:
$request = [];
// 当前偏移量
$offset = 0;
// 检测buffer长度
if (strlen($buffer) < 2) {
logger()->error('init socks5 failed. buffer too short.');
$connection->send("\x05\xff");
$connection->stage = STAGE_DESTROYED;
$connection->close();
return;
}
// Socks5 版本
$request['ver'] = ord($buffer[$offset]);
++$offset;
// 认证方法数量
$request['method_count'] = ord($buffer[$offset]);
++$offset;
if (strlen($buffer) < 2 + $request['method_count']) {
logger()->warning('init authentic failed. buffer too short.');
$connection->send("\x05\xff");
$connection->stage = STAGE_DESTROYED;
$connection->close();
return;
}
// 客户端支持的认证方法
$request['methods'] = [];
for ($i = 1; $i <= $request['method_count']; ++$i) {
$request['methods'][] = ord($buffer[$offset]);
++$offset;
}
foreach (($this->config['auth'] ?? []) as $k => $v) {
if (in_array($k, $request['methods'])) {
logger()->info("auth client via method {$k}");
logger()->debug('send:' . bin2hex("\x05" . chr($k)));
$connection->send("\x05" . chr($k));
if ($k === 0) {
$connection->stage = STAGE_ADDR;
} else {
$connection->stage = STAGE_AUTH;
}
$connection->auth_type = $k;
return;
}
}
if ($connection->stage != STAGE_AUTH) {
logger()->warning('client has no matched auth methods');
logger()->info('send:' . bin2hex("\x05\xff"));
$connection->send("\x05\xff");
$connection->stage = STAGE_DESTROYED;
$connection->close();
}
return;
case STAGE_ADDR:
$request = [];
// 当前偏移量
$offset = 0;
if (strlen($buffer) < 4) {
logger()->error('connect init failed. buffer too short.');
$connection->stage = STAGE_DESTROYED;
$response = [];
$response['ver'] = 5;
$response['rep'] = ERR_GENERAL;
$response['rsv'] = 0;
$response['addr_type'] = ADDRTYPE_IPV4;
$response['bind_addr'] = '0.0.0.0';
$response['bind_port'] = 0;
$connection->close($this->packResponse($response));
return;
}
// Socks 版本
$request['ver'] = ord($buffer[$offset]);
++$offset;
// 命令
$request['command'] = ord($buffer[$offset]);
++$offset;
// RSV
$request['rsv'] = ord($buffer[$offset]);
++$offset;
// AddressType
$request['addr_type'] = ord($buffer[$offset]);
++$offset;
// DestAddr
switch ($request['addr_type']) {
case ADDRTYPE_IPV4:
if (strlen($buffer) < 4 + 4) {
logger()->error('connect init failed.[ADDRTYPE_IPV4] buffer too short.');
$connection->stage = STAGE_DESTROYED;
$response = [];
$response['ver'] = 5;
$response['rep'] = ERR_GENERAL;
$response['rsv'] = 0;
$response['addr_type'] = ADDRTYPE_IPV4;
$response['bind_addr'] = '0.0.0.0';
$response['bind_port'] = 0;
$connection->close($this->packResponse($response));
return;
}
$tmp = substr($buffer, $offset, 4);
$ip = 0;
for ($i = 0; $i < 4; ++$i) {
// var_dump(ord($tmp[$i]));
$ip += ord($tmp[$i]) * pow(256, 3 - $i);
}
$request['dest_addr'] = long2ip($ip);
$offset += 4;
break;
case ADDRTYPE_HOST:
$request['host_len'] = ord($buffer[$offset]);
++$offset;
if (strlen($buffer) < 4 + 1 + $request['host_len']) {
logger()->error('connect init failed.[ADDRTYPE_HOST] buffer too short.');
$connection->stage = STAGE_DESTROYED;
$response = [];
$response['ver'] = 5;
$response['rep'] = ERR_GENERAL;
$response['rsv'] = 0;
$response['addr_type'] = ADDRTYPE_IPV4;
$response['bind_addr'] = '0.0.0.0';
$response['bind_port'] = 0;
$connection->close($this->packResponse($response));
return;
}
$request['dest_addr'] = substr($buffer, $offset, $request['host_len']);
$offset += $request['host_len'];
break;
case ADDRTYPE_IPV6:
default:
logger()->error('unsupport ipv6. [ADDRTYPE_IPV6].');
$connection->stage = STAGE_DESTROYED;
$response = [];
$response['ver'] = 5;
$response['rep'] = ERR_UNKNOW_ADDR_TYPE;
$response['rsv'] = 0;
$response['addr_type'] = ADDRTYPE_IPV4;
$response['bind_addr'] = '0.0.0.0';
$response['bind_port'] = 0;
$connection->close($this->packResponse($response));
return;
}
// DestPort
if (strlen($buffer) < $offset + 2) {
logger()->error('connect init failed.[port] buffer too short.');
$connection->stage = STAGE_DESTROYED;
$response = [];
$response['ver'] = 5;
$response['rep'] = ERR_GENERAL;
$response['rsv'] = 0;
$response['addr_type'] = ADDRTYPE_IPV4;
$response['bind_addr'] = '0.0.0.0';
$response['bind_port'] = 0;
$connection->close($this->packResponse($response));
return;
}
$portData = unpack('n', substr($buffer, $offset, 2));
$request['dest_port'] = $portData[1];
$offset += 2;
// var_dump($request);
switch ($request['command']) {
case CMD_CONNECT:
logger()->info('tcp://' . $request['dest_addr'] . ':' . $request['dest_port']);
if ($request['addr_type'] == ADDRTYPE_HOST) {
if (!filter_var($request['dest_addr'], FILTER_VALIDATE_IP)) {
logger()->debug('resolve DNS ' . $request['dest_addr']);
$connection->stage = STAGE_DNS;
$addr = dns_get_record($request['dest_addr'], DNS_A);
$addr = $addr ? array_pop($addr) : null;
logger()->debug('DNS resolved ' . $request['dest_addr'] . ' => ' . $addr['ip']);
} else {
$addr['ip'] = $request['dest_addr'];
}
} else {
$addr['ip'] = $request['dest_addr'];
}
if ($addr) {
$connection->stage = STAGE_CONNECTING;
$remote_connection = new AsyncTcpConnection('tcp://' . $addr['ip'] . ':' . $request['dest_port']);
$remote_connection->onConnect = function ($remote_connection) use ($connection, $request) {
$connection->state = STAGE_STREAM;
$response = [];
$response['ver'] = 5;
$response['rep'] = 0;
$response['rsv'] = 0;
$response['addr_type'] = $request['addr_type'];
$response['bind_addr'] = '0.0.0.0';
$response['bind_port'] = 18512;
$connection->send($this->packResponse($response));
$connection->pipe($remote_connection);
$remote_connection->pipe($connection);
logger()->debug('tcp://' . $request['dest_addr'] . ':' . $request['dest_port'] . ' [OK]');
};
$remote_connection->connect();
} else {
logger()->debug('DNS resolve failed.');
$connection->stage = STAGE_DESTROYED;
$response = [];
$response['ver'] = 5;
$response['rep'] = ERR_HOST;
$response['rsv'] = 0;
$response['addr_type'] = ADDRTYPE_IPV4;
$response['bind_addr'] = '0.0.0.0';
$response['bind_port'] = 0;
$connection->close($this->packResponse($response));
}
break;
case CMD_UDP_ASSOCIATE:
$connection->stage = STAGE_UDP_ASSOC;
var_dump('CMD_UDP_ASSOCIATE ' . ($this->config['udp_port'] ?? 2222));
if ($this->config['udp_port'] == 0) {
$connection->udpWorker = new Worker('udp://0.0.0.0:0');
/* @phpstan-ignore-next-line */
$connection->udpWorker->incId = 0;
$connection->udpWorker->onMessage = function ($udp_connection, $data) use ($connection) {
$this->udpWorkerOnMessage($udp_connection, $data, $connection->udpWorker);
};
$connection->udpWorker->listen();
$listenInfo = stream_socket_get_name($connection->udpWorker->getMainSocket(), false);
[$bind_addr, $bind_port] = explode(':', $listenInfo);
} else {
$bind_port = $this->config['udp_port'] ?? 2222;
}
$bind_addr = $this->config['wanIP'] ?? '192.168.1.1';
$response['ver'] = 5;
$response['rep'] = 0;
$response['rsv'] = 0;
$response['addr_type'] = ADDRTYPE_IPV4;
$response['bind_addr'] = $bind_addr;
$response['bind_port'] = $bind_port;
logger()->debug('send:' . bin2hex($this->packResponse($response)));
$connection->send($this->packResponse($response));
break;
default:
logger()->error('connect init failed. unknow command.');
$connection->stage = STAGE_DESTROYED;
$response = [];
$response['ver'] = 5;
$response['rep'] = ERR_UNKNOW_COMMAND;
$response['rsv'] = 0;
$response['addr_type'] = ADDRTYPE_IPV4;
$response['bind_addr'] = '0.0.0.0';
$response['bind_port'] = 0;
$connection->close($this->packResponse($response));
return;
}
}
}
public function udpWorkerOnMessage($udp_connection, $data, &$worker)
{
logger()->debug('send:' . bin2hex($data));
$request = [];
$offset = 0;
$request['rsv'] = substr($data, $offset, 2);
$offset += 2;
$request['frag'] = ord($data[$offset]);
++$offset;
$request['addr_type'] = ord($data[$offset]);
++$offset;
switch ($request['addr_type']) {
case ADDRTYPE_IPV4:
$tmp = substr($data, $offset, 4);
$ip = 0;
for ($i = 0; $i < 4; ++$i) {
$ip += ord($tmp[$i]) * pow(256, 3 - $i);
}
$request['dest_addr'] = long2ip($ip);
$offset += 4;
break;
case ADDRTYPE_HOST:
$request['host_len'] = ord($data[$offset]);
++$offset;
$request['dest_addr'] = substr($data, $offset, $request['host_len']);
$offset += $request['host_len'];
break;
case ADDRTYPE_IPV6:
if (strlen($data) < 22) {
echo "buffer too short\n";
$error = true;
break;
}
echo "todo ipv6\n";
$error = true;
// no break
default:
echo "unsupported addrtype {$request['addr_type']}\n";
$error = true;
}
$portData = unpack('n', substr($data, $offset, 2));
$request['dest_port'] = $portData[1];
$offset += 2;
// var_dump($request['dest_addr']);
if ($request['addr_type'] == ADDRTYPE_HOST) {
logger()->debug('解析DNS');
$addr = dns_get_record($request['dest_addr'], DNS_A);
$addr = $addr ? array_pop($addr) : null;
logger()->debug('DNS 解析完成' . $addr['ip']);
} else {
$addr['ip'] = $request['dest_addr'];
}
// var_dump($request);
// var_dump($udp_connection);
$remote_connection = new AsyncUdpConnection('udp://' . $addr['ip'] . ':' . $request['dest_port']);
/* @phpstan-ignore-next-line */
$remote_connection->id = $worker->incId++;
/* @phpstan-ignore-next-line */
$remote_connection->udp_connection = $udp_connection;
$remote_connection->onConnect = function ($remote_connection) use ($data, $offset) {
$remote_connection->send(substr($data, $offset));
};
$remote_connection->onMessage = function ($remote_connection, $recv) use ($data, $offset, $udp_connection, $worker) {
$udp_connection->close(substr($data, 0, $offset) . $recv);
$remote_connection->close();
unset($worker->udpConnections[$remote_connection->id]);
};
/* @phpstan-ignore-next-line */
$remote_connection->deadTime = time() + 3;
$remote_connection->connect();
/* @phpstan-ignore-next-line */
$worker->udpConnections[$remote_connection->id] = $remote_connection;
}
/**
* 配置
*/
protected function configure()
{
$this->setDescription('Start HTTP proxy server | 开启一个 HTTP 代理服务器');
$this->addOption('type', 't', InputOption::VALUE_REQUIRED, '类型可选http、socks');
$this->addOption('host', 'H', InputOption::VALUE_REQUIRED, '监听地址默认0.0.0.0');
$this->addOption('port', 'P', InputOption::VALUE_REQUIRED, '监听端口默认8080');
$this->addOption('udp-port', 'U', InputOption::VALUE_REQUIRED, '监听端口默认8080');
$this->addOption('username', 'u', InputOption::VALUE_REQUIRED, '认证用的用户名');
$this->addOption('password', 'p', InputOption::VALUE_REQUIRED, '认证用的密码');
// ...
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
ob_logger_registered() || ob_logger_register(new ConsoleLogger());
ini_set('memory_limit', '512M');
// Create a TCP worker.
$address = $input->getOption('host') ?? '0.0.0.0';
$port = $input->getOption('port') ?? '8080';
$this->config['auth'] = [0 => true];
$type = $input->getOption('type') ?? 'http';
logger()->notice('Proxy server started at ' . $type . '://' . $address . ':' . $port);
switch ($type) {
case 'http':
$this->startHttpProxy($address, $port);
break;
case 'socks':
case 'socks5':
$this->startSocksProxy($address, $port);
break;
}
return 0;
}
private function startHttpProxy($address, $port)
{
// Create a TCP worker.
/** @noinspection PhpObjectFieldsAreOnlyWrittenInspection */
$worker = new Worker('tcp://' . $address . ':' . $port);
// 6 processes
$worker->count = 6;
// Worker name.
$worker->name = 'zhamao-http-proxy';
Worker::$internal_running = true;
// Emitted when data received from client.
$worker->onMessage = function ($connection, $buffer) {
// Parse http header.
[$method, $addr, $http_version] = explode(' ', $buffer);
$url_data = parse_url($addr);
$addr = !isset($url_data['port']) ? "{$url_data['host']}:80" : "{$url_data['host']}:{$url_data['port']}";
// Async TCP connection.
$remote_connection = new AsyncTcpConnection("tcp://{$addr}");
// CONNECT.
if ($method !== 'CONNECT') {
$remote_connection->send($buffer);
// POST GET PUT DELETE etc.
} else {
$connection->send("HTTP/1.1 200 Connection Established\r\n\r\n");
logger()->info('Receive connection: ' . $addr);
}
// Pipe.
$remote_connection->pipe($connection);
$connection->pipe($remote_connection);
$remote_connection->connect();
};
Worker::runAll();
}
/**
* @see https://github.com/walkor/php-socks5/blob/master/start.php
* @param string $address 地址
* @param int|string $port 端口
*/
private function startSocksProxy(string $address, $port)
{
define('STAGE_INIT', 0);
define('STAGE_AUTH', 1);
define('STAGE_ADDR', 2);
define('STAGE_UDP_ASSOC', 3);
define('STAGE_DNS', 4);
define('STAGE_CONNECTING', 5);
define('STAGE_STREAM', 6);
define('STAGE_DESTROYED', -1);
define('CMD_CONNECT', 1);
define('CMD_BIND', 2);
define('CMD_UDP_ASSOCIATE', 3);
define('ERR_GENERAL', 1);
define('ERR_NOT_ALLOW', 2);
define('ERR_NETWORK', 3);
define('ERR_HOST', 4);
define('ERR_REFUSE', 5);
define('ERR_TTL_EXPIRED', 6);
define('ERR_UNKNOW_COMMAND', 7);
define('ERR_UNKNOW_ADDR_TYPE', 8);
define('ERR_UNKNOW', 9);
define('ADDRTYPE_IPV4', 1);
define('ADDRTYPE_IPV6', 4);
define('ADDRTYPE_HOST', 3);
define('METHOD_NO_AUTH', 0);
define('METHOD_GSSAPI', 1);
define('METHOD_USER_PASS', 2);
/** @noinspection PhpObjectFieldsAreOnlyWrittenInspection */
$worker = new Worker('tcp://' . $address . ':' . $port);
$worker->onConnect = function ($connection) {
$connection->stage = STAGE_INIT;
$connection->auth_type = null;
};
$worker->onMessage = [$this, 'onSocksMessage'];
$worker->onWorkerStart = function () use ($address, $port) {
$udpWorker = new Worker('udp://' . $address . ':' . $port);
/* @phpstan-ignore-next-line */
$udpWorker->incId = 0;
$udpWorker->onWorkerStart = function ($worker) {
$worker->udpConnections = [];
Timer::add(1, function () use ($worker) {
/* @phpstan-ignore-next-line */
foreach ($worker->udpConnections as $id => $remote_connection) {
if ($remote_connection->deadTime < time()) {
$remote_connection->close();
$remote_connection->udp_connection->close();
unset($worker->udpConnections[$id]);
}
}
});
};
$udpWorker->onMessage = [$this, 'udpWorkerOnMessage'];
$udpWorker->listen();
};
$worker->onClose = function ($connection) {
logger()->info('client closed.');
};
$worker::$internal_running = true;
Worker::runAll();
}
private function packResponse($response)
{
$data = '';
$data .= chr($response['ver']);
$data .= chr($response['rep']);
$data .= chr($response['rsv']);
$data .= chr($response['addr_type']);
switch ($response['addr_type']) {
case ADDRTYPE_IPV4:
$tmp = explode('.', $response['bind_addr']);
foreach ($tmp as $block) {
$data .= chr(intval($block));
}
break;
case ADDRTYPE_HOST:
$host_len = strlen($response['bind_addr']);
$data .= chr($host_len);
$data .= $response['bind_addr'];
break;
}
$data .= pack('n', $response['bind_port']);
return $data;
}
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM\Command\Server;
use Exception;
use OneBot\Driver\Process\ProcessManager;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -48,7 +47,7 @@ class ServerStartCommand extends ServerCommand
/**
* @throws ZMKnownException
* @throws InitException
* @throws Exception
* @throws \Exception
* @noinspection PhpComposerExtensionStubsInspection
*/
protected function execute(InputInterface $input, OutputInterface $output): int

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM;
use Exception;
use Phar;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputInterface;
@ -14,6 +13,7 @@ use ZM\Command\BuildCommand;
use ZM\Command\CheckConfigCommand;
use ZM\Command\Generate\SystemdGenerateCommand;
use ZM\Command\InitCommand;
use ZM\Command\ProxyServerCommand;
use ZM\Command\ReplCommand;
use ZM\Command\Server\ServerReloadCommand;
use ZM\Command\Server\ServerStartCommand;
@ -47,10 +47,11 @@ final class ConsoleApplication extends Application
$this->add(new SystemdGenerateCommand()); // 生成systemd文件
$this->add(new BotCraftCommand()); // 用于从命令行创建插件
$this->add(new ReplCommand()); // 交互式控制台
$this->add(new ProxyServerCommand()); // HTTP 代理服务器
if (LOAD_MODE === 1) { // 如果是 Composer 模式加载的,那么可以输入 check:config 命令,检查配置文件是否需要更新
$this->add(new CheckConfigCommand());
}
if (Phar::running() === '') { // 不是 Phar 模式的话,可以执行打包解包初始化命令
if (\Phar::running() === '') { // 不是 Phar 模式的话,可以执行打包解包初始化命令
$this->add(new BuildCommand()); // 用于将整个应用打包为一个可执行的 phar
$this->add(new InitCommand()); // 用于在 Composer 模式启动下,初始化脚手架文件
// $this->add(new PluginPackCommand()); // 用于打包一个子模块为 phar 并进行分发
@ -69,7 +70,7 @@ final class ConsoleApplication extends Application
{
try {
return parent::run($input, $output);
} catch (Exception $e) {
} catch (\Exception $e) {
echo zm_internal_errcode('E00005') . "{$e->getMessage()} at {$e->getFile()}({$e->getLine()})" . PHP_EOL;
exit(1);
}

View File

@ -4,9 +4,6 @@ declare(strict_types=1);
namespace ZM\Container;
use InvalidArgumentException;
use ReflectionException;
use ReflectionParameter;
use ZM\Utils\ReflectionUtil;
class BoundMethod
@ -17,8 +14,8 @@ class BoundMethod
* @param Container $container
* @param callable|string $callback
* @return mixed
* @throws EntryResolutionException|ReflectionException
* @throws InvalidArgumentException
* @throws EntryResolutionException|\ReflectionException
* @throws \InvalidArgumentException
*/
public static function call(ContainerInterface $container, $callback, array $parameters = [], string $default_method = null)
{
@ -35,7 +32,7 @@ class BoundMethod
}
if (!is_callable($callback)) {
throw new InvalidArgumentException('Callback is not callable.');
throw new \InvalidArgumentException('Callback is not callable.');
}
return call_user_func_array($callback, self::getMethodDependencies($container, $callback, $parameters));
@ -45,7 +42,7 @@ class BoundMethod
* Get all dependencies for a given method.
*
* @param callable|string $callback
* @throws ReflectionException
* @throws \ReflectionException
*/
protected static function getMethodDependencies(ContainerInterface $container, $callback, array $parameters = []): array
{
@ -71,7 +68,7 @@ class BoundMethod
*/
protected static function addDependencyForCallParameter(
ContainerInterface $container,
ReflectionParameter $parameter,
\ReflectionParameter $parameter,
array &$parameters,
array &$dependencies
): void {

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM\Container;
use Closure;
use Psr\Container\ContainerInterface as PsrContainerInterface;
/**
@ -33,7 +32,7 @@ interface ContainerInterface extends PsrContainerInterface
* 注册绑定
*
* @param string $abstract 类或接口名
* @param null|Closure|string $concrete 返回类实例的闭包,或是类名
* @param null|\Closure|string $concrete 返回类实例的闭包,或是类名
* @param bool $shared 是否共享
*/
public function bind(string $abstract, $concrete = null, bool $shared = false): void;
@ -44,7 +43,7 @@ interface ContainerInterface extends PsrContainerInterface
* 在已经绑定时不会重复注册
*
* @param string $abstract 类或接口名
* @param null|Closure|string $concrete 返回类实例的闭包,或是类名
* @param null|\Closure|string $concrete 返回类实例的闭包,或是类名
* @param bool $shared 是否共享
*/
public function bindIf(string $abstract, $concrete = null, bool $shared = false): void;
@ -53,7 +52,7 @@ interface ContainerInterface extends PsrContainerInterface
* 注册一个单例绑定
*
* @param string $abstract 类或接口名
* @param null|Closure|string $concrete 返回类实例的闭包,或是类名
* @param null|\Closure|string $concrete 返回类实例的闭包,或是类名
*/
public function singleton(string $abstract, $concrete = null): void;
@ -63,7 +62,7 @@ interface ContainerInterface extends PsrContainerInterface
* 在已经绑定时不会重复注册
*
* @param string $abstract 类或接口名
* @param null|Closure|string $concrete 返回类实例的闭包,或是类名
* @param null|\Closure|string $concrete 返回类实例的闭包,或是类名
*/
public function singletonIf(string $abstract, $concrete = null): void;
@ -81,7 +80,7 @@ interface ContainerInterface extends PsrContainerInterface
*
* @param string $abstract 类或接口名
*/
public function factory(string $abstract): Closure;
public function factory(string $abstract): \Closure;
/**
* 清除所有绑定和实例
@ -94,7 +93,7 @@ interface ContainerInterface extends PsrContainerInterface
* @template T
* @param class-string<T> $abstract 类或接口名
* @param array $parameters 参数
* @return Closure|mixed|T 实例
* @return \Closure|mixed|T 实例
*/
public function make(string $abstract, array $parameters = []);

View File

@ -4,15 +4,8 @@ declare(strict_types=1);
namespace ZM\Container;
use Closure;
use Exception;
use InvalidArgumentException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use ReflectionClass;
use ReflectionException;
use ReflectionNamedType;
use ReflectionParameter;
use ZM\Utils\ReflectionUtil;
trait ContainerTrait
@ -55,7 +48,7 @@ trait ContainerTrait
private static $aliases = [];
/**
* @var Closure[][]
* @var \Closure[][]
*/
private static $extenders = [];
@ -103,7 +96,7 @@ trait ContainerTrait
public function alias(string $abstract, string $alias): void
{
if ($alias === $abstract) {
throw new InvalidArgumentException("[{$abstract}] is same as [{$alias}]");
throw new \InvalidArgumentException("[{$abstract}] is same as [{$alias}]");
}
self::$aliases[$alias] = $abstract;
@ -117,7 +110,7 @@ trait ContainerTrait
* 注册绑定
*
* @param string $abstract 类或接口名
* @param null|Closure|string $concrete 返回类实例的闭包,或是类名
* @param null|\Closure|string $concrete 返回类实例的闭包,或是类名
* @param bool $shared 是否共享
*/
public function bind(string $abstract, $concrete = null, bool $shared = false): void
@ -135,7 +128,7 @@ trait ContainerTrait
}
// 如果不是闭包,则认为是类名,此时将其包装在一个闭包中,以方便后续处理
if (!$concrete instanceof Closure) {
if (!$concrete instanceof \Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
@ -152,7 +145,7 @@ trait ContainerTrait
* 在已经绑定时不会重复注册
*
* @param string $abstract 类或接口名
* @param null|Closure|string $concrete 返回类实例的闭包,或是类名
* @param null|\Closure|string $concrete 返回类实例的闭包,或是类名
* @param bool $shared 是否共享
*/
public function bindIf(string $abstract, $concrete = null, bool $shared = false): void
@ -166,7 +159,7 @@ trait ContainerTrait
* 注册一个单例绑定
*
* @param string $abstract 类或接口名
* @param null|Closure|string $concrete 返回类实例的闭包,或是类名
* @param null|\Closure|string $concrete 返回类实例的闭包,或是类名
*/
public function singleton(string $abstract, $concrete = null): void
{
@ -179,7 +172,7 @@ trait ContainerTrait
* 在已经绑定时不会重复注册
*
* @param string $abstract 类或接口名
* @param null|Closure|string $concrete 返回类实例的闭包,或是类名
* @param null|\Closure|string $concrete 返回类实例的闭包,或是类名
*/
public function singletonIf(string $abstract, $concrete = null): void
{
@ -216,7 +209,7 @@ trait ContainerTrait
*
* @param string $abstract 类或接口名
*/
public function factory(string $abstract): Closure
public function factory(string $abstract): \Closure
{
return function () use ($abstract) {
return $this->make($abstract);
@ -247,7 +240,7 @@ trait ContainerTrait
* @template T
* @param class-string<T> $abstract 类或接口名
* @param array $parameters 参数
* @return Closure|mixed|T 实例
* @return \Closure|mixed|T 实例
* @throws EntryResolutionException
*/
public function make(string $abstract, array $parameters = [])
@ -316,20 +309,20 @@ trait ContainerTrait
/**
* 实例化具体的类实例
*
* @param Closure|string $concrete 类名或对应的闭包
* @param \Closure|string $concrete 类名或对应的闭包
* @return mixed
* @throws EntryResolutionException
*/
public function build($concrete)
{
// 如果传入的是闭包,则直接执行并返回
if ($concrete instanceof Closure) {
if ($concrete instanceof \Closure) {
return $concrete($this, $this->getLastParameterOverride());
}
try {
$reflection = new ReflectionClass($concrete);
} catch (ReflectionException $e) {
$reflection = new \ReflectionClass($concrete);
} catch (\ReflectionException $e) {
throw new EntryResolutionException("指定的类 {$concrete} 不存在", 0, $e);
}
@ -402,7 +395,7 @@ trait ContainerTrait
{
try {
return $this->make($id);
} catch (Exception $e) {
} catch (\Exception $e) {
if ($this->has($id)) {
throw new EntryResolutionException('', 0, $e);
}
@ -429,9 +422,9 @@ trait ContainerTrait
* 扩展一个类或接口
*
* @param string $abstract 类或接口名
* @param Closure $closure 扩展闭包
* @param \Closure $closure 扩展闭包
*/
public function extend(string $abstract, Closure $closure): void
public function extend(string $abstract, \Closure $closure): void
{
$abstract = $this->getAlias($abstract);
@ -468,7 +461,7 @@ trait ContainerTrait
* 获取对应类型的所有扩展器
*
* @param string $abstract 类或接口名
* @return Closure[]
* @return \Closure[]
*/
protected function getExtenders(string $abstract): array
{
@ -505,7 +498,7 @@ trait ContainerTrait
* @param string $abstract 类或接口名
* @param string $concrete 实际类名
*/
protected function getClosure(string $abstract, string $concrete): Closure
protected function getClosure(string $abstract, string $concrete): \Closure
{
return static function ($container, $parameters = []) use ($abstract, $concrete) {
$method = $abstract === $concrete ? 'build' : 'make';
@ -542,7 +535,7 @@ trait ContainerTrait
/**
* 解析依赖
*
* @param ReflectionParameter[] $dependencies
* @param \ReflectionParameter[] $dependencies
* @throws EntryResolutionException
*/
protected function resolveDependencies(array $dependencies): array
@ -587,7 +580,7 @@ trait ContainerTrait
/**
* 判断传入的参数是否存在覆盖参数
*/
protected function hasParameterOverride(ReflectionParameter $parameter): bool
protected function hasParameterOverride(\ReflectionParameter $parameter): bool
{
return array_key_exists($parameter->name, $this->getLastParameterOverride());
}
@ -597,7 +590,7 @@ trait ContainerTrait
*
* @return mixed
*/
protected function getParameterOverride(ReflectionParameter $parameter)
protected function getParameterOverride(\ReflectionParameter $parameter)
{
return $this->getLastParameterOverride()[$parameter->name];
}
@ -605,7 +598,7 @@ trait ContainerTrait
/**
* 判断传入的参数是否存在临时注入的参数
*/
protected function hasParameterTypeOverride(ReflectionParameter $parameter): bool
protected function hasParameterTypeOverride(\ReflectionParameter $parameter): bool
{
if (!$parameter->hasType()) {
return false;
@ -613,7 +606,7 @@ trait ContainerTrait
$type = $parameter->getType();
if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) {
if (!$type instanceof \ReflectionNamedType || $type->isBuiltin()) {
return false;
}
@ -625,11 +618,11 @@ trait ContainerTrait
*
* @return mixed
*/
protected function getParameterTypeOverride(ReflectionParameter $parameter)
protected function getParameterTypeOverride(\ReflectionParameter $parameter)
{
$type = $parameter->getType();
if (!$type instanceof ReflectionNamedType) {
if (!$type instanceof \ReflectionNamedType) {
return [];
}
@ -642,7 +635,7 @@ trait ContainerTrait
* @return mixed 对应类型的默认值
* @throws EntryResolutionException 如参数不存在默认值,则抛出异常
*/
protected function resolvePrimitive(ReflectionParameter $parameter)
protected function resolvePrimitive(\ReflectionParameter $parameter)
{
if ($parameter->isDefaultValueAvailable()) {
return $parameter->getDefaultValue();
@ -657,7 +650,7 @@ trait ContainerTrait
* @return mixed
* @throws EntryResolutionException 如果无法解析类,则抛出异常
*/
protected function resolveClass(ReflectionParameter $parameter)
protected function resolveClass(\ReflectionParameter $parameter)
{
try {
// 尝试解析
@ -682,7 +675,7 @@ trait ContainerTrait
* 获取类名的实际类型
*
* @param string $abstract 类或接口名
* @return Closure|string
* @return \Closure|string
*/
protected function getConcrete(string $abstract)
{
@ -701,7 +694,7 @@ trait ContainerTrait
*/
protected function isBuildable($concrete, string $abstract): bool
{
return $concrete === $abstract || $concrete instanceof Closure;
return $concrete === $abstract || $concrete instanceof \Closure;
}
/**

View File

@ -4,9 +4,8 @@ declare(strict_types=1);
namespace ZM\Container;
use Exception;
use Psr\Container\NotFoundExceptionInterface;
class EntryNotFoundException extends Exception implements NotFoundExceptionInterface
class EntryNotFoundException extends \Exception implements NotFoundExceptionInterface
{
}

View File

@ -4,9 +4,8 @@ declare(strict_types=1);
namespace ZM\Container;
use Exception;
use Psr\Container\ContainerExceptionInterface;
class EntryResolutionException extends Exception implements ContainerExceptionInterface
class EntryResolutionException extends \Exception implements ContainerExceptionInterface
{
}

View File

@ -6,7 +6,6 @@ namespace ZM\Event;
use OneBot\Driver\Interfaces\SortedProviderInterface;
use OneBot\Util\Singleton;
use Stringable;
class EventProvider implements SortedProviderInterface
{
@ -73,7 +72,7 @@ class EventProvider implements SortedProviderInterface
/**
* 排序事件
*
* @param string|Stringable $name
* @param string|\Stringable $name
*/
private function sortEvents($name)
{

View File

@ -8,8 +8,6 @@ use OneBot\Driver\Event\Http\HttpRequestEvent;
use OneBot\Http\HttpFactory;
use OneBot\Http\Stream;
use OneBot\Util\Singleton;
use Stringable;
use Throwable;
use ZM\Annotation\AnnotationHandler;
use ZM\Annotation\Framework\BindEvent;
use ZM\Annotation\Http\Route;
@ -26,7 +24,7 @@ class HttpEventListener
* 这里处理框架特有的内容,比如:
* 路由、断点续传、注解再分发等
*
* @throws Throwable
* @throws \Throwable
*/
public function onRequest999(HttpRequestEvent $event)
{
@ -56,7 +54,7 @@ class HttpEventListener
$div->class = $node['class'];
$starttime = microtime(true);
$handler->handle($div, null, $params, $event->getRequest(), $event);
if (is_string($val = $handler->getReturnVal()) || ($val instanceof Stringable)) {
if (is_string($val = $handler->getReturnVal()) || ($val instanceof \Stringable)) {
$event->withResponse(HttpFactory::getInstance()->createResponse(200, null, [], Stream::create($val)));
} elseif ($event->getResponse() === null) {
$event->withResponse(HttpFactory::getInstance()->createResponse(500));

View File

@ -4,20 +4,32 @@ declare(strict_types=1);
namespace ZM\Event\Listener;
use OneBot\Driver\Event\WebSocket\WebSocketCloseEvent;
use OneBot\Driver\Event\WebSocket\WebSocketOpenEvent;
use OneBot\Driver\Process\ProcessManager;
use OneBot\Http\HttpFactory;
use OneBot\Util\Singleton;
use ZM\Container\ContainerServicesProvider;
use ZM\Process\ProcessStateManager;
class WSEventListener
{
use Singleton;
private static int $ws_counter = 0;
private static array $conn_handle = [];
public function onWebSocketOpen(WebSocketOpenEvent $event)
{
// 计数,最多只能接入 1024 个连接,为了适配多进程
++self::$ws_counter;
if (self::$ws_counter >= 1024) {
$event->withResponse(HttpFactory::getInstance()->createResponse(503));
return;
}
// 注册容器
resolve(ContainerServicesProvider::class)->registerServices('connection');
// 判断是不是 OneBot 12 反向 WS 连进来的,通过 Sec-WebSocket-Protocol 头
$line = explode('.', $event->getRequest()->getHeaderLine('Sec-WebSocket-Protocol'), 2);
if ($line[0] === '12') {
@ -32,6 +44,25 @@ class WSEventListener
}
}
// 这里下面为连接准入,允许接入反向 WSTODO
if (ProcessStateManager::$process_mode['worker'] > 1) {
// 如果开了多 Worker则需要将连接信息写入文件以便跨进程读取
$info = ['impl' => $line[1] ?? 'unknown'];
self::$conn_handle[$event->getFd()] = $info;
file_put_contents(zm_dir(ZM_STATE_DIR . '/.WS' . $event->getFd() . '.' . ProcessManager::getProcessId()), json_encode($info));
}
}
}
public function onWebSocketClose(WebSocketCloseEvent $event)
{
--self::$ws_counter;
// 删除连接信息
$fd = $event->getFd();
$filename = zm_dir(ZM_STATE_DIR . '/.WS' . $fd . '.' . ProcessManager::getProcessId());
if (file_exists($filename)) {
unlink($filename);
}
unset(self::$conn_handle[$fd]);
resolve(ContainerServicesProvider::class)->cleanup();
}
}

View File

@ -6,7 +6,6 @@ namespace ZM\Event\Listener;
use OneBot\Driver\Process\ProcessManager;
use OneBot\Util\Singleton;
use Throwable;
use ZM\Annotation\AnnotationHandler;
use ZM\Annotation\AnnotationMap;
use ZM\Annotation\AnnotationParser;
@ -26,7 +25,7 @@ class WorkerEventListener
/**
* Driver Worker 进程启动后执行的事件
*
* @throws Throwable
* @throws \Throwable
*/
public function onWorkerStart999()
{
@ -113,7 +112,7 @@ class WorkerEventListener
/**
* 加载用户代码资源包括普通插件、单文件插件、Composer 插件等
* @throws Throwable
* @throws \Throwable
*/
private function initUserPlugins()
{
@ -143,7 +142,7 @@ class WorkerEventListener
}
/**
* @throws Throwable
* @throws \Throwable
*/
private function dispatchInit()
{

View File

@ -4,15 +4,13 @@ declare(strict_types=1);
namespace ZM\Exception;
use Throwable;
class ConfigException extends ZMException
{
public const UNSUPPORTED_FILE_TYPE = 'E00079';
public const LOAD_CONFIG_FAILED = 'E00080';
public function __construct($err_code, $message = '', $code = 0, Throwable $previous = null)
public function __construct($err_code, $message = '', $code = 0, \Throwable $previous = null)
{
parent::__construct(zm_internal_errcode($err_code) . $message, $code, $previous);
}

View File

@ -4,13 +4,11 @@ declare(strict_types=1);
namespace ZM\Exception;
use Throwable;
class InterruptException extends ZMException
{
public $return_var;
public function __construct($return_var = null, $message = '', $code = 0, Throwable $previous = null)
public function __construct($return_var = null, $message = '', $code = 0, \Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->return_var = $return_var;

View File

@ -4,11 +4,9 @@ declare(strict_types=1);
namespace ZM\Exception;
use Throwable;
class InvalidArgumentException extends ZMException
{
public function __construct($message = '', $code = 0, Throwable $previous = null)
public function __construct($message = '', $code = 0, \Throwable $previous = null)
{
parent::__construct(zm_internal_errcode('E00074') . $message, $code, $previous);
}

View File

@ -4,8 +4,6 @@ declare(strict_types=1);
namespace ZM\Exception;
use Exception;
abstract class ZMException extends Exception
abstract class ZMException extends \Exception
{
}

View File

@ -4,11 +4,9 @@ declare(strict_types=1);
namespace ZM\Exception;
use Throwable;
class ZMKnownException extends ZMException
{
public function __construct($err_code, $message = '', $code = 0, Throwable $previous = null)
public function __construct($err_code, $message = '', $code = 0, \Throwable $previous = null)
{
parent::__construct(zm_internal_errcode($err_code) . $message, $code, $previous);
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM;
use Exception;
use OneBot\Driver\Driver;
use OneBot\Driver\Event\DriverInitEvent;
use OneBot\Driver\Event\Http\HttpRequestEvent;
@ -12,6 +11,7 @@ use OneBot\Driver\Event\Process\ManagerStartEvent;
use OneBot\Driver\Event\Process\ManagerStopEvent;
use OneBot\Driver\Event\Process\WorkerStartEvent;
use OneBot\Driver\Event\Process\WorkerStopEvent;
use OneBot\Driver\Event\WebSocket\WebSocketCloseEvent;
use OneBot\Driver\Event\WebSocket\WebSocketOpenEvent;
use OneBot\Driver\Interfaces\DriverInitPolicy;
use OneBot\Driver\Swoole\SwooleDriver;
@ -46,23 +46,23 @@ class Framework
public const VERSION_ID = 627;
/** @var string 版本名称 */
public const VERSION = '3.0.0-alpha3';
public const VERSION = '3.0.0-alpha4';
/** @var array 传入的参数 */
protected $argv;
protected array $argv;
/** @var Driver|SwooleDriver|WorkermanDriver OneBot驱动 */
protected $driver;
protected SwooleDriver|Driver|WorkermanDriver $driver;
/** @var array<array<string, string>> 启动注解列表 */
protected $setup_annotations = [];
protected array $setup_annotations = [];
/**
* 框架初始化文件
*
* @param array<string, null|bool|string> $argv 传入的参数(见 ServerStartCommand
* @throws InitException
* @throws Exception
* @throws \Exception
*/
public function __construct(array $argv = [])
{
@ -77,7 +77,7 @@ class Framework
}
/**
* @throws Exception
* @throws \Exception
*/
public function init(): Framework
{
@ -96,7 +96,7 @@ class Framework
/**
* 启动框架
*/
public function start()
public function start(): void
{
// 对多进程有效,记录当前已经加载的所有文件,最后在 Worker 进程中比较可重载的文件,用于排错
global $zm_loaded_files;
@ -249,9 +249,9 @@ class Framework
* 初始化驱动及相关事件
* 实例化 Driver 对象
*
* @throws Exception
* @throws \Exception
*/
public function initDriver()
public function initDriver(): void
{
switch ($driver = config('global.driver')) {
case 'swoole':
@ -278,10 +278,8 @@ class Framework
* 初始化框架并输出一些信息
*
* 绑定、注册框架本身的事件到 Driver EventProvider
*
* @throws ConfigException
*/
public function initFramework()
public function initFramework(): void
{
// private-mode 模式下,不输出任何内容
if (!$this->argv['private-mode']) {
@ -303,17 +301,16 @@ class Framework
ob_event_provider()->addEventListener(DriverInitEvent::getName(), [MasterEventListener::getInstance(), 'onMasterStart'], 999);
// websocket 事件
ob_event_provider()->addEventListener(WebSocketOpenEvent::getName(), [WSEventListener::getInstance(), 'onWebSocketOpen'], 999);
ob_event_provider()->addEventListener(WebSocketCloseEvent::getName(), [WSEventListener::getInstance(), 'onWebSocketClose'], 999);
// 框架多进程依赖
if (defined('ZM_PID_DIR') && !is_dir(ZM_STATE_DIR)) {
if (defined('ZM_STATE_DIR') && !is_dir(ZM_STATE_DIR)) {
mkdir(ZM_STATE_DIR);
}
}
/**
* 打印属性表格
* @noinspection PhpComposerExtensionStubsInspection
* @throws ConfigException
*/
private function printProperties(): void
{
@ -491,9 +488,9 @@ class Framework
/**
* 初始化 OnSetup 注解
*/
private function initSetupAnnotations()
private function initSetupAnnotations(): void
{
if (Phar::running() !== '') {
if (\Phar::running() !== '') {
// 在 Phar 下,不需要新启动进程了,因为 Phar 没办法重载,自然不需要考虑多进程的加载 reload 问题
require FRAMEWORK_ROOT_DIR . '/src/Globals/script_setup_loader.php';
$r = _zm_setup_loader();

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM;
use Exception;
use ZM\Command\Server\ServerStartCommand;
use ZM\Exception\InitException;
use ZM\Plugin\InstantPlugin;
@ -44,7 +43,7 @@ class InstantApplication extends InstantPlugin
}
/**
* @throws Exception
* @throws \Exception
*/
public function run()
{

View File

@ -4,9 +4,7 @@ declare(strict_types=1);
namespace ZM\Middleware;
use Closure;
use OneBot\Util\Singleton;
use Throwable;
use ZM\Exception\InvalidArgumentException;
class MiddlewareHandler
@ -107,7 +105,7 @@ class MiddlewareHandler
$after_result = container()->call($this->middlewares[$item[0]]['after'], $args);
}
}
} catch (Throwable $e) {
} catch (\Throwable $e) {
while (isset($this->stack[$stack_id]) && ($item = array_pop($this->stack[$stack_id])) !== null) {
// 如果是 pipeline 形式的中间件,则使用闭包回去
if (class_exists($item[0]) && is_a($item[0], PipelineInterface::class, true)) {
@ -134,7 +132,7 @@ class MiddlewareHandler
/**
* @throws InvalidArgumentException
* @throws Throwable
* @throws \Throwable
*/
public function process(callable $callback, ...$args)
{
@ -169,7 +167,7 @@ class MiddlewareHandler
*/
public function getStackId(callable $callback): string
{
if ($callback instanceof Closure) {
if ($callback instanceof \Closure) {
// 闭包情况下直接根据闭包的ID号来找stack
return strval(spl_object_id($callback));
}

View File

@ -8,12 +8,10 @@ namespace ZM\Store\Database;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\ParameterType;
use PDO;
use PDOException;
class DBConnection implements Connection
{
/** @var PDO */
/** @var \PDO */
private $conn;
private $pool_name;
@ -42,7 +40,7 @@ class DBConnection implements Connection
logger()->debug('Running SQL prepare: ' . $sql);
$statement = $this->conn->prepare($sql, $options);
assert($statement !== false);
} catch (PDOException $exception) {
} catch (\PDOException $exception) {
throw new DBException($exception->getMessage(), 0, $exception);
}
return new DBStatement($statement);
@ -56,7 +54,7 @@ class DBConnection implements Connection
try {
$statement = $this->conn->query(...$args);
assert($statement !== false);
} catch (PDOException $exception) {
} catch (\PDOException $exception) {
throw new DBException($exception->getMessage(), 0, $exception);
}
return new DBStatement($statement);
@ -78,7 +76,7 @@ class DBConnection implements Connection
$statement = $this->conn->exec($sql);
assert($statement !== false);
return $statement;
} catch (PDOException $exception) {
} catch (\PDOException $exception) {
throw new DBException($exception->getMessage(), 0, $exception);
}
}
@ -91,7 +89,7 @@ class DBConnection implements Connection
{
try {
return $name === null ? $this->conn->lastInsertId() : $this->conn->lastInsertId($name);
} catch (PDOException $exception) {
} catch (\PDOException $exception) {
throw new DBException($exception->getMessage(), 0, $exception);
}
}

View File

@ -12,8 +12,6 @@ use OneBot\Driver\Swoole\ObjectPool as SwooleObjectPool;
use OneBot\Driver\Swoole\SwooleDriver;
use OneBot\Driver\Workerman\ObjectPool as WorkermanObjectPool;
use OneBot\Driver\Workerman\WorkermanDriver;
use PDO;
use RuntimeException;
use ZM\Store\FileSystem;
class DBPool
@ -60,10 +58,10 @@ class DBPool
}
switch (Driver::getActiveDriverClass()) {
case WorkermanDriver::class:
self::$pools[$name] = new WorkermanObjectPool($size, PDO::class, $connect_str, ...$args);
self::$pools[$name] = new WorkermanObjectPool($size, \PDO::class, $connect_str, ...$args);
break;
case SwooleDriver::class:
self::$pools[$name] = new SwooleObjectPool($size, PDO::class, $connect_str, ...$args);
self::$pools[$name] = new SwooleObjectPool($size, \PDO::class, $connect_str, ...$args);
}
}
@ -76,7 +74,7 @@ class DBPool
public static function pool(string $name)
{
if (!isset(self::$pools[$name]) && count(self::$pools) !== 1) {
throw new RuntimeException("Pool {$name} not found");
throw new \RuntimeException("Pool {$name} not found");
}
return self::$pools[$name] ?? self::$pools[array_key_first(self::$pools)];
}

View File

@ -10,14 +10,10 @@ namespace ZM\Store\Database;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\ParameterType;
use IteratorAggregate;
use PDO;
use PDOStatement;
use Traversable;
class DBStatement implements IteratorAggregate, Statement
class DBStatement implements \IteratorAggregate, Statement
{
/** @var PDOStatement */
/** @var \PDOStatement */
private $statement;
public function __construct($obj)
@ -50,12 +46,12 @@ class DBStatement implements IteratorAggregate, Statement
return $this->statement->setFetchMode($fetchMode);
}
public function fetch($fetchMode = PDO::FETCH_ASSOC, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
public function fetch($fetchMode = \PDO::FETCH_ASSOC, $cursorOrientation = \PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
{
return $this->statement->fetch($fetchMode, $cursorOrientation, $cursorOffset);
}
public function fetchAll($fetchMode = PDO::FETCH_ASSOC, $fetchArgument = null, $ctorArgs = null)
public function fetchAll($fetchMode = \PDO::FETCH_ASSOC, $fetchArgument = null, $ctorArgs = null)
{
if ($fetchArgument === null && $ctorArgs === null) {
return $this->statement->fetchAll($fetchMode);
@ -102,7 +98,7 @@ class DBStatement implements IteratorAggregate, Statement
return $this->statement->rowCount();
}
public function getIterator(): Traversable
public function getIterator(): \Traversable
{
while (($result = $this->statement->fetch()) !== false) {
yield $result;

View File

@ -11,8 +11,6 @@ namespace ZM\Store\Database;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\ForwardCompatibility\Result;
use Throwable;
use Traversable;
class DBStatementWrapper
{
@ -52,7 +50,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->fetchNumeric();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -66,7 +64,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->fetchAssociative();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -80,7 +78,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->fetchOne();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -93,7 +91,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->fetchAllNumeric();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -106,7 +104,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->fetchAllAssociative();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -119,7 +117,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->fetchAllKeyValue();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -132,7 +130,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->fetchAllAssociativeIndexed();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -145,7 +143,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->fetchFirstColumn();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -154,11 +152,11 @@ class DBStatementWrapper
* wrapper method
* @throws DBException
*/
public function iterateNumeric(): Traversable
public function iterateNumeric(): \Traversable
{
try {
return $this->stmt->iterateNumeric();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -167,11 +165,11 @@ class DBStatementWrapper
* wrapper method
* @throws DBException
*/
public function iterateAssociative(): Traversable
public function iterateAssociative(): \Traversable
{
try {
return $this->stmt->iterateAssociative();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -180,11 +178,11 @@ class DBStatementWrapper
* wrapper method
* @throws DBException
*/
public function iterateKeyValue(): Traversable
public function iterateKeyValue(): \Traversable
{
try {
return $this->stmt->iterateKeyValue();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -193,11 +191,11 @@ class DBStatementWrapper
* wrapper method
* @throws DBException
*/
public function iterateAssociativeIndexed(): Traversable
public function iterateAssociativeIndexed(): \Traversable
{
try {
return $this->stmt->iterateAssociativeIndexed();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -206,11 +204,11 @@ class DBStatementWrapper
* wrapper method
* @throws DBException
*/
public function iterateColumn(): Traversable
public function iterateColumn(): \Traversable
{
try {
return $this->stmt->iterateColumn();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -224,7 +222,7 @@ class DBStatementWrapper
{
try {
return $this->stmt->rowCount();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}

View File

@ -4,14 +4,11 @@ declare(strict_types=1);
namespace ZM\Store\Database;
use Closure;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Types\Type;
use Throwable;
use Traversable;
class DBWrapper
{
@ -33,7 +30,7 @@ class DBWrapper
} else {
throw new DBException('Cannot find database config named "' . $name . '" !');
}
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -76,7 +73,7 @@ class DBWrapper
{
try {
return $this->connection->fetchAssociative($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), intval($e->getCode()), $e);
}
}
@ -90,7 +87,7 @@ class DBWrapper
{
try {
return $this->connection->fetchNumeric($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -103,7 +100,7 @@ class DBWrapper
{
try {
return $this->connection->fetchOne($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -124,7 +121,7 @@ class DBWrapper
{
try {
return $this->connection->delete($table, $criteria, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -155,7 +152,7 @@ class DBWrapper
{
try {
return $this->connection->update($table, $data, $criteria, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -169,7 +166,7 @@ class DBWrapper
{
try {
return $this->connection->insert($table, $data, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -206,7 +203,7 @@ class DBWrapper
{
try {
return $this->connection->fetchAllNumeric($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -224,7 +221,7 @@ class DBWrapper
{
try {
return $this->connection->fetchAllAssociative($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -241,7 +238,7 @@ class DBWrapper
{
try {
return $this->connection->fetchAllKeyValue($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -259,7 +256,7 @@ class DBWrapper
{
try {
return $this->connection->fetchAllAssociativeIndexed($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -277,7 +274,7 @@ class DBWrapper
{
try {
return $this->connection->fetchFirstColumn($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -288,14 +285,14 @@ class DBWrapper
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @return Traversable<int,array<int,mixed>>
* @return \Traversable<int,array<int,mixed>>
* @throws DBException
*/
public function iterateNumeric(string $query, array $params = [], array $types = []): Traversable
public function iterateNumeric(string $query, array $params = [], array $types = []): \Traversable
{
try {
return $this->connection->iterateNumeric($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -306,14 +303,14 @@ class DBWrapper
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @return Traversable<int,array<string,mixed>>
* @return \Traversable<int,array<string,mixed>>
* @throws DBException
*/
public function iterateAssociative(string $query, array $params = [], array $types = []): Traversable
public function iterateAssociative(string $query, array $params = [], array $types = []): \Traversable
{
try {
return $this->connection->iterateAssociative($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -324,14 +321,14 @@ class DBWrapper
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string>|array<string, int|string> $types Parameter types
*
* @return Traversable<mixed,mixed>
* @return \Traversable<mixed,mixed>
* @throws DBException
*/
public function iterateKeyValue(string $query, array $params = [], array $types = []): Traversable
public function iterateKeyValue(string $query, array $params = [], array $types = []): \Traversable
{
try {
return $this->connection->iterateKeyValue($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -342,14 +339,14 @@ class DBWrapper
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, int|string>|array<string, int|string> $types Parameter types
*
* @return Traversable<mixed,array<string,mixed>>
* @return \Traversable<mixed,array<string,mixed>>
* @throws DBException
*/
public function iterateAssociativeIndexed(string $query, array $params = [], array $types = []): Traversable
public function iterateAssociativeIndexed(string $query, array $params = [], array $types = []): \Traversable
{
try {
return $this->connection->iterateAssociativeIndexed($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -360,14 +357,14 @@ class DBWrapper
* @param array<int, mixed>|array<string, mixed> $params Query parameters
* @param array<int, null|int|string|Type>|array<string, null|int|string|Type> $types Parameter types
*
* @return Traversable<int,mixed>
* @return \Traversable<int,mixed>
* @throws DBException
*/
public function iterateColumn(string $query, array $params = [], array $types = []): Traversable
public function iterateColumn(string $query, array $params = [], array $types = []): \Traversable
{
try {
return $this->connection->iterateColumn($query, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -385,7 +382,7 @@ class DBWrapper
try {
$query = $this->connection->executeQuery($sql, $params, $types, $qcp);
return new DBStatementWrapper($query);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw $e;
// throw new DBException($e->getMessage(), intval($e->getCode()), $e);
}
@ -403,7 +400,7 @@ class DBWrapper
try {
$query = $this->connection->executeCacheQuery($sql, $params, $types, $qcp);
return new DBStatementWrapper($query);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -421,7 +418,7 @@ class DBWrapper
{
try {
return $this->connection->executeStatement($sql, $params, $types);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -449,14 +446,14 @@ class DBWrapper
* @return mixed
* @throws DBException
*/
public function transactional(Closure $func)
public function transactional(\Closure $func)
{
$this->beginTransaction();
try {
$res = $func($this);
$this->commit();
return $res;
} catch (Throwable $e) {
} catch (\Throwable $e) {
$this->rollBack();
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
@ -470,7 +467,7 @@ class DBWrapper
{
try {
$this->connection->setNestTransactionsWithSavepoints($nest_transactions_with_savepoints);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -499,7 +496,7 @@ class DBWrapper
{
try {
return $this->connection->commit();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -512,7 +509,7 @@ class DBWrapper
{
try {
return $this->connection->rollBack();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -526,7 +523,7 @@ class DBWrapper
{
try {
$this->connection->createSavepoint($savepoint);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -540,7 +537,7 @@ class DBWrapper
{
try {
$this->connection->releaseSavepoint($savepoint);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -554,7 +551,7 @@ class DBWrapper
{
try {
$this->connection->rollbackSavepoint($savepoint);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -567,7 +564,7 @@ class DBWrapper
{
try {
$this->connection->setRollbackOnly();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}
@ -580,7 +577,7 @@ class DBWrapper
{
try {
return $this->connection->isRollbackOnly();
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new DBException($e->getMessage(), $e->getCode(), $e);
}
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace ZM\Store;
use RuntimeException;
use ZM\Utils\ZMUtil;
class FileSystem
@ -85,7 +84,7 @@ class FileSystem
public static function createDir(string $path): void
{
if (!is_dir($path) && !mkdir($path, 0777, true) && !is_dir($path)) {
throw new RuntimeException(sprintf('无法建立目录:%s', $path));
throw new \RuntimeException(sprintf('无法建立目录:%s', $path));
}
}

View File

@ -31,11 +31,8 @@ class HttpUtil
* 返回值为状态
* 第二个参数为路由节点
* 第三个参数为动态路由节点中匹配到的参数列表
*
* @param mixed $node
* @param mixed $params
*/
public static function parseUri(ServerRequest $request, &$node, &$params): int
public static function parseUri(ServerRequest $request, mixed &$node, mixed &$params): int
{
// 建立上下文,设置当前请求的方法
$context = new RequestContext();

View File

@ -4,28 +4,23 @@ declare(strict_types=1);
namespace ZM\Utils;
use Closure;
use ReflectionException;
use ReflectionFunction;
use ReflectionFunctionAbstract;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionParameter;
class ReflectionUtil
{
/**
* 获取参数的类名(如有)
*
* @param ReflectionParameter $parameter 参数
* @param \ReflectionParameter $parameter 参数
* @return null|string 类名,如果参数不是类,返回 null
*/
public static function getParameterClassName(ReflectionParameter $parameter): ?string
public static function getParameterClassName(\ReflectionParameter $parameter): ?string
{
// 获取参数类型
$type = $parameter->getType();
// 没有声明类型或为基本类型
if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) {
if (!$type instanceof \ReflectionNamedType || $type->isBuiltin()) {
return null;
}
@ -86,12 +81,12 @@ class ReflectionUtil
* 判断传入的回调是否为任意类的非静态方法
*
* @param callable|string $callback 回调
* @throws ReflectionException
* @throws \ReflectionException
*/
public static function isNonStaticMethod($callback): bool
{
if (is_array($callback) && is_string($callback[0])) {
$reflection = new ReflectionMethod($callback[0], $callback[1]);
$reflection = new \ReflectionMethod($callback[0], $callback[1]);
return !$reflection->isStatic();
}
return false;
@ -106,19 +101,19 @@ class ReflectionUtil
* 可传入实现了 __invoke 的类
*
* @param callable|string $callback 回调
* @throws ReflectionException
* @throws \ReflectionException
*/
public static function getCallReflector($callback): ReflectionFunctionAbstract
public static function getCallReflector($callback): \ReflectionFunctionAbstract
{
if (is_string($callback) && str_contains($callback, '::')) {
$callback = explode('::', $callback);
} elseif (is_object($callback) && !$callback instanceof Closure) {
} elseif (is_object($callback) && !$callback instanceof \Closure) {
$callback = [$callback, '__invoke'];
}
return is_array($callback)
? new ReflectionMethod($callback[0], $callback[1])
: new ReflectionFunction($callback);
? new \ReflectionMethod($callback[0], $callback[1])
: new \ReflectionFunction($callback);
}
/**
@ -128,9 +123,9 @@ class ReflectionUtil
*
* @param string $class 类名
* @param string $method 方法名
* @throws ReflectionException
* @throws \ReflectionException
*/
public static function getMethod(string $class, string $method): ReflectionMethod
public static function getMethod(string $class, string $method): \ReflectionMethod
{
$class = new \ReflectionClass($class);
$method = $class->getMethod($method);

View File

@ -4,13 +4,7 @@ declare(strict_types=1);
namespace Tests\ZM\Utils;
use Closure;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use ReflectionFunction;
use ReflectionFunctionAbstract;
use ReflectionMethod;
use stdClass;
use ZM\Utils\ReflectionUtil;
/**
@ -30,7 +24,7 @@ class ReflectionUtilTest extends TestCase
public function testGetParameterClassName(): void
{
$class = new ReflectionClass(ReflectionUtilTestClass::class);
$class = new \ReflectionClass(ReflectionUtilTestClass::class);
$method = $class->getMethod('method');
[$string_parameter, $object_parameter] = $method->getParameters();
@ -52,10 +46,10 @@ class ReflectionUtilTest extends TestCase
return [
'callable' => [[new ReflectionUtilTestClass(), 'method'], ReflectionUtilTestClass::class . '@method'],
'static callable' => [[ReflectionUtilTestClass::class, 'staticMethod'], ReflectionUtilTestClass::class . '::staticMethod'],
'closure' => [Closure::fromCallable([$this, 'testVariableToString']), 'closure'],
'closure' => [\Closure::fromCallable([$this, 'testVariableToString']), 'closure'],
'string' => ['string', 'string'],
'array' => [['123', '42', 'hello', 122], 'array["123","42","hello",122]'],
'object' => [new stdClass(), 'stdClass'],
'object' => [new \stdClass(), 'stdClass'],
'resource' => [fopen('php://memory', 'rb'), 'resource(stream)'],
'null' => [null, 'null'],
'boolean 1' => [true, 'true'],
@ -69,7 +63,7 @@ class ReflectionUtilTest extends TestCase
* @dataProvider provideTestGetCallReflector
* @param mixed $callback
*/
public function testGetCallReflector($callback, ReflectionFunctionAbstract $expected): void
public function testGetCallReflector($callback, \ReflectionFunctionAbstract $expected): void
{
$this->assertEquals($expected, ReflectionUtil::getCallReflector($callback));
}
@ -80,11 +74,11 @@ class ReflectionUtilTest extends TestCase
};
return [
'callable' => [[new ReflectionUtilTestClass(), 'method'], new ReflectionMethod(ReflectionUtilTestClass::class, 'method')],
'static callable' => [[ReflectionUtilTestClass::class, 'staticMethod'], new ReflectionMethod(ReflectionUtilTestClass::class, 'staticMethod')],
'class::method' => [ReflectionUtilTestClass::class . '::staticMethod', new ReflectionMethod(ReflectionUtilTestClass::class, 'staticMethod')],
'invokable class' => [new InvokableClass(), new ReflectionMethod(InvokableClass::class, '__invoke')],
'closure' => [$closure, new ReflectionFunction($closure)],
'callable' => [[new ReflectionUtilTestClass(), 'method'], new \ReflectionMethod(ReflectionUtilTestClass::class, 'method')],
'static callable' => [[ReflectionUtilTestClass::class, 'staticMethod'], new \ReflectionMethod(ReflectionUtilTestClass::class, 'staticMethod')],
'class::method' => [ReflectionUtilTestClass::class . '::staticMethod', new \ReflectionMethod(ReflectionUtilTestClass::class, 'staticMethod')],
'invokable class' => [new InvokableClass(), new \ReflectionMethod(InvokableClass::class, '__invoke')],
'closure' => [$closure, new \ReflectionFunction($closure)],
];
}
}

View File

@ -9,7 +9,6 @@ use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Runner\PhptTestCase;
use PHPUnit\Util\Color;
use PHPUnit\Util\TestDox\CliTestDoxPrinter;
use Throwable;
class ZMResultPrinter extends CliTestDoxPrinter
{
@ -164,7 +163,7 @@ class ZMResultPrinter extends CliTestDoxPrinter
}
}
protected function formatTestResultMessage(Throwable $t, array $result, ?string $prefix = null): string
protected function formatTestResultMessage(\Throwable $t, array $result, ?string $prefix = null): string
{
$message = $this->formatThrowable($t, $result['status']);
$diff = '';