mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-02 14:25:38 +08:00
update to 2.5.0-b1 (build 408)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,7 +2,6 @@
|
|||||||
/src/test/
|
/src/test/
|
||||||
/src/webconsole/config/
|
/src/webconsole/config/
|
||||||
/vendor/
|
/vendor/
|
||||||
zm.json
|
|
||||||
/zm_data/
|
/zm_data/
|
||||||
composer.lock
|
composer.lock
|
||||||
/resources/server.phar
|
/resources/server.phar
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
/** @noinspection ALL */<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Copyright: Swlib
|
* Copyright: Swlib
|
||||||
* Author: Twosee <twose@qq.com>
|
* Author: Twosee <twose@qq.com>
|
||||||
* Date: 2018/4/14 下午10:58
|
* Date: 2018/4/14 下午10:58
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Co::set([
|
use Swoole\Coroutine;
|
||||||
'log_level' => SWOOLE_LOG_INFO,
|
|
||||||
|
Coroutine::set([
|
||||||
|
'log_level' => SWOOLE_LOG_INFO,
|
||||||
'trace_flags' => 0
|
'trace_flags' => 0
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!ini_get('date.timezone')) {
|
if (!ini_get('date.timezone')) {
|
||||||
ini_set('date.timezone', 'UTC');
|
ini_set('date.timezone', 'Asia/Shanghai');
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ([
|
foreach ([
|
||||||
@@ -55,12 +57,12 @@ if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
|
|||||||
/** @noinspection PhpIncludeInspection */
|
/** @noinspection PhpIncludeInspection */
|
||||||
require PHPUNIT_COMPOSER_INSTALL;
|
require PHPUNIT_COMPOSER_INSTALL;
|
||||||
$starttime = microtime(true);
|
$starttime = microtime(true);
|
||||||
go(function (){
|
go(function () {
|
||||||
try{
|
try {
|
||||||
PHPUnit\TextUI\Command::main(false);
|
PHPUnit\TextUI\Command::main(false);
|
||||||
} catch(Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo $e->getMessage().PHP_EOL;
|
echo $e->getMessage() . PHP_EOL;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Swoole\Event::wait();
|
Swoole\Event::wait();
|
||||||
echo "Took ".round(microtime(true) - $starttime, 4). "s\n";
|
echo "Took " . round(microtime(true) - $starttime, 4) . "s\n";
|
||||||
|
|||||||
27
bin/start
27
bin/start
@@ -1,23 +1,34 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
# shellcheck disable=SC2068
|
||||||
|
# shellcheck disable=SC2181
|
||||||
|
# author: crazywhalecc
|
||||||
|
# since: 2.5.0
|
||||||
|
|
||||||
if [ -f "$(pwd)/runtime/php" ]; then
|
if [ -f "$(pwd)/runtime/php" ]; then
|
||||||
executable="$(pwd)/runtime/php"
|
executable="$(pwd)/runtime/php"
|
||||||
echo "* Framework started with built-in php."
|
echo "* Framework started with built-in php."
|
||||||
else
|
else
|
||||||
which php >/dev/null 2>&1
|
which php >/dev/null 2>&1
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
executable=$(which php)
|
executable=$(which php)
|
||||||
else
|
else
|
||||||
echo 'Cannot find any PHP runtime, please use command `./install-runtime.sh` or install PHP manually!'
|
echo '[ErrCode:E00014] Cannot find any PHP runtime, please use command "./install-runtime.sh" or install PHP manually!'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
result=$(echo "$1" | grep -E "module|build")
|
||||||
|
|
||||||
|
if [ "$result" != "" ]; then
|
||||||
|
executable="$executable -d phar.readonly=off"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f "$(pwd)/src/entry.php" ]; then
|
if [ -f "$(pwd)/src/entry.php" ]; then
|
||||||
$executable "$(pwd)/src/entry.php" $@
|
$executable "$(pwd)/src/entry.php" $@
|
||||||
elif [ -f "$(pwd)/vendor/zhamao/framework/src/entry.php" ]; then
|
elif [ -f "$(pwd)/vendor/zhamao/framework/src/entry.php" ]; then
|
||||||
$executable "$(pwd)/vendor/zhamao/framework/src/entry.php" $@
|
$executable "$(pwd)/vendor/zhamao/framework/src/entry.php" $@
|
||||||
else
|
else
|
||||||
echo "Cannot find zhamao-framework entry file!"
|
echo "[ErrCode:E00015] Cannot find zhamao-framework entry file!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -23,17 +23,18 @@
|
|||||||
"php": ">=7.2",
|
"php": ">=7.2",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-posix": "*",
|
"ext-posix": "*",
|
||||||
"ext-pcntl": "*",
|
|
||||||
"doctrine/annotations": "~1.12 || ~1.4.0",
|
"doctrine/annotations": "~1.12 || ~1.4.0",
|
||||||
"psy/psysh": "@stable",
|
|
||||||
"symfony/polyfill-ctype": "^1.19",
|
"symfony/polyfill-ctype": "^1.19",
|
||||||
"symfony/polyfill-mbstring": "^1.19",
|
"symfony/polyfill-mbstring": "^1.19",
|
||||||
"symfony/console": "~5.0 || ~4.0 || ~3.0",
|
"symfony/console": "~5.0 || ~4.0 || ~3.0",
|
||||||
"symfony/routing": "~5.0 || ~4.0 || ~3.0",
|
"symfony/routing": "~5.0 || ~4.0 || ~3.0",
|
||||||
"zhamao/console": "^1.0.10",
|
"zhamao/console": "^1.0",
|
||||||
"zhamao/config": "^1.0",
|
"zhamao/config": "^1.0",
|
||||||
"zhamao/request": "^1.1",
|
"zhamao/request": "^1.1",
|
||||||
"zhamao/connection-manager": "^1.0"
|
"zhamao/connection-manager": "^1.0",
|
||||||
|
"jelix/version": "^2.0",
|
||||||
|
"league/climate": "^3.7",
|
||||||
|
"psy/psysh": "^0.10.8"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-ctype": "Use C/C++ extension instead of polyfill will be more efficient",
|
"ext-ctype": "Use C/C++ extension instead of polyfill will be more efficient",
|
||||||
@@ -51,6 +52,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"swoole/ide-helper": "@dev"
|
"swoole/ide-helper": "@dev",
|
||||||
|
"phpunit/phpunit": "^8.5 || ^9.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ $config['swoole'] = [
|
|||||||
//'task_enable_coroutine' => true
|
//'task_enable_coroutine' => true
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** 一些框架与Swoole运行时设置的调整 */
|
||||||
|
$config['runtime'] = [
|
||||||
|
'swoole_coroutine_hook_flags' => SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL)
|
||||||
|
];
|
||||||
|
|
||||||
/** 轻量字符串缓存,默认开启 */
|
/** 轻量字符串缓存,默认开启 */
|
||||||
$config['light_cache'] = [
|
$config['light_cache'] = [
|
||||||
'size' => 512, //最多允许储存的条数(需要2的倍数)
|
'size' => 512, //最多允许储存的条数(需要2的倍数)
|
||||||
@@ -122,4 +127,10 @@ $config['remote_terminal'] = [
|
|||||||
'token' => ''
|
'token' => ''
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** 模块(插件)加载器的相关设置 */
|
||||||
|
$config['module_loader'] = [
|
||||||
|
'enable_hotload' => true,
|
||||||
|
'load_path' => $config['zm_data'] . 'modules'
|
||||||
|
];
|
||||||
|
|
||||||
return $config;
|
return $config;
|
||||||
|
|||||||
3
docs/advanced/manually-install.md
Normal file
3
docs/advanced/manually-install.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# 手动部署环境教程
|
||||||
|
|
||||||
|
TODO: 还没写
|
||||||
@@ -124,7 +124,7 @@ public function ping() {
|
|||||||
|
|
||||||
## getRobot() - 获取机器人 API 对象
|
## getRobot() - 获取机器人 API 对象
|
||||||
|
|
||||||
返回当前上下文关联的机器人 API 调用对象 [ZMRobot](robot-api.md)。
|
返回当前上下文关联的机器人 API 调用对象 [ZMRobot](bot/robot-api.md)。
|
||||||
|
|
||||||
可以使用的事件:所有 HTTP API 发来的事件:`@CQCommand()`,`@CQMessage()` 等。
|
可以使用的事件:所有 HTTP API 发来的事件:`@CQCommand()`,`@CQMessage()` 等。
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,16 @@ DataProvider 是框架内提供的一个简易的文件管理类。
|
|||||||
|
|
||||||
获取配置项 `zm_data` 指定的目录。
|
获取配置项 `zm_data` 指定的目录。
|
||||||
|
|
||||||
|
如果指定参数 `$second`,则返回二级目录地址,如果二级目录不存在则自动创建。
|
||||||
|
|
||||||
|
```php
|
||||||
|
DataProvider::getDataFolder("TestModule"); // 例如返回 /root/zhamao-framework/zm_data/TestModule/
|
||||||
|
```
|
||||||
|
|
||||||
|
## DataProvider::getFrameworkRootDir()
|
||||||
|
|
||||||
|
返回框架本体的根目录。
|
||||||
|
|
||||||
## DataProvider::saveToJson()
|
## DataProvider::saveToJson()
|
||||||
|
|
||||||
将变量内容保存为 json 格式的文件,存储在 `zm_data/config/` 目录下或子目录下。
|
将变量内容保存为 json 格式的文件,存储在 `zm_data/config/` 目录下或子目录下。
|
||||||
@@ -2,111 +2,49 @@
|
|||||||
|
|
||||||
> 这篇为炸毛框架以及环境的部署教程。
|
> 这篇为炸毛框架以及环境的部署教程。
|
||||||
|
|
||||||
框架部署分为环境部署和框架部署。框架部署非常简单,只需要通用的指令,下方主要说环境部署。
|
框架部署分为两部分,一部分是安装 PHP 环境,另一部分是通过 Composer 或 GitHub 拉取框架的脚手架。
|
||||||
|
|
||||||
## Docker 部署 PHP 环境
|
## 一键下载静态 PHP 环境和框架脚手架
|
||||||
如果你不想干扰主机的环境,可以使用 Docker 进行拉取框架适用的 PHP7 with Swoole Extension Docker Container。本框架安装教程中使用的 DockerHub 及 Dockerfile 构建文件所构建的容器均为独立的容器,和框架无关,此 Docker 也可以用作运行**其他基于 php-cli 模式的项目**。
|
|
||||||
|
|
||||||
方法一、直接拉取远程容器(推荐)
|
从 2.4.4 版本起,炸毛框架支持一键拉取一个静态的 PHP 运行时和脚手架,只需运行下面的脚本即可。(开发环境推荐此方法)
|
||||||
```bash
|
|
||||||
docker pull zmbot/swoole
|
|
||||||
```
|
|
||||||
|
|
||||||
方法二、从 Dockerfile 构建容器
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/zhamao-robot/zhamao-swoole-docker.git
|
|
||||||
cd zhamao-swoole-docker/
|
|
||||||
docker build -t zm .
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note "从 Dockerfile 构建容器的提示"
|
|
||||||
|
|
||||||
使用 Dockerfile 构建后,需要将下方所有的 `zmbot/swoole` 全部更换成 `zm`,或者你上方指令中的 `-t` 参数后方的名称,具体可以详情查阅 Docker 的文档。
|
|
||||||
|
|
||||||
## 主机部署 PHP 环境
|
|
||||||
|
|
||||||
### Debian 系列(Ubuntu、Kali )
|
|
||||||
|
|
||||||
需要的系统内软件包为:`php php-dev php-mbstring gcc make openssl php-mbstring php-json php-curl php-mysql wget composer`
|
|
||||||
|
|
||||||
下面是一个一键安装的命令行(最小安装,需 root 权限):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
apt-get update && apt-get install -y software-properties-common && add-apt-repository ppa:ondrej/php && apt-get update && apt-get install php php-dev php-mbstring gcc make openssl php-mbstring php-json php-curl php-mysql -y && apt-get install wget composer -y && wget https://github.com/swoole/swoole-src/archive/v4.5.7.tar.gz && tar -zxvf v4.5.7.tar.gz && cd swoole-src-4.5.7/ && phpize && ./configure --enable-openssl --enable-mysqlnd && make -j2 && make install && (echo "extension=swoole.so" >> $(php -i | grep "Loaded Configuration File" | awk '{print $5}'))
|
# 将会把 PHP、框架都安装在此目录下
|
||||||
```
|
mkdir zhamao-app/ # 这里可以取自己的项目名字
|
||||||
|
cd zhamao-app/
|
||||||
|
bash -c "$(curl -fsSL https://api.zhamao.xin/go.sh)"
|
||||||
|
|
||||||
### macOS (with Homebrew)
|
# 安装完成后的启动框架命令(2.5.0 版本后可省略掉 runtime/php 前缀)
|
||||||
|
|
||||||
macOS 系统下的部署相对简单很多,只需要使用 Homebrew 安装以下包和执行安装命令即可
|
|
||||||
|
|
||||||
!!! note "给 macOS 开发者的提示"
|
|
||||||
|
|
||||||
因为苹果新的 Apple Sillicon 对 Homebrew 的支持目前仅限于 Rosetta2 转译版,
|
|
||||||
所以在使用 M1-based Mac 时出现问题暂时无解。
|
|
||||||
使用以下指令可能会遇到报错等问题,如有疑问可直接使用 Docker 或咨询我(炸毛框架开发者)。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install php composer
|
|
||||||
pecl install swoole
|
|
||||||
```
|
|
||||||
|
|
||||||
### 其他 Linux 发行版
|
|
||||||
|
|
||||||
其他 Linux 发行版,如 CentOS,Fedora,Arch 等暂时还没有经过严格的测试需要哪些依赖,大体和 Ubuntu、Debian 系需要的依赖包差不多,可根据安装过程中报错提示依次安装,或者直接使用 Docker 环境。
|
|
||||||
|
|
||||||
## 安装框架
|
|
||||||
|
|
||||||
恭喜你,前方通过 Docker 或主机安装环境后可以开始构建框架的开发脚手架了!
|
|
||||||
|
|
||||||
如果你是通过**主机安装 PHP 部署的环境**,下方是通过脚手架来构建项目的命令行。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
composer create-project zhamao/framework-starter zhamao-app
|
|
||||||
cd zhamao-app/ # 这个是你可以自己定义的名称
|
|
||||||
vendor/bin/start server # 启动框架
|
|
||||||
```
|
|
||||||
|
|
||||||
如果是通过 **Docker 部署的环境**,则需要在先克隆脚手架后在文件夹内使用 Docker 命令下的 `composer update`。(如果主机环境有 composer 也可以使用 `composer create-project` 的方式拉取脚手架。)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/zhamao-robot/zhamao-framework-starter.git
|
|
||||||
cd zhamao-framework-starter/
|
|
||||||
docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole composer update
|
|
||||||
```
|
|
||||||
|
|
||||||
或者在 Docker 环境下,你可以直接使用如下方法拉取和快速启动一个最标准的框架。
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/zhamao-robot/zhamao-framework-starter.git
|
|
||||||
cd zhamao-framework-starter
|
|
||||||
./run-docker.sh # 在正式版炸毛框架 v2 发布后可用,测试版暂不放出
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! tip "提示"
|
|
||||||
|
|
||||||
如果国内 Composer 下载过慢,可以使用阿里云的 Composer 镜像加速。
|
|
||||||
```bash
|
|
||||||
# 仅对当前的项目使用阿里云加速
|
|
||||||
composer config repo.packagist composer https://mirrors.aliyun.com/composer/
|
|
||||||
# 对全局的 Composer 使用阿里云加速
|
|
||||||
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## 启动框架
|
|
||||||
|
|
||||||
本地环境启动方式:
|
|
||||||
```bash
|
|
||||||
cd zhamao-framework-starter
|
|
||||||
vendor/bin/start server
|
vendor/bin/start server
|
||||||
|
|
||||||
|
# 扩展用法:使用静态 PHP 版本的 Composer update
|
||||||
|
runtime/composer update
|
||||||
|
# 扩展用法:使用静态 PHP 运行别的 CLI 脚本
|
||||||
|
runtime/php path/to/your/script.php
|
||||||
```
|
```
|
||||||
|
|
||||||
使用 Docker 启动:
|
> 有关静态 PHP 的多种用法(如 Composer),见 [进阶 - PHP 环境高级](/advanced/php-env)
|
||||||
|
|
||||||
|
## 使用 Docker 部署 PHP 和框架
|
||||||
|
你也可以使用 Docker 进行拉取 PHP 环境。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd zhamao-framework-starter
|
# 拉取 Docker 镜像
|
||||||
|
docker pull zmbot/swoole
|
||||||
|
|
||||||
|
# 再通过 GitHub 或其他方式拉取框架脚手架
|
||||||
|
git clone --depth=1 https://github.com/zhamao-robot/zhamao-framework-starter.git
|
||||||
|
cd zhamao-framework-starter/
|
||||||
|
|
||||||
|
# Docker 内使用 Composer 更新依赖
|
||||||
|
docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole composer update
|
||||||
|
docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole vendor/bin/start init
|
||||||
|
|
||||||
|
# 使用 Docker 启动框架
|
||||||
docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole vendor/bin/start server
|
docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole vendor/bin/start server
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
启动后你会看到和下方类似的初始化内容,表明启动成功了
|
启动后你会看到和下方类似的初始化内容,表明启动成功了
|
||||||
|
|
||||||
```verilog
|
```verilog
|
||||||
@@ -114,17 +52,13 @@ $ vendor/bin/start server
|
|||||||
host: 0.0.0.0 | port: 20001
|
host: 0.0.0.0 | port: 20001
|
||||||
log_level: 2 | version: 2.0.0
|
log_level: 2 | version: 2.0.0
|
||||||
config: global.php | worker_num: 4
|
config: global.php | worker_num: 4
|
||||||
working_dir: /Users/jerry/project/git-project/zhamao-framework
|
working_dir: /app/zhamao-framework
|
||||||
______
|
______
|
||||||
|__ / |__ __ _ _ __ ___ __ _ ___
|
|__ / |__ __ _ _ __ ___ __ _ ___
|
||||||
/ /| '_ \ / _` | '_ ` _ \ / _` |/ _ \
|
/ /| '_ \ / _` | '_ ` _ \ / _` |/ _ \
|
||||||
/ /_| | | | (_| | | | | | | (_| | (_) |
|
/ /_| | | | (_| | | | | | | (_| | (_) |
|
||||||
/____|_| |_|\__,_|_| |_| |_|\__,_|\___/
|
/____|_| |_|\__,_|_| |_| |_|\__,_|\___/
|
||||||
|
|
||||||
[14:27:31] [I] [#0] Worker #0 启动中
|
|
||||||
[14:27:31] [I] [#2] Worker #2 启动中
|
|
||||||
[14:27:31] [I] [#1] Worker #1 启动中
|
|
||||||
[14:27:31] [I] [#3] Worker #3 启动中
|
|
||||||
[14:27:31] [S] [#3] Worker #3 已启动
|
[14:27:31] [S] [#3] Worker #3 已启动
|
||||||
[14:27:31] [S] [#0] Worker #0 已启动
|
[14:27:31] [S] [#0] Worker #0 已启动
|
||||||
[14:27:31] [S] [#2] Worker #2 已启动
|
[14:27:31] [S] [#2] Worker #2 已启动
|
||||||
@@ -133,9 +67,11 @@ working_dir: /Users/jerry/project/git-project/zhamao-framework
|
|||||||
|
|
||||||
单纯运行 炸毛框架 后,如果不部署或安装启动任何机器人客户端的话,仅仅相当于启动了一个 监听 20001 端口的WebSoket + HTTP 服务器。你可以通过浏览器访问:http://127.0.0.1:20001 ,或者你部署到了服务器后需要输入服务器地址。
|
单纯运行 炸毛框架 后,如果不部署或安装启动任何机器人客户端的话,仅仅相当于启动了一个 监听 20001 端口的WebSoket + HTTP 服务器。你可以通过浏览器访问:http://127.0.0.1:20001 ,或者你部署到了服务器后需要输入服务器地址。
|
||||||
|
|
||||||
!!! note "安装和部署总结"
|
## 命令总结
|
||||||
|
|
||||||
根据上方描述,此文档中剩余提到的所有 Bash 命令,如果使用 Docker 部署环境,则需要加上 Docker 环境的指令:`docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole`,如执行其他 Linux 指令(以查看 PHP 版本为例):`docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole php -v`。
|
1. 对于框架的启动,必须 cd 到项目的跟目录,比如 `cd zhamao-app/` 进入到项目根目录。
|
||||||
|
2. 无论何种方式启动,启动框架的命令格式都为这个格式:`{php二进制路径} vendor/bin/start server {--如果需要参数的话这样跟}`
|
||||||
|
3. 第二条的 `php 二进制路径` 指的是,比如使用第一种静态 PHP 环境,这里写 `runtime/php` 就好了,如果是安装到系统的 PHP 的话,这里为空,如果是 Docker 部署的环境,则这里填 `docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole`
|
||||||
|
|
||||||
## 使用 IDE 等工具开发代码
|
## 使用 IDE 等工具开发代码
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,68 @@
|
|||||||
# 更新日志(v2 版本)
|
# 更新日志(v2 版本)
|
||||||
|
|
||||||
|
## v2.5.0(未发布,测试中)
|
||||||
|
|
||||||
|
> 更新时间:未知
|
||||||
|
|
||||||
|
以下是版本**新增内容**:
|
||||||
|
|
||||||
|
- 新增全新的模块系统,可打包模块(src 目录下的子目录用户逻辑代码)为 phar 格式进行分发和版本备份。
|
||||||
|
- 全局配置文件新增 `module_loader` 项,用于配置外部模块加载的一些设置。
|
||||||
|
- 全局配置文件新增 `runtime` 配置项,可自定义配置 Swoole 的一些运行时参数,目前可配置一键协程化的 Hook 参数。
|
||||||
|
- 新增 `module:list` 命令,用于查看未打包和已打包的模块列表。
|
||||||
|
- 新增 `module:pack` 命令,用于打包现有 src 目录下的模块。
|
||||||
|
- 新增打包框架功能,支持将用户的整个项目连同炸毛框架打包为一个 phar 便携运行,使用命令 `build`。
|
||||||
|
- 新增快捷脚本 `./zhamao`,效果同 `vendor/bin/start` 或 `bin/start`。
|
||||||
|
- 新增启动参数 `--interact`:又重新支持交互终端了,但还是有点问题,不推荐使用。
|
||||||
|
- 新增启动参数 `--disable-safe-exit`:如果你的项目在 Ctrl+C 时总是卡住且项目内没有什么使用 LightCache 等缓存在内存的数据可开启防止关不掉框架。
|
||||||
|
- 新增启动参数 `--preview`:只显示参数,不启动炸毛框架的服务器。
|
||||||
|
- 新增启动参数 `--force-load-module`:强制打包状态下加载的模块(使用英文逗号分隔多个模块名称)。
|
||||||
|
- `CoroutinePool` 协程池新增 `getRunningCoroutineCount` 方法,用于查看协程池中的协程数量。
|
||||||
|
- `DataProvider` 新增 `getFrameworkRootDir()`、`getSourceRootDir()`,分别代表获取框架的根目录和用户源码根目录。(详见下方对目录的定义解释)
|
||||||
|
- `DataProvider` 中 `getDataFolder` 新增参数 `$second = ''`,如果给定,则自动创建子目录 `$second` 并返回。
|
||||||
|
- `DataProvider` 新增 `scanDirFiles()` 方法,用于扫描目录,可选择是否递归、是否返回相对路径,也支持扫描 Phar 文件内的路径,非常好用。
|
||||||
|
- `DataProvider` 新增 `isRelativePath()` 方法,检查路径是否为相对路径(根据第一个字符是否是 '/' 来判断)。
|
||||||
|
- `ZMUtil` 新增 `getClassesPsr4()` 方法,用于根据 Psr-4 标准来获取目录下的所有类文件。
|
||||||
|
- 新增全局错误码,可以根据错误码在文档内快速定位和解决问题。
|
||||||
|
|
||||||
|
以下是版本**修改内容**:
|
||||||
|
|
||||||
|
- 启动文件 `vendor/bin/start` 修改为 shell 脚本,可自动寻找 PHP 环境。
|
||||||
|
- 全局配置文件的 `zm_data` 根目录默认修改为 `WORKING_DIR`。
|
||||||
|
- 全局配置文件删除 `server_event_handler_class` 项,此项废弃。
|
||||||
|
- 修复部分 CQ 码解析过程中没有转义的问题。
|
||||||
|
- 将 `ZMRobot` 类转移为 `OneBotV11` 类,但提供兼容。
|
||||||
|
- 修复在守护进程模式下使用 `daemon:reload` 和 `daemon:stop` 命令可能失效的问题。
|
||||||
|
- 修复 systemd 生成时脚本目录错误的 bug。
|
||||||
|
- 修复 PipeMessage 等事件未捕获错误导致崩溃的问题。
|
||||||
|
- `ZM\Http\RouteManager` 移动到 `ZM\Utils\Manager\RouteManager`,但原地址兼容。
|
||||||
|
- 修复 `Terminal` 类使用的一些问题。
|
||||||
|
- 对 `pcntl` 扩展改为可选依赖,当 Swoole 版本大于等于 4.6.7 时不需要安装 `pcntl` 扩展。
|
||||||
|
- 修正启动时框架对缺省配置项的一些默认参数。
|
||||||
|
- 注解 `@OnSetup` 和 `@SwooleHandler` 可直接使用,无需设置 `server_event_handler_class` 即可。
|
||||||
|
- 修复框架在一些非正常终端中运行时导致错误的问题。
|
||||||
|
- 使用 `--debug-mode` 参数时,自动开启热更新。
|
||||||
|
|
||||||
|
**对目录的定义解释**:
|
||||||
|
|
||||||
|
在 2.4.4 版本之前,使用炸毛框架中,只含有两种目录,`getWorkingDir` 和 `getDataFolder`,分别代表获取工作目录和数据目录。在 2.5 版本中,又新增了 `getFrameworkRootDir` 代表获取框架的根目录,`getSourceRootDir` 代表获取源码的根目录。
|
||||||
|
|
||||||
|
以 Composer 运行模式举例,如果你使用 `composer create-project zhamao/framework-starter` 命令新建的框架,那么假设我们从 `/app` 目录下运行此命令,然后使用 `cd framework-starter/` 进入项目目录,此时我们使用 `vendor/bin/start server` 命令运行服务器,对应的目录为:
|
||||||
|
|
||||||
|
- `WorkingDir`:`/app/framework-starter/`
|
||||||
|
- `SourceRootDir`:`/app/framework-starter/`
|
||||||
|
- `FrameworkRootDir`:`/app/framework-starter/vendor/zhamao/framework/`
|
||||||
|
|
||||||
|
如果以源码模式(直接克隆 `zhamao-framework.git` 仓库),启动框架,那么使用命令 `bin/start server` 启动框架后,以上三个返回的目录则完全相同。
|
||||||
|
|
||||||
|
如果以 2.5 版本新的项目归档模式(build)启动框架,假设我们的项目代码打包为 `server.phar`,在 `/app/` 目录,我们使用命令 `php server.phar server` 启动炸毛框架,那么它对应的目录为:
|
||||||
|
|
||||||
|
- `WorkingDir`:`/app/`
|
||||||
|
- `SourceRootDir`:`phar:///app/server.phar/`
|
||||||
|
- `FrameworkRootDir`:`phar:///app/server.phar/vendor/zhamao/framework/`
|
||||||
|
|
||||||
|
如果最后一种归档方式启动的框架是从源码模式打包而来,那么 `FrameworkRootDir` 就与 `SourceRootDir` 相同。
|
||||||
|
|
||||||
## v2.4.4 (build 405)
|
## v2.4.4 (build 405)
|
||||||
|
|
||||||
> 更新时间:2021.3.29
|
> 更新时间:2021.3.29
|
||||||
|
|||||||
@@ -29,6 +29,6 @@ if [ "$ver" != "" ]; then
|
|||||||
tar -zxvf temp.tar.gz go-cqhttp
|
tar -zxvf temp.tar.gz go-cqhttp
|
||||||
rm temp.tar.gz
|
rm temp.tar.gz
|
||||||
echo "下载完成,启动命令:./go-cqhttp"
|
echo "下载完成,启动命令:./go-cqhttp"
|
||||||
echo "首次启动后先编辑config.hjson文件!"
|
echo "首次启动后先编辑config文件!"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
29
mkdocs.yml
29
mkdocs.yml
@@ -1,4 +1,4 @@
|
|||||||
site_name: 炸毛框架 v2
|
site_name: 炸毛框架文档
|
||||||
|
|
||||||
repo_name: '炸毛框架'
|
repo_name: '炸毛框架'
|
||||||
repo_url: 'https://github.com/zhamao-robot/zhamao-framework'
|
repo_url: 'https://github.com/zhamao-robot/zhamao-framework'
|
||||||
@@ -32,7 +32,7 @@ markdown_extensions:
|
|||||||
linenums_style: pymdownx.inline
|
linenums_style: pymdownx.inline
|
||||||
extra:
|
extra:
|
||||||
version:
|
version:
|
||||||
method: mike
|
provider: mike
|
||||||
|
|
||||||
copyright: 'Copyright © 2019 - 2021 CrazyBot Team <span class="tx-switch">
|
copyright: 'Copyright © 2019 - 2021 CrazyBot Team <span class="tx-switch">
|
||||||
<button data-md-color-scheme="default"><code>默认模式</code></button>
|
<button data-md-color-scheme="default"><code>默认模式</code></button>
|
||||||
@@ -50,7 +50,7 @@ copyright: 'Copyright © 2019 - 2021 CrazyBot Team &n
|
|||||||
name.textContent = attr;
|
name.textContent = attr;
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script><br><a href="http://beian.miit.gov.cn">蒙ICP备18000198号-1</a>'
|
</script><br><a href="http://beian.miit.gov.cn">沪ICP备2021010446号-1</a>'
|
||||||
|
|
||||||
nav:
|
nav:
|
||||||
- 指南:
|
- 指南:
|
||||||
@@ -74,18 +74,18 @@ nav:
|
|||||||
- 框架组件: component/index.md
|
- 框架组件: component/index.md
|
||||||
- 上下文: component/context.md
|
- 上下文: component/context.md
|
||||||
- 聊天机器人组件:
|
- 聊天机器人组件:
|
||||||
- 机器人 API: component/robot-api.md
|
- 机器人 API: component/bot/robot-api.md
|
||||||
- CQ 码(多媒体消息): component/cqcode.md
|
- CQ 码(多媒体消息): component/bot/cqcode.md
|
||||||
- 机器人消息处理: component/message-util.md
|
- 机器人消息处理: component/bot/message-util.md
|
||||||
- Token 验证: component/access-token.md
|
- Token 验证: component/bot/access-token.md
|
||||||
- 图灵机器人 API: component/turing-api.md
|
- 图灵机器人 API: component/bot/turing-api.md
|
||||||
- 存储:
|
- 存储:
|
||||||
- LightCache 轻量缓存: component/light-cache.md
|
- LightCache 轻量缓存: component/store/light-cache.md
|
||||||
- MySQL 数据库: component/mysql.md
|
- MySQL 数据库: component/store/mysql.md
|
||||||
- Redis 数据库: component/redis.md
|
- Redis 数据库: component/store/redis.md
|
||||||
- ZMAtomic 原子计数器: component/atomics.md
|
- ZMAtomic 原子计数器: component/store/atomics.md
|
||||||
- SpinLock 自旋锁: component/spin-lock.md
|
- SpinLock 自旋锁: component/store/spin-lock.md
|
||||||
- 文件管理: component/data-provider.md
|
- 文件管理: component/store/data-provider.md
|
||||||
- HTTP 服务器工具类:
|
- HTTP 服务器工具类:
|
||||||
- HTTP 和 WebSocket 客户端: component/zmrequest.md
|
- HTTP 和 WebSocket 客户端: component/zmrequest.md
|
||||||
- HTTP 路由管理: component/route-manager.md
|
- HTTP 路由管理: component/route-manager.md
|
||||||
@@ -100,6 +100,7 @@ nav:
|
|||||||
- 进阶开发: advanced/index.md
|
- 进阶开发: advanced/index.md
|
||||||
- 框架剖析: advanced/framework-structure.md
|
- 框架剖析: advanced/framework-structure.md
|
||||||
- 框架启动模式: advanced/custom-start.md
|
- 框架启动模式: advanced/custom-start.md
|
||||||
|
- 手动安装环境: advanced/manually-install.md
|
||||||
- 从 v1 升级: advanced/to-v2.md
|
- 从 v1 升级: advanced/to-v2.md
|
||||||
- 内部类文件手册: advanced/inside-class.md
|
- 内部类文件手册: advanced/inside-class.md
|
||||||
- 接入 WebSocket 客户端: advanced/connect-ws-client.md
|
- 接入 WebSocket 客户端: advanced/connect-ws-client.md
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ class Hello
|
|||||||
return TuringAPI::getTuringMsg($msg, $user_id, $api);
|
return TuringAPI::getTuringMsg($msg, $user_id, $api);
|
||||||
} else {
|
} else {
|
||||||
QQBot::getInstance()->handle(ctx()->getData(), ctx()->getCache("level") + 1);
|
QQBot::getInstance()->handle(ctx()->getData(), ctx()->getCache("level") + 1);
|
||||||
|
//执行嵌套消息,递归层级+1
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class CQ
|
|||||||
if (is_numeric($qq) || $qq === "all") {
|
if (is_numeric($qq) || $qq === "all") {
|
||||||
return "[CQ:at,qq=" . $qq . "]";
|
return "[CQ:at,qq=" . $qq . "]";
|
||||||
}
|
}
|
||||||
Console::warning("传入的QQ号码($qq)错误!");
|
Console::warning(zm_internal_errcode("E00035") . "传入的QQ号码($qq)错误!");
|
||||||
return " ";
|
return " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ class CQ
|
|||||||
if (is_numeric($id)) {
|
if (is_numeric($id)) {
|
||||||
return "[CQ:face,id=" . $id . "]";
|
return "[CQ:face,id=" . $id . "]";
|
||||||
}
|
}
|
||||||
Console::warning("传入的face id($id)错误!");
|
Console::warning(zm_internal_errcode("E00035") . "传入的face id($id)错误!");
|
||||||
return " ";
|
return " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,13 +46,13 @@ class CQ
|
|||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function image($file, $cache = true, $flash = false, $proxy = true, $timeout = -1) {
|
public static function image($file, bool $cache = true, bool $flash = false, bool $proxy = true, int $timeout = -1) {
|
||||||
return
|
return
|
||||||
"[CQ:image,file=" . self::encode($file, true) .
|
"[CQ:image,file=" . self::encode($file, true) .
|
||||||
(!$cache ? ",cache=0" : "") .
|
(!$cache ? ",cache=0" : "") .
|
||||||
($flash ? ",type=flash" : "") .
|
($flash ? ",type=flash" : "") .
|
||||||
(!$proxy ? ",proxy=false" : "") .
|
(!$proxy ? ",proxy=false" : "") .
|
||||||
($timeout != -1 ? (",timeout=" . intval($timeout)) : "") .
|
($timeout != -1 ? (",timeout=" . $timeout) : "") .
|
||||||
"]";
|
"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,13 +65,13 @@ class CQ
|
|||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function record($file, $magic = false, $cache = true, $proxy = true, $timeout = -1) {
|
public static function record($file, bool $magic = false, bool $cache = true, bool $proxy = true, int $timeout = -1) {
|
||||||
return
|
return
|
||||||
"[CQ:record,file=" . self::encode($file, true) .
|
"[CQ:record,file=" . self::encode($file, true) .
|
||||||
(!$cache ? ",cache=0" : "") .
|
(!$cache ? ",cache=0" : "") .
|
||||||
($magic ? ",magic=1" : "") .
|
($magic ? ",magic=1" : "") .
|
||||||
(!$proxy ? ",proxy=false" : "") .
|
(!$proxy ? ",proxy=false" : "") .
|
||||||
($timeout != -1 ? (",timeout=" . intval($timeout)) : "") .
|
($timeout != -1 ? (",timeout=" . $timeout) : "") .
|
||||||
"]";
|
"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ class CQ
|
|||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function video($file, $cache = true, $proxy = true, $timeout = -1) {
|
public static function video($file, bool $cache = true, bool $proxy = true, int $timeout = -1) {
|
||||||
return
|
return
|
||||||
"[CQ:video,file=" . self::encode($file, true) .
|
"[CQ:video,file=" . self::encode($file, true) .
|
||||||
(!$cache ? ",cache=0" : "") .
|
(!$cache ? ",cache=0" : "") .
|
||||||
@@ -123,8 +123,8 @@ class CQ
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function poke($type, $id, $name = "") {
|
public static function poke($type, $id, string $name = "") {
|
||||||
return "[CQ:poke,type=$type,id=$id" . ($name != "" ? (",name=".self::encode($name, true)) : "") . "]";
|
return "[CQ:poke,type=$type,id=$id" . ($name != "" ? (",name=" . self::encode($name, true)) : "") . "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,7 +132,7 @@ class CQ
|
|||||||
* @param int $ignore
|
* @param int $ignore
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function anonymous($ignore = 1) {
|
public static function anonymous(int $ignore = 1) {
|
||||||
return "[CQ:anonymous" . ($ignore != 1 ? ",ignore=0" : "") . "]";
|
return "[CQ:anonymous" . ($ignore != 1 ? ",ignore=0" : "") . "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,12 +170,12 @@ class CQ
|
|||||||
* @param string $content
|
* @param string $content
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function location($lat, $lon, $title = "", $content = "") {
|
public static function location($lat, $lon, string $title = "", string $content = "") {
|
||||||
return "[CQ:location" .
|
return "[CQ:location" .
|
||||||
",lat=".self::encode($lat, true) .
|
",lat=" . self::encode($lat, true) .
|
||||||
",lon=".self::encode($lon, true).
|
",lon=" . self::encode($lon, true) .
|
||||||
($title != "" ? (",title=".self::encode($title, true)) : "") .
|
($title != "" ? (",title=" . self::encode($title, true)) : "") .
|
||||||
($content != "" ? (",content=".self::encode($content, true)) : "") .
|
($content != "" ? (",content=" . self::encode($content, true)) : "") .
|
||||||
"]";
|
"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ class CQ
|
|||||||
return "[CQ:music,type=$type,id=$id_or_url]";
|
return "[CQ:music,type=$type,id=$id_or_url]";
|
||||||
case "custom":
|
case "custom":
|
||||||
if ($title === null || $audio === null) {
|
if ($title === null || $audio === null) {
|
||||||
Console::warning("传入CQ码实例的标题和音频链接不能为空!");
|
Console::warning(zm_internal_errcode("E00035") . "传入CQ码实例的标题和音频链接不能为空!");
|
||||||
return " ";
|
return " ";
|
||||||
}
|
}
|
||||||
if ($content === null) $c = "";
|
if ($content === null) $c = "";
|
||||||
@@ -217,17 +217,17 @@ class CQ
|
|||||||
",audio=" . self::encode($audio, true) . ",title=" . self::encode($title, true) . $c . $i .
|
",audio=" . self::encode($audio, true) . ",title=" . self::encode($title, true) . $c . $i .
|
||||||
"]";
|
"]";
|
||||||
default:
|
default:
|
||||||
Console::warning("传入的music type($type)错误!");
|
Console::warning(zm_internal_errcode("E00035") . "传入的music type($type)错误!");
|
||||||
return " ";
|
return " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function forward($id) {
|
public static function forward($id) {
|
||||||
return "[CQ:forward,id=$id]";
|
return "[CQ:forward,id=".self::encode($id)."]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function node($user_id, $nickname, $content) {
|
public static function node($user_id, $nickname, $content) {
|
||||||
return "[CQ:node,user_id=$user_id,nickname=".self::encode($nickname, true).",content=" . self::encode($content, true) . "]";
|
return "[CQ:node,user_id=$user_id,nickname=" . self::encode($nickname, true) . ",content=" . self::encode($content, true) . "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function xml($data) {
|
public static function xml($data) {
|
||||||
@@ -297,7 +297,7 @@ class CQ
|
|||||||
public static function removeCQ($msg) {
|
public static function removeCQ($msg) {
|
||||||
$final = "";
|
$final = "";
|
||||||
$last_end = 0;
|
$last_end = 0;
|
||||||
foreach(self::getAllCQ($msg) as $k => $v) {
|
foreach (self::getAllCQ($msg) as $v) {
|
||||||
$final .= mb_substr($msg, $last_end, $v["start"] - $last_end);
|
$final .= mb_substr($msg, $last_end, $v["start"] - $last_end);
|
||||||
$last_end = $v["end"] + 1;
|
$last_end = $v["end"] + 1;
|
||||||
}
|
}
|
||||||
@@ -319,7 +319,7 @@ class CQ
|
|||||||
$content = mb_substr($msg, $head + 4, $close + $head - mb_strlen($msg));
|
$content = mb_substr($msg, $head + 4, $close + $head - mb_strlen($msg));
|
||||||
$exp = explode(",", $content);
|
$exp = explode(",", $content);
|
||||||
$cq["type"] = array_shift($exp);
|
$cq["type"] = array_shift($exp);
|
||||||
foreach ($exp as $k => $v) {
|
foreach ($exp as $v) {
|
||||||
$ss = explode("=", $v);
|
$ss = explode("=", $v);
|
||||||
$sk = array_shift($ss);
|
$sk = array_shift($ss);
|
||||||
$cq["params"][$sk] = self::decode(implode("=", $ss), true);
|
$cq["params"][$sk] = self::decode(implode("=", $ss), true);
|
||||||
@@ -349,7 +349,7 @@ class CQ
|
|||||||
$exp = explode(",", $content);
|
$exp = explode(",", $content);
|
||||||
$cq = [];
|
$cq = [];
|
||||||
$cq["type"] = array_shift($exp);
|
$cq["type"] = array_shift($exp);
|
||||||
foreach ($exp as $k => $v) {
|
foreach ($exp as $v) {
|
||||||
$ss = explode("=", $v);
|
$ss = explode("=", $v);
|
||||||
$sk = array_shift($ss);
|
$sk = array_shift($ss);
|
||||||
$cq["params"][$sk] = self::decode(implode("=", $ss), true);
|
$cq["params"][$sk] = self::decode(implode("=", $ss), true);
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ trait CQAPI
|
|||||||
return $this->processWebsocketAPI($connection, $reply, $function);
|
return $this->processWebsocketAPI($connection, $reply, $function);
|
||||||
else
|
else
|
||||||
return $this->processHttpAPI($connection, $reply, $function);
|
return $this->processHttpAPI($connection, $reply, $function);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processWebsocketAPI($connection, $reply, $function = false) {
|
public function processWebsocketAPI($connection, $reply, $function = false) {
|
||||||
@@ -41,7 +39,7 @@ trait CQAPI
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Console::warning("CQAPI send failed, websocket push error.");
|
Console::warning(zm_internal_errcode("E00036") . "CQAPI send failed, websocket push error.");
|
||||||
$response = [
|
$response = [
|
||||||
"status" => "failed",
|
"status" => "failed",
|
||||||
"retcode" => -1000,
|
"retcode" => -1000,
|
||||||
@@ -69,7 +67,6 @@ trait CQAPI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @noinspection PhpMissingReturnTypeInspection */
|
|
||||||
public function __call($name, $arguments) {
|
public function __call($name, $arguments) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
689
src/ZM/API/OneBotV11.php
Normal file
689
src/ZM/API/OneBotV11.php
Normal file
@@ -0,0 +1,689 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\API;
|
||||||
|
|
||||||
|
use ZM\ConnectionManager\ConnectionObject;
|
||||||
|
use ZM\ConnectionManager\ManagerGM;
|
||||||
|
use ZM\Exception\RobotNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OneBot V11 的 API 实现类
|
||||||
|
* Class OneBotV11
|
||||||
|
* @package ZM\API
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
class OneBotV11
|
||||||
|
{
|
||||||
|
use CQAPI;
|
||||||
|
|
||||||
|
const API_ASYNC = 1;
|
||||||
|
const API_NORMAL = 0;
|
||||||
|
const API_RATE_LIMITED = 2;
|
||||||
|
|
||||||
|
/** @var ConnectionObject|null */
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
private $callback = true;
|
||||||
|
private $prefix = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $robot_id
|
||||||
|
* @return ZMRobot
|
||||||
|
* @throws RobotNotFoundException
|
||||||
|
*/
|
||||||
|
public static function get($robot_id) {
|
||||||
|
$r = ManagerGM::getAllByName('qq');
|
||||||
|
foreach ($r as $v) {
|
||||||
|
if ($v->getOption('connect_id') == $robot_id) return new ZMRobot($v);
|
||||||
|
}
|
||||||
|
throw new RobotNotFoundException("机器人 " . $robot_id . " 未连接到框架!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ZMRobot
|
||||||
|
* @throws RobotNotFoundException
|
||||||
|
*/
|
||||||
|
public static function getRandom() {
|
||||||
|
$r = ManagerGM::getAllByName('qq');
|
||||||
|
if ($r == []) throw new RobotNotFoundException("没有任何机器人连接到框架!");
|
||||||
|
return new ZMRobot($r[array_rand($r)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getFirst() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ZMRobot[]
|
||||||
|
*/
|
||||||
|
public static function getAllRobot() {
|
||||||
|
$r = ManagerGM::getAllByName('qq');
|
||||||
|
$obj = [];
|
||||||
|
foreach ($r as $v) {
|
||||||
|
$obj[] = new ZMRobot($v);
|
||||||
|
}
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(ConnectionObject $connection) {
|
||||||
|
$this->connection = $connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCallback($callback = true) {
|
||||||
|
$this->callback = $callback;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPrefix($prefix = self::API_NORMAL) {
|
||||||
|
$this->prefix = $prefix;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSelfId() {
|
||||||
|
return $this->connection->getOption('connect_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下面是 OneBot 标准的 V11 公开 API */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送私聊消息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#send_private_msg-%E5%8F%91%E9%80%81%E7%A7%81%E8%81%8A%E6%B6%88%E6%81%AF
|
||||||
|
* @param $user_id
|
||||||
|
* @param $message
|
||||||
|
* @param bool $auto_escape
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function sendPrivateMsg($user_id, $message, $auto_escape = false) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'message' => $message,
|
||||||
|
'auto_escape' => $auto_escape
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送群消息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#send_group_msg-%E5%8F%91%E9%80%81%E7%BE%A4%E6%B6%88%E6%81%AF
|
||||||
|
* @param $group_id
|
||||||
|
* @param $message
|
||||||
|
* @param bool $auto_escape
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function sendGroupMsg($group_id, $message, $auto_escape = false) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'message' => $message,
|
||||||
|
'auto_escape' => $auto_escape
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#send_msg-%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF
|
||||||
|
* @param $message_type
|
||||||
|
* @param $target_id
|
||||||
|
* @param $message
|
||||||
|
* @param bool $auto_escape
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function sendMsg($message_type, $target_id, $message, $auto_escape = false) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'message_type' => $message_type,
|
||||||
|
($message_type == 'private' ? 'user' : $message_type) . '_id' => $target_id,
|
||||||
|
'message' => $message,
|
||||||
|
'auto_escape' => $auto_escape
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤回消息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#delete_msg-%E6%92%A4%E5%9B%9E%E6%B6%88%E6%81%AF
|
||||||
|
* @param $message_id
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function deleteMsg($message_id) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'message_id' => $message_id
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取消息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_msg-%E8%8E%B7%E5%8F%96%E6%B6%88%E6%81%AF
|
||||||
|
* @param $message_id
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getMsg($message_id) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'message_id' => $message_id
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取合并转发消息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_forward_msg-%E8%8E%B7%E5%8F%96%E5%90%88%E5%B9%B6%E8%BD%AC%E5%8F%91%E6%B6%88%E6%81%AF
|
||||||
|
* @param $id
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getForwardMsg($id) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'id' => $id
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送好友赞
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#send_like-%E5%8F%91%E9%80%81%E5%A5%BD%E5%8F%8B%E8%B5%9E
|
||||||
|
* @param $user_id
|
||||||
|
* @param int $times
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function sendLike($user_id, $times = 1) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'times' => $times
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群组踢人
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_kick-%E7%BE%A4%E7%BB%84%E8%B8%A2%E4%BA%BA
|
||||||
|
* @param $group_id
|
||||||
|
* @param $user_id
|
||||||
|
* @param bool $reject_add_request
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupKick($group_id, $user_id, $reject_add_request = false) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'reject_add_request' => $reject_add_request
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群组单人禁言
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_ban-%E7%BE%A4%E7%BB%84%E5%8D%95%E4%BA%BA%E7%A6%81%E8%A8%80
|
||||||
|
* @param $group_id
|
||||||
|
* @param $user_id
|
||||||
|
* @param $duration
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupBan($group_id, $user_id, $duration = 1800) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'duration' => $duration
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群组匿名用户禁言
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_anonymous_ban-%E7%BE%A4%E7%BB%84%E5%8C%BF%E5%90%8D%E7%94%A8%E6%88%B7%E7%A6%81%E8%A8%80
|
||||||
|
* @param $group_id
|
||||||
|
* @param $anonymous_or_flag
|
||||||
|
* @param int $duration
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupAnonymousBan($group_id, $anonymous_or_flag, $duration = 1800) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
(is_string($anonymous_or_flag) ? 'flag' : 'anonymous') => $anonymous_or_flag,
|
||||||
|
'duration' => $duration
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群组全员禁言
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_whole_ban-%E7%BE%A4%E7%BB%84%E5%85%A8%E5%91%98%E7%A6%81%E8%A8%80
|
||||||
|
* @param $group_id
|
||||||
|
* @param bool $enable
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupWholeBan($group_id, $enable = true) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'enable' => $enable
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群组设置管理员
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_admin-%E7%BE%A4%E7%BB%84%E8%AE%BE%E7%BD%AE%E7%AE%A1%E7%90%86%E5%91%98
|
||||||
|
* @param $group_id
|
||||||
|
* @param $user_id
|
||||||
|
* @param bool $enable
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupAdmin($group_id, $user_id, $enable = true) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'enable' => $enable
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群组匿名
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_anonymous-%E7%BE%A4%E7%BB%84%E5%8C%BF%E5%90%8D
|
||||||
|
* @param $group_id
|
||||||
|
* @param bool $enable
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupAnonymous($group_id, $enable = true) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'enable' => $enable
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置群名片(群备注)
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_card-%E8%AE%BE%E7%BD%AE%E7%BE%A4%E5%90%8D%E7%89%87%E7%BE%A4%E5%A4%87%E6%B3%A8
|
||||||
|
* @param $group_id
|
||||||
|
* @param $user_id
|
||||||
|
* @param string $card
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupCard($group_id, $user_id, $card = "") {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'card' => $card
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置群名
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_name-%E8%AE%BE%E7%BD%AE%E7%BE%A4%E5%90%8D
|
||||||
|
* @param $group_id
|
||||||
|
* @param $group_name
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupName($group_id, $group_name) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'group_name' => $group_name
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出群组
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_leave-%E9%80%80%E5%87%BA%E7%BE%A4%E7%BB%84
|
||||||
|
* @param $group_id
|
||||||
|
* @param bool $is_dismiss
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupLeave($group_id, $is_dismiss = false) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'is_dismiss' => $is_dismiss
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置群组专属头衔
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_special_title-%E8%AE%BE%E7%BD%AE%E7%BE%A4%E7%BB%84%E4%B8%93%E5%B1%9E%E5%A4%B4%E8%A1%94
|
||||||
|
* @param $group_id
|
||||||
|
* @param $user_id
|
||||||
|
* @param string $special_title
|
||||||
|
* @param int $duration
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupSpecialTitle($group_id, $user_id, $special_title = "", $duration = -1) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'special_title' => $special_title,
|
||||||
|
'duration' => $duration
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理加好友请求
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_friend_add_request-%E5%A4%84%E7%90%86%E5%8A%A0%E5%A5%BD%E5%8F%8B%E8%AF%B7%E6%B1%82
|
||||||
|
* @param $flag
|
||||||
|
* @param bool $approve
|
||||||
|
* @param string $remark
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setFriendAddRequest($flag, $approve = true, $remark = "") {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'flag' => $flag,
|
||||||
|
'approve' => $approve,
|
||||||
|
'remark' => $remark
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理加群请求/邀请
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_add_request-%E5%A4%84%E7%90%86%E5%8A%A0%E7%BE%A4%E8%AF%B7%E6%B1%82%E9%82%80%E8%AF%B7
|
||||||
|
* @param $flag
|
||||||
|
* @param $sub_type
|
||||||
|
* @param bool $approve
|
||||||
|
* @param string $reason
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setGroupAddRequest($flag, $sub_type, $approve = true, $reason = "") {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'flag' => $flag,
|
||||||
|
'sub_type' => $sub_type,
|
||||||
|
'approve' => $approve,
|
||||||
|
'reason' => $reason
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取登录号信息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_login_info-%E8%8E%B7%E5%8F%96%E7%99%BB%E5%BD%95%E5%8F%B7%E4%BF%A1%E6%81%AF
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getLoginInfo() {
|
||||||
|
return $this->processAPI($this->connection, ['action' => $this->getActionName(__FUNCTION__)], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取陌生人信息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_stranger_info-%E8%8E%B7%E5%8F%96%E9%99%8C%E7%94%9F%E4%BA%BA%E4%BF%A1%E6%81%AF
|
||||||
|
* @param $user_id
|
||||||
|
* @param bool $no_cache
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getStrangerInfo($user_id, $no_cache = false) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'no_cache' => $no_cache
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取好友列表
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_friend_list-%E8%8E%B7%E5%8F%96%E5%A5%BD%E5%8F%8B%E5%88%97%E8%A1%A8
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getFriendList() {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__)
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群信息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_info-%E8%8E%B7%E5%8F%96%E7%BE%A4%E4%BF%A1%E6%81%AF
|
||||||
|
* @param $group_id
|
||||||
|
* @param bool $no_cache
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getGroupInfo($group_id, $no_cache = false) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'no_cache' => $no_cache
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群列表
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_list-%E8%8E%B7%E5%8F%96%E7%BE%A4%E5%88%97%E8%A1%A8
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getGroupList() {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__)
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群成员信息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_member_info-%E8%8E%B7%E5%8F%96%E7%BE%A4%E6%88%90%E5%91%98%E4%BF%A1%E6%81%AF
|
||||||
|
* @param $group_id
|
||||||
|
* @param $user_id
|
||||||
|
* @param bool $no_cache
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getGroupMemberInfo($group_id, $user_id, $no_cache = false) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'no_cache' => $no_cache
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群成员列表
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_member_list-%E8%8E%B7%E5%8F%96%E7%BE%A4%E6%88%90%E5%91%98%E5%88%97%E8%A1%A8
|
||||||
|
* @param $group_id
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getGroupMemberList($group_id) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取群荣誉信息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_honor_info-%E8%8E%B7%E5%8F%96%E7%BE%A4%E8%8D%A3%E8%AA%89%E4%BF%A1%E6%81%AF
|
||||||
|
* @param $group_id
|
||||||
|
* @param $type
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getGroupHonorInfo($group_id, $type) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'group_id' => $group_id,
|
||||||
|
'type' => $type
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 CSRF Token
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_csrf_token-%E8%8E%B7%E5%8F%96-csrf-token
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getCsrfToken() {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__)
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 QQ 相关接口凭证
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_credentials-%E8%8E%B7%E5%8F%96-qq-%E7%9B%B8%E5%85%B3%E6%8E%A5%E5%8F%A3%E5%87%AD%E8%AF%81
|
||||||
|
* @param string $domain
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getCredentials($domain = "") {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'domain' => $domain
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取语音
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_record-%E8%8E%B7%E5%8F%96%E8%AF%AD%E9%9F%B3
|
||||||
|
* @param $file
|
||||||
|
* @param $out_format
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getRecord($file, $out_format) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'file' => $file,
|
||||||
|
'out_format' => $out_format
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取图片
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_image-%E8%8E%B7%E5%8F%96%E5%9B%BE%E7%89%87
|
||||||
|
* @param $file
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getImage($file) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'file' => $file
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否可以发送图片
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#can_send_image-%E6%A3%80%E6%9F%A5%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E5%8F%91%E9%80%81%E5%9B%BE%E7%89%87
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function canSendImage() {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__)
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否可以发送语音
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#can_send_record-%E6%A3%80%E6%9F%A5%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E5%8F%91%E9%80%81%E8%AF%AD%E9%9F%B3
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function canSendRecord() {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__)
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取运行状态
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_status-%E8%8E%B7%E5%8F%96%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getStatus() {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__)
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取版本信息
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_version_info-%E8%8E%B7%E5%8F%96%E7%89%88%E6%9C%AC%E4%BF%A1%E6%81%AF
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function getVersionInfo() {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__)
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重启 OneBot 实现
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_restart-%E9%87%8D%E5%90%AF-onebot-%E5%AE%9E%E7%8E%B0
|
||||||
|
* @param int $delay
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function setRestart($delay = 0) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__),
|
||||||
|
'params' => [
|
||||||
|
'delay' => $delay
|
||||||
|
]
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理缓存
|
||||||
|
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#clean_cache-%E6%B8%85%E7%90%86%E7%BC%93%E5%AD%98
|
||||||
|
* @return array|bool|null
|
||||||
|
*/
|
||||||
|
public function cleanCache() {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $this->getActionName(__FUNCTION__)
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function callExtendedAPI($action, $params = []) {
|
||||||
|
return $this->processAPI($this->connection, [
|
||||||
|
'action' => $action,
|
||||||
|
'params' => $params
|
||||||
|
], $this->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getActionName(string $method) {
|
||||||
|
$prefix = ($this->prefix == self::API_ASYNC ? '_async' : ($this->prefix == self::API_RATE_LIMITED ? '_rate_limited' : ''));
|
||||||
|
$func_name = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $method));
|
||||||
|
return $func_name . $prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,14 +54,14 @@ class TuringAPI
|
|||||||
if ($api_return["intent"]["code"] == 4003) {
|
if ($api_return["intent"]["code"] == 4003) {
|
||||||
return "哎呀,我刚才有点走神了,可能忘记你说什么了,可以重说一遍吗";
|
return "哎呀,我刚才有点走神了,可能忘记你说什么了,可以重说一遍吗";
|
||||||
}
|
}
|
||||||
Console::error("图灵机器人发送错误!\n错误原始内容:" . $origin . "\n来自:" . $user_id . "\n错误信息:" . $status);
|
Console::error(zm_internal_errcode("E00038") . "图灵机器人发送错误!\n错误原始内容:" . $origin . "\n来自:" . $user_id . "\n错误信息:" . $status);
|
||||||
//echo json_encode($r, 128|256);
|
//echo json_encode($r, 128|256);
|
||||||
return "哎呀,我刚才有点走神了,要不一会儿换一种问题试试?";
|
return "哎呀,我刚才有点走神了,要不一会儿换一种问题试试?";
|
||||||
}
|
}
|
||||||
$result = $api_return["results"];
|
$result = $api_return["results"];
|
||||||
//Console::info(Console::setColor(json_encode($result, 128 | 256), "green"));
|
//Console::info(Console::setColor(json_encode($result, 128 | 256), "green"));
|
||||||
$final = "";
|
$final = "";
|
||||||
foreach ($result as $k => $v) {
|
foreach ($result as $v) {
|
||||||
switch ($v["resultType"]) {
|
switch ($v["resultType"]) {
|
||||||
case "url":
|
case "url":
|
||||||
$final .= "\n" . $v["values"]["url"];
|
$final .= "\n" . $v["values"]["url"];
|
||||||
|
|||||||
@@ -5,687 +5,13 @@
|
|||||||
|
|
||||||
namespace ZM\API;
|
namespace ZM\API;
|
||||||
|
|
||||||
use ZM\ConnectionManager\ConnectionObject;
|
|
||||||
use ZM\ConnectionManager\ManagerGM;
|
|
||||||
use ZM\Exception\RobotNotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ZMRobot
|
* Class ZMRobot
|
||||||
* @package ZM\Utils
|
* @package ZM\Utils
|
||||||
* @since 1.2
|
* @since 1.2
|
||||||
* @version V11
|
* @version V11
|
||||||
*/
|
*/
|
||||||
class ZMRobot
|
class ZMRobot extends OneBotV11
|
||||||
{
|
{
|
||||||
use CQAPI;
|
|
||||||
|
|
||||||
const API_ASYNC = 1;
|
|
||||||
const API_NORMAL = 0;
|
|
||||||
const API_RATE_LIMITED = 2;
|
|
||||||
|
|
||||||
/** @var ConnectionObject|null */
|
|
||||||
private $connection;
|
|
||||||
|
|
||||||
private $callback = true;
|
|
||||||
private $prefix = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $robot_id
|
|
||||||
* @return ZMRobot
|
|
||||||
* @throws RobotNotFoundException
|
|
||||||
*/
|
|
||||||
public static function get($robot_id) {
|
|
||||||
$r = ManagerGM::getAllByName('qq');
|
|
||||||
foreach ($r as $v) {
|
|
||||||
if ($v->getOption('connect_id') == $robot_id) return new ZMRobot($v);
|
|
||||||
}
|
|
||||||
throw new RobotNotFoundException("机器人 " . $robot_id . " 未连接到框架!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ZMRobot
|
|
||||||
* @throws RobotNotFoundException
|
|
||||||
*/
|
|
||||||
public static function getRandom() {
|
|
||||||
$r = ManagerGM::getAllByName('qq');
|
|
||||||
if ($r == []) throw new RobotNotFoundException("没有任何机器人连接到框架!");
|
|
||||||
return new ZMRobot($r[array_rand($r)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getFirst() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return ZMRobot[]
|
|
||||||
*/
|
|
||||||
public static function getAllRobot() {
|
|
||||||
$r = ManagerGM::getAllByName('qq');
|
|
||||||
$obj = [];
|
|
||||||
foreach ($r as $v) {
|
|
||||||
$obj[] = new ZMRobot($v);
|
|
||||||
}
|
|
||||||
return $obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct(ConnectionObject $connection) {
|
|
||||||
$this->connection = $connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCallback($callback = true) {
|
|
||||||
$this->callback = $callback;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPrefix($prefix = self::API_NORMAL) {
|
|
||||||
$this->prefix = $prefix;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSelfId() {
|
|
||||||
return $this->connection->getOption('connect_id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 下面是 OneBot 标准的 V11 公开 API */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送私聊消息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#send_private_msg-%E5%8F%91%E9%80%81%E7%A7%81%E8%81%8A%E6%B6%88%E6%81%AF
|
|
||||||
* @param $user_id
|
|
||||||
* @param $message
|
|
||||||
* @param bool $auto_escape
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function sendPrivateMsg($user_id, $message, $auto_escape = false) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'message' => $message,
|
|
||||||
'auto_escape' => $auto_escape
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送群消息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#send_group_msg-%E5%8F%91%E9%80%81%E7%BE%A4%E6%B6%88%E6%81%AF
|
|
||||||
* @param $group_id
|
|
||||||
* @param $message
|
|
||||||
* @param bool $auto_escape
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function sendGroupMsg($group_id, $message, $auto_escape = false) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'message' => $message,
|
|
||||||
'auto_escape' => $auto_escape
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送消息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#send_msg-%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF
|
|
||||||
* @param $message_type
|
|
||||||
* @param $target_id
|
|
||||||
* @param $message
|
|
||||||
* @param bool $auto_escape
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function sendMsg($message_type, $target_id, $message, $auto_escape = false) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'message_type' => $message_type,
|
|
||||||
($message_type == 'private' ? 'user' : $message_type) . '_id' => $target_id,
|
|
||||||
'message' => $message,
|
|
||||||
'auto_escape' => $auto_escape
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 撤回消息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#delete_msg-%E6%92%A4%E5%9B%9E%E6%B6%88%E6%81%AF
|
|
||||||
* @param $message_id
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function deleteMsg($message_id) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'message_id' => $message_id
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取消息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_msg-%E8%8E%B7%E5%8F%96%E6%B6%88%E6%81%AF
|
|
||||||
* @param $message_id
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getMsg($message_id) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'message_id' => $message_id
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取合并转发消息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_forward_msg-%E8%8E%B7%E5%8F%96%E5%90%88%E5%B9%B6%E8%BD%AC%E5%8F%91%E6%B6%88%E6%81%AF
|
|
||||||
* @param $id
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getForwardMsg($id) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'id' => $id
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送好友赞
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#send_like-%E5%8F%91%E9%80%81%E5%A5%BD%E5%8F%8B%E8%B5%9E
|
|
||||||
* @param $user_id
|
|
||||||
* @param int $times
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function sendLike($user_id, $times = 1) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'times' => $times
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 群组踢人
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_kick-%E7%BE%A4%E7%BB%84%E8%B8%A2%E4%BA%BA
|
|
||||||
* @param $group_id
|
|
||||||
* @param $user_id
|
|
||||||
* @param bool $reject_add_request
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupKick($group_id, $user_id, $reject_add_request = false) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'reject_add_request' => $reject_add_request
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 群组单人禁言
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_ban-%E7%BE%A4%E7%BB%84%E5%8D%95%E4%BA%BA%E7%A6%81%E8%A8%80
|
|
||||||
* @param $group_id
|
|
||||||
* @param $user_id
|
|
||||||
* @param $duration
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupBan($group_id, $user_id, $duration = 1800) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'duration' => $duration
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 群组匿名用户禁言
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_anonymous_ban-%E7%BE%A4%E7%BB%84%E5%8C%BF%E5%90%8D%E7%94%A8%E6%88%B7%E7%A6%81%E8%A8%80
|
|
||||||
* @param $group_id
|
|
||||||
* @param $anonymous_or_flag
|
|
||||||
* @param int $duration
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupAnonymousBan($group_id, $anonymous_or_flag, $duration = 1800) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
(is_string($anonymous_or_flag) ? 'flag' : 'anonymous') => $anonymous_or_flag,
|
|
||||||
'duration' => $duration
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 群组全员禁言
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_whole_ban-%E7%BE%A4%E7%BB%84%E5%85%A8%E5%91%98%E7%A6%81%E8%A8%80
|
|
||||||
* @param $group_id
|
|
||||||
* @param bool $enable
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupWholeBan($group_id, $enable = true) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'enable' => $enable
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 群组设置管理员
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_admin-%E7%BE%A4%E7%BB%84%E8%AE%BE%E7%BD%AE%E7%AE%A1%E7%90%86%E5%91%98
|
|
||||||
* @param $group_id
|
|
||||||
* @param $user_id
|
|
||||||
* @param bool $enable
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupAdmin($group_id, $user_id, $enable = true) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'enable' => $enable
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 群组匿名
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_anonymous-%E7%BE%A4%E7%BB%84%E5%8C%BF%E5%90%8D
|
|
||||||
* @param $group_id
|
|
||||||
* @param bool $enable
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupAnonymous($group_id, $enable = true) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'enable' => $enable
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置群名片(群备注)
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_card-%E8%AE%BE%E7%BD%AE%E7%BE%A4%E5%90%8D%E7%89%87%E7%BE%A4%E5%A4%87%E6%B3%A8
|
|
||||||
* @param $group_id
|
|
||||||
* @param $user_id
|
|
||||||
* @param string $card
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupCard($group_id, $user_id, $card = "") {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'card' => $card
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置群名
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_name-%E8%AE%BE%E7%BD%AE%E7%BE%A4%E5%90%8D
|
|
||||||
* @param $group_id
|
|
||||||
* @param $group_name
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupName($group_id, $group_name) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'group_name' => $group_name
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出群组
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_leave-%E9%80%80%E5%87%BA%E7%BE%A4%E7%BB%84
|
|
||||||
* @param $group_id
|
|
||||||
* @param bool $is_dismiss
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupLeave($group_id, $is_dismiss = false) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'is_dismiss' => $is_dismiss
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置群组专属头衔
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_special_title-%E8%AE%BE%E7%BD%AE%E7%BE%A4%E7%BB%84%E4%B8%93%E5%B1%9E%E5%A4%B4%E8%A1%94
|
|
||||||
* @param $group_id
|
|
||||||
* @param $user_id
|
|
||||||
* @param string $special_title
|
|
||||||
* @param int $duration
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupSpecialTitle($group_id, $user_id, $special_title = "", $duration = -1) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'special_title' => $special_title,
|
|
||||||
'duration' => $duration
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理加好友请求
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_friend_add_request-%E5%A4%84%E7%90%86%E5%8A%A0%E5%A5%BD%E5%8F%8B%E8%AF%B7%E6%B1%82
|
|
||||||
* @param $flag
|
|
||||||
* @param bool $approve
|
|
||||||
* @param string $remark
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setFriendAddRequest($flag, $approve = true, $remark = "") {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'flag' => $flag,
|
|
||||||
'approve' => $approve,
|
|
||||||
'remark' => $remark
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理加群请求/邀请
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_group_add_request-%E5%A4%84%E7%90%86%E5%8A%A0%E7%BE%A4%E8%AF%B7%E6%B1%82%E9%82%80%E8%AF%B7
|
|
||||||
* @param $flag
|
|
||||||
* @param $sub_type
|
|
||||||
* @param bool $approve
|
|
||||||
* @param string $reason
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setGroupAddRequest($flag, $sub_type, $approve = true, $reason = "") {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'flag' => $flag,
|
|
||||||
'sub_type' => $sub_type,
|
|
||||||
'approve' => $approve,
|
|
||||||
'reason' => $reason
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取登录号信息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_login_info-%E8%8E%B7%E5%8F%96%E7%99%BB%E5%BD%95%E5%8F%B7%E4%BF%A1%E6%81%AF
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getLoginInfo() {
|
|
||||||
return $this->processAPI($this->connection, ['action' => $this->getActionName(__FUNCTION__)], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取陌生人信息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_stranger_info-%E8%8E%B7%E5%8F%96%E9%99%8C%E7%94%9F%E4%BA%BA%E4%BF%A1%E6%81%AF
|
|
||||||
* @param $user_id
|
|
||||||
* @param bool $no_cache
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getStrangerInfo($user_id, $no_cache = false) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'no_cache' => $no_cache
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取好友列表
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_friend_list-%E8%8E%B7%E5%8F%96%E5%A5%BD%E5%8F%8B%E5%88%97%E8%A1%A8
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getFriendList() {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__)
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取群信息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_info-%E8%8E%B7%E5%8F%96%E7%BE%A4%E4%BF%A1%E6%81%AF
|
|
||||||
* @param $group_id
|
|
||||||
* @param bool $no_cache
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getGroupInfo($group_id, $no_cache = false) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'no_cache' => $no_cache
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取群列表
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_list-%E8%8E%B7%E5%8F%96%E7%BE%A4%E5%88%97%E8%A1%A8
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getGroupList() {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__)
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取群成员信息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_member_info-%E8%8E%B7%E5%8F%96%E7%BE%A4%E6%88%90%E5%91%98%E4%BF%A1%E6%81%AF
|
|
||||||
* @param $group_id
|
|
||||||
* @param $user_id
|
|
||||||
* @param bool $no_cache
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getGroupMemberInfo($group_id, $user_id, $no_cache = false) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'user_id' => $user_id,
|
|
||||||
'no_cache' => $no_cache
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取群成员列表
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_member_list-%E8%8E%B7%E5%8F%96%E7%BE%A4%E6%88%90%E5%91%98%E5%88%97%E8%A1%A8
|
|
||||||
* @param $group_id
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getGroupMemberList($group_id) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取群荣誉信息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_group_honor_info-%E8%8E%B7%E5%8F%96%E7%BE%A4%E8%8D%A3%E8%AA%89%E4%BF%A1%E6%81%AF
|
|
||||||
* @param $group_id
|
|
||||||
* @param $type
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getGroupHonorInfo($group_id, $type) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'group_id' => $group_id,
|
|
||||||
'type' => $type
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 CSRF Token
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_csrf_token-%E8%8E%B7%E5%8F%96-csrf-token
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getCsrfToken() {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__)
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 QQ 相关接口凭证
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_credentials-%E8%8E%B7%E5%8F%96-qq-%E7%9B%B8%E5%85%B3%E6%8E%A5%E5%8F%A3%E5%87%AD%E8%AF%81
|
|
||||||
* @param string $domain
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getCredentials($domain = "") {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'domain' => $domain
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取语音
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_record-%E8%8E%B7%E5%8F%96%E8%AF%AD%E9%9F%B3
|
|
||||||
* @param $file
|
|
||||||
* @param $out_format
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getRecord($file, $out_format) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'file' => $file,
|
|
||||||
'out_format' => $out_format
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取图片
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_image-%E8%8E%B7%E5%8F%96%E5%9B%BE%E7%89%87
|
|
||||||
* @param $file
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getImage($file) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'file' => $file
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查是否可以发送图片
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#can_send_image-%E6%A3%80%E6%9F%A5%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E5%8F%91%E9%80%81%E5%9B%BE%E7%89%87
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function canSendImage() {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__)
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查是否可以发送语音
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#can_send_record-%E6%A3%80%E6%9F%A5%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E5%8F%91%E9%80%81%E8%AF%AD%E9%9F%B3
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function canSendRecord() {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__)
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取运行状态
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_status-%E8%8E%B7%E5%8F%96%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getStatus() {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__)
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取版本信息
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_version_info-%E8%8E%B7%E5%8F%96%E7%89%88%E6%9C%AC%E4%BF%A1%E6%81%AF
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function getVersionInfo() {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__)
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重启 OneBot 实现
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#set_restart-%E9%87%8D%E5%90%AF-onebot-%E5%AE%9E%E7%8E%B0
|
|
||||||
* @param int $delay
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function setRestart($delay = 0) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__),
|
|
||||||
'params' => [
|
|
||||||
'delay' => $delay
|
|
||||||
]
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清理缓存
|
|
||||||
* @link https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#clean_cache-%E6%B8%85%E7%90%86%E7%BC%93%E5%AD%98
|
|
||||||
* @return array|bool|null
|
|
||||||
*/
|
|
||||||
public function cleanCache() {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $this->getActionName(__FUNCTION__)
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function callExtendedAPI($action, $params = []) {
|
|
||||||
return $this->processAPI($this->connection, [
|
|
||||||
'action' => $action,
|
|
||||||
'params' => $params
|
|
||||||
], $this->callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getActionName(string $method) {
|
|
||||||
$prefix = ($this->prefix == self::API_ASYNC ? '_async' : ($this->prefix == self::API_RATE_LIMITED ? '_rate_limited' : ''));
|
|
||||||
$func_name = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $method));
|
|
||||||
return $func_name . $prefix;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ use ZM\Annotation\Http\MiddlewareClass;
|
|||||||
use ZM\Annotation\Http\RequestMapping;
|
use ZM\Annotation\Http\RequestMapping;
|
||||||
use ZM\Annotation\Interfaces\Level;
|
use ZM\Annotation\Interfaces\Level;
|
||||||
use ZM\Annotation\Module\Closed;
|
use ZM\Annotation\Module\Closed;
|
||||||
use ZM\Http\RouteManager;
|
use ZM\Utils\Manager\RouteManager;
|
||||||
|
use ZM\Utils\ZMUtil;
|
||||||
|
|
||||||
class AnnotationParser
|
class AnnotationParser
|
||||||
{
|
{
|
||||||
@@ -53,7 +54,7 @@ class AnnotationParser
|
|||||||
public function registerMods() {
|
public function registerMods() {
|
||||||
foreach ($this->path_list as $path) {
|
foreach ($this->path_list as $path) {
|
||||||
Console::debug("parsing annotation in " . $path[0]);
|
Console::debug("parsing annotation in " . $path[0]);
|
||||||
$all_class = getAllClasses($path[0], $path[1]);
|
$all_class = ZMUtil::getClassesPsr4($path[0], $path[1]);
|
||||||
$this->reader = new AnnotationReader();
|
$this->reader = new AnnotationReader();
|
||||||
foreach ($all_class as $v) {
|
foreach ($all_class as $v) {
|
||||||
Console::debug("正在检索 " . $v);
|
Console::debug("正在检索 " . $v);
|
||||||
@@ -88,7 +89,7 @@ class AnnotationParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach ($this->annotation_map[$v]["class_annotations"] as $ks => $vs) {
|
foreach ($this->annotation_map[$v]["class_annotations"] as $vs) {
|
||||||
$vs->class = $v;
|
$vs->class = $v;
|
||||||
|
|
||||||
//预处理1:将适用于每一个函数的注解到类注解重新注解到每个函数下面
|
//预处理1:将适用于每一个函数的注解到类注解重新注解到每个函数下面
|
||||||
@@ -132,12 +133,12 @@ class AnnotationParser
|
|||||||
|
|
||||||
public function generateAnnotationEvents() {
|
public function generateAnnotationEvents() {
|
||||||
$o = [];
|
$o = [];
|
||||||
foreach ($this->annotation_map as $module => $obj) {
|
foreach ($this->annotation_map as $obj) {
|
||||||
foreach (($obj["class_annotations"] ?? []) as $class_annotation) {
|
foreach (($obj["class_annotations"] ?? []) as $class_annotation) {
|
||||||
if ($class_annotation instanceof ErgodicAnnotation) continue;
|
if ($class_annotation instanceof ErgodicAnnotation) continue;
|
||||||
else $o[get_class($class_annotation)][] = $class_annotation;
|
else $o[get_class($class_annotation)][] = $class_annotation;
|
||||||
}
|
}
|
||||||
foreach (($obj["methods_annotations"] ?? []) as $method_name => $methods_annotations) {
|
foreach (($obj["methods_annotations"] ?? []) as $methods_annotations) {
|
||||||
foreach ($methods_annotations as $annotation) {
|
foreach ($methods_annotations as $annotation) {
|
||||||
$o[get_class($annotation)][] = $annotation;
|
$o[get_class($annotation)][] = $annotation;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use Symfony\Component\Console\Input\InputInterface;
|
|||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use ZM\Console\TermColor;
|
use ZM\Console\TermColor;
|
||||||
|
use ZM\Utils\DataProvider;
|
||||||
|
|
||||||
class BuildCommand extends Command
|
class BuildCommand extends Command
|
||||||
{
|
{
|
||||||
@@ -21,28 +22,28 @@ class BuildCommand extends Command
|
|||||||
|
|
||||||
protected function configure() {
|
protected function configure() {
|
||||||
$this->setDescription("Build an \".phar\" file | 将项目构建一个phar包");
|
$this->setDescription("Build an \".phar\" file | 将项目构建一个phar包");
|
||||||
$this->setHelp("此功能将会把炸毛框架的模块打包为\".phar\",供发布和执行。");
|
$this->setHelp("此功能将会把整个项目打包为phar");
|
||||||
$this->addOption("target", "D", InputOption::VALUE_REQUIRED, "Output Directory | 指定输出目录");
|
$this->addOption("target", "D", InputOption::VALUE_REQUIRED, "Output Directory | 指定输出目录");
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||||
$this->output = $output;
|
$this->output = $output;
|
||||||
$target_dir = $input->getOption("target") ?? (__DIR__ . '/../../../resources/');
|
$target_dir = $input->getOption("target") ?? (WORKING_DIR);
|
||||||
if (mb_strpos($target_dir, "../")) $target_dir = realpath($target_dir);
|
if (mb_strpos($target_dir, "../")) $target_dir = realpath($target_dir);
|
||||||
if ($target_dir === false) {
|
if ($target_dir === false) {
|
||||||
$output->writeln(TermColor::color8(31) . "Error: No such file or directory (" . __DIR__ . '/../../../resources/' . ")" . TermColor::RESET);
|
$output->writeln(TermColor::color8(31) . zm_internal_errcode("E00039") . "Error: No such file or directory (" . $target_dir . ")" . TermColor::RESET);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
$output->writeln("Target: " . $target_dir . " , Version: " . ($version = json_decode(file_get_contents(__DIR__ . "/../../../composer.json"), true)["version"]));
|
$output->writeln("Target: " . $target_dir);
|
||||||
if (mb_substr($target_dir, -1, 1) !== '/') $target_dir .= "/";
|
if (mb_substr($target_dir, -1, 1) !== '/') $target_dir .= "/";
|
||||||
if (ini_get('phar.readonly') == 1) {
|
if (ini_get('phar.readonly') == 1) {
|
||||||
$output->writeln(TermColor::color8(31) . "You need to set \"phar.readonly\" to \"Off\"!");
|
$output->writeln(TermColor::color8(31) . zm_internal_errcode("E00040") . "You need to set \"phar.readonly\" to \"Off\"!");
|
||||||
$output->writeln(TermColor::color8(31) . "See: https://stackoverflow.com/questions/34667606/cant-enable-phar-writing");
|
$output->writeln(TermColor::color8(31) . "See: https://stackoverflow.com/questions/34667606/cant-enable-phar-writing");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!is_dir($target_dir)) {
|
if (!is_dir($target_dir)) {
|
||||||
$output->writeln(TermColor::color8(31) . "Error: No such file or directory ($target_dir)" . TermColor::RESET);
|
$output->writeln(TermColor::color8(31) . zm_internal_errcode("E00039") . "Error: No such file or directory ($target_dir)" . TermColor::RESET);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
$filename = "server.phar";
|
$filename = "server.phar";
|
||||||
@@ -55,19 +56,43 @@ class BuildCommand extends Command
|
|||||||
@unlink($target_dir . $filename);
|
@unlink($target_dir . $filename);
|
||||||
$phar = new Phar($target_dir . $filename);
|
$phar = new Phar($target_dir . $filename);
|
||||||
$phar->startBuffering();
|
$phar->startBuffering();
|
||||||
$src = realpath(__DIR__ . '/../../zhamao-framework/');
|
|
||||||
$hello = file_get_contents($src . '/src/Module/Example/Hello.php');
|
$allow_dir = ["bin", "config", "resources", "src", "vendor", "composer.json", "README.md", "zhamao"];
|
||||||
$middleware = file_get_contents($src . '/src/Module/Middleware/TimerMiddleware.php');
|
|
||||||
unlink($src . '/src/Module/Example/Hello.php');
|
$archive_dir = DataProvider::getSourceRootDir();
|
||||||
unlink($src . '/src/Module/Middleware/TimerMiddleware.php');
|
$scan = scandir($archive_dir);
|
||||||
$phar->buildFromDirectory($src);
|
if ($scan[0] == ".") {
|
||||||
$phar->addFromString('tmp/Hello.php.bak', $hello);
|
unset($scan[0], $scan[1]);
|
||||||
$phar->addFromString('tmp/TimerMiddleware.php.bak', $middleware);
|
}
|
||||||
//$phar->compressFiles(Phar::GZ);
|
foreach ($scan as $v) {
|
||||||
$phar->setStub($phar->createDefaultStub('phar-starter.php'));
|
if (in_array($v, $allow_dir)) {
|
||||||
|
if (is_dir($archive_dir . "/" . $v)) {
|
||||||
|
$this->addDirectory($phar, $archive_dir . "/" . $v, $v);
|
||||||
|
} elseif (is_file($archive_dir . "/" . $v)) {
|
||||||
|
$phar->addFile($archive_dir . "/" . $v, $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$phar->setStub(
|
||||||
|
"#!/usr/bin/env php\n" .
|
||||||
|
$phar->createDefaultStub(LOAD_MODE == 0 ? "src/entry.php" : "vendor/zhamao/framework/src/entry.php")
|
||||||
|
);
|
||||||
$phar->stopBuffering();
|
$phar->stopBuffering();
|
||||||
file_put_contents($src . '/src/Module/Example/Hello.php', $hello);
|
|
||||||
file_put_contents($src . '/src/Module/Middleware/TimerMiddleware.php', $middleware);
|
|
||||||
$this->output->writeln("Successfully built. Location: " . $target_dir . "$filename");
|
$this->output->writeln("Successfully built. Location: " . $target_dir . "$filename");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function addDirectory(Phar $phar, $dir, $local_dir) {
|
||||||
|
$o = scandir($dir);
|
||||||
|
if ($o[0] == ".") {
|
||||||
|
unset($o[0], $o[1]);
|
||||||
|
}
|
||||||
|
foreach ($o as $v) {
|
||||||
|
if (is_dir($dir . "/" . $v)) {
|
||||||
|
$this->addDirectory($phar, $dir . "/" . $v, $local_dir . "/" . $v);
|
||||||
|
} elseif (is_file($dir . "/" . $v)) {
|
||||||
|
$phar->addFile($dir . "/" . $v, $local_dir . "/" . $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace ZM\Command;
|
namespace ZM\Command\Daemon;
|
||||||
|
|
||||||
|
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
@@ -16,12 +16,12 @@ abstract class DaemonCommand extends Command
|
|||||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||||
$pid_path = DataProvider::getWorkingDir() . "/.daemon_pid";
|
$pid_path = DataProvider::getWorkingDir() . "/.daemon_pid";
|
||||||
if (!file_exists($pid_path)) {
|
if (!file_exists($pid_path)) {
|
||||||
$output->writeln("<comment>没有检测到正在运行的守护进程!</comment>");
|
$output->writeln("<comment>没有检测到正在运行的守护进程或框架进程!</comment>");
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
$file = json_decode(file_get_contents($pid_path), true);
|
$file = json_decode(file_get_contents($pid_path), true);
|
||||||
if ($file === null || posix_getsid(intval($file["pid"])) === false) {
|
if ($file === null || posix_getsid(intval($file["pid"])) === false) {
|
||||||
$output->writeln("<comment>未检测到正在运行的守护进程!</comment>");
|
$output->writeln("<comment>未检测到正在运行的守护进程或框架进程!</comment>");
|
||||||
unlink($pid_path);
|
unlink($pid_path);
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace ZM\Command;
|
namespace ZM\Command\Daemon;
|
||||||
|
|
||||||
use Swoole\Process;
|
use Swoole\Process;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace ZM\Command;
|
namespace ZM\Command\Daemon;
|
||||||
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace ZM\Command;
|
namespace ZM\Command\Daemon;
|
||||||
|
|
||||||
use Swoole\Process;
|
use Swoole\Process;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
@@ -45,13 +45,13 @@ class InitCommand extends Command
|
|||||||
$info = pathinfo($file);
|
$info = pathinfo($file);
|
||||||
@mkdir($base_path . $info["dirname"], 0777, true);
|
@mkdir($base_path . $info["dirname"], 0777, true);
|
||||||
echo "Copying " . $file . PHP_EOL;
|
echo "Copying " . $file . PHP_EOL;
|
||||||
$package_name = ($version = json_decode(file_get_contents(__DIR__ . "/../../../composer.json"), true)["name"]);
|
$package_name = (json_decode(file_get_contents(__DIR__ . "/../../../composer.json"), true)["name"]);
|
||||||
copy($base_path . "/vendor/" . $package_name . $file, $base_path . $file);
|
copy($base_path . "/vendor/" . $package_name . $file, $base_path . $file);
|
||||||
} else {
|
} else {
|
||||||
echo "Skipping " . $file . " , file exists." . PHP_EOL;
|
echo "Skipping " . $file . " , file exists." . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chmod($base_path."/zhamao", 0755);
|
chmod($base_path . "/zhamao", 0755);
|
||||||
$autoload = [
|
$autoload = [
|
||||||
"psr-4" => [
|
"psr-4" => [
|
||||||
"Module\\" => "src/Module",
|
"Module\\" => "src/Module",
|
||||||
@@ -69,7 +69,7 @@ class InitCommand extends Command
|
|||||||
foreach ($autoload["psr-4"] as $k => $v) {
|
foreach ($autoload["psr-4"] as $k => $v) {
|
||||||
if (!isset($composer["autoload"]["psr-4"][$k])) $composer["autoload"]["psr-4"][$k] = $v;
|
if (!isset($composer["autoload"]["psr-4"][$k])) $composer["autoload"]["psr-4"][$k] = $v;
|
||||||
}
|
}
|
||||||
foreach ($autoload["files"] as $k => $v) {
|
foreach ($autoload["files"] as $v) {
|
||||||
if (!in_array($v, $composer["autoload"]["files"])) $composer["autoload"]["files"][] = $v;
|
if (!in_array($v, $composer["autoload"]["files"])) $composer["autoload"]["files"][] = $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ class InitCommand extends Command
|
|||||||
exec("composer dump-autoload");
|
exec("composer dump-autoload");
|
||||||
echo PHP_EOL;
|
echo PHP_EOL;
|
||||||
} else {
|
} else {
|
||||||
echo("Error occurred. Please check your updates.\n");
|
echo(zm_internal_errcode("E00041") . "Error occurred. Please check your updates.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
$output->writeln("<info>Done!</info>");
|
$output->writeln("<info>Done!</info>");
|
||||||
@@ -99,7 +99,7 @@ class InitCommand extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$output->writeln("initialization must be started with composer-project mode!");
|
$output->writeln(zm_internal_errcode("E00042") . "initialization must be started with composer-project mode!");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
75
src/ZM/Command/Module/ModuleListCommand.php
Normal file
75
src/ZM/Command/Module/ModuleListCommand.php
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Command\Module;
|
||||||
|
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use ZM\Config\ZMConfig;
|
||||||
|
use ZM\Console\Console;
|
||||||
|
use ZM\Utils\DataProvider;
|
||||||
|
use ZM\Utils\Manager\ModuleManager;
|
||||||
|
|
||||||
|
class ModuleListCommand extends Command
|
||||||
|
{
|
||||||
|
// the name of the command (the part after "bin/console")
|
||||||
|
protected static $defaultName = 'module:list';
|
||||||
|
|
||||||
|
protected function configure() {
|
||||||
|
$this->setDescription("Build an \".phar\" file | 将项目构建一个phar包");
|
||||||
|
$this->setHelp("此功能将会把炸毛框架的模块打包为\".phar\",供发布和执行。");
|
||||||
|
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||||
|
ZMConfig::setEnv($args["env"] ?? "");
|
||||||
|
if (ZMConfig::get("global") === false) {
|
||||||
|
die ("Global config load failed: " . ZMConfig::$last_error . "\nPlease init first!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//定义常量
|
||||||
|
include_once DataProvider::getFrameworkRootDir() . "/src/ZM/global_defines.php";
|
||||||
|
|
||||||
|
Console::init(
|
||||||
|
ZMConfig::get("global", "info_level") ?? 2,
|
||||||
|
null,
|
||||||
|
$args["log-theme"] ?? "default",
|
||||||
|
($o = ZMConfig::get("console_color")) === false ? [] : $o
|
||||||
|
);
|
||||||
|
|
||||||
|
$timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai";
|
||||||
|
date_default_timezone_set($timezone);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||||
|
$list = ModuleManager::getConfiguredModules();
|
||||||
|
|
||||||
|
foreach ($list as $v) {
|
||||||
|
echo "[" . Console::setColor($v["name"], "green") . "]" . PHP_EOL;
|
||||||
|
$out_list = ["类型" => "source"];
|
||||||
|
if (isset($v["version"])) $out_list["版本"] = $v["version"];
|
||||||
|
if (isset($v["description"])) $out_list["描述"] = $v["description"];
|
||||||
|
$out_list["目录"] = str_replace(DataProvider::getSourceRootDir() . "/", "", $v["module-path"]);
|
||||||
|
$this->printList($out_list);
|
||||||
|
}
|
||||||
|
$list = ModuleManager::getPackedModules();
|
||||||
|
foreach ($list as $v) {
|
||||||
|
echo "[" . Console::setColor($v["name"], "gold") . "]" . PHP_EOL;
|
||||||
|
$out_list = ["类型" => "archive(phar)"];
|
||||||
|
if (isset($v["module-config"]["version"])) $out_list["版本"] = $v["module-config"]["version"];
|
||||||
|
if (isset($v["module-config"]["description"])) $out_list["描述"] = $v["module-config"]["description"];
|
||||||
|
$out_list["位置"] = str_replace(DataProvider::getSourceRootDir() . "/", "", $v["phar-path"]);
|
||||||
|
$this->printList($out_list);
|
||||||
|
}
|
||||||
|
if ($list === []) {
|
||||||
|
echo Console::setColor("没有发现已编写打包配置文件(zm.json)的模块和已打包且装载的模块!", "yellow") . PHP_EOL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function printList($list) {
|
||||||
|
foreach ($list as $k => $v) {
|
||||||
|
echo "\t" . $k . ": " . Console::setColor($v, "yellow") . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/ZM/Command/Module/ModulePackCommand.php
Normal file
59
src/ZM/Command/Module/ModulePackCommand.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Command\Module;
|
||||||
|
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use ZM\Config\ZMConfig;
|
||||||
|
use ZM\Console\Console;
|
||||||
|
use ZM\Utils\DataProvider;
|
||||||
|
use ZM\Utils\Manager\ModuleManager;
|
||||||
|
|
||||||
|
class ModulePackCommand extends Command
|
||||||
|
{
|
||||||
|
// the name of the command (the part after "bin/console")
|
||||||
|
protected static $defaultName = 'module:pack';
|
||||||
|
|
||||||
|
protected function configure() {
|
||||||
|
$this->addArgument("module-name", InputArgument::REQUIRED);
|
||||||
|
$this->setDescription("Build an \".phar\" file | 将项目构建一个phar包");
|
||||||
|
$this->setHelp("此功能将会把炸毛框架的模块打包为\".phar\",供发布和执行。");
|
||||||
|
$this->addOption("target", "D", InputOption::VALUE_REQUIRED, "Output Directory | 指定输出目录");
|
||||||
|
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||||
|
ZMConfig::setEnv($args["env"] ?? "");
|
||||||
|
if (ZMConfig::get("global") === false) {
|
||||||
|
die ("Global config load failed: " . ZMConfig::$last_error . "\nPlease init first!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//定义常量
|
||||||
|
include_once DataProvider::getFrameworkRootDir()."/src/ZM/global_defines.php";
|
||||||
|
|
||||||
|
Console::init(
|
||||||
|
ZMConfig::get("global", "info_level") ?? 2,
|
||||||
|
null,
|
||||||
|
$args["log-theme"] ?? "default",
|
||||||
|
($o = ZMConfig::get("console_color")) === false ? [] : $o
|
||||||
|
);
|
||||||
|
|
||||||
|
$timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai";
|
||||||
|
date_default_timezone_set($timezone);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||||
|
$list = ModuleManager::getConfiguredModules();
|
||||||
|
if (!isset($list[$input->getArgument("module-name")])) {
|
||||||
|
$output->writeln("<error>不存在模块 ".$input->getArgument("module-name")." !</error>");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
$result = ModuleManager::packModule($list[$input->getArgument("module-name")]);
|
||||||
|
if ($result) Console::success("打包完成!");
|
||||||
|
else Console::error("打包失败!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/ZM/Command/Module/ModuleUnpackCommand.php
Normal file
57
src/ZM/Command/Module/ModuleUnpackCommand.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Command\Module;
|
||||||
|
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use ZM\Config\ZMConfig;
|
||||||
|
use ZM\Console\Console;
|
||||||
|
use ZM\Utils\DataProvider;
|
||||||
|
use ZM\Utils\Manager\ModuleManager;
|
||||||
|
|
||||||
|
class ModuleUnpackCommand extends Command
|
||||||
|
{
|
||||||
|
// the name of the command (the part after "bin/console")
|
||||||
|
protected static $defaultName = 'module:unpack';
|
||||||
|
|
||||||
|
protected function configure() {
|
||||||
|
$this->addArgument("module-name", InputArgument::REQUIRED);
|
||||||
|
$this->setDescription("Unpack a phar module into src directory");
|
||||||
|
$this->setHelp("此功能将phar格式的模块包解包到src目录下。");
|
||||||
|
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||||
|
ZMConfig::setEnv($args["env"] ?? "");
|
||||||
|
if (ZMConfig::get("global") === false) {
|
||||||
|
die ("Global config load failed: " . ZMConfig::$last_error . "\nPlease init first!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//定义常量
|
||||||
|
include_once DataProvider::getFrameworkRootDir()."/src/ZM/global_defines.php";
|
||||||
|
|
||||||
|
Console::init(
|
||||||
|
ZMConfig::get("global", "info_level") ?? 2,
|
||||||
|
null,
|
||||||
|
$args["log-theme"] ?? "default",
|
||||||
|
($o = ZMConfig::get("console_color")) === false ? [] : $o
|
||||||
|
);
|
||||||
|
|
||||||
|
$timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai";
|
||||||
|
date_default_timezone_set($timezone);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||||
|
$list = ModuleManager::getPackedModules();
|
||||||
|
if (!isset($list[$input->getArgument("module-name")])) {
|
||||||
|
$output->writeln("<error>不存在打包的模块 ".$input->getArgument("module-name")." !</error>");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
$result = ModuleManager::unpackModule($list[$input->getArgument("module-name")]);
|
||||||
|
if ($result) Console::success("解压完成!");
|
||||||
|
else Console::error("解压失败!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ class PureHttpCommand extends Command
|
|||||||
$output->writeln("<error>Directory error(" . ($input->getArgument('dir') ?? '.') . "): no such file or directory.</error>");
|
$output->writeln("<error>Directory error(" . ($input->getArgument('dir') ?? '.') . "): no such file or directory.</error>");
|
||||||
return self::FAILURE;
|
return self::FAILURE;
|
||||||
}
|
}
|
||||||
ZMConfig::setDirectory(DataProvider::getWorkingDir() . '/config');
|
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||||
$global = ZMConfig::get("global");
|
$global = ZMConfig::get("global");
|
||||||
$host = $input->getOption("host") ?? $global["host"];
|
$host = $input->getOption("host") ?? $global["host"];
|
||||||
$port = $input->getOption("port") ?? $global["port"];
|
$port = $input->getOption("port") ?? $global["port"];
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class RunServerCommand extends Command
|
|||||||
new InputOption("log-error", null, null, "调整消息等级到error (log-level=0)"),
|
new InputOption("log-error", null, null, "调整消息等级到error (log-level=0)"),
|
||||||
new InputOption("log-theme", null, InputOption::VALUE_REQUIRED, "改变终端的主题配色"),
|
new InputOption("log-theme", null, InputOption::VALUE_REQUIRED, "改变终端的主题配色"),
|
||||||
new InputOption("disable-console-input", null, null, "禁止终端输入内容 (废弃)"),
|
new InputOption("disable-console-input", null, null, "禁止终端输入内容 (废弃)"),
|
||||||
|
new InputOption("interact", null, null, "打开终端输入"),
|
||||||
new InputOption("remote-terminal", null, null, "启用远程终端,配置使用global.php中的"),
|
new InputOption("remote-terminal", null, null, "启用远程终端,配置使用global.php中的"),
|
||||||
new InputOption("disable-coroutine", null, null, "关闭协程Hook"),
|
new InputOption("disable-coroutine", null, null, "关闭协程Hook"),
|
||||||
new InputOption("daemon", null, null, "以守护进程的方式运行框架"),
|
new InputOption("daemon", null, null, "以守护进程的方式运行框架"),
|
||||||
@@ -32,7 +33,8 @@ class RunServerCommand extends Command
|
|||||||
new InputOption("show-php-ver", null, null, "启动时显示PHP和Swoole版本"),
|
new InputOption("show-php-ver", null, null, "启动时显示PHP和Swoole版本"),
|
||||||
new InputOption("env", null, InputOption::VALUE_REQUIRED, "设置环境类型 (production, development, staging)"),
|
new InputOption("env", null, InputOption::VALUE_REQUIRED, "设置环境类型 (production, development, staging)"),
|
||||||
new InputOption("disable-safe-exit", null, null, "关闭安全退出(关闭后按CtrlC时直接杀死进程)"),
|
new InputOption("disable-safe-exit", null, null, "关闭安全退出(关闭后按CtrlC时直接杀死进程)"),
|
||||||
new InputOption("preview", null, null, "只显示参数,不启动服务器")
|
new InputOption("preview", null, null, "只显示参数,不启动服务器"),
|
||||||
|
new InputOption("force-load-module", null, InputOption::VALUE_OPTIONAL, "强制打包状态下加载模块(使用英文逗号分割多个)")
|
||||||
]);
|
]);
|
||||||
$this->setDescription("Run zhamao-framework | 启动框架");
|
$this->setDescription("Run zhamao-framework | 启动框架");
|
||||||
$this->setHelp("直接运行可以启动");
|
$this->setHelp("直接运行可以启动");
|
||||||
|
|||||||
@@ -29,11 +29,8 @@ class SystemdCommand extends Command
|
|||||||
$s .= "\nUser=" . exec("whoami");
|
$s .= "\nUser=" . exec("whoami");
|
||||||
$s .= "\nGroup=" . exec("groups | awk '{print $1}'");
|
$s .= "\nGroup=" . exec("groups | awk '{print $1}'");
|
||||||
$s .= "\nWorkingDirectory=" . getcwd();
|
$s .= "\nWorkingDirectory=" . getcwd();
|
||||||
if (LOAD_MODE == 1) {
|
global $argv;
|
||||||
$s .= "\nExecStart=" . getcwd() . "/vendor/bin/start server";
|
$s .= "\nExecStart=".PHP_BINARY." {$argv[0]} server";
|
||||||
} else {
|
|
||||||
$s .= "\nExecStart=" . getcwd() . "/bin/start server";
|
|
||||||
}
|
|
||||||
$s .= "\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n";
|
$s .= "\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n";
|
||||||
@mkdir(getcwd() . "/resources/");
|
@mkdir(getcwd() . "/resources/");
|
||||||
file_put_contents(getcwd() . "/resources/zhamao.service", $s);
|
file_put_contents(getcwd() . "/resources/zhamao.service", $s);
|
||||||
|
|||||||
@@ -5,22 +5,28 @@ namespace ZM;
|
|||||||
|
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Phar;
|
||||||
|
use ZM\Command\BuildCommand;
|
||||||
use ZM\Command\CheckConfigCommand;
|
use ZM\Command\CheckConfigCommand;
|
||||||
use ZM\Command\DaemonReloadCommand;
|
use ZM\Command\Daemon\DaemonReloadCommand;
|
||||||
use ZM\Command\DaemonStatusCommand;
|
use ZM\Command\Daemon\DaemonStatusCommand;
|
||||||
use ZM\Command\DaemonStopCommand;
|
use ZM\Command\Daemon\DaemonStopCommand;
|
||||||
use ZM\Command\InitCommand;
|
use ZM\Command\InitCommand;
|
||||||
|
use ZM\Command\Module\ModuleListCommand;
|
||||||
|
use ZM\Command\Module\ModulePackCommand;
|
||||||
|
use ZM\Command\Module\ModuleUnpackCommand;
|
||||||
use ZM\Command\PureHttpCommand;
|
use ZM\Command\PureHttpCommand;
|
||||||
use ZM\Command\RunServerCommand;
|
use ZM\Command\RunServerCommand;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use ZM\Command\SystemdCommand;
|
use ZM\Command\SystemdCommand;
|
||||||
|
use ZM\Console\Console;
|
||||||
|
|
||||||
class ConsoleApplication extends Application
|
class ConsoleApplication extends Application
|
||||||
{
|
{
|
||||||
const VERSION_ID = 407;
|
const VERSION_ID = 408;
|
||||||
const VERSION = "2.5.0";
|
const VERSION = "2.5.0-b1";
|
||||||
|
|
||||||
public function __construct(string $name = 'UNKNOWN') {
|
public function __construct(string $name = 'UNKNOWN') {
|
||||||
define("ZM_VERSION_ID", self::VERSION_ID);
|
define("ZM_VERSION_ID", self::VERSION_ID);
|
||||||
@@ -32,10 +38,18 @@ class ConsoleApplication extends Application
|
|||||||
$this->selfCheck();
|
$this->selfCheck();
|
||||||
|
|
||||||
define("WORKING_DIR", getcwd());
|
define("WORKING_DIR", getcwd());
|
||||||
define("LOAD_MODE", is_dir(WORKING_DIR . "/src/ZM") ? 0 : 1);
|
if (Phar::running() !== "") {
|
||||||
define("FRAMEWORK_ROOT_DIR", realpath(__DIR__ . "/../../"));
|
echo "* Running in phar mode.\n";
|
||||||
|
define("SOURCE_ROOT_DIR", Phar::running());
|
||||||
|
define("LOAD_MODE", is_dir(SOURCE_ROOT_DIR . "/src/ZM") ? 0 : 1);
|
||||||
|
define("FRAMEWORK_ROOT_DIR", LOAD_MODE == 1 ? (SOURCE_ROOT_DIR . "/vendor/zhamao/framework") : SOURCE_ROOT_DIR);
|
||||||
|
} else {
|
||||||
|
define("SOURCE_ROOT_DIR", WORKING_DIR);
|
||||||
|
define("LOAD_MODE", is_dir(SOURCE_ROOT_DIR . "/src/ZM") ? 0 : 1);
|
||||||
|
define("FRAMEWORK_ROOT_DIR", realpath(__DIR__ . "/../../"));
|
||||||
|
}
|
||||||
if (LOAD_MODE == 0) {
|
if (LOAD_MODE == 0) {
|
||||||
$composer = json_decode(file_get_contents(WORKING_DIR . "/composer.json"), true);
|
$composer = json_decode(file_get_contents(SOURCE_ROOT_DIR . "/composer.json"), true);
|
||||||
if (!isset($composer["autoload"]["psr-4"]["Module\\"])) {
|
if (!isset($composer["autoload"]["psr-4"]["Module\\"])) {
|
||||||
echo "框架源码模式需要在autoload文件中添加Module目录为自动加载,是否添加?[Y/n] ";
|
echo "框架源码模式需要在autoload文件中添加Module目录为自动加载,是否添加?[Y/n] ";
|
||||||
$r = strtolower(trim(fgets(STDIN)));
|
$r = strtolower(trim(fgets(STDIN)));
|
||||||
@@ -47,7 +61,7 @@ class ConsoleApplication extends Application
|
|||||||
echo "成功添加!请运行 composer dump-autoload !\n";
|
echo "成功添加!请运行 composer dump-autoload !\n";
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
echo "添加失败!请按任意键继续!";
|
echo zm_internal_errcode("E00006") . "添加失败!请按任意键继续!";
|
||||||
fgets(STDIN);
|
fgets(STDIN);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -62,13 +76,19 @@ class ConsoleApplication extends Application
|
|||||||
new DaemonReloadCommand(),
|
new DaemonReloadCommand(),
|
||||||
new DaemonStopCommand(),
|
new DaemonStopCommand(),
|
||||||
new RunServerCommand(), //运行主服务的指令控制器
|
new RunServerCommand(), //运行主服务的指令控制器
|
||||||
new InitCommand(), //初始化用的,用于项目初始化和phar初始化
|
|
||||||
new PureHttpCommand(), //纯HTTP服务器指令
|
new PureHttpCommand(), //纯HTTP服务器指令
|
||||||
new SystemdCommand()
|
new SystemdCommand()
|
||||||
]);
|
]);
|
||||||
if (LOAD_MODE === 1) {
|
if (LOAD_MODE === 1) {
|
||||||
$this->add(new CheckConfigCommand());
|
$this->add(new CheckConfigCommand());
|
||||||
}
|
}
|
||||||
|
if (Phar::running() === "") {
|
||||||
|
$this->add(new BuildCommand());
|
||||||
|
$this->add(new InitCommand());
|
||||||
|
$this->add(new ModulePackCommand());
|
||||||
|
$this->add(new ModuleListCommand());
|
||||||
|
$this->add(new ModuleUnpackCommand());
|
||||||
|
}
|
||||||
if (!empty($with_default_cmd)) {
|
if (!empty($with_default_cmd)) {
|
||||||
$this->setDefaultCommand($with_default_cmd);
|
$this->setDefaultCommand($with_default_cmd);
|
||||||
}
|
}
|
||||||
@@ -84,14 +104,20 @@ class ConsoleApplication extends Application
|
|||||||
try {
|
try {
|
||||||
return parent::run($input, $output);
|
return parent::run($input, $output);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
die("{$e->getMessage()} at {$e->getFile()}({$e->getLine()})");
|
die(zm_internal_errcode("E00005") . "{$e->getMessage()} at {$e->getFile()}({$e->getLine()})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function selfCheck(): bool {
|
/**
|
||||||
if (!extension_loaded("swoole")) die("Can not find swoole extension.\nSee: https://github.com/zhamao-robot/zhamao-framework/issues/19\n");
|
* 启动炸毛前要做的环境检查项目
|
||||||
if (version_compare(SWOOLE_VERSION, "4.5.0") == -1) die("You must install swoole version >= 4.5.0 !");
|
*/
|
||||||
if (version_compare(PHP_VERSION, "7.2") == -1) die("PHP >= 7.2 required.");
|
private function selfCheck(): void {
|
||||||
return true;
|
if (!extension_loaded("swoole")) die(zm_internal_errcode("E00001") . "Can not find swoole extension.\n");
|
||||||
|
if (version_compare(SWOOLE_VERSION, "4.5.0") == -1) die(zm_internal_errcode("E00002") . "You must install swoole version >= 4.5.0 !");
|
||||||
|
if (version_compare(PHP_VERSION, "7.2") == -1) die(zm_internal_errcode("E00003") . "PHP >= 7.2 required.");
|
||||||
|
if (version_compare(SWOOLE_VERSION, "4.6.7") < 0 && !extension_loaded("pcntl")) {
|
||||||
|
Console::error(zm_internal_errcode("E00004") . "Swoole 版本必须不低于 4.6.7 或 PHP 安装加载了 pcntl 扩展!");
|
||||||
|
die();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
namespace ZM\Context;
|
namespace ZM\Context;
|
||||||
|
|
||||||
|
|
||||||
use Co;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Swoole\Coroutine;
|
||||||
use Swoole\Http\Request;
|
use Swoole\Http\Request;
|
||||||
use Swoole\WebSocket\Frame;
|
use Swoole\WebSocket\Frame;
|
||||||
use Swoole\WebSocket\Server;
|
use Swoole\WebSocket\Server;
|
||||||
@@ -104,8 +104,7 @@ class Context implements ContextInterface
|
|||||||
* only can used by cq->message event function
|
* only can used by cq->message event function
|
||||||
* @param $msg
|
* @param $msg
|
||||||
* @param bool $yield
|
* @param bool $yield
|
||||||
* @return mixed
|
* @return array|bool
|
||||||
* @noinspection PhpMissingReturnTypeInspection
|
|
||||||
*/
|
*/
|
||||||
public function reply($msg, $yield = false) {
|
public function reply($msg, $yield = false) {
|
||||||
$data = $this->getData();
|
$data = $this->getData();
|
||||||
@@ -136,7 +135,7 @@ class Context implements ContextInterface
|
|||||||
/**
|
/**
|
||||||
* @param $msg
|
* @param $msg
|
||||||
* @param false $yield
|
* @param false $yield
|
||||||
* @return mixed|void
|
* @return void
|
||||||
* @throws InterruptException
|
* @throws InterruptException
|
||||||
*/
|
*/
|
||||||
public function finalReply($msg, $yield = false) {
|
public function finalReply($msg, $yield = false) {
|
||||||
@@ -170,42 +169,6 @@ class Context implements ContextInterface
|
|||||||
throw new WaitTimeoutException($this, $timeout_prompt);
|
throw new WaitTimeoutException($this, $timeout_prompt);
|
||||||
}
|
}
|
||||||
return $r["message"];
|
return $r["message"];
|
||||||
/*
|
|
||||||
$cid = Co::getuid();
|
|
||||||
$api_id = ZMAtomic::get("wait_msg_id")->add(1);
|
|
||||||
$hang = [
|
|
||||||
"coroutine" => $cid,
|
|
||||||
"user_id" => $this->getData()["user_id"],
|
|
||||||
"message" => $this->getData()["message"],
|
|
||||||
"self_id" => $this->getData()["self_id"],
|
|
||||||
"message_type" => $this->getData()["message_type"],
|
|
||||||
"result" => null
|
|
||||||
];
|
|
||||||
if ($hang["message_type"] == "group" || $hang["message_type"] == "discuss") {
|
|
||||||
$hang[$hang["message_type"] . "_id"] = $this->getData()[$this->getData()["message_type"] . "_id"];
|
|
||||||
}
|
|
||||||
SpinLock::lock("wait_api");
|
|
||||||
$hw = LightCacheInside::get("wait_api", "wait_api") ?? [];
|
|
||||||
$hw[$api_id] = $hang;
|
|
||||||
LightCacheInside::set("wait_api", "wait_api", $hw);
|
|
||||||
SpinLock::unlock("wait_api");
|
|
||||||
$id = swoole_timer_after($timeout * 1000, function () use ($api_id, $timeout_prompt) {
|
|
||||||
$r = LightCacheInside::get("wait_api", "wait_api")[$api_id] ?? null;
|
|
||||||
if (is_array($r)) {
|
|
||||||
Co::resume($r["coroutine"]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Co::suspend();
|
|
||||||
SpinLock::lock("wait_api");
|
|
||||||
$hw = LightCacheInside::get("wait_api", "wait_api") ?? [];
|
|
||||||
$sess = $hw[$api_id];
|
|
||||||
unset($hw[$api_id]);
|
|
||||||
LightCacheInside::set("wait_api", "wait_api", $hw);
|
|
||||||
$result = $sess["result"];
|
|
||||||
if (isset($id)) swoole_timer_clear($id);
|
|
||||||
if ($result === null) throw new WaitTimeoutException($this, $timeout_prompt);
|
|
||||||
return $result;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -269,7 +232,7 @@ class Context implements ContextInterface
|
|||||||
|
|
||||||
/** @noinspection PhpMissingReturnTypeInspection */
|
/** @noinspection PhpMissingReturnTypeInspection */
|
||||||
public function cloneFromParent() {
|
public function cloneFromParent() {
|
||||||
set_coroutine_params(self::$context[Co::getPcid()] ?? self::$context[$this->cid]);
|
set_coroutine_params(self::$context[Coroutine::getPcid()] ?? self::$context[$this->cid]);
|
||||||
return context();
|
return context();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ class EventManager
|
|||||||
try {
|
try {
|
||||||
$dispatcher->dispatchEvent($vss, null);
|
$dispatcher->dispatchEvent($vss, null);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Console::error("Uncaught error from TimerTick: " . $e->getMessage() . " at " . $e->getFile() . "({$e->getLine()})");
|
Console::error(zm_internal_errcode("E00034") . "Uncaught error from TimerTick: " . $e->getMessage() . " at " . $e->getFile() . "({$e->getLine()})");
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
Console::error("Uncaught fatal error from TimerTick: " . $e->getMessage());
|
Console::error(zm_internal_errcode("E00034") . "Uncaught fatal error from TimerTick: " . $e->getMessage());
|
||||||
echo Console::setColor($e->getTraceAsString(), "gray");
|
echo Console::setColor($e->getTraceAsString(), "gray");
|
||||||
Console::error("Please check your code!");
|
Console::error("Please check your code!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
namespace ZM\Event\SwooleEvent;
|
namespace ZM\Event\SwooleEvent;
|
||||||
|
|
||||||
|
|
||||||
use Co;
|
|
||||||
use Error;
|
use Error;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Swoole\Coroutine;
|
||||||
use ZM\Annotation\Swoole\OnCloseEvent;
|
use ZM\Annotation\Swoole\OnCloseEvent;
|
||||||
use ZM\Annotation\Swoole\OnSwooleEvent;
|
use ZM\Annotation\Swoole\OnSwooleEvent;
|
||||||
use ZM\Annotation\Swoole\SwooleHandler;
|
use ZM\Annotation\Swoole\SwooleHandler;
|
||||||
@@ -27,7 +27,7 @@ class OnClose implements SwooleEvent
|
|||||||
{
|
{
|
||||||
/** @noinspection PhpUnreachableStatementInspection */
|
/** @noinspection PhpUnreachableStatementInspection */
|
||||||
public function onCall($server, $fd) {
|
public function onCall($server, $fd) {
|
||||||
unset(Context::$context[Co::getCid()]);
|
unset(Context::$context[Coroutine::getCid()]);
|
||||||
Console::debug("Calling Swoole \"close\" event from fd=" . $fd);
|
Console::debug("Calling Swoole \"close\" event from fd=" . $fd);
|
||||||
$conn = ManagerGM::get($fd);
|
$conn = ManagerGM::get($fd);
|
||||||
if ($conn === null) return;
|
if ($conn === null) return;
|
||||||
@@ -61,11 +61,11 @@ class OnClose implements SwooleEvent
|
|||||||
$dispatcher->dispatchEvents($conn);
|
$dispatcher->dispatchEvents($conn);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught exception " . get_class($e) . " when calling \"close\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00016") . "Uncaught exception " . get_class($e) . " when calling \"close\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught " . get_class($e) . " when calling \"close\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00016") . "Uncaught " . get_class($e) . " when calling \"close\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
}
|
}
|
||||||
ManagerGM::popConnect($fd);
|
ManagerGM::popConnect($fd);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use ZM\Annotation\Swoole\SwooleHandler;
|
|||||||
use ZM\Console\Console;
|
use ZM\Console\Console;
|
||||||
use ZM\Event\SwooleEvent;
|
use ZM\Event\SwooleEvent;
|
||||||
use ZM\Framework;
|
use ZM\Framework;
|
||||||
|
use ZM\Utils\SignalListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class OnManagerStart
|
* Class OnManagerStart
|
||||||
@@ -21,9 +22,7 @@ class OnManagerStart implements SwooleEvent
|
|||||||
{
|
{
|
||||||
public function onCall(Server $server) {
|
public function onCall(Server $server) {
|
||||||
if (!Framework::$argv["disable-safe-exit"]) {
|
if (!Framework::$argv["disable-safe-exit"]) {
|
||||||
pcntl_signal(SIGINT, function () {
|
SignalListener::signalManager();
|
||||||
Console::verbose("Interrupted in manager!");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Console::verbose("进程 Manager 已启动");
|
Console::verbose("进程 Manager 已启动");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ class OnMessage implements SwooleEvent
|
|||||||
//Console::success("Used ".round((microtime(true) - $starttime) * 1000, 3)." ms!");
|
//Console::success("Used ".round((microtime(true) - $starttime) * 1000, 3)." ms!");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught exception " . get_class($e) . " when calling \"message\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00017") . "Uncaught exception " . get_class($e) . " when calling \"message\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught " . get_class($e) . " when calling \"message\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00017") . "Uncaught " . get_class($e) . " when calling \"message\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ namespace ZM\Event\SwooleEvent;
|
|||||||
|
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Co;
|
|
||||||
use Error;
|
use Error;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Swoole\Coroutine;
|
||||||
use Swoole\Http\Request;
|
use Swoole\Http\Request;
|
||||||
use ZM\Annotation\Swoole\OnOpenEvent;
|
use ZM\Annotation\Swoole\OnOpenEvent;
|
||||||
use ZM\Annotation\Swoole\OnSwooleEvent;
|
use ZM\Annotation\Swoole\OnSwooleEvent;
|
||||||
@@ -30,20 +30,20 @@ class OnOpen implements SwooleEvent
|
|||||||
/** @noinspection PhpUnreachableStatementInspection */
|
/** @noinspection PhpUnreachableStatementInspection */
|
||||||
public function onCall($server, Request $request) {
|
public function onCall($server, Request $request) {
|
||||||
Console::debug("Calling Swoole \"open\" event from fd=" . $request->fd);
|
Console::debug("Calling Swoole \"open\" event from fd=" . $request->fd);
|
||||||
unset(Context::$context[Co::getCid()]);
|
unset(Context::$context[Coroutine::getCid()]);
|
||||||
$type = strtolower($request->header["x-client-role"] ?? $request->get["type"] ?? "");
|
$type = strtolower($request->header["x-client-role"] ?? $request->get["type"] ?? "");
|
||||||
$access_token = explode(" ", $request->header["authorization"] ?? "")[1] ?? $request->get["token"] ?? "";
|
$access_token = explode(" ", $request->header["authorization"] ?? "")[1] ?? $request->get["token"] ?? "";
|
||||||
$token = ZMConfig::get("global", "access_token");
|
$token = ZMConfig::get("global", "access_token");
|
||||||
if ($token instanceof Closure) {
|
if ($token instanceof Closure) {
|
||||||
if (!$token($access_token)) {
|
if (!$token($access_token)) {
|
||||||
$server->close($request->fd);
|
$server->close($request->fd);
|
||||||
Console::warning("Unauthorized access_token: " . $access_token);
|
Console::warning(zm_internal_errcode("E00018") . "Unauthorized access_token: " . $access_token);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} elseif (is_string($token)) {
|
} elseif (is_string($token)) {
|
||||||
if ($access_token !== $token && $token !== "") {
|
if ($access_token !== $token && $token !== "") {
|
||||||
$server->close($request->fd);
|
$server->close($request->fd);
|
||||||
Console::warning("Unauthorized access_token: " . $access_token);
|
Console::warning(zm_internal_errcode("E00019") . "Unauthorized access_token: " . $access_token);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,11 +81,11 @@ class OnOpen implements SwooleEvent
|
|||||||
$dispatcher->dispatchEvents($conn);
|
$dispatcher->dispatchEvents($conn);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught exception " . get_class($e) . " when calling \"open\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00020") . "Uncaught exception " . get_class($e) . " when calling \"open\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught " . get_class($e) . " when calling \"open\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00020") . "Uncaught " . get_class($e) . " when calling \"open\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
namespace ZM\Event\SwooleEvent;
|
namespace ZM\Event\SwooleEvent;
|
||||||
|
|
||||||
|
|
||||||
|
use Error;
|
||||||
|
use Exception;
|
||||||
use Swoole\Server;
|
use Swoole\Server;
|
||||||
use ZM\Annotation\Swoole\SwooleHandler;
|
use ZM\Annotation\Swoole\SwooleHandler;
|
||||||
|
use ZM\Console\Console;
|
||||||
use ZM\Event\SwooleEvent;
|
use ZM\Event\SwooleEvent;
|
||||||
use ZM\Utils\ProcessManager;
|
use ZM\Utils\Manager\ProcessManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class OnPipeMessage
|
* Class OnPipeMessage
|
||||||
@@ -18,6 +21,16 @@ class OnPipeMessage implements SwooleEvent
|
|||||||
{
|
{
|
||||||
public function onCall(Server $server, $src_worker_id, $data) {
|
public function onCall(Server $server, $src_worker_id, $data) {
|
||||||
$data = json_decode($data, true);
|
$data = json_decode($data, true);
|
||||||
ProcessManager::workerAction($src_worker_id, $data);
|
try {
|
||||||
|
ProcessManager::workerAction($src_worker_id, $data);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
|
Console::error(zm_internal_errcode("E00021") . "Uncaught exception " . get_class($e) . " when calling \"pipeMessage\": " . $error_msg);
|
||||||
|
Console::trace();
|
||||||
|
} catch (Error $e) {
|
||||||
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
|
Console::error(zm_internal_errcode("E00021") . "Uncaught " . get_class($e) . " when calling \"pipeMessage\": " . $error_msg);
|
||||||
|
Console::trace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
namespace ZM\Event\SwooleEvent;
|
namespace ZM\Event\SwooleEvent;
|
||||||
|
|
||||||
|
|
||||||
use Co;
|
|
||||||
use Error;
|
use Error;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Swoole\Coroutine;
|
||||||
use Swoole\Http\Request;
|
use Swoole\Http\Request;
|
||||||
use ZM\Annotation\Http\RequestMapping;
|
use ZM\Annotation\Http\RequestMapping;
|
||||||
use ZM\Annotation\Swoole\OnRequestEvent;
|
use ZM\Annotation\Swoole\OnRequestEvent;
|
||||||
@@ -33,7 +33,7 @@ class OnRequest implements SwooleEvent
|
|||||||
foreach (ZMConfig::get("global")["http_header"] as $k => $v) {
|
foreach (ZMConfig::get("global")["http_header"] as $k => $v) {
|
||||||
$response->setHeader($k, $v);
|
$response->setHeader($k, $v);
|
||||||
}
|
}
|
||||||
unset(Context::$context[Co::getCid()]);
|
unset(Context::$context[Coroutine::getCid()]);
|
||||||
Console::debug("Calling Swoole \"request\" event from fd=" . $request->fd);
|
Console::debug("Calling Swoole \"request\" event from fd=" . $request->fd);
|
||||||
set_coroutine_params(["request" => $request, "response" => $response]);
|
set_coroutine_params(["request" => $request, "response" => $response]);
|
||||||
|
|
||||||
@@ -86,11 +86,11 @@ class OnRequest implements SwooleEvent
|
|||||||
);
|
);
|
||||||
if (!$response->isEnd()) {
|
if (!$response->isEnd()) {
|
||||||
if (ZMConfig::get("global", "debug_mode"))
|
if (ZMConfig::get("global", "debug_mode"))
|
||||||
$response->end("Internal server exception: " . $e->getMessage());
|
$response->end(zm_internal_errcode("E00023") . "Internal server exception: " . $e->getMessage());
|
||||||
else
|
else
|
||||||
$response->end("Internal server error.");
|
$response->end(zm_internal_errcode("E00023") . "Internal server error.");
|
||||||
}
|
}
|
||||||
Console::error("Internal server exception (500), caused by " . get_class($e) . ": " . $e->getMessage());
|
Console::error(zm_internal_errcode("E00023") . "Internal server exception (500), caused by " . get_class($e) . ": " . $e->getMessage());
|
||||||
Console::log($e->getTraceAsString(), "gray");
|
Console::log($e->getTraceAsString(), "gray");
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$response->status(500);
|
$response->status(500);
|
||||||
@@ -100,11 +100,11 @@ class OnRequest implements SwooleEvent
|
|||||||
if (!$response->isEnd()) {
|
if (!$response->isEnd()) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
if (ZMConfig::get("global", "debug_mode"))
|
if (ZMConfig::get("global", "debug_mode"))
|
||||||
$response->end("Internal server error: " . $error_msg);
|
$response->end(zm_internal_errcode("E00023") . "Internal server error: " . $error_msg);
|
||||||
else
|
else
|
||||||
$response->end("Internal server error.");
|
$response->end(zm_internal_errcode("E00023") . "Internal server error.");
|
||||||
}
|
}
|
||||||
Console::error("Internal server error (500), caused by " . get_class($e) . ": " . $e->getMessage());
|
Console::error(zm_internal_errcode("E00023") . "Internal server error (500), caused by " . get_class($e) . ": " . $e->getMessage());
|
||||||
Console::log($e->getTraceAsString(), "gray");
|
Console::log($e->getTraceAsString(), "gray");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,18 @@
|
|||||||
namespace ZM\Event\SwooleEvent;
|
namespace ZM\Event\SwooleEvent;
|
||||||
|
|
||||||
|
|
||||||
|
use Error;
|
||||||
|
use Exception;
|
||||||
use Swoole\Event;
|
use Swoole\Event;
|
||||||
use Swoole\Process;
|
|
||||||
use Swoole\Server;
|
use Swoole\Server;
|
||||||
use ZM\Annotation\Swoole\SwooleHandler;
|
use ZM\Annotation\Swoole\SwooleHandler;
|
||||||
use ZM\Config\ZMConfig;
|
|
||||||
use ZM\Console\Console;
|
use ZM\Console\Console;
|
||||||
use ZM\Event\SwooleEvent;
|
use ZM\Event\SwooleEvent;
|
||||||
use ZM\Framework;
|
use ZM\Framework;
|
||||||
|
use ZM\Store\ZMBuf;
|
||||||
use ZM\Utils\DataProvider;
|
use ZM\Utils\DataProvider;
|
||||||
|
use ZM\Utils\SignalListener;
|
||||||
|
use ZM\Utils\Terminal;
|
||||||
use ZM\Utils\ZMUtil;
|
use ZM\Utils\ZMUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,48 +26,49 @@ use ZM\Utils\ZMUtil;
|
|||||||
class OnStart implements SwooleEvent
|
class OnStart implements SwooleEvent
|
||||||
{
|
{
|
||||||
public function onCall(Server $server) {
|
public function onCall(Server $server) {
|
||||||
$r = null;
|
|
||||||
if (!Framework::$argv["disable-safe-exit"]) {
|
if (!Framework::$argv["disable-safe-exit"]) {
|
||||||
Process::signal(SIGINT, function () use ($r, $server) {
|
SignalListener::signalMaster($server);
|
||||||
if (zm_atomic("_int_is_reload")->get() === 1) {
|
|
||||||
zm_atomic("_int_is_reload")->set(0);
|
|
||||||
$server->reload();
|
|
||||||
} else {
|
|
||||||
echo "\r";
|
|
||||||
Console::warning("Server interrupted(SIGINT) on Master.");
|
|
||||||
if ((Framework::$server->inotify ?? null) !== null)
|
|
||||||
/** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify);
|
|
||||||
Process::kill($server->master_pid, SIGTERM);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (Framework::$argv["daemon"]) {
|
|
||||||
$daemon_data = json_encode([
|
|
||||||
"pid" => $server->master_pid,
|
|
||||||
"stdout" => ZMConfig::get("global")["swoole"]["log_file"]
|
|
||||||
], 128 | 256);
|
|
||||||
file_put_contents(DataProvider::getWorkingDir() . "/.daemon_pid", $daemon_data);
|
|
||||||
}
|
}
|
||||||
if (Framework::$argv["watch"]) {
|
if (Framework::$argv["watch"]) {
|
||||||
if (extension_loaded('inotify')) {
|
if (extension_loaded('inotify')) {
|
||||||
Console::info("Enabled File watcher, framework will reload automatically.");
|
Console::info("Enabled File watcher, framework will reload automatically.");
|
||||||
/** @noinspection PhpUndefinedFieldInspection */
|
/** @noinspection PhpUndefinedFieldInspection */
|
||||||
Framework::$server->inotify = $fd = inotify_init();
|
Framework::$server->inotify = $fd = inotify_init();
|
||||||
$this->addWatcher(DataProvider::getWorkingDir() . "/src", $fd);
|
$this->addWatcher(DataProvider::getSourceRootDir() . "/src", $fd);
|
||||||
Event::add($fd, function () use ($fd) {
|
Event::add($fd, function () use ($fd) {
|
||||||
$r = inotify_read($fd);
|
$r = inotify_read($fd);
|
||||||
Console::verbose("File updated: ".$r[0]["name"]);
|
Console::verbose("File updated: " . $r[0]["name"]);
|
||||||
ZMUtil::reload();
|
ZMUtil::reload();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Console::warning("You have not loaded \"inotify\" extension, please install first.");
|
Console::warning(zm_internal_errcode("E00024") . "You have not loaded \"inotify\" extension, please install first.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Framework::$argv["interact"]) {
|
||||||
|
ZMBuf::$terminal = $r = STDIN;
|
||||||
|
Event::add($r, function () use ($r) {
|
||||||
|
$fget = fgets($r);
|
||||||
|
if ($fget === false) {
|
||||||
|
Event::del($r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$var = trim($fget);
|
||||||
|
try {
|
||||||
|
Terminal::executeCommand($var);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Console::error(zm_internal_errcode("E00025") . "Uncaught exception " . get_class($e) . ": " . $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")");
|
||||||
|
} catch (Error $e) {
|
||||||
|
Console::error(zm_internal_errcode("E00025") . "Uncaught error " . get_class($e) . ": " . $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addWatcher($maindir, $fd) {
|
private function addWatcher($maindir, $fd) {
|
||||||
$dir = scandir($maindir);
|
$dir = scandir($maindir);
|
||||||
unset($dir[0], $dir[1]);
|
if ($dir[0] == ".") {
|
||||||
|
unset($dir[0], $dir[1]);
|
||||||
|
}
|
||||||
foreach ($dir as $subdir) {
|
foreach ($dir as $subdir) {
|
||||||
if (is_dir($maindir . "/" . $subdir)) {
|
if (is_dir($maindir . "/" . $subdir)) {
|
||||||
Console::debug("添加监听目录:" . $maindir . "/" . $subdir);
|
Console::debug("添加监听目录:" . $maindir . "/" . $subdir);
|
||||||
|
|||||||
@@ -65,11 +65,11 @@ class OnTask implements SwooleEvent
|
|||||||
$dispatcher->dispatchEvents();
|
$dispatcher->dispatchEvents();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught exception " . get_class($e) . " when calling \"task\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00026") . "Uncaught exception " . get_class($e) . " when calling \"task\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught " . get_class($e) . " when calling \"task\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00026") . "Uncaught " . get_class($e) . " when calling \"task\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use Swoole\Database\PDOConfig;
|
|||||||
use Swoole\Database\PDOPool;
|
use Swoole\Database\PDOPool;
|
||||||
use Swoole\Process;
|
use Swoole\Process;
|
||||||
use Swoole\Server;
|
use Swoole\Server;
|
||||||
use Swoole\Timer;
|
|
||||||
use ZM\Annotation\AnnotationParser;
|
use ZM\Annotation\AnnotationParser;
|
||||||
use ZM\Annotation\Swoole\OnStart;
|
use ZM\Annotation\Swoole\OnStart;
|
||||||
use ZM\Annotation\Swoole\OnSwooleEvent;
|
use ZM\Annotation\Swoole\OnSwooleEvent;
|
||||||
@@ -26,13 +25,14 @@ use ZM\Event\EventDispatcher;
|
|||||||
use ZM\Event\EventManager;
|
use ZM\Event\EventManager;
|
||||||
use ZM\Event\SwooleEvent;
|
use ZM\Event\SwooleEvent;
|
||||||
use ZM\Exception\DbException;
|
use ZM\Exception\DbException;
|
||||||
|
use ZM\Exception\ZMException;
|
||||||
use ZM\Framework;
|
use ZM\Framework;
|
||||||
use ZM\Module\QQBot;
|
use ZM\Module\QQBot;
|
||||||
use ZM\Store\LightCacheInside;
|
use ZM\Store\LightCacheInside;
|
||||||
use ZM\Store\MySQL\SqlPoolStorage;
|
use ZM\Store\MySQL\SqlPoolStorage;
|
||||||
use ZM\Store\Redis\ZMRedisPool;
|
use ZM\Store\Redis\ZMRedisPool;
|
||||||
use ZM\Utils\DataProvider;
|
use ZM\Utils\DataProvider;
|
||||||
use ZM\Utils\ProcessManager;
|
use ZM\Utils\SignalListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class OnWorkerStart
|
* Class OnWorkerStart
|
||||||
@@ -43,18 +43,10 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
{
|
{
|
||||||
public function onCall(Server $server, $worker_id) {
|
public function onCall(Server $server, $worker_id) {
|
||||||
if (!Framework::$argv["disable-safe-exit"]) {
|
if (!Framework::$argv["disable-safe-exit"]) {
|
||||||
Process::signal(SIGINT, function () use ($worker_id, $server) {
|
SignalListener::signalWorker($server, $worker_id);
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
unset(Context::$context[Coroutine::getCid()]);
|
unset(Context::$context[Coroutine::getCid()]);
|
||||||
if ($server->taskworker === false) {
|
if ($server->taskworker === false) {
|
||||||
if (!Framework::$argv["disable-safe-exit"]) {
|
|
||||||
Process::signal(SIGUSR1, function () use ($worker_id) {
|
|
||||||
Timer::clearAll();
|
|
||||||
ProcessManager::resumeAllWorkerCoroutines();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
zm_atomic("_#worker_" . $worker_id)->set($server->worker_pid);
|
zm_atomic("_#worker_" . $worker_id)->set($server->worker_pid);
|
||||||
if (LightCacheInside::get("wait_api", "wait_api") !== null) {
|
if (LightCacheInside::get("wait_api", "wait_api") !== null) {
|
||||||
LightCacheInside::unset("wait_api", "wait_api");
|
LightCacheInside::unset("wait_api", "wait_api");
|
||||||
@@ -63,7 +55,8 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
register_shutdown_function(function () use ($server) {
|
register_shutdown_function(function () use ($server) {
|
||||||
$error = error_get_last();
|
$error = error_get_last();
|
||||||
if (($error["type"] ?? -1) != 0) {
|
if (($error["type"] ?? -1) != 0) {
|
||||||
Console::error("Internal fatal error: " . $error["message"] . " at " . $error["file"] . "({$error["line"]})");
|
Console::error(zm_internal_errcode("E00027") . "Internal fatal error: " . $error["message"] . " at " . $error["file"] . "({$error["line"]})");
|
||||||
|
zm_dump($error);
|
||||||
}
|
}
|
||||||
//DataProvider::saveBuffer();
|
//DataProvider::saveBuffer();
|
||||||
/** @var Server $server */
|
/** @var Server $server */
|
||||||
@@ -71,7 +64,7 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
else server()->shutdown();
|
else server()->shutdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
Console::verbose("Worker #{$server->worker_id} 启动中");
|
Console::verbose("Worker #{$server->worker_id} starting");
|
||||||
Framework::$server = $server;
|
Framework::$server = $server;
|
||||||
//ZMBuf::resetCache(); //清空变量缓存
|
//ZMBuf::resetCache(); //清空变量缓存
|
||||||
//ZMBuf::set("wait_start", []); //添加队列,在workerStart运行完成前先让其他协程等待执行
|
//ZMBuf::set("wait_start", []); //添加队列,在workerStart运行完成前先让其他协程等待执行
|
||||||
@@ -90,12 +83,12 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
phpinfo(); //这个phpinfo是有用的,不能删除
|
phpinfo(); //这个phpinfo是有用的,不能删除
|
||||||
$str = ob_get_clean();
|
$str = ob_get_clean();
|
||||||
$str = explode("\n", $str);
|
$str = explode("\n", $str);
|
||||||
foreach ($str as $k => $v) {
|
foreach ($str as $v) {
|
||||||
$v = trim($v);
|
$v = trim($v);
|
||||||
if ($v == "") continue;
|
if ($v == "") continue;
|
||||||
if (mb_strpos($v, "API Extensions") === false) continue;
|
if (mb_strpos($v, "API Extensions") === false) continue;
|
||||||
if (mb_strpos($v, "pdo_mysql") === false) {
|
if (mb_strpos($v, "pdo_mysql") === false) {
|
||||||
throw new DbException("未安装 mysqlnd php-mysql扩展。");
|
throw new DbException(zm_internal_errcode("E00028") . "未安装 mysqlnd php-mysql扩展。");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$sql = ZMConfig::get("global", "sql_config");
|
$sql = ZMConfig::get("global", "sql_config");
|
||||||
@@ -115,7 +108,7 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
// 开箱即用的Redis
|
// 开箱即用的Redis
|
||||||
$redis = ZMConfig::get("global", "redis_config");
|
$redis = ZMConfig::get("global", "redis_config");
|
||||||
if ($redis !== null && $redis["host"] != "") {
|
if ($redis !== null && $redis["host"] != "") {
|
||||||
if (!extension_loaded("redis")) Console::error("Can not find redis extension.\n");
|
if (!extension_loaded("redis")) Console::error(zm_internal_errcode("E00029") . "Can not find redis extension.\n");
|
||||||
else ZMRedisPool::init($redis);
|
else ZMRedisPool::init($redis);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,11 +129,11 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
Console::success("Worker #" . $worker_id . " started");
|
Console::success("Worker #" . $worker_id . " started");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Console::error("Worker加载出错!停止服务!");
|
Console::error("Worker加载出错!停止服务!");
|
||||||
Console::error($e->getMessage() . "\n" . $e->getTraceAsString());
|
Console::error(zm_internal_errcode("E00030") . $e->getMessage() . "\n" . $e->getTraceAsString());
|
||||||
Process::kill($server->master_pid, SIGTERM);
|
Process::kill($server->master_pid, SIGTERM);
|
||||||
return;
|
return;
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
Console::error("PHP Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
|
Console::error(zm_internal_errcode("E00030") . "PHP Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
|
||||||
Console::error("Maybe it caused by your own code if in your own Module directory.");
|
Console::error("Maybe it caused by your own code if in your own Module directory.");
|
||||||
Console::log($e->getTraceAsString(), 'gray');
|
Console::log($e->getTraceAsString(), 'gray');
|
||||||
Process::kill($server->master_pid, SIGTERM);
|
Process::kill($server->master_pid, SIGTERM);
|
||||||
@@ -153,11 +146,11 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
Console::success("TaskWorker #" . $server->worker_id . " started");
|
Console::success("TaskWorker #" . $server->worker_id . " started");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Console::error("Worker加载出错!停止服务!");
|
Console::error("Worker加载出错!停止服务!");
|
||||||
Console::error($e->getMessage() . "\n" . $e->getTraceAsString());
|
Console::error(zm_internal_errcode("E00030") . $e->getMessage() . "\n" . $e->getTraceAsString());
|
||||||
Process::kill($server->master_pid, SIGTERM);
|
Process::kill($server->master_pid, SIGTERM);
|
||||||
return;
|
return;
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
Console::error("PHP Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
|
Console::error(zm_internal_errcode("E00030") . "PHP Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
|
||||||
Console::error("Maybe it caused by your own code if in your own Module directory.");
|
Console::error("Maybe it caused by your own code if in your own Module directory.");
|
||||||
Console::log($e->getTraceAsString(), 'gray');
|
Console::log($e->getTraceAsString(), 'gray');
|
||||||
Process::kill($server->master_pid, SIGTERM);
|
Process::kill($server->master_pid, SIGTERM);
|
||||||
@@ -189,15 +182,13 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
//加载各个模块的注解类,以及反射
|
//加载各个模块的注解类,以及反射
|
||||||
Console::debug("检索Module中");
|
Console::debug("检索Module中");
|
||||||
$parser = new AnnotationParser();
|
$parser = new AnnotationParser();
|
||||||
$path = DataProvider::getWorkingDir() . "/src/";
|
$composer = json_decode(file_get_contents(DataProvider::getSourceRootDir() . "/composer.json"), true);
|
||||||
$dir = scandir($path);
|
foreach ($composer["autoload"]["psr-4"] as $k => $v) {
|
||||||
unset($dir[0], $dir[1]);
|
if (is_dir(DataProvider::getSourceRootDir() . "/" . $v)) {
|
||||||
$composer = json_decode(file_get_contents(DataProvider::getWorkingDir() . "/composer.json"), true);
|
if (in_array(trim($k, "\\") . "\\", $composer["extra"]["exclude_annotate"] ?? [])) continue;
|
||||||
foreach ($dir as $v) {
|
if (trim($k, "\\") == "ZM") continue;
|
||||||
if (is_dir($path . "/" . $v) && isset($composer["autoload"]["psr-4"][$v . "\\"]) && !in_array($composer["autoload"]["psr-4"][$v . "\\"], $composer["extra"]["exclude_annotate"] ?? [])) {
|
if (\server()->worker_id == 0) Console::verbose("Add " . $v . ":$k to register path");
|
||||||
if (\server()->worker_id == 0)
|
$parser->addRegisterPath(DataProvider::getSourceRootDir() . "/" . $v . "/", trim($k, "\\"));
|
||||||
Console::verbose("Add " . $v . " to register path");
|
|
||||||
$parser->addRegisterPath(DataProvider::getWorkingDir() . "/src/" . $v . "/", $v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$parser->registerMods();
|
$parser->registerMods();
|
||||||
@@ -207,7 +198,7 @@ class OnWorkerStart implements SwooleEvent
|
|||||||
Console::debug("加载自定义上下文中...");
|
Console::debug("加载自定义上下文中...");
|
||||||
$context_class = ZMConfig::get("global", "context_class");
|
$context_class = ZMConfig::get("global", "context_class");
|
||||||
if (!is_a($context_class, ContextInterface::class, true)) {
|
if (!is_a($context_class, ContextInterface::class, true)) {
|
||||||
throw new Exception("Context class must implemented from ContextInterface!");
|
throw new ZMException(zm_internal_errcode("E00032") ."Context class must implemented from ContextInterface!");
|
||||||
}
|
}
|
||||||
|
|
||||||
//加载插件
|
//加载插件
|
||||||
|
|||||||
@@ -4,7 +4,11 @@
|
|||||||
namespace ZM\Exception;
|
namespace ZM\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
class DbException extends ZMException
|
class DbException extends ZMException
|
||||||
{
|
{
|
||||||
|
public function __construct($message = "", $code = 0, Throwable $previous = null) {
|
||||||
|
parent::__construct(zm_internal_errcode("E00043") . $message, $code, $previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/ZM/Exception/ExceptionHandler.php
Normal file
15
src/ZM/Exception/ExceptionHandler.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这里放所有框架内部的异常处理方法
|
||||||
|
* Class ExceptionHandler
|
||||||
|
* @package ZM\Exception
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
class ExceptionHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
14
src/ZM/Exception/ModulePackException.php
Normal file
14
src/ZM/Exception/ModulePackException.php
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ModulePackException extends ZMException
|
||||||
|
{
|
||||||
|
public function __construct($message = "", $code = 0, Throwable $previous = null) {
|
||||||
|
parent::__construct(zm_internal_errcode("E00044") . $message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,11 @@
|
|||||||
namespace ZM\Exception;
|
namespace ZM\Exception;
|
||||||
|
|
||||||
|
|
||||||
class NotInitializedException extends ZMException
|
use Throwable;
|
||||||
{
|
|
||||||
|
|
||||||
|
class NotInitializedException extends RedisException
|
||||||
|
{
|
||||||
|
public function __construct($message = "", $code = 0, Throwable $previous = null) {
|
||||||
|
parent::__construct(zm_internal_errcode("E00046") . $message, $code, $previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
src/ZM/Exception/RedisException.php
Normal file
9
src/ZM/Exception/RedisException.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class RedisException extends ZMException
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -14,6 +14,6 @@ use Throwable;
|
|||||||
class RobotNotFoundException extends ZMException
|
class RobotNotFoundException extends ZMException
|
||||||
{
|
{
|
||||||
public function __construct($message = "", $code = 0, Throwable $previous = null) {
|
public function __construct($message = "", $code = 0, Throwable $previous = null) {
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct(zm_internal_errcode("E00037") . $message, $code, $previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,11 @@
|
|||||||
|
|
||||||
namespace ZM;
|
namespace ZM;
|
||||||
|
|
||||||
|
|
||||||
use Doctrine\Common\Annotations\AnnotationReader;
|
use Doctrine\Common\Annotations\AnnotationReader;
|
||||||
use Error;
|
use Error;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Swoole\Event;
|
|
||||||
use Swoole\Process;
|
|
||||||
use Swoole\Server\Port;
|
use Swoole\Server\Port;
|
||||||
use ZM\Annotation\Swoole\OnSetup;
|
use Throwable;
|
||||||
use ZM\Config\ZMConfig;
|
use ZM\Config\ZMConfig;
|
||||||
use ZM\ConnectionManager\ManagerGM;
|
use ZM\ConnectionManager\ManagerGM;
|
||||||
use ZM\Console\TermColor;
|
use ZM\Console\TermColor;
|
||||||
@@ -21,7 +18,6 @@ use ZM\Store\ZMAtomic;
|
|||||||
use ZM\Utils\DataProvider;
|
use ZM\Utils\DataProvider;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
use ReflectionMethod;
|
|
||||||
use Swoole\Runtime;
|
use Swoole\Runtime;
|
||||||
use Swoole\WebSocket\Server;
|
use Swoole\WebSocket\Server;
|
||||||
use ZM\Annotation\Swoole\SwooleHandler;
|
use ZM\Annotation\Swoole\SwooleHandler;
|
||||||
@@ -47,17 +43,19 @@ class Framework
|
|||||||
* @var array|bool|mixed|null
|
* @var array|bool|mixed|null
|
||||||
*/
|
*/
|
||||||
private $server_set;
|
private $server_set;
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $setup_events = [];
|
||||||
|
|
||||||
/** @noinspection PhpUnusedParameterInspection */
|
|
||||||
public function __construct($args = []) {
|
public function __construct($args = []) {
|
||||||
$tty_width = $this->getTtyWidth();
|
$tty_width = $this->getTtyWidth();
|
||||||
|
|
||||||
self::$argv = $args;
|
self::$argv = $args;
|
||||||
|
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||||
ZMConfig::setDirectory(DataProvider::getWorkingDir() . '/config');
|
|
||||||
ZMConfig::setEnv($args["env"] ?? "");
|
ZMConfig::setEnv($args["env"] ?? "");
|
||||||
if (ZMConfig::get("global") === false) {
|
if (ZMConfig::get("global") === false) {
|
||||||
die ("Global config load failed: " . ZMConfig::$last_error . "\nPlease init first!\n");
|
die (zm_internal_errcode("E00007") . "Global config load failed: " . ZMConfig::$last_error . "\nPlease init first!\nSee: https://github.com/zhamao-robot/zhamao-framework/issues/37\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//定义常量
|
//定义常量
|
||||||
@@ -80,9 +78,10 @@ class Framework
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
} catch (ConnectionManager\TableException $e) {
|
} catch (ConnectionManager\TableException $e) {
|
||||||
die($e->getMessage());
|
die(zm_internal_errcode("E00008") . $e->getMessage());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Console::init(
|
Console::init(
|
||||||
ZMConfig::get("global", "info_level") ?? 2,
|
ZMConfig::get("global", "info_level") ?? 2,
|
||||||
self::$server,
|
self::$server,
|
||||||
@@ -97,13 +96,18 @@ class Framework
|
|||||||
$this->server_set["log_level"] = SWOOLE_LOG_DEBUG;
|
$this->server_set["log_level"] = SWOOLE_LOG_DEBUG;
|
||||||
$add_port = ZMConfig::get("global", "remote_terminal")["status"] ?? false;
|
$add_port = ZMConfig::get("global", "remote_terminal")["status"] ?? false;
|
||||||
|
|
||||||
|
$this->loadServerEvents();
|
||||||
|
|
||||||
$this->parseCliArgs(self::$argv, $add_port);
|
$this->parseCliArgs(self::$argv, $add_port);
|
||||||
|
|
||||||
if (!isset($this->server_set["max_wait_time"])) {
|
if (!isset($this->server_set["max_wait_time"])) {
|
||||||
$this->server_set["max_wait_time"] = 5;
|
$this->server_set["max_wait_time"] = 5;
|
||||||
}
|
}
|
||||||
$worker = $this->server_set["worker_num"] ?? swoole_cpu_num();
|
$worker = $this->server_set["worker_num"] ?? swoole_cpu_num();
|
||||||
define("ZM_WORKER_NUM", $worker);
|
define("ZM_WORKER_NUM", $worker);
|
||||||
|
|
||||||
ZMAtomic::init();
|
ZMAtomic::init();
|
||||||
|
|
||||||
// 打印初始信息
|
// 打印初始信息
|
||||||
$out["listen"] = ZMConfig::get("global", "host") . ":" . ZMConfig::get("global", "port");
|
$out["listen"] = ZMConfig::get("global", "host") . ":" . ZMConfig::get("global", "port");
|
||||||
if (!isset($this->server_set["worker_num"])) $out["worker"] = swoole_cpu_num() . " (auto)";
|
if (!isset($this->server_set["worker_num"])) $out["worker"] = swoole_cpu_num() . " (auto)";
|
||||||
@@ -116,6 +120,9 @@ class Framework
|
|||||||
if (isset($this->server_set["task_worker_num"])) {
|
if (isset($this->server_set["task_worker_num"])) {
|
||||||
$out["task_worker"] = $this->server_set["task_worker_num"];
|
$out["task_worker"] = $this->server_set["task_worker_num"];
|
||||||
}
|
}
|
||||||
|
if (!isset($this->server_set["pid_file"])) {
|
||||||
|
$this->server_set["pid_file"] = ZMConfig::get("crash_dir") . ".zm.pid";
|
||||||
|
}
|
||||||
if (ZMConfig::get("global", "sql_config")["sql_host"] !== "") {
|
if (ZMConfig::get("global", "sql_config")["sql_host"] !== "") {
|
||||||
$conf = ZMConfig::get("global", "sql_config");
|
$conf = ZMConfig::get("global", "sql_config");
|
||||||
$out["mysql_pool"] = $conf["sql_database"] . "@" . $conf["sql_host"] . ":" . $conf["sql_port"];
|
$out["mysql_pool"] = $conf["sql_database"] . "@" . $conf["sql_host"] . ":" . $conf["sql_port"];
|
||||||
@@ -141,6 +148,8 @@ class Framework
|
|||||||
if ($args["preview"]) {
|
if ($args["preview"]) {
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
self::$server = new Server(ZMConfig::get("global", "host"), ZMConfig::get("global", "port"));
|
self::$server = new Server(ZMConfig::get("global", "host"), ZMConfig::get("global", "port"));
|
||||||
|
|
||||||
if ($add_port) {
|
if ($add_port) {
|
||||||
@@ -196,11 +205,11 @@ class Framework
|
|||||||
Terminal::executeCommand(trim($data));
|
Terminal::executeCommand(trim($data));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught exception " . get_class($e) . " when calling \"open\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00009") . "Uncaught exception " . get_class($e) . " when calling \"open\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught " . get_class($e) . " when calling \"open\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00009") . "Uncaught " . get_class($e) . " when calling \"open\": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,11 +233,11 @@ class Framework
|
|||||||
// 注册 Swoole Server 的事件
|
// 注册 Swoole Server 的事件
|
||||||
$this->registerServerEvents();
|
$this->registerServerEvents();
|
||||||
$r = ZMConfig::get("global", "light_cache") ?? [
|
$r = ZMConfig::get("global", "light_cache") ?? [
|
||||||
"size" => 1024,
|
'size' => 512, //最多允许储存的条数(需要2的倍数)
|
||||||
"max_strlen" => 8192,
|
'max_strlen' => 32768, //单行字符串最大长度(需要2的倍数)
|
||||||
"hash_conflict_proportion" => 0.6,
|
'hash_conflict_proportion' => 0.6, //Hash冲突率(越大越好,但是需要的内存更多)
|
||||||
"persistence_path" => realpath(DataProvider::getDataFolder() . "_cache.json"),
|
'persistence_path' => DataProvider::getDataFolder() . '_cache.json',
|
||||||
"auto_save_interval" => 900
|
'auto_save_interval' => 900
|
||||||
];
|
];
|
||||||
LightCache::init($r);
|
LightCache::init($r);
|
||||||
LightCacheInside::init();
|
LightCacheInside::init();
|
||||||
@@ -269,15 +278,15 @@ class Framework
|
|||||||
}, E_ALL | E_STRICT);
|
}, E_ALL | E_STRICT);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Console::error("Framework初始化出现错误,请检查!");
|
Console::error("Framework初始化出现错误,请检查!");
|
||||||
Console::error($e->getMessage());
|
Console::error(zm_internal_errcode("E00010") . $e->getMessage());
|
||||||
Console::debug($e);
|
Console::debug($e);
|
||||||
die;
|
die;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function printMotd($tty_width) {
|
private static function printMotd($tty_width) {
|
||||||
if (file_exists(DataProvider::getWorkingDir() . "/config/motd.txt")) {
|
if (file_exists(DataProvider::getSourceRootDir() . "/config/motd.txt")) {
|
||||||
$motd = file_get_contents(DataProvider::getWorkingDir() . "/config/motd.txt");
|
$motd = file_get_contents(DataProvider::getSourceRootDir() . "/config/motd.txt");
|
||||||
} else {
|
} else {
|
||||||
$motd = file_get_contents(__DIR__ . "/../../config/motd.txt");
|
$motd = file_get_contents(__DIR__ . "/../../config/motd.txt");
|
||||||
}
|
}
|
||||||
@@ -290,10 +299,27 @@ class Framework
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function start() {
|
public function start() {
|
||||||
self::$loaded_files = get_included_files();
|
try {
|
||||||
self::$server->start();
|
self::$loaded_files = get_included_files();
|
||||||
zm_atomic("server_is_stopped")->set(1);
|
self::$server->start();
|
||||||
Console::log("zhamao-framework is stopped.");
|
zm_atomic("server_is_stopped")->set(1);
|
||||||
|
Console::log("zhamao-framework is stopped.");
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
die(zm_internal_errcode("E00011") . "Framework has an uncaught " . get_class($e) . ": " . $e->getMessage() . PHP_EOL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadServerEvents() {
|
||||||
|
$r = exec(PHP_BINARY . " " . DataProvider::getFrameworkRootDir() . "/src/ZM/script_setup_loader.php", $output, $result_code);
|
||||||
|
if ($result_code !== 0) {
|
||||||
|
Console::error("Parsing code error!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
$json = json_decode($r, true);
|
||||||
|
if (!is_array($json)) {
|
||||||
|
Console::warning(zm_internal_errcode("E00012") . "Parsing @SwooleHandler and @OnSetup error!");
|
||||||
|
}
|
||||||
|
$this->setup_events = $json;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,18 +329,13 @@ class Framework
|
|||||||
*/
|
*/
|
||||||
private function registerServerEvents() {
|
private function registerServerEvents() {
|
||||||
$reader = new AnnotationReader();
|
$reader = new AnnotationReader();
|
||||||
global $master_events;
|
$all = ZMUtil::getClassesPsr4(FRAMEWORK_ROOT_DIR . "/src/ZM/Event/SwooleEvent/", "ZM\\Event\\SwooleEvent");
|
||||||
$master_events = [
|
|
||||||
"setup" => [],
|
|
||||||
"event" => []
|
|
||||||
];
|
|
||||||
$all = getAllClasses(FRAMEWORK_ROOT_DIR . "/src/ZM/Event/SwooleEvent/", "ZM\\Event\\SwooleEvent");
|
|
||||||
foreach ($all as $v) {
|
foreach ($all as $v) {
|
||||||
$class = new $v();
|
$class = new $v();
|
||||||
$reflection_class = new ReflectionClass($class);
|
$reflection_class = new ReflectionClass($class);
|
||||||
$anno_class = $reader->getClassAnnotation($reflection_class, SwooleHandler::class);
|
$anno_class = $reader->getClassAnnotation($reflection_class, SwooleHandler::class);
|
||||||
if ($anno_class !== null) { // 类名形式的注解
|
if ($anno_class !== null) { // 类名形式的注解
|
||||||
$master_events["event"][]=[
|
$this->setup_events["event"][] = [
|
||||||
"class" => $v,
|
"class" => $v,
|
||||||
"method" => "onCall",
|
"method" => "onCall",
|
||||||
"event" => $anno_class->event
|
"event" => $anno_class->event
|
||||||
@@ -322,66 +343,14 @@ class Framework
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$base_path = DataProvider::getWorkingDir();
|
foreach (($this->setup_events["setup"] ?? []) as $v) {
|
||||||
$scan_paths = [];
|
|
||||||
$composer = json_decode(file_get_contents(DataProvider::getWorkingDir() . "/composer.json"), true);
|
|
||||||
foreach (($composer["autoload"]["psr-4"] ?? []) as $k => $v) {
|
|
||||||
if (is_dir($base_path."/".$v) && !in_array($v, $composer["extra"]["exclude_annotate"] ?? [])) {
|
|
||||||
$scan_paths[trim($k, "\\")]=realpath($base_path."/".$v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$all_event_class = [];
|
|
||||||
foreach($scan_paths as $namespace => $autoload_path) {
|
|
||||||
$all_event_class = array_merge($all_event_class, getAllClasses($autoload_path."/", $namespace));
|
|
||||||
}
|
|
||||||
$process = new Process(function(Process $process) use ($all_event_class) {
|
|
||||||
$reader = new AnnotationReader();
|
|
||||||
$event_list = [];
|
|
||||||
$setup_list = [];
|
|
||||||
foreach ($all_event_class as $v) {
|
|
||||||
$reflection_class = new ReflectionClass($v);
|
|
||||||
$methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC);
|
|
||||||
foreach ($methods as $vs) {
|
|
||||||
$method_annotations = $reader->getMethodAnnotations($vs);
|
|
||||||
if ($method_annotations != []) {
|
|
||||||
$annotation = $method_annotations[0];
|
|
||||||
if ($annotation instanceof SwooleHandler) {
|
|
||||||
$event_list[]=[
|
|
||||||
"class" => $v,
|
|
||||||
"method" => $vs->getName(),
|
|
||||||
"event" => $annotation->event
|
|
||||||
];
|
|
||||||
} elseif ($annotation instanceof OnSetup) {
|
|
||||||
$setup_list[]=[
|
|
||||||
"class" => $v,
|
|
||||||
"method" => $vs->getName()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$sock = $process->exportSocket();
|
|
||||||
$sock->send(json_encode(["setup" => $setup_list, "event" => $event_list]));
|
|
||||||
});
|
|
||||||
$process->start();
|
|
||||||
go(function() use ($process) {
|
|
||||||
$socket = $process->exportSocket();
|
|
||||||
global $master_events;
|
|
||||||
$obj = json_decode($socket->recv(), true);
|
|
||||||
if ($obj["setup"] != []) $master_events["setup"] = array_merge($master_events["setup"], $obj["setup"]);
|
|
||||||
if ($obj["event"] != []) $master_events["event"] = array_merge($master_events["event"], $obj["event"]);
|
|
||||||
});
|
|
||||||
Process::wait(true);
|
|
||||||
Event::wait();
|
|
||||||
|
|
||||||
foreach($master_events["setup"] as $k => $v) {
|
|
||||||
$c = ZMUtil::getModInstance($v["class"]);
|
$c = ZMUtil::getModInstance($v["class"]);
|
||||||
$method = $v["method"];
|
$method = $v["method"];
|
||||||
$c->$method();
|
$c->$method();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($master_events["event"] as $k => $v) {
|
foreach ($this->setup_events["event"] as $v) {
|
||||||
self::$server->on($v["event"], function (...$param) use ($k, $v) {
|
self::$server->on($v["event"], function (...$param) use ($v) {
|
||||||
ZMUtil::getModInstance($v["class"])->{$v["method"]}(...$param);
|
ZMUtil::getModInstance($v["class"])->{$v["method"]}(...$param);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -403,7 +372,7 @@ class Framework
|
|||||||
if (intval($y) >= 1 && intval($y) <= 1024) {
|
if (intval($y) >= 1 && intval($y) <= 1024) {
|
||||||
$this->server_set["worker_num"] = intval($y);
|
$this->server_set["worker_num"] = intval($y);
|
||||||
} else {
|
} else {
|
||||||
Console::warning("Invalid worker num! Turn to default value (" . ($this->server_set["worker_num"] ?? swoole_cpu_num()) . ")");
|
Console::warning(zm_internal_errcode("E00013") . "Invalid worker num! Turn to default value (" . ($this->server_set["worker_num"] ?? swoole_cpu_num()) . ")");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'task-worker-num':
|
case 'task-worker-num':
|
||||||
@@ -411,7 +380,7 @@ class Framework
|
|||||||
$this->server_set["task_worker_num"] = intval($y);
|
$this->server_set["task_worker_num"] = intval($y);
|
||||||
$this->server_set["task_enable_coroutine"] = true;
|
$this->server_set["task_enable_coroutine"] = true;
|
||||||
} else {
|
} else {
|
||||||
Console::warning("Invalid worker num! Turn to default value (0)");
|
Console::warning(zm_internal_errcode("E00013") . "Invalid worker num! Turn to default value (0)");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'disable-coroutine':
|
case 'disable-coroutine':
|
||||||
@@ -421,7 +390,7 @@ class Framework
|
|||||||
$coroutine_mode = false;
|
$coroutine_mode = false;
|
||||||
$terminal_id = null;
|
$terminal_id = null;
|
||||||
self::$argv["watch"] = true;
|
self::$argv["watch"] = true;
|
||||||
echo ("* You are in debug mode, do not use in production!\n");
|
echo("* You are in debug mode, do not use in production!\n");
|
||||||
break;
|
break;
|
||||||
case 'daemon':
|
case 'daemon':
|
||||||
$this->server_set["daemonize"] = 1;
|
$this->server_set["daemonize"] = 1;
|
||||||
@@ -463,7 +432,8 @@ class Framework
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($coroutine_mode) Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
|
$global_hook = ZMConfig::get("global", 'runtime')['swoole_coroutine_hook_flags'] ?? SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL);
|
||||||
|
if ($coroutine_mode && $global_hook === false) Runtime::enableCoroutine(true, $global_hook);
|
||||||
else Runtime::enableCoroutine(false, SWOOLE_HOOK_ALL);
|
else Runtime::enableCoroutine(false, SWOOLE_HOOK_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,7 +524,9 @@ class Framework
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function getTtyWidth(): string {
|
public static function getTtyWidth(): string {
|
||||||
return explode(" ", trim(exec("stty size")))[1];
|
$size = exec("stty size");
|
||||||
|
if (empty($size)) return 65;
|
||||||
|
return explode(" ", trim($size))[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function loadFrameworkState() {
|
public static function loadFrameworkState() {
|
||||||
|
|||||||
@@ -3,58 +3,12 @@
|
|||||||
|
|
||||||
namespace ZM\Http;
|
namespace ZM\Http;
|
||||||
|
|
||||||
|
/**
|
||||||
use Symfony\Component\Routing\Route;
|
* 为了兼容,豁出去了(2.5),此兼容类
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
* Class RouteManager
|
||||||
use ZM\Annotation\Http\Controller;
|
* @package ZM\Http
|
||||||
use ZM\Annotation\Http\RequestMapping;
|
* @deprecated
|
||||||
use ZM\Console\Console;
|
*/
|
||||||
use ZM\Store\LightCacheInside;
|
class RouteManager extends \ZM\Utils\Manager\RouteManager
|
||||||
|
|
||||||
class RouteManager
|
|
||||||
{
|
{
|
||||||
/** @var null|RouteCollection */
|
|
||||||
public static $routes = null;
|
|
||||||
|
|
||||||
public static function importRouteByAnnotation(RequestMapping $vss, $method, $class, $methods_annotations) {
|
|
||||||
if (self::$routes === null) self::$routes = new RouteCollection();
|
|
||||||
|
|
||||||
// 拿到所属方法的类上面有没有控制器的注解
|
|
||||||
$prefix = '';
|
|
||||||
foreach ($methods_annotations as $annotation) {
|
|
||||||
if ($annotation instanceof Controller) {
|
|
||||||
$prefix = $annotation->prefix;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$tail = trim($vss->route, "/");
|
|
||||||
$route_name = $prefix . ($tail === "" ? "" : "/") . $tail;
|
|
||||||
Console::debug("添加路由:" . $route_name);
|
|
||||||
$route = new Route($route_name, ['_class' => $class, '_method' => $method]);
|
|
||||||
$route->setMethods($vss->request_method);
|
|
||||||
|
|
||||||
self::$routes->add(md5($route_name), $route);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function addStaticFileRoute($route, $path) {
|
|
||||||
$tail = trim($route, "/");
|
|
||||||
$route_name = ($tail === "" ? "" : "/") . $tail . "/{filename}";
|
|
||||||
Console::debug("添加静态文件路由:" . $route_name);
|
|
||||||
$route = new Route($route_name, ['_class' => RouteManager::class, '_method' => "onStaticRoute"]);
|
|
||||||
//echo $path.PHP_EOL;
|
|
||||||
LightCacheInside::set("static_route", $route->getPath(), $path);
|
|
||||||
|
|
||||||
self::$routes->add(md5($route_name), $route);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onStaticRoute($params) {
|
|
||||||
$route_path = self::$routes->get($params["_route"])->getPath();
|
|
||||||
if(($path = LightCacheInside::get("static_route", $route_path)) === null) {
|
|
||||||
ctx()->getResponse()->endWithStatus(404);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
unset($params["_route"]);
|
|
||||||
$obj = array_shift($params);
|
|
||||||
return new StaticFileHandler($obj, $path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
206
src/ZM/Module/ModulePacker.php
Normal file
206
src/ZM/Module/ModulePacker.php
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Module;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Phar;
|
||||||
|
use ZM\Config\ZMConfig;
|
||||||
|
use ZM\Console\Console;
|
||||||
|
use ZM\Exception\ModulePackException;
|
||||||
|
use ZM\Exception\ZMException;
|
||||||
|
use ZM\Store\LightCache;
|
||||||
|
use ZM\Utils\DataProvider;
|
||||||
|
use ZM\Utils\ZMUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模块构造器
|
||||||
|
* Class ModulePacker
|
||||||
|
* @package ZM\Module
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
class ModulePacker
|
||||||
|
{
|
||||||
|
const ZM_MODULE_PACKER_VERSION = '1.0';
|
||||||
|
/** @var array $module */
|
||||||
|
private $module = [];
|
||||||
|
/** @var bool $override */
|
||||||
|
private $override = false;
|
||||||
|
/** @var string $output_path */
|
||||||
|
private $output_path = '';
|
||||||
|
/** @var string $filename */
|
||||||
|
private $filename = '';
|
||||||
|
/** @var Phar $phar */
|
||||||
|
private $phar;
|
||||||
|
/** @var null|array $module_config */
|
||||||
|
private $module_config = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ModulePackException
|
||||||
|
*/
|
||||||
|
public function __construct(array $module) {
|
||||||
|
if (ini_get('phar.readonly') == '1') {
|
||||||
|
throw new ModulePackException('请先在 php.ini 中设置 `phar.readonly = Off` 后再打包模块!');
|
||||||
|
}
|
||||||
|
if (!isset($module['name'], $module['module-path'], $module['namespace'])) {
|
||||||
|
throw new ModulePackException('模块打包需要至少传入name、module-path、namespace三个参数!');
|
||||||
|
}
|
||||||
|
$this->module = $module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置输出文件夹
|
||||||
|
* @param $path
|
||||||
|
*/
|
||||||
|
public function setOutputPath($path) {
|
||||||
|
$this->output_path = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否覆盖
|
||||||
|
* @param bool $override
|
||||||
|
*/
|
||||||
|
public function setOverride(bool $override = true) {
|
||||||
|
$this->override = $override;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模块名字
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getName() {
|
||||||
|
return $this->module['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取打包的文件名绝对路径
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFileName(): string {
|
||||||
|
return $this->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打包模块
|
||||||
|
* @throws ZMException
|
||||||
|
*/
|
||||||
|
public function pack() {
|
||||||
|
$this->filename = $this->output_path . '/' . $this->module['name'];
|
||||||
|
if (isset($this->module['version'])) {
|
||||||
|
$this->filename .= '_' . $this->module['version'];
|
||||||
|
}
|
||||||
|
$this->filename .= '.phar';
|
||||||
|
if ($this->override) {
|
||||||
|
if (file_exists($this->filename)) {
|
||||||
|
Console::info('Overwriting ' . $this->filename);
|
||||||
|
unlink($this->filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->phar = new Phar($this->filename);
|
||||||
|
$this->phar->startBuffering();
|
||||||
|
Console::info('模块输出文件:' . $this->filename);
|
||||||
|
|
||||||
|
$this->addFiles(); //添加文件
|
||||||
|
$this->addLightCacheStore(); //保存light-cache-store指定的项
|
||||||
|
$this->addModuleConfig(); //生成module-config.json
|
||||||
|
$this->addEntry(); //生成模块的入口文件module_entry.php
|
||||||
|
|
||||||
|
$this->phar->stopBuffering();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addFiles() {
|
||||||
|
$file_list = DataProvider::scanDirFiles($this->module['module-path'], true, false);
|
||||||
|
foreach ($file_list as $v) {
|
||||||
|
$this->phar->addFile($v, $this->getRelativePath($v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRelativePath($path) {
|
||||||
|
return str_replace(realpath(DataProvider::getSourceRootDir()) . '/', '', realpath($path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generatePharAutoload(): array {
|
||||||
|
return ZMUtil::getClassesPsr4($this->module['module-path'], $this->module['namespace'], null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getComposerAutoloadItems(): array {
|
||||||
|
$composer = json_decode(file_get_contents(DataProvider::getSourceRootDir() . '/composer.json'), true);
|
||||||
|
$path = self::getRelativePath($this->module['module-path']);
|
||||||
|
$item = [];
|
||||||
|
foreach (($composer['autoload']['psr-4'] ?? []) as $k => $v) {
|
||||||
|
if (strpos($path, $v) === 0) {
|
||||||
|
$item['psr-4'][$k] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (($composer['autoload']['files'] ?? []) as $v) {
|
||||||
|
if (strcmp($path, $v) === 0) {
|
||||||
|
$item['files'][] = $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ZMException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function addLightCacheStore() {
|
||||||
|
if (isset($this->module['light-cache-store'])) {
|
||||||
|
$store = [];
|
||||||
|
$r = ZMConfig::get('global', 'light_cache') ?? [
|
||||||
|
'size' => 512, //最多允许储存的条数(需要2的倍数)
|
||||||
|
'max_strlen' => 32768, //单行字符串最大长度(需要2的倍数)
|
||||||
|
'hash_conflict_proportion' => 0.6, //Hash冲突率(越大越好,但是需要的内存更多)
|
||||||
|
'persistence_path' => DataProvider::getDataFolder() . '_cache.json',
|
||||||
|
'auto_save_interval' => 900
|
||||||
|
];
|
||||||
|
LightCache::init($r);
|
||||||
|
foreach ($this->module['light-cache-store'] as $v) {
|
||||||
|
$r = LightCache::get($v);
|
||||||
|
if ($r === null) {
|
||||||
|
Console::warning(zm_internal_errcode("E00045") . 'LightCache 项:`$v` 不存在或值为null,无法为其保存。');
|
||||||
|
} else {
|
||||||
|
$store[$v] = $r;
|
||||||
|
Console::info('打包LightCache持久化项:' . $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->phar->addFromString('light_cache_store.json', json_encode($store, 128 | 256));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addModuleConfig() {
|
||||||
|
$stub_values = [
|
||||||
|
'zm-module' => true,
|
||||||
|
'generated-id' => sha1(strval(microtime(true))),
|
||||||
|
'module-packer-version' => self::ZM_MODULE_PACKER_VERSION,
|
||||||
|
'module-root-path' => $this->getRelativePath($this->module['module-path']),
|
||||||
|
'namespace' => $this->module['namespace'],
|
||||||
|
'autoload-psr-4' => $this->generatePharAutoload(),
|
||||||
|
'unpack' => [
|
||||||
|
'composer-autoload-items' => $this->getComposerAutoloadItems(),
|
||||||
|
'global-config-override' => !empty($this->module['global-config-override'] ?? []) ? $this->module['global-config-override'] : false
|
||||||
|
],
|
||||||
|
'allow-hotload' => empty($this->module['global-config-override'] ?? []) && !isset($this->module['depends'])
|
||||||
|
];
|
||||||
|
$this->phar->addFromString('zmplugin.json', json_encode($stub_values, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||||
|
$this->module_config = $stub_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addEntry() {
|
||||||
|
$stub_replace = [
|
||||||
|
'generated_id' => $this->module_config['generated-id']
|
||||||
|
];
|
||||||
|
|
||||||
|
$stub_template = str_replace(
|
||||||
|
array_map(function ($x) {
|
||||||
|
return '__' . $x . '__';
|
||||||
|
}, array_keys($stub_replace)),
|
||||||
|
array_values($stub_replace),
|
||||||
|
file_get_contents(DataProvider::getFrameworkRootDir() . '/src/ZM/script_phar_stub.php')
|
||||||
|
);
|
||||||
|
$this->phar->addFromString('module_entry.php', $stub_template);
|
||||||
|
|
||||||
|
$this->phar->setStub($this->phar->createDefaultStub('module_entry.php'));
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/ZM/Module/ModuleUnpacker.php
Normal file
23
src/ZM/Module/ModuleUnpacker.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Module;
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleUnpacker
|
||||||
|
{
|
||||||
|
private $module;
|
||||||
|
|
||||||
|
public function __construct(array $module) {
|
||||||
|
$this->module = $module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解包模块
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function unpack(): array {
|
||||||
|
// TODO: 解包模块到src
|
||||||
|
return $this->module;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ use ZM\Console\Console;
|
|||||||
use ZM\Event\EventDispatcher;
|
use ZM\Event\EventDispatcher;
|
||||||
use ZM\Exception\ZMException;
|
use ZM\Exception\ZMException;
|
||||||
use ZM\Framework;
|
use ZM\Framework;
|
||||||
use ZM\Utils\ProcessManager;
|
use ZM\Utils\Manager\ProcessManager;
|
||||||
|
|
||||||
class LightCache
|
class LightCache
|
||||||
{
|
{
|
||||||
@@ -26,7 +26,6 @@ class LightCache
|
|||||||
* @param $config
|
* @param $config
|
||||||
* @return bool|mixed
|
* @return bool|mixed
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
* @noinspection PhpMissingReturnTypeInspection
|
|
||||||
*/
|
*/
|
||||||
public static function init($config) {
|
public static function init($config) {
|
||||||
self::$config = $config;
|
self::$config = $config;
|
||||||
@@ -44,17 +43,17 @@ class LightCache
|
|||||||
$write = self::set($k, $v);
|
$write = self::set($k, $v);
|
||||||
Console::verbose("Writing LightCache: " . $k);
|
Console::verbose("Writing LightCache: " . $k);
|
||||||
if ($write === false) {
|
if ($write === false) {
|
||||||
self::$last_error = '可能是由于 Hash 冲突过多导致动态空间无法分配内存';
|
self::$last_error = zm_internal_errcode("E00051") . '可能是由于 Hash 冲突过多导致动态空间无法分配内存';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
self::$last_error = '系统内存不足,申请失败';
|
self::$last_error = zm_internal_errcode("E00050") . '系统内存不足,申请失败';
|
||||||
} else {
|
} else {
|
||||||
$obj = Framework::loadFrameworkState();
|
$obj = Framework::loadFrameworkState();
|
||||||
foreach(($obj["expiring_light_cache"] ?? []) as $k => $v) {
|
foreach (($obj["expiring_light_cache"] ?? []) as $k => $v) {
|
||||||
$value = $v["value"];
|
$value = $v["value"];
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||||
@@ -87,7 +86,7 @@ class LightCache
|
|||||||
* @throws ZMException
|
* @throws ZMException
|
||||||
*/
|
*/
|
||||||
public static function get(string $key) {
|
public static function get(string $key) {
|
||||||
if (self::$kv_table === null) throw new ZMException("not initialized LightCache");
|
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache");
|
||||||
self::checkExpire($key);
|
self::checkExpire($key);
|
||||||
$r = self::$kv_table->get($key);
|
$r = self::$kv_table->get($key);
|
||||||
return $r === false ? null : self::parseGet($r);
|
return $r === false ? null : self::parseGet($r);
|
||||||
@@ -99,7 +98,7 @@ class LightCache
|
|||||||
* @throws ZMException
|
* @throws ZMException
|
||||||
*/
|
*/
|
||||||
public static function getExpire(string $key) {
|
public static function getExpire(string $key) {
|
||||||
if (self::$kv_table === null) throw new ZMException("not initialized LightCache");
|
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache");
|
||||||
self::checkExpire($key);
|
self::checkExpire($key);
|
||||||
$r = self::$kv_table->get($key, "expire");
|
$r = self::$kv_table->get($key, "expire");
|
||||||
return $r === false ? null : $r - time();
|
return $r === false ? null : $r - time();
|
||||||
@@ -112,7 +111,7 @@ class LightCache
|
|||||||
* @since 2.4.3
|
* @since 2.4.3
|
||||||
*/
|
*/
|
||||||
public static function getExpireTS(string $key) {
|
public static function getExpireTS(string $key) {
|
||||||
if (self::$kv_table === null) throw new ZMException("not initialized LightCache");
|
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache");
|
||||||
self::checkExpire($key);
|
self::checkExpire($key);
|
||||||
$r = self::$kv_table->get($key, "expire");
|
$r = self::$kv_table->get($key, "expire");
|
||||||
return $r === false ? null : $r;
|
return $r === false ? null : $r;
|
||||||
@@ -124,10 +123,9 @@ class LightCache
|
|||||||
* @param int $expire
|
* @param int $expire
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws ZMException
|
* @throws ZMException
|
||||||
* @noinspection PhpMissingReturnTypeInspection
|
|
||||||
*/
|
*/
|
||||||
public static function set(string $key, $value, int $expire = -1) {
|
public static function set(string $key, $value, int $expire = -1) {
|
||||||
if (self::$kv_table === null) throw new ZMException("not initialized LightCache");
|
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache");
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||||
if (strlen($value) >= self::$config["max_strlen"]) return false;
|
if (strlen($value) >= self::$config["max_strlen"]) return false;
|
||||||
@@ -140,7 +138,7 @@ class LightCache
|
|||||||
$data_type = "bool";
|
$data_type = "bool";
|
||||||
$value = json_encode($value);
|
$value = json_encode($value);
|
||||||
} else {
|
} else {
|
||||||
throw new ZMException("Only can set string, array and int");
|
throw new ZMException(zm_internal_errcode("E00049") . "Only can set string, array and int");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return self::$kv_table->set($key, [
|
return self::$kv_table->set($key, [
|
||||||
@@ -158,10 +156,9 @@ class LightCache
|
|||||||
* @param $value
|
* @param $value
|
||||||
* @return bool|mixed
|
* @return bool|mixed
|
||||||
* @throws ZMException
|
* @throws ZMException
|
||||||
* @noinspection PhpMissingReturnTypeInspection
|
|
||||||
*/
|
*/
|
||||||
public static function update(string $key, $value) {
|
public static function update(string $key, $value) {
|
||||||
if (self::$kv_table === null) throw new ZMException("not initialized LightCache.");
|
if (self::$kv_table === null) throw new ZMException(zm_internal_errcode("E00048") . "not initialized LightCache.");
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||||
if (strlen($value) >= self::$config["max_strlen"]) return false;
|
if (strlen($value) >= self::$config["max_strlen"]) return false;
|
||||||
@@ -171,7 +168,7 @@ class LightCache
|
|||||||
} elseif (is_int($value)) {
|
} elseif (is_int($value)) {
|
||||||
$data_type = "int";
|
$data_type = "int";
|
||||||
} else {
|
} else {
|
||||||
throw new ZMException("Only can set string, array and int");
|
throw new ZMException(zm_internal_errcode("E00048") . "Only can set string, array and int");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (self::$kv_table->get($key) === false) return false;
|
if (self::$kv_table->get($key) === false) return false;
|
||||||
|
|||||||
@@ -67,6 +67,6 @@ class LightCacheInside
|
|||||||
self::$kv_table[$name] = new Table($size, $conflict_proportion);
|
self::$kv_table[$name] = new Table($size, $conflict_proportion);
|
||||||
self::$kv_table[$name]->column("value", Table::TYPE_STRING, $str_size);
|
self::$kv_table[$name]->column("value", Table::TYPE_STRING, $str_size);
|
||||||
$r = self::$kv_table[$name]->create();
|
$r = self::$kv_table[$name]->create();
|
||||||
if ($r === false) throw new ZMException("内存不足,创建静态表失败!");
|
if ($r === false) throw new ZMException(zm_internal_errcode("E00050") . "内存不足,创建静态表失败!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class ZMRedisPool
|
|||||||
var_dump($r);
|
var_dump($r);
|
||||||
}
|
}
|
||||||
} catch (RedisException $e) {
|
} catch (RedisException $e) {
|
||||||
Console::error("Redis init failed! " . $e->getMessage());
|
Console::error(zm_internal_errcode("E00047") . "Redis init failed! " . $e->getMessage());
|
||||||
self::$pool = null;
|
self::$pool = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class ZMAtomic
|
|||||||
for ($i = 0; $i < 10; ++$i) {
|
for ($i = 0; $i < 10; ++$i) {
|
||||||
self::$atomics["_tmp_" . $i] = new Atomic(0);
|
self::$atomics["_tmp_" . $i] = new Atomic(0);
|
||||||
}
|
}
|
||||||
|
self::$atomics["ss"] = new Atomic(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
namespace ZM\Utils;
|
namespace ZM\Utils;
|
||||||
|
|
||||||
|
|
||||||
use Co;
|
use Swoole\Coroutine;
|
||||||
use ZM\Store\LightCacheInside;
|
use ZM\Store\LightCacheInside;
|
||||||
use ZM\Store\Lock\SpinLock;
|
use ZM\Store\Lock\SpinLock;
|
||||||
use ZM\Store\ZMAtomic;
|
use ZM\Store\ZMAtomic;
|
||||||
|
use ZM\Utils\Manager\ProcessManager;
|
||||||
|
|
||||||
class CoMessage
|
class CoMessage
|
||||||
{
|
{
|
||||||
@@ -16,10 +17,9 @@ class CoMessage
|
|||||||
* @param array $compare
|
* @param array $compare
|
||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @noinspection PhpMissingReturnTypeInspection
|
|
||||||
*/
|
*/
|
||||||
public static function yieldByWS(array $hang, array $compare, $timeout = 600) {
|
public static function yieldByWS(array $hang, array $compare, $timeout = 600) {
|
||||||
$cid = Co::getuid();
|
$cid = Coroutine::getuid();
|
||||||
$api_id = ZMAtomic::get("wait_msg_id")->add(1);
|
$api_id = ZMAtomic::get("wait_msg_id")->add(1);
|
||||||
$hang["compare"] = $compare;
|
$hang["compare"] = $compare;
|
||||||
$hang["coroutine"] = $cid;
|
$hang["coroutine"] = $cid;
|
||||||
@@ -33,10 +33,10 @@ class CoMessage
|
|||||||
$id = swoole_timer_after($timeout * 1000, function () use ($api_id) {
|
$id = swoole_timer_after($timeout * 1000, function () use ($api_id) {
|
||||||
$r = LightCacheInside::get("wait_api", "wait_api")[$api_id] ?? null;
|
$r = LightCacheInside::get("wait_api", "wait_api")[$api_id] ?? null;
|
||||||
if (is_array($r)) {
|
if (is_array($r)) {
|
||||||
Co::resume($r["coroutine"]);
|
Coroutine::resume($r["coroutine"]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Co::suspend();
|
Coroutine::suspend();
|
||||||
SpinLock::lock("wait_api");
|
SpinLock::lock("wait_api");
|
||||||
$sess = LightCacheInside::get("wait_api", "wait_api");
|
$sess = LightCacheInside::get("wait_api", "wait_api");
|
||||||
$result = $sess[$api_id]["result"] ?? null;
|
$result = $sess[$api_id]["result"] ?? null;
|
||||||
@@ -70,7 +70,7 @@ class CoMessage
|
|||||||
if ($all[$last]["worker_id"] != server()->worker_id) {
|
if ($all[$last]["worker_id"] != server()->worker_id) {
|
||||||
ProcessManager::sendActionToWorker($all[$last]["worker_id"], "resume_ws_message", $all[$last]);
|
ProcessManager::sendActionToWorker($all[$last]["worker_id"], "resume_ws_message", $all[$last]);
|
||||||
} else {
|
} else {
|
||||||
Co::resume($all[$last]["coroutine"]);
|
Coroutine::resume($all[$last]["coroutine"]);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ class CoroutinePool
|
|||||||
self::$sizes[$name] = $size;
|
self::$sizes[$name] = $size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getRunningCoroutineCount($name = "default") {
|
||||||
|
return count(self::$cids[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
private static function checkCids($name) {
|
private static function checkCids($name) {
|
||||||
if (in_array(Coroutine::getCid(), self::$cids[$name])) {
|
if (in_array(Coroutine::getCid(), self::$cids[$name])) {
|
||||||
$a = array_search(Coroutine::getCid(), self::$cids[$name]);
|
$a = array_search(Coroutine::getCid(), self::$cids[$name]);
|
||||||
|
|||||||
@@ -11,44 +11,139 @@ class DataProvider
|
|||||||
{
|
{
|
||||||
public static $buffer_list = [];
|
public static $buffer_list = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回资源目录
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public static function getResourceFolder(): string {
|
public static function getResourceFolder(): string {
|
||||||
return self::getWorkingDir() . '/resources/';
|
return self::getWorkingDir() . '/resources/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回工作目录,不带最右边文件夹的斜杠(/)
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
public static function getWorkingDir() {
|
public static function getWorkingDir() {
|
||||||
return WORKING_DIR;
|
return WORKING_DIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取框架所在根目录
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
|
public static function getFrameworkRootDir() {
|
||||||
|
return FRAMEWORK_ROOT_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取源码根目录,除Phar模式外均与工作目录相同
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
|
public static function getSourceRootDir() {
|
||||||
|
return defined("SOURCE_ROOT_DIR") ? SOURCE_ROOT_DIR : WORKING_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取框架反代链接
|
||||||
|
* @return array|false|mixed|null
|
||||||
|
*/
|
||||||
public static function getFrameworkLink() {
|
public static function getFrameworkLink() {
|
||||||
return ZMConfig::get("global", "http_reverse_link");
|
return ZMConfig::get("global", "http_reverse_link");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getDataFolder() {
|
/**
|
||||||
|
* 获取zm_data数据目录,如果二级目录不为空,则自动创建目录并返回
|
||||||
|
* @param string $second
|
||||||
|
* @return array|false|mixed|string|null
|
||||||
|
*/
|
||||||
|
public static function getDataFolder(string $second = '') {
|
||||||
|
if ($second !== '') {
|
||||||
|
@mkdir(ZM_DATA . $second);
|
||||||
|
if (!is_dir(ZM_DATA . $second)) return false;
|
||||||
|
return realpath(ZM_DATA . $second) . "/";
|
||||||
|
}
|
||||||
return ZM_DATA;
|
return ZM_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将变量保存在zm_data下的数据目录,传入数组
|
||||||
|
* @param $filename
|
||||||
|
* @param $file_array
|
||||||
|
* @return false|int
|
||||||
|
*/
|
||||||
public static function saveToJson($filename, $file_array) {
|
public static function saveToJson($filename, $file_array) {
|
||||||
$path = ZMConfig::get("global", "config_dir");
|
$path = ZMConfig::get("global", "config_dir");
|
||||||
$r = explode("/", $filename);
|
$r = explode("/", $filename);
|
||||||
if(count($r) == 2) {
|
if (count($r) == 2) {
|
||||||
$path = $path . $r[0]."/";
|
$path = $path . $r[0] . "/";
|
||||||
if(!is_dir($path)) mkdir($path);
|
if (!is_dir($path)) mkdir($path);
|
||||||
$name = $r[1];
|
$name = $r[1];
|
||||||
} elseif (count($r) != 1) {
|
} elseif (count($r) != 1) {
|
||||||
Console::warning("存储失败,文件名只能有一级目录");
|
Console::warning(zm_internal_errcode("E00057") . "存储失败,文件名只能有一级目录");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
$name = $r[0];
|
$name = $r[0];
|
||||||
}
|
}
|
||||||
return file_put_contents($path.$name.".json", json_encode($file_array, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
return file_put_contents($path . $name . ".json", json_encode($file_array, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从json加载变量到内存
|
||||||
|
* @param $filename
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
public static function loadFromJson($filename) {
|
public static function loadFromJson($filename) {
|
||||||
$path = ZMConfig::get("global", "config_dir");
|
$path = ZMConfig::get("global", "config_dir");
|
||||||
if(file_exists($path.$filename.".json")) {
|
if (file_exists($path . $filename . ".json")) {
|
||||||
return json_decode(file_get_contents($path.$filename.".json"), true);
|
return json_decode(file_get_contents($path . $filename . ".json"), true);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归或非递归扫描目录,可返回相对目录的文件列表或绝对目录的文件列表
|
||||||
|
* @param $dir
|
||||||
|
* @param bool $recursive
|
||||||
|
* @param bool|string $relative
|
||||||
|
* @return array|false
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
public static function scanDirFiles($dir, bool $recursive = true, $relative = false) {
|
||||||
|
$dir = rtrim($dir, "/");
|
||||||
|
if (!is_dir($dir)) return false;
|
||||||
|
$r = scandir($dir);
|
||||||
|
if ($r === false) return false;
|
||||||
|
$list = [];
|
||||||
|
if ($relative === true) {
|
||||||
|
$relative = $dir;
|
||||||
|
}
|
||||||
|
foreach ($r as $v) {
|
||||||
|
if ($v == "." || $v == "..") continue;
|
||||||
|
$sub_file = $dir . "/" . $v;
|
||||||
|
if (is_dir($sub_file) && $recursive) {
|
||||||
|
$list = array_merge($list, self::scanDirFiles($sub_file, $recursive, $relative));
|
||||||
|
} elseif (is_file($sub_file)) {
|
||||||
|
if (is_string($relative) && mb_strpos($sub_file, $relative) === 0) {
|
||||||
|
$list [] = ltrim(mb_substr($sub_file, mb_strlen($relative)), "/");
|
||||||
|
} elseif ($relative === false) {
|
||||||
|
$list[] = $sub_file;
|
||||||
|
} else {
|
||||||
|
Console::warning(zm_internal_errcode("E00058") . "Relative path is not generated: wrong base directory ($relative)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查路径是否为相对路径(根据第一个字符是否为"/"来判断)
|
||||||
|
* @param $path
|
||||||
|
* @return bool
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
public static function isRelativePath($path) {
|
||||||
|
return strlen($path) > 0 && $path[0] === '/';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
namespace ZM\Utils;
|
namespace ZM\Utils;
|
||||||
|
|
||||||
|
|
||||||
use Co;
|
use Swoole\Coroutine;
|
||||||
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
|
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
|
||||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||||
use Symfony\Component\Routing\Matcher\UrlMatcher;
|
use Symfony\Component\Routing\Matcher\UrlMatcher;
|
||||||
@@ -13,7 +13,7 @@ use Symfony\Component\Routing\RouteCollection;
|
|||||||
use ZM\Config\ZMConfig;
|
use ZM\Config\ZMConfig;
|
||||||
use ZM\Console\Console;
|
use ZM\Console\Console;
|
||||||
use ZM\Http\Response;
|
use ZM\Http\Response;
|
||||||
use ZM\Http\RouteManager;
|
use ZM\Utils\Manager\RouteManager;
|
||||||
|
|
||||||
class HttpUtil
|
class HttpUtil
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,7 @@ class HttpUtil
|
|||||||
|
|
||||||
public static function getHttpCodePage(int $http_code) {
|
public static function getHttpCodePage(int $http_code) {
|
||||||
if (isset(ZMConfig::get("global", "http_default_code_page")[$http_code])) {
|
if (isset(ZMConfig::get("global", "http_default_code_page")[$http_code])) {
|
||||||
return Co::readFile(DataProvider::getResourceFolder() . "html/" . ZMConfig::get("global", "http_default_code_page")[$http_code]);
|
return Coroutine::readFile(DataProvider::getResourceFolder() . "html/" . ZMConfig::get("global", "http_default_code_page")[$http_code]);
|
||||||
} else return null;
|
} else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
115
src/ZM/Utils/Manager/ModuleManager.php
Normal file
115
src/ZM/Utils/Manager/ModuleManager.php
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Utils\Manager;
|
||||||
|
|
||||||
|
|
||||||
|
use ZM\Console\Console;
|
||||||
|
use ZM\Exception\ModulePackException;
|
||||||
|
use ZM\Exception\ZMException;
|
||||||
|
use ZM\Module\ModulePacker;
|
||||||
|
use ZM\Module\ModuleUnpacker;
|
||||||
|
use ZM\Utils\DataProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模块管理器,负责打包解包模块
|
||||||
|
* Class ModuleManager
|
||||||
|
* @package ZM\Utils\Manager
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
class ModuleManager
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描src目录下的所有已经被标注的模块
|
||||||
|
* @return array
|
||||||
|
* @throws ZMException
|
||||||
|
*/
|
||||||
|
public static function getConfiguredModules(): array {
|
||||||
|
$dir = DataProvider::getSourceRootDir() . "/src/";
|
||||||
|
$ls = DataProvider::scanDirFiles($dir, true, true);
|
||||||
|
$modules = [];
|
||||||
|
foreach ($ls as $v) {
|
||||||
|
$pathinfo = pathinfo($v);
|
||||||
|
if ($pathinfo["basename"] == "zm.json") {
|
||||||
|
$json = json_decode(file_get_contents(realpath($dir . "/" . $v)), true);
|
||||||
|
if ($json === null) continue;
|
||||||
|
if (!isset($json["name"])) continue;
|
||||||
|
if ($pathinfo["dirname"] == ".") {
|
||||||
|
throw new ZMException(zm_internal_errcode("E00052") . "在/src/目录下不可以直接标记为模块(zm.json),因为命名空间不能为根空间!");
|
||||||
|
}
|
||||||
|
$json["module-path"] = realpath($dir . "/" . $pathinfo["dirname"]);
|
||||||
|
$json["namespace"] = str_replace("/", "\\", $pathinfo["dirname"]);
|
||||||
|
if (isset($modules[$json["name"]])) {
|
||||||
|
throw new ZMException(zm_internal_errcode("E00053") . "重名模块:" . $json["name"]);
|
||||||
|
}
|
||||||
|
$modules[$json["name"]] = $json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPackedModules(): array {
|
||||||
|
$dir = DataProvider::getDataFolder() . "modules";
|
||||||
|
$ls = DataProvider::scanDirFiles($dir, true, false);
|
||||||
|
if ($ls === false) return [];
|
||||||
|
$modules = [];
|
||||||
|
foreach ($ls as $v) {
|
||||||
|
$pathinfo = pathinfo($v);
|
||||||
|
if (($pathinfo["extension"] ?? "") != "phar") continue;
|
||||||
|
$file = "phar://" . $v;
|
||||||
|
if (!is_file($file . "/module_entry.php") || !is_file($file . "/zmplugin.json")) continue;
|
||||||
|
$module_config = json_decode(file_get_contents($file . "/zmplugin.json"), true);
|
||||||
|
if ($module_config === null) continue;
|
||||||
|
if (!is_file($file . "/" . $module_config["module-root-path"] . "/zm.json")) {
|
||||||
|
Console::warning(zm_internal_errcode("E00054") . "模块(插件)文件 " . $pathinfo["basename"] . " 无法找到模块配置文件(zm.json)!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$module_file = json_decode(file_get_contents($file . "/" . $module_config["module-root-path"] . "/zm.json"), true);
|
||||||
|
if ($module_file === null) {
|
||||||
|
Console::warning(zm_internal_errcode("E000555") . "模块(插件)文件 " . $pathinfo["basename"] . " 无法正常读取模块配置文件(zm.json)!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$module_config["phar-path"] = $v;
|
||||||
|
$module_config["name"] = $module_file["name"] ?? null;
|
||||||
|
if ($module_config["name"] === null) continue;
|
||||||
|
$module_config["module-config"] = $module_file;
|
||||||
|
$modules[$module_config["name"]] = $module_config;
|
||||||
|
}
|
||||||
|
return $modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打包模块
|
||||||
|
* @param $module
|
||||||
|
* @return bool
|
||||||
|
* @throws ZMException
|
||||||
|
*/
|
||||||
|
public static function packModule($module): bool {
|
||||||
|
try {
|
||||||
|
$packer = new ModulePacker($module);
|
||||||
|
$packer->setOutputPath(DataProvider::getDataFolder() . "output");
|
||||||
|
$packer->setOverride();
|
||||||
|
$packer->pack();
|
||||||
|
return true;
|
||||||
|
} catch (ModulePackException $e) {
|
||||||
|
Console::error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解包模块 TODO
|
||||||
|
* @param $module
|
||||||
|
* @return array|false
|
||||||
|
*/
|
||||||
|
public static function unpackModule($module) {
|
||||||
|
try {
|
||||||
|
$packer = new ModuleUnpacker($module);
|
||||||
|
return $packer->unpack();
|
||||||
|
} catch (ModulePackException $e) {
|
||||||
|
Console::error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<?php /** @noinspection PhpUnused */
|
<?php /** @noinspection PhpUnused */
|
||||||
|
|
||||||
|
|
||||||
namespace ZM\Utils;
|
namespace ZM\Utils\Manager;
|
||||||
|
|
||||||
|
|
||||||
use Co;
|
use Swoole\Coroutine;
|
||||||
use ZM\Annotation\CQ\CQCommand;
|
use ZM\Annotation\CQ\CQCommand;
|
||||||
use ZM\Annotation\Swoole\OnPipeMessageEvent;
|
use ZM\Annotation\Swoole\OnPipeMessageEvent;
|
||||||
use ZM\Console\Console;
|
use ZM\Console\Console;
|
||||||
@@ -38,7 +38,7 @@ class ProcessManager
|
|||||||
break;
|
break;
|
||||||
case "resume_ws_message":
|
case "resume_ws_message":
|
||||||
$obj = $data["data"];
|
$obj = $data["data"];
|
||||||
Co::resume($obj["coroutine"]);
|
Coroutine::resume($obj["coroutine"]);
|
||||||
break;
|
break;
|
||||||
case "getWorkerCache":
|
case "getWorkerCache":
|
||||||
$r = WorkerCache::get($data["key"]);
|
$r = WorkerCache::get($data["key"]);
|
||||||
@@ -99,7 +99,7 @@ class ProcessManager
|
|||||||
public static function sendActionToWorker($worker_id, $action, $data) {
|
public static function sendActionToWorker($worker_id, $action, $data) {
|
||||||
$obj = ["action" => $action, "data" => $data];
|
$obj = ["action" => $action, "data" => $data];
|
||||||
if (server()->worker_id === -1 && server()->getManagerPid() != posix_getpid()) {
|
if (server()->worker_id === -1 && server()->getManagerPid() != posix_getpid()) {
|
||||||
Console::warning("Cannot send worker action from master or manager process!");
|
Console::warning(zm_internal_errcode("E00022") . "Cannot send worker action from master or manager process!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (server()->worker_id == $worker_id) {
|
if (server()->worker_id == $worker_id) {
|
||||||
@@ -114,9 +114,9 @@ class ProcessManager
|
|||||||
Console::warning("Cannot call '" . __FUNCTION__ . "' in non-worker process!");
|
Console::warning("Cannot call '" . __FUNCTION__ . "' in non-worker process!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach ((LightCacheInside::get("wait_api", "wait_api") ?? []) as $k => $v) {
|
foreach ((LightCacheInside::get("wait_api", "wait_api") ?? []) as $v) {
|
||||||
if (isset($v["coroutine"], $v["worker_id"])) {
|
if (isset($v["coroutine"], $v["worker_id"])) {
|
||||||
if (server()->worker_id == $v["worker_id"]) Co::resume($v["coroutine"]);
|
if (server()->worker_id == $v["worker_id"]) Coroutine::resume($v["coroutine"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
67
src/ZM/Utils/Manager/RouteManager.php
Normal file
67
src/ZM/Utils/Manager/RouteManager.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Utils\Manager;
|
||||||
|
|
||||||
|
|
||||||
|
use Symfony\Component\Routing\Route;
|
||||||
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
use ZM\Annotation\Http\Controller;
|
||||||
|
use ZM\Annotation\Http\RequestMapping;
|
||||||
|
use ZM\Console\Console;
|
||||||
|
use ZM\Http\StaticFileHandler;
|
||||||
|
use ZM\Store\LightCacheInside;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 路由管理器,2.5版本更改了命名空间
|
||||||
|
* Class RouteManager
|
||||||
|
* @package ZM\Utils\Manager
|
||||||
|
* @since 2.3.0
|
||||||
|
*/
|
||||||
|
class RouteManager
|
||||||
|
{
|
||||||
|
/** @var null|RouteCollection */
|
||||||
|
public static $routes = null;
|
||||||
|
|
||||||
|
public static function importRouteByAnnotation(RequestMapping $vss, $method, $class, $methods_annotations) {
|
||||||
|
if (self::$routes === null) self::$routes = new RouteCollection();
|
||||||
|
|
||||||
|
// 拿到所属方法的类上面有没有控制器的注解
|
||||||
|
$prefix = '';
|
||||||
|
foreach ($methods_annotations as $annotation) {
|
||||||
|
if ($annotation instanceof Controller) {
|
||||||
|
$prefix = $annotation->prefix;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$tail = trim($vss->route, "/");
|
||||||
|
$route_name = $prefix . ($tail === "" ? "" : "/") . $tail;
|
||||||
|
Console::debug("添加路由:" . $route_name);
|
||||||
|
$route = new Route($route_name, ['_class' => $class, '_method' => $method]);
|
||||||
|
$route->setMethods($vss->request_method);
|
||||||
|
|
||||||
|
self::$routes->add(md5($route_name), $route);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function addStaticFileRoute($route, $path) {
|
||||||
|
$tail = trim($route, "/");
|
||||||
|
$route_name = ($tail === "" ? "" : "/") . $tail . "/{filename}";
|
||||||
|
Console::debug("添加静态文件路由:" . $route_name);
|
||||||
|
$route = new Route($route_name, ['_class' => RouteManager::class, '_method' => "onStaticRoute"]);
|
||||||
|
//echo $path.PHP_EOL;
|
||||||
|
LightCacheInside::set("static_route", $route->getPath(), $path);
|
||||||
|
|
||||||
|
self::$routes->add(md5($route_name), $route);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onStaticRoute($params) {
|
||||||
|
$route_path = self::$routes->get($params["_route"])->getPath();
|
||||||
|
if(($path = LightCacheInside::get("static_route", $route_path)) === null) {
|
||||||
|
ctx()->getResponse()->endWithStatus(404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unset($params["_route"]);
|
||||||
|
$obj = array_shift($params);
|
||||||
|
return new StaticFileHandler($obj, $path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php /** @noinspection PhpUnused */
|
<?php /** @noinspection PhpUnused */
|
||||||
|
|
||||||
|
|
||||||
namespace ZM\Utils;
|
namespace ZM\Utils\Manager;
|
||||||
|
|
||||||
|
|
||||||
use ZM\Console\Console;
|
use ZM\Console\Console;
|
||||||
@@ -9,15 +9,14 @@ use ZM\Console\Console;
|
|||||||
class TaskManager
|
class TaskManager
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @noinspection PhpMissingReturnTypeInspection
|
|
||||||
* @param $task_name
|
* @param $task_name
|
||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @param mixed ...$params
|
* @param mixed ...$params
|
||||||
* @return false|mixed
|
* @return false|mixed
|
||||||
*/
|
*/
|
||||||
public static function runTask($task_name, $timeout = -1, ...$params) {
|
public static function runTask($task_name, int $timeout = -1, ...$params) {
|
||||||
if (!isset(server()->setting["task_worker_num"])) {
|
if (!isset(server()->setting["task_worker_num"])) {
|
||||||
Console::warning("未开启 TaskWorker 进程,请先修改 global 配置文件启用!");
|
Console::warning(zm_internal_errcode("E00056") . "未开启 TaskWorker 进程,请先修改 global 配置文件启用!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$r = server()->taskwait(["task" => $task_name, "params" => $params], $timeout);
|
$r = server()->taskwait(["task" => $task_name, "params" => $params], $timeout);
|
||||||
@@ -11,6 +11,7 @@ use ZM\Console\Console;
|
|||||||
use ZM\Entity\MatchResult;
|
use ZM\Entity\MatchResult;
|
||||||
use ZM\Event\EventManager;
|
use ZM\Event\EventManager;
|
||||||
use ZM\Requests\ZMRequest;
|
use ZM\Requests\ZMRequest;
|
||||||
|
use ZM\Utils\Manager\ProcessManager;
|
||||||
|
|
||||||
class MessageUtil
|
class MessageUtil
|
||||||
{
|
{
|
||||||
@@ -25,7 +26,7 @@ class MessageUtil
|
|||||||
if (!is_dir($path)) mkdir($path);
|
if (!is_dir($path)) mkdir($path);
|
||||||
$path = realpath($path);
|
$path = realpath($path);
|
||||||
if ($path === false) {
|
if ($path === false) {
|
||||||
Console::warning("指定的路径错误不存在!");
|
Console::warning(zm_internal_errcode("E00059") . "指定的路径错误不存在!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$files = [];
|
$files = [];
|
||||||
@@ -34,7 +35,7 @@ class MessageUtil
|
|||||||
if ($v->type == "image") {
|
if ($v->type == "image") {
|
||||||
$result = ZMRequest::downloadFile($v->params["url"], $path . "/" . $v->params["file"]);
|
$result = ZMRequest::downloadFile($v->params["url"], $path . "/" . $v->params["file"]);
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
Console::warning("图片 " . $v->params["url"] . " 下载失败!");
|
Console::warning(zm_internal_errcode("E00060") . "图片 " . $v->params["url"] . " 下载失败!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$files[] = $path . "/" . $v->params["file"];
|
$files[] = $path . "/" . $v->params["file"];
|
||||||
@@ -112,7 +113,7 @@ class MessageUtil
|
|||||||
$ls = EventManager::$events[CQCommand::class] ?? [];
|
$ls = EventManager::$events[CQCommand::class] ?? [];
|
||||||
$word = self::splitCommand($msg);
|
$word = self::splitCommand($msg);
|
||||||
$matched = new MatchResult();
|
$matched = new MatchResult();
|
||||||
foreach ($ls as $k => $v) {
|
foreach ($ls as $v) {
|
||||||
if (array_diff([$v->match, $v->pattern, $v->regex, $v->keyword, $v->end_with, $v->start_with], [""]) == []) continue;
|
if (array_diff([$v->match, $v->pattern, $v->regex, $v->keyword, $v->end_with, $v->start_with], [""]) == []) continue;
|
||||||
elseif (($v->user_id == 0 || ($v->user_id != 0 && $v->user_id == $obj["user_id"])) &&
|
elseif (($v->user_id == 0 || ($v->user_id != 0 && $v->user_id == $obj["user_id"])) &&
|
||||||
($v->group_id == 0 || ($v->group_id != 0 && $v->group_id == ($obj["group_id"] ?? 0))) &&
|
($v->group_id == 0 || ($v->group_id != 0 && $v->group_id == ($obj["group_id"] ?? 0))) &&
|
||||||
|
|||||||
75
src/ZM/Utils/SignalListener.php
Normal file
75
src/ZM/Utils/SignalListener.php
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Utils;
|
||||||
|
|
||||||
|
|
||||||
|
use Swoole\Event;
|
||||||
|
use Swoole\Process;
|
||||||
|
use Swoole\Server;
|
||||||
|
use Swoole\Timer;
|
||||||
|
use ZM\Console\Console;
|
||||||
|
use ZM\Framework;
|
||||||
|
use ZM\Store\ZMBuf;
|
||||||
|
use ZM\Utils\Manager\ProcessManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 炸毛框架的Linux signal管理类
|
||||||
|
* Class SignalListener
|
||||||
|
* @package ZM\Utils
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
class SignalListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 监听Master进程的Ctrl+C
|
||||||
|
* @param Server $server
|
||||||
|
*/
|
||||||
|
public static function signalMaster(Server $server) {
|
||||||
|
Process::signal(SIGINT, function () use ($server) {
|
||||||
|
if (zm_atomic("_int_is_reload")->get() === 1) {
|
||||||
|
zm_atomic("_int_is_reload")->set(0);
|
||||||
|
$server->reload();
|
||||||
|
} else {
|
||||||
|
echo "\r";
|
||||||
|
Console::warning("Server interrupted(SIGINT) on Master.");
|
||||||
|
if ((Framework::$server->inotify ?? null) !== null)
|
||||||
|
/** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify);
|
||||||
|
if (ZMBuf::$terminal !== null)
|
||||||
|
Event::del(ZMBuf::$terminal);
|
||||||
|
Process::kill($server->master_pid, SIGTERM);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听Manager进程的Ctrl+C
|
||||||
|
*/
|
||||||
|
public static function signalManager() {
|
||||||
|
$func = function () {
|
||||||
|
Console::verbose("Interrupted in manager!");
|
||||||
|
};
|
||||||
|
if (version_compare(SWOOLE_VERSION, "4.6.7") >= 0) {
|
||||||
|
Process::signal(SIGINT, $func);
|
||||||
|
} elseif (extension_loaded("pcntl")) {
|
||||||
|
pcntl_signal(SIGINT, $func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听Worker/TaskWorker进程的Ctrl+C
|
||||||
|
* @param Server $server
|
||||||
|
* @param $worker_id
|
||||||
|
*/
|
||||||
|
public static function signalWorker(Server $server, $worker_id) {
|
||||||
|
Process::signal(SIGINT, function () use ($worker_id, $server) {
|
||||||
|
// do nothing
|
||||||
|
});
|
||||||
|
if ($server->taskworker === false) {
|
||||||
|
Process::signal(SIGUSR1, function () use ($worker_id) {
|
||||||
|
Timer::clearAll();
|
||||||
|
ProcessManager::resumeAllWorkerCoroutines();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,13 +33,13 @@ class Terminal
|
|||||||
$dispatcher = new EventDispatcher(TerminalCommand::class);
|
$dispatcher = new EventDispatcher(TerminalCommand::class);
|
||||||
$dispatcher->setRuleFunction(function ($v) use ($it) {
|
$dispatcher->setRuleFunction(function ($v) use ($it) {
|
||||||
/** @var TerminalCommand $v */
|
/** @var TerminalCommand $v */
|
||||||
return $v->command == $it[0] || $v->alias == $it[0];
|
return !empty($it) && ($v->command == $it[0] || $v->alias == $it[0]);
|
||||||
});
|
});
|
||||||
$dispatcher->setReturnFunction(function () {
|
$dispatcher->setReturnFunction(function () {
|
||||||
EventDispatcher::interrupt('none');
|
EventDispatcher::interrupt('none');
|
||||||
});
|
});
|
||||||
$dispatcher->dispatchEvents($it);
|
$dispatcher->dispatchEvents($it);
|
||||||
if ($dispatcher->store !== 'none') {
|
if ($dispatcher->store !== 'none' && $cmd !== "") {
|
||||||
Console::info("Command not found: " . $cmd);
|
Console::info("Command not found: " . $cmd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ class Terminal
|
|||||||
Console::$type($log_msg);
|
Console::$type($log_msg);
|
||||||
$r = ob_get_clean();
|
$r = ob_get_clean();
|
||||||
$all = ManagerGM::getAllByName("terminal");
|
$all = ManagerGM::getAllByName("terminal");
|
||||||
foreach ($all as $k => $v) {
|
foreach ($all as $v) {
|
||||||
server()->send($v->getFd(), "\r" . $r);
|
server()->send($v->getFd(), "\r" . $r);
|
||||||
server()->send($v->getFd(), ">>> ");
|
server()->send($v->getFd(), ">>> ");
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ class Terminal
|
|||||||
$class = new Terminal();
|
$class = new Terminal();
|
||||||
$reader = new AnnotationReader();
|
$reader = new AnnotationReader();
|
||||||
$reflection = new ReflectionClass($class);
|
$reflection = new ReflectionClass($class);
|
||||||
foreach ($reflection->getMethods() as $k => $v) {
|
foreach ($reflection->getMethods() as $v) {
|
||||||
$r = $reader->getMethodAnnotation($v, TerminalCommand::class);
|
$r = $reader->getMethodAnnotation($v, TerminalCommand::class);
|
||||||
if ($r !== null) {
|
if ($r !== null) {
|
||||||
Console::debug("adding command " . $r->command);
|
Console::debug("adding command " . $r->command);
|
||||||
@@ -176,7 +176,7 @@ class Terminal
|
|||||||
* @TerminalCommand(command="stop",description="停止框架")
|
* @TerminalCommand(command="stop",description="停止框架")
|
||||||
*/
|
*/
|
||||||
public function stop() {
|
public function stop() {
|
||||||
Process::kill(server()->master_pid, SIGTERM);
|
posix_kill(server()->master_pid, SIGTERM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ class ZMUtil
|
|||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function stop() {
|
public static function stop() {
|
||||||
if (SpinLock::tryLock("_stop_signal") === false) return;
|
if (SpinLock::tryLock('_stop_signal') === false) return;
|
||||||
Console::warning(Console::setColor("Stopping server...", "red"));
|
Console::warning(Console::setColor('Stopping server...', 'red'));
|
||||||
if (Console::getLevel() >= 4) Console::trace();
|
if (Console::getLevel() >= 4) Console::trace();
|
||||||
ZMAtomic::get("stop_signal")->set(1);
|
ZMAtomic::get('stop_signal')->set(1);
|
||||||
for ($i = 0; $i < ZM_WORKER_NUM; ++$i) {
|
for ($i = 0; $i < ZM_WORKER_NUM; ++$i) {
|
||||||
if (Process::kill(zm_atomic("_#worker_" . $i)->get(), 0))
|
if (Process::kill(zm_atomic('_#worker_' . $i)->get(), 0))
|
||||||
Process::kill(zm_atomic("_#worker_" . $i)->get(), SIGUSR1);
|
Process::kill(zm_atomic('_#worker_' . $i)->get(), SIGUSR1);
|
||||||
}
|
}
|
||||||
server()->shutdown();
|
server()->shutdown();
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ class ZMUtil
|
|||||||
|
|
||||||
public static function getModInstance($class) {
|
public static function getModInstance($class) {
|
||||||
if (!isset(ZMBuf::$instance[$class])) {
|
if (!isset(ZMBuf::$instance[$class])) {
|
||||||
//Console::debug("Class instance $class not exist, so I created it.");
|
//Console::debug('Class instance $class not exist, so I created it.');
|
||||||
return ZMBuf::$instance[$class] = new $class();
|
return ZMBuf::$instance[$class] = new $class();
|
||||||
} else {
|
} else {
|
||||||
return ZMBuf::$instance[$class];
|
return ZMBuf::$instance[$class];
|
||||||
@@ -52,11 +52,44 @@ class ZMUtil
|
|||||||
public static function getReloadableFiles() {
|
public static function getReloadableFiles() {
|
||||||
return array_map(
|
return array_map(
|
||||||
function ($x) {
|
function ($x) {
|
||||||
return str_replace(DataProvider::getWorkingDir() . "/", "", $x);
|
return str_replace(DataProvider::getSourceRootDir() . '/', '', $x);
|
||||||
}, array_diff(
|
}, array_diff(
|
||||||
get_included_files(),
|
get_included_files(),
|
||||||
Framework::$loaded_files
|
Framework::$loaded_files
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用Psr-4标准获取目录下的所有类
|
||||||
|
* @param $dir
|
||||||
|
* @param $base_namespace
|
||||||
|
* @param null|mixed $rule
|
||||||
|
* @param bool $return_kv
|
||||||
|
* @return String[]
|
||||||
|
*/
|
||||||
|
public static function getClassesPsr4($dir, $base_namespace, $rule = null, $return_kv = false) {
|
||||||
|
// 预先读取下composer的file列表
|
||||||
|
$composer = json_decode(file_get_contents(DataProvider::getSourceRootDir() . '/composer.json'), true);
|
||||||
|
$classes = [];
|
||||||
|
// 扫描目录,使用递归模式,相对路径模式,因为下面此路径要用作转换成namespace
|
||||||
|
$files = DataProvider::scanDirFiles($dir, true, true);
|
||||||
|
foreach ($files as $v) {
|
||||||
|
$pathinfo = pathinfo($v);
|
||||||
|
if ($pathinfo['extension'] == 'php') {
|
||||||
|
if ($rule === null) { //规则未设置回调时候,使用默认的识别过滤规则
|
||||||
|
if (substr(file_get_contents($dir . '/' . $v), 6, 6) == '#plain') continue;
|
||||||
|
elseif (mb_substr($v, 0, 7) == 'global_' || mb_substr($v, 0, 7) == 'script_') continue;
|
||||||
|
foreach (($composer['autoload']['files'] ?? []) as $fi) {
|
||||||
|
if (md5_file(DataProvider::getSourceRootDir().'/'.$fi) == md5_file($dir.'/'.$v)) continue 2;
|
||||||
|
}
|
||||||
|
} elseif (is_callable($rule) && !($rule($dir, $pathinfo))) continue;
|
||||||
|
$dirname = $pathinfo['dirname'] == '.' ? '' : (str_replace('/', '\\', $pathinfo['dirname']) . '\\');
|
||||||
|
$class_name = $base_namespace . '\\' . $dirname . $pathinfo['filename'];
|
||||||
|
if ($return_kv) $classes[$class_name] = $v;
|
||||||
|
else $classes[] = $class_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $classes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use ZM\Utils\DataProvider;
|
|||||||
|
|
||||||
define("ZM_START_TIME", microtime(true));
|
define("ZM_START_TIME", microtime(true));
|
||||||
define("ZM_DATA", ZMConfig::get("global", "zm_data"));
|
define("ZM_DATA", ZMConfig::get("global", "zm_data"));
|
||||||
define("APP_VERSION", LOAD_MODE == 1 ? (json_decode(file_get_contents(DataProvider::getWorkingDir() . "/composer.json"), true)["version"] ?? "unknown") : "unknown");
|
define("APP_VERSION", LOAD_MODE == 1 ? (json_decode(file_get_contents(DataProvider::getSourceRootDir() . "/composer.json"), true)["version"] ?? "unknown") : "unknown");
|
||||||
define("CRASH_DIR", ZMConfig::get("global", "crash_dir"));
|
define("CRASH_DIR", ZMConfig::get("global", "crash_dir"));
|
||||||
define("MAIN_WORKER", ZMConfig::get("global", "worker_cache")["worker"] ?? 0);
|
define("MAIN_WORKER", ZMConfig::get("global", "worker_cache")["worker"] ?? 0);
|
||||||
if (!is_dir(ZM_DATA)) @mkdir(ZM_DATA);
|
if (!is_dir(ZM_DATA)) @mkdir(ZM_DATA);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<?php #plain
|
<?php #plain
|
||||||
|
use Swoole\Coroutine as Co;
|
||||||
use Swoole\Atomic;
|
use Swoole\Atomic;
|
||||||
use Swoole\Coroutine;
|
use Swoole\Coroutine;
|
||||||
use Swoole\WebSocket\Server;
|
use Swoole\WebSocket\Server;
|
||||||
use Symfony\Component\VarDumper\VarDumper;
|
use Symfony\Component\VarDumper\VarDumper;
|
||||||
use ZM\API\ZMRobot;
|
use ZM\API\OneBotV11;
|
||||||
use ZM\Config\ZMConfig;
|
use ZM\Config\ZMConfig;
|
||||||
use ZM\ConnectionManager\ManagerGM;
|
use ZM\ConnectionManager\ManagerGM;
|
||||||
use ZM\Console\Console;
|
use ZM\Console\Console;
|
||||||
@@ -23,7 +23,7 @@ use ZM\Context\ContextInterface;
|
|||||||
|
|
||||||
function getClassPath($class_name) {
|
function getClassPath($class_name) {
|
||||||
$dir = str_replace("\\", "/", $class_name);
|
$dir = str_replace("\\", "/", $class_name);
|
||||||
$dir2 = WORKING_DIR . "/src/" . $dir . ".php";
|
$dir2 = DataProvider::getSourceRootDir() . "/src/" . $dir . ".php";
|
||||||
//echo "@@@".$dir2.PHP_EOL;
|
//echo "@@@".$dir2.PHP_EOL;
|
||||||
$dir2 = str_replace("\\", "/", $dir2);
|
$dir2 = str_replace("\\", "/", $dir2);
|
||||||
if (file_exists($dir2)) return $dir2;
|
if (file_exists($dir2)) return $dir2;
|
||||||
@@ -44,50 +44,20 @@ function explodeMsg($msg, $ban_comma = false): array {
|
|||||||
}
|
}
|
||||||
$msgs = explode("\n", $msg);
|
$msgs = explode("\n", $msg);
|
||||||
$ls = [];
|
$ls = [];
|
||||||
foreach ($msgs as $k => $v) {
|
foreach ($msgs as $v) {
|
||||||
if (trim($v) == "") continue;
|
if (trim($v) == "") continue;
|
||||||
$ls[] = trim($v);
|
$ls[] = trim($v);
|
||||||
}
|
}
|
||||||
return $ls;
|
return $ls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @noinspection PhpUnused */
|
||||||
function unicode_decode($str) {
|
function unicode_decode($str) {
|
||||||
return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function ($matches) {
|
return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function ($matches) {
|
||||||
return mb_convert_encoding(pack("H*", $matches[1]), "UTF-8", "UCS-2BE");
|
return mb_convert_encoding(pack("H*", $matches[1]), "UTF-8", "UCS-2BE");
|
||||||
}, $str);
|
}, $str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取模块文件夹下的每个类文件的类名称
|
|
||||||
* @param $dir
|
|
||||||
* @param $indoor_name
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
function getAllClasses($dir, $indoor_name): array {
|
|
||||||
if (!is_dir($dir)) return [];
|
|
||||||
$list = scandir($dir);
|
|
||||||
$classes = [];
|
|
||||||
if ($list[0] == '.') unset($list[0], $list[1]);
|
|
||||||
foreach ($list as $v) {
|
|
||||||
//echo "Finding " . $dir . $v . PHP_EOL;
|
|
||||||
//echo "At " . $indoor_name . PHP_EOL;
|
|
||||||
if (is_dir($dir . $v)) $classes = array_merge($classes, getAllClasses($dir . $v . "/", $indoor_name . "\\" . $v));
|
|
||||||
elseif (mb_substr($v, -4) == ".php") {
|
|
||||||
if (substr(file_get_contents($dir . $v), 6, 6) == "#plain") continue;
|
|
||||||
$composer = json_decode(file_get_contents(DataProvider::getWorkingDir() . "/composer.json"), true);
|
|
||||||
foreach ($composer["autoload"]["files"] as $fi) {
|
|
||||||
if (realpath(DataProvider::getWorkingDir() . "/" . $fi) == realpath($dir . $v)) {
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($v == "global_function.php") continue;
|
|
||||||
$class_name = $indoor_name . "\\" . mb_substr($v, 0, -4);
|
|
||||||
$classes [] = $class_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
function matchPattern($pattern, $context): bool {
|
function matchPattern($pattern, $context): bool {
|
||||||
if (mb_substr($pattern, 0, 1) == "" && mb_substr($context, 0, 1) == "")
|
if (mb_substr($pattern, 0, 1) == "" && mb_substr($context, 0, 1) == "")
|
||||||
return true;
|
return true;
|
||||||
@@ -124,7 +94,7 @@ function split_explode($del, $str, $divide_en = false): array {
|
|||||||
$str = implode($del, $str);
|
$str = implode($del, $str);
|
||||||
//echo $str."\n";
|
//echo $str."\n";
|
||||||
$ls = [];
|
$ls = [];
|
||||||
foreach (explode($del, $str) as $k => $v) {
|
foreach (explode($del, $str) as $v) {
|
||||||
if (trim($v) == "") continue;
|
if (trim($v) == "") continue;
|
||||||
$ls[] = $v;
|
$ls[] = $v;
|
||||||
}
|
}
|
||||||
@@ -178,8 +148,8 @@ function getAnnotations(): array {
|
|||||||
$s = debug_backtrace()[1];
|
$s = debug_backtrace()[1];
|
||||||
//echo json_encode($s, 128|256);
|
//echo json_encode($s, 128|256);
|
||||||
$list = [];
|
$list = [];
|
||||||
foreach (EventManager::$events as $event => $v) {
|
foreach (EventManager::$events as $v) {
|
||||||
foreach ($v as $ks => $vs) {
|
foreach ($v as $vs) {
|
||||||
//echo get_class($vs).": ".$vs->class." => ".$vs->method.PHP_EOL;
|
//echo get_class($vs).": ".$vs->class." => ".$vs->method.PHP_EOL;
|
||||||
if ($vs->class == $s["class"] && $vs->method == $s["function"]) {
|
if ($vs->class == $s["class"] && $vs->method == $s["function"]) {
|
||||||
$list[get_class($vs)][] = $vs;
|
$list[get_class($vs)][] = $vs;
|
||||||
@@ -191,7 +161,7 @@ function getAnnotations(): array {
|
|||||||
|
|
||||||
function set_coroutine_params($array) {
|
function set_coroutine_params($array) {
|
||||||
$cid = Co::getCid();
|
$cid = Co::getCid();
|
||||||
if ($cid == -1) die("Cannot set coroutine params at none coroutine mode.");
|
if ($cid == -1) die(zm_internal_errcode("E00061")."Cannot set coroutine params at none coroutine mode.");
|
||||||
if (isset(Context::$context[$cid])) Context::$context[$cid] = array_merge(Context::$context[$cid], $array);
|
if (isset(Context::$context[$cid])) Context::$context[$cid] = array_merge(Context::$context[$cid], $array);
|
||||||
else Context::$context[$cid] = $array;
|
else Context::$context[$cid] = $array;
|
||||||
foreach (Context::$context as $c => $v) {
|
foreach (Context::$context as $c => $v) {
|
||||||
@@ -261,11 +231,11 @@ function call_with_catch($callable) {
|
|||||||
$callable();
|
$callable();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught exception " . get_class($e) . " when calling \"message\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00033") . "Uncaught exception " . get_class($e) . ": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Uncaught " . get_class($e) . " when calling \"message\": " . $error_msg);
|
Console::error(zm_internal_errcode("E00033") . "Uncaught " . get_class($e) . ": " . $error_msg);
|
||||||
Console::trace();
|
Console::trace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,15 +268,15 @@ function server(): ?Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ZMRobot
|
* @return OneBotV11
|
||||||
* @throws RobotNotFoundException
|
* @throws RobotNotFoundException
|
||||||
* @throws ZMException
|
* @throws ZMException
|
||||||
*/
|
*/
|
||||||
function bot(): ZMRobot {
|
function bot() {
|
||||||
if (($conn = LightCacheInside::get("connect", "conn_fd")) == -2) {
|
if (($conn = LightCacheInside::get("connect", "conn_fd")) == -2) {
|
||||||
return ZMRobot::getRandom();
|
return OneBotV11::getRandom();
|
||||||
} elseif ($conn != -1) {
|
} elseif ($conn != -1) {
|
||||||
if (($obj = ManagerGM::get($conn)) !== null) return new ZMRobot($obj);
|
if (($obj = ManagerGM::get($conn)) !== null) return new OneBotV11($obj);
|
||||||
else throw new RobotNotFoundException("单机器人连接模式可能连接了多个机器人!");
|
else throw new RobotNotFoundException("单机器人连接模式可能连接了多个机器人!");
|
||||||
} else {
|
} else {
|
||||||
throw new RobotNotFoundException("没有任何机器人连接到框架!");
|
throw new RobotNotFoundException("没有任何机器人连接到框架!");
|
||||||
@@ -376,7 +346,11 @@ function zm_error($obj) { Console::error($obj); }
|
|||||||
function zm_config($name, $key = null) { return ZMConfig::get($name, $key); }
|
function zm_config($name, $key = null) { return ZMConfig::get($name, $key); }
|
||||||
|
|
||||||
function quick_reply_closure($reply) {
|
function quick_reply_closure($reply) {
|
||||||
return function() use ($reply){
|
return function () use ($reply) {
|
||||||
return $reply;
|
return $reply;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zm_internal_errcode($code): string {
|
||||||
|
return "[ErrCode:$code] ";
|
||||||
|
}
|
||||||
|
|||||||
11
src/ZM/script_phar_stub.php
Normal file
11
src/ZM/script_phar_stub.php
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function loader__generated_id__() {
|
||||||
|
$obj = json_decode(file_get_contents(__DIR__.'/zmplugin.json'), true);
|
||||||
|
foreach(($obj["autoload-psr-4"] ?? []) as $v) {
|
||||||
|
require_once Phar::running().'/'.$v;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
echo "OK!\n";
|
||||||
|
return json_decode(file_get_contents(__DIR__.'/zmplugin.json'), true) ?? ['zm_module' => false];
|
||||||
59
src/ZM/script_setup_loader.php
Normal file
59
src/ZM/script_setup_loader.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Doctrine\Common\Annotations\AnnotationReader;
|
||||||
|
use ZM\Annotation\Swoole\OnSetup;
|
||||||
|
use ZM\Annotation\Swoole\SwooleHandler;
|
||||||
|
use ZM\ConsoleApplication;
|
||||||
|
use ZM\Utils\DataProvider;
|
||||||
|
use ZM\Utils\ZMUtil;
|
||||||
|
|
||||||
|
require_once ((!is_dir(__DIR__ . '/../../vendor')) ? getcwd() : (__DIR__ . "/../..")) . "/vendor/autoload.php";
|
||||||
|
|
||||||
|
try {
|
||||||
|
(new ConsoleApplication('zhamao'))->initEnv();
|
||||||
|
|
||||||
|
$base_path = DataProvider::getSourceRootDir();
|
||||||
|
$scan_paths = [];
|
||||||
|
$composer = json_decode(file_get_contents($base_path . "/composer.json"), true);
|
||||||
|
foreach (($composer["autoload"]["psr-4"] ?? []) as $k => $v) {
|
||||||
|
if (is_dir($base_path . "/" . $v) && !in_array($v, $composer["extra"]["exclude_annotate"] ?? [])) {
|
||||||
|
$scan_paths[trim($k, "\\")] = $base_path . "/" . $v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$all_event_class = [];
|
||||||
|
foreach ($scan_paths as $namespace => $autoload_path) {
|
||||||
|
$all_event_class = array_merge($all_event_class, ZMUtil::getClassesPsr4($autoload_path, $namespace));
|
||||||
|
}
|
||||||
|
|
||||||
|
$reader = new AnnotationReader();
|
||||||
|
$event_list = [];
|
||||||
|
$setup_list = [];
|
||||||
|
foreach ($all_event_class as $v) {
|
||||||
|
$reflection_class = new ReflectionClass($v);
|
||||||
|
$methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC);
|
||||||
|
foreach ($methods as $vs) {
|
||||||
|
$method_annotations = $reader->getMethodAnnotations($vs);
|
||||||
|
if ($method_annotations != []) {
|
||||||
|
$annotation = $method_annotations[0];
|
||||||
|
if ($annotation instanceof SwooleHandler) {
|
||||||
|
$event_list[] = [
|
||||||
|
"class" => $v,
|
||||||
|
"method" => $vs->getName(),
|
||||||
|
"event" => $annotation->event
|
||||||
|
];
|
||||||
|
} elseif ($annotation instanceof OnSetup) {
|
||||||
|
$setup_list[] = [
|
||||||
|
"class" => $v,
|
||||||
|
"method" => $vs->getName()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo json_encode(["setup" => $setup_list, "event" => $event_list]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$stderr = fopen("php://stderr", "w");
|
||||||
|
fwrite($stderr, zm_internal_errcode("E00031") . $e->getMessage() . " in " . $e->getFile() . " at line " . $e->getLine() . PHP_EOL);
|
||||||
|
fclose($stderr);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use ZM\Console\Console;
|
|
||||||
use ZM\Requests\ZMRequest;
|
|
||||||
use ZM\Utils\CoroutinePool;
|
|
||||||
|
|
||||||
class CoroutinePoolTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testStart() {
|
|
||||||
$this->assertTrue(true);
|
|
||||||
Console::init(4);
|
|
||||||
CoroutinePool::setSize("default", 2);
|
|
||||||
CoroutinePool::defaultSize(50);
|
|
||||||
for ($i = 0; $i < 59; ++$i) {
|
|
||||||
CoroutinePool::go(function () use ($i) {
|
|
||||||
//Console::debug("第 $i 个马上进入睡眠...");
|
|
||||||
ZMRequest::get("http://localhost:9002/test/ping");
|
|
||||||
Console::verbose(strval($i));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testA() {
|
|
||||||
$this->assertTrue(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use ZM\Store\LightCache;
|
|
||||||
|
|
||||||
class LightCacheTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testCache() {
|
|
||||||
LightCache::init([
|
|
||||||
"size" => 2,
|
|
||||||
"max_strlen" => 4096,
|
|
||||||
"hash_conflict_proportion" => 0,
|
|
||||||
"persistence_path" => "../composer.json"
|
|
||||||
]);
|
|
||||||
//LightCache::set("bool", true);
|
|
||||||
$this->assertEquals(true, LightCache::set("2048", 123, 3));
|
|
||||||
$this->assertArrayHasKey("2048", LightCache::getAll());
|
|
||||||
sleep(3);
|
|
||||||
$this->assertArrayNotHasKey("2048", LightCache::getAll());
|
|
||||||
$this->assertEquals("Apache-2.0", LightCache::get("license"));
|
|
||||||
$this->assertEquals("zhamao/framework", LightCache::get("name"));
|
|
||||||
//$this->assertTrue(LightCache::set("storage", "asdasd", -2));
|
|
||||||
//LightCache::savePersistence();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
test/ZM/Utils/DataProviderTest.php
Normal file
29
test/ZM/Utils/DataProviderTest.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Utils;
|
||||||
|
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ZM\Config\ZMConfig;
|
||||||
|
|
||||||
|
class DataProviderTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void {
|
||||||
|
ZMConfig::setDirectory(realpath(__DIR__ . "/../Mock"));
|
||||||
|
if (!defined('ZM_DATA'))
|
||||||
|
define("ZM_DATA", DataProvider::getWorkingDir() . "/zm_data/");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testScanDirFiles() {
|
||||||
|
zm_dump(DataProvider::scanDirFiles("/fwef/wegweg"));
|
||||||
|
$this->assertContains("Example/Hello.php", DataProvider::scanDirFiles(DataProvider::getSourceRootDir() . '/src/Module', true, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetDataFolder() {
|
||||||
|
DataProvider::getDataFolder("testFolder");
|
||||||
|
$this->assertDirectoryExists(DataProvider::getWorkingDir() . "/zm_data/testFolder");
|
||||||
|
rmdir(DataProvider::getWorkingDir() . "/zm_data/testFolder");
|
||||||
|
}
|
||||||
|
}
|
||||||
50
test/ZM/Utils/Manager/ModuleManagerTest.php
Normal file
50
test/ZM/Utils/Manager/ModuleManagerTest.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace ZM\Utils\Manager;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ZM\Config\ZMConfig;
|
||||||
|
use ZM\Console\Console;
|
||||||
|
use ZM\Utils\DataProvider;
|
||||||
|
|
||||||
|
class ModuleManagerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function setUp(): void {
|
||||||
|
file_put_contents(DataProvider::getSourceRootDir()."/src/Module/zm.json", json_encode([
|
||||||
|
"name" => "示例模块2"
|
||||||
|
]));
|
||||||
|
|
||||||
|
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||||
|
ZMConfig::setEnv($args["env"] ?? "");
|
||||||
|
if (ZMConfig::get("global") === false) {
|
||||||
|
die ("Global config load failed: " . ZMConfig::$last_error . "\nPlease init first!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//定义常量
|
||||||
|
include_once DataProvider::getFrameworkRootDir()."/src/ZM/global_defines.php";
|
||||||
|
|
||||||
|
Console::init(
|
||||||
|
ZMConfig::get("global", "info_level") ?? 2,
|
||||||
|
null,
|
||||||
|
$args["log-theme"] ?? "default",
|
||||||
|
($o = ZMConfig::get("console_color")) === false ? [] : $o
|
||||||
|
);
|
||||||
|
|
||||||
|
$timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai";
|
||||||
|
date_default_timezone_set($timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown(): void {
|
||||||
|
unlink(DataProvider::getSourceRootDir()."/src/Module/zm.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetConfiguredModules() {
|
||||||
|
zm_dump(ModuleManager::getConfiguredModules());
|
||||||
|
$this->assertArrayHasKey("示例模块", ModuleManager::getConfiguredModules());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPackModule() {
|
||||||
|
$list = ModuleManager::getConfiguredModules();
|
||||||
|
$this->assertTrue(ModuleManager::packModule(current($list)));
|
||||||
|
}
|
||||||
|
}
|
||||||
19
test/ZM/Utils/ZMUtilTest.php
Normal file
19
test/ZM/Utils/ZMUtilTest.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Utils;
|
||||||
|
|
||||||
|
|
||||||
|
use Module\Example\Hello;
|
||||||
|
use Module\Middleware\TimerMiddleware;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ZM\Framework;
|
||||||
|
|
||||||
|
class ZMUtilTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGetClassesPsr4() {
|
||||||
|
$this->assertContains(Hello::class, ZMUtil::getClassesPsr4(DataProvider::getSourceRootDir()."/src/Module", "Module"));
|
||||||
|
$this->assertContains(TimerMiddleware::class, ZMUtil::getClassesPsr4(DataProvider::getSourceRootDir()."/src/Module", "Module"));
|
||||||
|
$this->assertContains(Framework::class, ZMUtil::getClassesPsr4(DataProvider::getSourceRootDir()."/src/ZM", "ZM"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ namespace ZMTest\Testing;
|
|||||||
use Module\Example\Hello;
|
use Module\Example\Hello;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use ZM\Config\ZMConfig;
|
use ZM\Config\ZMConfig;
|
||||||
|
use ZM\ConsoleApplication;
|
||||||
use ZM\Utils\ZMUtil;
|
use ZM\Utils\ZMUtil;
|
||||||
|
|
||||||
class ModuleTest extends TestCase
|
class ModuleTest extends TestCase
|
||||||
@@ -14,6 +15,7 @@ class ModuleTest extends TestCase
|
|||||||
protected function setUp(): void {
|
protected function setUp(): void {
|
||||||
ZMConfig::setDirectory(realpath(__DIR__."/../Mock"));
|
ZMConfig::setDirectory(realpath(__DIR__."/../Mock"));
|
||||||
set_coroutine_params([]);
|
set_coroutine_params([]);
|
||||||
|
(new ConsoleApplication('zhamao-test'))->initEnv();
|
||||||
require_once __DIR__ . '/../../../src/ZM/global_defines.php';
|
require_once __DIR__ . '/../../../src/ZM/global_defines.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
test/bootstrap.php
Normal file
13
test/bootstrap.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
|
||||||
|
set_coroutine_params([]);
|
||||||
|
|
||||||
|
// 模拟define
|
||||||
|
chdir(__DIR__.'/../');
|
||||||
|
define("WORKING_DIR", getcwd());
|
||||||
|
define("SOURCE_ROOT_DIR", WORKING_DIR);
|
||||||
|
define("LOAD_MODE", 0);
|
||||||
|
define("FRAMEWORK_ROOT_DIR", realpath(__DIR__ . "/../"));
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use ZM\Exception\ZMException;
|
|
||||||
use ZM\Store\LightCache;
|
|
||||||
|
|
||||||
LightCache::getMemoryUsage();
|
|
||||||
try {
|
|
||||||
LightCache::getExpire('1');
|
|
||||||
} catch (ZMException $e) {
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user