update to 2.1.0 version

add @OnCloseEvent, @OnOpenEvent, @OnMessageEvent, @OnRequestEvent
update EventDispatcher.php and change it to status-based schema
fix @CQBefore bugs
This commit is contained in:
jerry 2021-01-02 13:15:50 +08:00
parent 7434bac94e
commit 6337b626d6
22 changed files with 318 additions and 136 deletions

View File

@ -3,8 +3,12 @@
"description": "High performance QQ robot and web server development framework",
"minimum-stability": "stable",
"license": "Apache-2.0",
"version": "2.0.3",
"extra": [],
"version": "2.1.0",
"extra": {
"exclude_annotate": [
"src/ZM"
]
},
"authors": [
{
"name": "whale",
@ -41,7 +45,9 @@
},
"autoload": {
"psr-4": {
"ZM\\": "src/ZM"
"ZM\\": "src/ZM",
"Module\\": "src/Module",
"Custom\\": "src/Custom"
},
"files": [
"src/ZM/global_functions.php"

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

View File

@ -1,4 +1,4 @@
<?php
<?php #plain
//这里写你的全局函数
function pgo(callable $func, $name = "default") {

View File

@ -3,13 +3,14 @@
namespace Module\Example;
use ZM\Annotation\Http\Middleware;
use ZM\Annotation\Swoole\OnSwooleEvent;
use ZM\Annotation\Swoole\OnCloseEvent;
use ZM\Annotation\Swoole\OnOpenEvent;
use ZM\Annotation\Swoole\OnRequestEvent;
use ZM\ConnectionManager\ConnectionObject;
use ZM\Console\Console;
use ZM\Annotation\CQ\CQCommand;
use ZM\Annotation\Http\RequestMapping;
use ZM\Event\EventDispatcher;
use ZM\Store\Redis\ZMRedis;
use ZM\Utils\ZMUtil;
/**
@ -19,29 +20,6 @@ use ZM\Utils\ZMUtil;
*/
class Hello
{
/**
* 一个简单的redis连接池使用demo将下方user_id改为你自己的QQ号即可(为了不被不法分子利用)
* @CQCommand("redis_test",user_id=627577391)
*/
public function testCase() {
$a = new ZMRedis();
$redis = $a->get();
$r1 = ctx()->getArgs(ZM_MATCH_FIRST, "请说出你想设置的操作[r/w]");
switch ($r1) {
case "r":
$k = ctx()->getArgs(ZM_MATCH_FIRST, "请说出你想读取的键名");
$result = $redis->get($k);
ctx()->reply("结果:" . $result);
break;
case "w":
$k = ctx()->getArgs(ZM_MATCH_FIRST, "请说出你想写入的键名");
$v = ctx()->getArgs(ZM_MATCH_FIRST, "请说出你想写入的字符串");
$result = $redis->set($k, $v);
ctx()->reply("结果:" . ($result ? "成功" : "失败"));
break;
}
}
/**
* 使用命令 .reload 发给机器人远程重载,注意将 user_id 换成你自己的 QQ
* @CQCommand(".reload",user_id=627577391)
@ -116,7 +94,7 @@ class Hello
/**
* 在机器人连接后向终端输出信息
* @OnSwooleEvent("open",rule="connectIsQQ()")
* @OnOpenEvent("qq")
* @param $conn
*/
public function onConnect(ConnectionObject $conn) {
@ -125,7 +103,7 @@ class Hello
/**
* 在机器人断开连接后向终端输出信息
* @OnSwooleEvent("close",rule="connectIsQQ()")
* @OnCloseEvent("qq")
* @param ConnectionObject $conn
*/
public function onDisconnect(ConnectionObject $conn) {
@ -134,7 +112,7 @@ class Hello
/**
* 阻止 Chrome 自动请求 /favicon.ico 导致的多条请求并发和干扰
* @OnSwooleEvent("request",rule="ctx()->getRequest()->server['request_uri'] == '/favicon.ico'",level=200)
* @OnRequestEvent(rule="ctx()->getRequest()->server['request_uri'] == '/favicon.ico'",level=200)
*/
public function onRequest() {
EventDispatcher::interrupt();
@ -142,7 +120,7 @@ class Hello
/**
* 框架会默认关闭未知的WebSocket链接因为这个绑定的事件你可以根据你自己的需求进行修改
* @OnSwooleEvent(type="open",rule="connectIsDefault()")
* @OnOpenEvent("default")
*/
public function closeUnknownConn() {
Console::info("Unknown connection , I will close it.");

View File

@ -2,6 +2,7 @@
namespace Module\Middleware;
use Exception;
use ZM\Annotation\Http\HandleAfter;
use ZM\Annotation\Http\HandleBefore;
use ZM\Annotation\Http\HandleException;
@ -37,8 +38,11 @@ class TimerMiddleware implements MiddlewareInterface
/**
* @HandleException(\Exception::class)
* @param Exception $e
* @throws Exception
*/
public function onException() {
public function onException(Exception $e) {
Console::error("Using " . round((microtime(true) - $this->starttime) * 1000, 2) . " ms but an Exception occurred.");
throw $e;
}
}

View File

@ -33,7 +33,7 @@ class AnnotationParser
*/
public function __construct() {
$this->start_time = microtime(true);
$this->loadAnnotationClasses();
//$this->loadAnnotationClasses();
$this->req_mapping[0] = [
'id' => 0,
'pid' => -1,
@ -100,7 +100,7 @@ class AnnotationParser
unset($this->annotation_map[$v]);
continue 2;
} elseif ($vs instanceof MiddlewareClass) {
Console::verbose("正在注册中间件 " . $reflection_class->getName());
Console::debug("正在注册中间件 " . $reflection_class->getName());
$rs = $this->registerMiddleware($vs, $reflection_class);
$this->middlewares[$rs["name"]] = $rs;
}
@ -297,7 +297,7 @@ class AnnotationParser
return $result;
}
private function sortByLevel(&$events, string $class_name, $prefix = "") {
public function sortByLevel(&$events, string $class_name, $prefix = "") {
if (is_a($class_name, Level::class, true)) {
$class_name .= $prefix;
usort($events[$class_name], function ($a, $b) {

View File

@ -0,0 +1,22 @@
<?php
namespace ZM\Annotation\Swoole;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\Interfaces\Rule;
/**
* @Annotation
* @Target("METHOD")
* Class OnCloseEvent
* @package ZM\Annotation\Swoole
*/
class OnCloseEvent extends OnSwooleEventBase
{
/**
* @var string
*/
public $connect_type = "default";
}

View File

@ -0,0 +1,21 @@
<?php
namespace ZM\Annotation\Swoole;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @Target("METHOD")
* Class OnMessageEvent
* @package ZM\Annotation\Swoole
*/
class OnMessageEvent extends OnSwooleEventBase
{
/**
* @var string
*/
public $connect_type = "default";
}

View File

@ -0,0 +1,21 @@
<?php
namespace ZM\Annotation\Swoole;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @Target("METHOD")
* Class OnOpenEvent
* @package ZM\Annotation\Swoole
*/
class OnOpenEvent extends OnSwooleEventBase
{
/**
* @var string
*/
public $connect_type = "default";
}

View File

@ -0,0 +1,17 @@
<?php
namespace ZM\Annotation\Swoole;
use Doctrine\Common\Annotations\Annotation\Target;
/**
* @Annotation
* @Target("METHOD")
* Class OnRequestEvent
* @package ZM\Annotation\Swoole
*/
class OnRequestEvent extends OnSwooleEventBase
{
}

View File

@ -10,7 +10,7 @@ use ZM\Annotation\AnnotationBase;
* Class OnWorkerStart
* @package ZM\Annotation\Swoole
* @Annotation
* @Target("ALL")
* @Target("METHOD")
*/
class OnStart extends AnnotationBase
{

View File

@ -5,17 +5,14 @@ namespace ZM\Annotation\Swoole;
use Doctrine\Common\Annotations\Annotation\Required;
use Doctrine\Common\Annotations\Annotation\Target;
use ZM\Annotation\AnnotationBase;
use ZM\Annotation\Interfaces\Level;
use ZM\Annotation\Interfaces\Rule;
/**
* Class OnSwooleEvent
* @Annotation
* @Target("ALL")
* @Target("METHOD")
* @package ZM\Annotation\Swoole
*/
class OnSwooleEvent extends AnnotationBase implements Rule, Level
class OnSwooleEvent extends OnSwooleEventBase
{
/**
* @var string
@ -23,14 +20,6 @@ class OnSwooleEvent extends AnnotationBase implements Rule, Level
*/
public $type;
/** @var string */
public $rule = "";
/** @var int */
public $level = 20;
public $callback = null;
/**
* @return string
*/
@ -44,33 +33,4 @@ class OnSwooleEvent extends AnnotationBase implements Rule, Level
public function setType(string $type) {
$this->type = $type;
}
/**
* @return string
*/
public function getRule(): string {
return $this->rule;
}
/**
* @param string $rule
*/
public function setRule(string $rule) {
$this->rule = $rule;
}
/**
* @return int
*/
public function getLevel(): int {
return $this->level;
}
/**
* @param int $level
*/
public function setLevel(int $level) {
$this->level = $level;
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace ZM\Annotation\Swoole;
use ZM\Annotation\AnnotationBase;
use ZM\Annotation\Interfaces\Level;
use ZM\Annotation\Interfaces\Rule;
abstract class OnSwooleEventBase extends AnnotationBase implements Level, Rule
{
/**
* @var string
*/
public $rule = "";
/**
* @var int
*/
public $level = 20;
/**
* @return string
*/
public function getRule(): string {
return $this->rule !== "" ? $this->rule : true;
}
/**
* @param string $rule
*/
public function setRule(string $rule) {
$this->rule = $rule;
}
/**
* @return int
*/
public function getLevel(): int {
return $this->level;
}
/**
* @param int $level
*/
public function setLevel(int $level) {
$this->level = $level;
}
}

View File

@ -5,8 +5,8 @@ namespace ZM\Event;
use Doctrine\Common\Annotations\AnnotationException;
use Error;
use Exception;
use ZM\Annotation\AnnotationBase;
use ZM\Console\Console;
use ZM\Exception\InterruptException;
use ZM\Exception\ZMException;
@ -17,6 +17,12 @@ use ZM\Utils\ZMUtil;
class EventDispatcher
{
const STATUS_NORMAL = 0; //正常结束
const STATUS_INTERRUPTED = 1; //被interrupt了不管在什么地方
const STATUS_EXCEPTION = 2; //执行过程中抛出了异常
const STATUS_BEFORE_FAILED = 3; //中间件HandleBefore返回了false所以不执行此方法
const STATUS_RULE_FAILED = 4; //判断事件执行的规则函数判定为false所以不执行此方法
/** @var string */
private $class;
/** @var null|callable */
@ -27,6 +33,10 @@ class EventDispatcher
private $log = false;
/** @var int */
private $eid = 0;
/** @var int */
public $status = self::STATUS_NORMAL;
/** @var mixed */
public $store = null;
/**
* @param null $return_var
@ -74,41 +84,53 @@ class EventDispatcher
return $this;
}
/**
* @param mixed ...$params
* @throws Exception
* @throws InterruptException
*/
public function dispatchEvents(...$params) {
try {
foreach ((EventManager::$events[$this->class] ?? []) as $v) {
$result = $this->dispatchEvent($v, $this->rule, ...$params);
$this->dispatchEvent($v, $this->rule, ...$params);
if ($this->log) Console::verbose("[事件分发{$this->eid}] 单一对象 " . $v->class . "::" . $v->method . " 分发结束。");
if ($result !== false && is_callable($this->return_func)) {
if($this->status == self::STATUS_BEFORE_FAILED || $this->status == self::STATUS_RULE_FAILED) continue;
if (is_callable($this->return_func) && $this->status === self::STATUS_NORMAL) {
if ($this->log) Console::verbose("[事件分发{$this->eid}] 单一对象 " . $v->class . "::" . $v->method . " 正在执行返回值处理函数 ...");
($this->return_func)($result);
($this->return_func)($this->store);
}
}
return true;
if($this->status === self::STATUS_RULE_FAILED) $this->status = self::STATUS_NORMAL;
} catch (InterruptException $e) {
return $e->return_var;
} catch (AnnotationException $e) {
return false;
$this->store = $e->return_var;
$this->status = self::STATUS_INTERRUPTED;
} catch (Exception $e) {
$this->status = self::STATUS_EXCEPTION;
throw $e;
} catch (Error $e) {
$this->status = self::STATUS_EXCEPTION;
throw $e;
}
}
/**
* @param AnnotationBase|null $v
* @param mixed $v
* @param null $rule_func
* @param mixed ...$params
* @throws AnnotationException
* @throws InterruptException
* @return mixed
* @return bool
*/
public function dispatchEvent(?AnnotationBase $v, $rule_func = null, ...$params) {
public function dispatchEvent($v, $rule_func = null, ...$params) {
$q_c = $v->class;
$q_f = $v->method;
if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在判断 " . $q_c . "::" . $q_f . " 方法下的 rule ...");
if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在判断 " . $q_c . "::" . $q_f . " 方法下的 ruleFunc ...");
if ($rule_func !== null && !$rule_func($v)) {
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法下的 rule 判断为 false, 拒绝执行此方法。");
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法下的 ruleFunc 判断为 false, 拒绝执行此方法。");
$this->status = self::STATUS_RULE_FAILED;
return false;
}
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法下的 rule 为真,继续执行方法本身 ...");
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法下的 ruleFunc 为真,继续执行方法本身 ...");
if (isset(EventManager::$middleware_map[$q_c][$q_f])) {
$middlewares = EventManager::$middleware_map[$q_c][$q_f];
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法还绑定了 Middleware" . implode(", ", $middlewares));
@ -138,7 +160,7 @@ class EventDispatcher
try {
$q_o = ZMUtil::getModInstance($q_c);
if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在执行方法 " . $q_c . "::" . $q_f . " ...");
$result = $q_o->$q_f(...$params);
$this->store = $q_o->$q_f(...$params);
} catch (Exception $e) {
if ($e instanceof InterruptException) {
if ($this->log) Console::verbose("[事件分发{$this->eid}] 检测到事件阻断调用,正在跳出事件分发器 ...");
@ -166,13 +188,17 @@ class EventDispatcher
if ($this->log) Console::verbose("[事件分发{$this->eid}] Middleware 后置事件执行完毕!");
}
}
return $result;
$this->status = self::STATUS_NORMAL;
return true;
}
$this->status = self::STATUS_BEFORE_FAILED;
return false;
} else {
$q_o = ZMUtil::getModInstance($q_c);
if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在执行方法 " . $q_c . "::" . $q_f . " ...");
return $q_o->$q_f(...$params);
$this->store = $q_o->$q_f(...$params);
$this->status = self::STATUS_NORMAL;
return true;
}
}
}

View File

@ -22,6 +22,7 @@ class EventManager
public static function addEvent($event_name, ?AnnotationBase $event_obj) {
self::$events[$event_name][] = $event_obj;
(new AnnotationParser())->sortByLevel(self::$events, $event_name);
}
public static function loadEventByParser(AnnotationParser $parser) {

View File

@ -9,6 +9,7 @@ use Error;
use Exception;
use PDO;
use ReflectionException;
use Swoole\Coroutine;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Event;
@ -16,6 +17,10 @@ use Swoole\Process;
use Swoole\Timer;
use ZM\Annotation\AnnotationParser;
use ZM\Annotation\Http\RequestMapping;
use ZM\Annotation\Swoole\OnCloseEvent;
use ZM\Annotation\Swoole\OnMessageEvent;
use ZM\Annotation\Swoole\OnOpenEvent;
use ZM\Annotation\Swoole\OnRequestEvent;
use ZM\Annotation\Swoole\OnStart;
use ZM\Annotation\Swoole\OnSwooleEvent;
use ZM\Config\ZMConfig;
@ -70,6 +75,40 @@ class ServerEventHandler
/** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify);
ZMUtil::stop();
});
set_error_handler(function ($error_no, $error_msg, $error_file, $error_line) {
switch ($error_no) {
case E_WARNING:
$level_tips = 'PHP Warning: ';
break;
case E_NOTICE:
$level_tips = 'PHP Notice: ';
break;
case E_DEPRECATED:
$level_tips = 'PHP Deprecated: ';
break;
case E_USER_ERROR:
$level_tips = 'User Error: ';
break;
case E_USER_WARNING:
$level_tips = 'User Warning: ';
break;
case E_USER_NOTICE:
$level_tips = 'User Notice: ';
break;
case E_USER_DEPRECATED:
$level_tips = 'User Deprecated: ';
break;
case E_STRICT:
$level_tips = 'PHP Strict: ';
break;
default:
$level_tips = 'Unkonw Type Error: ';
break;
} // do some handle
$error = $level_tips . $error_msg . ' in ' . $error_file . ' on ' . $error_line;
Console::warning($error); // 如果 return false 则错误会继续递交给 PHP 标准错误处理 /
return true;
}, E_ALL | E_STRICT);
if (Framework::$argv["watch"]) {
if (extension_loaded('inotify')) {
Console::warning("Enabled File watcher, do not use in production.");
@ -114,7 +153,7 @@ class ServerEventHandler
Console::debug("正在关闭 " . ($server->taskworker ? "Task" : "") . "Worker 进程 " . Console::setColor("#" . \server()->worker_id, "gold") . TermColor::frontColor256(59) . ", pid=" . posix_getpid());
server()->stop($worker_id);
});
unset(Context::$context[Co::getCid()]);
unset(Context::$context[Coroutine::getCid()]);
if ($server->taskworker === false) {
try {
register_shutdown_function(function () use ($server) {
@ -211,7 +250,8 @@ class ServerEventHandler
return server()->worker_id === $v->worker_id || $v->worker_id === -1;
});
$dispatcher->dispatchEvents($server, $worker_id);
Console::debug("@OnStart 执行完毕");
if ($dispatcher->status === EventDispatcher::STATUS_NORMAL) Console::debug("@OnStart 执行完毕");
else Console::warning("@OnStart 执行异常!");
} catch (Exception $e) {
Console::error("Worker加载出错停止服务");
Console::error($e->getMessage() . "\n" . $e->getTraceAsString());
@ -251,9 +291,15 @@ class ServerEventHandler
public function onMessage($server, Frame $frame) {
Console::debug("Calling Swoole \"message\" from fd=" . $frame->fd.": ".TermColor::ITALIC.$frame->data.TermColor::RESET);
unset(Context::$context[Co::getCid()]);
unset(Context::$context[\Swoole\Coroutine::getCid()]);
$conn = ManagerGM::get($frame->fd);
set_coroutine_params(["server" => $server, "frame" => $frame, "connection" => $conn]);
$dispatcher1 = new EventDispatcher(OnMessageEvent::class);
$dispatcher1->setRuleFunction(function($v) {
return ctx()->getConnection()->getName() == $v->connect_type && eval("return " . $v->getRule() . ";");
});
$dispatcher = new EventDispatcher(OnSwooleEvent::class);
$dispatcher->setRuleFunction(function ($v) {
if ($v->getRule() == '') {
@ -268,6 +314,7 @@ class ServerEventHandler
});
try {
//$starttime = microtime(true);
$dispatcher1->dispatchEvents($conn);
$dispatcher->dispatchEvents($conn);
//Console::success("Used ".round((microtime(true) - $starttime) * 1000, 3)." ms!");
} catch (Exception $e) {
@ -293,6 +340,11 @@ class ServerEventHandler
Console::debug("Calling Swoole \"request\" event from fd=" . $request->fd);
set_coroutine_params(["request" => $request, "response" => $response]);
$dis1 = new EventDispatcher(OnRequestEvent::class);
$dis1->setRuleFunction(function($v) {
return eval("return ".$v->getRule().";") ? true : false;
});
$dis = new EventDispatcher(OnSwooleEvent::class);
$dis->setRuleFunction(function ($v) {
if ($v->getRule() == '') {
@ -305,8 +357,10 @@ class ServerEventHandler
});
try {
$no_interrupt = $dis->dispatchEvents($request, $response);
if ($no_interrupt !== null) {
$dis1->dispatchEvents($request, $response);
$dis->dispatchEvents($request, $response);
var_dump($dis->status);
if ($dis->status === EventDispatcher::STATUS_NORMAL && $dis1->status === EventDispatcher::STATUS_NORMAL) {
$result = HttpUtil::parseUri($request, $response, $request->server["request_uri"], $node, $params);
if ($result === true) {
ctx()->setCache("params", $params);
@ -318,8 +372,8 @@ class ServerEventHandler
$div->request_method = $node["request_method"];
$div->class = $node["class"];
//Console::success("正在执行路由:".$node["method"]);
$r = $dispatcher->dispatchEvent($div, null, $params, $request, $response);
if (is_string($r) && !$response->isEnd()) $response->end($r);
$dispatcher->dispatchEvent($div, null, $params, $request, $response);
if (is_string($dispatcher->store) && !$response->isEnd()) $response->end($dispatcher->store);
}
}
if (!$response->isEnd()) {
@ -371,6 +425,11 @@ class ServerEventHandler
set_coroutine_params(["server" => $server, "request" => $request, "connection" => $conn, "fd" => $request->fd]);
$conn->setOption("connect_id", strval($request->header["x-self-id"] ?? ""));
$dispatcher1 = new EventDispatcher(OnOpenEvent::class);
$dispatcher1->setRuleFunction(function($v) {
return ctx()->getConnection()->getName() == $v->connect_type && eval("return ".$v->getRule().";");
});
$dispatcher = new EventDispatcher(OnSwooleEvent::class);
$dispatcher->setRuleFunction(function ($v) {
if ($v->getRule() == '') {
@ -387,6 +446,7 @@ class ServerEventHandler
LightCacheInside::set("connect", "conn_fd", $request->fd);
}
}
$dispatcher1->dispatchEvents($conn);
$dispatcher->dispatchEvents($conn);
} catch (Exception $e) {
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
@ -412,6 +472,10 @@ class ServerEventHandler
Console::debug("Calling Swoole \"close\" event from fd=" . $fd);
set_coroutine_params(["server" => $server, "connection" => $conn, "fd" => $fd]);
$dispatcher1 = new EventDispatcher(OnCloseEvent::class);
$dispatcher1->setRuleFunction(function($v){
return $v->connect_type == ctx()->getConnection()->getName() && eval("return " . $v->getRule() . ";");
});
$dispatcher = new EventDispatcher(OnSwooleEvent::class);
$dispatcher->setRuleFunction(function ($v) {
@ -429,6 +493,7 @@ class ServerEventHandler
LightCacheInside::set("connect", "conn_fd", -1);
}
}
$dispatcher1->dispatchEvents($conn);
$dispatcher->dispatchEvents($conn);
} catch (Exception $e) {
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
@ -505,7 +570,16 @@ class ServerEventHandler
//加载各个模块的注解类,以及反射
Console::debug("检索Module中");
$parser = new AnnotationParser();
$parser->addRegisterPath(DataProvider::getWorkingDir() . "/src/Module/", "Module");
$path = DataProvider::getWorkingDir()."/src/";
$dir = scandir($path);
unset($dir[0], $dir[1]);
$composer = json_decode(file_get_contents(__DIR__."/../../../composer.json"), true);
foreach($dir as $v) {
if(is_dir($path."/".$v) && isset($composer["autoload"]["psr-4"][$v."\\"]) && !in_array($composer["autoload"]["psr-4"][$v."\\"], $composer["extra"]["exclude_annotate"])) {
Console::verbose("Add ".$v . " to register path");
$parser->addRegisterPath(DataProvider::getWorkingDir()."/src/".$v."/", $v);
}
}
$parser->registerMods();
EventManager::loadEventByParser($parser); //加载事件
@ -518,14 +592,14 @@ class ServerEventHandler
//加载插件
$plugins = ZMConfig::get("global", "modules") ?? [];
if (!isset($plugins["onebot"])) $plugins["onebot"] = ["status" => true, "single_bot_mode" => false];
if (!isset($plugins["onebot"])) $plugins["onebot"] = ["status" => true, "single_bot_mode" => false, "message_level" => 99999];
if ($plugins["onebot"]) {
$obj = new OnSwooleEvent();
$obj->class = QQBot::class;
$obj->method = 'handle';
$obj->type = 'message';
$obj->level = 99999;
$obj->level = $plugins["onebot"]["message_level"] ?? 99999;
$obj->rule = 'connectIsQQ()';
EventManager::addEvent(OnSwooleEvent::class, $obj);
if ($plugins["onebot"]["single_bot_mode"]) {
@ -536,7 +610,6 @@ class ServerEventHandler
}
//TODO: 编写加载外部插件的方式
$this->loadExternalModules($plugins);
}
private function addWatcher($maindir, $fd) {
@ -550,11 +623,4 @@ class ServerEventHandler
}
}
}
private function loadExternalModules($plugins) {
foreach ($plugins as $k => $v) {
if ($k == "onebot") continue;
}
}
}

View File

@ -55,9 +55,9 @@ class Framework
ZMAtomic::init();
try {
$sw = ZMConfig::get("global");
if(!is_dir($sw["zm_data"])) mkdir($sw["zm_data"]);
if(!is_dir($sw["config_dir"])) mkdir($sw["config_dir"]);
if(!is_dir($sw["crash_dir"])) mkdir($sw["crash_dir"]);
if (!is_dir($sw["zm_data"])) mkdir($sw["zm_data"]);
if (!is_dir($sw["config_dir"])) mkdir($sw["config_dir"]);
if (!is_dir($sw["crash_dir"])) mkdir($sw["crash_dir"]);
ManagerGM::init(ZMConfig::get("global", "swoole")["max_connection"] ?? 2048, 0.5, [
[
"key" => "connect_id",
@ -174,11 +174,9 @@ class Framework
}
}
foreach ($event_list as $k => $v) {
self::$server->on($k, function (...$param) use ($v) {
$c = ZMUtil::getModInstance($v->class);
$m = $v->method;
$c->$m(...$param);
});
$c = ZMUtil::getModInstance($v->class);
$m = $v->method;
self::$server->on($k, function (...$param) use ($c, $m) { $c->$m(...$param); });
}
}

View File

@ -35,7 +35,10 @@ class QQBot
set_coroutine_params(["data" => $data]);
ctx()->setCache("level", 0);
//Console::debug("Calling CQ Event from fd=" . ctx()->getConnection()->getFd());
$this->dispatchBeforeEvents($data); // >= 200 的level before在这里执行
if ($data["post_type"] != "meta_event") {
$r = $this->dispatchBeforeEvents($data); // before在这里执行元事件不执行before为减少不必要的调试日志
if ($r->store === "block") EventDispatcher::interrupt();
}
if (CoMessage::resumeByWS()) {
EventDispatcher::interrupt();
}
@ -49,17 +52,27 @@ class QQBot
}
}
/**
* @param $data
* @return EventDispatcher
* @throws InterruptException
*/
public function dispatchBeforeEvents($data) {
$before = new EventDispatcher(CQBefore::class);
$before->setRuleFunction(function ($v) use ($data) {
return $v->cq_event == $data["post_type"];
});
$before->setReturnFunction(function ($result) {
if (!$result) EventDispatcher::interrupt();
if (!$result) EventDispatcher::interrupt("block");
});
$before->dispatchEvents($data);
return $before;
}
/**
* @param $data
* @throws InterruptException
*/
private function dispatchEvents($data) {
//Console::warning("最xia数据包".json_encode($data));
switch ($data["post_type"]) {
@ -73,16 +86,15 @@ class QQBot
$word[$k] = trim($word[$k]);
}
}
//分发CQCommand事件
$dispatcher = new EventDispatcher(CQCommand::class);
$dispatcher->setRuleFunction(function (CQCommand $v) use ($word) {
if(array_diff([$v->match, $v->pattern, $v->regex, $v->keyword, $v->end_with, $v->start_with], [""]) == []) return false;
if (array_diff([$v->match, $v->pattern, $v->regex, $v->keyword, $v->end_with, $v->start_with], [""]) == []) return false;
elseif (($v->user_id == 0 || ($v->user_id != 0 && $v->user_id == ctx()->getUserId())) &&
($v->group_id == 0 || ($v->group_id != 0 && $v->group_id == (ctx()->getGroupId() ?? 0))) &&
($v->message_type == '' || ($v->message_type != '' && $v->message_type == ctx()->getMessageType()))
) {
if(($word[0] != "" && $v->match == $word[0]) || in_array($word[0], $v->alias)) {
if (($word[0] != "" && $v->match == $word[0]) || in_array($word[0], $v->alias)) {
array_shift($word);
ctx()->setCache("match", $word);
return true;
@ -95,14 +107,14 @@ class QQBot
} elseif ($v->keyword != "" && mb_strpos(ctx()->getMessage(), $v->keyword) !== false) {
ctx()->setCache("match", explode($v->keyword, ctx()->getMessage()));
return true;
}elseif ($v->pattern != "") {
} elseif ($v->pattern != "") {
$match = matchArgs($v->pattern, ctx()->getMessage());
if($match !== false) {
if ($match !== false) {
ctx()->setCache("match", $match);
return true;
}
} elseif ($v->regex != "") {
if(preg_match("/" . $v->regex . "/u", ctx()->getMessage(), $word2) != 0) {
if (preg_match("/" . $v->regex . "/u", ctx()->getMessage(), $word2) != 0) {
ctx()->setCache("match", $word2);
return true;
}
@ -112,10 +124,10 @@ class QQBot
});
$dispatcher->setReturnFunction(function ($result) {
if (is_string($result)) ctx()->reply($result);
EventDispatcher::interrupt();
if (ctx()->getCache("has_reply") === true) EventDispatcher::interrupt();
});
$r = $dispatcher->dispatchEvents();
if ($r === null) EventDispatcher::interrupt();
$dispatcher->dispatchEvents();
if ($dispatcher->status == EventDispatcher::STATUS_INTERRUPTED) EventDispatcher::interrupt();
//分发CQMessage事件
$msg_dispatcher = new EventDispatcher(CQMessage::class);

View File

@ -1,4 +1,4 @@
<?php
<?php #plain
use ZM\Config\ZMConfig;

View File

@ -1,4 +1,4 @@
<?php
<?php #plain
use Swoole\Coroutine;
use ZM\API\ZMRobot;
@ -88,6 +88,7 @@ function getAllClasses($dir, $indoor_name) {
//echo "At " . $indoor_name . PHP_EOL;
if (is_dir($dir . $v)) $classes = array_merge($classes, getAllClasses($dir . $v . "/", $indoor_name . "\\" . $v));
elseif (mb_substr($v, -4) == ".php") {
if(substr(file_get_contents($dir.$v), 6, 6) == "#plain") continue;
$class_name = $indoor_name . "\\" . mb_substr($v, 0, -4);
$classes [] = $class_name;
}