mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-02 22:35:38 +08:00
Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41f03fbba4 | ||
|
|
b3089c1bba | ||
|
|
c5a6f1fea4 | ||
|
|
ba2777137b | ||
|
|
6d90be164a | ||
|
|
4da6f5859a | ||
|
|
15d4ea710a | ||
|
|
f0541c1f32 | ||
|
|
2b8cab1824 | ||
|
|
61c7972915 | ||
|
|
44a0eec74c | ||
|
|
e57753e44b | ||
|
|
74e91a2950 | ||
|
|
7ce3ef41df | ||
|
|
444a77933a | ||
|
|
78f78c607d | ||
|
|
69155002dc | ||
|
|
475d14fab7 | ||
|
|
f4d7e63358 | ||
|
|
f222d2b45b | ||
|
|
d0155fe1da | ||
|
|
4737d0b507 | ||
|
|
09bd0197bb | ||
|
|
f0f120bd32 | ||
|
|
c897da29c6 | ||
|
|
e347e254e8 | ||
|
|
12363aebf0 | ||
|
|
ff0b925313 | ||
|
|
a6b4bd9b80 | ||
|
|
485fa5476c | ||
|
|
689076d97c | ||
|
|
cca6102e91 | ||
|
|
095855162b | ||
|
|
326f934013 | ||
|
|
35b0c258fe | ||
|
|
6650846b15 | ||
|
|
a33d320f4c | ||
|
|
0bcfea6aa4 | ||
|
|
db6e63e91c | ||
|
|
a7f84fb53a | ||
|
|
ce7f2b1765 | ||
|
|
abbfb59eff | ||
|
|
b57fef16f9 | ||
|
|
1706afbcd0 | ||
|
|
d01bd69aa5 | ||
|
|
e6b9ae3ee1 | ||
|
|
73b6b8045d | ||
|
|
3c87abc6e8 | ||
|
|
e95925c129 | ||
|
|
82c44d6c40 | ||
|
|
e0a268e05e | ||
|
|
487892e1d9 | ||
|
|
7ab4e88359 | ||
|
|
4702b6ee75 | ||
|
|
20cd3aa66d | ||
|
|
391114bdef | ||
|
|
ffe1052ecc | ||
|
|
b4159152a7 | ||
|
|
8fc6e4b0f7 | ||
|
|
c8938b7a4b | ||
|
|
34db1626a5 | ||
|
|
7f0c97c5b9 | ||
|
|
74050c46e7 | ||
| 3ed1cb665a | |||
|
|
a6f33ba69d | ||
|
|
176b690417 | ||
|
|
e22b1b90ec | ||
|
|
a3c560790c | ||
| 570e2108dd | |||
|
|
59c0d95e5d | ||
|
|
9ceaecdc02 | ||
|
|
19d50898ef | ||
|
|
5b62ca62ae | ||
| fb528d30ce | |||
| 5f2d5ed334 |
38
.github/ISSUE_TEMPLATE/1_Bug_report.yaml
vendored
Normal file
38
.github/ISSUE_TEMPLATE/1_Bug_report.yaml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: 🐛 漏洞(BUG)报告
|
||||
description: ⚠️ 请不要直接在此提交安全漏洞
|
||||
labels: bug
|
||||
|
||||
body:
|
||||
- type: input
|
||||
id: affected-versions
|
||||
attributes:
|
||||
label: 受影响版本
|
||||
placeholder: x.y.z
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: 描述
|
||||
description: 请详细地描述您的问题
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce-steps
|
||||
attributes:
|
||||
label: 复现步骤
|
||||
description: |
|
||||
请尽可能地提供可以复现此步骤的漏洞。
|
||||
如果步骤过长或难以描述,您可以自行建立一个用于复现漏洞的仓库。
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: possible-solution
|
||||
attributes:
|
||||
label: 解决方案
|
||||
description: 如果您对这个漏洞的成因或修复有任何意见的话,请在此提出
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: 附加信息
|
||||
description: 其他可能有帮助的信息,如日志、截图等
|
||||
19
.github/ISSUE_TEMPLATE/2_Feature_request.yaml
vendored
Normal file
19
.github/ISSUE_TEMPLATE/2_Feature_request.yaml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: 🚀 功能建议
|
||||
description: 新功能、改进的意见、草案
|
||||
labels: enhancement
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: 描述
|
||||
description: 请提供简洁清楚的描述
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: example
|
||||
attributes:
|
||||
label: 例子
|
||||
description: |
|
||||
一个简单的例子,展示该功能将如何被使用(包括代码、配置文件等)
|
||||
如果这是针对已有功能的改进,请展示改进前后使用方式(或效能)的对比
|
||||
59
.github/workflows/integration-test.yml
vendored
Normal file
59
.github/workflows/integration-test.yml
vendored
Normal 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"
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Docs Build
|
||||
name: MkDocs Auto Deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -12,9 +12,18 @@ composer.lock
|
||||
.daemon_pid
|
||||
/runtime/
|
||||
/tmp/
|
||||
/temp/
|
||||
/site/
|
||||
|
||||
# go-cqhttp快速安装启动相关(可能被废弃)
|
||||
/ext/go-cqhttp/data/
|
||||
/ext/go-cqhttp/logs/
|
||||
/ext/go-cqhttp/config.hjson
|
||||
/ext/go-cqhttp/device.json
|
||||
/ext/go-cqhttp/go-cqhttp
|
||||
/ext/go-cqhttp/session.token
|
||||
|
||||
.zm_worker_*.pid
|
||||
|
||||
# Git Hook 的相关锁文件
|
||||
cghooks.lock
|
||||
75
.php-cs-fixer.php
Normal file
75
.php-cs-fixer.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @since 2.7.0
|
||||
*/
|
||||
|
||||
return (new PhpCsFixer\Config())
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'@PSR12' => true,
|
||||
'@Symfony' => true,
|
||||
'@PhpCsFixer' => true,
|
||||
'array_syntax' => [
|
||||
'syntax' => 'short',
|
||||
],
|
||||
'list_syntax' => [
|
||||
'syntax' => 'short',
|
||||
],
|
||||
'concat_space' => [
|
||||
'spacing' => 'one',
|
||||
],
|
||||
'blank_line_before_statement' => [
|
||||
'statements' => [
|
||||
'declare',
|
||||
],
|
||||
],
|
||||
'ordered_imports' => [
|
||||
'imports_order' => [
|
||||
'class',
|
||||
'function',
|
||||
'const',
|
||||
],
|
||||
'sort_algorithm' => 'alpha',
|
||||
],
|
||||
'single_line_comment_style' => [
|
||||
'comment_types' => [
|
||||
],
|
||||
],
|
||||
'yoda_style' => [
|
||||
'always_move_variable' => false,
|
||||
'equal' => false,
|
||||
'identical' => false,
|
||||
],
|
||||
'multiline_whitespace_before_semicolons' => [
|
||||
'strategy' => 'no_multi_line',
|
||||
],
|
||||
'constant_case' => [
|
||||
'case' => 'lower',
|
||||
],
|
||||
'class_attributes_separation' => true,
|
||||
'combine_consecutive_unsets' => true,
|
||||
'declare_strict_types' => true,
|
||||
'linebreak_after_opening_tag' => true,
|
||||
'lowercase_static_reference' => true,
|
||||
'no_useless_else' => true,
|
||||
'no_unused_imports' => true,
|
||||
'not_operator_with_successor_space' => false,
|
||||
'not_operator_with_space' => false,
|
||||
'ordered_class_elements' => true,
|
||||
'php_unit_strict' => false,
|
||||
'phpdoc_separation' => false,
|
||||
'single_quote' => true,
|
||||
'standardize_not_equals' => true,
|
||||
'multiline_comment_opening_closing' => true,
|
||||
'phpdoc_summary' => false,
|
||||
])
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->exclude('docs')
|
||||
->in(__DIR__ . '/src')
|
||||
)
|
||||
->setUsingCache(false);
|
||||
17
.run/Reload Zhamao Server.run.xml
Normal file
17
.run/Reload Zhamao Server.run.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Reload Zhamao Server" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="./zhamao server:reload && exit" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="false" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Run Zhamao Server.run.xml
Normal file
17
.run/Run Zhamao Server.run.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run Zhamao Server" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="./zhamao server" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="./zhamao" />
|
||||
<option name="SCRIPT_OPTIONS" value="server" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="false" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Run watcher.run.xml
Normal file
17
.run/Run watcher.run.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run watcher" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="bin/watcher" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="/bin/zsh" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="false" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
17
.run/Stop Zhamao Server.run.xml
Normal file
17
.run/Stop Zhamao Server.run.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Stop Zhamao Server" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="./zhamao server:stop && exit" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="false" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
23
README.md
23
README.md
@@ -7,7 +7,7 @@
|
||||
[](https://github.com/zhamao-robot/zhamao-framework/blob/master/LICENSE)
|
||||
[](https://packagist.org/packages/zhamao/framework)
|
||||
[](https://github.com/howmanybots/onebot)
|
||||

|
||||

|
||||
|
||||
[](https://github.com/zhamao-robot/zhamao-framework/search?q=AnnotationBase)
|
||||
[](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
|
||||
### 支付宝
|
||||

|
||||
|
||||
如果你对我们的周边感兴趣,我们还有炸毛机器人定制 logo 的雨伞,详情咨询作者 QQ,我们会作为您捐助了本项目!
|
||||
|
||||
## 关于
|
||||
框架和 SDK 是 炸毛机器人 项目的核心框架开源部分。炸毛机器人是作者写的一个高性能机器人,曾获全国计算机设计大赛一等奖。
|
||||
|
||||
作者的炸毛机器人已从2018年初起稳定运行了**四年**,并且持续迭代。
|
||||
作者的炸毛机器人已从2018年初起稳定运行了**四年半**,并且持续迭代。
|
||||
|
||||
欢迎随时在 HTTP-API 插件群里提问,当然更好的话可以加作者 QQ([627577391](http://wpa.qq.com/msgrd?v=3&uin=627577391&site=qq&menu=yes))或提交 Issue 进行疑难解答。
|
||||
|
||||
@@ -110,4 +103,10 @@ vendor/bin/start server
|
||||
|
||||
在贡献代码时,请保管好自己的全局配置文件中的敏感信息,请勿将带有个人信息的配置文件上传 GitHub 等网站。
|
||||
|
||||

|
||||
感谢 JetBrains 为此开源项目提供 PhpStorm 开发工具支持:
|
||||
|
||||
<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/PhpStorm.svg" width="300">
|
||||
|
||||
感谢 [php-libonebot](https://github.com/botuniverse/php-libonebot) 开发者 @sunxyw 中为项目开发规范化提出的一些建议。
|
||||
|
||||
<!--  -->
|
||||
|
||||
118
bin/watcher
Executable file
118
bin/watcher
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
_red="\e[33m"
|
||||
_green="\e[32m"
|
||||
_reset="\e[0m"
|
||||
|
||||
unix_s=$(uname -s)
|
||||
|
||||
unix_release=$(
|
||||
marked_release=""
|
||||
if [ "$unix_s" = "Linux" ]; then
|
||||
echo $HOME | grep com.termux >/dev/null
|
||||
if [ $? == 0 ]; then
|
||||
marked_release="termux"
|
||||
elif [ -f "/etc/redhat-release" ]; then
|
||||
if [ "$(cat /etc/redhat-release | awk '{print $1}' | grep -v '^$')" = "CentOS" ]; then
|
||||
marked_release="CentOS"
|
||||
else
|
||||
marked_release="unknown"
|
||||
fi
|
||||
elif [ -f "/etc/os-release" ]; then
|
||||
cat /etc/os-release | grep Alpine > /dev/null
|
||||
if [ $? == 0 ]; then
|
||||
marked_release="Alpine"
|
||||
fi
|
||||
fi
|
||||
if [ "$marked_release" = "" ]; then
|
||||
if [ -f "/etc/issue" ]; then
|
||||
marked_release=$(cat /etc/issue | grep -v '^$' | awk '{print $1}')
|
||||
else
|
||||
marked_release="unknown"
|
||||
fi
|
||||
fi
|
||||
elif [ "$unix_s" = "Darwin" ]; then
|
||||
marked_release=$(sw_vers | grep ProductName | awk '{print $2" "$3" "$4}')
|
||||
fi
|
||||
echo $marked_release
|
||||
)
|
||||
unix_release=$(echo $unix_release | xargs)
|
||||
|
||||
function echo_error() {
|
||||
echo -e "${_red}$1${_reset}"
|
||||
}
|
||||
|
||||
function echo_info() {
|
||||
echo -e "${_green}$1${_reset}"
|
||||
}
|
||||
|
||||
function install_test() {
|
||||
which fswatch >/dev/null
|
||||
if [ $? != 0 ]; then
|
||||
operate_confirm "fswatch还没有安装,是否确认安装?" && install_fswatch
|
||||
fi
|
||||
}
|
||||
function install_fswatch() {
|
||||
if [ "$unix_s" = "Linux" ]; then
|
||||
case $unix_release in
|
||||
"Kali" | "Ubuntu" | "Debian" | "Raspbian" | 'Pop!_OS')
|
||||
sudo apt-get install fswatch -y ;;
|
||||
#"termux") pkg install $1 -y ;;
|
||||
"CentOS")
|
||||
curl -o fswatch.tgz https://download.fastgit.org/emcrisostomo/fswatch/releases/download/1.16.0/fswatch-1.16.0.tar.gz && \
|
||||
tar -xzf fswatch.tgz && \
|
||||
cd fswatch-1.16.0 && \
|
||||
./configure && \
|
||||
make && \
|
||||
sudo make install && \
|
||||
cd .. && \
|
||||
rm -rf fswatch.tgz fswatch-1.16.0
|
||||
;;
|
||||
#"Alpine") apk add $1 ;;
|
||||
*)
|
||||
echo_error "不支持的 Linux 发行版:$unix_release"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
elif [ "$unix_s" = "Darwin" ]; then
|
||||
brew install fswatch
|
||||
else
|
||||
echo_error "不支持的操作系统:$unix_s"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
function operate_confirm() {
|
||||
echo -n $(echo_info "$1 [Y/n] ")
|
||||
read operate
|
||||
operate=$(echo $operate | tr A-Z a-z)
|
||||
if [[ "$operate" = "y" || "$operate" = "" ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo_info "当前系统:$unix_release"
|
||||
install_test
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
else
|
||||
echo_info "程序路径:$(which fswatch)"
|
||||
fi
|
||||
watch_dir="./src"
|
||||
if [ ! -d "$watch_dir" ]; then
|
||||
echo_error "src目录不存在!"
|
||||
exit 1
|
||||
else
|
||||
echo_info "监听目录:$watch_dir"
|
||||
fi
|
||||
_pid=$(cat .daemon_pid | awk -F"\"pid\": " '{print $2}' | grep -v ^$ | sed 's/,//g')
|
||||
if [ "$_pid" = "" ]; then
|
||||
echo_error "未检测到框架进程"
|
||||
exit 1
|
||||
fi
|
||||
fswatch $watch_dir | while read file
|
||||
do
|
||||
echo "Detect file change: $file"
|
||||
kill -USR1 $_pid
|
||||
done
|
||||
@@ -4,9 +4,22 @@
|
||||
"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": [
|
||||
"echo committing as $(git config user.name)",
|
||||
"./vendor/bin/php-cs-fixer fix --dry-run --diff ./src"
|
||||
],
|
||||
"pre-push": [
|
||||
"./vendor/bin/php-cs-fixer fix --dry-run --diff ./src",
|
||||
"composer analyse"
|
||||
]
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
@@ -17,25 +30,26 @@
|
||||
"prefer-stable": true,
|
||||
"bin": [
|
||||
"bin/start",
|
||||
"bin/phpunit-swoole"
|
||||
"bin/phpunit-swoole",
|
||||
"bin/watcher"
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"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",
|
||||
@@ -52,8 +66,28 @@
|
||||
"src/ZM/global_functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Module\\": "src/Module",
|
||||
"Custom\\": "src/Custom"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"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",
|
||||
"phpunit/phpunit": "^8.5 || ^9.0",
|
||||
"swoole/ide-helper": "^4.5"
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": [
|
||||
"[ $COMPOSER_DEV_MODE -eq 0 ] || vendor/bin/cghooks add"
|
||||
],
|
||||
"analyse": "phpstan analyse --memory-limit 300M -l 0 ./src",
|
||||
"cs-fix": "php-cs-fixer fix $1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +1,73 @@
|
||||
<?php
|
||||
/** @noinspection PhpFullyQualifiedNameUsageInspection */
|
||||
|
||||
/** @noinspection PhpComposerExtensionStubsInspection */
|
||||
|
||||
/** bind host */
|
||||
declare(strict_types=1);
|
||||
|
||||
/* bind host */
|
||||
$config['host'] = '0.0.0.0';
|
||||
|
||||
/** bind port */
|
||||
/* bind port */
|
||||
$config['port'] = 20001;
|
||||
|
||||
/** 框架开到公网或外部的HTTP访问链接,通过 DataProvider::getFrameworkLink() 获取 */
|
||||
/* 框架开到公网或外部的HTTP访问链接,通过 DataProvider::getFrameworkLink() 获取 */
|
||||
$config['http_reverse_link'] = 'http://127.0.0.1:' . $config['port'];
|
||||
|
||||
/** 框架是否启动debug模式,当debug模式为true时,启用热更新(需要安装inotify扩展) */
|
||||
/* 框架是否启动debug模式,当debug模式为true时,启用热更新(需要安装inotify扩展) */
|
||||
$config['debug_mode'] = false;
|
||||
|
||||
/** 存放框架内文件数据的目录 */
|
||||
/* 存放框架内文件数据的目录 */
|
||||
$config['zm_data'] = realpath(WORKING_DIR) . '/zm_data/';
|
||||
|
||||
/** 存放各个模块配置文件的目录 */
|
||||
/* 存放各个模块配置文件的目录 */
|
||||
$config['config_dir'] = $config['zm_data'] . 'config/';
|
||||
|
||||
/** 存放崩溃和运行日志的目录 */
|
||||
/* 存放崩溃和运行日志的目录 */
|
||||
$config['crash_dir'] = $config['zm_data'] . 'crash/';
|
||||
|
||||
/** 对应swoole的server->set参数 */
|
||||
/* 对应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
|
||||
'max_wait_time' => 5,
|
||||
// 'task_worker_num' => 4,
|
||||
// 'task_enable_coroutine' => true
|
||||
];
|
||||
|
||||
|
||||
/** 一些框架与框架运行时设置的调整 */
|
||||
/* 一些框架与框架运行时设置的调整 */
|
||||
$config['runtime'] = [
|
||||
'swoole_coroutine_hook_flags' => SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL),
|
||||
'swoole_server_mode' => SWOOLE_PROCESS,
|
||||
'middleware_error_policy' => 1,
|
||||
'reload_delay_time' => 800,
|
||||
'global_middleware_binding' => []
|
||||
'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
|
||||
'auto_save_interval' => 900,
|
||||
];
|
||||
|
||||
/** 大容量跨进程变量存储(2.2.0可用) */
|
||||
/* 大容量跨进程变量存储(2.2.0可用) */
|
||||
$config['worker_cache'] = [
|
||||
'worker' => 0,
|
||||
'transaction_timeout' => 30000
|
||||
'transaction_timeout' => 30000,
|
||||
];
|
||||
|
||||
/** MySQL数据库连接信息,host留空则启动时不创建sql连接池 */
|
||||
/* MySQL数据库连接信息,host留空则启动时不创建sql连接池 */
|
||||
$config['mysql_config'] = [
|
||||
'host' => '',
|
||||
'port' => 3306,
|
||||
@@ -71,73 +79,74 @@ $config['mysql_config'] = [
|
||||
'pool_size' => 64,
|
||||
'options' => [
|
||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
|
||||
]
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
],
|
||||
];
|
||||
|
||||
/** Redis连接信息,host留空则启动时不创建Redis连接池 */
|
||||
/* Redis连接信息,host留空则启动时不创建Redis连接池 */
|
||||
$config['redis_config'] = [
|
||||
'host' => '',
|
||||
'port' => 6379,
|
||||
'timeout' => 1,
|
||||
'db_index' => 0,
|
||||
'auth' => ''
|
||||
'auth' => '',
|
||||
];
|
||||
|
||||
/** onebot连接约定的token */
|
||||
/* onebot连接约定的token */
|
||||
$config['access_token'] = '';
|
||||
|
||||
/** HTTP服务器固定请求头的返回 */
|
||||
/* HTTP服务器固定请求头的返回 */
|
||||
$config['http_header'] = [
|
||||
'Server' => 'zhamao-framework',
|
||||
'Content-Type' => 'text/html; charset=utf-8'
|
||||
'Content-Type' => 'text/html; charset=utf-8',
|
||||
];
|
||||
|
||||
/** HTTP服务器在指定状态码下回复的页面(默认) */
|
||||
/* HTTP服务器在指定状态码下回复的页面(默认) */
|
||||
$config['http_default_code_page'] = [
|
||||
'404' => '404.html'
|
||||
'404' => '404.html',
|
||||
];
|
||||
|
||||
/** zhamao-framework在框架启动时初始化的atomic们 */
|
||||
/* zhamao-framework在框架启动时初始化的atomic们 */
|
||||
$config['init_atomics'] = [
|
||||
//'custom_atomic_name' => 0, //自定义添加的Atomic
|
||||
// 'custom_atomic_name' => 0, //自定义添加的Atomic
|
||||
];
|
||||
|
||||
/** 终端日志显示等级(0-4) */
|
||||
/* 终端日志显示等级(0-4) */
|
||||
$config['info_level'] = 2;
|
||||
|
||||
/** 上下文接口类 implemented from ContextInterface */
|
||||
/* 上下文接口类 implemented from ContextInterface */
|
||||
$config['context_class'] = \ZM\Context\Context::class;
|
||||
|
||||
/** 静态文件访问 */
|
||||
/* 静态文件访问 */
|
||||
$config['static_file_server'] = [
|
||||
'status' => false,
|
||||
'document_root' => realpath(__DIR__ . '/../') . '/resources/html',
|
||||
'document_index' => [
|
||||
'index.html'
|
||||
]
|
||||
'index.html',
|
||||
],
|
||||
];
|
||||
|
||||
/** 机器人解析模块,关闭后无法使用如CQCommand等注解(上面的modules即将废弃) */
|
||||
/* 机器人解析模块,关闭后无法使用如CQCommand等注解(上面的modules即将废弃) */
|
||||
$config['onebot'] = [
|
||||
'status' => true,
|
||||
'single_bot_mode' => false,
|
||||
'message_level' => 99,
|
||||
'message_convert_string' => true
|
||||
'message_convert_string' => true,
|
||||
'message_command_policy' => 'interrupt',
|
||||
];
|
||||
|
||||
/** 一个远程简易终端,使用nc直接连接即可,但是不建议开放host为0.0.0.0(远程连接) */
|
||||
/* 一个远程简易终端,使用nc直接连接即可,但是不建议开放host为0.0.0.0(远程连接) */
|
||||
$config['remote_terminal'] = [
|
||||
'status' => false,
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 20002,
|
||||
'token' => ''
|
||||
'token' => '',
|
||||
];
|
||||
|
||||
/** 模块(插件)加载器的相关设置 */
|
||||
/* 模块(插件)加载器的相关设置 */
|
||||
$config['module_loader'] = [
|
||||
'enable_hotload' => false,
|
||||
'load_path' => $config['zm_data'] . 'modules'
|
||||
'load_path' => $config['zm_data'] . 'modules',
|
||||
];
|
||||
|
||||
return $config;
|
||||
|
||||
88
docs/advanced/example/integrate-qingyunke-chatbot.md
Normal file
88
docs/advanced/example/integrate-qingyunke-chatbot.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# 接入青云客智能聊天机器人API
|
||||
|
||||
作为一个群聊机器人,懂得聊天会让机器人增色不少,在大数据和 AI 热潮下,不少厂商都研发了自己的智能聊天 API,例如图灵机器人、腾讯智能闲聊等,大厂开发的 API 自然有着他人无可比拟的健壮性和可靠性,但是随之而来不菲的价格显然并不适合大众开发者。这时候一个免费、可用的智能聊天 API 便非常重要了,其中,青云客是少有的完全免费、无需注册的智能聊天 API,提供了包括智能聊天、歌词、天气查询、笑话等多种有用功能,且接入简单,非常适合新手开发者尝试。
|
||||
|
||||
## 结果演示
|
||||

|
||||
|
||||
|
||||
## 阅读接入指南
|
||||
|
||||
不管接入何种服务,阅读接入指南永远都是最优先、最重要的一步,所幸青云客的接入指南十分简单,简单来说归纳为以下:
|
||||
* 请求: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;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
112
docs/advanced/example/weather-bot.md
Normal file
112
docs/advanced/example/weather-bot.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# 基于词性分析和魅族天气的天气查询机器人
|
||||
|
||||
本文将基于 [`jieba-php`](https://github.com/fukuball/jieba-php) 中文分词库以及 [魅族天气 API](https://github.com/shichunlei/-Api/blob/master/MeizuWeather.md) 开发一个天气查询机器人。
|
||||
|
||||
## 结果演示
|
||||

|
||||
尾部的随机表情并非本教程的一部分。
|
||||
|
||||
## 逻辑编写
|
||||
|
||||
[`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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
1
docs/assets/css/library/default.min.css
vendored
Normal file
1
docs/assets/css/library/default.min.css
vendored
Normal 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}
|
||||
@@ -128,3 +128,52 @@ public function onStart() {
|
||||
( 其实还是很聪明的!
|
||||
</chat-box>
|
||||
|
||||
### strToArray()
|
||||
|
||||
将 `string` 类型的消息文本转换为 `array` 格式。
|
||||
|
||||
定义:`strToArray($msg, bool $ignore_space = true, bool $trim_text = false)`
|
||||
|
||||
参数 `$msg` 为带 OB/CQ 码的字符串消息,如 `你好啊,[CQ:at,qq=123]`。
|
||||
|
||||
参数 `$ignore_space` 在 `false` 时,转换的数组内会包含空 `text` 段。
|
||||
|
||||
参数 `$trim_text` 为 `true` 时,会自动去除 `text` 段消息头尾的换行符和空格。
|
||||
|
||||
这个命令转换的数组格式符合 OneBot 11/12 标准,但细节上可能会与不同 OneBot 实现有所差异。
|
||||
|
||||
```php
|
||||
$str = "你好啊,[CQ:at,qq=123]";
|
||||
$arr = \ZM\Utils\MessageUtil::strToArray($str);
|
||||
```
|
||||
|
||||
转换结果参考如下:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "text",
|
||||
"data": {
|
||||
"text": "你好啊,"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "at",
|
||||
"data": {
|
||||
"qq": "123"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### arrayToStr()
|
||||
|
||||
将 `array` 格式的消息内容转换为字符串 + CQ 码的形式。
|
||||
|
||||
定义:`arrayToStr(array $array)`
|
||||
|
||||
```php
|
||||
// 我们使用上边的 $arr 作为传入值。
|
||||
$new_str = \ZM\Utils\MessageUtil::arrayToStr($arr);
|
||||
// 结果:"你好啊,[CQ:at,qq=123]"
|
||||
```
|
||||
@@ -769,6 +769,21 @@ vardump($result["retcode"]); //如果成功撤回,输出 int(0)
|
||||
|
||||
响应数据:无
|
||||
|
||||
### getExtendedAPI()
|
||||
|
||||
用来调用 OneBot 标准之外扩展出来的自定义 API。与下方 `callExtendedAPI` 不同的是,为了方便用户使用,炸毛框架内置了热门使用并且相对稳定的机器人客户端的专有 API。
|
||||
|
||||
目前内置了 `go-cqhttp` 频道相关的扩充 API。
|
||||
|
||||
使用示例:`getExtendedAPI('go-cqhttp')->getGuildList()`
|
||||
使用示例2:`getExtendedAPI()->sendGuildChannelMsg($guild_id, $channel_id, '频道的消息')`
|
||||
|
||||
唯一一个参数做保留,用于选择不同客户端,目前仅支持 `go-cqhttp`,所以缺省也默认为 `go-cqhttp`。
|
||||
|
||||
!!! warning "注意"
|
||||
|
||||
由于不同版本的扩展 API 变化可能会很大,改动较多,炸毛框架不会将对应扩展方法写入文档,具体调用情况可根据 IDE 自动补全中的文档或对应类的注释查看。
|
||||
|
||||
### callExtendedAPI() (扩充 API)
|
||||
|
||||
用来调用 OneBot 标准之外扩展出来的自定义 API。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
此类管理的是 TaskWorker 相关工作。有关使用 TaskWorker 的教程,见 [进阶 - 使用 TaskWorker 进程处理密集运算](/advanced/task-worker)
|
||||
|
||||
类定义:`\ZM\Utils\TaskManager`
|
||||
类定义:`\ZM\Utils\Manager\TaskManager`
|
||||
|
||||
使用 TaskWorker 需要先在 `global.php` 配置文件中开启!
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ src/
|
||||
```json
|
||||
{
|
||||
"name": "my-first-module",
|
||||
"description": "这个是一个示例模块打包教程"
|
||||
"description": "这个是一个示例模块打包教程",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ DataProvider 是框架内提供的一个简易的文件管理类。
|
||||
|
||||
同 `working_dir()`。
|
||||
|
||||
## DataProvider::getSourceRootDir()
|
||||
|
||||
获取用户的源码根目录,除 Phar 模式外与 `getWorkingDir()` 相同。
|
||||
|
||||
## DataProvider::getFrameworkLink()
|
||||
|
||||
同 `ZMConfig::get("global", "http_reverse_link")`,获取反向代理的链接。
|
||||
@@ -46,6 +50,45 @@ DataProvider::getDataFolder("TestModule"); // 例如返回 /root/zhamao-framewor
|
||||
|
||||
文件名同上 `saveToJson()` 的定义,解析后的返回值为原先的内容或 `null`(如果文件不存在或 json 解析失败)。
|
||||
|
||||
## DataProvider::scanDirFiles()
|
||||
|
||||
递归或非递归扫描目录,返回相对目录的文件列表或绝对目录的文件列表。(非常好用)
|
||||
|
||||
定义:`scanDirFiles($dir, $recursive = true, $relative = false)`
|
||||
|
||||
`$dir` 为要扫描的目录,`$recursive` 为是否递归,`$relative` 为是否返回相对目录的文件列表。
|
||||
|
||||
从给定的目录下开始遍历整个目录,如果将 `$recursive` 设置为 `true`,则会递归扫描子目录,否则将返回包含目录的文件列表。
|
||||
|
||||
如果将 `$relative` 设置为 `true`,则会返回文件列表的相对路径,否则返回绝对路径。
|
||||
|
||||
例如:假设目录 `/home/test/` 下有两个文件:`test1.txt` 和 `testdir/test2.txt`:如果将 `$recursive` 设置为 `true`,`$relative` 设置为 `false`,则返回的文件列表为:
|
||||
|
||||
```json
|
||||
[
|
||||
"/home/test/test1.txt",
|
||||
"home/test/testdir/test2.txt"
|
||||
]
|
||||
```
|
||||
|
||||
相同条件下,如果将 `$relative` 设置为 `true`:
|
||||
|
||||
```json
|
||||
[
|
||||
"test1.txt",
|
||||
"testdir/test2.txt"
|
||||
]
|
||||
```
|
||||
|
||||
如果再把 `$recursive` 设置为 `false`:
|
||||
|
||||
```json
|
||||
[
|
||||
"test1.txt",
|
||||
"testdir"
|
||||
]
|
||||
```
|
||||
|
||||
## 其他文件读取
|
||||
|
||||
框架比较贴近原生的 PHP,所以推荐直接使用原生的方法来读写文件(`file_get_contents` 和 `file_put_contents`)。但有一点要注意,框架内最好使用**工作目录或者绝对路径**。
|
||||
|
||||
@@ -6,9 +6,18 @@
|
||||
|
||||
但是如果因为用户的误操作,导致炸毛框架其中的一个或多个进程阻塞,或者比如将框架挂在 screen 等守护但是守护服务进程被杀掉,总之就是无法使用 Ctrl+C 的方式正常关闭框架,这时就需要正确地杀掉所有框架进程(这固然可能会造成内存的缓存数据丢失)。
|
||||
|
||||
### v2.7.0 及以上版本教程
|
||||
|
||||
- 安全关框架指令:`./zhamao server:stop`
|
||||
- 万能杀死所有框架进程指令:`./zhamao server:stop --force`
|
||||
- 监视框架是否在运行:`./zhamao server:status`
|
||||
- Worker 进程卡死:连续按 5 次 Ctrl+C 即可强行杀掉所有进程(SIGKILL)
|
||||
|
||||
### v2.6.6 及以下版本教程
|
||||
|
||||
!!! warning "注意"
|
||||
|
||||
下方涉及 `ps` 命令后使用 `grep` 过滤的框架进程方式,如果你的服务器同时有其他使用 PHP 启动的服务,命令行刚好有 `server` 字样,可能会导致误杀,如果有影响的话,建议将 `grep server` 换成你启动时命令行的特殊参数或手动排除!
|
||||
下方涉及 `ps` 命令后使用 `grep` 过滤的框架进程方式,如果你的服务器同时有其他使用 PHP 启动的服务,命令行刚好有 `server` 字样,可能会导致误杀,如果有影响的话,建议将 `grep server` 换成你启动时命令行的特殊参数或手动排除!
|
||||
|
||||
**一、**首先,使用 `ps`、`htop`、`netstat -nlp` 等命令确定框架的入口进程(也就是 Master 进程的 pid)。
|
||||
|
||||
|
||||
@@ -56,6 +56,9 @@
|
||||
| `swoole_coroutine_hook_flags` | Swoole 启动时一键协程化 Hook 的 Flag 值,详见 [一键协程化](http://wiki.swoole.com/#/runtime?id=%e5%87%bd%e6%95%b0%e5%8e%9f%e5%9e%8b) | `SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL)` |
|
||||
| `swoole_server_mode` | Swoole Server 启动的进程模式,有 `SWOOLE_PROCESS` 和 `SWOOLE_BASE` 两种,见 [启动方式](http://wiki.swoole.com/#/learn?id=swoole_process) | `SWOOLE_PROCESS` |
|
||||
| `middleware_error_policy` | 中间件错误处理策略,见 [中间件 - 错误处理策略](../../event/middleware/#_6) | 1 |
|
||||
| `reload_delay_time` | 框架 reload 重载命令接收后延迟的时间(毫秒,0 为不等待) | 800 |
|
||||
| `global_middleware_binding` | 给注解事件绑定全局中间件,见 [中间件 - 全局中间件](../../event/middleware/#_6) | `[]` |
|
||||
| `save_console_log_file` | 当这里输入字符串路径时,所有 `Console::xxx()` 输出的日志都将保存到目标文件 | false |
|
||||
|
||||
### 子表 **light_cache**
|
||||
|
||||
@@ -106,11 +109,13 @@
|
||||
|
||||
### 子表 onebot
|
||||
|
||||
| 配置名称 | 说明 | 默认值 |
|
||||
| ----------------- | ------------------------------------------------------------ | ------ |
|
||||
| `status` | 是否开启 OneBot 标准机器人解析功能 | true |
|
||||
| `single_bot_mode` | 是否开启单机器人模式 | false |
|
||||
| `message_level` | 机器人的 WebSocket 事件在 Swoole 原生事件 `@OnMessageEvent` 中的等级(越高说明越被优先处理) | 99999 |
|
||||
| 配置名称 | 说明 | 默认值 |
|
||||
| ------------------------ | ------------------------------------------------------------ | ------ |
|
||||
| `status` | 是否开启 OneBot 标准机器人解析功能 | true |
|
||||
| `single_bot_mode` | 是否开启单机器人模式 | false |
|
||||
| `message_level` | 机器人的 WebSocket 事件在 Swoole 原生事件 `@OnMessageEvent` 中的等级(越高说明越被优先处理) | 99 |
|
||||
| `message_convert_string` | 是否将数组格式的消息转换为字符串以保证与旧版本的兼容性 | true |
|
||||
| `message_command_policy` | CQCommand命令匹配后执行流程,`interrupt` 为不执行后续 CQMessage,`continue` 为继续 | `interrupt` |
|
||||
|
||||
### 子表 remote_terminal
|
||||
|
||||
|
||||
@@ -70,5 +70,9 @@
|
||||
| E00068 | 模块解包时无法正常拷贝文件 | 检查文件夹是否正常可以创建和写入。 |
|
||||
| E00069 | 框架不能启动两个 ConsoleApplication 实例 | 不要重复使用 `new ConsoleApplication()`。 |
|
||||
| E00070 | 框架找不到 `zm_data` 目录 | 检查配置中指定的 `zm_data` 目录是否存在。 |
|
||||
| E00071 | 框架找不到对应类型的 API 调用类 | 检查 `getExtendedAPI($name)` 传入的 `$name` 是否正确 |
|
||||
| E00072 | 上下文无法找到 | 检查上下文环境,如是否处于协程环境中 |
|
||||
| E00073 | 在类中找不到方法 | 检查调用对象是否存在对应的方法(method)或检查是否插入了对应的macro宏方法 |
|
||||
| E00074 | 参数非法 | 检查调用的参数是否正常(此处可能有多处问题,请看具体调用栈炸掉的地方) |
|
||||
| E99999 | 未知错误 | |
|
||||
|
||||
|
||||
@@ -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 ,或者你部署到了服务器后需要输入服务器地址。
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# 介绍
|
||||
|
||||
> 本文档为炸毛框架 v2 版本,如需查看 v1 版本,[点我](https://docs-v1.zhamao.xin/)。
|
||||
|
||||
!!! tip "提示"
|
||||
|
||||
编写文档需要较大精力,你也可以参与到本文档的建设中来,比如找错字,增加或更正内容,每页文档可直接点击右上方铅笔图标直接跳转至 GitHub 进行编辑,编辑后自动 Fork 并生成 Pull Request,以此来贡献此文档!
|
||||
|
||||
44
docs/javascripts/library/highlight.min.js
vendored
Normal file
44
docs/javascripts/library/highlight.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -4,6 +4,113 @@
|
||||
|
||||
同时此处将只使用 build 版本号进行区分。
|
||||
|
||||
## build 449 (2022-3-21)
|
||||
|
||||
- 新增 Composer 模块加载和分发模式
|
||||
|
||||
## 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 下运行时的一些问题
|
||||
- 新增 Console 日志输出到文件的功能
|
||||
|
||||
## build 433 (2021-12-28)
|
||||
|
||||
- 修复 OneBotV11 因 IDE 自动优化导致 API 接口发生变化的问题
|
||||
|
||||
## build 432 (2021-12-25)
|
||||
|
||||
- 新增 GoCqhttpAPI 包,用于支持额外的 OneBot Action(API)
|
||||
- 修复 MySQL 查询器中 `fetchOne()` 方法无法正确返回值的 Bug
|
||||
- 修复 Swoole Hook 因配置不当无法正确使用的 Bug
|
||||
|
||||
## build 431 (2021-12-22)
|
||||
|
||||
- 修复 Issue #50
|
||||
- 新增 PhpStorm IDE 直接运行框架的脚本
|
||||
|
||||
## build 430 (2021-12-8)
|
||||
|
||||
- 删除调试信息
|
||||
- 修复 #56 中关于数据库组件的 Bug
|
||||
|
||||
## build 429 (2021-12-7)
|
||||
|
||||
- 新增配置项 `onebot`.`message_command_policy`
|
||||
- 新增 CQCommand 阻断策略的自定义配置功能
|
||||
- 修复 CQAfter 无法正常使用的 bug #53
|
||||
|
||||
## build 428 (2021-11-16)
|
||||
|
||||
- 修复 `ctx()->waitMessage()` 在 array 消息模式下无法正确返回消息字符串的问题
|
||||
- 新增 `ctx()->getArrayMessage()` 和 `ctx()->getStringMessage()` 两个方法
|
||||
- 修复注解事件 `CQCommand` 和 `CQMessage` 在 array 消息模式下无法正确解析的 Bug
|
||||
|
||||
## build 427 (2021-11-16)
|
||||
|
||||
- 新增全局中间件,可在全局配置文件中设置
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
这里将会记录各个主版本的框架升级后,涉及 `global.php` 的更新日志,你可以根据这里描述的内容与你的旧配置文件进行合并。
|
||||
|
||||
## v2.7.0 (build 447)
|
||||
|
||||
- 新增 `$config['runtime']` 下的 `annotation_reader_ignore` 项。
|
||||
|
||||
## v2.6.6 (build 434)
|
||||
|
||||
- 新增 `$config['runtime']` 下的 `save_console_log_file` 项。
|
||||
|
||||
## v2.6.0 (build 427)
|
||||
|
||||
- 新增 `$config['runtime']` 下的 `reload_delay_time`、`global_middleware_binding` 项。
|
||||
|
||||
@@ -1,5 +1,90 @@
|
||||
# 更新日志(v2 版本)
|
||||
|
||||
## v2.7.2(build 449)
|
||||
|
||||
> 更新时间:2022.3.21
|
||||
|
||||
- 新增 Composer 模块加载和分发模式
|
||||
|
||||
## v2.7.1(build 448)
|
||||
|
||||
> 更新时间:2022.3.20
|
||||
|
||||
- 加快 build 命令的执行速度,取消进度条和提升性能
|
||||
|
||||
## v2.7.0(build 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.6(build 434)
|
||||
|
||||
> 更新时间:2022.1.8
|
||||
|
||||
- 修复框架在 PHP 8.1 下运行时的一些问题
|
||||
- 新增 Console 日志输出到文件的功能
|
||||
|
||||
## v2.6.5(build 433)
|
||||
|
||||
> 更新时间:2021.12.28
|
||||
|
||||
- 修复 OneBotV11 因 IDE 自动优化导致 API 接口发生变化的问题
|
||||
|
||||
## v2.6.4(build 432)
|
||||
|
||||
> 更新时间:2021.12.25
|
||||
|
||||
- 新增 GoCqhttpAPI 包,用于支持额外的 OneBot Action(API)
|
||||
- 修复 MySQL 查询器中 `fetchOne()` 方法无法正确返回值的 Bug
|
||||
- 修复 Swoole Hook 因配置不当无法正确使用的 Bug
|
||||
- 修复 Issue #50
|
||||
- 新增 PhpStorm IDE 直接运行框架的脚本
|
||||
|
||||
## v2.6.3 (build 430)
|
||||
|
||||
> 更新时间:2021.12.8
|
||||
|
||||
- 删除调试信息
|
||||
- 修复 #56 中关于数据库组件的 Bug
|
||||
|
||||
## v2.6.2 (build 429)
|
||||
|
||||
> 更新时间:2021.12.7
|
||||
|
||||
- 新增配置项 `onebot`.`message_command_policy`
|
||||
- 新增 CQCommand 阻断策略的自定义配置功能
|
||||
- 修复 CQAfter 无法正常使用的 bug #53
|
||||
|
||||
## v2.6.1 (build 428)
|
||||
|
||||
> 更新时间:2021.11.16
|
||||
|
||||
- 修复 ctx()->waitMessage() 在 array 消息模式下无法正确返回消息字符串的问题
|
||||
- 新增 ctx()->getArrayMessage() 和 ctx()->getStringMessage() 两个方法
|
||||
- 修复注解事件 CQCommand 和 CQMessage 在 array 消息模式下无法正确解析的 Bug
|
||||
|
||||
## v2.6.0 (build 427)
|
||||
|
||||
> 更新时间:2021.11.16
|
||||
|
||||
2
install-runtime.sh
Normal file → Executable file
2
install-runtime.sh
Normal file → Executable file
@@ -55,4 +55,4 @@ if [ $? -ne 0 ]; then
|
||||
fi
|
||||
echo "成功下载!" && \
|
||||
echo -e "PHP使用:\truntime/php -v" && \
|
||||
echo -e "Composer使用:\truntime/composer"
|
||||
echo -e "Composer使用:\truntime/composer"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
require_once "vendor/autoload.php";
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
use ZM\Annotation\CQ\CQCommand;
|
||||
use ZM\Annotation\Swoole\OnOpenEvent;
|
||||
@@ -9,17 +11,16 @@ use ZM\Console\Console;
|
||||
use ZM\Module\InstantModule;
|
||||
use ZM\ZMServer;
|
||||
|
||||
$weather = new InstantModule("weather");
|
||||
$weather = new InstantModule('weather');
|
||||
|
||||
|
||||
$weather->onEvent(OnOpenEvent::class, ['connect_type' => 'qq'], function(ConnectionObject $conn) {
|
||||
Console::info("机器人 " . $conn->getOption("connect_id") . " 已连接!");
|
||||
$weather->onEvent(OnOpenEvent::class, ['connect_type' => 'qq'], function (ConnectionObject $conn) {
|
||||
Console::info('机器人 ' . $conn->getOption('connect_id') . ' 已连接!');
|
||||
});
|
||||
|
||||
$weather->onEvent(CQCommand::class, ['match' => '你好'], function() {
|
||||
ctx()->reply("hello呀!");
|
||||
$weather->onEvent(CQCommand::class, ['match' => '你好'], function () {
|
||||
ctx()->reply('hello呀!');
|
||||
});
|
||||
|
||||
$app = new ZMServer("app-name");
|
||||
$app = new ZMServer('app-name');
|
||||
$app->addModule($weather);
|
||||
$app->run();
|
||||
$app->run();
|
||||
@@ -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 © 2019 - 2021 CrazyBot Team <span class="tx-switch">
|
||||
copyright: 'Copyright © 2019 - 2022 CrazyBot Team <span class="tx-switch">
|
||||
<button data-md-color-scheme="default"><code>默认模式</code></button>
|
||||
<button data-md-color-scheme="slate"><code>暗黑模式</code></button>
|
||||
</span>
|
||||
@@ -106,6 +106,7 @@ nav:
|
||||
- Console 终端: component/common/console.md
|
||||
- TaskWorker 管理: component/common/task-worker.md
|
||||
- Terminal 终端: component/common/remote-terminal.md
|
||||
- EventTracer 事件追踪器: component/common/event-tracer.md
|
||||
- HTTP 服务器工具类:
|
||||
- HTTP 和 WebSocket 客户端: component/http/zmrequest.md
|
||||
- HTTP 路由管理: component/http/route-manager.md
|
||||
@@ -124,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
|
||||
|
||||
7
phpstan.neon
Normal file
7
phpstan.neon
Normal file
@@ -0,0 +1,7 @@
|
||||
parameters:
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
level: 0
|
||||
paths:
|
||||
- ./src/
|
||||
ignoreErrors:
|
||||
- '#Used constant OS_TYPE_(LINUX|WINDOWS) not found#'
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
@@ -10,11 +13,17 @@ use ZM\Annotation\Interfaces\CustomAnnotation;
|
||||
/**
|
||||
* Class CustomAnnotation
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("ALL")
|
||||
* @package Custom\Annotation
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
|
||||
class Example extends AnnotationBase implements CustomAnnotation
|
||||
{
|
||||
/** @var string */
|
||||
public $str = '';
|
||||
|
||||
public function __construct($str = '')
|
||||
{
|
||||
$this->str = $str;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<?php /** @noinspection PhpFullyQualifiedNameUsageInspection */ #plain
|
||||
<?php
|
||||
|
||||
//这里写你的全局函数
|
||||
/**
|
||||
* @param callable $func
|
||||
* @param string $name
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
function pgo(callable $func, $name = "default") {
|
||||
\ZM\Utils\CoroutinePool::go($func, $name);
|
||||
declare(strict_types=1);
|
||||
|
||||
use ZM\Utils\CoroutinePool;
|
||||
|
||||
function pgo(callable $func, string $name = 'default')
|
||||
{
|
||||
CoroutinePool::go($func, $name);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
<?php /** @noinspection PhpMissingReturnTypeInspection */
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Module\Example;
|
||||
|
||||
use ZM\Annotation\CQ\CQBefore;
|
||||
use ZM\Annotation\CQ\CQCommand;
|
||||
use ZM\Annotation\CQ\CQMessage;
|
||||
use ZM\Annotation\Http\Middleware;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Annotation\Swoole\OnCloseEvent;
|
||||
use ZM\Annotation\Swoole\OnOpenEvent;
|
||||
use ZM\Annotation\Swoole\OnRequestEvent;
|
||||
use ZM\API\CQ;
|
||||
use ZM\API\TuringAPI;
|
||||
use ZM\API\OneBotV11;
|
||||
use ZM\API\TuringAPI;
|
||||
use ZM\ConnectionManager\ConnectionObject;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Annotation\CQ\CQCommand;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Event\EventDispatcher;
|
||||
use ZM\Exception\InterruptException;
|
||||
use ZM\Module\QQBot;
|
||||
@@ -24,7 +26,6 @@ use ZM\Utils\ZMUtil;
|
||||
|
||||
/**
|
||||
* Class Hello
|
||||
* @package Module\Example
|
||||
* @since 2.0
|
||||
*/
|
||||
class Hello
|
||||
@@ -33,49 +34,57 @@ 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
|
||||
* @CQCommand(".reload",user_id=627577391)
|
||||
*/
|
||||
public function reload() {
|
||||
ctx()->reply("重启中...");
|
||||
public function reload()
|
||||
{
|
||||
ctx()->reply('重启中...');
|
||||
ZMUtil::reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* @CQCommand("我是谁")
|
||||
*/
|
||||
public function whoami() {
|
||||
public function whoami()
|
||||
{
|
||||
$bot = ctx()->getRobot()->getLoginInfo();
|
||||
$bot_id = $bot["data"]["user_id"];
|
||||
$r = OneBotV11::get($bot_id);
|
||||
$bot_id = $bot['data']['user_id'];
|
||||
$r = OneBotV11::get($bot_id);
|
||||
$QQid = ctx()->getUserId();
|
||||
$nick = $r->getStrangerInfo($QQid)["data"]["nickname"];
|
||||
return "你是" . $nick . ",QQ号是" . $QQid;
|
||||
$nick = $r->getStrangerInfo($QQid)['data']['nickname'];
|
||||
return '你是' . $nick . ',QQ号是' . $QQid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向机器人发送"你好啊",也可回复这句话
|
||||
* @CQCommand(match="你好",alias={"你好啊","你是谁"})
|
||||
*/
|
||||
public function hello() {
|
||||
return "你好啊,我是由炸毛框架构建的机器人!";
|
||||
public function hello()
|
||||
{
|
||||
return '你好啊,我是由炸毛框架构建的机器人!';
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个最基本的第三方 API 接口使用示例
|
||||
* @CQCommand("一言")
|
||||
*/
|
||||
public function hitokoto() {
|
||||
$api_result = ZMRequest::get("https://v1.hitokoto.cn/");
|
||||
if ($api_result === false) return "接口请求出错,请稍后再试!";
|
||||
public function hitokoto()
|
||||
{
|
||||
$api_result = ZMRequest::get('https://v1.hitokoto.cn/');
|
||||
if ($api_result === false) {
|
||||
return '接口请求出错,请稍后再试!';
|
||||
}
|
||||
$obj = json_decode($api_result, true);
|
||||
if ($obj === null) return "接口解析出错!可能返回了非法数据!";
|
||||
return $obj["hitokoto"] . "\n----「" . $obj["from"] . "」";
|
||||
if ($obj === null) {
|
||||
return '接口解析出错!可能返回了非法数据!';
|
||||
}
|
||||
return $obj['hitokoto'] . "\n----「" . $obj['from'] . '」';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,33 +92,36 @@ class Hello
|
||||
* @CQCommand(start_with="机器人",end_with="机器人",message_type="group")
|
||||
* @CQMessage(message_type="private",level=1)
|
||||
*/
|
||||
public function turingAPI() {
|
||||
public function turingAPI()
|
||||
{
|
||||
$user_id = ctx()->getUserId();
|
||||
$api = ""; // 请在这里填入你的图灵机器人的apikey
|
||||
if ($api === "") return false; //如果没有填入apikey则此功能关闭
|
||||
$api = ''; // 请在这里填入你的图灵机器人的apikey
|
||||
if ($api === '') {
|
||||
return false;
|
||||
} // 如果没有填入apikey则此功能关闭
|
||||
if (($this->_running_annotation ?? null) instanceof CQCommand) {
|
||||
$msg = ctx()->getFullArg("我在!有什么事吗?");
|
||||
$msg = ctx()->getFullArg('我在!有什么事吗?');
|
||||
} else {
|
||||
$msg = ctx()->getMessage();
|
||||
}
|
||||
ctx()->setMessage($msg);
|
||||
if (MessageUtil::matchCommand($msg, ctx()->getData())->status === false) {
|
||||
return TuringAPI::getTuringMsg($msg, $user_id, $api);
|
||||
} else {
|
||||
QQBot::getInstance()->handle(ctx()->getData(), ctx()->getCache("level") + 1);
|
||||
//执行嵌套消息,递归层级+1
|
||||
return true;
|
||||
}
|
||||
QQBot::getInstance()->handle(ctx()->getData(), ctx()->getCache('level') + 1);
|
||||
// 执行嵌套消息,递归层级+1
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应at机器人的消息
|
||||
* @CQBefore("message")
|
||||
*/
|
||||
public function changeAt() {
|
||||
public function changeAt()
|
||||
{
|
||||
if (MessageUtil::isAtMe(ctx()->getMessage(), ctx()->getRobotId())) {
|
||||
$msg = str_replace(CQ::at(ctx()->getRobotId()), "", ctx()->getMessage());
|
||||
ctx()->setMessage("机器人" . $msg);
|
||||
$msg = str_replace(CQ::at(ctx()->getRobotId()), '', ctx()->getMessage());
|
||||
ctx()->setMessage('机器人' . $msg);
|
||||
Console::info(ctx()->getMessage());
|
||||
}
|
||||
return true;
|
||||
@@ -123,15 +135,16 @@ class Hello
|
||||
* @CQCommand(pattern="*从*到*的随机数")
|
||||
* @return string
|
||||
*/
|
||||
public function randNum() {
|
||||
public function randNum()
|
||||
{
|
||||
// 获取第一个数字类型的参数
|
||||
$num1 = ctx()->getNumArg("请输入第一个数字");
|
||||
$num1 = ctx()->getNumArg('请输入第一个数字');
|
||||
// 获取第二个数字类型的参数
|
||||
$num2 = ctx()->getNumArg("请输入第二个数字");
|
||||
$num2 = ctx()->getNumArg('请输入第二个数字');
|
||||
$a = min(intval($num1), intval($num2));
|
||||
$b = max(intval($num1), intval($num2));
|
||||
// 回复用户结果
|
||||
return "随机数是:" . mt_rand($a, $b);
|
||||
return '随机数是:' . mt_rand($a, $b);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,8 +152,9 @@ class Hello
|
||||
* @RequestMapping("/httpTimer")
|
||||
* @Middleware("timer")
|
||||
*/
|
||||
public function timer() {
|
||||
return "This page is used as testing TimerMiddleware! Do not use it in production.";
|
||||
public function timer()
|
||||
{
|
||||
return 'This page is used as testing TimerMiddleware! Do not use it in production.';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,8 +162,9 @@ class Hello
|
||||
* @RequestMapping("/index")
|
||||
* @RequestMapping("/")
|
||||
*/
|
||||
public function index() {
|
||||
return "Hello Zhamao!";
|
||||
public function index()
|
||||
{
|
||||
return 'Hello Zhamao!';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,8 +173,9 @@ class Hello
|
||||
* @param $param
|
||||
* @return string
|
||||
*/
|
||||
public function paramGet($param) {
|
||||
return "Hello, " . $param["name"];
|
||||
public function paramGet($param)
|
||||
{
|
||||
return 'Hello, ' . $param['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,17 +183,18 @@ class Hello
|
||||
* @OnOpenEvent("qq")
|
||||
* @param $conn
|
||||
*/
|
||||
public function onConnect(ConnectionObject $conn) {
|
||||
Console::info("机器人 " . $conn->getOption("connect_id") . " 已连接!");
|
||||
public function onConnect(ConnectionObject $conn)
|
||||
{
|
||||
Console::info('机器人 ' . $conn->getOption('connect_id') . ' 已连接!');
|
||||
}
|
||||
|
||||
/**
|
||||
* 在机器人断开连接后向终端输出信息
|
||||
* @OnCloseEvent("qq")
|
||||
* @param ConnectionObject $conn
|
||||
*/
|
||||
public function onDisconnect(ConnectionObject $conn) {
|
||||
Console::info("机器人 " . $conn->getOption("connect_id") . " 已断开连接!");
|
||||
public function onDisconnect(ConnectionObject $conn)
|
||||
{
|
||||
Console::info('机器人 ' . $conn->getOption('connect_id') . ' 已断开连接!');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +202,8 @@ class Hello
|
||||
* @OnRequestEvent(rule="ctx()->getRequest()->server['request_uri'] == '/favicon.ico'",level=200)
|
||||
* @throws InterruptException
|
||||
*/
|
||||
public function onRequest() {
|
||||
public function onRequest()
|
||||
{
|
||||
EventDispatcher::interrupt();
|
||||
}
|
||||
|
||||
@@ -193,8 +211,9 @@ class Hello
|
||||
* 框架会默认关闭未知的WebSocket链接,因为这个绑定的事件,你可以根据你自己的需求进行修改
|
||||
* @OnOpenEvent("default")
|
||||
*/
|
||||
public function closeUnknownConn() {
|
||||
Console::info("Unknown connection , I will close it.");
|
||||
public function closeUnknownConn()
|
||||
{
|
||||
Console::info('Unknown connection , I will close it.');
|
||||
server()->disconnect(ctx()->getConnection()->getFd());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Module\Middleware;
|
||||
|
||||
use Exception;
|
||||
@@ -13,7 +15,6 @@ use ZM\Http\MiddlewareInterface;
|
||||
/**
|
||||
* Class TimerMiddleware
|
||||
* 示例中间件:用于统计路由函数运行时间用的
|
||||
* @package Module\Middleware
|
||||
* @MiddlewareClass("timer")
|
||||
*/
|
||||
class TimerMiddleware implements MiddlewareInterface
|
||||
@@ -22,9 +23,9 @@ class TimerMiddleware implements MiddlewareInterface
|
||||
|
||||
/**
|
||||
* @HandleBefore()
|
||||
* @return bool
|
||||
*/
|
||||
public function onBefore(): bool {
|
||||
public function onBefore(): bool
|
||||
{
|
||||
$this->starttime = microtime(true);
|
||||
return true;
|
||||
}
|
||||
@@ -32,17 +33,18 @@ class TimerMiddleware implements MiddlewareInterface
|
||||
/**
|
||||
* @HandleAfter()
|
||||
*/
|
||||
public function onAfter() {
|
||||
Console::info("Using " . round((microtime(true) - $this->starttime) * 1000, 3) . " ms.");
|
||||
public function onAfter()
|
||||
{
|
||||
Console::info('Using ' . round((microtime(true) - $this->starttime) * 1000, 3) . ' ms.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @HandleException(\Exception::class)
|
||||
* @param Exception $e
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onException(Exception $e) {
|
||||
Console::error("Using " . round((microtime(true) - $this->starttime) * 1000, 3) . " ms but an Exception occurred.");
|
||||
public function onException(Exception $e)
|
||||
{
|
||||
Console::error('Using ' . round((microtime(true) - $this->starttime) * 1000, 3) . ' ms but an Exception occurred.');
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?php /** @noinspection PhpUnused */
|
||||
|
||||
/** @noinspection PhpMissingReturnTypeInspection */
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\API;
|
||||
|
||||
|
||||
use ZM\Console\Console;
|
||||
use ZM\Entity\CQObject;
|
||||
|
||||
@@ -16,12 +14,13 @@ class CQ
|
||||
* @param $qq
|
||||
* @return string
|
||||
*/
|
||||
public static function at($qq) {
|
||||
if (is_numeric($qq) || $qq === "all") {
|
||||
return "[CQ:at,qq=" . $qq . "]";
|
||||
public static function at($qq)
|
||||
{
|
||||
if (is_numeric($qq) || $qq === 'all') {
|
||||
return '[CQ:at,qq=' . $qq . ']';
|
||||
}
|
||||
Console::warning(zm_internal_errcode("E00035") . "传入的QQ号码($qq)错误!");
|
||||
return " ";
|
||||
Console::warning(zm_internal_errcode('E00035') . "传入的QQ号码({$qq})错误!");
|
||||
return ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,127 +28,130 @@ class CQ
|
||||
* @param $id
|
||||
* @return string
|
||||
*/
|
||||
public static function face($id) {
|
||||
public static function face($id)
|
||||
{
|
||||
if (is_numeric($id)) {
|
||||
return "[CQ:face,id=" . $id . "]";
|
||||
return '[CQ:face,id=' . $id . ']';
|
||||
}
|
||||
Console::warning(zm_internal_errcode("E00035") . "传入的face id($id)错误!");
|
||||
return " ";
|
||||
Console::warning(zm_internal_errcode('E00035') . "传入的face id({$id})错误!");
|
||||
return ' ';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送图片
|
||||
* @param $file
|
||||
* @param bool $cache
|
||||
* @param bool $flash
|
||||
* @param bool $proxy
|
||||
* @param int $timeout
|
||||
* @return string
|
||||
*/
|
||||
public static function image($file, bool $cache = true, bool $flash = false, bool $proxy = true, int $timeout = -1) {
|
||||
public static function image($file, bool $cache = true, bool $flash = false, bool $proxy = true, int $timeout = -1)
|
||||
{
|
||||
return
|
||||
"[CQ:image,file=" . self::encode($file, true) .
|
||||
(!$cache ? ",cache=0" : "") .
|
||||
($flash ? ",type=flash" : "") .
|
||||
(!$proxy ? ",proxy=false" : "") .
|
||||
($timeout != -1 ? (",timeout=" . $timeout) : "") .
|
||||
"]";
|
||||
'[CQ:image,file=' . self::encode($file, true) .
|
||||
(!$cache ? ',cache=0' : '') .
|
||||
($flash ? ',type=flash' : '') .
|
||||
(!$proxy ? ',proxy=false' : '') .
|
||||
($timeout != -1 ? (',timeout=' . $timeout) : '') .
|
||||
']';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送语音
|
||||
* @param $file
|
||||
* @param bool $magic
|
||||
* @param bool $cache
|
||||
* @param bool $proxy
|
||||
* @param int $timeout
|
||||
* @return string
|
||||
*/
|
||||
public static function record($file, bool $magic = false, bool $cache = true, bool $proxy = true, int $timeout = -1) {
|
||||
public static function record($file, bool $magic = false, bool $cache = true, bool $proxy = true, int $timeout = -1)
|
||||
{
|
||||
return
|
||||
"[CQ:record,file=" . self::encode($file, true) .
|
||||
(!$cache ? ",cache=0" : "") .
|
||||
($magic ? ",magic=1" : "") .
|
||||
(!$proxy ? ",proxy=false" : "") .
|
||||
($timeout != -1 ? (",timeout=" . $timeout) : "") .
|
||||
"]";
|
||||
'[CQ:record,file=' . self::encode($file, true) .
|
||||
(!$cache ? ',cache=0' : '') .
|
||||
($magic ? ',magic=1' : '') .
|
||||
(!$proxy ? ',proxy=false' : '') .
|
||||
($timeout != -1 ? (',timeout=' . $timeout) : '') .
|
||||
']';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送短视频
|
||||
* @param $file
|
||||
* @param bool $cache
|
||||
* @param bool $proxy
|
||||
* @param int $timeout
|
||||
* @return string
|
||||
*/
|
||||
public static function video($file, bool $cache = true, bool $proxy = true, int $timeout = -1) {
|
||||
public static function video($file, bool $cache = true, bool $proxy = true, int $timeout = -1)
|
||||
{
|
||||
return
|
||||
"[CQ:video,file=" . self::encode($file, true) .
|
||||
(!$cache ? ",cache=0" : "") .
|
||||
(!$proxy ? ",proxy=false" : "") .
|
||||
($timeout != -1 ? (",timeout=" . intval($timeout)) : "") .
|
||||
"]";
|
||||
'[CQ:video,file=' . self::encode($file, true) .
|
||||
(!$cache ? ',cache=0' : '') .
|
||||
(!$proxy ? ',proxy=false' : '') .
|
||||
($timeout != -1 ? (',timeout=' . $timeout) : '') .
|
||||
']';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送投掷骰子(只能在单条回复中单独使用)
|
||||
* @return string
|
||||
*/
|
||||
public static function rps() {
|
||||
return "[CQ:rps]";
|
||||
public static function rps()
|
||||
{
|
||||
return '[CQ:rps]';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送掷骰子表情(只能在单条回复中单独使用)
|
||||
* @return string
|
||||
*/
|
||||
public static function dice() {
|
||||
return "[CQ:dice]";
|
||||
public static function dice()
|
||||
{
|
||||
return '[CQ:dice]';
|
||||
}
|
||||
|
||||
/**
|
||||
* 戳一戳(原窗口抖动,仅支持好友消息使用)
|
||||
* @return string
|
||||
*/
|
||||
public static function shake() {
|
||||
return "[CQ:shake]";
|
||||
public static function shake()
|
||||
{
|
||||
return '[CQ:shake]';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送新的戳一戳
|
||||
* @param $type
|
||||
* @param $id
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public static function poke($type, $id, string $name = "") {
|
||||
return "[CQ:poke,type=$type,id=$id" . ($name != "" ? (",name=" . self::encode($name, true)) : "") . "]";
|
||||
public static function poke($type, $id, string $name = '')
|
||||
{
|
||||
return "[CQ:poke,type={$type},id={$id}" . ($name != '' ? (',name=' . self::encode($name, true)) : '') . ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送匿名消息
|
||||
* @param int $ignore
|
||||
* @return string
|
||||
*/
|
||||
public static function anonymous(int $ignore = 1) {
|
||||
return "[CQ:anonymous" . ($ignore != 1 ? ",ignore=0" : "") . "]";
|
||||
public static function anonymous(int $ignore = 1)
|
||||
{
|
||||
return '[CQ:anonymous' . ($ignore != 1 ? ',ignore=0' : '') . ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送链接分享(只能在单条回复中单独使用)
|
||||
* @param $url
|
||||
* @param $title
|
||||
* @param null $content
|
||||
* @param null $image
|
||||
* @param null $content
|
||||
* @param null $image
|
||||
* @return string
|
||||
*/
|
||||
public static function share($url, $title, $content = null, $image = null) {
|
||||
if ($content === null) $c = "";
|
||||
else $c = ",content=" . self::encode($content, true);
|
||||
if ($image === null) $i = "";
|
||||
else $i = ",image=" . self::encode($image, true);
|
||||
return "[CQ:share,url=" . self::encode($url, true) . ",title=" . self::encode($title, true) . $c . $i . "]";
|
||||
public static function share($url, $title, $content = null, $image = null)
|
||||
{
|
||||
if ($content === null) {
|
||||
$c = '';
|
||||
} else {
|
||||
$c = ',content=' . self::encode($content, true);
|
||||
}
|
||||
if ($image === null) {
|
||||
$i = '';
|
||||
} else {
|
||||
$i = ',image=' . self::encode($image, true);
|
||||
}
|
||||
return '[CQ:share,url=' . self::encode($url, true) . ',title=' . self::encode($title, true) . $c . $i . ']';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,25 +160,25 @@ class CQ
|
||||
* @param $id
|
||||
* @return string
|
||||
*/
|
||||
public static function contact($type, $id) {
|
||||
return "[CQ:contact,type=$type,id=$id]";
|
||||
public static function contact($type, $id)
|
||||
{
|
||||
return "[CQ:contact,type={$type},id={$id}]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送位置
|
||||
* @param $lat
|
||||
* @param $lon
|
||||
* @param string $title
|
||||
* @param string $content
|
||||
* @return string
|
||||
*/
|
||||
public static function location($lat, $lon, string $title = "", string $content = "") {
|
||||
return "[CQ:location" .
|
||||
",lat=" . self::encode($lat, true) .
|
||||
",lon=" . self::encode($lon, true) .
|
||||
($title != "" ? (",title=" . self::encode($title, true)) : "") .
|
||||
($content != "" ? (",content=" . self::encode($content, true)) : "") .
|
||||
"]";
|
||||
public static function location($lat, $lon, string $title = '', string $content = '')
|
||||
{
|
||||
return '[CQ:location' .
|
||||
',lat=' . self::encode($lat, true) .
|
||||
',lon=' . self::encode($lon, true) .
|
||||
($title != '' ? (',title=' . self::encode($title, true)) : '') .
|
||||
($content != '' ? (',content=' . self::encode($content, true)) : '') .
|
||||
']';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,101 +193,119 @@ class CQ
|
||||
* $image 为音乐卡片的图片链接地址(可忽略)
|
||||
* @param $type
|
||||
* @param $id_or_url
|
||||
* @param null $audio
|
||||
* @param null $title
|
||||
* @param null $content
|
||||
* @param null $image
|
||||
* @param null $audio
|
||||
* @param null $title
|
||||
* @param null $content
|
||||
* @param null $image
|
||||
* @return string
|
||||
*/
|
||||
public static function music($type, $id_or_url, $audio = null, $title = null, $content = null, $image = null) {
|
||||
public static function music($type, $id_or_url, $audio = null, $title = null, $content = null, $image = null)
|
||||
{
|
||||
switch ($type) {
|
||||
case "qq":
|
||||
case "163":
|
||||
case "xiami":
|
||||
return "[CQ:music,type=$type,id=$id_or_url]";
|
||||
case "custom":
|
||||
case 'qq':
|
||||
case '163':
|
||||
case 'xiami':
|
||||
return "[CQ:music,type={$type},id={$id_or_url}]";
|
||||
case 'custom':
|
||||
if ($title === null || $audio === null) {
|
||||
Console::warning(zm_internal_errcode("E00035") . "传入CQ码实例的标题和音频链接不能为空!");
|
||||
return " ";
|
||||
Console::warning(zm_internal_errcode('E00035') . '传入CQ码实例的标题和音频链接不能为空!');
|
||||
return ' ';
|
||||
}
|
||||
if ($content === null) $c = "";
|
||||
else $c = ",content=" . self::encode($content, true);
|
||||
if ($image === null) $i = "";
|
||||
else $i = ",image=" . self::encode($image, true);
|
||||
return "[CQ:music,type=custom,url=" .
|
||||
if ($content === null) {
|
||||
$c = '';
|
||||
} else {
|
||||
$c = ',content=' . self::encode($content, true);
|
||||
}
|
||||
if ($image === null) {
|
||||
$i = '';
|
||||
} else {
|
||||
$i = ',image=' . self::encode($image, true);
|
||||
}
|
||||
return '[CQ:music,type=custom,url=' .
|
||||
self::encode($id_or_url, true) .
|
||||
",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:
|
||||
Console::warning(zm_internal_errcode("E00035") . "传入的music type($type)错误!");
|
||||
return " ";
|
||||
Console::warning(zm_internal_errcode('E00035') . "传入的music type({$type})错误!");
|
||||
return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
public static function forward($id) {
|
||||
return "[CQ:forward,id=".self::encode($id)."]";
|
||||
public static function forward($id)
|
||||
{
|
||||
return '[CQ:forward,id=' . self::encode($id) . ']';
|
||||
}
|
||||
|
||||
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) . "]";
|
||||
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) . ']';
|
||||
}
|
||||
|
||||
public static function xml($data) {
|
||||
return "[CQ:xml,data=" . self::encode($data, true) . "]";
|
||||
public static function xml($data)
|
||||
{
|
||||
return '[CQ:xml,data=' . self::encode($data, true) . ']';
|
||||
}
|
||||
|
||||
public static function json($data, $resid = 0) {
|
||||
return "[CQ:json,data=" . self::encode($data, true) . ",resid=" . intval($resid) . "]";
|
||||
public static function json($data, $resid = 0)
|
||||
{
|
||||
return '[CQ:json,data=' . self::encode($data, true) . ',resid=' . intval($resid) . ']';
|
||||
}
|
||||
|
||||
public static function _custom(string $type_name, $params) {
|
||||
$code = "[CQ:" . $type_name;
|
||||
public static function _custom(string $type_name, $params)
|
||||
{
|
||||
$code = '[CQ:' . $type_name;
|
||||
foreach ($params as $k => $v) {
|
||||
$code .= "," . $k . "=" . self::escape($v, true);
|
||||
$code .= ',' . $k . '=' . self::escape($v, true);
|
||||
}
|
||||
$code .= "]";
|
||||
$code .= ']';
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 反转义字符串中的CQ码敏感符号
|
||||
* @param $msg
|
||||
* @param bool $is_content
|
||||
* @return mixed
|
||||
* @param mixed $msg
|
||||
* @param mixed $is_content
|
||||
*/
|
||||
public static function decode($msg, $is_content = false) {
|
||||
$msg = str_replace(["&", "[", "]"], ["&", "[", "]"], $msg);
|
||||
if ($is_content) $msg = str_replace(",", ",", $msg);
|
||||
public static function decode($msg, $is_content = false)
|
||||
{
|
||||
$msg = str_replace(['&', '[', ']'], ['&', '[', ']'], $msg);
|
||||
if ($is_content) {
|
||||
$msg = str_replace(',', ',', $msg);
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
|
||||
public static function replace($str) {
|
||||
$str = str_replace("{{", "[", $str);
|
||||
$str = str_replace("}}", "]", $str);
|
||||
return $str;
|
||||
public static function replace($str)
|
||||
{
|
||||
$str = str_replace('{{', '[', $str);
|
||||
return str_replace('}}', ']', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义CQ码的特殊字符,同encode
|
||||
* @param $msg
|
||||
* @param bool $is_content
|
||||
* @return mixed
|
||||
* @param mixed $msg
|
||||
* @param mixed $is_content
|
||||
*/
|
||||
public static function escape($msg, $is_content = false) {
|
||||
$msg = str_replace(["&", "[", "]"], ["&", "[", "]"], $msg);
|
||||
if ($is_content) $msg = str_replace(",", ",", $msg);
|
||||
public static function escape($msg, $is_content = false)
|
||||
{
|
||||
$msg = str_replace(['&', '[', ']'], ['&', '[', ']'], $msg);
|
||||
if ($is_content) {
|
||||
$msg = str_replace(',', ',', $msg);
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义CQ码的特殊字符
|
||||
* @param $msg
|
||||
* @param false $is_content
|
||||
* @return mixed
|
||||
* @param mixed $msg
|
||||
* @param mixed $is_content
|
||||
*/
|
||||
public static function encode($msg, $is_content = false) {
|
||||
$msg = str_replace(["&", "[", "]"], ["&", "[", "]"], $msg);
|
||||
if ($is_content) $msg = str_replace(",", ",", $msg);
|
||||
public static function encode($msg, $is_content = false)
|
||||
{
|
||||
$msg = str_replace(['&', '[', ']'], ['&', '[', ']'], $msg);
|
||||
if ($is_content) {
|
||||
$msg = str_replace(',', ',', $msg);
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
|
||||
@@ -294,12 +314,13 @@ class CQ
|
||||
* @param $msg
|
||||
* @return string
|
||||
*/
|
||||
public static function removeCQ($msg) {
|
||||
$final = "";
|
||||
public static function removeCQ($msg)
|
||||
{
|
||||
$final = '';
|
||||
$last_end = 0;
|
||||
foreach (self::getAllCQ($msg) as $v) {
|
||||
$final .= mb_substr($msg, $last_end, $v["start"] - $last_end);
|
||||
$last_end = $v["end"] + 1;
|
||||
$final .= mb_substr($msg, $last_end, $v['start'] - $last_end);
|
||||
$last_end = $v['end'] + 1;
|
||||
}
|
||||
$final .= mb_substr($msg, $last_end);
|
||||
return $final;
|
||||
@@ -307,55 +328,58 @@ class CQ
|
||||
|
||||
/**
|
||||
* 获取消息中第一个CQ码
|
||||
* @param $msg
|
||||
* @param bool $is_object
|
||||
* @return array|CQObject|null
|
||||
* @param mixed $msg
|
||||
* @param mixed $is_object
|
||||
*/
|
||||
public static function getCQ($msg, $is_object = false) {
|
||||
if (($head = mb_strpos($msg, "[CQ:")) !== false) {
|
||||
public static function getCQ($msg, $is_object = false)
|
||||
{
|
||||
if (($head = mb_strpos($msg, '[CQ:')) !== false) {
|
||||
$key_offset = mb_substr($msg, $head);
|
||||
$close = mb_strpos($key_offset, "]");
|
||||
if ($close === false) return null;
|
||||
$content = mb_substr($msg, $head + 4, $close + $head - mb_strlen($msg));
|
||||
$exp = explode(",", $content);
|
||||
$cq["type"] = array_shift($exp);
|
||||
foreach ($exp as $v) {
|
||||
$ss = explode("=", $v);
|
||||
$sk = array_shift($ss);
|
||||
$cq["params"][$sk] = self::decode(implode("=", $ss), true);
|
||||
$close = mb_strpos($key_offset, ']');
|
||||
if ($close === false) {
|
||||
return null;
|
||||
}
|
||||
$cq["start"] = $head;
|
||||
$cq["end"] = $close + $head;
|
||||
$content = mb_substr($msg, $head + 4, $close + $head - mb_strlen($msg));
|
||||
$exp = explode(',', $content);
|
||||
$cq['type'] = array_shift($exp);
|
||||
foreach ($exp as $v) {
|
||||
$ss = explode('=', $v);
|
||||
$sk = array_shift($ss);
|
||||
$cq['params'][$sk] = self::decode(implode('=', $ss), true);
|
||||
}
|
||||
$cq['start'] = $head;
|
||||
$cq['end'] = $close + $head;
|
||||
return !$is_object ? $cq : CQObject::fromArray($cq);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息中所有的CQ码
|
||||
* @param $msg
|
||||
* @param bool $is_object
|
||||
* @return array|CQObject[]
|
||||
* @param mixed $msg
|
||||
* @param mixed $is_object
|
||||
*/
|
||||
public static function getAllCQ($msg, $is_object = false) {
|
||||
public static function getAllCQ($msg, $is_object = false)
|
||||
{
|
||||
$cqs = [];
|
||||
$offset = 0;
|
||||
while (($head = mb_strpos(($submsg = mb_substr($msg, $offset)), "[CQ:")) !== false) {
|
||||
while (($head = mb_strpos(($submsg = mb_substr($msg, $offset)), '[CQ:')) !== false) {
|
||||
$key_offset = mb_substr($submsg, $head);
|
||||
$tmpmsg = mb_strpos($key_offset, "]");
|
||||
if ($tmpmsg === false) break; // 没闭合,不算CQ码
|
||||
$tmpmsg = mb_strpos($key_offset, ']');
|
||||
if ($tmpmsg === false) {
|
||||
break;
|
||||
} // 没闭合,不算CQ码
|
||||
$content = mb_substr($submsg, $head + 4, $tmpmsg + $head - mb_strlen($submsg));
|
||||
$exp = explode(",", $content);
|
||||
$exp = explode(',', $content);
|
||||
$cq = [];
|
||||
$cq["type"] = array_shift($exp);
|
||||
$cq['type'] = array_shift($exp);
|
||||
foreach ($exp as $v) {
|
||||
$ss = explode("=", $v);
|
||||
$ss = explode('=', $v);
|
||||
$sk = array_shift($ss);
|
||||
$cq["params"][$sk] = self::decode(implode("=", $ss), true);
|
||||
$cq['params'][$sk] = self::decode(implode('=', $ss), true);
|
||||
}
|
||||
$cq["start"] = $offset + $head;
|
||||
$cq["end"] = $offset + $tmpmsg + $head;
|
||||
$cq['start'] = $offset + $head;
|
||||
$cq['end'] = $offset + $tmpmsg + $head;
|
||||
$offset += $head + $tmpmsg + 1;
|
||||
$cqs[] = (!$is_object ? $cq : CQObject::fromArray($cq));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\API;
|
||||
|
||||
@@ -13,74 +14,89 @@ use ZM\Utils\CoMessage;
|
||||
trait CQAPI
|
||||
{
|
||||
/** @var null|Closure */
|
||||
private static $filter = null;
|
||||
private static $filter;
|
||||
|
||||
public static function registerFilter(callable $callable) {
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function registerFilter(callable $callable)
|
||||
{
|
||||
self::$filter = $callable;
|
||||
}
|
||||
|
||||
public function getActionName($suffix, string $method)
|
||||
{
|
||||
$postfix = ($suffix == OneBotV11::API_ASYNC ? '_async' : ($suffix == OneBotV11::API_RATE_LIMITED ? '_rate_limited' : ''));
|
||||
$func_name = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $method));
|
||||
return $func_name . $postfix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $connection
|
||||
* @param $reply
|
||||
* @param |null $function
|
||||
* @return bool|array
|
||||
* @return array|bool
|
||||
*/
|
||||
private function processAPI($connection, $reply, $function = null) {
|
||||
private function processAPI($connection, $reply, $function = null)
|
||||
{
|
||||
if (is_callable(self::$filter)) {
|
||||
$reply2 = call_user_func(self::$filter, $reply);
|
||||
if (is_bool($reply2)) return $reply2;
|
||||
else $reply = $reply2;
|
||||
if (is_bool($reply2)) {
|
||||
return $reply2;
|
||||
}
|
||||
$reply = $reply2;
|
||||
}
|
||||
if ($connection->getOption("type") === CONN_WEBSOCKET)
|
||||
if ($connection->getOption('type') === CONN_WEBSOCKET) {
|
||||
return $this->processWebsocketAPI($connection, $reply, $function);
|
||||
else
|
||||
return $this->processHttpAPI($connection, $reply, $function);
|
||||
}
|
||||
|
||||
return $this->processHttpAPI($connection, $reply, $function);
|
||||
}
|
||||
|
||||
private function processWebsocketAPI($connection, $reply, $function = false) {
|
||||
$api_id = ZMAtomic::get("wait_msg_id")->add(1);
|
||||
$reply["echo"] = $api_id;
|
||||
private function processWebsocketAPI($connection, $reply, $function = false)
|
||||
{
|
||||
$api_id = ZMAtomic::get('wait_msg_id')->add(1);
|
||||
$reply['echo'] = $api_id;
|
||||
if (server()->push($connection->getFd(), json_encode($reply))) {
|
||||
if ($function === true) {
|
||||
$obj = [
|
||||
"data" => $reply,
|
||||
"time" => microtime(true),
|
||||
"self_id" => $connection->getOption("connect_id"),
|
||||
"echo" => $api_id
|
||||
'data' => $reply,
|
||||
'time' => microtime(true),
|
||||
'self_id' => $connection->getOption('connect_id'),
|
||||
'echo' => $api_id,
|
||||
];
|
||||
return CoMessage::yieldByWS($obj, ["echo"], 30);
|
||||
return CoMessage::yieldByWS($obj, ['echo'], 30);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
Console::warning(zm_internal_errcode("E00036") . "CQAPI send failed, websocket push error.");
|
||||
$response = [
|
||||
"status" => "failed",
|
||||
"retcode" => -1000,
|
||||
"data" => null,
|
||||
"self_id" => $connection->getOption("connect_id")
|
||||
];
|
||||
SpinLock::lock("wait_api");
|
||||
$r = LightCacheInside::get("wait_api", "wait_api");
|
||||
unset($r[$reply["echo"]]);
|
||||
LightCacheInside::set("wait_api", "wait_api", $r);
|
||||
SpinLock::unlock("wait_api");
|
||||
if ($function === true) return $response;
|
||||
return false;
|
||||
}
|
||||
Console::warning(zm_internal_errcode('E00036') . 'CQAPI send failed, websocket push error.');
|
||||
$response = [
|
||||
'status' => 'failed',
|
||||
'retcode' => -1000,
|
||||
'data' => null,
|
||||
'self_id' => $connection->getOption('connect_id'),
|
||||
];
|
||||
SpinLock::lock('wait_api');
|
||||
$r = LightCacheInside::get('wait_api', 'wait_api');
|
||||
unset($r[$reply['echo']]);
|
||||
LightCacheInside::set('wait_api', 'wait_api', $r);
|
||||
SpinLock::unlock('wait_api');
|
||||
if ($function === true) {
|
||||
return $response;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $connection
|
||||
* @param $reply
|
||||
* @param null $function
|
||||
* @return bool
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
private function processHttpAPI($connection, $reply, $function = null): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function __call($name, $arguments) {
|
||||
private function processHttpAPI($connection, $reply, $function = null): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
120
src/ZM/API/GoCqhttpAPIV11.php
Normal file
120
src/ZM/API/GoCqhttpAPIV11.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\API;
|
||||
|
||||
class GoCqhttpAPIV11
|
||||
{
|
||||
use CQAPI;
|
||||
|
||||
public const SUPPORT_VERSION = '1.0.0-beta8';
|
||||
|
||||
private $connection;
|
||||
|
||||
private $callback;
|
||||
|
||||
private $prefix;
|
||||
|
||||
public function __construct($connection, $callback, $prefix)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->callback = $callback;
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取频道系统内BOT的资料
|
||||
* 响应字段:nickname, tiny_id, avatar_url
|
||||
* @see https://github.com/Mrs4s/go-cqhttp/blob/master/docs/guild.md#%E8%8E%B7%E5%8F%96%E9%A2%91%E9%81%93%E7%B3%BB%E7%BB%9F%E5%86%85bot%E7%9A%84%E8%B5%84%E6%96%99
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getGuildServiceProfile()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
], $this->callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取频道列表
|
||||
* @see https://github.com/Mrs4s/go-cqhttp/blob/master/docs/guild.md#%E8%8E%B7%E5%8F%96%E9%A2%91%E9%81%93%E5%88%97%E8%A1%A8
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getGuildList()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
], $this->callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过访客获取频道元数据
|
||||
* @see https://github.com/Mrs4s/go-cqhttp/blob/master/docs/guild.md#%E9%80%9A%E8%BF%87%E8%AE%BF%E5%AE%A2%E8%8E%B7%E5%8F%96%E9%A2%91%E9%81%93%E5%85%83%E6%95%B0%E6%8D%AE
|
||||
* @param $guild_id
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getGuildMetaByGuest($guild_id)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'guild_id' => $guild_id,
|
||||
],
|
||||
], $this->callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子频道列表
|
||||
* @see https://github.com/Mrs4s/go-cqhttp/blob/master/docs/guild.md#%E8%8E%B7%E5%8F%96%E5%AD%90%E9%A2%91%E9%81%93%E5%88%97%E8%A1%A8
|
||||
* @param $guild_id
|
||||
* @param false $no_cache
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getGuildChannelList($guild_id, bool $no_cache = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'guild_id' => $guild_id,
|
||||
'no_cache' => $no_cache,
|
||||
],
|
||||
], $this->callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取频道成员列表
|
||||
* @see https://github.com/Mrs4s/go-cqhttp/blob/master/docs/guild.md#%E8%8E%B7%E5%8F%96%E9%A2%91%E9%81%93%E6%88%90%E5%91%98%E5%88%97%E8%A1%A8
|
||||
* @param $guild_id
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getGuildMembers($guild_id)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'guild_id' => $guild_id,
|
||||
],
|
||||
], $this->callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送信息到子频道
|
||||
* @see https://github.com/Mrs4s/go-cqhttp/blob/master/docs/guild.md#%E5%8F%91%E9%80%81%E4%BF%A1%E6%81%AF%E5%88%B0%E5%AD%90%E9%A2%91%E9%81%93
|
||||
* @param $guild_id
|
||||
* @param $channel_id
|
||||
* @param $message
|
||||
* @return array|bool
|
||||
*/
|
||||
public function sendGuildChannelMsg($guild_id, $channel_id, $message)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'guild_id' => $guild_id,
|
||||
'channel_id' => $channel_id,
|
||||
'message' => $message,
|
||||
],
|
||||
], $this->callback);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,77 @@
|
||||
<?php
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\API;
|
||||
|
||||
use ZM\ConnectionManager\ConnectionObject;
|
||||
use ZM\ConnectionManager\ManagerGM;
|
||||
use ZM\Exception\RobotNotFoundException;
|
||||
use ZM\Exception\ZMKnownException;
|
||||
|
||||
/**
|
||||
* OneBot V11 的 API 实现类
|
||||
* Class OneBotV11
|
||||
* @package ZM\API
|
||||
* @since 2.5
|
||||
* @since 2.5.0
|
||||
*/
|
||||
class OneBotV11
|
||||
{
|
||||
use CQAPI;
|
||||
|
||||
const API_ASYNC = 1;
|
||||
const API_NORMAL = 0;
|
||||
const API_RATE_LIMITED = 2;
|
||||
public const API_ASYNC = 1;
|
||||
|
||||
/** @var ConnectionObject|null */
|
||||
private $connection;
|
||||
public const API_NORMAL = 0;
|
||||
|
||||
private $callback = true;
|
||||
private $prefix = 0;
|
||||
public const API_RATE_LIMITED = 2;
|
||||
|
||||
/**
|
||||
* @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 . " 未连接到框架!");
|
||||
/** @var null|ConnectionObject */
|
||||
protected $connection;
|
||||
|
||||
protected $callback = true;
|
||||
|
||||
protected $prefix = 0;
|
||||
|
||||
public function __construct(ConnectionObject $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ZMRobot
|
||||
* @param $robot_id
|
||||
* @throws RobotNotFoundException
|
||||
* @return ZMRobot
|
||||
*/
|
||||
public static function getRandom() {
|
||||
public static function get($robot_id)
|
||||
{
|
||||
$r = ManagerGM::getAllByName('qq');
|
||||
if ($r == []) throw new RobotNotFoundException("没有任何机器人连接到框架!");
|
||||
foreach ($r as $v) {
|
||||
if ($v->getOption('connect_id') == $robot_id) {
|
||||
return new ZMRobot($v);
|
||||
}
|
||||
}
|
||||
throw new RobotNotFoundException('机器人 ' . $robot_id . ' 未连接到框架!');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RobotNotFoundException
|
||||
* @return ZMRobot
|
||||
*/
|
||||
public static function getRandom()
|
||||
{
|
||||
$r = ManagerGM::getAllByName('qq');
|
||||
if ($r == []) {
|
||||
throw new RobotNotFoundException('没有任何机器人连接到框架!');
|
||||
}
|
||||
return new ZMRobot($r[array_rand($r)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ZMRobot[]
|
||||
*/
|
||||
public static function getAllRobot() {
|
||||
public static function getAllRobot()
|
||||
{
|
||||
$r = ManagerGM::getAllByName('qq');
|
||||
$obj = [];
|
||||
foreach ($r as $v) {
|
||||
@@ -62,21 +80,20 @@ class OneBotV11
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function __construct(ConnectionObject $connection) {
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
public function setCallback($callback = true) {
|
||||
public function setCallback($callback = true)
|
||||
{
|
||||
$this->callback = $callback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPrefix($prefix = self::API_NORMAL) {
|
||||
public function setPrefix($prefix = self::API_NORMAL)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSelfId() {
|
||||
public function getSelfId()
|
||||
{
|
||||
return $this->connection->getOption('connect_id');
|
||||
}
|
||||
|
||||
@@ -84,603 +101,629 @@ class OneBotV11
|
||||
|
||||
/**
|
||||
* 发送私聊消息
|
||||
* @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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function sendPrivateMsg($user_id, $message, $auto_escape = false) {
|
||||
public function sendPrivateMsg($user_id, $message, bool $auto_escape = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'user_id' => $user_id,
|
||||
'message' => $message,
|
||||
'auto_escape' => $auto_escape
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function sendGroupMsg($group_id, $message, $auto_escape = false) {
|
||||
public function sendGroupMsg($group_id, $message, bool $auto_escape = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'message' => $message,
|
||||
'auto_escape' => $auto_escape
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function sendMsg($message_type, $target_id, $message, $auto_escape = false) {
|
||||
public function sendMsg($message_type, $target_id, $message, bool $auto_escape = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'message_type' => $message_type,
|
||||
($message_type == 'private' ? 'user' : $message_type) . '_id' => $target_id,
|
||||
'message' => $message,
|
||||
'auto_escape' => $auto_escape
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function deleteMsg($message_id) {
|
||||
public function deleteMsg($message_id)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'message_id' => $message_id
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getMsg($message_id) {
|
||||
public function getMsg($message_id)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'message_id' => $message_id
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getForwardMsg($id) {
|
||||
public function getForwardMsg($id)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'id' => $id
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function sendLike($user_id, $times = 1) {
|
||||
public function sendLike($user_id, int $times = 1)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'user_id' => $user_id,
|
||||
'times' => $times
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupKick($group_id, $user_id, $reject_add_request = false) {
|
||||
public function setGroupKick($group_id, $user_id, bool $reject_add_request = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $user_id,
|
||||
'reject_add_request' => $reject_add_request
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupBan($group_id, $user_id, $duration = 1800) {
|
||||
public function setGroupBan($group_id, $user_id, int $duration = 1800)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $user_id,
|
||||
'duration' => $duration
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupAnonymousBan($group_id, $anonymous_or_flag, $duration = 1800) {
|
||||
public function setGroupAnonymousBan($group_id, $anonymous_or_flag, int $duration = 1800)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
(is_string($anonymous_or_flag) ? 'flag' : 'anonymous') => $anonymous_or_flag,
|
||||
'duration' => $duration
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupWholeBan($group_id, $enable = true) {
|
||||
public function setGroupWholeBan($group_id, bool $enable = true)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'enable' => $enable
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupAdmin($group_id, $user_id, $enable = true) {
|
||||
public function setGroupAdmin($group_id, $user_id, bool $enable = true)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $user_id,
|
||||
'enable' => $enable
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupAnonymous($group_id, $enable = true) {
|
||||
public function setGroupAnonymous($group_id, bool $enable = true)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'enable' => $enable
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupCard($group_id, $user_id, $card = "") {
|
||||
public function setGroupCard($group_id, $user_id, string $card = '')
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $user_id,
|
||||
'card' => $card
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupName($group_id, $group_name) {
|
||||
public function setGroupName($group_id, $group_name)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'group_name' => $group_name
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupLeave($group_id, $is_dismiss = false) {
|
||||
public function setGroupLeave($group_id, bool $is_dismiss = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'is_dismiss' => $is_dismiss
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupSpecialTitle($group_id, $user_id, $special_title = "", $duration = -1) {
|
||||
public function setGroupSpecialTitle($group_id, $user_id, string $special_title = '', int $duration = -1)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $user_id,
|
||||
'special_title' => $special_title,
|
||||
'duration' => $duration
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setFriendAddRequest($flag, $approve = true, $remark = "") {
|
||||
public function setFriendAddRequest($flag, bool $approve = true, string $remark = '')
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'flag' => $flag,
|
||||
'approve' => $approve,
|
||||
'remark' => $remark
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setGroupAddRequest($flag, $sub_type, $approve = true, $reason = "") {
|
||||
public function setGroupAddRequest($flag, $sub_type, bool $approve = true, string $reason = '')
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'flag' => $flag,
|
||||
'sub_type' => $sub_type,
|
||||
'approve' => $approve,
|
||||
'reason' => $reason
|
||||
]
|
||||
'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
|
||||
* @see 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 null|array|bool
|
||||
*/
|
||||
public function getLoginInfo() {
|
||||
return $this->processAPI($this->connection, ['action' => $this->getActionName(__FUNCTION__)], $this->callback);
|
||||
public function getLoginInfo()
|
||||
{
|
||||
return $this->processAPI($this->connection, ['action' => $this->getActionName($this->prefix, __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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getStrangerInfo($user_id, $no_cache = false) {
|
||||
public function getStrangerInfo($user_id, bool $no_cache = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'user_id' => $user_id,
|
||||
'no_cache' => $no_cache
|
||||
]
|
||||
'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
|
||||
* @see 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 null|array|bool
|
||||
*/
|
||||
public function getFriendList() {
|
||||
public function getFriendList()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__)
|
||||
'action' => $this->getActionName($this->prefix, __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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getGroupInfo($group_id, $no_cache = false) {
|
||||
public function getGroupInfo($group_id, bool $no_cache = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'no_cache' => $no_cache
|
||||
]
|
||||
'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
|
||||
* @see 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 null|array|bool
|
||||
*/
|
||||
public function getGroupList() {
|
||||
public function getGroupList()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__)
|
||||
'action' => $this->getActionName($this->prefix, __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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getGroupMemberInfo($group_id, $user_id, $no_cache = false) {
|
||||
public function getGroupMemberInfo($group_id, $user_id, bool $no_cache = false)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $user_id,
|
||||
'no_cache' => $no_cache
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getGroupMemberList($group_id) {
|
||||
public function getGroupMemberList($group_id)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getGroupHonorInfo($group_id, $type) {
|
||||
public function getGroupHonorInfo($group_id, $type)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'group_id' => $group_id,
|
||||
'type' => $type
|
||||
]
|
||||
'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
|
||||
* @see https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md#get_csrf_token-%E8%8E%B7%E5%8F%96-csrf-token
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getCsrfToken() {
|
||||
public function getCsrfToken()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__)
|
||||
'action' => $this->getActionName($this->prefix, __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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getCredentials($domain = "") {
|
||||
public function getCredentials(string $domain = '')
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'domain' => $domain
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getRecord($file, $out_format) {
|
||||
public function getRecord($file, $out_format)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'file' => $file,
|
||||
'out_format' => $out_format
|
||||
]
|
||||
'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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function getImage($file) {
|
||||
public function getImage($file)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'file' => $file
|
||||
]
|
||||
'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
|
||||
* @see 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 null|array|bool
|
||||
*/
|
||||
public function canSendImage() {
|
||||
public function canSendImage()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__)
|
||||
'action' => $this->getActionName($this->prefix, __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
|
||||
* @see 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 null|array|bool
|
||||
*/
|
||||
public function canSendRecord() {
|
||||
public function canSendRecord()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__)
|
||||
'action' => $this->getActionName($this->prefix, __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
|
||||
* @see 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 null|array|bool
|
||||
*/
|
||||
public function getStatus() {
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__)
|
||||
'action' => $this->getActionName($this->prefix, __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
|
||||
* @see 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 null|array|bool
|
||||
*/
|
||||
public function getVersionInfo() {
|
||||
public function getVersionInfo()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__)
|
||||
'action' => $this->getActionName($this->prefix, __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
|
||||
* @see 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
|
||||
* @return null|array|bool
|
||||
*/
|
||||
public function setRestart($delay = 0) {
|
||||
public function setRestart(int $delay = 0)
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__),
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
'params' => [
|
||||
'delay' => $delay
|
||||
]
|
||||
'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
|
||||
* @see 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 null|array|bool
|
||||
*/
|
||||
public function cleanCache() {
|
||||
public function cleanCache()
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $this->getActionName(__FUNCTION__)
|
||||
'action' => $this->getActionName($this->prefix, __FUNCTION__),
|
||||
], $this->callback);
|
||||
}
|
||||
|
||||
public function callExtendedAPI($action, $params = []) {
|
||||
/**
|
||||
* 获取内置支持的扩展API对象
|
||||
* 现支持 go-cqhttp 的扩展API
|
||||
* @throws ZMKnownException
|
||||
* @return mixed
|
||||
*/
|
||||
public function getExtendedAPI(string $package_name = 'go-cqhttp')
|
||||
{
|
||||
$table = [
|
||||
'go-cqhttp' => GoCqhttpAPIV11::class,
|
||||
];
|
||||
if (isset($table[$package_name])) {
|
||||
return new $table[$package_name]($this->connection, $this->callback, $this->prefix);
|
||||
}
|
||||
throw new ZMKnownException(zm_internal_errcode('E00071'), '无法找到对应的调用扩展类');
|
||||
}
|
||||
|
||||
public function callExtendedAPI($action, $params = [])
|
||||
{
|
||||
return $this->processAPI($this->connection, [
|
||||
'action' => $action,
|
||||
'params' => $params
|
||||
'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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\API;
|
||||
|
||||
|
||||
use Swoole\Coroutine\Http\Client;
|
||||
use ZM\Console\Console;
|
||||
|
||||
@@ -16,103 +16,113 @@ class TuringAPI
|
||||
* @param $api
|
||||
* @return string
|
||||
*/
|
||||
public static function getTuringMsg($msg, $user_id, $api) {
|
||||
public static function getTuringMsg($msg, $user_id, $api)
|
||||
{
|
||||
$origin = $msg;
|
||||
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);
|
||||
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" => [
|
||||
"apiKey" => $api,
|
||||
"userId" => $user_id
|
||||
]
|
||||
'reqType' => 0,
|
||||
'userInfo' => [
|
||||
'apiKey' => $api,
|
||||
'userId' => $user_id,
|
||||
],
|
||||
];
|
||||
if ($msg != "") {
|
||||
$content["perception"]["inputText"]["text"] = $msg;
|
||||
if ($msg != '') {
|
||||
$content['perception']['inputText']['text'] = $msg;
|
||||
}
|
||||
$msg = trim($msg);
|
||||
if (mb_strlen($msg) < 1 && !isset($url)) return "请说出你想说的话";
|
||||
if (isset($url)) {
|
||||
$content["perception"]["inputImage"]["url"] = $url;
|
||||
$content["reqType"] = 1;
|
||||
if (mb_strlen($msg) < 1 && !isset($url)) {
|
||||
return '请说出你想说的话';
|
||||
}
|
||||
if (!isset($content["perception"])) return "请说出你想说的话";
|
||||
$client = new Client("openapi.tuling123.com", 80);
|
||||
$client->setHeaders(["Content-type" => "application/json"]);
|
||||
$client->post("/openapi/api/v2", json_encode($content, JSON_UNESCAPED_UNICODE));
|
||||
if (isset($url)) {
|
||||
$content['perception']['inputImage']['url'] = $url;
|
||||
$content['reqType'] = 1;
|
||||
}
|
||||
if (!isset($content['perception'])) {
|
||||
return '请说出你想说的话';
|
||||
}
|
||||
$client = new Client('openapi.tuling123.com', 80);
|
||||
$client->setHeaders(['Content-type' => 'application/json']);
|
||||
$client->post('/openapi/api/v2', json_encode($content, JSON_UNESCAPED_UNICODE));
|
||||
$api_return = json_decode($client->body, true);
|
||||
if (!isset($api_return["intent"]["code"])) return "XD 哎呀,我脑子突然短路了,请稍后再问我吧!";
|
||||
if (!isset($api_return['intent']['code'])) {
|
||||
return 'XD 哎呀,我脑子突然短路了,请稍后再问我吧!';
|
||||
}
|
||||
$status = self::getResultStatus($api_return);
|
||||
if ($status !== true) {
|
||||
if ($status == "err:输入文本内容超长(上限150)") return "你的话太多了!!!";
|
||||
if ($api_return["intent"]["code"] == 4003) {
|
||||
return "哎呀,我刚才有点走神了,可能忘记你说什么了,可以重说一遍吗";
|
||||
if ($status == 'err:输入文本内容超长(上限150)') {
|
||||
return '你的话太多了!!!';
|
||||
}
|
||||
Console::error(zm_internal_errcode("E00038") . "图灵机器人发送错误!\n错误原始内容:" . $origin . "\n来自:" . $user_id . "\n错误信息:" . $status);
|
||||
//echo json_encode($r, 128|256);
|
||||
return "哎呀,我刚才有点走神了,要不一会儿换一种问题试试?";
|
||||
if ($api_return['intent']['code'] == 4003) {
|
||||
return '哎呀,我刚才有点走神了,可能忘记你说什么了,可以重说一遍吗';
|
||||
}
|
||||
Console::error(zm_internal_errcode('E00038') . "图灵机器人发送错误!\n错误原始内容:" . $origin . "\n来自:" . $user_id . "\n错误信息:" . $status);
|
||||
// echo json_encode($r, 128|256);
|
||||
return '哎呀,我刚才有点走神了,要不一会儿换一种问题试试?';
|
||||
}
|
||||
$result = $api_return["results"];
|
||||
//Console::info(Console::setColor(json_encode($result, 128 | 256), "green"));
|
||||
$final = "";
|
||||
$result = $api_return['results'];
|
||||
// Console::info(Console::setColor(json_encode($result, 128 | 256), "green"));
|
||||
$final = '';
|
||||
foreach ($result as $v) {
|
||||
switch ($v["resultType"]) {
|
||||
case "url":
|
||||
$final .= "\n" . $v["values"]["url"];
|
||||
switch ($v['resultType']) {
|
||||
case 'url':
|
||||
$final .= "\n" . $v['values']['url'];
|
||||
break;
|
||||
case "text":
|
||||
$final .= "\n" . $v["values"]["text"];
|
||||
case 'text':
|
||||
$final .= "\n" . $v['values']['text'];
|
||||
break;
|
||||
case "image":
|
||||
$final .= "\n" . CQ::image($v["values"]["image"]);
|
||||
case 'image':
|
||||
$final .= "\n" . CQ::image($v['values']['image']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return trim($final);
|
||||
}
|
||||
|
||||
public static function getResultStatus($r) {
|
||||
switch ($r["intent"]["code"]) {
|
||||
public static function getResultStatus($r)
|
||||
{
|
||||
switch ($r['intent']['code']) {
|
||||
case 5000:
|
||||
return "err:无解析结果";
|
||||
return 'err:无解析结果';
|
||||
case 4000:
|
||||
case 6000:
|
||||
return "err:暂不支持该功能";
|
||||
return 'err:暂不支持该功能';
|
||||
case 4001:
|
||||
return "err:加密方式错误";
|
||||
return 'err:加密方式错误';
|
||||
case 4005:
|
||||
case 4002:
|
||||
return "err:无功能权限";
|
||||
return 'err:无功能权限';
|
||||
case 4003:
|
||||
return "err:该apikey没有可用请求次数";
|
||||
return 'err:该apikey没有可用请求次数';
|
||||
case 4007:
|
||||
return "err:apikey不合法";
|
||||
return 'err:apikey不合法';
|
||||
case 4100:
|
||||
return "err:userid获取失败";
|
||||
return 'err:userid获取失败';
|
||||
case 4200:
|
||||
return "err:上传格式错误";
|
||||
return 'err:上传格式错误';
|
||||
case 4300:
|
||||
return "err:批量操作超过限制";
|
||||
return 'err:批量操作超过限制';
|
||||
case 4400:
|
||||
return "err:没有上传合法userid";
|
||||
return 'err:没有上传合法userid';
|
||||
case 4500:
|
||||
return "err:userid申请个数超过限制";
|
||||
return 'err:userid申请个数超过限制';
|
||||
case 4600:
|
||||
return "err:输入内容为空";
|
||||
return 'err:输入内容为空';
|
||||
case 4602:
|
||||
return "err:输入文本内容超长(上限150)";
|
||||
return 'err:输入文本内容超长(上限150)';
|
||||
case 7002:
|
||||
return "err:上传信息失败";
|
||||
return 'err:上传信息失败';
|
||||
case 8008:
|
||||
return "err:服务器错误";
|
||||
return 'err:服务器错误';
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
<?php /** @noinspection PhpMissingReturnTypeInspection */
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\API;
|
||||
|
||||
/**
|
||||
* Class ZMRobot
|
||||
* @package ZM\Utils
|
||||
* @since 1.2
|
||||
* @version V11
|
||||
*/
|
||||
class ZMRobot extends OneBotV11
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,29 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Annotation;
|
||||
|
||||
|
||||
use Closure;
|
||||
|
||||
abstract class AnnotationBase
|
||||
{
|
||||
public $method;
|
||||
public $method = '';
|
||||
|
||||
public $class;
|
||||
public $class = '';
|
||||
|
||||
public function __toString() {
|
||||
$str = __CLASS__ . ": ";
|
||||
public function __toString()
|
||||
{
|
||||
$str = __CLASS__ . ': ';
|
||||
foreach ($this as $k => $v) {
|
||||
$str .= "\n\t" . $k . " => ";
|
||||
if (is_string($v)) $str .= "\"$v\"";
|
||||
elseif (is_numeric($v)) $str .= $v;
|
||||
elseif (is_bool($v)) $str .= ($v ? "TRUE" : "FALSE");
|
||||
elseif (is_array($v)) $str .= json_encode($v, JSON_UNESCAPED_UNICODE);
|
||||
elseif ($v instanceof Closure) $str .= "@AnonymousFunction";
|
||||
elseif (is_null($v)) $str .= "NULL";
|
||||
else $str .= "@Unknown";
|
||||
$str .= "\n\t" . $k . ' => ';
|
||||
if (is_string($v)) {
|
||||
$str .= "\"{$v}\"";
|
||||
} elseif (is_numeric($v)) {
|
||||
$str .= $v;
|
||||
} elseif (is_bool($v)) {
|
||||
$str .= ($v ? 'TRUE' : 'FALSE');
|
||||
} elseif (is_array($v)) {
|
||||
$str .= json_encode($v, JSON_UNESCAPED_UNICODE);
|
||||
} elseif ($v instanceof Closure) {
|
||||
$str .= '@AnonymousFunction';
|
||||
} elseif (is_null($v)) {
|
||||
$str .= 'NULL';
|
||||
} else {
|
||||
$str .= '@Unknown';
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Annotation;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use ZM\Annotation\CQ\CQCommand;
|
||||
use ZM\Annotation\Interfaces\ErgodicAnnotation;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use Koriym\Attributes\AttributeReader;
|
||||
use Koriym\Attributes\DualReader;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionMethod;
|
||||
@@ -17,11 +16,15 @@ use ZM\Annotation\Http\HandleException;
|
||||
use ZM\Annotation\Http\Middleware;
|
||||
use ZM\Annotation\Http\MiddlewareClass;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Annotation\Interfaces\ErgodicAnnotation;
|
||||
use ZM\Annotation\Interfaces\Level;
|
||||
use ZM\Annotation\Module\Closed;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Exception\AnnotationException;
|
||||
use ZM\Utils\Manager\RouteManager;
|
||||
use ZM\Utils\ZMUtil;
|
||||
use function server;
|
||||
|
||||
class AnnotationParser
|
||||
{
|
||||
@@ -30,23 +33,27 @@ class AnnotationParser
|
||||
private $start_time;
|
||||
|
||||
private $annotation_map = [];
|
||||
|
||||
private $middleware_map = [];
|
||||
|
||||
private $middlewares = [];
|
||||
|
||||
/** @var null|AnnotationReader */
|
||||
private $reader = null;
|
||||
private $reader;
|
||||
|
||||
private $req_mapping = [];
|
||||
|
||||
/**
|
||||
* AnnotationParser constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
public function __construct()
|
||||
{
|
||||
$this->start_time = microtime(true);
|
||||
//$this->loadAnnotationClasses();
|
||||
// $this->loadAnnotationClasses();
|
||||
$this->req_mapping[0] = [
|
||||
'id' => 0,
|
||||
'pid' => -1,
|
||||
'name' => '/'
|
||||
'name' => '/',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -54,19 +61,32 @@ class AnnotationParser
|
||||
* 注册各个模块类的注解和模块level的排序
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function registerMods() {
|
||||
public function registerMods()
|
||||
{
|
||||
foreach ($this->path_list as $path) {
|
||||
Console::debug("parsing annotation in " . $path[0].":".$path[1]);
|
||||
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);
|
||||
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: {
|
||||
@@ -85,51 +105,50 @@ class AnnotationParser
|
||||
*/
|
||||
|
||||
// 生成主树
|
||||
$this->annotation_map[$v]["class_annotations"] = $class_annotations;
|
||||
$this->annotation_map[$v]["methods"] = $methods;
|
||||
$this->annotation_map[$v]['class_annotations'] = $class_annotations;
|
||||
$this->annotation_map[$v]['methods'] = $methods;
|
||||
foreach ($methods as $method) {
|
||||
$this->annotation_map[$v]["methods_annotations"][$method->getName()] = $this->reader->getMethodAnnotations($method);
|
||||
$this->annotation_map[$v]['methods_annotations'][$method->getName()] = $this->reader->getMethodAnnotations($method);
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->annotation_map[$v]["class_annotations"] as $vs) {
|
||||
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) {
|
||||
foreach (($this->annotation_map[$v]['methods'] ?? []) as $method) {
|
||||
$copy = clone $vs;
|
||||
$copy->method = $method->getName();
|
||||
$this->annotation_map[$v]["methods_annotations"][$method->getName()][] = $copy;
|
||||
$this->annotation_map[$v]['methods_annotations'][$method->getName()][] = $copy;
|
||||
}
|
||||
}
|
||||
|
||||
//预处理2:处理 class 下面的注解
|
||||
// 预处理2:处理 class 下面的注解
|
||||
if ($vs instanceof Closed) {
|
||||
unset($this->annotation_map[$v]);
|
||||
continue 2;
|
||||
} elseif ($vs instanceof MiddlewareClass) {
|
||||
//注册中间件本身的类,标记到 middlewares 属性中
|
||||
Console::debug("正在注册中间件 " . $reflection_class->getName());
|
||||
}
|
||||
if ($vs instanceof MiddlewareClass) {
|
||||
// 注册中间件本身的类,标记到 middlewares 属性中
|
||||
Console::debug('正在注册中间件 ' . $reflection_class->getName());
|
||||
$rs = $this->registerMiddleware($vs, $reflection_class);
|
||||
$this->middlewares[$rs["name"]] = $rs;
|
||||
$this->middlewares[$rs['name']] = $rs;
|
||||
}
|
||||
}
|
||||
|
||||
$inserted = [];
|
||||
|
||||
//预处理3:处理每个函数上面的特殊注解,就是需要操作一些东西的
|
||||
foreach (($this->annotation_map[$v]["methods_annotations"] ?? []) as $method_name => $methods_annotations) {
|
||||
// 预处理3:处理每个函数上面的特殊注解,就是需要操作一些东西的
|
||||
foreach (($this->annotation_map[$v]['methods_annotations'] ?? []) as $method_name => $methods_annotations) {
|
||||
foreach ($methods_annotations as $method_anno) {
|
||||
/** @var AnnotationBase $method_anno */
|
||||
/* @var AnnotationBase $method_anno */
|
||||
$method_anno->class = $v;
|
||||
$method_anno->method = $method_name;
|
||||
if (!($method_anno instanceof Middleware) && ($middlewares = ZMConfig::get("global", "runtime")["global_middleware_binding"][get_class($method_anno)] ?? []) !== []) {
|
||||
if (!($method_anno instanceof Middleware) && ($middlewares = ZMConfig::get('global', 'runtime')['global_middleware_binding'][get_class($method_anno)] ?? []) !== []) {
|
||||
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;
|
||||
@@ -146,23 +165,25 @@ class AnnotationParser
|
||||
}
|
||||
}
|
||||
}
|
||||
Console::debug("解析注解完毕!");
|
||||
Console::debug('解析注解完毕!');
|
||||
}
|
||||
|
||||
public function generateAnnotationEvents(): array {
|
||||
public function generateAnnotationEvents(): array
|
||||
{
|
||||
$o = [];
|
||||
foreach ($this->annotation_map as $obj) {
|
||||
// 这里的ErgodicAnnotation是为了解决类上的注解可穿透到方法上的问题
|
||||
foreach (($obj["class_annotations"] ?? []) as $class_annotation) {
|
||||
if ($class_annotation instanceof ErgodicAnnotation) continue;
|
||||
else $o[get_class($class_annotation)][] = $class_annotation;
|
||||
foreach (($obj['class_annotations'] ?? []) as $class_annotation) {
|
||||
if ($class_annotation instanceof ErgodicAnnotation) {
|
||||
continue;
|
||||
}
|
||||
$o[get_class($class_annotation)][] = $class_annotation;
|
||||
}
|
||||
foreach (($obj["methods_annotations"] ?? []) as $methods_annotations) {
|
||||
foreach (($obj['methods_annotations'] ?? []) as $methods_annotations) {
|
||||
foreach ($methods_annotations as $annotation) {
|
||||
$o[get_class($annotation)][] = $annotation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
foreach ($o as $k => $v) {
|
||||
$this->sortByLevel($o, $k);
|
||||
@@ -170,55 +191,39 @@ class AnnotationParser
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMiddlewares(): array { return $this->middlewares; }
|
||||
public function getMiddlewares(): array
|
||||
{
|
||||
return $this->middlewares;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMiddlewareMap(): array { return $this->middleware_map; }
|
||||
public function getMiddlewareMap(): array
|
||||
{
|
||||
return $this->middleware_map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getReqMapping(): array { return $this->req_mapping; }
|
||||
public function getReqMapping(): array
|
||||
{
|
||||
return $this->req_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @param $indoor_name
|
||||
*/
|
||||
public function addRegisterPath($path, $indoor_name) { $this->path_list[] = [$path, $indoor_name]; }
|
||||
|
||||
//private function below
|
||||
|
||||
private function registerMiddleware(MiddlewareClass $vs, ReflectionClass $reflection_class): array {
|
||||
$result = [
|
||||
"class" => "\\" . $reflection_class->getName(),
|
||||
"name" => $vs->name
|
||||
];
|
||||
|
||||
foreach ($reflection_class->getMethods() as $vss) {
|
||||
$method_annotations = $this->reader->getMethodAnnotations($vss);
|
||||
foreach ($method_annotations as $vsss) {
|
||||
if ($vsss instanceof HandleBefore) $result["before"] = $vss->getName();
|
||||
if ($vsss instanceof HandleAfter) $result["after"] = $vss->getName();
|
||||
if ($vsss instanceof HandleException) {
|
||||
$result["exceptions"][$vsss->class_name] = $vss->getName();
|
||||
}
|
||||
}
|
||||
public function addRegisterPath($path, $indoor_name)
|
||||
{
|
||||
if (server()->worker_id === 0) {
|
||||
Console::verbose('Add register path: ' . $path . ' => ' . $indoor_name);
|
||||
}
|
||||
return $result;
|
||||
$this->path_list[] = [$path, $indoor_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal 用于 level 排序
|
||||
* @param $events
|
||||
* @param string $class_name
|
||||
* @param string $prefix
|
||||
* @internal 用于 level 排序
|
||||
*/
|
||||
public function sortByLevel(&$events, string $class_name, $prefix = "") {
|
||||
public function sortByLevel(&$events, string $class_name, string $prefix = '')
|
||||
{
|
||||
if (is_a($class_name, Level::class, true)) {
|
||||
$class_name .= $prefix;
|
||||
usort($events[$class_name], function ($a, $b) {
|
||||
@@ -232,12 +237,13 @@ class AnnotationParser
|
||||
/**
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function verifyMiddlewares() {
|
||||
if ((ZMConfig::get("global", "runtime")["middleware_error_policy"] ?? 1) === 2) {
|
||||
//我承认套三层foreach很不优雅,但是这个会很快的。
|
||||
foreach($this->middleware_map as $class => $v) {
|
||||
foreach ($v as $method => $vs) {
|
||||
foreach($vs as $mid) {
|
||||
public function verifyMiddlewares()
|
||||
{
|
||||
if ((ZMConfig::get('global', 'runtime')['middleware_error_policy'] ?? 1) === 2) {
|
||||
// 我承认套三层foreach很不优雅,但是这个会很快的。
|
||||
foreach ($this->middleware_map as $v) {
|
||||
foreach ($v as $vs) {
|
||||
foreach ($vs as $mid) {
|
||||
if (!isset($this->middlewares[$mid->middleware])) {
|
||||
throw new AnnotationException("Annotation parse error: Unknown MiddlewareClass named \"{$mid->middleware}\"!");
|
||||
}
|
||||
@@ -246,4 +252,35 @@ class AnnotationParser
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getRunTime()
|
||||
{
|
||||
return microtime(true) - $this->start_time;
|
||||
}
|
||||
|
||||
// private function below
|
||||
|
||||
private function registerMiddleware(MiddlewareClass $vs, ReflectionClass $reflection_class): array
|
||||
{
|
||||
$result = [
|
||||
'class' => '\\' . $reflection_class->getName(),
|
||||
'name' => $vs->name,
|
||||
];
|
||||
|
||||
foreach ($reflection_class->getMethods() as $vss) {
|
||||
$method_annotations = $this->reader->getMethodAnnotations($vss);
|
||||
foreach ($method_annotations as $vsss) {
|
||||
if ($vsss instanceof HandleBefore) {
|
||||
$result['before'] = $vss->getName();
|
||||
}
|
||||
if ($vsss instanceof HandleAfter) {
|
||||
$result['after'] = $vss->getName();
|
||||
}
|
||||
if ($vsss instanceof HandleException) {
|
||||
$result['exceptions'][$vsss->class_name] = $vss->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class CQAPIResponse
|
||||
* @package ZM\Annotation\CQ
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class CQAPIResponse extends AnnotationBase
|
||||
{
|
||||
/**
|
||||
@@ -21,4 +24,9 @@ class CQAPIResponse extends AnnotationBase
|
||||
* @Required()
|
||||
*/
|
||||
public $retcode;
|
||||
|
||||
public function __construct($retcode)
|
||||
{
|
||||
$this->retcode = $retcode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
@@ -10,9 +13,10 @@ use ZM\Annotation\Interfaces\Level;
|
||||
/**
|
||||
* Class CQAfter
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
* @package ZM\Annotation\CQ
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class CQAfter extends AnnotationBase implements Level
|
||||
{
|
||||
/**
|
||||
@@ -23,17 +27,25 @@ 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
|
||||
*/
|
||||
public function getLevel() {
|
||||
public function getLevel()
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $level
|
||||
*/
|
||||
public function setLevel($level) {
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<?php
|
||||
|
||||
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,9 +14,10 @@ use ZM\Annotation\Interfaces\Level;
|
||||
/**
|
||||
* Class CQBefore
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
* @package ZM\Annotation\CQ
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class CQBefore extends AnnotationBase implements Level
|
||||
{
|
||||
/**
|
||||
@@ -25,18 +28,25 @@ 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
|
||||
*/
|
||||
public function getLevel(): int {
|
||||
public function getLevel(): int
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $level
|
||||
*/
|
||||
public function setLevel($level) {
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
@@ -10,44 +13,74 @@ use ZM\Annotation\Interfaces\Level;
|
||||
/**
|
||||
* Class CQCommand
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor
|
||||
* @Target("ALL")
|
||||
* @package ZM\Annotation\CQ
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
|
||||
class CQCommand extends AnnotationBase implements Level
|
||||
{
|
||||
/** @var string */
|
||||
public $match = "";
|
||||
public $match = '';
|
||||
|
||||
/** @var string */
|
||||
public $pattern = "";
|
||||
public $pattern = '';
|
||||
|
||||
/** @var string */
|
||||
public $regex = "";
|
||||
public $regex = '';
|
||||
|
||||
/** @var string */
|
||||
public $start_with = "";
|
||||
public $start_with = '';
|
||||
|
||||
/** @var string */
|
||||
public $end_with = "";
|
||||
public $end_with = '';
|
||||
|
||||
/** @var string */
|
||||
public $keyword = "";
|
||||
public $keyword = '';
|
||||
|
||||
/** @var string[] */
|
||||
public $alias = [];
|
||||
|
||||
/** @var string */
|
||||
public $message_type = "";
|
||||
public $message_type = '';
|
||||
|
||||
/** @var int */
|
||||
public $user_id = 0;
|
||||
|
||||
/** @var int */
|
||||
public $group_id = 0;
|
||||
|
||||
/** @var int */
|
||||
public $discuss_id = 0;
|
||||
|
||||
/** @var int */
|
||||
public $level = 20;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLevel(): int { return $this->level; }
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
*/
|
||||
public function setLevel($level) { $this->level = $level; }
|
||||
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
@@ -10,31 +13,53 @@ use ZM\Annotation\Interfaces\Level;
|
||||
/**
|
||||
* Class CQMessage
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("ALL")
|
||||
* @package ZM\Annotation\CQ
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
|
||||
class CQMessage extends AnnotationBase implements Level
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $message_type = "";
|
||||
public $message_type = '';
|
||||
|
||||
/** @var int */
|
||||
public $user_id = 0;
|
||||
|
||||
/** @var int */
|
||||
public $group_id = 0;
|
||||
|
||||
/** @var int */
|
||||
public $discuss_id = 0;
|
||||
|
||||
/** @var string */
|
||||
public $message = "";
|
||||
public $message = '';
|
||||
|
||||
/** @var string */
|
||||
public $raw_message = "";
|
||||
public $raw_message = '';
|
||||
|
||||
/** @var int */
|
||||
public $level = 20;
|
||||
|
||||
public function getLevel(): int { return $this->level; }
|
||||
|
||||
public function setLevel($level) {
|
||||
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;
|
||||
}
|
||||
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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,28 +14,40 @@ use ZM\Annotation\Interfaces\Level;
|
||||
/**
|
||||
* Class CQMetaEvent
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("ALL")
|
||||
* @package ZM\Annotation\CQ
|
||||
*/
|
||||
#[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
|
||||
*/
|
||||
public function getLevel(): int { return $this->level; }
|
||||
public function getLevel(): int
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
*/
|
||||
public function setLevel($level) {
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
@@ -10,33 +13,46 @@ use ZM\Annotation\Interfaces\Level;
|
||||
/**
|
||||
* Class CQNotice
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("ALL")
|
||||
* @package ZM\Annotation\CQ
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
|
||||
class CQNotice extends AnnotationBase implements Level
|
||||
{
|
||||
/** @var string */
|
||||
public $notice_type = "";
|
||||
public $notice_type = '';
|
||||
|
||||
/** @var string */
|
||||
public $sub_type = "";
|
||||
public $sub_type = '';
|
||||
|
||||
/** @var int */
|
||||
public $group_id = 0;
|
||||
|
||||
/** @var int */
|
||||
public $operator_id = 0;
|
||||
|
||||
/** @var int */
|
||||
public $level = 20;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLevel(): int {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
*/
|
||||
public function setLevel($level) {
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
@@ -10,33 +13,46 @@ use ZM\Annotation\Interfaces\Level;
|
||||
/**
|
||||
* Class CQRequest
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("ALL")
|
||||
* @package ZM\Annotation\CQ
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
|
||||
class CQRequest extends AnnotationBase implements Level
|
||||
{
|
||||
/** @var string */
|
||||
public $request_type = "";
|
||||
public $request_type = '';
|
||||
|
||||
/** @var string */
|
||||
public $sub_type = "";
|
||||
public $sub_type = '';
|
||||
|
||||
/** @var int */
|
||||
public $user_id = 0;
|
||||
|
||||
/** @var string */
|
||||
public $comment = "";
|
||||
public $comment = '';
|
||||
|
||||
/** @var int */
|
||||
public $level = 20;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLevel(): int {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
*/
|
||||
public function setLevel($level) {
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class TerminalCommand
|
||||
* @package ZM\Annotation\Command
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class TerminalCommand extends AnnotationBase
|
||||
{
|
||||
/**
|
||||
@@ -26,5 +30,12 @@ class TerminalCommand extends AnnotationBase
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $description = "";
|
||||
}
|
||||
public $description = '';
|
||||
|
||||
public function __construct($command, $alias = '', $description = '')
|
||||
{
|
||||
$this->command = $command;
|
||||
$this->alias = $alias;
|
||||
$this->description = $description;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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,9 +14,10 @@ use ZM\Annotation\Interfaces\ErgodicAnnotation;
|
||||
/**
|
||||
* Class Controller
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("CLASS")
|
||||
* @package ZM\Annotation\Http
|
||||
*/
|
||||
#[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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Http
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class HandleAfter extends AnnotationBase
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Http
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class HandleBefore extends AnnotationBase
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class HandleException
|
||||
* @package ZM\Annotation\Http
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<?php
|
||||
|
||||
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,10 +13,11 @@ use ZM\Annotation\Interfaces\ErgodicAnnotation;
|
||||
|
||||
/**
|
||||
* Class Middleware
|
||||
* @package ZM\Annotation\Http
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("ALL")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_ALL)]
|
||||
class Middleware extends AnnotationBase implements ErgodicAnnotation
|
||||
{
|
||||
/**
|
||||
@@ -27,4 +30,10 @@ class Middleware extends AnnotationBase implements ErgodicAnnotation
|
||||
* @var string[]
|
||||
*/
|
||||
public $params = [];
|
||||
|
||||
public function __construct($middleware, $params = [])
|
||||
{
|
||||
$this->middleware = $middleware;
|
||||
$this->params = $params;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<?php
|
||||
|
||||
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 MiddlewareClass
|
||||
* @package ZM\Annotation\Http
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("CLASS")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class MiddlewareClass extends AnnotationBase
|
||||
{
|
||||
/**
|
||||
@@ -21,4 +24,9 @@ class MiddlewareClass extends AnnotationBase
|
||||
* @Required()
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
@@ -10,9 +13,10 @@ use ZM\Annotation\AnnotationBase;
|
||||
/**
|
||||
* Class RequestMapping
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
* @package ZM\Annotation\Http
|
||||
*/
|
||||
#[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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,46 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Http
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class RequestMethod extends AnnotationBase
|
||||
{
|
||||
public const GET = 'GET';
|
||||
|
||||
public const POST = 'POST';
|
||||
|
||||
public const PUT = 'PUT';
|
||||
|
||||
public const PATCH = 'PATCH';
|
||||
|
||||
public const DELETE = 'DELETE';
|
||||
|
||||
public const OPTIONS = 'OPTIONS';
|
||||
|
||||
public const HEAD = 'HEAD';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @Required()
|
||||
*/
|
||||
public $method = self::GET;
|
||||
|
||||
public const GET = 'GET';
|
||||
public const POST = 'POST';
|
||||
public const PUT = 'PUT';
|
||||
public const PATCH = 'PATCH';
|
||||
public const DELETE = 'DELETE';
|
||||
public const OPTIONS = 'OPTIONS';
|
||||
public const HEAD = 'HEAD';
|
||||
public function __construct($method)
|
||||
{
|
||||
$this->method = $method;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Annotation\Interfaces;
|
||||
|
||||
|
||||
interface CustomAnnotation
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Annotation\Interfaces;
|
||||
|
||||
|
||||
interface ErgodicAnnotation
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Annotation\Interfaces;
|
||||
|
||||
|
||||
interface Level
|
||||
{
|
||||
public function getLevel();
|
||||
|
||||
public function setLevel($level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Annotation\Interfaces;
|
||||
|
||||
|
||||
interface Rule
|
||||
{
|
||||
public function getRule();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
<?php
|
||||
|
||||
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")
|
||||
* @package ZM\Annotation\Module
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
|
||||
class Closed extends AnnotationBase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Swoole
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnCloseEvent extends OnSwooleEventBase
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $connect_type = "default";
|
||||
}
|
||||
public $connect_type = 'default';
|
||||
|
||||
public function __construct($connect_type = 'default', $rule = '', $level = 20)
|
||||
{
|
||||
$this->connect_type = $connect_type;
|
||||
$this->rule = $rule;
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
|
||||
25
src/ZM/Annotation/Swoole/OnManagerStartEvent.php
Normal file
25
src/ZM/Annotation/Swoole/OnManagerStartEvent.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,31 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Swoole
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnMessageEvent extends OnSwooleEventBase
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $connect_type = "default";
|
||||
}
|
||||
public $connect_type = 'default';
|
||||
|
||||
public function __construct($connect_type = 'default', $rule = '', $level = 20)
|
||||
{
|
||||
$this->connect_type = $connect_type;
|
||||
$this->rule = $rule;
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Swoole
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnOpenEvent extends OnSwooleEventBase
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $connect_type = "default";
|
||||
}
|
||||
public $connect_type = 'default';
|
||||
|
||||
public function __construct($connect_type = 'default', $rule = '', $level = 20)
|
||||
{
|
||||
$this->connect_type = $connect_type;
|
||||
$this->rule = $rule;
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class OnPipeMessageEvent
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnPipeMessageEvent extends AnnotationBase
|
||||
{
|
||||
/**
|
||||
@@ -21,4 +24,9 @@ class OnPipeMessageEvent extends AnnotationBase
|
||||
* @Required()
|
||||
*/
|
||||
public $action;
|
||||
}
|
||||
|
||||
public function __construct($action)
|
||||
{
|
||||
$this->action = $action;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Swoole
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnRequestEvent extends OnSwooleEventBase
|
||||
{
|
||||
}
|
||||
public function __construct($rule = '', $level = 20)
|
||||
{
|
||||
$this->rule = $rule;
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnSave extends AnnotationBase
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnSetup extends AnnotationBase
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
<?php
|
||||
|
||||
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")
|
||||
* @package ZM\Annotation\Swoole
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnSwooleEvent extends OnSwooleEventBase
|
||||
{
|
||||
/**
|
||||
@@ -20,17 +24,20 @@ class OnSwooleEvent extends OnSwooleEventBase
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string {
|
||||
public function __construct($type, $rule = '', $level = 20)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->rule = $rule;
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
public function setType(string $type) {
|
||||
public function setType(string $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Annotation\Swoole;
|
||||
|
||||
|
||||
use ZM\Annotation\AnnotationBase;
|
||||
use ZM\Annotation\Interfaces\Level;
|
||||
use ZM\Annotation\Interfaces\Rule;
|
||||
@@ -13,37 +13,33 @@ abstract class OnSwooleEventBase extends AnnotationBase implements Level, Rule
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $rule = "";
|
||||
public $rule = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $level = 20;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRule(): string {
|
||||
return $this->rule !== "" ? $this->rule : true;
|
||||
public function getRule()
|
||||
{
|
||||
return $this->rule !== '' ? $this->rule : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $rule
|
||||
*/
|
||||
public function setRule(string $rule) {
|
||||
public function setRule(string $rule)
|
||||
{
|
||||
$this->rule = $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getLevel(): int {
|
||||
public function getLevel(): int
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $level
|
||||
*/
|
||||
public function setLevel($level) {
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
@@ -10,10 +13,11 @@ use ZM\Annotation\Interfaces\Rule;
|
||||
|
||||
/**
|
||||
* Class OnTask
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
*/
|
||||
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
|
||||
class OnTask extends AnnotationBase implements Rule
|
||||
{
|
||||
/**
|
||||
@@ -25,12 +29,19 @@ class OnTask extends AnnotationBase implements Rule
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $rule = "";
|
||||
public $rule = '';
|
||||
|
||||
public function __construct($task_name, $rule = '')
|
||||
{
|
||||
$this->task_name = $task_name;
|
||||
$this->rule = $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRule(): string {
|
||||
public function getRule(): string
|
||||
{
|
||||
return $this->rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Annotation\Swoole;
|
||||
|
||||
use Attribute;
|
||||
use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
|
||||
use Doctrine\Common\Annotations\Annotation\Target;
|
||||
|
||||
/**
|
||||
* Class OnTaskEvent
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class OnTick
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("METHOD")
|
||||
* @since 1.2
|
||||
*/
|
||||
@@ -27,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class SwooleHandler
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @Annotation
|
||||
* @NamedArgumentConstructor()
|
||||
* @Target("ALL")
|
||||
*/
|
||||
class SwooleHandler extends AnnotationBase
|
||||
@@ -21,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command;
|
||||
|
||||
use ArrayIterator;
|
||||
use League\CLImate\CLImate;
|
||||
use Phar;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
@@ -16,70 +18,87 @@ class BuildCommand extends Command
|
||||
{
|
||||
// the name of the command (the part after "bin/console")
|
||||
protected static $defaultName = 'build';
|
||||
|
||||
/**
|
||||
* @var OutputInterface
|
||||
*/
|
||||
private $output = null;
|
||||
private $output;
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("Build an \".phar\" file | 将项目构建一个phar包");
|
||||
$this->setHelp("此功能将会把整个项目打包为phar");
|
||||
$this->addOption("target", "D", InputOption::VALUE_REQUIRED, "Output Directory | 指定输出目录");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('Build an ".phar" file | 将项目构建一个phar包');
|
||||
$this->setHelp('此功能将会把整个项目打包为phar');
|
||||
$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;
|
||||
$target_dir = $input->getOption("target") ?? (WORKING_DIR);
|
||||
if (mb_strpos($target_dir, "../")) $target_dir = realpath($target_dir);
|
||||
$target_dir = $input->getOption('target') ?? (WORKING_DIR);
|
||||
if (mb_strpos($target_dir, '../')) {
|
||||
$target_dir = realpath($target_dir);
|
||||
}
|
||||
if ($target_dir === false) {
|
||||
$output->writeln(TermColor::color8(31) . zm_internal_errcode("E00039") . "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;
|
||||
}
|
||||
$output->writeln("Target: " . $target_dir);
|
||||
if (mb_substr($target_dir, -1, 1) !== '/') $target_dir .= "/";
|
||||
$output->writeln('Target: ' . $target_dir);
|
||||
if (mb_substr($target_dir, -1, 1) !== '/') {
|
||||
$target_dir .= '/';
|
||||
}
|
||||
if (ini_get('phar.readonly') == 1) {
|
||||
$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) . 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');
|
||||
return 1;
|
||||
}
|
||||
if (!is_dir($target_dir)) {
|
||||
$output->writeln(TermColor::color8(31) . zm_internal_errcode("E00039") . "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;
|
||||
}
|
||||
$filename = "server.phar";
|
||||
$filename = 'server.phar';
|
||||
$this->build($target_dir, $filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function build($target_dir, $filename) {
|
||||
private function build($target_dir, $filename)
|
||||
{
|
||||
@unlink($target_dir . $filename);
|
||||
$phar = new Phar($target_dir . $filename);
|
||||
$phar->startBuffering();
|
||||
$climate = new CLImate();
|
||||
|
||||
$all = DataProvider::scanDirFiles(DataProvider::getSourceRootDir(), true, true);
|
||||
|
||||
$all = array_filter($all, function ($x) {
|
||||
$dirs = preg_match("/(^(bin|config|resources|src|vendor)\/|^(composer\.json|README\.md)$)/", $x);
|
||||
$dirs = preg_match('/(^(bin|config|resources|src|vendor)\\/|^(composer\\.json|README\\.md)$)/', $x);
|
||||
return !($dirs !== 1);
|
||||
});
|
||||
|
||||
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->createDefaultStub(LOAD_MODE == 0 ? 'src/entry.php' : 'vendor/zhamao/framework/src/entry.php')
|
||||
);
|
||||
$phar->stopBuffering();
|
||||
$this->output->writeln("Successfully built. Location: " . $target_dir . "$filename");
|
||||
$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>');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command;
|
||||
|
||||
@@ -14,49 +15,53 @@ class CheckConfigCommand extends Command
|
||||
|
||||
private $need_update = false;
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("检查配置文件是否和框架当前版本有更新");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('检查配置文件是否和框架当前版本有更新');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (LOAD_MODE !== 1) {
|
||||
$output->writeln("<error>仅限在Composer依赖模式中使用此命令!</error>");
|
||||
$output->writeln('<error>仅限在Composer依赖模式中使用此命令!</error>');
|
||||
return 1;
|
||||
}
|
||||
$current_cfg = getcwd() . "/config/";
|
||||
$remote_cfg = include_once FRAMEWORK_ROOT_DIR . "/config/global.php";
|
||||
if (file_exists($current_cfg . "global.php")) {
|
||||
$this->check($remote_cfg, "global.php", $output);
|
||||
$current_cfg = getcwd() . '/config/';
|
||||
$remote_cfg = include_once FRAMEWORK_ROOT_DIR . '/config/global.php';
|
||||
if (file_exists($current_cfg . 'global.php')) {
|
||||
$this->check($remote_cfg, 'global.php', $output);
|
||||
}
|
||||
if (file_exists($current_cfg . "global.development.php")) {
|
||||
$this->check($remote_cfg, "global.development.php", $output);
|
||||
if (file_exists($current_cfg . 'global.development.php')) {
|
||||
$this->check($remote_cfg, 'global.development.php', $output);
|
||||
}
|
||||
if (file_exists($current_cfg . "global.staging.php")) {
|
||||
$this->check($remote_cfg, "global.staging.php", $output);
|
||||
if (file_exists($current_cfg . 'global.staging.php')) {
|
||||
$this->check($remote_cfg, 'global.staging.php', $output);
|
||||
}
|
||||
if (file_exists($current_cfg . "global.production.php")) {
|
||||
$this->check($remote_cfg, "global.production.php", $output);
|
||||
if (file_exists($current_cfg . 'global.production.php')) {
|
||||
$this->check($remote_cfg, 'global.production.php', $output);
|
||||
}
|
||||
if ($this->need_update === true) {
|
||||
$output->writeln("<comment>有配置文件需要更新,详情见文档 `https://framework.zhamao.xin/update/config`</comment>");
|
||||
$output->writeln('<comment>有配置文件需要更新,详情见文档 `https://framework.zhamao.xin/update/config`</comment>');
|
||||
} else {
|
||||
$output->writeln("<info>配置文件暂无更新!</info>");
|
||||
$output->writeln('<info>配置文件暂无更新!</info>');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @noinspection PhpIncludeInspection
|
||||
* @param mixed $remote
|
||||
* @param mixed $local
|
||||
*/
|
||||
private function check($remote, $local, OutputInterface $out) {
|
||||
$local_file = include_once WORKING_DIR . "/config/".$local;
|
||||
private function check($remote, $local, OutputInterface $out)
|
||||
{
|
||||
$local_file = include_once WORKING_DIR . '/config/' . $local;
|
||||
if ($local_file === true) {
|
||||
$local_file = ZMConfig::get("global");
|
||||
$local_file = ZMConfig::get('global');
|
||||
}
|
||||
foreach($remote as $k => $v) {
|
||||
foreach ($remote as $k => $v) {
|
||||
if (!isset($local_file[$k])) {
|
||||
$out->writeln("<comment>配置文件 ".$local . " 需要更新!(当前配置文件缺少 `$k` 字段配置)</comment>");
|
||||
$out->writeln('<comment>配置文件 ' . $local . " 需要更新!(当前配置文件缺少 `{$k}` 字段配置)</comment>");
|
||||
$this->need_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Daemon;
|
||||
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use ZM\Utils\DataProvider;
|
||||
use ZM\Framework;
|
||||
|
||||
abstract class DaemonCommand extends Command
|
||||
{
|
||||
protected $daemon_file = null;
|
||||
protected $daemon_file;
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$pid_path = DataProvider::getWorkingDir() . "/.daemon_pid";
|
||||
if (!file_exists($pid_path)) {
|
||||
$output->writeln("<comment>没有检测到正在运行的守护进程或框架进程!</comment>");
|
||||
die();
|
||||
}
|
||||
$file = json_decode(file_get_contents($pid_path), true);
|
||||
if ($file === null || posix_getsid(intval($file["pid"])) === false) {
|
||||
$output->writeln("<comment>未检测到正在运行的守护进程或框架进程!</comment>");
|
||||
unlink($pid_path);
|
||||
die();
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$file = Framework::getProcessState(ZM_PROCESS_MASTER);
|
||||
if ($file === false || posix_getsid(intval($file['pid'])) === false) {
|
||||
$output->writeln('<comment>未检测到正在运行的守护进程或框架进程!</comment>');
|
||||
Framework::removeProcessState(ZM_PROCESS_MASTER);
|
||||
exit(1);
|
||||
}
|
||||
$this->daemon_file = $file;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Daemon;
|
||||
|
||||
@@ -11,14 +12,16 @@ class DaemonReloadCommand extends DaemonCommand
|
||||
{
|
||||
protected static $defaultName = 'daemon:reload';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("重载框架");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('重载框架');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
parent::execute($input, $output);
|
||||
Process::kill(intval($this->daemon_file["pid"]), SIGUSR1);
|
||||
$output->writeln("<info>成功重载!</info>");
|
||||
Process::kill(intval($this->daemon_file['pid']), SIGUSR1);
|
||||
$output->writeln('<info>成功重载!</info>');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Daemon;
|
||||
|
||||
@@ -10,20 +11,23 @@ class DaemonStatusCommand extends DaemonCommand
|
||||
{
|
||||
protected static $defaultName = 'daemon:status';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("查看框架的运行状态");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('查看框架的运行状态');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
parent::execute($input, $output);
|
||||
$output->writeln("<info>框架" . ($this->daemon_file["daemon"] ? "以守护进程模式" : "") . "运行中,pid:" . $this->daemon_file["pid"] . "</info>");
|
||||
if ($this->daemon_file["daemon"]) {
|
||||
$output->writeln("<comment>----- 以下是stdout内容 -----</comment>");
|
||||
$stdout = file_get_contents($this->daemon_file["stdout"]);
|
||||
$output->writeln('<info>框架' . ($this->daemon_file['daemon'] ? '以守护进程模式' : '') . '运行中,pid:' . $this->daemon_file['pid'] . '</info>');
|
||||
if ($this->daemon_file['daemon']) {
|
||||
$output->writeln('<comment>----- 以下是stdout内容 -----</comment>');
|
||||
$stdout = file_get_contents($this->daemon_file['stdout']);
|
||||
$stdout = explode("\n", $stdout);
|
||||
for ($i = 15; $i > 0; --$i) {
|
||||
if (isset($stdout[count($stdout) - $i]))
|
||||
if (isset($stdout[count($stdout) - $i])) {
|
||||
echo $stdout[count($stdout) - $i] . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Daemon;
|
||||
|
||||
use Swoole\Process;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use ZM\Utils\DataProvider;
|
||||
use ZM\Framework;
|
||||
|
||||
class DaemonStopCommand extends DaemonCommand
|
||||
{
|
||||
protected static $defaultName = 'daemon:stop';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("停止运行的框架");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('停止运行的框架');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
parent::execute($input, $output);
|
||||
Process::kill(intval($this->daemon_file["pid"]), SIGTERM);
|
||||
Process::kill(intval($this->daemon_file['pid']), SIGTERM);
|
||||
$i = 10;
|
||||
while (file_exists(DataProvider::getWorkingDir() . "/.daemon_pid") && $i > 0) {
|
||||
while (Framework::getProcessState(ZM_PROCESS_MASTER) !== false && $i > 0) {
|
||||
sleep(1);
|
||||
--$i;
|
||||
}
|
||||
if ($i === 0) {
|
||||
$output->writeln("<error>停止失败,请检查进程pid #" . $this->daemon_file["pid"] . " 是否响应!</error>");
|
||||
$output->writeln('<error>停止失败,请检查进程pid #' . $this->daemon_file['pid'] . ' 是否响应!</error>');
|
||||
} else {
|
||||
$output->writeln("<info>成功停止!</info>");
|
||||
$output->writeln('<info>成功停止!</info>');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Generate;
|
||||
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -15,28 +15,31 @@ class SystemdGenerateCommand extends Command
|
||||
// the name of the command (the part after "bin/console")
|
||||
protected static $defaultName = 'generate:systemd';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("生成框架的 systemd 配置文件");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('生成框架的 systemd 配置文件');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||
$path = $this->generate();
|
||||
$output->writeln("<info>成功生成 systemd 文件,位置:" . $path . "</info>");
|
||||
$output->writeln("<info>有关如何使用 systemd 配置文件,请访问 `https://github.com/zhamao-robot/zhamao-framework/issues/36`</info>");
|
||||
$output->writeln('<info>成功生成 systemd 文件,位置:' . $path . '</info>');
|
||||
$output->writeln('<info>有关如何使用 systemd 配置文件,请访问 `https://github.com/zhamao-robot/zhamao-framework/issues/36`</info>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function generate() {
|
||||
private function generate()
|
||||
{
|
||||
$s = "[Unit]\nDescription=zhamao-framework Daemon\nAfter=rc-local.service\n\n[Service]\nType=simple";
|
||||
$s .= "\nUser=" . exec("whoami");
|
||||
$s .= "\nUser=" . exec('whoami');
|
||||
$s .= "\nGroup=" . exec("groups | awk '{print $1}'");
|
||||
$s .= "\nWorkingDirectory=" . getcwd();
|
||||
global $argv;
|
||||
$s .= "\nExecStart=" . PHP_BINARY . " {$argv[0]} server";
|
||||
$s .= "\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n";
|
||||
@mkdir(getcwd() . "/resources/");
|
||||
file_put_contents(ZMConfig::get("global", "zm_data") . "zhamao.service", $s);
|
||||
return ZMConfig::get("global", "zm_data") . "zhamao.service";
|
||||
@mkdir(getcwd() . '/resources/');
|
||||
file_put_contents(ZMConfig::get('global', 'zm_data') . 'zhamao.service', $s);
|
||||
return ZMConfig::get('global', 'zm_data') . 'zhamao.service';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command;
|
||||
|
||||
@@ -11,99 +12,107 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class InitCommand extends Command
|
||||
{
|
||||
private $extract_files = [
|
||||
"/zhamao",
|
||||
"/config/global.php",
|
||||
"/.gitignore",
|
||||
"/config/file_header.json",
|
||||
"/config/console_color.json",
|
||||
"/config/motd.txt",
|
||||
"/src/Module/Example/Hello.php",
|
||||
"/src/Module/Middleware/TimerMiddleware.php",
|
||||
"/src/Custom/global_function.php"
|
||||
];
|
||||
|
||||
// the name of the command (the part after "bin/console")
|
||||
protected static $defaultName = 'init';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("Initialize framework starter | 初始化框架运行的基础文件");
|
||||
private $extract_files = [
|
||||
'/zhamao',
|
||||
'/config/global.php',
|
||||
'/.gitignore',
|
||||
'/config/file_header.json',
|
||||
'/config/console_color.json',
|
||||
'/config/motd.txt',
|
||||
'/src/Module/Example/Hello.php',
|
||||
'/src/Module/Middleware/TimerMiddleware.php',
|
||||
'/src/Custom/global_function.php',
|
||||
];
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('Initialize framework starter | 初始化框架运行的基础文件');
|
||||
$this->setDefinition([
|
||||
new InputOption("force", "F", null, "强制重制,覆盖现有文件")
|
||||
new InputOption('force', 'F', null, '强制重制,覆盖现有文件'),
|
||||
]);
|
||||
$this->setHelp("此命令将会解压以下文件到项目的根目录:\n" . implode("\n", $this->getExtractFiles()));
|
||||
// ...
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (LOAD_MODE === 1) { // 从composer依赖而来的项目模式,最基本的需要初始化的模式
|
||||
$output->writeln("<comment>Initializing files</comment>");
|
||||
$output->writeln('<comment>Initializing files</comment>');
|
||||
$base_path = WORKING_DIR;
|
||||
$args = $input->getOption("force");
|
||||
$args = $input->getOption('force');
|
||||
foreach ($this->extract_files as $file) {
|
||||
if (!file_exists($base_path . $file) || $args) {
|
||||
$info = pathinfo($file);
|
||||
@mkdir($base_path . $info["dirname"], 0777, true);
|
||||
echo "Copying " . $file . PHP_EOL;
|
||||
$package_name = (json_decode(file_get_contents(__DIR__ . "/../../../composer.json"), true)["name"]);
|
||||
copy($base_path . "/vendor/" . $package_name . $file, $base_path . $file);
|
||||
@mkdir($base_path . $info['dirname'], 0777, true);
|
||||
echo 'Copying ' . $file . PHP_EOL;
|
||||
$package_name = (json_decode(file_get_contents(__DIR__ . '/../../../composer.json'), true)['name']);
|
||||
copy($base_path . '/vendor/' . $package_name . $file, $base_path . $file);
|
||||
} 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 = [
|
||||
"psr-4" => [
|
||||
"Module\\" => "src/Module",
|
||||
"Custom\\" => "src/Custom"
|
||||
'psr-4' => [
|
||||
'Module\\' => 'src/Module',
|
||||
'Custom\\' => 'src/Custom',
|
||||
],
|
||||
'files' => [
|
||||
'src/Custom/global_function.php',
|
||||
],
|
||||
"files" => [
|
||||
"src/Custom/global_function.php"
|
||||
]
|
||||
];
|
||||
if (file_exists($base_path . "/composer.json")) {
|
||||
$composer = json_decode(file_get_contents($base_path . "/composer.json"), true);
|
||||
if (!isset($composer["autoload"])) {
|
||||
$composer["autoload"] = $autoload;
|
||||
if (file_exists($base_path . '/composer.json')) {
|
||||
$composer = json_decode(file_get_contents($base_path . '/composer.json'), true);
|
||||
if (!isset($composer['autoload'])) {
|
||||
$composer['autoload'] = $autoload;
|
||||
} else {
|
||||
foreach ($autoload["psr-4"] as $k => $v) {
|
||||
if (!isset($composer["autoload"]["psr-4"][$k])) $composer["autoload"]["psr-4"][$k] = $v;
|
||||
foreach ($autoload['psr-4'] as $k => $v) {
|
||||
if (!isset($composer['autoload']['psr-4'][$k])) {
|
||||
$composer['autoload']['psr-4'][$k] = $v;
|
||||
}
|
||||
}
|
||||
foreach ($autoload["files"] as $v) {
|
||||
if (!in_array($v, $composer["autoload"]["files"])) $composer["autoload"]["files"][] = $v;
|
||||
foreach ($autoload['files'] as $v) {
|
||||
if (!in_array($v, $composer['autoload']['files'])) {
|
||||
$composer['autoload']['files'][] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
file_put_contents($base_path . "/composer.json", json_encode($composer, 64 | 128 | 256));
|
||||
$output->writeln("<info>Executing composer command: `composer dump-autoload`</info>");
|
||||
exec("composer dump-autoload");
|
||||
file_put_contents($base_path . '/composer.json', json_encode($composer, 64 | 128 | 256));
|
||||
$output->writeln('<info>Executing composer command: `composer dump-autoload`</info>');
|
||||
exec('composer dump-autoload');
|
||||
echo PHP_EOL;
|
||||
} else {
|
||||
echo(zm_internal_errcode("E00041") . "Error occurred. Please check your updates.\n");
|
||||
echo zm_internal_errcode('E00041') . "Error occurred. Please check your updates.\n";
|
||||
return 1;
|
||||
}
|
||||
$output->writeln("<info>Done!</info>");
|
||||
$output->writeln('<info>Done!</info>');
|
||||
return 0;
|
||||
} elseif (LOAD_MODE === 2) { //从phar启动的框架包,初始化的模式
|
||||
}
|
||||
if (LOAD_MODE === 2) { // 从phar启动的框架包,初始化的模式
|
||||
$phar_link = new Phar(__DIR__);
|
||||
$current_dir = pathinfo($phar_link->getPath())["dirname"];
|
||||
$current_dir = pathinfo($phar_link->getPath())['dirname'];
|
||||
chdir($current_dir);
|
||||
$phar_link = "phar://" . $phar_link->getPath();
|
||||
$phar_link = 'phar://' . $phar_link->getPath();
|
||||
foreach ($this->extract_files as $file) {
|
||||
if (!file_exists($current_dir . $file)) {
|
||||
$info = pathinfo($file);
|
||||
@mkdir($current_dir . $info["dirname"], 0777, true);
|
||||
echo "Copying " . $file . PHP_EOL;
|
||||
@mkdir($current_dir . $info['dirname'], 0777, true);
|
||||
echo 'Copying ' . $file . PHP_EOL;
|
||||
file_put_contents($current_dir . $file, file_get_contents($phar_link . $file));
|
||||
} else {
|
||||
echo "Skipping " . $file . " , file exists." . PHP_EOL;
|
||||
echo 'Skipping ' . $file . ' , file exists.' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
$output->writeln(zm_internal_errcode("E00042") . "initialization must be started with composer-project mode!");
|
||||
$output->writeln(zm_internal_errcode('E00042') . 'initialization must be started with composer-project mode!');
|
||||
return 1;
|
||||
}
|
||||
|
||||
private function getExtractFiles(): array {
|
||||
private function getExtractFiles(): array
|
||||
{
|
||||
return $this->extract_files;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Module;
|
||||
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -14,67 +14,97 @@ use ZM\Utils\Manager\ModuleManager;
|
||||
|
||||
class ModuleListCommand extends Command
|
||||
{
|
||||
// the name of the command (the part after "bin/console")
|
||||
// the name of the command (the part after "bin/console")
|
||||
protected static $defaultName = 'module:list';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("查看所有模块信息");
|
||||
$this->setHelp("此功能将会把炸毛框架的模块列举出来。");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('查看所有模块信息');
|
||||
$this->setHelp('此功能将会把炸毛框架的模块列举出来。');
|
||||
// ...
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||
ZMConfig::setEnv($args["env"] ?? "");
|
||||
if (ZMConfig::get("global") === false) {
|
||||
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");
|
||||
ZMConfig::setEnv($args['env'] ?? '');
|
||||
if (ZMConfig::get('global') === false) {
|
||||
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";
|
||||
include_once DataProvider::getFrameworkRootDir() . '/src/ZM/global_defines.php';
|
||||
|
||||
Console::init(
|
||||
ZMConfig::get("global", "info_level") ?? 2,
|
||||
ZMConfig::get('global', 'info_level') ?? 2,
|
||||
null,
|
||||
$args["log-theme"] ?? "default",
|
||||
($o = ZMConfig::get("console_color")) === false ? [] : $o
|
||||
$args['log-theme'] ?? 'default',
|
||||
($o = ZMConfig::get('console_color')) === false ? [] : $o
|
||||
);
|
||||
|
||||
$timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai";
|
||||
$timezone = ZMConfig::get('global', 'timezone') ?? 'Asia/Shanghai';
|
||||
date_default_timezone_set($timezone);
|
||||
|
||||
$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"]);
|
||||
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);
|
||||
}
|
||||
if ($list === []) {
|
||||
echo Console::setColor("没有发现已编写打包配置文件(zm.json)的模块!", "yellow") . PHP_EOL;
|
||||
echo Console::setColor('没有发现已编写打包配置文件(zm.json)的模块!', 'yellow') . PHP_EOL;
|
||||
}
|
||||
$list = ModuleManager::getPackedModules();
|
||||
foreach ($list as $v) {
|
||||
echo "[" . Console::setColor($v["name"], "gold") . "]" . PHP_EOL;
|
||||
$out_list = ["类型" => "模块包(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"]);
|
||||
echo '[' . Console::setColor($v['name'], 'gold') . ']' . PHP_EOL;
|
||||
$out_list = ['类型' => '模块包(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("没有发现已打包且装载的模块!", "yellow") . PHP_EOL;
|
||||
echo Console::setColor('没有发现已打包且装载的模块!', 'yellow') . PHP_EOL;
|
||||
}
|
||||
|
||||
$list = ModuleManager::getComposerModules();
|
||||
foreach ($list as $v) {
|
||||
echo '[' . Console::setColor($v['name'], 'blue') . ']' . PHP_EOL;
|
||||
$out_list = ['类型' => 'Composer库(composer)'];
|
||||
$out_list['包名'] = $v['composer-name'];
|
||||
$out_list['目录'] = str_replace(DataProvider::getSourceRootDir() . '/', '', $v['module-path']);
|
||||
if (isset($v['version'])) {
|
||||
$out_list['版本'] = $v['version'];
|
||||
}
|
||||
if (isset($v['description'])) {
|
||||
$out_list['描述'] = $v['description'];
|
||||
}
|
||||
$out_list['命名空间'] = $v['namespace'];
|
||||
$this->printList($out_list);
|
||||
}
|
||||
if ($list === []) {
|
||||
echo Console::setColor('没有发现Composer模块!', 'yellow') . PHP_EOL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function printList($list) {
|
||||
private function printList($list)
|
||||
{
|
||||
foreach ($list as $k => $v) {
|
||||
echo "\t" . $k . ": " . Console::setColor($v, "yellow") . PHP_EOL;
|
||||
echo "\t" . $k . ': ' . Console::setColor($v, 'yellow') . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Module;
|
||||
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -19,42 +19,47 @@ 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("将配置好的模块构建一个phar包");
|
||||
$this->setHelp("此功能将会把炸毛框架的模块打包为\".phar\",供发布和执行。");
|
||||
$this->addOption("target", "D", InputOption::VALUE_REQUIRED, "Output Directory | 指定输出目录");
|
||||
protected function configure()
|
||||
{
|
||||
$this->addArgument('module-name', InputArgument::REQUIRED);
|
||||
$this->setDescription('将配置好的模块构建一个phar包');
|
||||
$this->setHelp('此功能将会把炸毛框架的模块打包为".phar",供发布和执行。');
|
||||
$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
|
||||
{
|
||||
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||
ZMConfig::setEnv($args["env"] ?? "");
|
||||
if (ZMConfig::get("global") === false) {
|
||||
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");
|
||||
ZMConfig::setEnv($args['env'] ?? '');
|
||||
if (ZMConfig::get('global') === false) {
|
||||
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";
|
||||
// 定义常量
|
||||
include_once DataProvider::getFrameworkRootDir() . '/src/ZM/global_defines.php';
|
||||
|
||||
Console::init(
|
||||
ZMConfig::get("global", "info_level") ?? 2,
|
||||
ZMConfig::get('global', 'info_level') ?? 2,
|
||||
null,
|
||||
$args["log-theme"] ?? "default",
|
||||
($o = ZMConfig::get("console_color")) === false ? [] : $o
|
||||
$args['log-theme'] ?? 'default',
|
||||
($o = ZMConfig::get('console_color')) === false ? [] : $o
|
||||
);
|
||||
|
||||
$timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai";
|
||||
$timezone = ZMConfig::get('global', 'timezone') ?? 'Asia/Shanghai';
|
||||
date_default_timezone_set($timezone);
|
||||
|
||||
$list = ModuleManager::getConfiguredModules();
|
||||
if (!isset($list[$input->getArgument("module-name")])) {
|
||||
$output->writeln("<error>不存在模块 ".$input->getArgument("module-name")." !</error>");
|
||||
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")], $input->getOption("target"));
|
||||
if ($result) Console::success("打包完成!");
|
||||
else Console::error("打包失败!");
|
||||
$result = ModuleManager::packModule($list[$input->getArgument('module-name')], $input->getOption('target'));
|
||||
if ($result) {
|
||||
Console::success('打包完成!');
|
||||
} else {
|
||||
Console::error('打包失败!');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Module;
|
||||
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -16,51 +16,56 @@ use ZM\Utils\Manager\ModuleManager;
|
||||
|
||||
class ModuleUnpackCommand extends Command
|
||||
{
|
||||
// the name of the command (the part after "bin/console")
|
||||
// the name of the command (the part after "bin/console")
|
||||
protected static $defaultName = 'module:unpack';
|
||||
|
||||
protected function configure() {
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDefinition([
|
||||
new InputArgument("module-name", InputArgument::REQUIRED),
|
||||
new InputOption("overwrite-light-cache", null, null, "覆盖现有的LightCache项目"),
|
||||
new InputOption("overwrite-zm-data", null, null, "覆盖现有的zm_data文件"),
|
||||
new InputOption("overwrite-source", null, null, "覆盖现有的源码文件"),
|
||||
new InputOption("ignore-depends", null, null, "解包时忽略检查依赖")
|
||||
new InputArgument('module-name', InputArgument::REQUIRED),
|
||||
new InputOption('overwrite-light-cache', null, null, '覆盖现有的LightCache项目'),
|
||||
new InputOption('overwrite-zm-data', null, null, '覆盖现有的zm_data文件'),
|
||||
new InputOption('overwrite-source', null, null, '覆盖现有的源码文件'),
|
||||
new InputOption('ignore-depends', null, null, '解包时忽略检查依赖'),
|
||||
]);
|
||||
$this->setDescription("解包一个phar模块到src目录");
|
||||
$this->setHelp("此功能将phar格式的模块包解包到src目录下。");
|
||||
$this->setDescription('解包一个phar模块到src目录');
|
||||
$this->setHelp('此功能将phar格式的模块包解包到src目录下。');
|
||||
// ...
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||
ZMConfig::setEnv($args["env"] ?? "");
|
||||
if (ZMConfig::get("global") === false) {
|
||||
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");
|
||||
ZMConfig::setEnv($args['env'] ?? '');
|
||||
if (ZMConfig::get('global') === false) {
|
||||
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";
|
||||
include_once DataProvider::getFrameworkRootDir() . '/src/ZM/global_defines.php';
|
||||
|
||||
Console::init(
|
||||
ZMConfig::get("global", "info_level") ?? 4,
|
||||
ZMConfig::get('global', 'info_level') ?? 4,
|
||||
null,
|
||||
$args["log-theme"] ?? "default",
|
||||
($o = ZMConfig::get("console_color")) === false ? [] : $o
|
||||
$args['log-theme'] ?? 'default',
|
||||
($o = ZMConfig::get('console_color')) === false ? [] : $o
|
||||
);
|
||||
|
||||
$timezone = ZMConfig::get("global", "timezone") ?? "Asia/Shanghai";
|
||||
$timezone = ZMConfig::get('global', 'timezone') ?? 'Asia/Shanghai';
|
||||
date_default_timezone_set($timezone);
|
||||
|
||||
$list = ModuleManager::getPackedModules();
|
||||
if (!isset($list[$input->getArgument("module-name")])) {
|
||||
$output->writeln("<error>不存在打包的模块 ".$input->getArgument("module-name")." !</error>");
|
||||
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")], $input->getOptions());
|
||||
if ($result) Console::success("解压完成!");
|
||||
else Console::error("解压失败!");
|
||||
$result = ModuleManager::unpackModule($list[$input->getArgument('module-name')], $input->getOptions());
|
||||
if ($result) {
|
||||
Console::success('解压完成!');
|
||||
} else {
|
||||
Console::error('解压失败!');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command;
|
||||
|
||||
|
||||
use Swoole\Atomic;
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Http\Response;
|
||||
@@ -26,71 +26,74 @@ class PureHttpCommand extends Command
|
||||
// the name of the command (the part after "bin/console")
|
||||
protected static $defaultName = 'simple-http-server';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("Run a simple http server | 启动一个简单的文件 HTTP 服务器");
|
||||
$this->setHelp("直接运行可以启动");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('Run a simple http server | 启动一个简单的文件 HTTP 服务器');
|
||||
$this->setHelp('直接运行可以启动');
|
||||
$this->addArgument('dir', InputArgument::REQUIRED, 'Your directory');
|
||||
$this->addOption("host", 'H', InputOption::VALUE_REQUIRED, "启动监听地址");
|
||||
$this->addOption("port", 'P', InputOption::VALUE_REQUIRED, "启动监听地址的端口");
|
||||
$this->addOption('host', 'H', InputOption::VALUE_REQUIRED, '启动监听地址');
|
||||
$this->addOption('port', 'P', InputOption::VALUE_REQUIRED, '启动监听地址的端口');
|
||||
// ...
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$tty_width = explode(" ", trim(exec("stty size")))[1];
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$tty_width = explode(' ', trim(exec('stty size')))[1];
|
||||
if (realpath($input->getArgument('dir') ?? '.') === false) {
|
||||
$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;
|
||||
}
|
||||
ZMConfig::setDirectory(DataProvider::getSourceRootDir() . '/config');
|
||||
$global = ZMConfig::get("global");
|
||||
$host = $input->getOption("host") ?? $global["host"];
|
||||
$port = $input->getOption("port") ?? $global["port"];
|
||||
$global = ZMConfig::get('global');
|
||||
$host = $input->getOption('host') ?? $global['host'];
|
||||
$port = $input->getOption('port') ?? $global['port'];
|
||||
|
||||
$index = ["index.html", "index.htm"];
|
||||
$index = ['index.html', 'index.htm'];
|
||||
$out = [
|
||||
"listen" => $host.":".$port,
|
||||
"version" => ZM_VERSION,
|
||||
"web_root" => realpath($input->getArgument('dir') ?? '.'),
|
||||
"index" => implode(",", $index)
|
||||
'listen' => $host . ':' . $port,
|
||||
'version' => ZM_VERSION,
|
||||
'web_root' => realpath($input->getArgument('dir') ?? '.'),
|
||||
'index' => implode(',', $index),
|
||||
];
|
||||
Framework::printProps($out, $tty_width);
|
||||
$server = new Server($host, $port);
|
||||
$server->set(ZMConfig::get("global", "swoole"));
|
||||
$server->set(ZMConfig::get('global', 'swoole'));
|
||||
Console::init(2, $server);
|
||||
ZMAtomic::$atomics["request"] = [];
|
||||
ZMAtomic::$atomics['request'] = [];
|
||||
for ($i = 0; $i < 32; ++$i) {
|
||||
ZMAtomic::$atomics["request"][$i] = new Atomic(0);
|
||||
ZMAtomic::$atomics['request'][$i] = new Atomic(0);
|
||||
}
|
||||
$server->on("request", function (Request $request, Response $response) use ($input, $index, $server) {
|
||||
ZMAtomic::$atomics["request"][$server->worker_id]->add(1);
|
||||
$server->on('request', function (Request $request, Response $response) use ($input, $index, $server) {
|
||||
ZMAtomic::$atomics['request'][$server->worker_id]->add(1);
|
||||
HttpUtil::handleStaticPage(
|
||||
$request->server["request_uri"],
|
||||
$request->server['request_uri'],
|
||||
$response,
|
||||
[
|
||||
"document_root" => realpath($input->getArgument('dir') ?? '.'),
|
||||
"document_index" => $index
|
||||
]);
|
||||
//echo "\r" . Coroutine::stats()["coroutine_peak_num"];
|
||||
'document_root' => realpath($input->getArgument('dir') ?? '.'),
|
||||
'document_index' => $index,
|
||||
]
|
||||
);
|
||||
// echo "\r" . Coroutine::stats()["coroutine_peak_num"];
|
||||
});
|
||||
$server->on("start", function ($server) {
|
||||
$server->on('start', function ($server) {
|
||||
Process::signal(SIGINT, function () use ($server) {
|
||||
echo "\r";
|
||||
Console::warning("Server interrupted by keyboard.");
|
||||
Console::warning('Server interrupted by keyboard.');
|
||||
for ($i = 0; $i < 32; ++$i) {
|
||||
$num = ZMAtomic::$atomics["request"][$i]->get();
|
||||
if ($num != 0)
|
||||
echo "[$i]: " . $num . "\n";
|
||||
$num = ZMAtomic::$atomics['request'][$i]->get();
|
||||
if ($num != 0) {
|
||||
echo "[{$i}]: " . $num . "\n";
|
||||
}
|
||||
}
|
||||
$server->shutdown();
|
||||
$server->stop();
|
||||
});
|
||||
Console::success("Server started. Use Ctrl+C to stop.");
|
||||
Console::success('Server started. Use Ctrl+C to stop.');
|
||||
});
|
||||
$server->start();
|
||||
// return this if there was no problem running the command
|
||||
// (it's equivalent to returning int(0))
|
||||
return 0;
|
||||
|
||||
// or return this if some error happened during the execution
|
||||
// (it's equivalent to returning int(1))
|
||||
// return 1;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command;
|
||||
|
||||
@@ -8,65 +9,66 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use ZM\Framework;
|
||||
use ZM\Utils\DataProvider;
|
||||
|
||||
class RunServerCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'server';
|
||||
|
||||
protected function configure() {
|
||||
$this->setAliases(['server:start']);
|
||||
$this->setDefinition([
|
||||
new InputOption("debug-mode", "D", null, "开启调试模式 (这将关闭协程化)"),
|
||||
new InputOption("log-debug", null, null, "调整消息等级到debug (log-level=4)"),
|
||||
new InputOption("log-verbose", null, null, "调整消息等级到verbose (log-level=3)"),
|
||||
new InputOption("log-info", null, null, "调整消息等级到info (log-level=2)"),
|
||||
new InputOption("log-warning", null, null, "调整消息等级到warning (log-level=1)"),
|
||||
new InputOption("log-error", null, null, "调整消息等级到error (log-level=0)"),
|
||||
new InputOption("log-theme", null, InputOption::VALUE_REQUIRED, "改变终端的主题配色"),
|
||||
new InputOption("disable-console-input", null, null, "禁止终端输入内容 (废弃)"),
|
||||
new InputOption("interact", null, null, "打开终端输入"),
|
||||
new InputOption("remote-terminal", null, null, "启用远程终端,配置使用global.php中的"),
|
||||
new InputOption("disable-coroutine", null, null, "关闭协程Hook"),
|
||||
new InputOption("daemon", null, null, "以守护进程的方式运行框架"),
|
||||
new InputOption("worker-num", null, InputOption::VALUE_REQUIRED, "启动框架时运行的 Worker 进程数量"),
|
||||
new InputOption("task-worker-num", null, InputOption::VALUE_REQUIRED, "启动框架时运行的 TaskWorker 进程数量"),
|
||||
new InputOption("watch", null, null, "监听 src/ 目录的文件变化并热更新"),
|
||||
new InputOption("show-php-ver", null, null, "启动时显示PHP和Swoole版本"),
|
||||
new InputOption("env", null, InputOption::VALUE_REQUIRED, "设置环境类型 (production, development, staging)"),
|
||||
new InputOption("disable-safe-exit", null, null, "关闭安全退出(关闭后按CtrlC时直接杀死进程)"),
|
||||
new InputOption("preview", null, null, "只显示参数,不启动服务器"),
|
||||
new InputOption("force-load-module", null, InputOption::VALUE_OPTIONAL, "强制打包状态下加载模块(使用英文逗号分割多个)")
|
||||
]);
|
||||
$this->setDescription("Run zhamao-framework | 启动框架");
|
||||
$this->setHelp("直接运行可以启动");
|
||||
public static function exportDefinition()
|
||||
{
|
||||
$cmd = new self();
|
||||
$cmd->configure();
|
||||
return $cmd->getDefinition();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
if (($opt = $input->getOption("env")) !== null) {
|
||||
if (!in_array($opt, ["production", "staging", "development", ""])) {
|
||||
$output->writeln("<error> \"--env\" option only accept production, development, staging and [empty] ! </error>");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setAliases(['server:start']);
|
||||
$this->setDefinition([
|
||||
new InputOption('debug-mode', 'D', null, '开启调试模式 (这将关闭协程化)'),
|
||||
new InputOption('log-debug', null, null, '调整消息等级到debug (log-level=4)'),
|
||||
new InputOption('log-verbose', null, null, '调整消息等级到verbose (log-level=3)'),
|
||||
new InputOption('log-info', null, null, '调整消息等级到info (log-level=2)'),
|
||||
new InputOption('log-warning', null, null, '调整消息等级到warning (log-level=1)'),
|
||||
new InputOption('log-error', null, null, '调整消息等级到error (log-level=0)'),
|
||||
new InputOption('log-theme', null, InputOption::VALUE_REQUIRED, '改变终端的主题配色'),
|
||||
new InputOption('disable-console-input', null, null, '禁止终端输入内容 (废弃)'),
|
||||
new InputOption('interact', null, null, '打开终端输入'),
|
||||
new InputOption('remote-terminal', null, null, '启用远程终端,配置使用global.php中的'),
|
||||
new InputOption('disable-coroutine', null, null, '关闭协程Hook'),
|
||||
new InputOption('daemon', null, null, '以守护进程的方式运行框架'),
|
||||
new InputOption('worker-num', null, InputOption::VALUE_REQUIRED, '启动框架时运行的 Worker 进程数量'),
|
||||
new InputOption('task-worker-num', null, InputOption::VALUE_REQUIRED, '启动框架时运行的 TaskWorker 进程数量'),
|
||||
new InputOption('watch', null, null, '监听 src/ 目录的文件变化并热更新'),
|
||||
new InputOption('show-php-ver', null, null, '启动时显示PHP和Swoole版本'),
|
||||
new InputOption('env', null, InputOption::VALUE_REQUIRED, '设置环境类型 (production, development, staging)'),
|
||||
new InputOption('disable-safe-exit', null, null, '关闭安全退出(关闭后按CtrlC时直接杀死进程)'),
|
||||
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('直接运行可以启动');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (($opt = $input->getOption('env')) !== null) {
|
||||
if (!in_array($opt, ['production', 'staging', 'development', ''])) {
|
||||
$output->writeln('<error> "--env" option only accept production, development, staging and [empty] ! </error>');
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
$pid_path = DataProvider::getWorkingDir() . "/.daemon_pid";
|
||||
if (file_exists($pid_path)) {
|
||||
$pid = json_decode(file_get_contents($pid_path), true)["pid"] ?? null;
|
||||
if ($pid !== null && posix_getsid($pid) !== false) {
|
||||
$output->writeln("<error>检测到已经在 pid: $pid 进程启动了框架!</error>");
|
||||
$output->writeln("<error>不可以同时启动两个框架!</error>");
|
||||
$state = Framework::getProcessState(ZM_PROCESS_MASTER);
|
||||
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;
|
||||
} else {
|
||||
unlink($pid_path);
|
||||
}
|
||||
}
|
||||
(new Framework($input->getOptions()))->start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function exportDefinition() {
|
||||
$cmd = new self();
|
||||
$cmd->configure();
|
||||
return $cmd->getDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Server;
|
||||
|
||||
@@ -12,14 +13,16 @@ class ServerReloadCommand extends DaemonCommand
|
||||
{
|
||||
protected static $defaultName = 'server:reload';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("重载框架");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('重载框架');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
parent::execute($input, $output);
|
||||
Process::kill(intval($this->daemon_file["pid"]), SIGUSR1);
|
||||
$output->writeln("<info>成功重载!</info>");
|
||||
Process::kill(intval($this->daemon_file['pid']), SIGUSR1);
|
||||
$output->writeln('<info>成功重载!</info>');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ZM\Command\Server;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -10,25 +12,25 @@ class ServerStatusCommand extends DaemonCommand
|
||||
{
|
||||
protected static $defaultName = 'server:status';
|
||||
|
||||
protected function configure() {
|
||||
$this->setDescription("查看框架的运行状态");
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('查看框架的运行状态');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
parent::execute($input, $output);
|
||||
$output->writeln("<info>框架" . ($this->daemon_file["daemon"] ? "以守护进程模式" : "") . "运行中,pid:" . $this->daemon_file["pid"] . "</info>");
|
||||
if ($this->daemon_file["daemon"]) {
|
||||
$output->writeln("<comment>----- 以下是stdout内容 -----</comment>");
|
||||
$stdout = file_get_contents($this->daemon_file["stdout"]);
|
||||
$output->writeln('<info>框架' . ($this->daemon_file['daemon'] ? '以守护进程模式' : '') . '运行中,pid:' . $this->daemon_file['pid'] . '</info>');
|
||||
if ($this->daemon_file['daemon']) {
|
||||
$output->writeln('<comment>----- 以下是stdout内容 -----</comment>');
|
||||
$stdout = file_get_contents($this->daemon_file['stdout']);
|
||||
$stdout = explode("\n", $stdout);
|
||||
for ($i = 15; $i > 0; --$i) {
|
||||
if (isset($stdout[count($stdout) - $i]))
|
||||
if (isset($stdout[count($stdout) - $i])) {
|
||||
echo $stdout[count($stdout) - $i] . PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user