From 71585ed29dd8c772788ce55264fa5c41e050d9ea Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sat, 8 May 2021 10:02:41 +0800 Subject: [PATCH] update to build 407 change daemon command from system to Process::kill add master_pid for motd information add option --preview delete server_event_handler_class and use process go-cqhttp-down.sh script add arm64 support add ./zhamao support change build-runtime.sh to install-runtime.sh add option --disable-safe-exit adjust some Console output set start script using /bin/sh for supporting auto searching php and framework --- bin/start | 25 +- build-runtime.sh | 305 -------------------- composer.json | 9 +- config/global.php | 9 +- docs/component/global-functions.md | 12 + ext/go-cqhttp/go-cqhttp-down.sh | 5 + install-runtime.sh | 58 ++++ src/ZM/Command/DaemonReloadCommand.php | 4 +- src/ZM/Command/DaemonStatusCommand.php | 1 - src/ZM/Command/DaemonStopCommand.php | 4 +- src/ZM/Command/InitCommand.php | 6 +- src/ZM/Command/RunServerCommand.php | 2 + src/ZM/ConsoleApplication.php | 4 +- src/ZM/Event/SwooleEvent/OnManagerStart.php | 9 +- src/ZM/Event/SwooleEvent/OnStart.php | 30 +- src/ZM/Event/SwooleEvent/OnWorkerStart.php | 23 +- src/ZM/Framework.php | 105 +++++-- src/entry.php | 5 + zhamao | 26 +- 19 files changed, 248 insertions(+), 394 deletions(-) delete mode 100755 build-runtime.sh create mode 100755 install-runtime.sh create mode 100644 src/entry.php diff --git a/bin/start b/bin/start index f52dd8b5..6ad3dc2d 100755 --- a/bin/start +++ b/bin/start @@ -1,6 +1,23 @@ -#!/usr/bin/env php -/dev/null 2>&1 + if [ $? -eq 0 ]; then + executable=$(which php) + else + echo 'Cannot find any PHP runtime, please use command `./install-runtime.sh` or install PHP manually!' + exit 1 + fi +fi -(new ZM\ConsoleApplication("zhamao-framework"))->initEnv()->run(); +if [ -f "$(pwd)/src/entry.php" ]; then + $executable "$(pwd)/src/entry.php" $@ +elif [ -f "$(pwd)/vendor/zhamao/framework/src/entry.php" ]; then + $executable "$(pwd)/vendor/zhamao/framework/src/entry.php" $@ +else + echo "Cannot find zhamao-framework entry file!" + exit 1 +fi diff --git a/build-runtime.sh b/build-runtime.sh deleted file mode 100755 index 07d3f31b..00000000 --- a/build-runtime.sh +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env bash - -function downloadIt() { - downloader="wget" - type wget >/dev/null 2>&1 || { downloader="curl"; } - if [ "$downloader" = "wget" ]; then - _down_prefix="O" - else - _down_prefix="o" - fi - _down_symbol=0 - if [ ! -f "$2" ]; then - echo $1 - $downloader "$1" -$_down_prefix "$2" >/dev/null 2>&1 && \ - echo "完成!" && _down_symbol=1 - else - echo "已存在!" && _down_symbol=1 - fi - if [ $_down_symbol == 0 ]; then - echo "失败!请检查网络连接!" - rm -rf "$2" - return 1 - fi - return 0 -} - -downloadIt https://mirrors.cloud.tencent.com/openssl/source/ /tmp/openssl_ver.html - -_php_ver="7.1.33" -_libiconv_ver="1.15" -_openssl_ver=$(cat /tmp/openssl_ver.html | grep "openssl-1.1.1.*.tar.gz<" | awk -F\" '{print $2}' | awk -F- '{print $2}' | awk -F".tar.gz" '{print $1}') -_swoole_ver="4.6.3" -_home_dir=$(pwd)"/" - -function checkEnv() { - echo -n "检测核心组件... " - _msg="请通过包管理安装此依赖!" - type git >/dev/null 2>&1 || { echo "失败,git 不存在!"$_msg; return 1; } - type gcc >/dev/null 2>&1 || { echo "失败,gcc 不存在!"$_msg; return 1; } - type g++ >/dev/null 2>&1 || { echo "失败,g++ 不存在!"$_msg; return 1; } - type unzip >/dev/null 2>&1 || { echo "失败,unzip 不存在!"$_msg; return 1; } - type autoconf >/dev/null 2>&1 || { echo "失败,autoconf 不存在!"; return 1; } - #type pkg-config >/dev/null 2>&1 || { echo "失败,pkg-config 不存在!"$_msg; return 1; } - type wget >/dev/null 2>&1 || type curl >/dev/null 2>&1 || { echo "失败,curl/wget 不存在!"$_msg; return 1; } - echo "完成!" - echo "如果下载过程中出现错误,请删除 runtime/ 文件夹重试!" - echo "此脚本安装的php/swoole均为最小版本,不含其他扩展(如zip、xml、gd)等!" - echo -n "如果编译过程缺少依赖,请通过包管理安装对应的依赖![按回车继续] " - # shellcheck disable=SC2034 - read ents -} - - - -function downloadAll() { - # 创建文件夹 - mkdir "$_home_dir""runtime" >/dev/null 2>&1 - mkdir "$_home_dir""runtime/tmp_download" >/dev/null 2>&1 - mkdir "$_home_dir""runtime/cellar" >/dev/null 2>&1 - _down_dir=$_home_dir"runtime/tmp_download/" - - # 下载PHP - echo -n "正在下载 php 源码... " - downloadIt "http://mirrors.sohu.com/php/php-$_php_ver.tar.gz" "$_down_dir""php.tar.gz" || { exit; } & - - # 下载libiconv - echo -n "正在下载 libiconv 源码... " - downloadIt "https://mirrors.tuna.tsinghua.edu.cn/gnu/libiconv/libiconv-$_libiconv_ver.tar.gz" "$_down_dir""libiconv.tar.gz" || { exit; } & - - echo -n "正在下载 openssl 源码... " - downloadIt "http://mirrors.cloud.tencent.com/openssl/source/openssl-$_openssl_ver.tar.gz" "$_down_dir""openssl.tar.gz" || { exit; } & - - echo -n "正在下载 swoole 源码... " - downloadIt "https://dl.zhamao.me/swoole/swoole-$_swoole_ver.tgz" "$_down_dir""swoole.tar.gz" || { exit; } & - - echo -n "正在下载 composer ... " - downloadIt "https://mirrors.aliyun.com/composer/composer.phar" "$_home_dir""runtime/cellar/composer" || { exit; } & - - echo -n "正在下载 zlib ... " - downloadIt "https://zlib.net/fossils/zlib-1.2.5.tar.gz" "$_down_dir""zlib.tar.gz" || { exit; } & - - echo -n "正在下载 libxml2 ... " - downloadIt "https://dl.zhamao.me/libxml2/libxml2-2.9.8.tar.gz" "$_down_dir""libxml2.tar.gz" || { exit; } & - - echo -n "正在下载 libpng ... " - downloadIt "https://dl.zhamao.me/libpng/libpng-1.6.37.tar.gz" "$_down_dir""libpng.tar.gz" || { exit; } & - - echo -n "正在下载 oniguruma ... " - downloadIt "https://dl.zhamao.me/oniguruma/onig-6.9.6.tar.gz" "$_down_dir""onig.tar.gz" || { exit; } & - - wait - - #echo -n "正在下载 libcurl 源码... " - #downloadIt "https://curl.se/download/curl-7.75.0.tar.gz" "$_down_dir""libcurl.tar.gz" || { exit; } -} - -function compileIt() { - _down_dir="$_home_dir""runtime/tmp_download/" - _source_dir="$_home_dir""runtime/tmp_source/" - _cellar_dir="$_home_dir""runtime/cellar/" - case $1 in - "onig") - if [ -f "$_cellar_dir""onig/bin/onig-config" ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""onig.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""onig-6.9.6" && \ - ./configure --prefix="$_cellar_dir""onig" && \ - make -j4 && \ - make install && \ - echo "完成!" - ;; - "libxml2") - if [ -f "$_cellar_dir""libxml2/lib/libxml2.so" ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""libxml2.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""libxml2-2.9.8" && \ - ./configure --prefix="$_cellar_dir""libxml2" --exec-prefix="$_cellar_dir""libxml2" --without-python && \ - make -j4 && \ - make install && \ - echo "完成!" - ;; - "libpng") - if [ -f "$_cellar_dir""libpng/bin/libpng-config" ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""libpng.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""libpng-1.6.37" && \ - LDFLAGS="-L$_cellar_dir""zlib/lib" CPPFLAGS="-I$_cellar_dir""zlib/include" ./configure --prefix="$_cellar_dir""libpng" && \ - make -j4 && \ - make install && \ - echo "完成!" - ;; - "zlib") - if [ -f "$_cellar_dir""zlib/lib/libz.so" ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""zlib.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""zlib-1.2.5" && \ - ./configure --prefix="$_cellar_dir""zlib" && \ - make -j4 && \ - make install && \ - echo "完成!" - ;; - "libiconv") - if [ -f "$_cellar_dir""libiconv/bin/iconv" ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""libiconv.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""libiconv-"$_libiconv_ver && \ - ./configure --prefix="$_cellar_dir""libiconv" >/dev/null 2>&1 && \ - make -j4 >/dev/null 2>&1 && \ - make install >/dev/null 2>&1 && \ - echo "完成!" - ;; - "libzip") - if [ -f "$_cellar_dir""libzip/bin/libzip" ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""libzip.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""libzip-1.7.3" && \ - ./configure --prefix="$_cellar_dir""libzip" && \ - make -j4 && \ - make install && \ - echo "完成!" - ;; - "libcurl") - if [ -f "$_cellar_dir""libcurl/bin/libcurl" ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""libcurl.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""libcurl-7.75.0" && \ - ./configure --prefix="$_cellar_dir""libcurl" && \ - make -j4 && \ - make install && \ - echo "完成!" - ;; - "php") - if [ -f "$_cellar_dir""php/bin/php" ]; then - echo "已编译!" && return - fi - PKG_CONFIG_PATH="$_cellar_dir""openssl/lib/pkgconfig" - PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$_cellar_dir""zlib/lib/pkgconfig" - PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$_cellar_dir""libxml2/lib/pkgconfig" - PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$_cellar_dir""libpng/lib/pkgconfig" - PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$_cellar_dir""onig/lib/pkgconfig" - tar -xf "$_down_dir""php.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""php-"$_php_ver && \ - ./buildconf --force && \ - PKG_CONFIG_PATH="$PKG_CONFIG_PATH" ./configure --prefix="$_cellar_dir""php" \ - --with-config-file-path="$_home_dir""runtime/etc" \ - --disable-fpm \ - --enable-cli \ - --enable-posix \ - --enable-ctype \ - --enable-mysqlnd \ - --enable-mbstring \ - --enable-gd \ - --enable-pdo \ - --enable-pcntl \ - --with-openssl="$_cellar_dir""openssl" \ - --enable-sockets \ - --without-sqlite3 \ - --without-pdo-sqlite \ - --with-pdo-mysql=mysqlnd \ - --with-zlib="$_cellar_dir""zlib" \ - --with-iconv="$_cellar_dir""libiconv" \ - --enable-phar && \ - make -j4 && \ - make install && \ - cp "$_source_dir""php-$_php_ver/php.ini-production" "$_home_dir""runtime/etc/php.ini" && \ - echo "完成!" - ;; - "openssl") - if [ -f "$_cellar_dir""openssl/bin/openssl" ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""openssl.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""openssl-""$_openssl_ver" && \ - ./config --prefix="$_cellar_dir""openssl" && \ - make -j4 && \ - make install && \ - echo "完成!" - ;; - "swoole") - "$_home_dir"runtime/cellar/php/bin/php --ri swoole >/dev/null 2>&1 - # shellcheck disable=SC2181 - if [ $? == 0 ]; then - echo "已编译!" && return - fi - tar -xf "$_down_dir""swoole.tar.gz" -C "$_source_dir" && \ - cd "$_source_dir""swoole-""$_swoole_ver" && \ - PATH="$_cellar_dir""php/bin:$PATH" phpize && \ - PATH="$_cellar_dir""php/bin:$PATH" ./configure --prefix="$_cellar_dir""php" \ - --enable-sockets \ - --enable-http2 \ - --enable-openssl \ - --with-openssl-dir="$_cellar_dir""openssl" \ - --enable-mysqlnd && \ - make -j4 && \ - make install && \ - echo "extension=swoole.so" >> "$_home_dir""runtime/etc/php.ini" && \ - echo "完成!" - ;; - esac -} - -function compileAll() { - _down_dir=$_home_dir"runtime/tmp_download/" - _source_dir=$_home_dir"runtime/tmp_source/" - mkdir "$_source_dir" >/dev/null 2>&1 - mkdir "$_home_dir""runtime/etc" >/dev/null 2>&1 - - echo -n "正在编译 libiconv ... " - compileIt libiconv || { return 1; } - - #echo -n "正在编译 libcurl ... " - #compileIt libcurl || { exit; } - - echo -n "正在编译 openssl ... " - compileIt openssl || { return 1; } - - echo -n "正在编译 zlib ... " - compileIt zlib || { return 1; } - - echo -n "正在编译 libxml2 ... " - compileIt libxml2 || { return 1; } - - echo -n "正在编译 libpng ... " - compileIt libpng || { return 1; } - - echo -n "正在编译 oniguruma ... " - compileIt onig || { return 1; } - - #echo -n "正在编译 libzip ... " - #compileIt libzip || { exit; } - - echo -n "正在编译 php ... " - compileIt php || { return 1; } - - echo -n "正在编译 swoole ... " - compileIt swoole || { return 1; } - - return 0 -} - -function linkBin(){ - mkdir "$_home_dir""runtime/bin" >/dev/null 2>&1 - ln -s "$_home_dir""runtime/cellar/php/bin/php" "$_home_dir""runtime/bin/php" >/dev/null 2>&1 - echo "runtime/cellar/php/bin/php runtime/cellar/composer \$@" > "$_home_dir""runtime/bin/composer" && chmod +x "$_home_dir""runtime/bin/composer" - echo "Done!" - "$_home_dir"runtime/bin/composer config repo.packagist composer https://mirrors.aliyun.com/composer/ -} - -checkEnv && \ -downloadAll && \ -compileAll && \ -linkBin && \ -echo "成功部署所有环境!" && \ -echo -e "composer更新依赖:\t\"runtime/bin/composer update\"" && \ -echo -e "启动框架(源码模式):\t\"runtime/bin/php bin/start server\"" && \ -echo -e "启动框架(普通模式):\t\"runtime/bin/php vendor/bin/start server\"" - - diff --git a/composer.json b/composer.json index a5b9e90d..68a47509 100644 --- a/composer.json +++ b/composer.json @@ -33,8 +33,7 @@ "zhamao/console": "^1.0.10", "zhamao/config": "^1.0", "zhamao/request": "^1.1", - "zhamao/connection-manager": "^1.0", - "league/climate": "^3.7" + "zhamao/connection-manager": "^1.0" }, "suggest": { "ext-ctype": "Use C/C++ extension instead of polyfill will be more efficient", @@ -45,9 +44,7 @@ }, "autoload": { "psr-4": { - "ZM\\": "src/ZM", - "Module\\": "src/Module", - "Custom\\": "src/Custom" + "ZM\\": "src/ZM" }, "files": [ "src/ZM/global_functions.php" @@ -56,4 +53,4 @@ "require-dev": { "swoole/ide-helper": "@dev" } -} \ No newline at end of file +} diff --git a/config/global.php b/config/global.php index 0441f463..9f334790 100644 --- a/config/global.php +++ b/config/global.php @@ -11,11 +11,11 @@ $config['port'] = 20001; /** 框架开到公网或外部的HTTP访问链接,通过 DataProvider::getFrameworkLink() 获取 */ $config['http_reverse_link'] = "http://127.0.0.1:" . $config['port']; -/** 框架是否启动debug模式 */ +/** 框架是否启动debug模式,当debug模式为true时,启用热更新(需要安装inotify扩展) */ $config['debug_mode'] = false; /** 存放框架内文件数据的目录 */ -$config['zm_data'] = realpath(__DIR__ . "/../") . '/zm_data/'; +$config['zm_data'] = realpath(WORKING_DIR) . '/zm_data/'; /** 存放各个模块配置文件的目录 */ $config['config_dir'] = $config['zm_data'] . 'config/'; @@ -107,11 +107,6 @@ $config['static_file_server'] = [ ] ]; -/** 注册 Swoole Server 事件注解的类列表 */ -$config['server_event_handler_class'] = [ - // 这里添加例如 \ZM\Event\ServerEventHandler::class 这样的启动注解类 -]; - /** 机器人解析模块,关闭后无法使用如CQCommand等注解(上面的modules即将废弃) */ $config['onebot'] = [ 'status' => true, diff --git a/docs/component/global-functions.md b/docs/component/global-functions.md index d90fe552..2566314f 100644 --- a/docs/component/global-functions.md +++ b/docs/component/global-functions.md @@ -4,6 +4,8 @@ ## getClassPath() +[源码](https://github.com/zhamao-robot/zhamao-framework/blob/master/src/ZM/global_functions.php#L24) + 根据加载的用户编写的代码类名来获取类所在的文件路径。 === "src/Module/Example/Hello.php" @@ -38,6 +40,8 @@ ## explodeMsg() +[源码](https://github.com/zhamao-robot/zhamao-framework/blob/master/src/ZM/global_functions.php#L39) + 切割字符串的函数,支持多空格,换行,tab。 定义:`explodeMsg($msg, $ban_comma = false)` @@ -49,6 +53,8 @@ echo json_encode($s, 128|256); // ["你好啊","你好你好","我还有多个 ## unicode_decode() +[源码](https://github.com/zhamao-robot/zhamao-framework/blob/master/src/ZM/global_functions.php#L54) + Unicode 解码,一般用于被转义的 Unicode 转回来。 ```php @@ -57,6 +63,8 @@ echo unicode_decode("\u4f60\u597d"); // 你好 ## matchPattern() +[源码](https://github.com/zhamao-robot/zhamao-framework/blob/master/src/ZM/global_functions.php#L91) + 根据星号匹配字符串(非正则表达式)。 匹配示例: @@ -81,6 +89,8 @@ matchPattern("*把*翻译成*", "请把你好翻译成阿拉伯语"); // true ## split_explode() +[源码](https://github.com/zhamao-robot/zhamao-framework/blob/master/src/ZM/global_functions.php#L103) + 和 `explodeMsg()` 类似,用作分割字符串,不过此函数加入了对 `中文|数字` 两者的分割,也就是说中文和数字之间也会被分割。 定义:`split_explode($del, $str, $divide_en = false)` @@ -97,6 +107,8 @@ split_explode(" ", "前进20 急啊急啊"); // ["前进","20","急啊急啊"] ## matchArgs() +[源码](https://github.com/zhamao-robot/zhamao-framework/blob/master/src/ZM/global_functions.php#L135) + `matchPattern()` 的扩展,如果 `matchPattern()` 格式的字符串和模式匹配成功,则通过星号位置来提取星号匹配到的内容,参数同 `matchPattern()`。 ```php diff --git a/ext/go-cqhttp/go-cqhttp-down.sh b/ext/go-cqhttp/go-cqhttp-down.sh index 846d49e8..4559a90e 100755 --- a/ext/go-cqhttp/go-cqhttp-down.sh +++ b/ext/go-cqhttp/go-cqhttp-down.sh @@ -6,6 +6,11 @@ if [ "$(uname -m)" = "x86_64" ]; then arch_type="amd64" elif [ "$(uname -m)" = "i386" ]; then arch_type="386" +elif [ "$(uname -m)" = "aarch64" ]; then + arch_type="arm64" +else + echo "Not supported architecture: $(uname -m)" + exit 1 fi aas=$(uname -s | tr 'A-Z' 'a-z') diff --git a/install-runtime.sh b/install-runtime.sh new file mode 100755 index 00000000..f934af1b --- /dev/null +++ b/install-runtime.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +function download_file() { + downloader="wget" + type wget >/dev/null 2>&1 || { downloader="curl"; } + if [ "$downloader" = "wget" ]; then + _down_prefix="O" + else + _down_prefix="o" + fi + _down_symbol=0 + if [ ! -f "$2" ]; then + echo $1 + $downloader "$1" -$_down_prefix "$2" >/dev/null 2>&1 && \ + echo "完成!" && _down_symbol=1 + else + echo "已存在!" && _down_symbol=1 + fi + if [ $_down_symbol == 0 ]; then + echo "失败!请检查网络连接!" + rm -rf "$2" + return 1 + fi + return 0 +} + +function test_composer_and_php() { + succ=$("$(pwd)/runtime/composer" -n about | grep Manage) + if [ "$succ" = "" ]; then + echo "Download PHP binary and composer failed!" + return 1 + fi + return 0 +} + +mkdir "$(pwd)/runtime" >/dev/null 2>&1 +if [ ! -f "$(pwd)/runtime/php" ]; then + download_file "https://dl.zhamao.me/php-bin/down.php?php_ver=7.4&arch=$(uname -m)" "$(pwd)/runtime/php.tar.gz" + if [ $? -ne 0 ]; then + exit 1 + fi + tar -xf "$(pwd)/runtime/php.tar.gz" -C "$(pwd)/runtime/" +fi +if [ ! -f "$(pwd)/runtime/composer" ]; then + download_file "https://mirrors.aliyun.com/composer/composer.phar" "$(pwd)/runtime/composer.phar" + if [ $? -ne 0 ]; then + exit 1 + fi + echo '$(dirname $0)/php $(dirname $0)/composer.phar $@' > $(pwd)/runtime/composer + chmod +x $(pwd)/runtime/composer + test_composer_and_php +fi +if [ $? -ne 0 ]; then + exit 1 +fi +echo "成功下载!" && \ + echo -e "PHP使用:\truntime/php -v" && \ + echo -e "Composer使用:\truntime/composer" \ No newline at end of file diff --git a/src/ZM/Command/DaemonReloadCommand.php b/src/ZM/Command/DaemonReloadCommand.php index 7f17513c..0a5f86f7 100644 --- a/src/ZM/Command/DaemonReloadCommand.php +++ b/src/ZM/Command/DaemonReloadCommand.php @@ -3,7 +3,7 @@ namespace ZM\Command; -use Symfony\Component\Console\Command\Command; +use Swoole\Process; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -17,7 +17,7 @@ class DaemonReloadCommand extends DaemonCommand protected function execute(InputInterface $input, OutputInterface $output): int { parent::execute($input, $output); - system("kill -USR1 " . intval($this->daemon_file["pid"])); + Process::kill(intval($this->daemon_file["pid"]), SIGUSR1); $output->writeln("成功重载!"); return 0; } diff --git a/src/ZM/Command/DaemonStatusCommand.php b/src/ZM/Command/DaemonStatusCommand.php index d1aee2e4..fb0e19f6 100644 --- a/src/ZM/Command/DaemonStatusCommand.php +++ b/src/ZM/Command/DaemonStatusCommand.php @@ -3,7 +3,6 @@ namespace ZM\Command; -use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/src/ZM/Command/DaemonStopCommand.php b/src/ZM/Command/DaemonStopCommand.php index ca2ae5d4..933fbc76 100644 --- a/src/ZM/Command/DaemonStopCommand.php +++ b/src/ZM/Command/DaemonStopCommand.php @@ -3,7 +3,7 @@ namespace ZM\Command; -use Symfony\Component\Console\Command\Command; +use Swoole\Process; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use ZM\Utils\DataProvider; @@ -18,7 +18,7 @@ class DaemonStopCommand extends DaemonCommand protected function execute(InputInterface $input, OutputInterface $output): int { parent::execute($input, $output); - system("kill -INT " . intval($this->daemon_file["pid"])); + Process::kill(intval($this->daemon_file["pid"]), SIGINT); unlink(DataProvider::getWorkingDir() . "/.daemon_pid"); $output->writeln("成功停止!"); return 0; diff --git a/src/ZM/Command/InitCommand.php b/src/ZM/Command/InitCommand.php index 1093e431..6f324758 100644 --- a/src/ZM/Command/InitCommand.php +++ b/src/ZM/Command/InitCommand.php @@ -12,6 +12,7 @@ use Symfony\Component\Console\Output\OutputInterface; class InitCommand extends Command { private $extract_files = [ + "/zhamao", "/config/global.php", "/.gitignore", "/config/file_header.json", @@ -50,11 +51,6 @@ class InitCommand extends Command echo "Skipping " . $file . " , file exists." . PHP_EOL; } } - echo "Copying ./zhamao\n"; - file_put_contents( - $base_path."/zhamao", - "#!/usr/bin/env php\ninitEnv(\"server\")->run();" - ); chmod($base_path."/zhamao", 0755); $autoload = [ "psr-4" => [ diff --git a/src/ZM/Command/RunServerCommand.php b/src/ZM/Command/RunServerCommand.php index 50971533..6a07cb6e 100644 --- a/src/ZM/Command/RunServerCommand.php +++ b/src/ZM/Command/RunServerCommand.php @@ -31,6 +31,8 @@ class RunServerCommand extends Command new InputOption("watch", null, null, "监听 src/ 目录的文件变化并热更新"), new InputOption("show-php-ver", null, null, "启动时显示PHP和Swoole版本"), new InputOption("env", null, InputOption::VALUE_REQUIRED, "设置环境类型 (production, development, staging)"), + new InputOption("disable-safe-exit", null, null, "关闭安全退出(关闭后按CtrlC时直接杀死进程)"), + new InputOption("preview", null, null, "只显示参数,不启动服务器") ]); $this->setDescription("Run zhamao-framework | 启动框架"); $this->setHelp("直接运行可以启动"); diff --git a/src/ZM/ConsoleApplication.php b/src/ZM/ConsoleApplication.php index 1c011e73..61b5c4b3 100644 --- a/src/ZM/ConsoleApplication.php +++ b/src/ZM/ConsoleApplication.php @@ -19,8 +19,8 @@ use ZM\Command\SystemdCommand; class ConsoleApplication extends Application { - const VERSION_ID = 406; - const VERSION = "2.4.5"; + const VERSION_ID = 407; + const VERSION = "2.5.0"; public function __construct(string $name = 'UNKNOWN') { define("ZM_VERSION_ID", self::VERSION_ID); diff --git a/src/ZM/Event/SwooleEvent/OnManagerStart.php b/src/ZM/Event/SwooleEvent/OnManagerStart.php index 240f1233..b65cad5a 100644 --- a/src/ZM/Event/SwooleEvent/OnManagerStart.php +++ b/src/ZM/Event/SwooleEvent/OnManagerStart.php @@ -10,6 +10,7 @@ use Swoole\Server; use ZM\Annotation\Swoole\SwooleHandler; use ZM\Console\Console; use ZM\Event\SwooleEvent; +use ZM\Framework; /** * Class OnManagerStart @@ -19,9 +20,11 @@ use ZM\Event\SwooleEvent; class OnManagerStart implements SwooleEvent { public function onCall(Server $server) { - pcntl_signal(SIGINT, function () { - Console::verbose("Interrupted in manager!"); - }); + if (!Framework::$argv["disable-safe-exit"]) { + pcntl_signal(SIGINT, function () { + Console::verbose("Interrupted in manager!"); + }); + } Console::verbose("进程 Manager 已启动"); } } \ No newline at end of file diff --git a/src/ZM/Event/SwooleEvent/OnStart.php b/src/ZM/Event/SwooleEvent/OnStart.php index fa53c229..f3830139 100644 --- a/src/ZM/Event/SwooleEvent/OnStart.php +++ b/src/ZM/Event/SwooleEvent/OnStart.php @@ -24,18 +24,20 @@ class OnStart implements SwooleEvent { public function onCall(Server $server) { $r = null; - Process::signal(SIGINT, function () use ($r, $server) { - if (zm_atomic("_int_is_reload")->get() === 1) { - zm_atomic("_int_is_reload")->set(0); - $server->reload(); - } else { - echo "\r"; - Console::warning("Server interrupted(SIGINT) on Master."); - if ((Framework::$server->inotify ?? null) !== null) - /** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify); - Process::kill($server->master_pid, SIGTERM); - } - }); + if (!Framework::$argv["disable-safe-exit"]) { + Process::signal(SIGINT, function () use ($r, $server) { + if (zm_atomic("_int_is_reload")->get() === 1) { + zm_atomic("_int_is_reload")->set(0); + $server->reload(); + } else { + echo "\r"; + Console::warning("Server interrupted(SIGINT) on Master."); + if ((Framework::$server->inotify ?? null) !== null) + /** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify); + Process::kill($server->master_pid, SIGTERM); + } + }); + } if (Framework::$argv["daemon"]) { $daemon_data = json_encode([ "pid" => $server->master_pid, @@ -45,13 +47,13 @@ class OnStart implements SwooleEvent } if (Framework::$argv["watch"]) { if (extension_loaded('inotify')) { - Console::warning("Enabled File watcher, do not use in production."); + Console::info("Enabled File watcher, framework will reload automatically."); /** @noinspection PhpUndefinedFieldInspection */ Framework::$server->inotify = $fd = inotify_init(); $this->addWatcher(DataProvider::getWorkingDir() . "/src", $fd); Event::add($fd, function () use ($fd) { $r = inotify_read($fd); - dump($r); + Console::verbose("File updated: ".$r[0]["name"]); ZMUtil::reload(); }); } else { diff --git a/src/ZM/Event/SwooleEvent/OnWorkerStart.php b/src/ZM/Event/SwooleEvent/OnWorkerStart.php index e58f0933..dc375960 100644 --- a/src/ZM/Event/SwooleEvent/OnWorkerStart.php +++ b/src/ZM/Event/SwooleEvent/OnWorkerStart.php @@ -33,7 +33,6 @@ use ZM\Store\MySQL\SqlPoolStorage; use ZM\Store\Redis\ZMRedisPool; use ZM\Utils\DataProvider; use ZM\Utils\ProcessManager; -use ZM\Utils\ZMUtil; /** * Class OnWorkerStart @@ -43,15 +42,19 @@ use ZM\Utils\ZMUtil; class OnWorkerStart implements SwooleEvent { public function onCall(Server $server, $worker_id) { - Process::signal(SIGINT, function () use ($worker_id, $server) { + if (!Framework::$argv["disable-safe-exit"]) { + Process::signal(SIGINT, function () use ($worker_id, $server) { - }); + }); + } unset(Context::$context[Coroutine::getCid()]); if ($server->taskworker === false) { - Process::signal(SIGUSR1, function () use ($worker_id) { - Timer::clearAll(); - ProcessManager::resumeAllWorkerCoroutines(); - }); + if (!Framework::$argv["disable-safe-exit"]) { + Process::signal(SIGUSR1, function () use ($worker_id) { + Timer::clearAll(); + ProcessManager::resumeAllWorkerCoroutines(); + }); + } zm_atomic("_#worker_" . $worker_id)->set($server->worker_pid); if (LightCacheInside::get("wait_api", "wait_api") !== null) { LightCacheInside::unset("wait_api", "wait_api"); @@ -84,7 +87,7 @@ class OnWorkerStart implements SwooleEvent } Console::info("新建SQL连接池中"); ob_start(); - phpinfo(); + phpinfo(); //这个phpinfo是有用的,不能删除 $str = ob_get_clean(); $str = explode("\n", $str); foreach ($str as $k => $v) { @@ -130,7 +133,7 @@ class OnWorkerStart implements SwooleEvent $dispatcher->dispatchEvents($server, $worker_id); if ($dispatcher->status === EventDispatcher::STATUS_NORMAL) Console::debug("@OnStart 执行完毕"); else Console::warning("@OnStart 执行异常!"); - Console::success("Worker #" . $worker_id . " 已启动"); + Console::success("Worker #" . $worker_id . " started"); } catch (Exception $e) { Console::error("Worker加载出错!停止服务!"); Console::error($e->getMessage() . "\n" . $e->getTraceAsString()); @@ -147,7 +150,7 @@ class OnWorkerStart implements SwooleEvent try { Framework::$server = $server; $this->loadAnnotations(); - Console::success("TaskWorker #" . $server->worker_id . " 已启动"); + Console::success("TaskWorker #" . $server->worker_id . " started"); } catch (Exception $e) { Console::error("Worker加载出错!停止服务!"); Console::error($e->getMessage() . "\n" . $e->getTraceAsString()); diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index 2bf72bbb..a55974fa 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -7,6 +7,8 @@ namespace ZM; use Doctrine\Common\Annotations\AnnotationReader; use Error; use Exception; +use Swoole\Event; +use Swoole\Process; use Swoole\Server\Port; use ZM\Annotation\Swoole\OnSetup; use ZM\Config\ZMConfig; @@ -109,6 +111,7 @@ class Framework $out["environment"] = $args["env"] === null ? "default" : $args["env"]; $out["log_level"] = Console::getLevel(); $out["version"] = ZM_VERSION . (LOAD_MODE == 0 ? (" (build " . ZM_VERSION_ID . ")") : ""); + $out["master_pid"] = posix_getpid(); if (APP_VERSION !== "unknown") $out["app_version"] = APP_VERSION; if (isset($this->server_set["task_worker_num"])) { $out["task_worker"] = $this->server_set["task_worker_num"]; @@ -135,7 +138,9 @@ class Framework $out["working_dir"] = DataProvider::getWorkingDir(); self::printProps($out, $tty_width, $args["log-theme"] === null); - + if ($args["preview"]) { + exit(); + } self::$server = new Server(ZMConfig::get("global", "host"), ZMConfig::get("global", "port")); if ($add_port) { @@ -297,47 +302,88 @@ class Framework * @throws ReflectionException */ private function registerServerEvents() { - $event_list = []; $reader = new AnnotationReader(); - + global $master_events; + $master_events = [ + "setup" => [], + "event" => [] + ]; $all = getAllClasses(FRAMEWORK_ROOT_DIR . "/src/ZM/Event/SwooleEvent/", "ZM\\Event\\SwooleEvent"); foreach ($all as $v) { $class = new $v(); $reflection_class = new ReflectionClass($class); $anno_class = $reader->getClassAnnotation($reflection_class, SwooleHandler::class); if ($anno_class !== null) { // 类名形式的注解 - $anno_class->class = $v; - $anno_class->method = "onCall"; - $event_list[strtolower($anno_class->event)] = $anno_class; + $master_events["event"][]=[ + "class" => $v, + "method" => "onCall", + "event" => $anno_class->event + ]; } } - $all_event_class = ZMConfig::get("global", "server_event_handler_class") ?? []; - foreach ($all_event_class as $v) { - $reflection_class = new ReflectionClass($v); - $methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC); - foreach ($methods as $vs) { - $method_annotations = $reader->getMethodAnnotations($vs); - if ($method_annotations != []) { - $annotation = $method_annotations[0]; - if ($annotation instanceof SwooleHandler) { - $annotation->class = $v; - $annotation->method = $vs->getName(); - $event_list[strtolower($annotation->event)] = $annotation; - } elseif ($annotation instanceof OnSetup) { - $annotation->class = $v; - $annotation->method = $vs->getName(); - $c = new $v(); - $m = $annotation->method; - $c->$m(); + $base_path = DataProvider::getWorkingDir(); + $scan_paths = []; + $composer = json_decode(file_get_contents(DataProvider::getWorkingDir() . "/composer.json"), true); + foreach (($composer["autoload"]["psr-4"] ?? []) as $k => $v) { + if (is_dir($base_path."/".$v) && !in_array($v, $composer["extra"]["exclude_annotate"] ?? [])) { + $scan_paths[trim($k, "\\")]=realpath($base_path."/".$v); + } + } + $all_event_class = []; + foreach($scan_paths as $namespace => $autoload_path) { + $all_event_class = array_merge($all_event_class, getAllClasses($autoload_path."/", $namespace)); + } + $process = new Process(function(Process $process) use ($all_event_class) { + $reader = new AnnotationReader(); + $event_list = []; + $setup_list = []; + foreach ($all_event_class as $v) { + $reflection_class = new ReflectionClass($v); + $methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC); + foreach ($methods as $vs) { + $method_annotations = $reader->getMethodAnnotations($vs); + if ($method_annotations != []) { + $annotation = $method_annotations[0]; + if ($annotation instanceof SwooleHandler) { + $event_list[]=[ + "class" => $v, + "method" => $vs->getName(), + "event" => $annotation->event + ]; + } elseif ($annotation instanceof OnSetup) { + $setup_list[]=[ + "class" => $v, + "method" => $vs->getName() + ]; + } } } } + $sock = $process->exportSocket(); + $sock->send(json_encode(["setup" => $setup_list, "event" => $event_list])); + }); + $process->start(); + go(function() use ($process) { + $socket = $process->exportSocket(); + global $master_events; + $obj = json_decode($socket->recv(), true); + if ($obj["setup"] != []) $master_events["setup"] = array_merge($master_events["setup"], $obj["setup"]); + if ($obj["event"] != []) $master_events["event"] = array_merge($master_events["event"], $obj["event"]); + }); + Process::wait(true); + Event::wait(); + + foreach($master_events["setup"] as $k => $v) { + $c = ZMUtil::getModInstance($v["class"]); + $method = $v["method"]; + $c->$method(); } - foreach ($event_list as $k => $v) { - $c = ZMUtil::getModInstance($v->class); - $m = $v->method; - self::$server->on($k, function (...$param) use ($c, $m) { $c->$m(...$param); }); + + foreach ($master_events["event"] as $k => $v) { + self::$server->on($v["event"], function (...$param) use ($k, $v) { + ZMUtil::getModInstance($v["class"])->{$v["method"]}(...$param); + }); } } @@ -374,7 +420,8 @@ class Framework case 'debug-mode': $coroutine_mode = false; $terminal_id = null; - Console::warning("You are in debug mode, do not use in production!"); + self::$argv["watch"] = true; + echo ("* You are in debug mode, do not use in production!\n"); break; case 'daemon': $this->server_set["daemonize"] = 1; diff --git a/src/entry.php b/src/entry.php new file mode 100644 index 00000000..9dd3cff1 --- /dev/null +++ b/src/entry.php @@ -0,0 +1,5 @@ +initEnv()->run(); \ No newline at end of file diff --git a/zhamao b/zhamao index 37879438..9dce209a 100755 --- a/zhamao +++ b/zhamao @@ -1,4 +1,22 @@ -#!/usr/bin/env php -initEnv("server")->run(); +#!/bin/sh + +if [ -f "$(pwd)/runtime/php" ]; then + executable="$(pwd)/runtime/php" +else + which php >/dev/null 2>&1 + if [ $? -eq 0 ]; then + executable=$(which php) + else + echo 'Cannot find any PHP runtime, please use command `./install-runtime.sh` or install PHP manually!' + exit 1 + fi +fi + +if [ -f "$(pwd)/src/entry.php" ]; then + $executable "$(pwd)/src/entry.php" $@ +elif [ -f "$(pwd)/vendor/zhamao/framework/src/entry.php" ]; then + $executable "$(pwd)/vendor/zhamao/framework/src/entry.php" $@ +else + echo "Cannot find zhamao-framework entry file!" + exit 1 +fi \ No newline at end of file