Compare commits

...

108 Commits
2.6.3 ... 2.7.5

Author SHA1 Message Date
Jerry Ma
c1ae1dee06 Merge pull request #81 from zhamao-robot/add-auto-api-docs-generator
添加 API 文档生成器
2022-03-27 21:52:15 +08:00
Jerry Ma
c4aedf2958 Add gendoc to composer 2022-03-27 21:51:38 +08:00
Github Build Bot
736c8f2fc0 increment build number 2022-03-27 13:44:26 +00:00
Jerry Ma
294084299e Merge pull request #82 from zhamao-robot/bugfix/not-response
再次修复无法处理消息的 Bug
2022-03-27 21:44:10 +08:00
crazywhalecc
b1d30da4bc Re-fix the last no-message-response bug 2022-03-27 21:34:49 +08:00
sunxyw
506f2e7c0c add api docs generator 2022-03-27 19:19:05 +08:00
sunxyw
e13660dcdc add nav for api docs 2022-03-27 16:51:28 +08:00
sunxyw
4fbe2aa5af add api docs (#80) 2022-03-27 16:42:36 +08:00
crazywhalecc
5ddc514545 update docs 2022-03-27 01:27:50 +08:00
sunxyw
3cfcbaec16 fix mb_strpos empty delimiter 2022-03-27 01:16:44 +08:00
sunxyw
50f06e6a4f add middleware params docs (#78) 2022-03-26 22:46:24 +08:00
Github Build Bot
c7e2b15629 increment build number 2022-03-26 07:44:43 +00:00
Jerry Ma
8e81f72584 Merge pull request #76 from zhamao-robot/feature/cron
新增 Cron 注解及修复部分 Bug
2022-03-26 15:44:29 +08:00
crazywhalecc
0fb5ed00f6 update docs 2022-03-26 14:59:13 +08:00
crazywhalecc
bf7920cc15 Add Cron annotation event 2022-03-26 14:51:57 +08:00
crazywhalecc
971f03ae0f Fix type convert error 2022-03-26 14:51:25 +08:00
Jerry Ma
24b9d93920 Merge pull request #75 from zhamao-robot/add-auto-build-number-workflow
添加构建工作流以自增构建编号
2022-03-26 01:49:43 +08:00
sunxyw
8d81f4d5df add build workflow to increment build number 2022-03-25 23:40:41 +08:00
Jerry Ma
b6e135a642 Merge pull request #74 from zhamao-robot/fix-onsetup-attribute-exec
Fix OnSetup Attribute execution bug (release 2.7.3)
2022-03-25 19:21:07 +08:00
crazywhalecc
d3f4ade215 Add Attribute and property (build 453, release 2.7.3) 2022-03-25 19:15:58 +08:00
crazywhalecc
56d2a52706 Fix OnSetup Attribute execution bug (build 452, release 2.7.3) 2022-03-25 19:02:43 +08:00
Jerry Ma
b40dc1e05e Merge pull request #71 from zhamao-robot/add-help-generator-docs
增加命令帮助生成器文档
2022-03-24 16:54:50 +08:00
Jerry Ma
bed3337866 Merge pull request #73 from zhamao-robot/integration-test-ignore-docs
修改集成测试配置以忽略文档变更
2022-03-24 16:40:48 +08:00
sunxyw
28dc73d060 Update integration-test.yml 2022-03-24 15:36:36 +08:00
sunxyw
5ea1226ad0 add help generator docs 2022-03-23 20:03:47 +08:00
sunxyw
e43f2a4158 update readme about php8 attribute (#70)
* update readme

* add docs about php8 attribute
2022-03-23 19:45:07 +08:00
sunxyw
d73e771ef3 fix help generator not working with alias (#69) 2022-03-23 19:44:16 +08:00
crazywhalecc
c077e9418c revert changes 2022-03-22 12:01:21 +08:00
crazywhalecc
2ce888c84c add robots.txt 2022-03-22 12:00:37 +08:00
crazywhalecc
b4d175ff98 fix docs problem 2022-03-22 11:52:12 +08:00
crazywhalecc
35e18d0481 add some irrelevant docs to expand white border 2022-03-22 01:26:53 +08:00
Jerry Ma
f6cccb00e3 Merge pull request #68 from zhamao-robot/document-upgrade
将文档重新部署和重构为 VuePress
2022-03-22 01:00:43 +08:00
Jerry Ma
2a82c82039 update to build 451
重构全局函数,统一函数命名,并补全注释
2022-03-22 01:00:20 +08:00
Jerry Ma
a2e8a1b582 update to build 451 2022-03-22 00:55:34 +08:00
crazywhalecc
dbd78d4b86 change ALL docs from MkDocs to VuePress!! 2022-03-22 00:51:03 +08:00
sunxyw
8105892b6e fix review 2022-03-21 23:28:57 +08:00
sunxyw
bc7d5871e4 replace deprecated functions 2022-03-21 20:49:09 +08:00
sunxyw
680e6a8c5f refactor global functions 2022-03-21 20:09:28 +08:00
Jerry Ma
c364084cb2 add command help generator (build 450)
增加命令帮助生成器 by @sunxyw
2022-03-21 14:13:56 +08:00
Jerry Ma
63f8042746 update to build 450 2022-03-21 12:52:48 +08:00
Jerry Ma
48e6b2cea0 update README.md [skip ci] 2022-03-21 05:04:37 +08:00
sunxyw
228309c571 fix cs 2022-03-21 04:46:54 +08:00
sunxyw
ca3a3df3ba add command help generator 2022-03-21 04:43:27 +08:00
crazywhalecc
c7df37b17c update install-runtime.sh 2022-03-21 02:58:59 +08:00
crazywhalecc
41f03fbba4 update docs 2022-03-21 01:25:26 +08:00
crazywhalecc
b3089c1bba add composer module support (build 449, 2.7.2) 2022-03-21 01:24:07 +08:00
crazywhalecc
c5a6f1fea4 update docs 2022-03-20 23:28:20 +08:00
crazywhalecc
ba2777137b let build command faster (build 448, 2.7.1) 2022-03-20 23:26:42 +08:00
crazywhalecc
6d90be164a update docs 2022-03-20 22:16:34 +08:00
crazywhalecc
4da6f5859a update to 2.7.0 release (build 447) 2022-03-20 22:12:58 +08:00
crazywhalecc
15d4ea710a add --no-state-check option (build 446) 2022-03-20 21:04:07 +08:00
crazywhalecc
f0541c1f32 Merge remote-tracking branch 'origin/master' 2022-03-20 19:05:54 +08:00
crazywhalecc
2b8cab1824 add AnnotationReader ignore name config (build 445, 2.7.0-beta5) 2022-03-20 19:05:13 +08:00
Jerry Ma
61c7972915 Update README.md 2022-03-20 17:09:24 +08:00
crazywhalecc
44a0eec74c change to integration-test 2022-03-20 17:00:37 +08:00
crazywhalecc
e57753e44b change to integration-test 2022-03-20 16:58:53 +08:00
crazywhalecc
74e91a2950 fix unpack autoload not working, change exclude_annotate to another name (build 444) 2022-03-20 16:51:48 +08:00
crazywhalecc
7ce3ef41df fix comment spacing problem (build 443) 2022-03-20 16:23:07 +08:00
crazywhalecc
444a77933a change autoload to hotload for phar hotload mode (build 442) 2022-03-20 16:20:14 +08:00
crazywhalecc
78f78c607d add packer namespace adjust (build 441) 2022-03-20 16:18:33 +08:00
crazywhalecc
69155002dc add site to gitignore 2022-03-20 16:13:51 +08:00
crazywhalecc
475d14fab7 update composer.json 2022-03-20 16:13:33 +08:00
crazywhalecc
f4d7e63358 update php cs fixer 2022-03-20 15:48:14 +08:00
crazywhalecc
f222d2b45b update composer requirement version 2022-03-20 15:43:31 +08:00
Jerry Ma
d0155fe1da Create code-style-analysis.yml 2022-03-20 15:35:10 +08:00
Jerry Ma
4737d0b507 Update and rename main.yml to mkdocs-deploy.yml 2022-03-20 15:23:05 +08:00
Jerry Ma
09bd0197bb Merge pull request #64 from sunxyw/patch-1
docs: add weather bot example
2022-03-20 15:20:59 +08:00
crazywhalecc
f0f120bd32 add Macroable (build 440) 2022-03-20 01:54:14 +08:00
crazywhalecc
c897da29c6 add PHP8 Attribute compatibility (build 439, 2.7.0-beta4) 2022-03-20 01:53:36 +08:00
sunxyw
e347e254e8 update docs index 2022-03-20 00:11:45 +08:00
crazywhalecc
12363aebf0 Merge remote-tracking branch 'origin/master' 2022-03-19 23:23:54 +08:00
crazywhalecc
ff0b925313 update docs 2022-03-19 23:23:14 +08:00
sunxyw
a6b4bd9b80 update weather bot example 2022-03-19 21:35:48 +08:00
sunxyw
485fa5476c add weather bot example 2022-03-19 21:25:10 +08:00
Jerry Ma
689076d97c Update mkdocs.yml 2022-03-19 20:33:13 +08:00
Jerry Ma
cca6102e91 Update README.md 2022-03-18 16:57:27 +08:00
Jerry Ma
095855162b Update mkdocs.yml 2022-03-18 16:48:30 +08:00
Jerry Ma
326f934013 Update mkdocs.yml 2022-03-18 16:44:04 +08:00
Jerry Ma
35b0c258fe Merge pull request #63 from sunxyw/patch-2
docs: add qingyunke chatbot integration example
2022-03-18 16:01:15 +08:00
sunxyw
6650846b15 update integrate-qingyunke-chatbot.md 2022-03-18 15:19:19 +08:00
sunxyw
a33d320f4c update integrate-qingyunke-chatbot.md 2022-03-18 02:54:23 +08:00
sunxyw
0bcfea6aa4 add qingyunke chatbot integration example 2022-03-18 02:30:45 +08:00
crazywhalecc
db6e63e91c fix Response class null error (build 438) 2022-03-17 20:48:09 +08:00
crazywhalecc
a7f84fb53a Merge remote-tracking branch 'origin/master' 2022-03-17 19:48:38 +08:00
crazywhalecc
ce7f2b1765 change ctx return force to ContextInterface (build 437) 2022-03-17 19:42:59 +08:00
Jerry Ma
abbfb59eff Merge pull request #62 from sunxyw/patch-2
docs: add missing module version example
2022-03-17 18:19:02 +08:00
sunxyw
b57fef16f9 add missing module version example 2022-03-17 01:53:06 +08:00
crazywhalecc
1706afbcd0 add cs fixer and PHPStan and activate it (build 436) 2022-03-15 18:05:33 +08:00
crazywhalecc
d01bd69aa5 update to 2.7.0-beta1 (build 435) 2022-03-13 22:50:32 +08:00
crazywhalecc
e6b9ae3ee1 add --watch function for no-installed-inotify users 2022-03-13 22:50:01 +08:00
crazywhalecc
73b6b8045d enhancement for process state 2022-03-13 22:47:11 +08:00
crazywhalecc
3c87abc6e8 enhancement for process state 2022-03-13 22:46:22 +08:00
crazywhalecc
e95925c129 add compatibility for PHP 8.1 2022-03-13 22:16:02 +08:00
crazywhalecc
82c44d6c40 enhancement for process state 2022-03-13 22:15:27 +08:00
crazywhalecc
e0a268e05e add autoload-dev auto scanner 2022-03-13 22:11:30 +08:00
crazywhalecc
487892e1d9 add force kill framework command --force 2022-03-13 22:05:53 +08:00
crazywhalecc
7ab4e88359 add KILLER PROMPT function 2022-03-13 22:05:23 +08:00
crazywhalecc
4702b6ee75 separate ProcessManager and WorkerManager 2022-03-13 22:04:52 +08:00
crazywhalecc
20cd3aa66d update docs 2022-03-13 22:03:52 +08:00
crazywhalecc
391114bdef update docs 2022-03-13 21:57:41 +08:00
crazywhalecc
ffe1052ecc add gitignore items 2022-03-13 21:54:43 +08:00
crazywhalecc
b4159152a7 add watcher 2022-01-08 20:19:10 +08:00
crazywhalecc
8fc6e4b0f7 update docs 2022-01-08 16:26:47 +08:00
crazywhalecc
c8938b7a4b update docs 2022-01-08 16:23:10 +08:00
crazywhalecc
34db1626a5 update to 2.6.6 (build 434) 2022-01-08 16:19:43 +08:00
crazywhalecc
7f0c97c5b9 update to 2.6.5 (build 433) 2021-12-28 22:40:40 +08:00
crazywhalecc
74050c46e7 update to 2.6.4 (build 432) 2021-12-25 19:21:41 +08:00
3ed1cb665a update to build 431 2021-12-22 14:39:46 +08:00
414 changed files with 15613 additions and 5363 deletions

30
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Build
on:
pull_request:
branches:
- master
types:
- closed
paths:
- 'src/**.php'
jobs:
incremental-build-number:
if: github.event.pull_request.merged == true
name: Incremental Build Number
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Increment build number
run: sed -i -r 's/(.*)(\VERSION_ID\s=\s)([0-9]+)(.*)/echo "\1\2$((\3+1))\4"/ge' src/ZM/ConsoleApplication.php
- name: Commit change
run: |
git config --global user.name 'Github Build Bot'
git config --global user.email 'noreply@github.com'
git add src/ZM/ConsoleApplication.php
git commit -m "increment build number"
git push

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

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

View File

@@ -1,4 +1,4 @@
name: Docs Build name: VuePress Auto Deploy
on: on:
push: push:
branches: branches:
@@ -13,15 +13,14 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Deploy docs to GitHub Pages - name: Deploy docs to GitHub Pages
uses: mhausenblas/mkdocs-deploy-gh-pages@master uses: jenkey2011/vuepress-deploy@master
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CUSTOM_DOMAIN: framework.zhamao.me BUILD_SCRIPT: yarn && yarn docs:build
CONFIG_FILE: mkdocs.yml BUILD_DIR: docs/.vuepress/dist/
EXTRA_PACKAGES: build-base
- name: Copy deployment to current folder - name: Copy deployment to current folder
run: | run: |
cp -r "${GITHUB_WORKSPACE}/site" "./deploy" cp -r "${GITHUB_WORKSPACE}/docs/.vuepress/dist" "./deploy"
- name: Deploy to Zhamao Server - name: Deploy to Zhamao Server
uses: easingthemes/ssh-deploy@main uses: easingthemes/ssh-deploy@main
env: env:

14
.gitignore vendored
View File

@@ -12,9 +12,23 @@ composer.lock
.daemon_pid .daemon_pid
/runtime/ /runtime/
/tmp/ /tmp/
/temp/
/site/
# go-cqhttp快速安装启动相关可能被废弃
/ext/go-cqhttp/data/ /ext/go-cqhttp/data/
/ext/go-cqhttp/logs/ /ext/go-cqhttp/logs/
/ext/go-cqhttp/config.hjson /ext/go-cqhttp/config.hjson
/ext/go-cqhttp/device.json /ext/go-cqhttp/device.json
/ext/go-cqhttp/go-cqhttp /ext/go-cqhttp/go-cqhttp
/ext/go-cqhttp/session.token /ext/go-cqhttp/session.token
.zm_worker_*.pid
# Git Hook 的相关锁文件
cghooks.lock
# Vuepress 相关文件
/node_modules/
/docs/.vuepress/dist/
package-lock.json

75
.php-cs-fixer.php Normal file
View 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);

View 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 &amp;&amp; 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>

View 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
View 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>

View 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 &amp;&amp; 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>

View File

@@ -7,7 +7,7 @@
[![zhamao License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/zhamao-robot/zhamao-framework/blob/master/LICENSE) [![zhamao License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/zhamao-robot/zhamao-framework/blob/master/LICENSE)
[![Latest Stable Version](http://img.shields.io/packagist/v/zhamao/framework.svg)](https://packagist.org/packages/zhamao/framework) [![Latest Stable Version](http://img.shields.io/packagist/v/zhamao/framework.svg)](https://packagist.org/packages/zhamao/framework)
[![Banner](https://img.shields.io/badge/OneBot-v11-success)](https://github.com/howmanybots/onebot) [![Banner](https://img.shields.io/badge/OneBot-v11-success)](https://github.com/howmanybots/onebot)
![Build Actions](https://github.com/zhamao-robot/zhamao-framework/actions/workflows/main.yml/badge.svg) ![Integration Test](https://github.com/zhamao-robot/zhamao-framework/actions/workflows/integration-test.yml/badge.svg)
[![注解数量](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/AnnotationBase.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=AnnotationBase) [![注解数量](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/AnnotationBase.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=AnnotationBase)
[![TODO 数量](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/TODO.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=TODO) [![TODO 数量](https://img.shields.io/github/search/zhamao-robot/zhamao-framework/TODO.svg)](https://github.com/zhamao-robot/zhamao-framework/search?q=TODO)
@@ -16,12 +16,14 @@
开发者 QQ 群:**670821194** [点击加入群聊](https://jq.qq.com/?_wv=1027&k=YkNI3AIr) 开发者 QQ 群:**670821194** [点击加入群聊](https://jq.qq.com/?_wv=1027&k=YkNI3AIr)
**如果有愿意一起开发框架本身的开发者,请提出 PR 或 Issue 参与开发!如果对框架本身的核心设计有更好的想法,可与作者成立开发组(目前仅作者 1 人),参与 OneBot V12 生态和框架本身的开发。** **如果有愿意一起开发框架本身的开发者,请提出 PR 或 Issue 参与开发!如果对框架本身的核心设计有更好的想法,可与作者成立开发组(目前仅 2 人),参与 OneBot V12 生态和框架本身的开发。**
**相关正在进行的版本任务见 Projects 一栏!** **相关正在进行的版本任务见 Projects 一栏!**
## 简介 ## 简介
炸毛框架使用 PHP 编写,采用 Swoole 扩展为基础,主要面向 API 服务聊天机器人OneBot 兼容的 QQ 机器人对接),包含 Websocket、HTTP 等监听和请求库,用户代码采用模块化处理,使用注解可以方便地编写各类功能。
炸毛框架使用 PHP 编写,采用 Swoole 扩展为基础,主要面向 API 服务聊天机器人OneBot 兼容的 QQ 机器人对接),包含 Websocket、HTTP
等监听和请求库,用户代码采用模块化处理,使用注解可以方便地编写各类功能。
框架主要用途为 HTTP 服务器,机器人搭建框架。尤其对于 QQ 机器人消息处理较为方便和全面,提供了众多会话机制和内部调用机制,可以以各种方式设计你自己的模块。 框架主要用途为 HTTP 服务器,机器人搭建框架。尤其对于 QQ 机器人消息处理较为方便和全面,提供了众多会话机制和内部调用机制,可以以各种方式设计你自己的模块。
@@ -40,48 +42,54 @@ public function index() {
} }
``` ```
> 从 2.7.0 版本开始,框架已支持同时使用 Annotation 和原生 Attribute 注解,供开发者根据需要自由选用。
## 开始 ## 开始
如果你是初学者,可以直接使用以下脚本部署 PHP 环境和安装框架的脚手架: 如果你是初学者,可以直接使用以下脚本部署 PHP 环境和安装框架的脚手架:
```bash ```bash
# 新建一个自己喜欢名字的文件夹,运行一键安装脚本 (仅限 x86_64 和 aarch64 平台) # 新建一个自己喜欢名字的文件夹,运行一键安装脚本 (仅限 x86-64(AMD64)AArch64(ARM64) 平台)
mkdir zhamao-app/ mkdir zhamao-app/
cd zhamao-app/ cd zhamao-app/
# 默认安装的 PHP 版本为 7.4,如需使用其他版本,请设置环境变量 ZM_DOWN_PHP_VERSION 为对应的 PHP 版本,例如:
# export ZM_DOWN_PHP_VERSION=8.1
bash -c "$(curl -fsSL https://api.zhamao.xin/go.sh)" bash -c "$(curl -fsSL https://api.zhamao.xin/go.sh)"
# 启动 # 启动
vendor/bin/start server ./zhamao server:start
``` ```
## 文档v2 版本) 关于其他安装方式,请参阅[文档](https://framework.zhamao.xin/guide/installation.html) 。
## 文档
查看文档(国内自建):<https://framework.zhamao.xin/> 查看文档(国内自建):<https://framework.zhamao.xin/>
备用链接(国外托管):<https://framework.zhamao.me/> 备用链接(国外托管):<https://framework.zhamao.me/>
自行构建文档:`mkdocs build -d distribute`
## 特点 ## 特点
- 原生为多账号设计,支持多个机器人负载均衡
- 原生支持多个机器人客户端同时连接
- 使用 Swoole 多工作进程机制和协程加持,尽可能简单的情况下提升了性能 - 使用 Swoole 多工作进程机制和协程加持,尽可能简单的情况下提升了性能
- 灵活的注解事件绑定机制 - 灵活的注解事件绑定机制,可同时使用 Annotation 和原生 Attribute 注解
- 易用的上下文,模块内随处可用 - 易用的上下文,模块内随处可用
- 采用模块化编写,可自由搭配其他 composer 组件 - 采用模块化编写,可自由搭配其他 Composer 组件,也可单文件面向过程编写
- 支持模块打包、热加载,分享模块更方便
- 常驻内存,全局缓存变量随处使用,提供多种缓存方案 - 常驻内存,全局缓存变量随处使用,提供多种缓存方案
- 自带 MySQL、Redis 等数据库连接池等数据库连接方案 - 自带 MySQL、Redis 等数据库连接池等数据库连接方案
- 本身为 HTTP 服务器、WebSocket 服务器,可以构建属于自己的 HTTP API 接口 - 本身为 HTTP 服务器、WebSocket 服务器,可以构建属于自己的 HTTP API 接口
- 静态文件服务器,可将前端合并到一起 - 静态文件服务器,可将前端合并到一起
- 自带 PHP + Swoole 环境无需手动编译安装by [crazywhalecc/static-php-cli](https://github.com/crazywhalecc/static-php-cli) - 自带 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` 进行加速。
框架源码可直接克隆本仓库进行编辑,如果你在国内,访问 GitHub 和克隆仓库比较慢,可以将 `github.com` 替换为 `fgit.zhamao.me` 进行加速。
例如:`git clone https://fgit.zhamao.me/zhamao-robot/zhamao-framework.git --depth 1` 例如:`git clone https://fgit.zhamao.me/zhamao-robot/zhamao-framework.git --depth 1`
## 贡献和捐赠 ## 贡献和捐赠
如果你在使用过程中发现任何问题,可以提交 Issue 或自行 Fork 后修改并提交 Pull Request。 如果你在使用过程中发现任何问题,可以提交 Issue 或自行 Fork 后修改并提交 Pull Request。
目前项目仅一人维护,耗费精力较大,所以非常欢迎对框架的贡献。 目前项目仅一人维护,耗费精力较大,所以非常欢迎对框架的贡献。
@@ -90,17 +98,20 @@ vendor/bin/start server
我们会将捐赠的资金用于本项目驱动的炸毛机器人和框架文档的服务器开销上。[捐赠列表](https://github.com/zhamao-robot/thanks) 我们会将捐赠的资金用于本项目驱动的炸毛机器人和框架文档的服务器开销上。[捐赠列表](https://github.com/zhamao-robot/thanks)
如果您不想直接参与框架的开发,也可以分享你编写的模块,帮助完善框架生态。
### 支付宝 ### 支付宝
![支付宝二维码](https://cdn.jsdelivr.net/gh/zhamao-robot/zhamao-framework/resources/images/alipay_img.jpg) ![支付宝二维码](https://cdn.jsdelivr.net/gh/zhamao-robot/zhamao-framework/resources/images/alipay_img.jpg)
如果你对我们的周边感兴趣,我们还有炸毛机器人定制 logo 的雨伞,详情咨询作者 QQ我们会作为您捐助了本项目
## 关于 ## 关于
框架和 SDK 是 炸毛机器人 项目的核心框架开源部分。炸毛机器人是作者写的一个高性能机器人,曾获全国计算机设计大赛一等奖。 框架和 SDK 是 炸毛机器人 项目的核心框架开源部分。炸毛机器人是作者写的一个高性能机器人,曾获全国计算机设计大赛一等奖。
作者的炸毛机器人已从2018年初起稳定运行了**四年**,并且持续迭代。 作者的炸毛机器人已从2018年初起稳定运行了**四年**,并且持续迭代。
欢迎随时在 HTTP-API 插件群里提问,当然更好的话可以加作者 QQ[627577391](http://wpa.qq.com/msgrd?v=3&uin=627577391&site=qq&menu=yes)或提交 Issue 进行疑难解答。 欢迎随时在 HTTP-API 插件群里提问,当然更好的话可以加作者 QQ[627577391](http://wpa.qq.com/msgrd?v=3&uin=627577391&site=qq&menu=yes)
或提交 [Issue](https://github.com/zhamao-robot/zhamao-framework/issues/new/choose) 进行疑难解答。
本项目在更新内容时,请及时关注 GitHub 动态,更新前请将自己的模块代码做好备份。 本项目在更新内容时,请及时关注 GitHub 动态,更新前请将自己的模块代码做好备份。

396
bin/gendoc Executable file
View File

@@ -0,0 +1,396 @@
#!/usr/bin/env php
<?php
/**
* 决定是否忽略该类
*
* @param ReflectionClass $class 准备生成的类的反射类
* @return bool
*/
function should_ignore_class(ReflectionClass $class): bool
{
// 注解类
if (($doc = $class->getDocComment()) && strpos($doc, '@Annotation') !== false) {
return true;
}
if (str_ends_with($class->getName(), 'Exception')) {
return true;
}
if (str_contains($class->getName(), '_')) {
return true;
}
return false;
}
if (PHP_VERSION_ID < 70400) {
echo 'PHP 版本必须为 7.4 或以上';
exit(1);
}
function check_composer_executable(string $composer): bool
{
passthru($composer . ' --version 2>/dev/null', $exit_code);
return $exit_code === 0;
}
function find_valid_root(string $current_dir, int $max_loop): string
{
if ($max_loop <= 0) {
return '';
}
if (!file_exists($current_dir . '/composer.json')) {
return find_valid_root(dirname($current_dir), $max_loop - 1);
}
return $current_dir;
}
$root = find_valid_root(getcwd(), 3);
if (empty($root)) {
echo '找不到有效的根目录';
exit(1);
}
echo '根目录: ' . $root . PHP_EOL;
chdir($root);
if (!is_dir($root . '/src/ZM')) {
echo '源码目录不存在';
exit(1);
}
$phpdoc_package_temp_installed = false;
if (file_exists($root . '/vendor/jasny/phpdoc-parser/composer.json')) {
echo '正在使用现有的 PHPDoc 解析库' . PHP_EOL;
} else {
echo 'PHPDoc 解析库不存在,正在尝试安装...' . PHP_EOL;
echo '本次生成完成后将会自动移除' . PHP_EOL;
$composers = [
'runtime/composer', 'composer', 'php composer.phar',
];
foreach ($composers as $composer) {
if (check_composer_executable($composer)) {
echo '正在使用 ' . $composer . ' 安装 PHPDoc 解析库,请稍候...' . PHP_EOL;
passthru("$composer require --quiet jasny/phpdoc-parser", $exit_code);
if ($exit_code === 0) {
$phpdoc_package_temp_installed = true;
break;
}
}
}
if (!$phpdoc_package_temp_installed) {
echo '安装失败请手动安装composer require jasny/phpdoc-parser' . PHP_EOL;
exit(1);
}
}
// 从这里开始是主要生成逻辑
require_once $root . '/vendor/autoload.php';
use Jasny\PhpdocParser\PhpdocParser;
use Jasny\PhpdocParser\Set\PhpDocumentor;
use Jasny\PhpdocParser\Tag\Summery;
use ZM\Console\Console;
$opts = getopt('', ['show-warnings']);
if (array_key_exists('show-warnings', $opts)) {
$show_warnings = true;
} else {
$show_warnings = false;
}
Console::init(2);
$errors = [];
$warnings = [];
// 获取源码目录的文件遍历器
$fs = new \RecursiveDirectoryIterator($root . '/src/ZM', FilesystemIterator::SKIP_DOTS);
// 初始化文档解析器
$parser = new PhpdocParser(PhpDocumentor::tags()->with([
new Summery(),
]));
$metas = [];
$class_count = 0;
$method_count = 0;
function error(string $message)
{
global $errors;
$errors[] = $message;
Console::error($message);
}
function warning(string $message)
{
global $warnings, $show_warnings;
$warnings[] = $message;
if ($show_warnings) {
Console::warning($message);
}
}
/**
* 获取类的元数据
*
* 包括类的注释、方法的注释、参数、返回值等
*/
function get_class_metas(string $class_name, PhpdocParser $parser): array
{
// 尝试获取反射类
try {
$class = new \ReflectionClass($class_name);
} catch (\ReflectionException $e) {
error('无法获取类 ' . $class_name . ' 的反射类');
return [];
}
// 判断是否略过该类
if (should_ignore_class($class)) {
return [];
}
$metas = [];
// 遍历类方法
foreach ($class->getMethods() as $method) {
if ($method->getDeclaringClass()->getName() !== $class_name) {
continue;
}
Console::verbose('正在解析方法:' . $class_name . '::' . $method->getName());
// 获取方法的注释并解析
$doc = $method->getDocComment();
if (!$doc) {
warning('找不到文档:' . $class_name . '::' . $method->getName());
continue;
}
try {
$meta = $parser->parse($doc);
} catch (\Exception $e) {
error('解析失败:' . $class_name . '::' . $method->getName() . '' . $e->getMessage());
continue;
}
// 少数情况解析后会带有 */,需要去除
array_walk_recursive($meta, static function (&$item) {
if (is_string($item)) {
$item = trim(str_replace('*/', '', $item));
}
});
// 对比反射方法获取的参数和注释声明的参数
$parameters = $method->getParameters();
$params_in_doc = $meta['params'] ?? [];
foreach ($parameters as $parameter) {
$parameter_name = $parameter->getName();
// 不存在则添加进参数列表中
if (!isset($params_in_doc[$parameter_name])) {
$params_in_doc[$parameter_name] = [
'type' => $parameter->getType()?->getName(),
'description' => '',
];
}
}
// 确保所有参数都有对应的类型和描述
foreach ($params_in_doc as &$param) {
if (!isset($param['type'])) {
$param['type'] = 'mixed';
}
if (!isset($param['description'])) {
$param['description'] = '';
}
}
// 清除引用
unset($param);
$meta['params'] = $params_in_doc;
// 设定方法默认返回值
if (!isset($meta['return'])) {
$meta['return'] = [
'type' => $method->getReturnType()?->getName() ?: 'mixed',
'description' => '',
];
}
// 设定默认描述
if (!isset($meta['return']['description'])) {
$meta['return']['description'] = '';
}
$metas[$method->getName()] = $meta;
}
return $metas;
}
/**
* 将方法的元数据转换为 Markdown 格式
*
* @param string $method 方法名
* @param array $meta 元数据
*/
function convert_meta_to_markdown(string $method, array $meta): string
{
// 方法名作为标题
$markdown = '## ' . $method . "\n\n";
// 构造方法代码块
$markdown .= '```php' . "\n";
// TODO: 适配 private 等修饰符
$markdown .= 'public function ' . $method . '(';
$params = [];
// 添加参数
foreach ($meta['params'] as $param_name => $param_meta) {
$params[] = sprintf('%s $%s', $param_meta['type'] ?? 'mixed', $param_name);
}
$markdown .= implode(', ', $params) . ')';
// 添加返回值
$markdown .= ': ' . $meta['return']['type'];
$markdown .= "\n```\n\n";
// 方法描述
$markdown .= '### 描述' . "\n\n";
$markdown .= ($meta['description'] ?? '作者很懒,什么也没有说') . "\n\n";
// 参数
if (count($meta['params'])) {
$markdown .= '### 参数' . "\n\n";
$markdown .= '| 名称 | 类型 | 描述 |' . "\n";
$markdown .= '| -------- | ---- | ----------- |' . "\n";
foreach ($meta['params'] as $param_name => $param_meta) {
$markdown .= '| ' . $param_name . ' | ' . $param_meta['type'] . ' | ' . $param_meta['description'] . ' |' . "\n";
}
}
// 返回值
$markdown .= '### 返回' . "\n\n";
$markdown .= '| 类型 | 描述 |' . "\n";
$markdown .= '| ---- | ----------- |' . "\n";
$markdown .= '| ' . $meta['return']['type'] . ' | ' . $meta['return']['description'] . ' |' . "\n";
return $markdown;
}
function generate_sidebar_config(string $title, array $items): array
{
return [
'title' => $title,
'collapsable' => true,
'children' => $items,
];
}
Console::info('开始生成!');
// 遍历类并将元数据添加至数组中
foreach (new \RecursiveIteratorIterator($fs) as $file) {
if (!$file->isFile()) {
continue;
}
$path = $file->getPathname();
// 过滤不包含类的文件
$tokens = token_get_all(file_get_contents($path));
$found = false;
foreach ($tokens as $token) {
if (!is_array($token)) {
continue;
}
if ($token[0] === T_CLASS) {
$found = true;
}
}
if (!$found) {
continue;
}
// 获取完整类名
$path = ltrim($path, $root . '/');
$class = str_replace(['.php', 'src/', '/'], ['', '', '\\'], $path);
Console::verbose('正在解析类:' . $class);
$meta = get_class_metas($class, $parser);
// 忽略不包含任何方法的类
if (empty($meta)) {
continue;
}
$metas[$class] = $meta;
++$class_count;
$method_count += count($meta);
}
// 将元数据转换为 Markdown
$markdown = [];
foreach ($metas as $class => $class_metas) {
$markdown[$class] = [];
// 将类名作为页面大标题
$markdown[$class]['class'] = '# ' . $class;
foreach ($class_metas as $method => $meta) {
$markdown[$class][$method] = convert_meta_to_markdown($method, $meta);
}
}
// 生成文档
$docs = $root . '/docs/api/';
foreach ($markdown as $class => $methods) {
$file = $docs . str_replace('\\', '/', $class) . '.md';
// 确保目录存在
if (!file_exists(dirname($file)) && !mkdir($concurrent_directory = dirname($file), 0777, true) && !is_dir($concurrent_directory)) {
throw new \RuntimeException(sprintf('无法建立目录 %s', $concurrent_directory));
}
Console::verbose('正在生成文档:' . $file);
$text = implode("\n\n", $methods);
file_put_contents($file, $text);
}
// 生成文档目录
$children = array_keys($markdown);
$children = str_replace('\\', '/', $children);
$class_tree = [];
foreach ($children as $child) {
$parent = dirname($child);
$class_tree[$parent][] = $child;
}
ksort($class_tree);
$config = 'module.exports = [';
foreach ($class_tree as $parent => $children) {
$encode = json_encode(generate_sidebar_config($parent, $children));
$encode = str_replace('\/', '/', $encode);
$config .= $encode . ',';
}
$config = rtrim($config, ',');
$config .= ']';
$file = $root . '/docs/.vuepress/api.js';
file_put_contents($file, $config);
if (count($warnings)) {
Console::warning('生成过程中发现 ' . count($warnings) . ' 次警告');
if (!$show_warnings) {
Console::info('生成器默认忽略了警告,你可以通过 gendoc --show-warnings 来查看警告');
}
}
if (count($errors)) {
Console::error('生成过程中发现错误:');
foreach ($errors as $error) {
Console::error($error);
}
}
Console::success('API 文档生成完毕');
Console::success(sprintf('共生成 %d 个类,共 %d 个方法', $class_count, $method_count));
// 完成生成,进行善后
if ($phpdoc_package_temp_installed) {
echo '正在移除 PHPDoc 解析库,请稍候...' . PHP_EOL;
passthru('composer remove --quiet jasny/phpdoc-parser', $exit_code);
if ($exit_code !== 0) {
echo '移除失败请手动移除composer remove jasny/phpdoc-parser' . PHP_EOL;
}
echo '移除完成';
}
exit(0);

0
bin/start Normal file → Executable file
View File

118
bin/watcher Executable file
View 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

View File

@@ -4,9 +4,22 @@
"minimum-stability": "stable", "minimum-stability": "stable",
"license": "Apache-2.0", "license": "Apache-2.0",
"extra": { "extra": {
"exclude_annotate": [ "zm": {
"src/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": [ "authors": [
{ {
@@ -17,25 +30,27 @@
"prefer-stable": true, "prefer-stable": true,
"bin": [ "bin": [
"bin/start", "bin/start",
"bin/phpunit-swoole" "bin/phpunit-swoole",
"bin/gendoc"
], ],
"require": { "require": {
"php": ">=7.2", "php": "^7.2 || ^7.3 || ^7.4 || ^8.0 || ^8.1",
"ext-json": "*", "ext-json": "*",
"ext-posix": "*", "ext-posix": "*",
"doctrine/annotations": "~1.12 || ~1.4.0", "doctrine/dbal": "^2.13.1",
"dragonmantank/cron-expression": "^3.3",
"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-ctype": "^1.19",
"symfony/polyfill-mbstring": "^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", "symfony/routing": "~5.0 || ~4.0 || ~3.0",
"zhamao/console": "^1.0",
"zhamao/config": "^1.0", "zhamao/config": "^1.0",
"zhamao/request": "^1.1",
"zhamao/connection-manager": "^1.0", "zhamao/connection-manager": "^1.0",
"jelix/version": "^2.0", "zhamao/console": "^1.0",
"league/climate": "^3.6", "zhamao/request": "^1.1"
"psy/psysh": "@stable",
"doctrine/dbal": "^2.13.1"
}, },
"suggest": { "suggest": {
"ext-ctype": "Use C/C++ extension instead of polyfill will be more efficient", "ext-ctype": "Use C/C++ extension instead of polyfill will be more efficient",
@@ -52,8 +67,28 @@
"src/ZM/global_functions.php" "src/ZM/global_functions.php"
] ]
}, },
"autoload-dev": {
"psr-4": {
"Module\\": "src/Module",
"Custom\\": "src/Custom"
}
},
"config": {
"optimize-autoloader": true,
"sort-packages": true
},
"require-dev": { "require-dev": {
"swoole/ide-helper": "@dev", "brainmaestro/composer-git-hooks": "^2.8",
"phpunit/phpunit": "^8.5 || ^9.0" "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"
} }
} }

View File

@@ -1,65 +1,73 @@
<?php <?php
/** @noinspection PhpFullyQualifiedNameUsageInspection */
/** @noinspection PhpComposerExtensionStubsInspection */ /** @noinspection PhpComposerExtensionStubsInspection */
/** bind host */ declare(strict_types=1);
/* bind host */
$config['host'] = '0.0.0.0'; $config['host'] = '0.0.0.0';
/** bind port */ /* bind port */
$config['port'] = 20001; $config['port'] = 20001;
/** 框架开到公网或外部的HTTP访问链接通过 DataProvider::getFrameworkLink() 获取 */ /* 框架开到公网或外部的HTTP访问链接通过 DataProvider::getFrameworkLink() 获取 */
$config['http_reverse_link'] = 'http://127.0.0.1:' . $config['port']; $config['http_reverse_link'] = 'http://127.0.0.1:' . $config['port'];
/** 框架是否启动debug模式当debug模式为true时启用热更新需要安装inotify扩展 */ /* 框架是否启动debug模式当debug模式为true时启用热更新需要安装inotify扩展 */
$config['debug_mode'] = false; $config['debug_mode'] = false;
/** 存放框架内文件数据的目录 */ /* 存放框架内文件数据的目录 */
$config['zm_data'] = realpath(WORKING_DIR) . '/zm_data/'; $config['zm_data'] = realpath(WORKING_DIR) . '/zm_data/';
/** 存放各个模块配置文件的目录 */ /* 存放各个模块配置文件的目录 */
$config['config_dir'] = $config['zm_data'] . 'config/'; $config['config_dir'] = $config['zm_data'] . 'config/';
/** 存放崩溃和运行日志的目录 */ /* 存放崩溃和运行日志的目录 */
$config['crash_dir'] = $config['zm_data'] . 'crash/'; $config['crash_dir'] = $config['zm_data'] . 'crash/';
/** 对应swoole的server->set参数 */ /* 对应swoole的server->set参数 */
$config['swoole'] = [ $config['swoole'] = [
'log_file' => $config['crash_dir'] . 'swoole_error.log', 'log_file' => $config['crash_dir'] . 'swoole_error.log',
//'worker_num' => swoole_cpu_num(), //如果你只有一个 OneBot 实例连接到框架并且代码没有复杂的CPU密集计算则可把这里改为1使用全局变量 // 'worker_num' => swoole_cpu_num(), //如果你只有一个 OneBot 实例连接到框架并且代码没有复杂的CPU密集计算则可把这里改为1使用全局变量
'dispatch_mode' => 2, //包分配原则,见 https://wiki.swoole.com/#/server/setting?id=dispatch_mode 'dispatch_mode' => 2, // 包分配原则,见 https://wiki.swoole.com/#/server/setting?id=dispatch_mode
'max_coroutine' => 300000, 'max_coroutine' => 300000,
'max_wait_time' => 5 'max_wait_time' => 5,
//'task_worker_num' => 4, // 'task_worker_num' => 4,
//'task_enable_coroutine' => true // 'task_enable_coroutine' => true
]; ];
/* 一些框架与框架运行时设置的调整 */
/** 一些框架与框架运行时设置的调整 */
$config['runtime'] = [ $config['runtime'] = [
'swoole_coroutine_hook_flags' => SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL), 'swoole_coroutine_hook_flags' => SWOOLE_HOOK_ALL & (~SWOOLE_HOOK_CURL),
'swoole_server_mode' => SWOOLE_PROCESS, 'swoole_server_mode' => SWOOLE_PROCESS,
'middleware_error_policy' => 1, 'middleware_error_policy' => 1,
'reload_delay_time' => 800, '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'] = [ $config['light_cache'] = [
'size' => 512, //最多允许储存的条数需要2的倍数 'size' => 512, // 最多允许储存的条数需要2的倍数
'max_strlen' => 32768, //单行字符串最大长度需要2的倍数 'max_strlen' => 32768, // 单行字符串最大长度需要2的倍数
'hash_conflict_proportion' => 0.6, //Hash冲突率越大越好但是需要的内存更多 'hash_conflict_proportion' => 0.6, // Hash冲突率越大越好但是需要的内存更多
'persistence_path' => $config['zm_data'] . '_cache.json', 'persistence_path' => $config['zm_data'] . '_cache.json',
'auto_save_interval' => 900 'auto_save_interval' => 900,
]; ];
/** 大容量跨进程变量存储2.2.0可用) */ /* 大容量跨进程变量存储2.2.0可用) */
$config['worker_cache'] = [ $config['worker_cache'] = [
'worker' => 0, 'worker' => 0,
'transaction_timeout' => 30000 'transaction_timeout' => 30000,
]; ];
/** MySQL数据库连接信息host留空则启动时不创建sql连接池 */ /* MySQL数据库连接信息host留空则启动时不创建sql连接池 */
$config['mysql_config'] = [ $config['mysql_config'] = [
'host' => '', 'host' => '',
'port' => 3306, 'port' => 3306,
@@ -71,54 +79,54 @@ $config['mysql_config'] = [
'pool_size' => 64, 'pool_size' => 64,
'options' => [ 'options' => [
PDO::ATTR_STRINGIFY_FETCHES => false, 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'] = [ $config['redis_config'] = [
'host' => '', 'host' => '',
'port' => 6379, 'port' => 6379,
'timeout' => 1, 'timeout' => 1,
'db_index' => 0, 'db_index' => 0,
'auth' => '' 'auth' => '',
]; ];
/** onebot连接约定的token */ /* onebot连接约定的token */
$config['access_token'] = ''; $config['access_token'] = '';
/** HTTP服务器固定请求头的返回 */ /* HTTP服务器固定请求头的返回 */
$config['http_header'] = [ $config['http_header'] = [
'Server' => 'zhamao-framework', 'Server' => 'zhamao-framework',
'Content-Type' => 'text/html; charset=utf-8' 'Content-Type' => 'text/html; charset=utf-8',
]; ];
/** HTTP服务器在指定状态码下回复的页面默认 */ /* HTTP服务器在指定状态码下回复的页面默认 */
$config['http_default_code_page'] = [ $config['http_default_code_page'] = [
'404' => '404.html' '404' => '404.html',
]; ];
/** zhamao-framework在框架启动时初始化的atomic们 */ /* zhamao-framework在框架启动时初始化的atomic们 */
$config['init_atomics'] = [ $config['init_atomics'] = [
//'custom_atomic_name' => 0, //自定义添加的Atomic // 'custom_atomic_name' => 0, //自定义添加的Atomic
]; ];
/** 终端日志显示等级0-4 */ /* 终端日志显示等级0-4 */
$config['info_level'] = 2; $config['info_level'] = 2;
/** 上下文接口类 implemented from ContextInterface */ /* 上下文接口类 implemented from ContextInterface */
$config['context_class'] = \ZM\Context\Context::class; $config['context_class'] = \ZM\Context\Context::class;
/** 静态文件访问 */ /* 静态文件访问 */
$config['static_file_server'] = [ $config['static_file_server'] = [
'status' => false, 'status' => false,
'document_root' => realpath(__DIR__ . '/../') . '/resources/html', 'document_root' => realpath(__DIR__ . '/../') . '/resources/html',
'document_index' => [ 'document_index' => [
'index.html' 'index.html',
] ],
]; ];
/** 机器人解析模块关闭后无法使用如CQCommand等注解(上面的modules即将废弃) */ /* 机器人解析模块关闭后无法使用如CQCommand等注解(上面的modules即将废弃) */
$config['onebot'] = [ $config['onebot'] = [
'status' => true, 'status' => true,
'single_bot_mode' => false, 'single_bot_mode' => false,
@@ -127,18 +135,18 @@ $config['onebot'] = [
'message_command_policy' => 'interrupt', 'message_command_policy' => 'interrupt',
]; ];
/** 一个远程简易终端使用nc直接连接即可但是不建议开放host为0.0.0.0(远程连接) */ /* 一个远程简易终端使用nc直接连接即可但是不建议开放host为0.0.0.0(远程连接) */
$config['remote_terminal'] = [ $config['remote_terminal'] = [
'status' => false, 'status' => false,
'host' => '127.0.0.1', 'host' => '127.0.0.1',
'port' => 20002, 'port' => 20002,
'token' => '' 'token' => '',
]; ];
/** 模块(插件)加载器的相关设置 */ /* 模块(插件)加载器的相关设置 */
$config['module_loader'] = [ $config['module_loader'] = [
'enable_hotload' => false, 'enable_hotload' => false,
'load_path' => $config['zm_data'] . 'modules' 'load_path' => $config['zm_data'] . 'modules',
]; ];
return $config; return $config;

1
docs/.vuepress/api.js Normal file
View File

@@ -0,0 +1 @@
module.exports = [{"title":"ZM","collapsable":true,"children":["ZM/ZMServer","ZM/ConsoleApplication","ZM/Framework"]},{"title":"ZM/API","collapsable":true,"children":["ZM/API/CQ","ZM/API/OneBotV11","ZM/API/TuringAPI","ZM/API/GoCqhttpAPIV11"]},{"title":"ZM/Annotation","collapsable":true,"children":["ZM/Annotation/AnnotationParser"]},{"title":"ZM/Annotation/Swoole","collapsable":true,"children":["ZM/Annotation/Swoole/OnSwooleEventBase"]},{"title":"ZM/Command","collapsable":true,"children":["ZM/Command/CheckConfigCommand"]},{"title":"ZM/Command/Generate","collapsable":true,"children":["ZM/Command/Generate/APIDocsGenerateCommand"]},{"title":"ZM/Context","collapsable":true,"children":["ZM/Context/Context"]},{"title":"ZM/DB","collapsable":true,"children":["ZM/DB/Table","ZM/DB/DeleteBody","ZM/DB/UpdateBody","ZM/DB/DB","ZM/DB/SelectBody","ZM/DB/InsertBody"]},{"title":"ZM/Event","collapsable":true,"children":["ZM/Event/EventManager","ZM/Event/EventTracer","ZM/Event/EventDispatcher"]},{"title":"ZM/Event/SwooleEvent","collapsable":true,"children":["ZM/Event/SwooleEvent/OnWorkerStart","ZM/Event/SwooleEvent/OnTask"]},{"title":"ZM/Http","collapsable":true,"children":["ZM/Http/Response"]},{"title":"ZM/Module","collapsable":true,"children":["ZM/Module/ModuleUnpacker","ZM/Module/ModulePacker","ZM/Module/ModuleBase","ZM/Module/QQBot"]},{"title":"ZM/MySQL","collapsable":true,"children":["ZM/MySQL/MySQLStatementWrapper","ZM/MySQL/MySQLQueryBuilder","ZM/MySQL/MySQLWrapper","ZM/MySQL/MySQLPool"]},{"title":"ZM/Store","collapsable":true,"children":["ZM/Store/LightCache","ZM/Store/ZMAtomic","ZM/Store/LightCacheInside"]},{"title":"ZM/Store/Redis","collapsable":true,"children":["ZM/Store/Redis/ZMRedis"]},{"title":"ZM/Utils","collapsable":true,"children":["ZM/Utils/Terminal","ZM/Utils/MessageUtil","ZM/Utils/DataProvider","ZM/Utils/SignalListener","ZM/Utils/ZMUtil","ZM/Utils/HttpUtil","ZM/Utils/CoMessage"]},{"title":"ZM/Utils/Manager","collapsable":true,"children":["ZM/Utils/Manager/CronManager","ZM/Utils/Manager/ModuleManager","ZM/Utils/Manager/WorkerManager"]}]

View File

@@ -0,0 +1,141 @@
<template>
<div class="doc-chat-container">
<div class="doc-chat-content">
<div v-for="i in chat" v-bind="i">
<div class="doc-chat-row" v-if="i.type === 0">
<div class="doc-chat-box">{{ i.content }}</div>
<img class="doc-chat-avatar" src="http://api.btstu.cn/sjtx/api.php" alt=""/>
</div>
<div class="doc-chat-row doc-chat-row-robot" v-else-if="i.type === 1">
<img class="doc-chat-avatar" src="https://docs-v1.zhamao.xin/logo.png" alt=""/>
<div class="doc-chat-box doc-chat-box-robot">
<span v-for="(p,index) in i.content.split('\n')">{{p}}<br v-if="index !== i.content.length - 1"></span>
</div>
</div>
<div class="doc-chat-row doc-chat-banner" v-else-if="i.type === 2">
{{ i.content }}
</div>
<div class="doc-chat-row doc-chat-row-robot" v-else-if="i.type === 3">
<img class="doc-chat-avatar" src="https://docs-v1.zhamao.xin/logo.png" alt=""/>
<div class="doc-chat-box doc-chat-box-robot">
<img :src="i.content" alt="" />
</div>
</div>
</div>
</div>
</div>
</template>
<!--
type:
0: 我方发送消息
1: 机器人回复消息
2: 显示一个横幅系统消息
3: 机器人回复一个图片
-->
<script>
export default {
name: "ChatBox",
props: ['myChats'],
data() {
return {
chat: this.myChats,
multiline: ''
}
}
}
</script>
<style scoped>
.doc-chat-content {
padding: 12px;
}
.doc-chat-container {
border-radius: 6px;
max-width: 550px;
min-height: 30px;
/*noinspection CssUnresolvedCustomProperty*/
background-color: #f2f4f5;
margin-bottom: 1em;
box-shadow: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
}
.doc-chat-row {
margin: 0;
display: flex;
flex-wrap: wrap;
flex: 1 1 auto;
justify-content: flex-end;
}
.doc-chat-banner {
justify-content: center;
background: rgba(0,0,0,0.1);
width: max-content;
margin: 8px auto;
padding: 4px 14px;
border-radius: 8px;
color: gray;
font-size: 14px;
}
.doc-chat-row-robot {
justify-content: flex-start !important;
}
.doc-chat-box {
color: #000000de;
position: relative;
width: fit-content;
max-width: 55%;
border-radius: .5rem;
padding: .4rem .6rem;
margin: .4rem .8rem;
background-color: #fff;
line-height: 1.5;
font-size: 16px;
outline: none;
overflow-wrap: break-word;
white-space: normal;
box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
}
.doc-chat-box:after {
content: "";
position: absolute;
right: auto;
top: 0;
width: 8px;
height: 12px;
color: #fff;
border: 0 solid transparent;
border-bottom: 7px solid;
border-radius: 0 0 8px 0;
left: calc(100% - 4px);
box-sizing: inherit;
}
.doc-chat-box-robot:after {
content: "";
position: absolute;
right: calc(100% - 4px);
top: 0;
width: 8px;
height: 12px;
color: #fff;
border: 0 solid transparent;
border-bottom: 7px solid;
border-radius: 0 0 0 8px;
left: auto;
box-sizing: inherit;
}
.doc-chat-avatar {
background-color: aquamarine;
width: 36px !important;
height: 36px !important;
border-radius: 18px;
}
</style>

192
docs/.vuepress/config.js Normal file
View File

@@ -0,0 +1,192 @@
const apiConfig = require('./api')
module.exports = {
title: '炸毛框架',
description: '一个聊天机器人 + Web 框架',
theme: 'antdocs',
markdown: {
lineNumbers: true
},
head: [
['link', { rel: 'icon', href: '/logo_trans.png' }],
['script', {}, `
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?f0f276cefa10aa31a20ae3815a50b795";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
`]
],
themeConfig: {
repo: 'zhamao-robot/zhamao-framework',
logo: '/logo_trans.png',
docsDir: 'docs',
editLinks: true,
lastUpdated: '上次更新',
activeHeaderLinks: false,
nav: [
{ text: '指南', link: '/guide/' },
{ text: '事件和注解', link: '/event/' },
{ text: '组件', link: '/component/' },
{ text: '进阶', link: '/advanced/' },
{ text: 'API', link: '/api/' },
{ text: 'FAQ', link: '/faq/' },
{ text: '更新日志', link: '/update/v2/' },
{ text: '炸毛框架 v1', link: 'https://docs-v1.zhamao.xin/' }
],
sidebar: {
'/guide/': [
{
title: '指南',
collapsable: false,
sidebarDepth: 1,
children: [
'',
'installation',
'quickstart-robot',
'quickstart-http',
'onebot-choose',
'basic-config',
'write-module',
'register-event',
'upgrade',
'errcode'
]
}
],
'/event/': [
{
title: '事件和注解',
collapsable: false,
sidebarDepth: 1,
children: [
'',
'robot-annotations',
'route-annotations',
'framework-annotations',
'middleware',
'custom-annotations',
'event-dispatcher'
]
}
],
'/component/': [
'',
{
title: '聊天机器人组件',
collapsable: true,
sidebarDepth: 2,
children: [
'bot/robot-api-12',
'bot/robot-api',
'bot/cqcode',
'bot/message-util',
'bot/access-token',
'bot/turing-api',
'bot/help-generator.md',
]
},
{
title: '存储组件',
collapsable: true,
sidebarDepth: 2,
children: [
'store/light-cache',
'store/mysql',
'store/mysql-db',
'store/redis',
'store/atomics',
'store/spin-lock',
'store/data-provider'
]
},
{
title: '通用组件',
collapsable: true,
sidebarDepth: 2,
children: [
'common/context',
'common/coroutine-pool',
'common/singleton-trait',
'common/zmutil',
'common/global-functions',
'common/console',
'common/task-worker',
'common/remote-terminal',
'common/event-tracer'
]
},
{
title: 'HTTP 组件',
collapsable: true,
sidebarDepth: 2,
children: [
'http/zmrequest',
'http/route-manager'
]
},
{
title: '模块/插件管理',
collapsable: true,
sidebarDepth: 2,
children: [
'module/module-pack',
'module/module-unpack'
]
}
],
'/advanced/': [
'',
{
title: '框架高级开发',
collapsable: true,
sidebarDepth: 2,
children: [
'framework-structure',
'custom-start',
'manually-install',
'inside-class',
'multi-process',
'task-worker'
]
},
{
title: '开发实战教程',
collapsable: true,
sidebarDepth: 2,
children: [
'connect-ws-client',
'example/admin',
'example/integrate-qingyunke-chatbot',
'example/weather-bot'
]
},
],
'/api/': apiConfig,
'/faq/': [
'',
'to-v2',
'usual-question',
'address-already-in-use',
'display-deadlock',
'light-cache-wrong',
'wait-message-cqbefore'
],
'/update/': [
{
title: '更新日志',
collapsable: true,
sidebarDepth: 0,
children: [
'v2',
'v1',
'build-update'
]
},
'config'
]
}
}
}

View File

@@ -0,0 +1 @@
framework.zhamao.me

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1 @@
User-agent: *

View File

@@ -0,0 +1 @@
@accentColor: #3665aa;

40
docs/README.md Normal file
View File

@@ -0,0 +1,40 @@
---
home: true
heroImage: ./logo_trans.png
actionBtn:
text: 快速上手
link: /guide/
type: primary
size: large
features:
- title: 高性能
details: 基于 PHP 的 Swoole 高性能扩展,利用 WebSocket 进行与 OneBot 协议兼容的聊天机器人软件的通信,还有数据库连接池、内存缓存、多任务进程等特色,大幅增强性能。
- title: 易于开发
details: 所有功能采用模块化设计,除特殊情况外几乎所有功能都不需要修改框架内任意代码,框架采用灵活的注解进行各类事件绑定,同时支持下断点调试。
- title: 接口直观
details: 支持命令、普通文本、正则匹配、自然语言处理等多种对话解析方式,利用协程巧妙实现了直观的交互式会话模式,同时支持多种富文本的处理。
footer: |
Apache-2.0 Licensed &nbsp;|&nbsp; Copyright © 2019-2022 Zhamao Developer Team &nbsp;|&nbsp; <a href="http://beian.miit.gov.cn">沪ICP备2021010446号-1</a>
---
# 快速上手
## 安装框架和环境
此命令可一键以模板安装 `zhamao-framework``PHP` 独立环境到目录下,无需 root仅限 Linux
```bash
mkdir my-app
cd my-app
bash -c "$(curl -fsSL https://api.zhamao.xin/go.sh)"
```
## 运行框架
```bash
./zhamao server
```
## 效果图
![index_demo](/index_demo.png)

4
docs/advanced/README.md Normal file
View File

@@ -0,0 +1,4 @@
# 进阶开发
在本章,下面的部分将详细说明一些具体的案例和自定义框架的操作。
> 更多进阶教程敬请期待....(或者你可以选择提 Issue 到框架 GitHub有需求就写入文档

View File

@@ -11,9 +11,11 @@
以上两种方式,`Header` 方式比 `GET` 方式优先级要高,如果两者均没有指定,框架会将此连接当作 `default` 类型接入。 以上两种方式,`Header` 方式比 `GET` 方式优先级要高,如果两者均没有指定,框架会将此连接当作 `default` 类型接入。
!!! note "提示" ::: tip 提示
对于对接 OneBot 标准的机器人客户端,只要符合 OneBot 标准,即 `X-Client-Role` 会自动带上 `universal``qq` 等字样,就会自动标记为 `qq` 类型。 对于对接 OneBot 标准的机器人客户端,只要符合 OneBot 标准,即 `X-Client-Role` 会自动带上 `universal``qq` 等字样,就会自动标记为 `qq` 类型。
:::
## 逻辑编写 ## 逻辑编写
@@ -140,4 +142,3 @@ public function onMessage() {
```php ```php
server()->close($conn->getFd()); server()->close($conn->getFd());
``` ```

View File

@@ -5,8 +5,10 @@
从前面的几章中,我们了解到框架有多种下载到本地的方式。 从前面的几章中,我们了解到框架有多种下载到本地的方式。
- Composer 依赖模式 - Composer 依赖模式
- Starter 从模板创建模式 - Starter 从模板创建模式(等同于 Composer 模式)
- 源码模式 - 源码模式
- Phar Composer 依赖模式
- Phar 源码模式
### Composer 依赖模式 ### Composer 依赖模式
@@ -131,4 +133,4 @@ vendor/bin/start simple-http-server your-web-dir/ --host=0.0.0.0 --port=8080
命令:`vendor/bin/start systemd:generate` 命令:`vendor/bin/start systemd:generate`
注意systemd 启动的守护进程模式和使用参数 `--daemon` 不一样,请勿同时混用,直接使用上述命令生成的配置文件即可正常使用! 注意systemd 启动的守护进程模式和使用参数 `--daemon` 不一样,请勿同时混用,直接使用上述命令生成的配置文件即可正常使用!

View File

@@ -87,14 +87,13 @@ class AdminMiddleware implements MiddlewareInterface
*/ */
``` ```
<chat-box> <chat-box :my-chats="[
^ 假设我是管理员 {type:0,content:'禁言 1234567 600'},
) 禁言 1234567 600 {type:1,content:'禁言成功!'},
( 禁言成功! {type:2,content:'假设我不在管理员名单里'},
^ 假设我不在管理员名单里 {type:0,content:'禁言 1234567 900'},
) 禁言 1234567 900 {type:2,content:'机器人没有回复,因为中间件返回了 false不继续执行'},
^ 机器人没有回复,因为中间件返回了 false不继续执行 ]"></chat-box>
</chat-box>
而这时候有朋友又要问了,如果我有一系列管理员命令,假设都在一个叫 `AdminFunc.php` 的模块类里,我是不是还得一个一个地给注解事件写 `@Middleware("admin")` 呢?当然不需要!如果你这个类所有的注解事件都是机器人的聊天事件(`@CQCommand``@CQMessage`)的话,可以直接给类注解这个中间件,效果等同于给每一个函数写一次中间件注解。 而这时候有朋友又要问了,如果我有一系列管理员命令,假设都在一个叫 `AdminFunc.php` 的模块类里,我是不是还得一个一个地给注解事件写 `@Middleware("admin")` 呢?当然不需要!如果你这个类所有的注解事件都是机器人的聊天事件(`@CQCommand``@CQMessage`)的话,可以直接给类注解这个中间件,效果等同于给每一个函数写一次中间件注解。
@@ -120,112 +119,111 @@ class AdminFunc
上面我们讲到了,中间件里面使用了 `LightCache` 轻量缓存来储存临时的管理员列表,那么我们将这部分的代码完善吧! 上面我们讲到了,中间件里面使用了 `LightCache` 轻量缓存来储存临时的管理员列表,那么我们将这部分的代码完善吧!
=== "src/Module/Example/AdminFunc.php" **src/Module/Example/AdminFunc.php**
```php ```php
<?php <?php
namespace Module\Example; namespace Module\Example;
use ZM\Annotation\CQ\CQCommand; use ZM\Annotation\CQ\CQCommand;
use ZM\Annotation\Http\Middleware; use ZM\Annotation\Http\Middleware;
use ZM\API\CQ; use ZM\API\CQ;
/**
* Class AdminFunc
* @package Module\Example
* @Middleware("admin")
*/
class AdminFunc
{
/**
* @CQCommand(match="禁言",message_type="group")
*/
public function banSomeone() {
$r1 = ctx()->getNextArg("请输入禁言的人或at他");
$r2 = ctx()->getFullArg("请输入禁言的时间(秒)");
$cq = CQ::getCQ($r1);
if ($cq !== null) {
if ($cq["type"] != "at") return "请at或者输入正确的QQ号";
$r1 = $cq["params"]["qq"];
}
// 群内禁言用户
ctx()->getRobot()->setGroupBan(ctx()->getGroupId(), $r1, $r2);
return "禁言成功!";
}
/** /**
* Class AdminFunc * @CQCommand(match="解除禁言",message_type="group")
* @package Module\Example */
public function unbanSomeone() {
$r1 = ctx()->getNextArg("请输入禁言的人或at他");
$cq = CQ::getCQ($r1);
if ($cq !== null) {
if ($cq["type"] != "at") return "请at或者输入正确的QQ号";
$r1 = $cq["params"]["qq"];
}
// 群内禁言用户
ctx()->getRobot()->setGroupBan(ctx()->getGroupId(), $r1, 0);
return "解除禁言成功!";
}
}
```
**src/Module/Example/AdminManager.php**
```php
<?php
namespace Module\Example;
use ZM\Annotation\CQ\CQCommand;
use ZM\Annotation\Http\Middleware;
use ZM\Annotation\Swoole\OnStart;
use ZM\Store\LightCache;
use ZM\Store\Lock\SpinLock;
class AdminManager
{
/**
* @OnStart()
*/
public function onStart() {
if (!LightCache::isset("admin_list")) { //一次性代码首次执行才会执行if
LightCache::set("admin_list", [ // 框架启动时初始化管理员列表
"123456",
"234567"
], -2); // 这里用 -2 的原因是将这一列表持久化保存,避免关闭框架后丢失
}
}
/**
* @CQCommand(match="添加管理员")
* @Middleware("admin") * @Middleware("admin")
*/ */
class AdminFunc public function addAdmin() { //只有管理员才能添加管理员
{ $qq = ctx()->getNextArg("请输入要添加管理员的QQ(qq号码不可at");
/** SpinLock::lock("admin_list"); //如果是多进程模式的话需要加锁
* @CQCommand(match="禁言",message_type="group") $ls = LightCache::get("admin_list");
*/ if (!in_array($qq, $ls)) $ls[] = $qq;
public function banSomeone() { LightCache::set("admin_list", $ls, -2);
$r1 = ctx()->getNextArg("请输入禁言的人或at他"); SpinLock::unlock("admin_list"); //如果是多进程模式的话需要加锁
$r2 = ctx()->getFullArg("请输入禁言的时间(秒)"); return "成功添加 $qq 到管理员列表!";
$cq = CQ::getCQ($r1);
if ($cq !== null) {
if ($cq["type"] != "at") return "请at或者输入正确的QQ号";
$r1 = $cq["params"]["qq"];
}
// 群内禁言用户
ctx()->getRobot()->setGroupBan(ctx()->getGroupId(), $r1, $r2);
return "禁言成功!";
}
/**
* @CQCommand(match="解除禁言",message_type="group")
*/
public function unbanSomeone() {
$r1 = ctx()->getNextArg("请输入禁言的人或at他");
$cq = CQ::getCQ($r1);
if ($cq !== null) {
if ($cq["type"] != "at") return "请at或者输入正确的QQ号";
$r1 = $cq["params"]["qq"];
}
// 群内禁言用户
ctx()->getRobot()->setGroupBan(ctx()->getGroupId(), $r1, 0);
return "解除禁言成功!";
}
} }
``` }
```
=== "src/Module/Example/AdminManager.php"
```php
<?php
namespace Module\Example;
use ZM\Annotation\CQ\CQCommand;
use ZM\Annotation\Http\Middleware;
use ZM\Annotation\Swoole\OnStart;
use ZM\Store\LightCache;
use ZM\Store\Lock\SpinLock;
class AdminManager
{
/**
* @OnStart()
*/
public function onStart() {
if (!LightCache::isset("admin_list")) { //一次性代码首次执行才会执行if
LightCache::set("admin_list", [ // 框架启动时初始化管理员列表
"123456",
"234567"
], -2); // 这里用 -2 的原因是将这一列表持久化保存,避免关闭框架后丢失
}
}
/**
* @CQCommand(match="添加管理员")
* @Middleware("admin")
*/
public function addAdmin() { //只有管理员才能添加管理员
$qq = ctx()->getNextArg("请输入要添加管理员的QQ(qq号码不可at");
SpinLock::lock("admin_list"); //如果是多进程模式的话需要加锁
$ls = LightCache::get("admin_list");
if (!in_array($qq, $ls)) $ls[] = $qq;
LightCache::set("admin_list", $ls, -2);
SpinLock::unlock("admin_list"); //如果是多进程模式的话需要加锁
return "成功添加 $qq 到管理员列表!";
}
}
```
<chat-box>
^ 现在我是 123456
) 禁言 13579 60
( 禁言成功!
) 解除禁言 13579
( 解除禁言成功!
) 添加管理员 98765
( 成功添加 98765 到管理员列表!
^ 现在我是98765
) 禁言 13579
( 请输入禁言的时间(秒)
) 120
( 禁言成功!
</chat-box>
<chat-box :my-chats="[
{type:2,content:'现在我是 123456'},
{type:0,content:'禁言 13579 60'},
{type:1,content:'禁言成功!'},
{type:0,content:'解除禁言 13579'},
{type:1,content:'解除禁言成功!'},
{type:0,content:'添加管理员 98765'},
{type:1,content:'成功添加 98765 到管理员列表!'},
{type:2,content:'现在我是98765'},
{type:0,content:'禁言 13579'},
{type:1,content:'请输入禁言的时间(秒)'},
{type:0,content:'120'},
{type:1,content:'禁言成功!'},
]"></chat-box>

View File

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

View File

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

View File

@@ -3,4 +3,3 @@
## 框架运行总结构图 ## 框架运行总结构图
![](https://static.zhamao.me/images/docs/a23d8a952cf9c88d395888d220605a4f.png) ![](https://static.zhamao.me/images/docs/a23d8a952cf9c88d395888d220605a4f.png)

View File

@@ -1,9 +0,0 @@
# 进阶开发
在本章,下面的部分将详细说明一些具体的案例和自定义框架的操作。
- 如何自定义修改框架本身?- [框架启动方式](/advanced/custom-start/)
- 如何接入一个自己的 WebSocket 客户端?- [接入 WebSocket 客户端](/advanced/connect-ws-client/)
- 框架到底是怎么工作的?- [框架结构剖析](/advanced/framework-structure/)
> 更多进阶教程敬请期待....(或者你可以选择提 Issue 到框架 GitHub有需求就写入文档

View File

@@ -65,6 +65,3 @@ $obj->match ==> [
] ]
*/ */
``` ```

View File

@@ -1,3 +1,3 @@
# 手动部署环境教程 # 手动部署环境教程
TODO: 还没写 TODO: 还没写

View File

@@ -63,8 +63,10 @@ PHP 也是如此,框架的多进程又是怎么一回事呢?为什么要采
| LightCache | 框架封装的跨进程的 key-value 存储模型 | 性能强悍,无 I/O 和网络通信 | 需要提前分配最大内存大小,最大单个值长度大小,不灵活 | | LightCache | 框架封装的跨进程的 key-value 存储模型 | 性能强悍,无 I/O 和网络通信 | 需要提前分配最大内存大小,最大单个值长度大小,不灵活 |
| WorkerCache | 框架封装的基于进程的 key-value 存储模型,类似 Redis | 无需提前分配最大内存大小,受限于 PHP memory_limit | 见 WorkerCache 的说明 | | WorkerCache | 框架封装的基于进程的 key-value 存储模型,类似 Redis | 无需提前分配最大内存大小,受限于 PHP memory_limit | 见 WorkerCache 的说明 |
!!! note "WorkerCache 的说明" ::: tip WorkerCache 的说明
对于 WorkerCache 来说其实是比较特殊的进程间通信。具体来说就是WorkerCache 的原理就是将变量指定的存到一个进程中,如果是本进程读写的话直接相当于改一下全局变量,如果是其他进程读写的话,则依靠进程间通信。
所以缺点也显而易见,如果使用过程中不是命中了 WorkerCache 存储所在的进程的话,则一直会使用进程间通信,影响一定的效率。
对于 WorkerCache 来说其实是比较特殊的进程间通信。具体来说就是WorkerCache 的原理就是将变量指定的存到一个进程中,如果是本进程读写的话直接相当于改一下全局变量,如果是其他进程读写的话,则依靠进程间通信。
所以缺点也显而易见,如果使用过程中不是命中了 WorkerCache 存储所在的进程的话,则一直会使用进程间通信,影响一定的效率。
:::

3
docs/advanced/php-env.md Normal file
View File

@@ -0,0 +1,3 @@
# PHP 环境高级部署方式
TODO: 留个坑。

View File

@@ -1,4 +1,3 @@
# 使用 TaskWorker 进程处理密集运算 # 使用 TaskWorker 进程处理密集运算
> 新开个坑有时间补上。__填坑标记__ > TODO: 新开个坑有时间补上。__填坑标记__

463
docs/api/ZM/API/CQ.md Normal file
View File

@@ -0,0 +1,463 @@
# ZM\API\CQ
## at
```php
public function at(mixed $qq): string
```
### 描述
at一下QQ用户仅在QQ群支持at全体
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| qq | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## face
```php
public function face(mixed $id): string
```
### 描述
发送QQ原生表情
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## image
```php
public function image(mixed $file, bool $cache, bool $flash, bool $proxy, int $timeout): string
```
### 描述
发送图片
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| file | mixed | |
| cache | bool | |
| flash | bool | |
| proxy | bool | |
| timeout | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## record
```php
public function record(mixed $file, bool $magic, bool $cache, bool $proxy, int $timeout): string
```
### 描述
发送语音
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| file | mixed | |
| magic | bool | |
| cache | bool | |
| proxy | bool | |
| timeout | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## video
```php
public function video(mixed $file, bool $cache, bool $proxy, int $timeout): string
```
### 描述
发送短视频
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| file | mixed | |
| cache | bool | |
| proxy | bool | |
| timeout | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## rps
```php
public function rps(): string
```
### 描述
发送投掷骰子(只能在单条回复中单独使用)
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## dice
```php
public function dice(): string
```
### 描述
发送掷骰子表情(只能在单条回复中单独使用)
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## shake
```php
public function shake(): string
```
### 描述
戳一戳(原窗口抖动,仅支持好友消息使用)
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## poke
```php
public function poke(mixed $type, mixed $id, string $name): string
```
### 描述
发送新的戳一戳
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| type | mixed | |
| id | mixed | |
| name | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## anonymous
```php
public function anonymous(int $ignore): string
```
### 描述
发送匿名消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| ignore | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## share
```php
public function share(mixed $url, mixed $title, null $content, null $image): string
```
### 描述
发送链接分享(只能在单条回复中单独使用)
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| url | mixed | |
| title | mixed | |
| content | null | |
| image | null | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## contact
```php
public function contact(mixed $type, mixed $id): string
```
### 描述
发送好友或群推荐名片
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| type | mixed | |
| id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## location
```php
public function location(mixed $lat, mixed $lon, string $title, string $content): string
```
### 描述
发送位置
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| lat | mixed | |
| lon | mixed | |
| title | string | |
| content | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## music
```php
public function music(mixed $type, mixed $id_or_url, null $audio, null $title, null $content, null $image): string
```
### 描述
发送音乐分享(只能在单条回复中单独使用)
qq、163、xiami为内置分享需要先通过搜索功能获取id后使用
custom为自定义分享
当为自定义分享时:
$id_or_url 为音乐卡片点进去打开的链接(一般是音乐介绍界面啦什么的)
$audio 为音乐如mp3文件的HTTP链接地址不可为空
$title 为音乐卡片的标题建议12字以内不可为空
$content 为音乐卡片的简介(可忽略)
$image 为音乐卡片的图片链接地址(可忽略)
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| type | mixed | |
| id_or_url | mixed | |
| audio | null | |
| title | null | |
| content | null | |
| image | null | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## decode
```php
public function decode(mixed $msg, mixed $is_content): mixed
```
### 描述
反转义字符串中的CQ码敏感符号
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
| is_content | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## escape
```php
public function escape(mixed $msg, mixed $is_content): mixed
```
### 描述
转义CQ码的特殊字符同encode
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
| is_content | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## encode
```php
public function encode(mixed $msg, mixed $is_content): mixed
```
### 描述
转义CQ码的特殊字符
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
| is_content | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## removeCQ
```php
public function removeCQ(mixed $msg): string
```
### 描述
移除消息中所有的CQ码并返回移除CQ码后的消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## getCQ
```php
public function getCQ(mixed $msg, mixed $is_object): mixed
```
### 描述
获取消息中第一个CQ码
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
| is_object | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## getAllCQ
```php
public function getAllCQ(mixed $msg, mixed $is_object): mixed
```
### 描述
获取消息中所有的CQ码
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
| is_object | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1,174 @@
# ZM\API\GoCqhttpAPIV11
## getGuildServiceProfile
```php
public function getGuildServiceProfile(): array|bool
```
### 描述
获取频道系统内BOT的资料
响应字段nickname, tiny_id, avatar_url
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## getGuildList
```php
public function getGuildList(): array|bool
```
### 描述
获取频道列表
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## getGuildMetaByGuest
```php
public function getGuildMetaByGuest(mixed $guild_id): array|bool
```
### 描述
通过访客获取频道元数据
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| guild_id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## getGuildChannelList
```php
public function getGuildChannelList(mixed $guild_id, false $no_cache): array|bool
```
### 描述
获取子频道列表
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| guild_id | mixed | |
| no_cache | false | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## getGuildMembers
```php
public function getGuildMembers(mixed $guild_id): array|bool
```
### 描述
获取频道成员列表
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| guild_id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## sendGuildChannelMsg
```php
public function sendGuildChannelMsg(mixed $guild_id, mixed $channel_id, mixed $message): array|bool
```
### 描述
发送信息到子频道
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| guild_id | mixed | |
| channel_id | mixed | |
| message | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## processAPI
```php
public function processAPI(mixed $connection, mixed $reply, |null $function): array|bool
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| connection | mixed | |
| reply | mixed | |
| function | |null | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## processHttpAPI
```php
public function processHttpAPI(mixed $connection, mixed $reply, null $function): bool
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| connection | mixed | |
| reply | mixed | |
| function | null | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| bool | |

View File

@@ -0,0 +1,932 @@
# ZM\API\OneBotV11
## get
```php
public function get(mixed $robot_id): ZMRobot
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| robot_id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| ZMRobot | |
## getRandom
```php
public function getRandom(): ZMRobot
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| ZMRobot | |
## getAllRobot
```php
public function getAllRobot(): ZMRobot[]
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| ZMRobot[] | |
## sendPrivateMsg
```php
public function sendPrivateMsg(mixed $user_id, mixed $message, bool $auto_escape): null|array|bool
```
### 描述
发送私聊消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| user_id | mixed | |
| message | mixed | |
| auto_escape | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## sendGroupMsg
```php
public function sendGroupMsg(mixed $group_id, mixed $message, bool $auto_escape): null|array|bool
```
### 描述
发送群消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| message | mixed | |
| auto_escape | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## sendMsg
```php
public function sendMsg(mixed $message_type, mixed $target_id, mixed $message, bool $auto_escape): null|array|bool
```
### 描述
发送消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| message_type | mixed | |
| target_id | mixed | |
| message | mixed | |
| auto_escape | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## deleteMsg
```php
public function deleteMsg(mixed $message_id): null|array|bool
```
### 描述
撤回消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| message_id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getMsg
```php
public function getMsg(mixed $message_id): null|array|bool
```
### 描述
获取消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| message_id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getForwardMsg
```php
public function getForwardMsg(mixed $id): null|array|bool
```
### 描述
获取合并转发消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## sendLike
```php
public function sendLike(mixed $user_id, int $times): null|array|bool
```
### 描述
发送好友赞
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| user_id | mixed | |
| times | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupKick
```php
public function setGroupKick(mixed $group_id, mixed $user_id, bool $reject_add_request): null|array|bool
```
### 描述
群组踢人
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| user_id | mixed | |
| reject_add_request | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupBan
```php
public function setGroupBan(mixed $group_id, mixed $user_id, int $duration): null|array|bool
```
### 描述
群组单人禁言
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| user_id | mixed | |
| duration | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupAnonymousBan
```php
public function setGroupAnonymousBan(mixed $group_id, mixed $anonymous_or_flag, int $duration): null|array|bool
```
### 描述
群组匿名用户禁言
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| anonymous_or_flag | mixed | |
| duration | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupWholeBan
```php
public function setGroupWholeBan(mixed $group_id, bool $enable): null|array|bool
```
### 描述
群组全员禁言
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| enable | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupAdmin
```php
public function setGroupAdmin(mixed $group_id, mixed $user_id, bool $enable): null|array|bool
```
### 描述
群组设置管理员
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| user_id | mixed | |
| enable | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupAnonymous
```php
public function setGroupAnonymous(mixed $group_id, bool $enable): null|array|bool
```
### 描述
群组匿名
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| enable | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupCard
```php
public function setGroupCard(mixed $group_id, mixed $user_id, string $card): null|array|bool
```
### 描述
设置群名片(群备注)
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| user_id | mixed | |
| card | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupName
```php
public function setGroupName(mixed $group_id, mixed $group_name): null|array|bool
```
### 描述
设置群名
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| group_name | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupLeave
```php
public function setGroupLeave(mixed $group_id, bool $is_dismiss): null|array|bool
```
### 描述
退出群组
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| is_dismiss | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupSpecialTitle
```php
public function setGroupSpecialTitle(mixed $group_id, mixed $user_id, string $special_title, int $duration): null|array|bool
```
### 描述
设置群组专属头衔
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| user_id | mixed | |
| special_title | string | |
| duration | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setFriendAddRequest
```php
public function setFriendAddRequest(mixed $flag, bool $approve, string $remark): null|array|bool
```
### 描述
处理加好友请求
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| flag | mixed | |
| approve | bool | |
| remark | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setGroupAddRequest
```php
public function setGroupAddRequest(mixed $flag, mixed $sub_type, bool $approve, string $reason): null|array|bool
```
### 描述
处理加群请求/邀请
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| flag | mixed | |
| sub_type | mixed | |
| approve | bool | |
| reason | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getLoginInfo
```php
public function getLoginInfo(): null|array|bool
```
### 描述
获取登录号信息
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getStrangerInfo
```php
public function getStrangerInfo(mixed $user_id, bool $no_cache): null|array|bool
```
### 描述
获取陌生人信息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| user_id | mixed | |
| no_cache | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getFriendList
```php
public function getFriendList(): null|array|bool
```
### 描述
获取好友列表
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getGroupInfo
```php
public function getGroupInfo(mixed $group_id, bool $no_cache): null|array|bool
```
### 描述
获取群信息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| no_cache | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getGroupList
```php
public function getGroupList(): null|array|bool
```
### 描述
获取群列表
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getGroupMemberInfo
```php
public function getGroupMemberInfo(mixed $group_id, mixed $user_id, bool $no_cache): null|array|bool
```
### 描述
获取群成员信息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| user_id | mixed | |
| no_cache | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getGroupMemberList
```php
public function getGroupMemberList(mixed $group_id): null|array|bool
```
### 描述
获取群成员列表
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getGroupHonorInfo
```php
public function getGroupHonorInfo(mixed $group_id, mixed $type): null|array|bool
```
### 描述
获取群荣誉信息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| group_id | mixed | |
| type | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getCsrfToken
```php
public function getCsrfToken(): null|array|bool
```
### 描述
获取 CSRF Token
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getCredentials
```php
public function getCredentials(string $domain): null|array|bool
```
### 描述
获取 QQ 相关接口凭证
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| domain | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getRecord
```php
public function getRecord(mixed $file, mixed $out_format): null|array|bool
```
### 描述
获取语音
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| file | mixed | |
| out_format | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getImage
```php
public function getImage(mixed $file): null|array|bool
```
### 描述
获取图片
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| file | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## canSendImage
```php
public function canSendImage(): null|array|bool
```
### 描述
检查是否可以发送图片
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## canSendRecord
```php
public function canSendRecord(): null|array|bool
```
### 描述
检查是否可以发送语音
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getStatus
```php
public function getStatus(): null|array|bool
```
### 描述
获取运行状态
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getVersionInfo
```php
public function getVersionInfo(): null|array|bool
```
### 描述
获取版本信息
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## setRestart
```php
public function setRestart(int $delay): null|array|bool
```
### 描述
重启 OneBot 实现
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| delay | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## cleanCache
```php
public function cleanCache(): null|array|bool
```
### 描述
清理缓存
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| null|array|bool | |
## getExtendedAPI
```php
public function getExtendedAPI(string $package_name): mixed
```
### 描述
获取内置支持的扩展API对象
现支持 go-cqhttp 的扩展API
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| package_name | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## processAPI
```php
public function processAPI(mixed $connection, mixed $reply, |null $function): array|bool
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| connection | mixed | |
| reply | mixed | |
| function | |null | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## processHttpAPI
```php
public function processHttpAPI(mixed $connection, mixed $reply, null $function): bool
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| connection | mixed | |
| reply | mixed | |
| function | null | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| bool | |

View File

@@ -0,0 +1,24 @@
# ZM\API\TuringAPI
## getTuringMsg
```php
public function getTuringMsg(mixed $msg, mixed $user_id, mixed $api): string
```
### 描述
请求图灵API返回图灵的消息
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
| user_id | mixed | |
| api | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |

View File

@@ -0,0 +1 @@
# ZM\API\ZMRobot

View File

@@ -0,0 +1 @@
# ZM\Annotation\AnnotationBase

View File

@@ -0,0 +1,98 @@
# ZM\Annotation\AnnotationParser
## __construct
```php
public function __construct(): mixed
```
### 描述
AnnotationParser constructor.
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## registerMods
```php
public function registerMods(): mixed
```
### 描述
注册各个模块类的注解和模块level的排序
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## addRegisterPath
```php
public function addRegisterPath(mixed $path, mixed $indoor_name): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| path | mixed | |
| indoor_name | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## sortByLevel
```php
public function sortByLevel(mixed $events, string $class_name, string $prefix): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| events | mixed | |
| class_name | string | |
| prefix | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## verifyMiddlewares
```php
public function verifyMiddlewares(): mixed
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1 @@
# ZM\Annotation\CQ\CQAPIResponse

View File

@@ -0,0 +1,39 @@
# ZM\Annotation\CQ\CQAfter
## getLevel
```php
public function getLevel(): mixed
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## setLevel
```php
public function setLevel(mixed $level): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| level | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1,39 @@
# ZM\Annotation\CQ\CQBefore
## getLevel
```php
public function getLevel(): mixed
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## setLevel
```php
public function setLevel(mixed $level): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| level | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1,22 @@
# ZM\Annotation\CQ\CQCommand
## setLevel
```php
public function setLevel(int $level): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| level | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1 @@
# ZM\Annotation\CQ\CQMessage

View File

@@ -0,0 +1,39 @@
# ZM\Annotation\CQ\CQMetaEvent
## getLevel
```php
public function getLevel(): mixed
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## setLevel
```php
public function setLevel(int $level): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| level | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1,22 @@
# ZM\Annotation\CQ\CQNotice
## setLevel
```php
public function setLevel(int $level): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| level | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1,22 @@
# ZM\Annotation\CQ\CQRequest
## setLevel
```php
public function setLevel(int $level): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| level | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1 @@
# ZM\Annotation\Command\TerminalCommand

View File

@@ -0,0 +1,61 @@
# ZM\Annotation\Cron\Cron
## setStatus
```php
public function setStatus(int $status): void
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| status | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| void | |
## getRecordNextTime
```php
public function getRecordNextTime(): int
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| int | |
## setRecordNextTime
```php
public function setRecordNextTime(int $record_next_time): void
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| record_next_time | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| void | |

View File

@@ -0,0 +1 @@
# ZM\Annotation\Http\Controller

View File

@@ -0,0 +1 @@
# ZM\Annotation\Http\HandleAfter

View File

@@ -0,0 +1 @@
# ZM\Annotation\Http\HandleBefore

View File

@@ -0,0 +1 @@
# ZM\Annotation\Http\HandleException

View File

@@ -0,0 +1 @@
# ZM\Annotation\Http\Middleware

View File

@@ -0,0 +1 @@
# ZM\Annotation\Http\MiddlewareClass

View File

@@ -0,0 +1 @@
# ZM\Annotation\Http\RequestMapping

View File

@@ -0,0 +1 @@
# ZM\Annotation\Http\RequestMethod

View File

@@ -0,0 +1 @@
# ZM\Annotation\Module\Closed

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnCloseEvent

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnManagerStartEvent

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnMessageEvent

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnOpenEvent

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnPipeMessageEvent

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnRequestEvent

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnSave

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnSetup

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnStart

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnSwooleEvent

View File

@@ -0,0 +1,22 @@
# ZM\Annotation\Swoole\OnSwooleEventBase
## setLevel
```php
public function setLevel(int $level): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| level | int | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1,17 @@
# ZM\Annotation\Swoole\OnTask
## getRule
```php
public function getRule(): mixed
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnTaskEvent

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\OnTick

View File

@@ -0,0 +1 @@
# ZM\Annotation\Swoole\SwooleHandler

View File

@@ -0,0 +1 @@
# ZM\Command\BuildCommand

View File

@@ -0,0 +1,24 @@
# ZM\Command\CheckConfigCommand
## check
```php
public function check(mixed $remote, mixed $local, Symfony\Component\Console\Output\OutputInterface $out): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| remote | mixed | |
| local | mixed | |
| out | Symfony\Component\Console\Output\OutputInterface | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

View File

@@ -0,0 +1 @@
# ZM\Command\Daemon\DaemonCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Daemon\DaemonReloadCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Daemon\DaemonStatusCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Daemon\DaemonStopCommand

View File

@@ -0,0 +1,91 @@
# ZM\Command\Generate\APIDocsGenerateCommand
## configure
```php
public function configure(): void
```
### 描述
Configures the current command.
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| void | |
## execute
```php
public function execute(Symfony\Component\Console\Input\InputInterface $input, Symfony\Component\Console\Output\OutputInterface $output): int
```
### 描述
Executes the current command.
This method is not abstract because you can use this class
as a concrete class. In this case, instead of defining the
execute() method, you set the code to execute by passing
a Closure to the setCode() method.
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| input | Symfony\Component\Console\Input\InputInterface | |
| output | Symfony\Component\Console\Output\OutputInterface | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| int | 0 if everything went fine, or an exit code * |
## getClassMetas
```php
public function getClassMetas(string $class_name, Jasny\PhpdocParser\PhpdocParser $parser): array
```
### 描述
获取类的元数据
包括类的注释、方法的注释、参数、返回值等
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| class_name | string | |
| parser | Jasny\PhpdocParser\PhpdocParser | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array | |
## convertMetaToMarkdown
```php
public function convertMetaToMarkdown(string $method, array $meta): string
```
### 描述
将方法的元数据转换为 Markdown 格式
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| method | string | 方法名 |
| meta | array | 元数据 |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |

View File

@@ -0,0 +1 @@
# ZM\Command\Generate\SystemdGenerateCommand

View File

@@ -0,0 +1 @@
# ZM\Command\InitCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Module\ModuleListCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Module\ModulePackCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Module\ModuleUnpackCommand

View File

@@ -0,0 +1 @@
# ZM\Command\PureHttpCommand

View File

@@ -0,0 +1 @@
# ZM\Command\RunServerCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Server\ServerReloadCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Server\ServerStatusCommand

View File

@@ -0,0 +1 @@
# ZM\Command\Server\ServerStopCommand

View File

@@ -0,0 +1,44 @@
# ZM\ConsoleApplication
## __construct
```php
public function __construct(string $name): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| name | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## initEnv
```php
public function initEnv(string $with_default_cmd): ZM\ConsoleApplication
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| with_default_cmd | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| ZM\ConsoleApplication | |

View File

@@ -0,0 +1,210 @@
# ZM\Context\Context
## getServer
```php
public function getServer(): Server
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| Server | |
## getData
```php
public function getData(): mixed
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## reply
```php
public function reply(mixed $msg, bool $yield): array|bool
```
### 描述
only can used by cq->message event function
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
| yield | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| array|bool | |
## finalReply
```php
public function finalReply(mixed $msg, bool $yield): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| msg | mixed | |
| yield | bool | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## waitMessage
```php
public function waitMessage(string $prompt, int $timeout, string $timeout_prompt): string
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| prompt | string | |
| timeout | int | |
| timeout_prompt | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| string | |
## getArgs
```php
public function getArgs(mixed $mode, mixed $prompt_msg): mixed|string
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| mode | mixed | |
| prompt_msg | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed|string | |
## getNextArg
```php
public function getNextArg(string $prompt_msg): int|mixed|string
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| prompt_msg | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| int|mixed|string | |
## getFullArg
```php
public function getFullArg(string $prompt_msg): int|mixed|string
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| prompt_msg | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| int|mixed|string | |
## getNumArg
```php
public function getNumArg(string $prompt_msg): int|mixed|string
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| prompt_msg | string | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| int|mixed|string | |
## cloneFromParent
```php
public function cloneFromParent(): mixed
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

88
docs/api/ZM/DB/DB.md Normal file
View File

@@ -0,0 +1,88 @@
# ZM\DB\DB
## initTableList
```php
public function initTableList(mixed $db_name): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| db_name | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## table
```php
public function table(mixed $table_name): ZM\DB\Table
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| table_name | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| ZM\DB\Table | |
## statement
```php
public function statement(mixed $line): mixed
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| line | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## unprepared
```php
public function unprepared(mixed $line): bool
```
### 描述
作者很懒,什么也没有说
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| line | mixed | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| bool | |

View File

@@ -0,0 +1,39 @@
# ZM\DB\DeleteBody
## __construct
```php
public function __construct(ZM\DB\Table $table): mixed
```
### 描述
DeleteBody constructor.
### 参数
| 名称 | 类型 | 描述 |
| -------- | ---- | ----------- |
| table | ZM\DB\Table | |
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |
## save
```php
public function save(): mixed
```
### 描述
作者很懒,什么也没有说
### 返回
| 类型 | 描述 |
| ---- | ----------- |
| mixed | |

Some files were not shown because too many files have changed in this diff Show More