Compare commits

...

41 Commits

Author SHA1 Message Date
crazywhalecc
c5a6f1fea4 update docs 2022-03-20 23:28:20 +08:00
crazywhalecc
ba2777137b let build command faster (build 448, 2.7.1) 2022-03-20 23:26:42 +08:00
crazywhalecc
6d90be164a update docs 2022-03-20 22:16:34 +08:00
crazywhalecc
4da6f5859a update to 2.7.0 release (build 447) 2022-03-20 22:12:58 +08:00
crazywhalecc
15d4ea710a add --no-state-check option (build 446) 2022-03-20 21:04:07 +08:00
crazywhalecc
f0541c1f32 Merge remote-tracking branch 'origin/master' 2022-03-20 19:05:54 +08:00
crazywhalecc
2b8cab1824 add AnnotationReader ignore name config (build 445, 2.7.0-beta5) 2022-03-20 19:05:13 +08:00
Jerry Ma
61c7972915 Update README.md 2022-03-20 17:09:24 +08:00
crazywhalecc
44a0eec74c change to integration-test 2022-03-20 17:00:37 +08:00
crazywhalecc
e57753e44b change to integration-test 2022-03-20 16:58:53 +08:00
crazywhalecc
74e91a2950 fix unpack autoload not working, change exclude_annotate to another name (build 444) 2022-03-20 16:51:48 +08:00
crazywhalecc
7ce3ef41df fix comment spacing problem (build 443) 2022-03-20 16:23:07 +08:00
crazywhalecc
444a77933a change autoload to hotload for phar hotload mode (build 442) 2022-03-20 16:20:14 +08:00
crazywhalecc
78f78c607d add packer namespace adjust (build 441) 2022-03-20 16:18:33 +08:00
crazywhalecc
69155002dc add site to gitignore 2022-03-20 16:13:51 +08:00
crazywhalecc
475d14fab7 update composer.json 2022-03-20 16:13:33 +08:00
crazywhalecc
f4d7e63358 update php cs fixer 2022-03-20 15:48:14 +08:00
crazywhalecc
f222d2b45b update composer requirement version 2022-03-20 15:43:31 +08:00
Jerry Ma
d0155fe1da Create code-style-analysis.yml 2022-03-20 15:35:10 +08:00
Jerry Ma
4737d0b507 Update and rename main.yml to mkdocs-deploy.yml 2022-03-20 15:23:05 +08:00
Jerry Ma
09bd0197bb Merge pull request #64 from sunxyw/patch-1
docs: add weather bot example
2022-03-20 15:20:59 +08:00
crazywhalecc
f0f120bd32 add Macroable (build 440) 2022-03-20 01:54:14 +08:00
crazywhalecc
c897da29c6 add PHP8 Attribute compatibility (build 439, 2.7.0-beta4) 2022-03-20 01:53:36 +08:00
sunxyw
e347e254e8 update docs index 2022-03-20 00:11:45 +08:00
crazywhalecc
12363aebf0 Merge remote-tracking branch 'origin/master' 2022-03-19 23:23:54 +08:00
crazywhalecc
ff0b925313 update docs 2022-03-19 23:23:14 +08:00
sunxyw
a6b4bd9b80 update weather bot example 2022-03-19 21:35:48 +08:00
sunxyw
485fa5476c add weather bot example 2022-03-19 21:25:10 +08:00
Jerry Ma
689076d97c Update mkdocs.yml 2022-03-19 20:33:13 +08:00
Jerry Ma
cca6102e91 Update README.md 2022-03-18 16:57:27 +08:00
Jerry Ma
095855162b Update mkdocs.yml 2022-03-18 16:48:30 +08:00
Jerry Ma
326f934013 Update mkdocs.yml 2022-03-18 16:44:04 +08:00
Jerry Ma
35b0c258fe Merge pull request #63 from sunxyw/patch-2
docs: add qingyunke chatbot integration example
2022-03-18 16:01:15 +08:00
sunxyw
6650846b15 update integrate-qingyunke-chatbot.md 2022-03-18 15:19:19 +08:00
sunxyw
a33d320f4c update integrate-qingyunke-chatbot.md 2022-03-18 02:54:23 +08:00
sunxyw
0bcfea6aa4 add qingyunke chatbot integration example 2022-03-18 02:30:45 +08:00
crazywhalecc
db6e63e91c fix Response class null error (build 438) 2022-03-17 20:48:09 +08:00
crazywhalecc
a7f84fb53a Merge remote-tracking branch 'origin/master' 2022-03-17 19:48:38 +08:00
crazywhalecc
ce7f2b1765 change ctx return force to ContextInterface (build 437) 2022-03-17 19:42:59 +08:00
Jerry Ma
abbfb59eff Merge pull request #62 from sunxyw/patch-2
docs: add missing module version example
2022-03-17 18:19:02 +08:00
sunxyw
b57fef16f9 add missing module version example 2022-03-17 01:53:06 +08:00
90 changed files with 1077 additions and 247 deletions

59
.github/workflows/integration-test.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
name: Integration Test
on:
push:
branches:
- master
pull_request:
branches:
- master
types:
- opened
- synchronize
- reopened
- ready_for_review
- review_requested
jobs:
integration:
name: Integration Test (PHP ${{ matrix.php-versions }}) (OS ${{ matrix.operating-system }})
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ "ubuntu-latest", "macos-latest" ]
php-versions: [ "7.2", "7.3", "7.4", "8.0", "8.1" ]
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup PHP
uses: "shivammathur/setup-php@v2"
with:
php-version: ${{ matrix.php-versions }}
extensions: swoole, posix, json
- name: Setup problem matchers for PHP
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
- name: Validate composer.json
run: "composer validate --strict"
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer Dependencies
run: "composer install --prefer-dist --no-progress --optimize-autoloader"
- name: Run Static Analysis
run: "composer analyse"
- name: Run PHP CS Fixer Check
run: "./vendor/bin/php-cs-fixer fix --dry-run --diff"

View File

@@ -1,4 +1,4 @@
name: Docs Build
name: MkDocs Auto Deploy
on:
push:
branches:

1
.gitignore vendored
View File

@@ -13,6 +13,7 @@ composer.lock
/runtime/
/tmp/
/temp/
/site/
# go-cqhttp快速安装启动相关可能被废弃
/ext/go-cqhttp/data/

View File

@@ -65,7 +65,6 @@ return (new PhpCsFixer\Config())
'standardize_not_equals' => true,
'multiline_comment_opening_closing' => true,
'phpdoc_summary' => false,
'class_reference_name_casing' => false,
])
->setFinder(
PhpCsFixer\Finder::create()

View File

@@ -7,7 +7,7 @@
[![zhamao License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/zhamao-robot/zhamao-framework/blob/master/LICENSE)
[![Latest Stable Version](http://img.shields.io/packagist/v/zhamao/framework.svg)](https://packagist.org/packages/zhamao/framework)
[![Banner](https://img.shields.io/badge/OneBot-v11-success)](https://github.com/howmanybots/onebot)
![Build Actions](https://github.com/zhamao-robot/zhamao-framework/actions/workflows/main.yml/badge.svg)
![Integration Test](https://github.com/zhamao-robot/zhamao-framework/actions/workflows/integration-test.yml/badge.svg)
[![注解数量](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/AnnotationBase.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=AnnotationBase)
[![TODO 数量](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/TODO.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=TODO)
@@ -62,20 +62,15 @@ vendor/bin/start server
## 特点
- 原生为多账号设计,支持多个机器人负载均衡
- 使用 Swoole 多工作进程机制和协程加持,尽可能简单的情况下提升了性能
- 灵活的注解事件绑定机制
- 灵活的注解事件绑定机制,可兼容使用 PHP8 的 Attribute>=2.7 可用)
- 易用的上下文,模块内随处可用
- 采用模块化编写,可自由搭配其他 composer 组件
- 采用模块化编写,可自由搭配其他 composer 组件,也可单文件面向过程编写
- 常驻内存,全局缓存变量随处使用,提供多种缓存方案
- 自带 MySQL、Redis 等数据库连接池等数据库连接方案
- 本身为 HTTP 服务器、WebSocket 服务器,可以构建属于自己的 HTTP API 接口
- 静态文件服务器,可将前端合并到一起
- 自带 PHP + Swoole 环境无需手动编译安装by [crazywhalecc/static-php-cli](https://github.com/crazywhalecc/static-php-cli)
## 从 v1 升级
炸毛框架 v2 相对 v1 版本改动了不少内容,其中包括框架底层机制、注解事件分发、调试、命名空间等变化,详情可查看上方文档。
如果旧版框架使用过程中无问题且对新功能暂无需求,可以继续使用 v1 版本,后续也将维护安全类更新和修复致命 bug。
## 下载源码
框架源码可直接克隆本仓库进行编辑,如果你在国内,访问 GitHub 和 clone 仓库比较慢,可以将 `github.com` 替换为 `fgit.zhamao.me` 进行加速。
@@ -93,12 +88,10 @@ vendor/bin/start server
### 支付宝
![支付宝二维码](https://cdn.jsdelivr.net/gh/zhamao-robot/zhamao-framework/resources/images/alipay_img.jpg)
如果你对我们的周边感兴趣,我们还有炸毛机器人定制 logo 的雨伞,详情咨询作者 QQ我们会作为您捐助了本项目
## 关于
框架和 SDK 是 炸毛机器人 项目的核心框架开源部分。炸毛机器人是作者写的一个高性能机器人,曾获全国计算机设计大赛一等奖。
作者的炸毛机器人已从2018年初起稳定运行了**四年**,并且持续迭代。
作者的炸毛机器人已从2018年初起稳定运行了**四年**,并且持续迭代。
欢迎随时在 HTTP-API 插件群里提问,当然更好的话可以加作者 QQ[627577391](http://wpa.qq.com/msgrd?v=3&uin=627577391&site=qq&menu=yes))或提交 Issue 进行疑难解答。

View File

@@ -4,9 +4,11 @@
"minimum-stability": "stable",
"license": "Apache-2.0",
"extra": {
"exclude_annotate": [
"src/ZM"
],
"zm": {
"exclude-annotation-path": [
"src/ZM"
]
},
"hooks": {
"post-merge": "composer install",
"pre-commit": [
@@ -35,19 +37,19 @@
"php": "^7.2 || ^7.3 || ^7.4 || ^8.0 || ^8.1",
"ext-json": "*",
"ext-posix": "*",
"doctrine/annotations": "~1.12 || ~1.4.0",
"doctrine/dbal": "^2.13.1",
"jelix/version": "^2.0",
"koriym/attributes": "^1.0",
"psy/psysh": "^0.11.2",
"symfony/console": "~5.0 || ~4.0 || ~3.0",
"symfony/polyfill-ctype": "^1.19",
"symfony/polyfill-mbstring": "^1.19",
"symfony/console": "~5.0 || ~4.0 || ~3.0",
"symfony/polyfill-php80": "^1.16",
"symfony/routing": "~5.0 || ~4.0 || ~3.0",
"zhamao/console": "^1.0",
"zhamao/config": "^1.0",
"zhamao/request": "^1.1",
"zhamao/connection-manager": "^1.0",
"jelix/version": "^2.0",
"league/climate": "^3.6",
"psy/psysh": "@stable",
"doctrine/dbal": "^2.13.1"
"zhamao/console": "^1.0",
"zhamao/request": "^1.1"
},
"suggest": {
"ext-ctype": "Use C/C++ extension instead of polyfill will be more efficient",
@@ -75,11 +77,11 @@
"sort-packages": true
},
"require-dev": {
"swoole/ide-helper": "@dev",
"phpunit/phpunit": "^8.5 || ^9.0",
"brainmaestro/composer-git-hooks": "^2.8",
"friendsofphp/php-cs-fixer": "^3.2 != 3.7.0",
"phpstan/phpstan": "^1.1"
"phpstan/phpstan": "^1.1",
"phpunit/phpunit": "^8.5 || ^9.0",
"swoole/ide-helper": "^4.5"
},
"scripts": {
"post-install-cmd": [
@@ -88,4 +90,4 @@
"analyse": "phpstan analyse --memory-limit 300M -l 0 ./src",
"cs-fix": "php-cs-fixer fix $1"
}
}
}

View File

@@ -28,12 +28,12 @@ $config['crash_dir'] = $config['zm_data'] . 'crash/';
/* 对应swoole的server->set参数 */
$config['swoole'] = [
'log_file' => $config['crash_dir'] . 'swoole_error.log',
//'worker_num' => swoole_cpu_num(), //如果你只有一个 OneBot 实例连接到框架并且代码没有复杂的CPU密集计算则可把这里改为1使用全局变量
'dispatch_mode' => 2, //包分配原则,见 https://wiki.swoole.com/#/server/setting?id=dispatch_mode
// 'worker_num' => swoole_cpu_num(), //如果你只有一个 OneBot 实例连接到框架并且代码没有复杂的CPU密集计算则可把这里改为1使用全局变量
'dispatch_mode' => 2, // 包分配原则,见 https://wiki.swoole.com/#/server/setting?id=dispatch_mode
'max_coroutine' => 300000,
'max_wait_time' => 5,
//'task_worker_num' => 4,
//'task_enable_coroutine' => true
// 'task_worker_num' => 4,
// 'task_enable_coroutine' => true
];
/* 一些框架与框架运行时设置的调整 */
@@ -44,13 +44,19 @@ $config['runtime'] = [
'reload_delay_time' => 800,
'global_middleware_binding' => [],
'save_console_log_file' => false, // 改为目标路径,则将 Console 输出的日志保存到文件
'annotation_reader_ignore' => [ // 设置注解解析器忽略的注解名或命名空间,防止解析到不该解析的
'name' => [
'mixin',
],
'namespace' => [],
],
];
/* 轻量字符串缓存,默认开启 */
$config['light_cache'] = [
'size' => 512, //最多允许储存的条数需要2的倍数
'max_strlen' => 32768, //单行字符串最大长度需要2的倍数
'hash_conflict_proportion' => 0.6, //Hash冲突率越大越好但是需要的内存更多
'size' => 512, // 最多允许储存的条数需要2的倍数
'max_strlen' => 32768, // 单行字符串最大长度需要2的倍数
'hash_conflict_proportion' => 0.6, // Hash冲突率越大越好但是需要的内存更多
'persistence_path' => $config['zm_data'] . '_cache.json',
'auto_save_interval' => 900,
];
@@ -102,7 +108,7 @@ $config['http_default_code_page'] = [
/* zhamao-framework在框架启动时初始化的atomic们 */
$config['init_atomics'] = [
//'custom_atomic_name' => 0, //自定义添加的Atomic
// 'custom_atomic_name' => 0, //自定义添加的Atomic
];
/* 终端日志显示等级0-4 */

View File

@@ -0,0 +1,88 @@
# 接入青云客智能聊天机器人API
作为一个群聊机器人,懂得聊天会让机器人增色不少,在大数据和 AI 热潮下,不少厂商都研发了自己的智能聊天 API例如图灵机器人、腾讯智能闲聊等大厂开发的 API 自然有着他人无可比拟的健壮性和可靠性,但是随之而来不菲的价格显然并不适合大众开发者。这时候一个免费、可用的智能聊天 API 便非常重要了,其中,青云客是少有的完全免费、无需注册的智能聊天 API提供了包括智能聊天、歌词、天气查询、笑话等多种有用功能且接入简单非常适合新手开发者尝试。
## 结果演示
![圖片](https://user-images.githubusercontent.com/31698606/158875192-108698a3-b54e-4fc0-889a-0829ca328b13.png)
## 阅读接入指南
不管接入何种服务,阅读接入指南永远都是最优先、最重要的一步,所幸青云客的接入指南十分简单,简单来说归纳为以下:
* 请求GET https://api.qingyunke.com/api.php
* 参数:
* * `key` 目前固定为 `free`
* * `appid` 目前固定为 `0`
* * `msg` 关键词,需要经过 `urlencode`
* 注意:返回结果中 `{br}` 代表换行
## 逻辑编写
阅读过后,我们便可以进行主要的编写工作了。
首先,为了机器人的性能考虑,也为了避免过分打扰群聊的聊天,我们希望机器人只有在主动触发(@AT 或者 关键词等)时才会进行智能聊天。
对于关键词匹配,我们可以使用 `@CQCommand`
```php
/**
* 智能聊天
*
* @CQCommand(start_with="机器人")
*/
public function chat()
{
// 替换掉机器人前缀,并获取消息内容
$msg = ctx()->getMessage();
$msg = str_replace('机器人', '', $msg);
if (empty(trim($msg))) {
$msg = ctx()->getFullArg('怎么了?');
}
Console::info('正在获取智能聊天回复:' . $msg);
// 请求 API 获取回复
$raw_data = file_get_contents('https://api.qingyunke.com/api.php?key=free&appid=0&msg=' . urlencode($msg));
try {
$data = json_decode($raw_data, true, 512, JSON_THROW_ON_ERROR);
} catch (\Exception $e) {
$data = ['content' => '机器人解析异常,请稍后再试'];
Console::warning('无法获取智能聊天回复:' . $e->getMessage());
}
if ($data['result'] !== 0) {
$data = ['content' => '机器人服务异常,请稍后再试'];
Console::warning('无法获取智能聊天回复:' . $raw_data);
}
Console::info('获取智能聊天回复完成:' . $data['content']);
// 将 {br} 替换为换行
$data['content'] = strtr($data['content'], ['{br}' => "\n"]);
return $data['content'];
}
```
这样我们的命令便只会在用户发送以`机器人`开头的消息时才会触发。
同时,我们也希望在 @AT 机器人时也进行回复,此时可以使用 `@CQBefore` 方法进行折中:
```php
/**
* 将 AT 机器人的消息交由智能聊天处理
*
* @CQBefore("message")
*/
public function changeAt(): bool
{
// 判断此条消息是否 AT 了机器人
if (MessageUtil::isAtMe(ctx()->getMessage(), ctx()->getRobotId())) {
// 将 AT 本身从消息中去掉
$msg = str_replace(CQ::at(ctx()->getRobotId()), '', ctx()->getMessage());
ctx()->setMessage('机器人' . trim($msg));
// 调用智能聊天
ctx()->reply($this->chat());
return false;
}
return true;
}
```

View File

@@ -0,0 +1,112 @@
# 基于词性分析和魅族天气的天气查询机器人
本文将基于 [`jieba-php`](https://github.com/fukuball/jieba-php) 中文分词库以及 [魅族天气 API](https://github.com/shichunlei/-Api/blob/master/MeizuWeather.md) 开发一个天气查询机器人。
## 结果演示
![圖片](https://user-images.githubusercontent.com/31698606/159122016-61ba9696-5786-4561-b371-827d9f1d01aa.png)
尾部的随机表情并非本教程的一部分。
## 逻辑编写
[`jieba-php`](https://github.com/fukuball/jieba-php) 是目前比较好用的中文分词库,虽然最近的维护并不活跃,但已足够我们的需求:
```shell
composer require fukuball/jieba-php:dev-master
```
以下代码使用了本文作者自行编写的天气查询库,需要进行引入:
```shell
composer require sunxyw/weather
```
您也可以将以下代码自行改写为直接调用魅族天气 API详情请参阅[魅族天气 API 文档](https://github.com/shichunlei/-Api/blob/master/MeizuWeather.md)。
```php
<?php
namespace Bot\Module\SmartChat;
use Fukuball\Jieba\Jieba;
use Fukuball\Jieba\Posseg;
use Sunxyw\Weather\Weather;
use ZM\Annotation\CQ\CQCommand;
use ZM\Console\Console;
class WeatherReport
{
/**
* 加载字典
*
* @OnStart(worker_id=-1)
*
* @return void
*/
public function initDictionary(): void
{
// 分词以及词性分析需要载入字典到内存
ini_set('memory_limit', '600M');
Jieba::init(['dict' => 'small']);
Posseg::init();
}
/**
* 查询天气
*
* @CQCommand(keyword="天气")
*
* @return string
*/
public function cmdQueryWeather(): string
{
// 分词并进行词性分析
$seg_list = Posseg::cut(ctx()->getMessage());
$tags = array_column($seg_list, 'tag');
// 找出词性为 ns地名的单词
$location_index = array_search('ns', $tags, true);
$location = $seg_list[$location_index]['word'];
// 此处引入了本文作者自己写的天气库
$w = new Weather();
try {
$report = $w->getWeather($location);
} catch (\InvalidArgumentException) {
return '城市输入错误';
} catch (\JsonException $e) {
Console::warning("天气查询失败:{$e->getMessage()}");
return '天气查询失败';
}
$template = <<<EOF
%s天气%s
温度:%s℃
湿度:%s%%
风向:%s %s
空气质量:%s
------------------------------
未来三天天气:
%s%s日间%s℃夜间%s℃吹%s %s
%s%s日间%s℃夜间%s℃吹%s %s
%s%s日间%s℃夜间%s℃吹%s %s
EOF;
$args = [
$report->getCity(),
$report->getRealtime()['weather'],
$report->getRealtime()['temperature'],
$report->getRealtime()['humidity'],
$report->getRealtime()['wind_direction'],
$report->getRealtime()['wind_speed'],
$report->getRealtime()['air_quality'],
];
foreach (array_slice($report->getForecastDaily(), 0, 3) as $forecast) {
$args[] = $forecast['date'];
$args[] = $forecast['weather'];
$args[] = $forecast['temperature']['day'];
$args[] = $forecast['temperature']['night'];
$args[] = $forecast['wind_direction'];
$args[] = $forecast['wind_speed'];
}
return vsprintf($template, ...$args);
}
}
```

View File

@@ -0,0 +1 @@
.hljs{display:block;overflow-x:auto;padding:.5em;background:#f0f0f0}.hljs,.hljs-subst{color:#444}.hljs-comment{color:#888}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#bc6060}.hljs-literal{color:#78a960}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

View File

@@ -56,7 +56,8 @@ src/
```json
{
"name": "my-first-module",
"description": "这个是一个示例模块打包教程"
"description": "这个是一个示例模块打包教程",
"version": "1.0.0"
}
```

View File

@@ -71,5 +71,8 @@
| E00069 | 框架不能启动两个 ConsoleApplication 实例 | 不要重复使用 `new ConsoleApplication()`。 |
| E00070 | 框架找不到 `zm_data` 目录 | 检查配置中指定的 `zm_data` 目录是否存在。 |
| E00071 | 框架找不到对应类型的 API 调用类 | 检查 `getExtendedAPI($name)` 传入的 `$name` 是否正确 |
| E00072 | 上下文无法找到 | 检查上下文环境,如是否处于协程环境中 |
| E00073 | 在类中找不到方法 | 检查调用对象是否存在对应的方法method或检查是否插入了对应的macro宏方法 |
| E00074 | 参数非法 | 检查调用的参数是否正常(此处可能有多处问题,请看具体调用栈炸掉的地方) |
| E99999 | 未知错误 | |

View File

@@ -49,20 +49,22 @@ docker run -it --rm -v $(pwd):/app/ -p 20001:20001 zmbot/swoole vendor/bin/start
```verilog
$ vendor/bin/start server
host: 0.0.0.0 | port: 20001
log_level: 2 | version: 2.0.0
config: global.php | worker_num: 4
working_dir: /app/zhamao-framework
______
|__ / |__ __ _ _ __ ___ __ _ ___
/ /| '_ \ / _` | '_ ` _ \ / _` |/ _ \
/ /_| | | | (_| | | | | | | (_| | (_) |
/____|_| |_|\__,_|_| |_| |_|\__,_|\___/
=================================================================
working_dir: /app/zhamao-framework-starter
listen: 0.0.0.0:20001 | worker: 4 (auto)
environment: default | log_level: 2
version: 2.7.0 | master_pid: 28449
=================================================================
______
|__ / |__ __ _ _ __ ___ __ _ ___
/ /| '_ \ / _` | '_ ` _ \ / _` |/ _ \
/ /_| | | | (_| | | | | | | (_| | (_) |
/____|_| |_|\__,_|_| |_| |_|\__,_|\___/
[14:27:31] [S] [#3] Worker #3
[14:27:31] [S] [#0] Worker #0
[14:27:31] [S] [#2] Worker #2
[14:27:31] [S] [#1] Worker #1
[03-20 22:30:56] [S] [#1] Worker #1 started
[03-20 22:30:56] [S] [#2] Worker #2 started
[03-20 22:30:56] [S] [#3] Worker #3 started
[03-20 22:30:56] [S] [#0] Worker #0 started
```
单纯运行 炸毛框架 后,如果不部署或安装启动任何机器人客户端的话,仅仅相当于启动了一个 监听 20001 端口的WebSoket + HTTP 服务器。你可以通过浏览器访问http://127.0.0.1:20001 ,或者你部署到了服务器后需要输入服务器地址。

File diff suppressed because one or more lines are too long

View File

@@ -4,6 +4,72 @@
同时此处将只使用 build 版本号进行区分。
## build 448 (2022-3-20)
- 加快 build 命令的执行速度,取消进度条和提升性能
## build 447 (2022-3-20)
- 发布 2.7.0 正式版
## build 446 (2022-3-20)
- 新增 `./zhamao server` 下的 `--no-state-check` 参数,关闭“启动框架前的运行状态检查”功能
## build 445 (2022-3-20)
- 新增配置项 `runtime`.`annotation_reader_ignore`:支持注解解析器忽略注解的自定义
## build 444 (2022-3-20)
- 更改 `extra`.`exclude_annotate``zm`.`exclude-annotation-path`
## build 443 (2022-3-20)
- 修复注释空格的样式
## build 442 (2022-3-20)
- 修复打包模块后 `files` 的 autoload 项不能被解压和引入的 Bug
## build 441 (2022-3-20)
- 修复打包模块时命名空间与实际不一致的 Bug
## build 440 (2022-3-20)
- 新增方法宏Macroable
## build 439 (2022-3-19)
- 新增 PHP 8 Attribute 与注解同时支持的特性
## build 438 (2022-3-18)
- 修复 Response 类在 PHP 8.1 环境下的报错
## build 437 (2022-3-17)
- 修复 `ctx()` 可能会返回 null 的 Bug
## build 436 (2022-3-15)
- 新增 PHPStan 和 PHP CS Fixer 并优化全局代码
## build 435 (2022-3-13)
- 优化分离 WorkerManager 与 ProcessManager 的职责
- 新增 Ctrl+C 一次无法停止框架时多次 Ctrl+C 后可强行杀掉所有进程的功能
- `./zhamao server:stop` 新增参数 `--force`,使用 `SIGKILL` 强行杀掉所有进程
- 新增 AnnotationParser 对 `autoload-dev` 项中的 `psr-4` 默认检索条件
- 新增框架启动状态检测功能,如果已经启动了同样目录的框架,则会报错
- 新增“强制启用轮询模式启动热更新”功能(参数 `--polling-watch`
- 修复与 PHP 8.1 的兼容性
- 对 DaemonCommand 进行优化,与 ServerCommand 效果相同
- 修复 `autoload`.`psr-4` 不存在时报错的 Bug
- 新增框架停止时 Worker 退出回显状态码
- 新增 inotify 判断模式,如果使用 `--watch` 检测到没有安装 inotify则自动使用轮询模式
## build 434 (2022-1-8)
- 修复框架在 PHP 8.1 下运行时的一些问题

View File

@@ -2,6 +2,10 @@
这里将会记录各个主版本的框架升级后,涉及 `global.php` 的更新日志,你可以根据这里描述的内容与你的旧配置文件进行合并。
## v2.7.0 (build 447)
- 新增 `$config['runtime']` 下的 `annotation_reader_ignore` 项。
## v2.6.6 (build 434)
- 新增 `$config['runtime']` 下的 `save_console_log_file` 项。

View File

@@ -1,5 +1,38 @@
# 更新日志v2 版本)
## v2.7.1build 448
> 更新时间2022.3.20
- 加快 build 命令的执行速度,取消进度条和提升性能
## v2.7.0build 447
> 更新时间2022.3.20
- 优化分离 WorkerManager 与 ProcessManager 的职责
- 新增 Ctrl+C 一次无法停止框架时多次 Ctrl+C 后可强行杀掉所有进程的功能
- `./zhamao server:stop` 新增参数 `--force`,使用 `SIGKILL` 强行杀掉所有进程
- 新增 AnnotationParser 对 `autoload-dev` 项中的 `psr-4` 默认检索条件
- 新增框架启动状态检测功能,如果已经启动了同样目录的框架,则会报错
- 新增“强制启用轮询模式启动热更新”功能(参数 `--polling-watch`
- 修复与 PHP 8.1 的兼容性
- 对 DaemonCommand 进行优化,与 ServerCommand 效果相同
- 修复 `autoload`.`psr-4` 不存在时报错的 Bug
- 新增框架停止时 Worker 退出回显状态码
- 新增 inotify 判断模式,如果使用 `--watch` 检测到没有安装 inotify则自动使用轮询模式
- 新增 PHPStan 和 PHP CS Fixer 并优化全局代码
- 修复 `ctx()` 可能会返回 null 的 Bug
- 修复 Response 类在 PHP 8.1 环境下的报错
- 新增 PHP 8 Attribute 与注解同时支持的特性
- 新增方法宏Macroable
- 修复打包模块时命名空间与实际不一致的 Bug
- 修复打包模块后 `files` 的 autoload 项不能被解压和引入的 Bug
- 修复注释空格的样式
- 更改 `extra`.`exclude_annotate``zm`.`exclude-annotation-path`
- 新增配置项 `runtime`.`annotation_reader_ignore`:支持注解解析器忽略注解的自定义
- 新增 `./zhamao server` 下的 `--no-state-check` 参数,关闭“启动框架前的运行状态检查”功能
## v2.6.6build 434
> 更新时间2022.1.8

View File

@@ -16,11 +16,11 @@ theme:
- navigation.tabs
- navigation.sections
extra_javascript:
- https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js
- javascripts/library/highlight.min.js
- javascripts/config.js
extra_css:
- assets/css/extra.css
- https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/default.min.css
- assets/css/library/default.min.css
plugins:
- search:
lang: ja
@@ -39,7 +39,7 @@ extra:
version:
provider: mike
copyright: 'Copyright &copy; 2019 - 2021 CrazyBot Team&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tx-switch">
copyright: 'Copyright &copy; 2019 - 2022 CrazyBot Team&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="tx-switch">
<button data-md-color-scheme="default"><code>默认模式</code></button>
<button data-md-color-scheme="slate"><code>暗黑模式</code></button>
</span>
@@ -106,7 +106,7 @@ nav:
- Console 终端: component/common/console.md
- TaskWorker 管理: component/common/task-worker.md
- Terminal 终端: component/common/remote-terminal.md
- EventTracer 事件追踪器: component/comon/event-tracer.md
- EventTracer 事件追踪器: component/common/event-tracer.md
- HTTP 服务器工具类:
- HTTP 和 WebSocket 客户端: component/http/zmrequest.md
- HTTP 路由管理: component/http/route-manager.md
@@ -125,6 +125,8 @@ nav:
- 开发实战教程:
- 接入 WebSocket 客户端: advanced/connect-ws-client.md
- 编写管理员才能触发的功能: advanced/example/admin.md
- 接入青云客聊天API: advanced/example/integrate-qingyunke-chatbot.md
- 开发天气机器人: advanced/example/weather-bot.md
- FAQ:
- FAQ: faq/FAQ.md
- 从 v1 升级: faq/to-v2.md

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Custom\Annotation;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
use ZM\Annotation\Interfaces\CustomAnnotation;
@@ -11,10 +13,17 @@ use ZM\Annotation\Interfaces\CustomAnnotation;
/**
* Class CustomAnnotation
* @Annotation
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
class Example extends AnnotationBase implements CustomAnnotation
{
/** @var string */
public $str = '';
public function __construct($str = '')
{
$this->str = $str;
}
}

View File

@@ -34,9 +34,9 @@ class Hello
* 默认的图片监听路由对应目录,如需要使用可取消下面的注释,把上面的 /* 换成 /**
* @OnStart(-1)
*/
//public function onStart() {
// public function onStart() {
// \ZM\Http\RouteManager::addStaticFileRoute("/images/", \ZM\Utils\DataProvider::getWorkingDir()."/zm_data/images/");
//}
// }
/**
* 使用命令 .reload 发给机器人远程重载,注意将 user_id 换成你自己的 QQ
@@ -98,7 +98,7 @@ class Hello
$api = ''; // 请在这里填入你的图灵机器人的apikey
if ($api === '') {
return false;
} //如果没有填入apikey则此功能关闭
} // 如果没有填入apikey则此功能关闭
if (($this->_running_annotation ?? null) instanceof CQCommand) {
$msg = ctx()->getFullArg('我在!有什么事吗?');
} else {
@@ -109,7 +109,7 @@ class Hello
return TuringAPI::getTuringMsg($msg, $user_id, $api);
}
QQBot::getInstance()->handle(ctx()->getData(), ctx()->getCache('level') + 1);
//执行嵌套消息,递归层级+1
// 执行嵌套消息,递归层级+1
return true;
}

View File

@@ -19,14 +19,14 @@ class TuringAPI
public static function getTuringMsg($msg, $user_id, $api)
{
$origin = $msg;
if (($cq = CQ::getCQ($msg)) !== null) {//如有CQ码则去除
if (($cq = CQ::getCQ($msg)) !== null) {// 如有CQ码则去除
if ($cq['type'] == 'image') {
$url = $cq['params']['url'];
$msg = str_replace(mb_substr($msg, $cq['start'], $cq['end'] - $cq['start'] + 1), '', $msg);
}
$msg = trim($msg);
}
//构建将要发送的json包给图灵
// 构建将要发送的json包给图灵
$content = [
'reqType' => 0,
'userInfo' => [
@@ -64,11 +64,11 @@ class TuringAPI
return '哎呀,我刚才有点走神了,可能忘记你说什么了,可以重说一遍吗';
}
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 '哎呀,我刚才有点走神了,要不一会儿换一种问题试试?';
}
$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 = '';
foreach ($result as $v) {
switch ($v['resultType']) {

View File

@@ -8,9 +8,9 @@ use Closure;
abstract class AnnotationBase
{
public $method;
public $method = '';
public $class;
public $class = '';
public function __toString()
{

View File

@@ -5,6 +5,8 @@ declare(strict_types=1);
namespace ZM\Annotation;
use Doctrine\Common\Annotations\AnnotationReader;
use Koriym\Attributes\AttributeReader;
use Koriym\Attributes\DualReader;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
@@ -46,7 +48,7 @@ class AnnotationParser
public function __construct()
{
$this->start_time = microtime(true);
//$this->loadAnnotationClasses();
// $this->loadAnnotationClasses();
$this->req_mapping[0] = [
'id' => 0,
'pid' => -1,
@@ -63,15 +65,27 @@ class AnnotationParser
foreach ($this->path_list as $path) {
Console::debug('parsing annotation in ' . $path[0] . ':' . $path[1]);
$all_class = ZMUtil::getClassesPsr4($path[0], $path[1]);
$this->reader = new AnnotationReader();
$conf = ZMConfig::get('global', 'runtime')['annotation_reader_ignore'] ?? [];
if (isset($conf['name']) && is_array($conf['name'])) {
foreach ($conf['name'] as $v) {
AnnotationReader::addGlobalIgnoredName($v);
}
}
if (isset($conf['namespace']) && is_array($conf['namespace'])) {
foreach ($conf['namespace'] as $v) {
AnnotationReader::addGlobalIgnoredNamespace($v);
}
}
AnnotationReader::addGlobalIgnoredName('mixin');
$this->reader = new DualReader(new AnnotationReader(), new AttributeReader());
foreach ($all_class as $v) {
Console::debug('正在检索 ' . $v);
$reflection_class = new ReflectionClass($v);
$methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC);
$class_annotations = $this->reader->getClassAnnotations($reflection_class);
// 这段为新加的:start
//这里将每个类里面所有的类注解、方法注解通通加到一颗大树上,后期解析
// 这里将每个类里面所有的类注解、方法注解通通加到一颗大树上,后期解析
/*
$annotation_map: {
Module\Example\Hello: {
@@ -99,7 +113,7 @@ class AnnotationParser
foreach ($this->annotation_map[$v]['class_annotations'] as $vs) {
$vs->class = $v;
//预处理1将适用于每一个函数的注解到类注解重新注解到每个函数下面
// 预处理1将适用于每一个函数的注解到类注解重新注解到每个函数下面
if ($vs instanceof ErgodicAnnotation) {
foreach (($this->annotation_map[$v]['methods'] ?? []) as $method) {
$copy = clone $vs;
@@ -108,13 +122,13 @@ class AnnotationParser
}
}
//预处理2处理 class 下面的注解
// 预处理2处理 class 下面的注解
if ($vs instanceof Closed) {
unset($this->annotation_map[$v]);
continue 2;
}
if ($vs instanceof MiddlewareClass) {
//注册中间件本身的类,标记到 middlewares 属性中
// 注册中间件本身的类,标记到 middlewares 属性中
Console::debug('正在注册中间件 ' . $reflection_class->getName());
$rs = $this->registerMiddleware($vs, $reflection_class);
$this->middlewares[$rs['name']] = $rs;
@@ -123,7 +137,7 @@ class AnnotationParser
$inserted = [];
//预处理3处理每个函数上面的特殊注解就是需要操作一些东西的
// 预处理3处理每个函数上面的特殊注解就是需要操作一些东西的
foreach (($this->annotation_map[$v]['methods_annotations'] ?? []) as $method_name => $methods_annotations) {
foreach ($methods_annotations as $method_anno) {
/* @var AnnotationBase $method_anno */
@@ -133,8 +147,7 @@ class AnnotationParser
if (!isset($inserted[$v][$method_name])) {
// 在这里在其他中间件前插入插入全局的中间件
foreach ($middlewares as $middleware) {
$mid_class = new Middleware();
$mid_class->middleware = $middleware;
$mid_class = new Middleware($middleware);
$mid_class->class = $v;
$mid_class->method = $method_name;
$this->middleware_map[$v][$method_name][] = $mid_class;
@@ -223,7 +236,7 @@ class AnnotationParser
public function verifyMiddlewares()
{
if ((ZMConfig::get('global', 'runtime')['middleware_error_policy'] ?? 1) === 2) {
//我承认套三层foreach很不优雅但是这个会很快的。
// 我承认套三层foreach很不优雅但是这个会很快的。
foreach ($this->middleware_map as $v) {
foreach ($v as $vs) {
foreach ($vs as $mid) {
@@ -241,7 +254,7 @@ class AnnotationParser
return microtime(true) - $this->start_time;
}
//private function below
// private function below
private function registerMiddleware(MiddlewareClass $vs, ReflectionClass $reflection_class): array
{

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\CQ;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -11,8 +13,10 @@ use ZM\Annotation\AnnotationBase;
/**
* Class CQAPIResponse
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class CQAPIResponse extends AnnotationBase
{
/**
@@ -20,4 +24,9 @@ class CQAPIResponse extends AnnotationBase
* @Required()
*/
public $retcode;
public function __construct($retcode)
{
$this->retcode = $retcode;
}
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\CQ;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
use ZM\Annotation\Interfaces\Level;
@@ -11,8 +13,10 @@ use ZM\Annotation\Interfaces\Level;
/**
* Class CQAfter
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class CQAfter extends AnnotationBase implements Level
{
/**
@@ -23,6 +27,12 @@ class CQAfter extends AnnotationBase implements Level
public $level = 20;
public function __construct($cq_event, $level = 20)
{
$this->cq_event = $cq_event;
$this->level = $level;
}
/**
* @return mixed
*/

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\CQ;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -12,8 +14,10 @@ use ZM\Annotation\Interfaces\Level;
/**
* Class CQBefore
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class CQBefore extends AnnotationBase implements Level
{
/**
@@ -24,6 +28,12 @@ class CQBefore extends AnnotationBase implements Level
public $level = 20;
public function __construct($cq_event, $level = 20)
{
$this->cq_event = $cq_event;
$this->level = $level;
}
/**
* @return mixed
*/

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\CQ;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
use ZM\Annotation\Interfaces\Level;
@@ -11,8 +13,10 @@ use ZM\Annotation\Interfaces\Level;
/**
* Class CQCommand
* @Annotation
* @NamedArgumentConstructor
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
class CQCommand extends AnnotationBase implements Level
{
/** @var string */
@@ -51,6 +55,22 @@ class CQCommand extends AnnotationBase implements Level
/** @var int */
public $level = 20;
public function __construct($match = '', $pattern = '', $regex = '', $start_with = '', $end_with = '', $keyword = '', $alias = [], $message_type = '', $user_id = 0, $group_id = 0, $discuss_id = 0, $level = 20)
{
$this->match = $match;
$this->pattern = $pattern;
$this->regex = $regex;
$this->start_with = $start_with;
$this->end_with = $end_with;
$this->keyword = $keyword;
$this->alias = $alias;
$this->message_type = $message_type;
$this->user_id = $user_id;
$this->group_id = $group_id;
$this->discuss_id = $discuss_id;
$this->level = $level;
}
public function getLevel(): int
{
return $this->level;

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\CQ;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
use ZM\Annotation\Interfaces\Level;
@@ -11,8 +13,10 @@ use ZM\Annotation\Interfaces\Level;
/**
* Class CQMessage
* @Annotation
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
class CQMessage extends AnnotationBase implements Level
{
/**
@@ -38,6 +42,17 @@ class CQMessage extends AnnotationBase implements Level
/** @var int */
public $level = 20;
public function __construct($message_type = '', $user_id = 0, $group_id = 0, $discuss_id = 0, $message = '', $raw_message = '', $level = 20)
{
$this->message_type = $message_type;
$this->user_id = $user_id;
$this->group_id = $group_id;
$this->discuss_id = $discuss_id;
$this->message = $message;
$this->raw_message = $raw_message;
$this->level = $level;
}
public function getLevel(): int
{
return $this->level;

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\CQ;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -12,18 +14,26 @@ use ZM\Annotation\Interfaces\Level;
/**
* Class CQMetaEvent
* @Annotation
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
class CQMetaEvent extends AnnotationBase implements Level
{
/**
* @var string
* @Required()
*/
public $meta_event_type = '';
public $meta_event_type;
/** @var int */
public $level;
public $level = 20;
public function __construct($meta_event_type, $level = 20)
{
$this->meta_event_type = $meta_event_type;
$this->level = $level;
}
/**
* @return mixed

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\CQ;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
use ZM\Annotation\Interfaces\Level;
@@ -11,8 +13,10 @@ use ZM\Annotation\Interfaces\Level;
/**
* Class CQNotice
* @Annotation
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
class CQNotice extends AnnotationBase implements Level
{
/** @var string */
@@ -30,6 +34,15 @@ class CQNotice extends AnnotationBase implements Level
/** @var int */
public $level = 20;
public function __construct($notice_type = '', $sub_type = '', $group_id = 0, $operator_id = 0, $level = 20)
{
$this->notice_type = $notice_type;
$this->sub_type = $sub_type;
$this->group_id = $group_id;
$this->operator_id = $operator_id;
$this->level = $level;
}
public function getLevel(): int
{
return $this->level;

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\CQ;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
use ZM\Annotation\Interfaces\Level;
@@ -11,8 +13,10 @@ use ZM\Annotation\Interfaces\Level;
/**
* Class CQRequest
* @Annotation
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
class CQRequest extends AnnotationBase implements Level
{
/** @var string */
@@ -30,6 +34,15 @@ class CQRequest extends AnnotationBase implements Level
/** @var int */
public $level = 20;
public function __construct($request_type = '', $sub_type = '', $user_id = 0, $comment = '', $level = 20)
{
$this->request_type = $request_type;
$this->sub_type = $sub_type;
$this->user_id = $user_id;
$this->comment = $comment;
$this->level = $level;
}
public function getLevel(): int
{
return $this->level;

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\Command;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -11,8 +13,10 @@ use ZM\Annotation\AnnotationBase;
/**
* Class TerminalCommand
* @Annotation
* @NamedArgumentConstructor
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class TerminalCommand extends AnnotationBase
{
/**
@@ -27,4 +31,11 @@ class TerminalCommand extends AnnotationBase
* @var string
*/
public $description = '';
public function __construct($command, $alias = '', $description = '')
{
$this->command = $command;
$this->alias = $alias;
$this->description = $description;
}
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\Http;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -12,8 +14,10 @@ use ZM\Annotation\Interfaces\ErgodicAnnotation;
/**
* Class Controller
* @Annotation
* @NamedArgumentConstructor()
* @Target("CLASS")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
class Controller extends AnnotationBase implements ErgodicAnnotation
{
/**
@@ -21,4 +25,9 @@ class Controller extends AnnotationBase implements ErgodicAnnotation
* @Required()
*/
public $prefix = '';
public function __construct(string $prefix)
{
$this->prefix = $prefix;
}
}

View File

@@ -4,14 +4,18 @@ declare(strict_types=1);
namespace ZM\Annotation\Http;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class HandleAfter
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class HandleAfter extends AnnotationBase
{
}

View File

@@ -4,14 +4,18 @@ declare(strict_types=1);
namespace ZM\Annotation\Http;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class HandleBefore
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class HandleBefore extends AnnotationBase
{
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\Http;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use Exception;
use ZM\Annotation\AnnotationBase;
@@ -11,12 +13,19 @@ use ZM\Annotation\AnnotationBase;
/**
* Class HandleException
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class HandleException extends AnnotationBase
{
/**
* @var string
*/
public $class_name = Exception::class;
public function __construct($class_name = Exception::class)
{
$this->class_name = $class_name;
}
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\Http;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -12,8 +14,10 @@ use ZM\Annotation\Interfaces\ErgodicAnnotation;
/**
* Class Middleware
* @Annotation
* @NamedArgumentConstructor()
* @Target("ALL")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
class Middleware extends AnnotationBase implements ErgodicAnnotation
{
/**
@@ -26,4 +30,10 @@ class Middleware extends AnnotationBase implements ErgodicAnnotation
* @var string[]
*/
public $params = [];
public function __construct($middleware, $params = [])
{
$this->middleware = $middleware;
$this->params = $params;
}
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\Http;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -11,8 +13,10 @@ use ZM\Annotation\AnnotationBase;
/**
* Class MiddlewareClass
* @Annotation
* @NamedArgumentConstructor()
* @Target("CLASS")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
class MiddlewareClass extends AnnotationBase
{
/**
@@ -20,4 +24,9 @@ class MiddlewareClass extends AnnotationBase
* @Required()
*/
public $name = '';
public function __construct($name)
{
$this->name = $name;
}
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\Http;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -11,8 +13,10 @@ use ZM\Annotation\AnnotationBase;
/**
* Class RequestMapping
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class RequestMapping extends AnnotationBase
{
/**
@@ -36,4 +40,12 @@ class RequestMapping extends AnnotationBase
* @var array
*/
public $params = [];
public function __construct($route, $name = '', $request_method = [RequestMethod::GET, RequestMethod::POST], $params = [])
{
$this->route = $route;
$this->name = $name;
$this->request_method = $request_method;
$this->params = $params;
}
}

View File

@@ -4,13 +4,19 @@ declare(strict_types=1);
namespace ZM\Annotation\Http;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class RequestMethod
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class RequestMethod extends AnnotationBase
{
public const GET = 'GET';
@@ -32,4 +38,9 @@ class RequestMethod extends AnnotationBase
* @Required()
*/
public $method = self::GET;
public function __construct($method)
{
$this->method = $method;
}
}

View File

@@ -4,14 +4,18 @@ declare(strict_types=1);
namespace ZM\Annotation\Module;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class Closed
* @Annotation
* @NamedArgumentConstructor()
* @Target("CLASS")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
class Closed extends AnnotationBase
{
}

View File

@@ -4,17 +4,28 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
* Class OnCloseEvent
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnCloseEvent extends OnSwooleEventBase
{
/**
* @var string
*/
public $connect_type = 'default';
public function __construct($connect_type = 'default', $rule = '', $level = 20)
{
$this->connect_type = $connect_type;
$this->rule = $rule;
$this->level = $level;
}
}

View File

@@ -4,13 +4,22 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
* @since 2.7.0
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnManagerStartEvent extends OnSwooleEventBase
{
public function __construct($rule = '', $level = 20)
{
$this->rule = $rule;
$this->level = $level;
}
}

View File

@@ -4,17 +4,28 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @Target("METHOD")
* @NamedArgumentConstructor()
* Class OnMessageEvent
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnMessageEvent extends OnSwooleEventBase
{
/**
* @var string
*/
public $connect_type = 'default';
public function __construct($connect_type = 'default', $rule = '', $level = 20)
{
$this->connect_type = $connect_type;
$this->rule = $rule;
$this->level = $level;
}
}

View File

@@ -4,17 +4,28 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
* Class OnOpenEvent
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnOpenEvent extends OnSwooleEventBase
{
/**
* @var string
*/
public $connect_type = 'default';
public function __construct($connect_type = 'default', $rule = '', $level = 20)
{
$this->connect_type = $connect_type;
$this->rule = $rule;
$this->level = $level;
}
}

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -11,8 +13,10 @@ use ZM\Annotation\AnnotationBase;
/**
* Class OnPipeMessageEvent
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnPipeMessageEvent extends AnnotationBase
{
/**
@@ -20,4 +24,9 @@ class OnPipeMessageEvent extends AnnotationBase
* @Required()
*/
public $action;
public function __construct($action)
{
$this->action = $action;
}
}

View File

@@ -4,13 +4,22 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
* Class OnRequestEvent
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnRequestEvent extends OnSwooleEventBase
{
public function __construct($rule = '', $level = 20)
{
$this->rule = $rule;
$this->level = $level;
}
}

View File

@@ -4,14 +4,18 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class OnSave
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnSave extends AnnotationBase
{
}

View File

@@ -4,14 +4,18 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class ZMSetup
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnSetup extends AnnotationBase
{
}

View File

@@ -4,18 +4,27 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
/**
* Class OnWorkerStart
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnStart extends AnnotationBase
{
/**
* @var int
*/
public $worker_id = 0;
public function __construct($worker_id = 0)
{
$this->worker_id = $worker_id;
}
}

View File

@@ -4,14 +4,18 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* Class OnSwooleEvent
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnSwooleEvent extends OnSwooleEventBase
{
/**
@@ -20,6 +24,13 @@ class OnSwooleEvent extends OnSwooleEventBase
*/
public $type;
public function __construct($type, $rule = '', $level = 20)
{
$this->type = $type;
$this->rule = $rule;
$this->level = $level;
}
public function getType(): string
{
return $this->type;

View File

@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -12,8 +14,10 @@ use ZM\Annotation\Interfaces\Rule;
/**
* Class OnTask
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnTask extends AnnotationBase implements Rule
{
/**
@@ -27,6 +31,12 @@ class OnTask extends AnnotationBase implements Rule
*/
public $rule = '';
public function __construct($task_name, $rule = '')
{
$this->task_name = $task_name;
$this->rule = $rule;
}
/**
* @return mixed
*/

View File

@@ -4,13 +4,22 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Attribute;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* Class OnTaskEvent
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class OnTaskEvent extends OnSwooleEventBase
{
public function __construct($rule = '', $level = 20)
{
$this->rule = $rule;
$this->level = $level;
}
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -11,6 +12,7 @@ use ZM\Annotation\AnnotationBase;
/**
* Class OnTick
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
* @since 1.2
*/
@@ -26,4 +28,10 @@ class OnTick extends AnnotationBase
* @var int
*/
public $worker_id = 0;
public function __construct($tick_ms, $worker_id = 0)
{
$this->tick_ms = $tick_ms;
$this->worker_id = $worker_id;
}
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ZM\Annotation\Swoole;
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
@@ -11,6 +12,7 @@ use ZM\Annotation\AnnotationBase;
/**
* Class SwooleHandler
* @Annotation
* @NamedArgumentConstructor()
* @Target("ALL")
*/
class SwooleHandler extends AnnotationBase
@@ -20,4 +22,13 @@ class SwooleHandler extends AnnotationBase
* @Required()
*/
public $event;
/** @var string */
public $params = '';
public function __construct($event, $params = '')
{
$this->event = $event;
$this->params = $params;
}
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace ZM\Command;
use ArrayIterator;
use League\CLImate\CLImate;
use Phar;
use Symfony\Component\Console\Command\Command;
@@ -66,7 +67,6 @@ class BuildCommand extends Command
@unlink($target_dir . $filename);
$phar = new Phar($target_dir . $filename);
$phar->startBuffering();
$climate = new CLImate();
$all = DataProvider::scanDirFiles(DataProvider::getSourceRootDir(), true, true);
@@ -76,19 +76,29 @@ class BuildCommand extends Command
});
sort($all);
$progress = $climate->progress()->total(count($all));
$archive_dir = DataProvider::getSourceRootDir();
foreach ($all as $k => $v) {
$phar->addFile($archive_dir . '/' . $v, $v);
$progress->current($k + 1, 'Adding ' . $v);
}
$map = [];
if (class_exists('\\League\\CLImate\\CLImate')) {
$climate = new CLImate();
$progress = $climate->progress()->total(count($all));
}
foreach ($all as $k => $v) {
$map[$v] = $archive_dir . '/' . $v;
if (isset($progress)) {
$progress->current($k + 1, 'Adding ' . $v);
}
}
$this->output->write('<info>Building...</info>');
$phar->buildFromIterator(new ArrayIterator($map));
$phar->setStub(
"#!/usr/bin/env php\n" .
$phar->createDefaultStub(LOAD_MODE == 0 ? 'src/entry.php' : 'vendor/zhamao/framework/src/entry.php')
);
$phar->stopBuffering();
$this->output->writeln('');
$this->output->writeln('Successfully built. Location: ' . $target_dir . "{$filename}");
$this->output->writeln('<info>You may use `chmod +x server.phar` to let phar executable with `./` command</info>');
}
}

View File

@@ -91,7 +91,7 @@ class InitCommand extends Command
$output->writeln('<info>Done!</info>');
return 0;
}
if (LOAD_MODE === 2) { //从phar启动的框架包初始化的模式
if (LOAD_MODE === 2) { // 从phar启动的框架包初始化的模式
$phar_link = new Phar(__DIR__);
$current_dir = pathinfo($phar_link->getPath())['dirname'];
chdir($current_dir);

View File

@@ -32,7 +32,7 @@ class ModuleListCommand extends Command
exit(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");
}
//定义常量
// 定义常量
/** @noinspection PhpIncludeInspection */
include_once DataProvider::getFrameworkRootDir() . '/src/ZM/global_defines.php';

View File

@@ -36,7 +36,7 @@ class ModulePackCommand extends Command
exit(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");
}
//定义常量
// 定义常量
include_once DataProvider::getFrameworkRootDir() . '/src/ZM/global_defines.php';
Console::init(

View File

@@ -41,7 +41,7 @@ class ModuleUnpackCommand extends Command
exit(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");
}
//定义常量
// 定义常量
/** @noinspection PhpIncludeInspection */
include_once DataProvider::getFrameworkRootDir() . '/src/ZM/global_defines.php';

View File

@@ -73,7 +73,7 @@ class PureHttpCommand extends Command
'document_index' => $index,
]
);
//echo "\r" . Coroutine::stats()["coroutine_peak_num"];
// echo "\r" . Coroutine::stats()["coroutine_peak_num"];
});
$server->on('start', function ($server) {
Process::signal(SIGINT, function () use ($server) {

View File

@@ -46,6 +46,7 @@ class RunServerCommand extends Command
new InputOption('preview', null, null, '只显示参数,不启动服务器'),
new InputOption('force-load-module', null, InputOption::VALUE_OPTIONAL, '强制打包状态下加载模块(使用英文逗号分割多个)'),
new InputOption('polling-watch', null, null, '强制启用轮询模式监听'),
new InputOption('no-state-check', null, null, '关闭启动前框架运行状态检查'),
]);
$this->setDescription('Run zhamao-framework | 启动框架');
$this->setHelp('直接运行可以启动');
@@ -60,10 +61,12 @@ class RunServerCommand extends Command
}
}
$state = Framework::getProcessState(ZM_PROCESS_MASTER);
if (is_array($state) && posix_getsid($state['pid'] ?? -1) !== false) {
$output->writeln("<error>检测到已经在 pid: {$state['pid']} 进程启动了框架!</error>");
$output->writeln('<error>不可以同时启动两个框架!</error>');
return 1;
if (!$input->getOption('no-state-check')) {
if (is_array($state) && posix_getsid($state['pid'] ?? -1) !== false) {
$output->writeln("<error>检测到已经在 pid: {$state['pid']} 进程启动了框架!</error>");
$output->writeln('<error>不可以同时启动两个框架!</error>');
return 1;
}
}
(new Framework($input->getOptions()))->start();
return 0;

View File

@@ -28,9 +28,9 @@ use ZM\Exception\InitException;
class ConsoleApplication extends Application
{
public const VERSION_ID = 436;
public const VERSION_ID = 448;
public const VERSION = '2.7.0-beta2';
public const VERSION = '2.7.1';
private static $obj;
@@ -87,11 +87,11 @@ class ConsoleApplication extends Application
new DaemonStatusCommand(),
new DaemonReloadCommand(),
new DaemonStopCommand(),
new RunServerCommand(), //运行主服务的指令控制器
new RunServerCommand(), // 运行主服务的指令控制器
new ServerStatusCommand(),
new ServerStopCommand(),
new ServerReloadCommand(),
new PureHttpCommand(), //纯HTTP服务器指令
new PureHttpCommand(), // 纯HTTP服务器指令
new SystemdGenerateCommand(),
]);
if (LOAD_MODE === 1) {

View File

@@ -123,7 +123,7 @@ class DB
if ($result !== true) {
SqlPoolStorage::$sql_pool->putConnection(null);
throw new DBException("语句[{$line}]错误!" . $ps->errorInfo()[2]);
//echo json_encode(debug_backtrace(), 128 | 256);
// echo json_encode(debug_backtrace(), 128 | 256);
}
SqlPoolStorage::$sql_pool->putConnection($conn);
return $ps->fetchAll($fetch_mode);

View File

@@ -67,7 +67,7 @@ class Table
public function statement()
{
$this->cache = [];
//TODO: 无返回的statement语句
// TODO: 无返回的statement语句
}
public function paintWhereSQL($rule, $operator)

View File

@@ -19,15 +19,15 @@ use ZM\Utils\ZMUtil;
class EventDispatcher
{
public const STATUS_NORMAL = 0; //正常结束
public const STATUS_NORMAL = 0; // 正常结束
public const STATUS_INTERRUPTED = 1; //被interrupt了不管在什么地方
public const STATUS_INTERRUPTED = 1; // 被interrupt了不管在什么地方
public const STATUS_EXCEPTION = 2; //执行过程中抛出了异常
public const STATUS_EXCEPTION = 2; // 执行过程中抛出了异常
public const STATUS_BEFORE_FAILED = 3; //中间件HandleBefore返回了false所以不执行此方法
public const STATUS_BEFORE_FAILED = 3; // 中间件HandleBefore返回了false所以不执行此方法
public const STATUS_RULE_FAILED = 4; //判断事件执行的规则函数判定为false所以不执行此方法
public const STATUS_RULE_FAILED = 4; // 判断事件执行的规则函数判定为false所以不执行此方法
/** @var int */
public $status = self::STATUS_NORMAL;
@@ -133,7 +133,7 @@ class EventDispatcher
if ($this->status === self::STATUS_RULE_FAILED) {
$this->status = self::STATUS_NORMAL;
}
//TODO:没有过滤before的false可能会导致一些问题先观望一下
// TODO:没有过滤before的false可能会导致一些问题先观望一下
} catch (InterruptException $e) {
$this->store = $e->return_var;
$this->status = self::STATUS_INTERRUPTED;
@@ -200,7 +200,7 @@ class EventDispatcher
}
$middleware_obj = EventManager::$middlewares[$middleware->middleware];
$before = $middleware_obj['class'];
//var_dump($middleware_obj);
// var_dump($middleware_obj);
$r[$k] = new $before();
$r[$k]->class = $q_c;
$r[$k]->method = $q_f;

View File

@@ -61,7 +61,7 @@ class EventManager
if (server()->worker_id !== $vss->worker_id && $vss->worker_id != -1) {
return;
}
//echo server()->worker_id.PHP_EOL;
// echo server()->worker_id.PHP_EOL;
$plain_class = $vss->class;
Console::debug('Added Middleware-based timer: ' . $plain_class . ' -> ' . $vss->method);
Timer::tick($vss->tick_ms, function () use ($vss, $dispatcher) {

View File

@@ -30,7 +30,10 @@ class EventTracer
public static function getCurrentEventMiddlewares()
{
$current_event = self::getCurrentEvent();
if (!isset($current_event->class, $current_event->method)) {
if (empty($current_event->class)) {
return null;
}
if (empty($current_event->method)) {
return null;
}
return EventManager::$middleware_map[$current_event->class][$current_event->method] ?? [];

View File

@@ -52,10 +52,10 @@ class OnMessage implements SwooleEvent
return false;
});
try {
//$starttime = microtime(true);
// $starttime = microtime(true);
$dispatcher1->dispatchEvents($conn);
$dispatcher->dispatchEvents($conn);
//Console::success("Used ".round((microtime(true) - $starttime) * 1000, 3)." ms!");
// Console::success("Used ".round((microtime(true) - $starttime) * 1000, 3)." ms!");
} catch (Exception $e) {
$error_msg = $e->getMessage() . ' at ' . $e->getFile() . '(' . $e->getLine() . ')';
Console::error(zm_internal_errcode('E00017') . 'Uncaught exception ' . get_class($e) . ' when calling "message": ' . $error_msg);

View File

@@ -39,7 +39,7 @@ class OnRequest implements SwooleEvent
$dis1 = new EventDispatcher(OnRequestEvent::class);
$dis1->setRuleFunction(function ($v) {
return eval('return ' . $v->getRule() . ';') ? true : false;
return (bool) eval('return ' . $v->getRule() . ';');
});
$dis = new EventDispatcher(OnSwooleEvent::class);
@@ -61,13 +61,12 @@ class OnRequest implements SwooleEvent
if ($result === true) {
ctx()->setCache('params', $params);
$dispatcher = new EventDispatcher(RequestMapping::class);
$div = new RequestMapping();
$div->route = $node['route'];
$div = new RequestMapping($node['route']);
$div->params = $params;
$div->method = $node['method'];
$div->request_method = $node['request_method'];
$div->class = $node['class'];
//Console::success("正在执行路由:".$node["method"]);
// Console::success("正在执行路由:".$node["method"]);
$dispatcher->dispatchEvent($div, null, $params, $request, $response);
if (is_string($dispatcher->store) && !$response->isEnd()) {
$response->end($dispatcher->store);
@@ -75,7 +74,7 @@ class OnRequest implements SwooleEvent
}
}
if (!$response->isEnd()) {
//Console::warning('返回了404');
// Console::warning('返回了404');
HttpUtil::responseCodePage($response, 404);
}
} catch (InterruptException $e) {

View File

@@ -66,7 +66,7 @@ class OnWorkerStart implements SwooleEvent
} elseif (!isset($error['type'])) {
return;
}
//DataProvider::saveBuffer();
// DataProvider::saveBuffer();
/* @var Server $server */
if (server() === null) {
$server->shutdown();
@@ -77,10 +77,10 @@ class OnWorkerStart implements SwooleEvent
Console::verbose("Worker #{$server->worker_id} starting");
Framework::$server = $server;
//ZMBuf::resetCache(); //清空变量缓存
//ZMBuf::set("wait_start", []); //添加队列在workerStart运行完成前先让其他协程等待执行
// ZMBuf::resetCache(); //清空变量缓存
// ZMBuf::set("wait_start", []); //添加队列在workerStart运行完成前先让其他协程等待执行
//TODO: 单独抽出来MySQL和Redis连接池
// TODO: 单独抽出来MySQL和Redis连接池
$this->initMySQLPool();
// 开箱即用的Redis
@@ -93,9 +93,9 @@ class OnWorkerStart implements SwooleEvent
}
}
$this->loadAnnotations(); //加载composer资源、phar外置包、注解解析注册等
$this->loadAnnotations(); // 加载composer资源、phar外置包、注解解析注册等
EventManager::registerTimerTick(); //启动计时器
EventManager::registerTimerTick(); // 启动计时器
set_coroutine_params(['server' => $server, 'worker_id' => $worker_id]);
$dispatcher = new EventDispatcher(OnStart::class);
$dispatcher->setRuleFunction(function ($v) {
@@ -151,14 +151,15 @@ class OnWorkerStart implements SwooleEvent
if (Framework::$instant_mode) {
goto skip;
}
//加载各个模块的注解类,以及反射
// 加载各个模块的注解类,以及反射
Console::debug('Mapping annotations');
$parser = new AnnotationParser();
$composer = json_decode(file_get_contents(DataProvider::getSourceRootDir() . '/composer.json'), true);
$merge = array_merge($composer['autoload']['psr-4'] ?? [], $composer['autoload-dev']['psr-4'] ?? []);
$exclude_annotations = array_merge($composer['extra']['exclude_annotate'] ?? [], $composer['extra']['zm']['exclude-annotation-path'] ?? []);
foreach ($merge as $k => $v) {
if (is_dir(DataProvider::getSourceRootDir() . '/' . $v)) {
if (in_array(trim($k, '\\') . '\\', $composer['extra']['exclude_annotate'] ?? [])) {
if (in_array(trim($k, '\\') . '\\', $exclude_annotations)) {
continue;
}
if (trim($k, '\\') == 'ZM') {
@@ -187,16 +188,16 @@ class OnWorkerStart implements SwooleEvent
}
$parser->registerMods();
EventManager::loadEventByParser($parser); //加载事件
EventManager::loadEventByParser($parser); // 加载事件
skip:
//加载自定义的全局函数
// 加载自定义的全局函数
Console::debug('Loading context class...');
$context_class = ZMConfig::get('global', 'context_class');
if (!is_a($context_class, ContextInterface::class, true)) {
throw new ZMKnownException('E00032', 'Context class must implemented from ContextInterface!');
}
//加载插件
// 加载插件
$obb_onebot = ZMConfig::get('global', 'onebot') ??
ZMConfig::get('global', 'modules')['onebot'] ??
['status' => true, 'single_bot_mode' => false, 'message_level' => 99999];
@@ -251,7 +252,7 @@ class OnWorkerStart implements SwooleEvent
if (!empty($real_conf)) {
Console::info('Connecting to MySQL pool');
ob_start();
phpinfo(); //这个phpinfo是有用的不能删除
phpinfo(); // 这个phpinfo是有用的不能删除
$str = ob_get_clean();
$str = explode("\n", $str);
foreach ($str as $v) {

View File

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

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace ZM\Exception;
use Throwable;
class MethodNotFoundException extends ZMException
{
public function __construct($message = '', $code = 0, Throwable $previous = null)
{
parent::__construct(zm_internal_errcode('E00073') . $message, $code, $previous);
}
}

View File

@@ -97,7 +97,7 @@ class Framework
exit(1);
}
//定义常量
// 定义常量
include_once 'global_defines.php';
try {
@@ -144,9 +144,9 @@ class Framework
$this->server_set['log_level'] = SWOOLE_LOG_DEBUG;
$add_port = ZMConfig::get('global', 'remote_terminal')['status'] ?? false;
//if ($instant_mode) {
// if ($instant_mode) {
$this->loadServerEvents();
//}
// }
$this->parseCliArgs(self::$argv, $add_port);
@@ -288,7 +288,7 @@ class Framework
$port->on('close', function ($serv, $fd) {
ManagerGM::popConnect($fd);
//echo "Client: Close.\n";
// echo "Client: Close.\n";
});
}
@@ -301,9 +301,9 @@ class Framework
// 注册 Swoole Server 的事件
$this->registerServerEvents();
$r = ZMConfig::get('global', 'light_cache') ?? [
'size' => 512, //最多允许储存的条数需要2的倍数
'max_strlen' => 32768, //单行字符串最大长度需要2的倍数
'hash_conflict_proportion' => 0.6, //Hash冲突率越大越好但是需要的内存更多
'size' => 512, // 最多允许储存的条数需要2的倍数
'max_strlen' => 32768, // 单行字符串最大长度需要2的倍数
'hash_conflict_proportion' => 0.6, // Hash冲突率越大越好但是需要的内存更多
'persistence_path' => DataProvider::getDataFolder() . '_cache.json',
'auto_save_interval' => 900,
];
@@ -520,13 +520,13 @@ class Framework
if (!isset($line_width[$current_line])) {
$line_width[$current_line] = $max_border - 2;
}
//Console::info("行宽[$current_line]".$line_width[$current_line]);
// Console::info("行宽[$current_line]".$line_width[$current_line]);
if ($max_border >= 57) { // 很宽的时候,一行能放两个短行
if ($line_width[$current_line] == ($max_border - 2)) { //空行
if ($line_width[$current_line] == ($max_border - 2)) { // 空行
self::writeNoDouble($k, $v, $line_data, $line_width, $current_line, $colorful, $max_border);
} else { // 不是空行,已经有东西了
$tmp_line = $k . ': ' . $v;
//Console::info("[$current_line]即将插入后面的东西[".$tmp_line."]");
// Console::info("[$current_line]即将插入后面的东西[".$tmp_line."]");
if (strlen($tmp_line) > $line_width[$current_line]) { // 地方不够,另起一行
$line_data[$current_line] = str_replace('| ', '', $line_data[$current_line]);
++$current_line;
@@ -725,8 +725,8 @@ class Framework
break;
case 'show-php-ver':
default:
//Console::info("Calculating ".$x);
//dump($y);
// Console::info("Calculating ".$x);
// dump($y);
break;
}
}
@@ -742,8 +742,8 @@ class Framework
private static function writeNoDouble($k, $v, &$line_data, &$line_width, &$current_line, $colorful, $max_border)
{
$tmp_line = $k . ': ' . $v;
//Console::info("写入[".$tmp_line."]");
if (strlen($tmp_line) > $line_width[$current_line]) { //输出的内容太多了,以至于一行都放不下一个,要折行
// Console::info("写入[".$tmp_line."]");
if (strlen($tmp_line) > $line_width[$current_line]) { // 输出的内容太多了,以至于一行都放不下一个,要折行
$title_strlen = strlen($k . ': ');
$content_len = $line_width[$current_line] - $title_strlen;
@@ -769,7 +769,7 @@ class Framework
++$current_line;
} while ($rest > $max_border - 2); // 循环,直到放完
} else { // 不需要折行
//Console::info("不需要折行");
// Console::info("不需要折行");
$line_data[$current_line] = ' ' . $k . ': ';
if ($colorful) {
$line_data[$current_line] .= TermColor::color8(32);
@@ -781,10 +781,10 @@ class Framework
if ($max_border >= 57) {
if (strlen($tmp_line) >= intval(($max_border - 2) / 2)) { // 不需要折行,直接输出一个转下一行
//Console::info("不需要折行,直接输出一个转下一行");
// Console::info("不需要折行,直接输出一个转下一行");
++$current_line;
} else { // 输出很小,写到前面并分片
//Console::info("输出很小,写到前面并分片");
// Console::info("输出很小,写到前面并分片");
$space = intval($max_border / 2) - 2 - strlen($tmp_line);
$line_data[$current_line] .= str_pad('', $space);
$line_data[$current_line] .= '| '; // 添加分片

View File

@@ -56,50 +56,32 @@ class Response
/**
* @param $name
* @param $value
* @param $expires
* @param $path
* @param $domain
* @param $secure
* @param $httponly
* @param $samesite
* @param mixed ...$params
* @return mixed
*/
public function cookie($name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httponly = null, $samesite = null)
public function cookie($name, ...$params)
{
return $this->response->rawcookie($name, $value, $expires, $path, $domain, $secure, $httponly, $samesite);
return empty($params) ? $this->response->rawcookie($name) : $this->response->rawcookie($name, ...$params);
}
/**
* @param $name
* @param $value
* @param $expires
* @param $path
* @param $domain
* @param $secure
* @param $httponly
* @param $samesite
* @param mixed ...$params
* @param mixed $name
* @return mixed
*/
public function setCookie($name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httponly = null, $samesite = null)
public function setCookie($name, ...$params)
{
return $this->response->setCookie($name, $value, $expires, $path, $domain, $secure, $httponly, $samesite);
return empty($params) ? $this->response->rawcookie($name) : $this->response->setCookie($name, ...$params);
}
/**
* @param $name
* @param $value
* @param $expires
* @param $path
* @param $domain
* @param $secure
* @param $httponly
* @param $samesite
* @param mixed ...$params
* @param mixed $name
* @return mixed
*/
public function rawcookie($name, $value = null, $expires = null, $path = null, $domain = null, $secure = null, $httponly = null, $samesite = null)
public function rawcookie($name, ...$params)
{
return $this->response->rawcookie($name, $value, $expires, $path, $domain, $secure, $httponly, $samesite);
return empty($params) ? $this->response->rawcookie($name) : $this->response->rawcookie($name, ...$params);
}
/**
@@ -107,11 +89,11 @@ class Response
* @param $reason
* @return mixed
*/
public function status($http_code, $reason = null)
public function status($http_code, ...$params)
{
$this->status_code = $http_code;
if (!$this->is_end) {
return $this->response->status($http_code, $reason);
return empty($params) ? $this->response->status($http_code) : $this->response->status($http_code, ...$params);
}
return false;
}
@@ -126,10 +108,10 @@ class Response
* @param $reason
* @return mixed
*/
public function setStatusCode($http_code, $reason = null)
public function setStatusCode($http_code, ...$params)
{
if (!$this->is_end) {
return $this->response->setStatusCode($http_code, $reason);
return empty($params) ? $this->response->status($http_code) : $this->response->status($http_code, ...$params);
}
return false;
}

View File

@@ -21,7 +21,7 @@ use ZM\Utils\ZMUtil;
*/
class ModulePacker
{
public const ZM_MODULE_PACKER_VERSION = '1.0';
public const ZM_MODULE_PACKER_VERSION = '1.1';
/** @var array */
private $module = [];
@@ -114,11 +114,11 @@ class ModulePacker
$this->phar->startBuffering();
Console::info('模块输出文件:' . $this->filename);
$this->addFiles(); //添加文件
$this->addLightCacheStore(); //保存light-cache-store指定的项
$this->addModuleConfig(); //生成module-config.json
$this->addZMDataFiles(); //添加需要保存的zm_data下的目录或文件
$this->addEntry(); //生成模块的入口文件module_entry.php
$this->addFiles(); // 添加文件
$this->addLightCacheStore(); // 保存light-cache-store指定的项
$this->addModuleConfig(); // 生成module-config.json
$this->addZMDataFiles(); // 添加需要保存的zm_data下的目录或文件
$this->addEntry(); // 生成模块的入口文件module_entry.php
$this->phar->stopBuffering();
}
@@ -142,7 +142,7 @@ class ModulePacker
if ($pos === 0) {
$path_value = substr($this->module['module-path'], strlen(DataProvider::getSourceRootDir() . '/'));
} else {
throw new ModulePackException(zm_internal_errcode('E99999')); //未定义的错误
throw new ModulePackException(zm_internal_errcode('E99999')); // 未定义的错误
}
return ZMUtil::getClassesPsr4($this->module['module-path'], $this->module['namespace'], null, $path_value);
}
@@ -158,7 +158,7 @@ class ModulePacker
}
}
foreach (($composer['autoload']['files'] ?? []) as $v) {
if (strcmp($path, $v) === 0) {
if (strpos($v, $path) === 0) {
$item['files'][] = $v;
}
}
@@ -174,9 +174,9 @@ class ModulePacker
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冲突率越大越好但是需要的内存更多
'size' => 512, // 最多允许储存的条数需要2的倍数
'max_strlen' => 32768, // 单行字符串最大长度需要2的倍数
'hash_conflict_proportion' => 0.6, // Hash冲突率越大越好但是需要的内存更多
'persistence_path' => DataProvider::getDataFolder() . '_cache.json',
'auto_save_interval' => 900,
];
@@ -202,7 +202,7 @@ class ModulePacker
'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(),
'hotload-psr-4' => $this->generatePharAutoload(),
'unpack' => [
'composer-autoload-items' => $this->getComposerAutoloadItems(),
'global-config-override' => $this->module['global-config-override'] ?? false,
@@ -210,6 +210,9 @@ class ModulePacker
'allow-hotload' => $this->module['allow-hotload'] ?? false,
'pack-time' => time(),
];
if (isset($stub_values['unpack']['composer-autoload-items']['files'])) {
$stub_values['hotload-files'] = $stub_values['unpack']['composer-autoload-items']['files'];
}
$this->phar->addFromString('zmplugin.json', json_encode($stub_values, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
$this->module_config = $stub_values;
}

View File

@@ -30,7 +30,8 @@ class ModuleUnpacker
/**
* 解包模块
* @param bool $ignore_depends
*
* @param mixed $ignore_depends
* @throws ModulePackException
* @throws ZMException
*/
@@ -61,7 +62,8 @@ class ModuleUnpacker
/**
* 检查模块依赖关系
* @param bool $ignore_depends
*
* @param mixed $ignore_depends
* @throws ModulePackException
* @throws ZMException
*/
@@ -125,8 +127,8 @@ class ModuleUnpacker
throw new ModulePackException(zm_internal_errcode('E00068'));
}
$composer = json_decode(file_get_contents($composer_file), true);
if (isset($this->module_config['composer-extend-autoload'])) {
$autoload = $this->module_config['composer-extend-autoload'];
if (isset($this->module_config['unpack']['composer-autoload-items'])) {
$autoload = $this->module_config['unpack']['composer-autoload-items'];
if (isset($autoload['psr-4'])) {
Console::info('Adding extended autoload psr-4 for composer');
$composer['autoload']['psr-4'] = isset($composer['autoload']['psr-4']) ? array_merge($composer['autoload']['psr-4'], $autoload['psr-4']) : $autoload['psr-4'];
@@ -136,6 +138,7 @@ class ModuleUnpacker
$composer['autoload']['files'] = isset($composer['autoload']['files']) ? array_merge($composer['autoload']['files'], $autoload['files']) : $autoload['files'];
}
}
if (isset($this->module_config['composer-extend-require'])) {
foreach ($this->module_config['composer-extend-require'] as $k => $v) {
Console::info('Adding extended required composer library: ' . $k);
@@ -172,9 +175,9 @@ class ModuleUnpacker
private function copyLightCacheStore($override)
{
$r = ZMConfig::get('global', 'light_cache') ?? [
'size' => 512, //最多允许储存的条数需要2的倍数
'max_strlen' => 32768, //单行字符串最大长度需要2的倍数
'hash_conflict_proportion' => 0.6, //Hash冲突率越大越好但是需要的内存更多
'size' => 512, // 最多允许储存的条数需要2的倍数
'max_strlen' => 32768, // 单行字符串最大长度需要2的倍数
'hash_conflict_proportion' => 0.6, // Hash冲突率越大越好但是需要的内存更多
'persistence_path' => DataProvider::getDataFolder() . '_cache.json',
'auto_save_interval' => 900,
];

View File

@@ -47,16 +47,16 @@ class QQBot
}
set_coroutine_params(['data' => $data]);
if (isset($data['post_type'])) {
//echo TermColor::ITALIC.json_encode($data, 128|256).TermColor::RESET.PHP_EOL;
// echo TermColor::ITALIC.json_encode($data, 128|256).TermColor::RESET.PHP_EOL;
ctx()->setCache('level', $level);
//Console::debug("Calling CQ Event from fd=" . ctx()->getConnection()->getFd());
// Console::debug("Calling CQ Event from fd=" . ctx()->getConnection()->getFd());
if ($data['post_type'] != 'meta_event') {
$r = $this->dispatchBeforeEvents($data, 'pre'); // before在这里执行元事件不执行before为减少不必要的调试日志
if ($r->store === 'block') {
EventDispatcher::interrupt();
}
}
//Console::warning("最上数据包:".json_encode($data));
// Console::warning("最上数据包:".json_encode($data));
}
if (isset($data['echo']) || isset($data['post_type'])) {
if (CoMessage::resumeByWS()) {
@@ -134,10 +134,10 @@ class QQBot
*/
private function dispatchEvents($data)
{
//Console::warning("最xia数据包".json_encode($data));
// Console::warning("最xia数据包".json_encode($data));
switch ($data['post_type']) {
case 'message':
//分发CQCommand事件
// 分发CQCommand事件
$dispatcher = new EventDispatcher(CQCommand::class);
$dispatcher->setReturnFunction(function ($result) {
if (is_string($result)) {
@@ -170,7 +170,7 @@ class QQBot
}
}
//分发CQMessage事件
// 分发CQMessage事件
$msg_dispatcher = new EventDispatcher(CQMessage::class);
$msg_dispatcher->setRuleFunction(function ($v) {
return ($v->message == '' || ($v->message == ctx()->getStringMessage()))
@@ -187,12 +187,12 @@ class QQBot
$msg_dispatcher->dispatchEvents(ctx()->getMessage());
return;
case 'meta_event':
//Console::success("当前数据包:".json_encode(ctx()->getData()));
// Console::success("当前数据包:".json_encode(ctx()->getData()));
$dispatcher = new EventDispatcher(CQMetaEvent::class);
$dispatcher->setRuleFunction(function (CQMetaEvent $v) {
return $v->meta_event_type == '' || ($v->meta_event_type != '' && $v->meta_event_type == ctx()->getData()['meta_event_type']);
});
//eval(BP);
// eval(BP);
$dispatcher->dispatchEvents(ctx()->getData());
return;
case 'notice':

View File

@@ -18,13 +18,13 @@ class LightCacheInside
{
try {
self::createTable('wait_api', 3, 65536);
self::createTable('connect', 3, 64); //用于存单机器人模式下的机器人fd的
self::createTable('static_route', 64, 256); //用于存储
self::createTable('connect', 3, 64); // 用于存单机器人模式下的机器人fd的
self::createTable('static_route', 64, 256); // 用于存储
self::createTable('light_array', 8, 512, 0.6);
} catch (ZMException $e) {
return false;
} //用于存协程等待的状态内容的
//self::createTable("worker_start", 2, 1024);//用于存启动服务器时的状态的
} // 用于存协程等待的状态内容的
// self::createTable("worker_start", 2, 1024);//用于存启动服务器时的状态的
return true;
}

View File

@@ -27,7 +27,7 @@ class SpinLock
public static function lock(string $key)
{
while (($r = self::$kv_lock->incr($key, 'lock_num')) > 1) { //此资源已经被锁上了
while (($r = self::$kv_lock->incr($key, 'lock_num')) > 1) { // 此资源已经被锁上了
if (Coroutine::getCid() != -1) {
System::sleep(self::$delay / 1000);
} else {

View File

@@ -27,7 +27,7 @@ class CoroutinePool
}
go(function () use ($func, $name) {
self::$cids[$name][] = Coroutine::getCid();
//Console::debug("正在执行协程,当前协程池中有 " . count(self::$cids[$name]) . " 个正在运行的协程: ".implode(", ", self::$cids[$name]));
// Console::debug("正在执行协程,当前协程池中有 " . count(self::$cids[$name]) . " 个正在运行的协程: ".implode(", ", self::$cids[$name]));
$func();
self::checkCids($name);
});

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace ZM\Utils;
use Closure;
use ZM\Exception\MethodNotFoundException;
trait Macroable
{
protected static $macros = [];
public static function __callStatic($method, $parameters)
{
if (!static::hasMacro($method)) {
throw new MethodNotFoundException("Method {$method} does not exist.");
}
if (static::$macros[$method] instanceof Closure) {
return call_user_func_array(Closure::bind(static::$macros[$method], null, static::class), $parameters);
}
return call_user_func_array(static::$macros[$method], $parameters);
}
public function __call($method, $parameters)
{
if (!static::hasMacro($method)) {
throw new MethodNotFoundException("Method {$method} does not exist.");
}
if (static::$macros[$method] instanceof Closure) {
return call_user_func_array(static::$macros[$method]->bindTo($this, static::class), $parameters);
}
return call_user_func_array(static::$macros[$method], $parameters);
}
public static function macro($name, callable $macro)
{
static::$macros[$name] = $macro;
}
public static function hasMacro($name)
{
return isset(static::$macros[$name]);
}
}

View File

@@ -20,12 +20,18 @@ use ZM\Utils\DataProvider;
*/
class ModuleManager
{
public static function getComposer()
{
return json_decode(file_get_contents(DataProvider::getSourceRootDir() . '/composer.json'), true);
}
/**
* 扫描src目录下的所有已经被标注的模块
* @throws ZMException
*/
public static function getConfiguredModules(): array
{
$composer = self::getComposer();
$dir = DataProvider::getSourceRootDir() . '/src/';
$ls = DataProvider::scanDirFiles($dir, true, true);
$modules = [];
@@ -43,7 +49,18 @@ class ModuleManager
throw new ZMKnownException('E00052', '在/src/目录下不可以直接标记为模块(zm.json),因为命名空间不能为根空间!');
}
$json['module-path'] = realpath($dir . '/' . $pathinfo['dirname']);
$json['namespace'] = str_replace('/', '\\', $pathinfo['dirname']);
$relative_path = str_replace(DataProvider::getSourceRootDir() . '/', '', $json['module-path']);
foreach (array_merge($composer['autoload']['psr-4'] ?? [], $composer['autoload-dev']['psr-4'] ?? []) as $ks => $vs) {
if (strpos($relative_path, $vs) === 0) {
$remain = trim(substr($relative_path, strlen($vs)), '/');
$remain = str_replace('/', '\\', $remain);
$json['namespace'] = $ks . $remain;
break;
}
}
// $json['namespace'] = str_replace('/', '\\', $pathinfo['dirname']);
if (isset($modules[$json['name']])) {
throw new ZMKnownException('E00053', '重名模块:' . $json['name']);
}

View File

@@ -51,7 +51,7 @@ class RouteManager
$route_name = ($tail === '' ? '' : '/') . $tail . '/{filename}';
Console::debug('添加静态文件路由:' . $route_name);
$route = new Route($route_name, ['_class' => RouteManager::class, '_method' => 'onStaticRoute']);
//echo $path.PHP_EOL;
// echo $path.PHP_EOL;
LightCacheInside::set('static_route', $route->getPath(), $path);
self::$routes->add(md5($route_name), $route);

View File

@@ -77,7 +77,7 @@ class SignalListener
});
self::processKillerPrompt();
}
//Console::verbose("Interrupted in worker");
// Console::verbose("Interrupted in worker");
// do nothing
});
}

View File

@@ -52,7 +52,7 @@ class ZMUtil
public static function getModInstance($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];
@@ -92,7 +92,7 @@ class ZMUtil
foreach ($files as $v) {
$pathinfo = pathinfo($v);
if (($pathinfo['extension'] ?? '') == 'php') {
if ($rule === null) { //规则未设置回调时候,使用默认的识别过滤规则
if ($rule === null) { // 规则未设置回调时候,使用默认的识别过滤规则
/*if (substr(file_get_contents($dir . '/' . $v), 6, 6) == '#plain') {
continue;
}*/

View File

@@ -17,6 +17,7 @@ use ZM\Context\ContextInterface;
use ZM\Event\EventManager;
use ZM\Exception\RobotNotFoundException;
use ZM\Exception\ZMException;
use ZM\Exception\ZMKnownException;
use ZM\Framework;
use ZM\Store\LightCacheInside;
use ZM\Store\ZMAtomic;
@@ -27,7 +28,7 @@ function getClassPath($class_name)
{
$dir = str_replace('\\', '/', $class_name);
$dir2 = DataProvider::getSourceRootDir() . '/src/' . $dir . '.php';
//echo "@@@".$dir2.PHP_EOL;
// echo "@@@".$dir2.PHP_EOL;
$dir2 = str_replace('\\', '/', $dir2);
if (file_exists($dir2)) {
return $dir2;
@@ -65,7 +66,7 @@ function explodeMsg($msg, $ban_comma = false): array
{
$msg = str_replace(' ', "\n", trim($msg));
if (!$ban_comma) {
//$msg = str_replace("", "\n", $msg);
// $msg = str_replace("", "\n", $msg);
$msg = str_replace("\t", "\n", $msg);
}
$msgs = explode("\n", $msg);
@@ -127,7 +128,7 @@ function split_explode($del, $str, $divide_en = false): array
}
}
$str = implode($del, $str);
//echo $str."\n";
// echo $str."\n";
$ls = [];
foreach (explode($del, $str) as $v) {
if (trim($v) == '') {
@@ -135,7 +136,7 @@ function split_explode($del, $str, $divide_en = false): array
}
$ls[] = $v;
}
//var_dump($ls);
// var_dump($ls);
return $ls == [] ? [''] : $ls;
}
@@ -149,7 +150,7 @@ function matchArgs($pattern, $context)
$exp = explode('*', $pattern);
$i = 0;
foreach ($exp as $k => $v) {
//echo "[MATCH$k] " . $v . PHP_EOL;
// echo "[MATCH$k] " . $v . PHP_EOL;
if ($v == '' && $k == 0) {
continue;
}
@@ -158,14 +159,14 @@ function matchArgs($pattern, $context)
$v = '^EOL';
}
$cur_var = '';
//echo mb_substr($context, $i) . "|" . $v . PHP_EOL;
// echo mb_substr($context, $i) . "|" . $v . PHP_EOL;
$ori = $i;
while (($a = mb_substr($context, $i, mb_strlen($v))) != $v && $a != '') {
$cur_var .= mb_substr($context, $i, 1);
++$i;
}
if ($i != $ori || $k == 1 || $k == count($exp) - 1) {
//echo $cur_var . PHP_EOL;
// echo $cur_var . PHP_EOL;
$result[] = $cur_var;
}
$i += mb_strlen($v);
@@ -193,11 +194,11 @@ function connectIs($type): bool
function getAnnotations(): array
{
$s = debug_backtrace()[1];
//echo json_encode($s, 128|256);
// echo json_encode($s, 128|256);
$list = [];
foreach (EventManager::$events as $v) {
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']) {
$list[get_class($vs)][] = $vs;
}
@@ -224,12 +225,18 @@ function set_coroutine_params($array)
}
}
function context(): ?ContextInterface
/**
* @throws ZMKnownException
*/
function context(): ContextInterface
{
return ctx();
}
function ctx(): ?ContextInterface
/**
* @throws ZMKnownException
*/
function ctx(): ContextInterface
{
$cid = Co::getCid();
$c_class = ZMConfig::get('global', 'context_class');
@@ -243,8 +250,7 @@ function ctx(): ?ContextInterface
return ZMBuf::$context_class[$cid] ?? (ZMBuf::$context_class[$cid] = new $c_class($cid));
}
}
return null;
throw new ZMKnownException(zm_internal_errcode('E00072') . 'Unable to find context environment');
}
function onebot_target_id_name($message_type): string

View File

@@ -5,7 +5,10 @@ declare(strict_types=1);
function loader__generated_id__()
{
$obj = json_decode(file_get_contents(__DIR__ . '/zmplugin.json'), true);
foreach (($obj['autoload-psr-4'] ?? []) as $v) {
foreach (($obj['hotload-psr-4'] ?? []) as $v) {
require_once Phar::running() . '/' . $v;
}
foreach (($obj['hotload-files'] ?? []) as $v) {
require_once Phar::running() . '/' . $v;
}
}

View File

@@ -20,13 +20,14 @@ try {
$base_path = DataProvider::getSourceRootDir();
$scan_paths = [];
$composer = json_decode(file_get_contents($base_path . '/composer.json'), true);
$exclude_annotations = array_merge($composer['extra']['exclude_annotate'] ?? [], $composer['extra']['zm']['exclude-annotation-path'] ?? []);
foreach (($composer['autoload']['psr-4'] ?? []) as $k => $v) {
if (is_dir($base_path . '/' . $v) && !in_array($v, $composer['extra']['exclude_annotate'] ?? [])) {
if (is_dir($base_path . '/' . $v) && !in_array($v, $exclude_annotations)) {
$scan_paths[trim($k, '\\')] = $base_path . '/' . $v;
}
}
foreach (($composer['autoload-dev']['psr-4'] ?? []) as $k => $v) {
if (is_dir($base_path . '/' . $v) && !in_array($v, $composer['extra']['exclude_annotate'] ?? [])) {
if (is_dir($base_path . '/' . $v) && !in_array($v, $exclude_annotations)) {
$scan_paths[trim($k, '\\')] = $base_path . '/' . $v;
}
}

View File

@@ -35,6 +35,7 @@ class AnnotationParserRegisterTest extends TestCase
public function testAnnotation() {
ob_start();
$gen = $this->parser->generateAnnotationEvents();
//zm_dump($gen);
$m = $gen[OnStart::class][0]->method;
$class = $gen[OnStart::class][0]->class;
$c = new $class();
@@ -43,12 +44,10 @@ class AnnotationParserRegisterTest extends TestCase
} catch (Exception $e) {
}
$result = ob_get_clean();
echo $result;
$this->assertStringContainsString("我开始了!", $result);
}
public function testAnnotation2() {
foreach ($this->parser->generateAnnotationEvents() as $k => $v) {
foreach ($v as $vs) {
$this->assertTrue($vs->method === null || $vs->method != '');
@@ -57,22 +56,9 @@ class AnnotationParserRegisterTest extends TestCase
}
}
public function testAnnotationMap() {
$map = $this->parser->getMiddlewareMap();
$this->assertContainsEquals("timer", $map[Hello::class]["timer"]);
}
public function testMiddlewares() {
$wares = $this->parser->getMiddlewares();
zm_dump($wares);
$this->assertArrayHasKey("timer", $wares);
}
public function testReqMapping() {
$mapping = $this->parser->getReqMapping();
$this->assertEquals("index", $mapping["method"]);
}
public function testTracer() {
}
}