Compare commits

...

9 Commits

Author SHA1 Message Date
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
14 changed files with 275 additions and 39 deletions

View File

@@ -37,11 +37,9 @@
"php": "^7.2 || ^7.3 || ^7.4 || ^8.0 || ^8.1",
"ext-json": "*",
"ext-posix": "*",
"doctrine/annotations": "~1.12 || ~1.4.0",
"doctrine/dbal": "^2.13.1",
"jelix/version": "^2.0",
"koriym/attributes": "^1.0",
"league/climate": "^3.6",
"psy/psysh": "^0.11.2",
"symfony/console": "~5.0 || ~4.0 || ~3.0",
"symfony/polyfill-ctype": "^1.19",

View File

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

View File

@@ -73,6 +73,6 @@
| E00071 | 框架找不到对应类型的 API 调用类 | 检查 `getExtendedAPI($name)` 传入的 `$name` 是否正确 |
| E00072 | 上下文无法找到 | 检查上下文环境,如是否处于协程环境中 |
| E00073 | 在类中找不到方法 | 检查调用对象是否存在对应的方法method或检查是否插入了对应的macro宏方法 |
| E00073 | 参数非法 | 检查调用的参数是否正常(此处可能有多处问题,请看具体调用栈炸掉的地方) |
| E00074 | 参数非法 | 检查调用的参数是否正常(此处可能有多处问题,请看具体调用栈炸掉的地方) |
| E99999 | 未知错误 | |

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,6 +24,7 @@ use ZM\Console\Console;
use ZM\Exception\AnnotationException;
use ZM\Utils\Manager\RouteManager;
use ZM\Utils\ZMUtil;
use function server;
class AnnotationParser
{
@@ -65,6 +66,19 @@ class AnnotationParser
foreach ($this->path_list as $path) {
Console::debug('parsing annotation in ' . $path[0] . ':' . $path[1]);
$all_class = ZMUtil::getClassesPsr4($path[0], $path[1]);
$conf = ZMConfig::get('global', 'runtime')['annotation_reader_ignore'] ?? [];
if (isset($conf['name']) && is_array($conf['name'])) {
foreach ($conf['name'] as $v) {
AnnotationReader::addGlobalIgnoredName($v);
}
}
if (isset($conf['namespace']) && is_array($conf['namespace'])) {
foreach ($conf['namespace'] as $v) {
AnnotationReader::addGlobalIgnoredNamespace($v);
}
}
AnnotationReader::addGlobalIgnoredName('mixin');
$this->reader = new DualReader(new AnnotationReader(), new AttributeReader());
foreach ($all_class as $v) {
Console::debug('正在检索 ' . $v);
@@ -198,6 +212,9 @@ class AnnotationParser
*/
public function addRegisterPath($path, $indoor_name)
{
if (server()->worker_id === 0) {
Console::verbose('Add register path: ' . $path . ' => ' . $indoor_name);
}
$this->path_list[] = [$path, $indoor_name];
}

View File

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

View File

@@ -79,6 +79,25 @@ class ModuleListCommand extends Command
if ($list === []) {
echo Console::setColor('没有发现已打包且装载的模块!', 'yellow') . PHP_EOL;
}
$list = ModuleManager::getComposerModules();
foreach ($list as $v) {
echo '[' . Console::setColor($v['name'], 'blue') . ']' . PHP_EOL;
$out_list = ['类型' => 'Composer库(composer)'];
$out_list['包名'] = $v['composer-name'];
$out_list['目录'] = str_replace(DataProvider::getSourceRootDir() . '/', '', $v['module-path']);
if (isset($v['version'])) {
$out_list['版本'] = $v['version'];
}
if (isset($v['description'])) {
$out_list['描述'] = $v['description'];
}
$out_list['命名空间'] = $v['namespace'];
$this->printList($out_list);
}
if ($list === []) {
echo Console::setColor('没有发现Composer模块', 'yellow') . PHP_EOL;
}
return 0;
}

View File

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

View File

@@ -28,9 +28,9 @@ use ZM\Exception\InitException;
class ConsoleApplication extends Application
{
public const VERSION_ID = 444;
public const VERSION_ID = 449;
public const VERSION = '2.7.0-beta4';
public const VERSION = '2.7.2';
private static $obj;

View File

@@ -165,9 +165,6 @@ class OnWorkerStart implements SwooleEvent
if (trim($k, '\\') == 'ZM') {
continue;
}
if (\server()->worker_id == 0) {
Console::verbose('Add ' . $v . ":{$k} to register path");
}
$parser->addRegisterPath(DataProvider::getSourceRootDir() . '/' . $v . '/', trim($k, '\\'));
}
}
@@ -187,6 +184,15 @@ class OnWorkerStart implements SwooleEvent
}
}
// 检查所有的Composer模块并加载注解
$list = ModuleManager::getComposerModules();
foreach ($list as $k => $v) {
if (\server()->worker_id === 0) {
Console::info('Loading composer module: ' . $k);
}
$parser->addRegisterPath($v['module-path'], $v['namespace']);
}
$parser->registerMods();
EventManager::loadEventByParser($parser); // 加载事件

View File

@@ -111,6 +111,34 @@ class ModuleManager
return $modules;
}
public static function getComposerModules()
{
$vendor_file = DataProvider::getSourceRootDir() . '/vendor/composer/installed.json';
$obj = json_decode(file_get_contents($vendor_file), true);
if ($obj === null) {
return [];
}
$modules = [];
foreach ($obj['packages'] as $v) {
if (isset($v['extra']['zm']['module-path'])) {
if (is_array($v['extra']['zm']['module-path'])) {
foreach ($v['extra']['zm']['module-path'] as $module_path) {
$m = self::getComposerModuleInfo($v, $module_path);
if ($m !== null) {
$modules[$m['name']] = $m;
}
}
} elseif (is_string($v['extra']['zm']['module-path'])) {
$m = self::getComposerModuleInfo($v, $v['extra']['zm']['module-path']);
if ($m !== null) {
$modules[$m['name']] = $m;
}
}
}
}
return $modules;
}
/**
* 打包模块
* @param $module
@@ -152,4 +180,38 @@ class ModuleManager
return false;
}
}
private static function getComposerModuleInfo($v, $module_path)
{
$module_root_path = realpath(DataProvider::getSourceRootDir() . '/vendor/composer/' . $v['install-path'] . '/' . $module_path);
if ($module_root_path === false) {
Console::warning(zm_internal_errcode('E00055') . '无法找到Composer发布的插件配置路径在包 `' . $v['name'] . '` 中!');
return null;
}
$json = json_decode(file_get_contents($module_root_path . '/zm.json'), true);
if ($json === null) {
Console::warning(zm_internal_errcode('E00054') . 'Composer包内无法正常读取 ' . $v['name'] . ' 的内的配置文件zm.json');
return null;
}
if (!isset($json['name'])) {
return null;
}
$json['composer-name'] = $v['name'];
$json['module-root-path'] = realpath(DataProvider::getSourceRootDir() . '/vendor/composer/' . $v['install-path']);
$json['module-path'] = realpath($json['module-root-path'] . '/' . $module_path);
if (isset($v['autoload']['psr-4'])) {
foreach ($v['autoload']['psr-4'] as $ks => $vs) {
$vs = trim($vs, '/');
if (strpos($module_path, $vs) === 0) {
$json['namespace'] = trim($ks . str_replace('/', '\\', trim(substr($module_path, strlen($vs)), '/')), '\\');
break;
}
}
}
if (!isset($json['namespace'])) {
Console::warning(zm_internal_errcode('E00055') . '无法获取Composer发布的模块命名空间');
return null;
}
return $json;
}
}