mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-21 15:45:36 +08:00
initial 2.0.0-a4 commit
This commit is contained in:
@@ -1,169 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\CQ;
|
||||
|
||||
|
||||
use Co;
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use ZM\ConnectionManager\ConnectionObject;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Event\EventDispatcher;
|
||||
use ZM\Event\EventManager;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Annotation\CQ\CQAfter;
|
||||
use ZM\Annotation\CQ\CQBefore;
|
||||
use ZM\Annotation\CQ\CQCommand;
|
||||
use ZM\Annotation\CQ\CQMessage;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Exception\WaitTimeoutException;
|
||||
use ZM\Http\Response;
|
||||
|
||||
class MessageEvent
|
||||
{
|
||||
private $function_call = false;
|
||||
private $data;
|
||||
private $circle;
|
||||
/** @var ConnectionObject|Response */
|
||||
private $connection;
|
||||
|
||||
public function __construct($data, $conn_or_response, $circle = 0) {
|
||||
$this->data = $data;
|
||||
$this->connection = $conn_or_response;
|
||||
$this->circle = $circle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onBefore() {
|
||||
$dispatcher = new EventDispatcher(CQBefore::class . "::message");
|
||||
$dispatcher->setRuleFunction(function ($v) {
|
||||
if($v->level < 200) EventDispatcher::interrupt();
|
||||
return true;
|
||||
});
|
||||
$dispatcher->setReturnFunction(function($result){
|
||||
if(!$result) EventDispatcher::interrupt();
|
||||
});
|
||||
$dispatcher->dispatchEvents();
|
||||
|
||||
foreach (ZMBuf::get("wait_api", []) as $k => $v) {
|
||||
if(zm_data_hash(ctx()->getData()) == $v["hash"]) {
|
||||
$v["result"] = context()->getData()["message"];
|
||||
ZMBuf::appendKey("wait_api", $k, $v);
|
||||
Co::resume($v["coroutine"]);
|
||||
return false;
|
||||
}
|
||||
if (context()->getData()["user_id"] == $v["user_id"] &&
|
||||
context()->getData()["self_id"] == $v["self_id"] &&
|
||||
context()->getData()["message_type"] == $v["message_type"] &&
|
||||
(context()->getData()[context()->getData()["message_type"] . "_id"] ?? context()->getData()["user_id"]) ==
|
||||
($v[$v["message_type"] . "_id"] ?? $v["user_id"])) {
|
||||
$v["result"] = context()->getData()["message"];
|
||||
ZMBuf::appendKey("wait_api", $k, $v);
|
||||
Co::resume($v["coroutine"]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach (EventManager::$events[CQBefore::class]["message"] ?? [] as $v) {
|
||||
if ($v->level >= 200) continue;
|
||||
$c = $v->class;
|
||||
if (ctx()->getCache("level") != 0) continue;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["data" => context()->getData(), "connection" => $this->connection],
|
||||
[],
|
||||
function ($r) {
|
||||
if (!$r) context()->setCache("block_continue", true);
|
||||
}
|
||||
);
|
||||
if (context()->getCache("block_continue") === true) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @noinspection PhpRedundantCatchClauseInspection
|
||||
*/
|
||||
public function onActivate() {
|
||||
try {
|
||||
$word = split_explode(" ", str_replace("\r", "", context()->getMessage()));
|
||||
if (count(explode("\n", $word[0])) >= 2) {
|
||||
$enter = explode("\n", context()->getMessage());
|
||||
$first = split_explode(" ", array_shift($enter));
|
||||
$word = array_merge($first, $enter);
|
||||
foreach ($word as $k => $v) {
|
||||
$word[$k] = trim($word[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
//分发CQCommand事件
|
||||
$dispatcher = new EventDispatcher(CQCommand::class);
|
||||
$dispatcher->setRuleFunction(function ($v) use ($word) {
|
||||
if ($v->match == "" && $v->regexMatch == "" && $v->fullMatch == "") 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) ||
|
||||
($v->regexMatch != "" && ($args = matchArgs($v->regexMatch, ctx()->getMessage())) !== false) ||
|
||||
($v->fullMatch != "" && (preg_match("/" . $v->fullMatch . "/u", ctx()->getMessage(), $args)) != 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
$dispatcher->setReturnFunction(function ($result) {
|
||||
if (is_string($result)) ctx()->reply($result);
|
||||
EventDispatcher::interrupt();
|
||||
});
|
||||
$r = $dispatcher->dispatchEvents($word);
|
||||
if ($r === null) return;
|
||||
|
||||
//分发CQMessage事件
|
||||
$msg_dispatcher = new EventDispatcher(CQMessage::class);
|
||||
$msg_dispatcher->setRuleFunction(function ($v) {
|
||||
return ($v->message == '' || ($v->message != '' && $v->message == context()->getData()["message"])) &&
|
||||
($v->user_id == 0 || ($v->user_id != 0 && $v->user_id == context()->getData()["user_id"])) &&
|
||||
($v->group_id == 0 || ($v->group_id != 0 && $v->group_id == (context()->getData()["group_id"] ?? 0))) &&
|
||||
($v->message_type == '' || ($v->message_type != '' && $v->message_type == context()->getData()["message_type"])) &&
|
||||
($v->raw_message == '' || ($v->raw_message != '' && $v->raw_message == context()->getData()["raw_message"]));
|
||||
});
|
||||
$msg_dispatcher->setReturnFunction(function ($result) {
|
||||
if (is_string($result)) ctx()->reply($result);
|
||||
});
|
||||
$msg_dispatcher->dispatchEvents(ctx()->getMessage());
|
||||
} catch (WaitTimeoutException $e) {
|
||||
$e->module->finalReply($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在调用完事件后执行的
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onAfter() {
|
||||
context()->setCache("block_continue", null);
|
||||
foreach (ZMBuf::$events[CQAfter::class]["message"] ?? [] as $v) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["data" => context()->getData(), "connection" => $this->connection],
|
||||
[],
|
||||
function ($r) {
|
||||
if (!$r) context()->setCache("block_continue", true);
|
||||
}
|
||||
);
|
||||
if (context()->getCache("block_continue") === true) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function hasReply() {
|
||||
return $this->function_call;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\CQ;
|
||||
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use ZM\Annotation\CQ\CQBefore;
|
||||
use ZM\Annotation\CQ\CQMetaEvent;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Exception\WaitTimeoutException;
|
||||
use ZM\Store\ZMBuf;
|
||||
|
||||
class MetaEvent
|
||||
{
|
||||
private $data;
|
||||
private $connection;
|
||||
private $circle;
|
||||
|
||||
public function __construct($data, $connection, $circle = 0) {
|
||||
$this->data = $data;
|
||||
$this->connection = $connection;
|
||||
$this->circle = $circle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onBefore() {
|
||||
foreach (ZMBuf::$events[CQBefore::class]["meta_event"] ?? [] as $v) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["data" => context()->getData(), "connection" => $this->connection],
|
||||
[],
|
||||
function ($r) {
|
||||
if(!$r) context()->setCache("block_continue", true);
|
||||
}
|
||||
);
|
||||
if(context()->getCache("block_continue") === true) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onActivate() {
|
||||
try {
|
||||
$obj = [];
|
||||
foreach (ZMBuf::$events[CQMetaEvent::class] ?? [] as $v) {
|
||||
/** @var CQMetaEvent $v */
|
||||
if (
|
||||
($v->meta_event_type == '' || ($v->meta_event_type != '' && $v->meta_event_type == $this->data["meta_event_type"])) &&
|
||||
($v->sub_type == 0 || ($v->sub_type != 0 && $v->sub_type == $this->data["sub_type"]))) {
|
||||
$c = $v->class;
|
||||
if (!isset($obj[$c]))
|
||||
$obj[$c] = new $c();
|
||||
EventHandler::callWithMiddleware($obj[$c],$v->method, [], [], function($r) {
|
||||
if (is_string($r)) context()->reply($r);
|
||||
});
|
||||
if (context()->getCache("block_continue") === true) return;
|
||||
}
|
||||
}
|
||||
} /** @noinspection PhpRedundantCatchClauseInspection */ catch (WaitTimeoutException $e) {
|
||||
$e->module->finalReply($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\CQ;
|
||||
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use ZM\Annotation\CQ\CQAfter;
|
||||
use ZM\Annotation\CQ\CQBefore;
|
||||
use ZM\Annotation\CQ\CQNotice;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Exception\WaitTimeoutException;
|
||||
use ZM\Store\ZMBuf;
|
||||
|
||||
class NoticeEvent
|
||||
{
|
||||
private $data;
|
||||
private $connection;
|
||||
private $circle;
|
||||
|
||||
public function __construct($data, $connection, $circle = 0) {
|
||||
$this->data = $data;
|
||||
$this->connection = $connection;
|
||||
$this->circle = $circle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onBefore() {
|
||||
foreach (ZMBuf::$events[CQBefore::class]["notice"] ?? [] as $v) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["data" => context()->getData(), "connection" => $this->connection],
|
||||
[],
|
||||
function ($r) {
|
||||
if(!$r) context()->setCache("block_continue", true);
|
||||
}
|
||||
);
|
||||
if(context()->getCache("block_continue") === true) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onActivate() {
|
||||
try {
|
||||
$obj = [];
|
||||
foreach (ZMBuf::$events[CQNotice::class] ?? [] as $v) {
|
||||
/** @var CQNotice $v */
|
||||
if (
|
||||
($v->notice_type == '' || ($v->notice_type != '' && $v->notice_type == $this->data["notice_type"])) &&
|
||||
($v->sub_type == 0 || ($v->sub_type != 0 && $v->sub_type == $this->data["sub_type"])) &&
|
||||
($v->group_id == 0 || ($v->group_id != 0 && $v->group_id == ($this->data["group_id"] ?? 0))) &&
|
||||
($v->operator_id == 0 || ($v->operator_id != 0 && $v->operator_id == ($this->data["operator_id"] ?? 0)))) {
|
||||
$c = $v->class;
|
||||
if (!isset($obj[$c]))
|
||||
$obj[$c] = new $c();
|
||||
EventHandler::callWithMiddleware($obj[$c],$v->method, [], [], function($r) {
|
||||
if (is_string($r)) context()->reply($r);
|
||||
});
|
||||
if (context()->getCache("block_continue") === true) return;
|
||||
}
|
||||
}
|
||||
} /** @noinspection PhpRedundantCatchClauseInspection */ catch (WaitTimeoutException $e) {
|
||||
$e->module->finalReply($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onAfter() {
|
||||
foreach (ZMBuf::$events[CQAfter::class]["notice"] ?? [] as $v) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["data" => context()->getData(), "connection" => $this->connection],
|
||||
[],
|
||||
function ($r) {
|
||||
if(!$r) context()->setCache("block_continue", true);
|
||||
}
|
||||
);
|
||||
if(context()->getCache("block_continue") === true) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\CQ;
|
||||
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use ZM\Annotation\CQ\CQAfter;
|
||||
use ZM\Annotation\CQ\CQBefore;
|
||||
use ZM\Annotation\CQ\CQRequest;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Exception\WaitTimeoutException;
|
||||
use ZM\Store\ZMBuf;
|
||||
|
||||
class RequestEvent
|
||||
{
|
||||
private $data;
|
||||
private $connection;
|
||||
private $circle;
|
||||
|
||||
public function __construct($data, $connection, $circle = 0) {
|
||||
$this->data = $data;
|
||||
$this->connection = $connection;
|
||||
$this->circle = $circle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onBefore() {
|
||||
foreach (ZMBuf::$events[CQBefore::class]["request"] ?? [] as $v) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["data" => context()->getData(), "connection" => $this->connection],
|
||||
[],
|
||||
function ($r) {
|
||||
if(!$r) context()->setCache("block_continue", true);
|
||||
}
|
||||
);
|
||||
if(context()->getCache("block_continue") === true) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AnnotationException
|
||||
* @noinspection PhpRedundantCatchClauseInspection
|
||||
*/
|
||||
public function onActivate() {
|
||||
try {
|
||||
$obj = [];
|
||||
foreach (ZMBuf::$events[CQRequest::class] ?? [] as $v) {
|
||||
/** @var CQRequest $v */
|
||||
if (
|
||||
($v->request_type == '' || ($v->request_type != '' && $v->request_type == $this->data["request_type"])) &&
|
||||
($v->sub_type == 0 || ($v->sub_type != 0 && $v->sub_type == $this->data["sub_type"])) &&
|
||||
($v->user_id == 0 || ($v->user_id != 0 && $v->user_id == ($this->data["user_id"] ?? 0))) &&
|
||||
($v->comment == 0 || ($v->comment != 0 && $v->comment == ($this->data["comment"] ?? 0)))) {
|
||||
$c = $v->class;
|
||||
if (!isset($obj[$c]))
|
||||
$obj[$c] = new $c();
|
||||
EventHandler::callWithMiddleware($obj[$c],$v->method, [], [], function($r) {
|
||||
if (is_string($r)) context()->reply($r);
|
||||
});
|
||||
if (context()->getCache("block_continue") === true) return;
|
||||
}
|
||||
}
|
||||
} catch (WaitTimeoutException $e) {
|
||||
$e->module->finalReply($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onAfter() {
|
||||
foreach (ZMBuf::$events[CQAfter::class]["request"] ?? [] as $v) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["data" => context()->getData(), "connection" => $this->connection],
|
||||
[],
|
||||
function ($r) {
|
||||
if(!$r) context()->setCache("block_continue", true);
|
||||
}
|
||||
);
|
||||
if(context()->getCache("block_continue") === true) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event;
|
||||
|
||||
|
||||
interface Event
|
||||
{
|
||||
const SWOOLE = 1;
|
||||
const CQ = 2;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ namespace ZM\Event;
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use Exception;
|
||||
use ZM\Annotation\AnnotationBase;
|
||||
use ZM\Annotation\CQ\CQMetaEvent;
|
||||
use ZM\Exception\InterruptException;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
@@ -42,9 +43,13 @@ class EventDispatcher
|
||||
|
||||
public function dispatchEvents(...$params) {
|
||||
try {
|
||||
foreach (EventManager::$events[$this->class] ?? [] as $v) {
|
||||
|
||||
foreach ((EventManager::$events[$this->class] ?? []) as $v) {
|
||||
if($this->class == CQMetaEvent::class) {
|
||||
//eval(BP);
|
||||
}
|
||||
$result = $this->dispatchEvent($v, $this->rule, ...$params);
|
||||
if (is_callable($this->return_func)) ($this->return_func)($result);
|
||||
if ($result !== false && is_callable($this->return_func)) ($this->return_func)($result);
|
||||
}
|
||||
return true;
|
||||
} catch (InterruptException $e) {
|
||||
|
||||
@@ -1,293 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event;
|
||||
|
||||
|
||||
use Co;
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use Error;
|
||||
use Exception;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\ConnectionManager\ConnectionObject;
|
||||
use ZM\ConnectionManager\ManagerGM;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Event\Swoole\{MessageEvent, RequestEvent, WSCloseEvent, WSOpenEvent};
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Server;
|
||||
use Swoole\WebSocket\Frame;
|
||||
use ZM\Annotation\CQ\CQAPIResponse;
|
||||
use ZM\Annotation\CQ\CQAPISend;
|
||||
use ZM\Annotation\Http\MiddlewareClass;
|
||||
use ZM\Context\Context;
|
||||
use ZM\Http\MiddlewareInterface;
|
||||
use ZM\Http\Response;
|
||||
use ZM\Store\LightCache;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
class EventHandler
|
||||
{
|
||||
/**
|
||||
* @param $event_name
|
||||
* @param $param0
|
||||
* @param null $param1
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public static function callSwooleEvent($event_name, $param0, $param1 = null) {
|
||||
//$starttime = microtime(true);
|
||||
unset(Context::$context[Co::getCid()]);
|
||||
$event_name = strtolower($event_name);
|
||||
switch ($event_name) {
|
||||
case "message":
|
||||
/** @var Frame $param1 */
|
||||
/** @var Server $param0 */
|
||||
$conn = ManagerGM::get($param1->fd);
|
||||
set_coroutine_params(["server" => $param0, "frame" => $param1, "connection" => $conn]);
|
||||
try {
|
||||
(new MessageEvent($param0, $param1))->onActivate()->onAfter();
|
||||
} catch (Error $e) {
|
||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
||||
Console::trace();
|
||||
}
|
||||
break;
|
||||
case "request":
|
||||
try {
|
||||
set_coroutine_params(["request" => $param0, "response" => $param1]);
|
||||
(new RequestEvent($param0, $param1))->onActivate()->onAfter();
|
||||
} catch (Exception $e) {
|
||||
/** @var Response $param1 */
|
||||
$param1->status(500);
|
||||
Console::info($param0->server["remote_addr"] . ":" . $param0->server["remote_port"] .
|
||||
" [" . $param1->getStatusCode() . "] " . $param0->server["request_uri"]
|
||||
);
|
||||
if (!$param1->isEnd()) {
|
||||
if (ZMConfig::get("global", "debug_mode"))
|
||||
$param1->end("Internal server error: " . $e->getMessage());
|
||||
else
|
||||
$param1->end("Internal server error.");
|
||||
}
|
||||
Console::error("Internal server exception (500), caused by " . get_class($e));
|
||||
Console::log($e->getTraceAsString(), "gray");
|
||||
} catch (Error $e) {
|
||||
/** @var Response $param1 */
|
||||
$param1->status(500);
|
||||
Console::info($param0->server["remote_addr"] . ":" . $param0->server["remote_port"] .
|
||||
" [" . $param1->getStatusCode() . "] " . $param0->server["request_uri"]
|
||||
);
|
||||
$doc = "Internal server error<br>";
|
||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||
if (Console::getLevel() >= 4) $doc .= $error_msg;
|
||||
if (!$param1->isEnd()) $param1->end($doc);
|
||||
Console::error("Internal server error (500): " . $error_msg);
|
||||
Console::log($e->getTraceAsString(), "gray");
|
||||
}
|
||||
break;
|
||||
case "open":
|
||||
/** @var Request $param1 */
|
||||
set_coroutine_params(["server" => $param0, "request" => $param1, "fd" => $param1->fd]);
|
||||
try {
|
||||
(new WSOpenEvent($param0, $param1))->onActivate()->onAfter();
|
||||
} catch (Error $e) {
|
||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
||||
Console::trace();
|
||||
}
|
||||
break;
|
||||
case "close":
|
||||
set_coroutine_params(["server" => $param0, "fd" => $param1]);
|
||||
try {
|
||||
(new WSCloseEvent($param0, $param1))->onActivate()->onAfter();
|
||||
} catch (Error $e) {
|
||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
||||
Console::trace();
|
||||
}
|
||||
break;
|
||||
}
|
||||
//Console::info(Console::setColor("Event: " . $event_name . " 运行了 " . round(microtime(true) - $starttime, 5) . " 秒", "gold"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $event_data
|
||||
* @param $conn_or_response
|
||||
* @param int $level
|
||||
* @return bool
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public static function callCQEvent($event_data, $conn_or_response, int $level = 0) {
|
||||
ctx()->setCache("level", $level);
|
||||
if ($level >= 5) {
|
||||
Console::warning("Recursive call reached " . $level . " times");
|
||||
Console::trace();
|
||||
return false;
|
||||
}
|
||||
$starttime = microtime(true);
|
||||
switch ($event_data["post_type"]) {
|
||||
case "message":
|
||||
$event = new CQ\MessageEvent($event_data, $conn_or_response, $level);
|
||||
if ($event->onBefore()) $event->onActivate();
|
||||
$event->onAfter();
|
||||
return $event->hasReply();
|
||||
break;
|
||||
case "notice":
|
||||
$event = new CQ\NoticeEvent($event_data, $conn_or_response, $level);
|
||||
if ($event->onBefore()) $event->onActivate();
|
||||
$event->onAfter();
|
||||
return true;
|
||||
case "request":
|
||||
$event = new CQ\RequestEvent($event_data, $conn_or_response, $level);
|
||||
if ($event->onBefore()) $event->onActivate();
|
||||
$event->onAfter();
|
||||
return true;
|
||||
case "meta_event":
|
||||
$event = new CQ\MetaEvent($event_data, $conn_or_response, $level);
|
||||
if ($event->onBefore()) $event->onActivate();
|
||||
return true;
|
||||
}
|
||||
unset($starttime);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $req
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public static function callCQResponse($req) {
|
||||
Console::debug("收到来自API连接的回复:" . json_encode($req, 128 | 256));
|
||||
$status = $req["status"];
|
||||
$retcode = $req["retcode"];
|
||||
$data = $req["data"];
|
||||
if (isset($req["echo"]) && LightCache::isset("sent_api_" . $req["echo"])) {
|
||||
$origin = LightCache::get("sent_api_" . $req["echo"]);
|
||||
$self_id = $origin["self_id"];
|
||||
$response = [
|
||||
"status" => $status,
|
||||
"retcode" => $retcode,
|
||||
"data" => $data,
|
||||
"self_id" => $self_id,
|
||||
"echo" => $req["echo"]
|
||||
];
|
||||
set_coroutine_params(["cq_response" => $response]);
|
||||
if (isset(ZMBuf::$events[CQAPIResponse::class][$req["retcode"]])) {
|
||||
list($c, $method) = ZMBuf::$events[CQAPIResponse::class][$req["retcode"]];
|
||||
$class = new $c(["data" => $origin["data"]]);
|
||||
call_user_func_array([$class, $method], [$origin["data"], $req]);
|
||||
}
|
||||
$origin_ctx = ctx()->copy();
|
||||
ctx()->setCache("action", $origin["data"]["action"] ?? "unknown");
|
||||
ctx()->setData($origin["data"]);
|
||||
foreach (ZMBuf::$events[CQAPISend::class] ?? [] as $k => $v) {
|
||||
if (($v->action == "" || $v->action == ctx()->getCache("action")) && $v->with_result) {
|
||||
$c = $v->class;
|
||||
self::callWithMiddleware($c, $v->method, context()->copy(), [ctx()->getCache("action"), $origin["data"]["params"] ?? [], ctx()->getRobotId()]);
|
||||
if (context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
set_coroutine_params($origin_ctx);
|
||||
if (($origin["func"] ?? null) !== null) {
|
||||
call_user_func($origin["func"], $response, $origin["data"]);
|
||||
} elseif (($origin["coroutine"] ?? false) !== false) {
|
||||
$r = LightCache::get("sent_api_" . $req["echo"]);
|
||||
$r["result"] = $response;
|
||||
LightCache::set("sent_api_" . $req["echo"], $r);
|
||||
Co::resume($origin['coroutine']);
|
||||
}
|
||||
LightCache::unset("sent_api_" . $req["echo"]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function callCQAPISend($reply, ?ConnectionObject $connection) {
|
||||
$action = $reply["action"] ?? null;
|
||||
if ($action === null) {
|
||||
Console::warning("API 激活事件异常!");
|
||||
return;
|
||||
}
|
||||
if (ctx() === null) $content = [];
|
||||
else $content = ctx()->copy();
|
||||
go(function () use ($action, $reply, $connection, $content) {
|
||||
set_coroutine_params($content);
|
||||
context()->setCache("action", $action);
|
||||
context()->setCache("reply", $reply);
|
||||
foreach (ZMBuf::$events[CQAPISend::class] ?? [] as $k => $v) {
|
||||
if (($v->action == "" || $v->action == $action) && !$v->with_result) {
|
||||
$c = $v->class;
|
||||
self::callWithMiddleware($c, $v->method, context()->copy(), [$reply["action"], $reply["params"] ?? [], $connection->getOption('connect_id')]);
|
||||
if (context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $c
|
||||
* @param $method
|
||||
* @param array $class_construct
|
||||
* @param array $func_args
|
||||
* @param null $after_call
|
||||
* @return mixed|null
|
||||
* @throws AnnotationException
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function callWithMiddleware($c, $method, array $class_construct, array $func_args, $after_call = null) {
|
||||
$return_value = null;
|
||||
$plain_class = is_object($c) ? get_class($c) : $c;
|
||||
if (isset(ZMBuf::$events[MiddlewareInterface::class][$plain_class][$method])) {
|
||||
$middlewares = ZMBuf::$events[MiddlewareInterface::class][$plain_class][$method];
|
||||
$before_result = true;
|
||||
$r = [];
|
||||
foreach ($middlewares as $k => $middleware) {
|
||||
if (!isset(ZMBuf::$events[MiddlewareClass::class][$middleware])) throw new AnnotationException("Annotation parse error: Unknown MiddlewareClass named \"{$middleware}\"!");
|
||||
$middleware_obj = ZMBuf::$events[MiddlewareClass::class][$middleware];
|
||||
$before = $middleware_obj["class"];
|
||||
//var_dump($middleware_obj);
|
||||
$r[$k] = new $before();
|
||||
$r[$k]->class = is_object($c) ? get_class($c) : $c;
|
||||
$r[$k]->method = $method;
|
||||
if (isset($middleware_obj["before"])) {
|
||||
$rs = $middleware_obj["before"];
|
||||
$before_result = $r[$k]->$rs(...$func_args);
|
||||
if ($before_result === false) break;
|
||||
}
|
||||
}
|
||||
if ($before_result) {
|
||||
try {
|
||||
if (is_object($c)) $class = $c;
|
||||
elseif ($class_construct == []) $class = ZMUtil::getModInstance($c);
|
||||
else $class = new $c($class_construct);
|
||||
$result = $class->$method(...$func_args);
|
||||
if (is_callable($after_call))
|
||||
$return_value = $after_call($result);
|
||||
} catch (Exception $e) {
|
||||
for ($i = count($middlewares) - 1; $i >= 0; --$i) {
|
||||
$middleware_obj = ZMBuf::$events[MiddlewareClass::class][$middlewares[$i]];
|
||||
if (!isset($middleware_obj["exceptions"])) continue;
|
||||
foreach ($middleware_obj["exceptions"] as $name => $method) {
|
||||
if ($e instanceof $name) {
|
||||
$r[$i]->$method($e);
|
||||
context()->setCache("block_continue", true);
|
||||
}
|
||||
}
|
||||
if (context()->getCache("block_continue") === true) return $return_value;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
for ($i = count($middlewares) - 1; $i >= 0; --$i) {
|
||||
$middleware_obj = ZMBuf::$events[MiddlewareClass::class][$middlewares[$i]];
|
||||
if (isset($middleware_obj["after"], $r[$i])) {
|
||||
$r[$i]->{$middleware_obj["after"]}(...$func_args);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_object($c)) $class = $c;
|
||||
elseif ($class_construct == []) $class = ZMUtil::getModInstance($c);
|
||||
else $class = new $c($class_construct);
|
||||
$result = call_user_func_array([$class, $method], $func_args);
|
||||
if (is_callable($after_call))
|
||||
$return_value = call_user_func_array($after_call, [$result]);
|
||||
}
|
||||
return $return_value;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ use ZM\Annotation\AnnotationBase;
|
||||
use ZM\Annotation\AnnotationParser;
|
||||
use ZM\Annotation\Swoole\OnTick;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Store\ZMAtomic;
|
||||
|
||||
class EventManager
|
||||
{
|
||||
@@ -20,7 +20,7 @@ class EventManager
|
||||
public static $middlewares = [];
|
||||
public static $req_mapping = [];
|
||||
|
||||
public static function addEvent($event_name, AnnotationBase $event_obj) {
|
||||
public static function addEvent($event_name, ?AnnotationBase $event_obj) {
|
||||
self::$events[$event_name][] = $event_obj;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class EventManager
|
||||
Console::debug("Added Middleware-based timer: " . $plain_class . " -> " . $vss->method);
|
||||
Timer::tick($vss->tick_ms, function () use ($vss, $dispatcher) {
|
||||
set_coroutine_params([]);
|
||||
if (ZMBuf::atomic("stop_signal")->get() != 0) {
|
||||
if (ZMAtomic::get("stop_signal")->get() != 0) {
|
||||
Timer::clearAll();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use Swoole\Timer;
|
||||
use ZM\Annotation\AnnotationParser;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Annotation\Swoole\OnWorkerStart;
|
||||
use ZM\Annotation\Swoole\SwooleEvent;
|
||||
use ZM\Annotation\Swoole\OnSwooleEvent;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\ConnectionManager\ManagerGM;
|
||||
use ZM\Console\Console;
|
||||
@@ -33,6 +33,8 @@ use ZM\Exception\DbException;
|
||||
use ZM\Framework;
|
||||
use ZM\Http\Response;
|
||||
use ZM\Module\QQBot;
|
||||
use ZM\Store\MySQL\SqlPoolStorage;
|
||||
use ZM\Store\Redis\ZMRedisPool;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Utils\DataProvider;
|
||||
use ZM\Utils\HttpUtil;
|
||||
@@ -132,9 +134,9 @@ class ServerEventHandler
|
||||
foreach ($server->connections as $v) {
|
||||
$server->close($v);
|
||||
}
|
||||
if (ZMBuf::$sql_pool !== null) {
|
||||
ZMBuf::$sql_pool->close();
|
||||
ZMBuf::$sql_pool = null;
|
||||
if (SqlPoolStorage::$sql_pool !== null) {
|
||||
SqlPoolStorage::$sql_pool->close();
|
||||
SqlPoolStorage::$sql_pool = null;
|
||||
}
|
||||
|
||||
// 这里执行的是只需要执行一遍的代码,比如终端监听器和键盘监听器
|
||||
@@ -175,7 +177,7 @@ class ServerEventHandler
|
||||
}
|
||||
}
|
||||
$sql = ZMConfig::get("global", "sql_config");
|
||||
ZMBuf::$sql_pool = new PDOPool((new PDOConfig())
|
||||
SqlPoolStorage::$sql_pool = new PDOPool((new PDOConfig())
|
||||
->withHost($sql["sql_host"])
|
||||
->withPort($sql["sql_port"])
|
||||
// ->withUnixSocket('/tmp/mysql.sock')
|
||||
@@ -188,6 +190,13 @@ class ServerEventHandler
|
||||
DB::initTableList();
|
||||
}
|
||||
|
||||
// 开箱即用的Redis
|
||||
$redis = ZMConfig::get("global", "redis_config");
|
||||
if($redis !== null && $redis["host"] != "") {
|
||||
if (!extension_loaded("redis")) Console::error("Can not find redis extension.\n");
|
||||
else ZMRedisPool::init($redis);
|
||||
}
|
||||
|
||||
$this->loadAnnotations(); //加载composer资源、phar外置包、注解解析注册等
|
||||
|
||||
//echo json_encode(debug_backtrace(), 128|256);
|
||||
@@ -238,11 +247,11 @@ class ServerEventHandler
|
||||
* @param Frame $frame
|
||||
*/
|
||||
public function onMessage($server, Frame $frame) {
|
||||
Console::debug("Calling Swoole \"message\" from fd=" . $frame->fd);
|
||||
Console::debug("Calling Swoole \"message\" from fd=" . $frame->fd.": ".TermColor::ITALIC.$frame->data.TermColor::RESET);
|
||||
unset(Context::$context[Co::getCid()]);
|
||||
$conn = ManagerGM::get($frame->fd);
|
||||
set_coroutine_params(["server" => $server, "frame" => $frame, "connection" => $conn]);
|
||||
$dispatcher = new EventDispatcher(SwooleEvent::class);
|
||||
$dispatcher = new EventDispatcher(OnSwooleEvent::class);
|
||||
$dispatcher->setRuleFunction(function ($v) {
|
||||
if ($v->getRule() == '') {
|
||||
return strtolower($v->type) == 'message';
|
||||
@@ -278,7 +287,7 @@ class ServerEventHandler
|
||||
Console::debug("Calling Swoole \"request\" event from fd=" . $request->fd);
|
||||
set_coroutine_params(["request" => $request, "response" => $response]);
|
||||
|
||||
$dis = new EventDispatcher();
|
||||
$dis = new EventDispatcher(OnSwooleEvent::class);
|
||||
$dis->setRuleFunction(function ($v) {
|
||||
if ($v->getRule() == '') {
|
||||
return strtolower($v->type) == 'request';
|
||||
@@ -322,7 +331,7 @@ class ServerEventHandler
|
||||
else
|
||||
$response->end("Internal server error.");
|
||||
}
|
||||
Console::error("Internal server exception (500), caused by " . get_class($e));
|
||||
Console::error("Internal server exception (500), caused by " . get_class($e).": ".$e->getMessage());
|
||||
Console::log($e->getTraceAsString(), "gray");
|
||||
} catch (Error $e) {
|
||||
$response->status(500);
|
||||
@@ -354,7 +363,8 @@ class ServerEventHandler
|
||||
ManagerGM::pushConnect($request->fd, $type_conn);
|
||||
$conn = ManagerGM::get($request->fd);
|
||||
set_coroutine_params(["server" => $server, "request" => $request, "connection" => $conn, "fd" => $request->fd]);
|
||||
$dispatcher = new EventDispatcher(SwooleEvent::class);
|
||||
$conn->setOption("connect_id", strval($request->header["x-self-id"]) ?? "");
|
||||
$dispatcher = new EventDispatcher(OnSwooleEvent::class);
|
||||
$dispatcher->setRuleFunction(function ($v) {
|
||||
if ($v->getRule() == '') {
|
||||
return strtolower($v->type) == 'open';
|
||||
@@ -389,7 +399,7 @@ class ServerEventHandler
|
||||
if ($conn === null) return;
|
||||
Console::debug("Calling Swoole \"close\" event from fd=" . $fd);
|
||||
set_coroutine_params(["server" => $server, "connection" => $conn, "fd" => $fd]);
|
||||
$dispatcher = new EventDispatcher(SwooleEvent::class);
|
||||
$dispatcher = new EventDispatcher(OnSwooleEvent::class);
|
||||
$dispatcher->setRuleFunction(function ($v) {
|
||||
if ($v->getRule() == '') {
|
||||
return strtolower($v->type) == 'close';
|
||||
@@ -421,9 +431,13 @@ class ServerEventHandler
|
||||
*/
|
||||
public function onPipeMessage(Server $server, $src_worker_id, $data) {
|
||||
//var_dump($data, $server->worker_id);
|
||||
unset(Context::$context[Co::getCid()]);
|
||||
//unset(Context::$context[Co::getCid()]);
|
||||
$data = json_decode($data, true);
|
||||
switch ($data["action"]) {
|
||||
switch ($data["action"] ?? '') {
|
||||
case "resume_ws_message":
|
||||
$obj = $data["data"];
|
||||
Co::resume($obj["coroutine"]);
|
||||
break;
|
||||
case "stop":
|
||||
Console::verbose('正在清理 #' . $server->worker_id . ' 的计时器');
|
||||
Timer::clearAll();
|
||||
@@ -434,6 +448,9 @@ class ServerEventHandler
|
||||
case 'echo':
|
||||
Console::success('接收到来自 #' . $src_worker_id . ' 的消息');
|
||||
break;
|
||||
case 'send':
|
||||
$server->sendMessage(json_encode(["action" => "echo"]), $data["target"]);
|
||||
break;
|
||||
default:
|
||||
echo $data . PHP_EOL;
|
||||
}
|
||||
@@ -481,17 +498,17 @@ class ServerEventHandler
|
||||
}
|
||||
|
||||
//加载插件
|
||||
$plugins = ZMConfig::get("global", "plugins") ?? [];
|
||||
$plugins = ZMConfig::get("global", "modules") ?? [];
|
||||
if (!isset($plugins["qqbot"])) $plugins["qqbot"] = true;
|
||||
|
||||
if ($plugins["qqbot"]) {
|
||||
$obj = new SwooleEvent();
|
||||
$obj = new OnSwooleEvent();
|
||||
$obj->class = QQBot::class;
|
||||
$obj->method = 'handle';
|
||||
$obj->type = 'message';
|
||||
$obj->level = 99999;
|
||||
$obj->rule = 'connectIsQQ()';
|
||||
EventManager::addEvent(SwooleEvent::class, $obj);
|
||||
EventManager::addEvent(OnSwooleEvent::class, $obj);
|
||||
}
|
||||
|
||||
//TODO: 编写加载外部插件的方式
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\Swoole;
|
||||
|
||||
|
||||
use Closure;
|
||||
use ZM\ConnectionManager\ManagerGM;
|
||||
use ZM\Console\Console;
|
||||
use Swoole\WebSocket\Frame;
|
||||
use Swoole\WebSocket\Server;
|
||||
use ZM\Annotation\Swoole\SwooleEventAfter;
|
||||
use ZM\Annotation\Swoole\SwooleEvent;
|
||||
use Exception;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Store\ZMBuf;
|
||||
|
||||
class MessageEvent implements SwooleEventInterface
|
||||
{
|
||||
/**
|
||||
* @var Server
|
||||
*/
|
||||
public $server;
|
||||
/**
|
||||
* @var Frame
|
||||
*/
|
||||
public $frame;
|
||||
|
||||
public function __construct(Server $server, Frame $frame) {
|
||||
$this->server = $server;
|
||||
$this->frame = $frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function onActivate() {
|
||||
$conn = ManagerGM::get(context()->getFrame()->fd);
|
||||
try {
|
||||
if ($conn->getName() == "qq") {
|
||||
$data = json_decode(context()->getFrame()->data, true);
|
||||
if (isset($data["post_type"])) {
|
||||
set_coroutine_params(["data" => $data, "connection" => $conn]);
|
||||
ctx()->setCache("level", 0);
|
||||
Console::debug("Calling CQ Event from fd=" . $conn->getFd());
|
||||
EventHandler::callCQEvent($data, ManagerGM::get(context()->getFrame()->fd), 0);
|
||||
} else{
|
||||
set_coroutine_params(["connection" => $conn]);
|
||||
EventHandler::callCQResponse($data);
|
||||
}
|
||||
}
|
||||
foreach (ZMBuf::$events[SwooleEvent::class] ?? [] as $v) {
|
||||
if (strtolower($v->type) == "message" && $this->parseSwooleRule($v)) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["server" => $this->server, "frame" => $this->frame, "connection" => $conn],
|
||||
[$conn]
|
||||
);
|
||||
if (context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Console::warning("Websocket message event exception: " . (($cs = $e->getMessage()) == "" ? get_class($e) : $cs));
|
||||
Console::warning("In ". $e->getFile() . " at line ".$e->getLine());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function onAfter() {
|
||||
foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) {
|
||||
if (strtolower($v->type) == "message" && $this->parseSwooleRule($v) === true) {
|
||||
$c = $v->class;
|
||||
$class = new $c();
|
||||
call_user_func_array([$class, $v->method], []);
|
||||
if (context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function parseSwooleRule($v) {
|
||||
switch (explode(":", $v->rule)[0]) {
|
||||
case "connectType": //websocket连接类型
|
||||
if ($v->callback instanceof Closure) return call_user_func($v->callback, ManagerGM::get($this->frame->fd));
|
||||
break;
|
||||
case "dataEqual": //handle websocket message事件时才能用
|
||||
if ($v->callback instanceof Closure) return call_user_func($v->callback, $this->frame->data);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\Swoole;
|
||||
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Event\EventManager;
|
||||
use ZM\Store\ZMBuf;
|
||||
use Swoole\Http\Request;
|
||||
use ZM\Annotation\Swoole\SwooleEventAfter;
|
||||
use ZM\Annotation\Swoole\SwooleEvent;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Http\Response;
|
||||
use ZM\Utils\DataProvider;
|
||||
use ZM\Utils\HttpUtil;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
class RequestEvent implements SwooleEventInterface
|
||||
{
|
||||
/**
|
||||
* @var Request
|
||||
*/
|
||||
private $request;
|
||||
/**
|
||||
* @var Response
|
||||
*/
|
||||
private $response;
|
||||
|
||||
public function __construct(Request $request, Response $response) {
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this|SwooleEvent
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onActivate() {
|
||||
foreach (ZMConfig::get("global", "http_header") as $k => $v) {
|
||||
$this->response->setHeader($k, $v);
|
||||
}
|
||||
$uri = $this->request->server["request_uri"];
|
||||
Console::verbose($this->request->server["remote_addr"] . " request " . $uri);
|
||||
$uri = explode("/", $uri);
|
||||
$uri = array_diff($uri, ["..", "", "."]);
|
||||
$node = EventManager::$req_mapping;
|
||||
$params = [];
|
||||
while (true) {
|
||||
$r = array_shift($uri);
|
||||
if ($r === null) break;
|
||||
if (($cnt = count($node["son"] ?? [])) == 1) {
|
||||
if (isset($node["param_route"])) {
|
||||
foreach ($node["son"] as $k => $v) {
|
||||
if ($v["id"] == $node["param_route"]) {
|
||||
$node = $v;
|
||||
$params[mb_substr($v["name"], 1, -1)] = $r;
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
} elseif ($node["son"][0]["name"] == $r) {
|
||||
$node = $node["son"][0];
|
||||
continue;
|
||||
}
|
||||
} elseif ($cnt >= 1) {
|
||||
if (isset($node["param_route"])) {
|
||||
foreach ($node["son"] as $k => $v) {
|
||||
if ($v["id"] == $node["param_route"]) {
|
||||
$node = $v;
|
||||
$params[mb_substr($v["name"], 1, -1)] = $r;
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($node["son"] as $k => $v) {
|
||||
if ($v["name"] == $r) {
|
||||
$node = $v;
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ZMConfig::get("global", "static_file_server")["status"]) {
|
||||
$base_dir = ZMConfig::get("global", "static_file_server")["document_root"];
|
||||
$base_index = ZMConfig::get("global", "static_file_server")["document_index"];
|
||||
$uri = $this->request->server["request_uri"];
|
||||
$path = realpath($base_dir . urldecode($uri));
|
||||
if ($path !== false) {
|
||||
if (is_dir($path)) $path = $path . '/';
|
||||
$work = realpath(DataProvider::getWorkingDir()) . '/';
|
||||
if (strpos($path, $work) !== 0) {
|
||||
$this->responseStatus(403);
|
||||
return $this;
|
||||
}
|
||||
if (is_dir($path)) {
|
||||
foreach ($base_index as $vp) {
|
||||
if (is_file($path . $vp)) {
|
||||
Console::info("[200] " . $uri . " (static)");
|
||||
$exp = strtolower(pathinfo($path . $vp)['extension'] ?? "unknown");
|
||||
$this->response->setHeader("Content-Type", ZMConfig::get("file_header")[$exp] ?? "application/octet-stream");
|
||||
$this->response->end(file_get_contents($path . $vp));
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
} elseif (is_file($path)) {
|
||||
Console::info("[200] " . $uri . " (static)");
|
||||
$exp = strtolower(pathinfo($path)['extension'] ?? "unknown");
|
||||
$this->response->setHeader("Content-Type", ZMConfig::get("file_header")[$exp] ?? "application/octet-stream");
|
||||
$this->response->end(file_get_contents($path));
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->response->status(404);
|
||||
$this->response->end(HttpUtil::getHttpCodePage(404));
|
||||
return $this;
|
||||
}
|
||||
context()->setCache("params", $params);
|
||||
|
||||
if (in_array(strtoupper($this->request->server["request_method"]), $node["request_method"] ?? [])) { //判断目标方法在不在里面
|
||||
$c_name = $node["class"];
|
||||
EventHandler::callWithMiddleware(
|
||||
$c_name,
|
||||
$node["method"],
|
||||
["request" => $this->request, "response" => &$this->response, "params" => $params],
|
||||
[$params],
|
||||
function ($result) {
|
||||
if (is_string($result) && !$this->response->isEnd()) $this->response->end($result);
|
||||
if ($this->response->isEnd()) context()->setCache("block_continue", true);
|
||||
}
|
||||
);
|
||||
}
|
||||
foreach (ZMBuf::$events[SwooleEvent::class] ?? [] as $v) {
|
||||
if (strtolower($v->type) == "request" && $this->parseSwooleRule($v)) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware($c, $v->method, ["request" => $this->request, "response" => $this->response], []);
|
||||
if (context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->response->isEnd()) {
|
||||
$this->response->status(404);
|
||||
$this->response->end(HttpUtil::getHttpCodePage(404));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function onAfter() {
|
||||
foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) {
|
||||
if (strtolower($v->type) == "request" && $this->parseSwooleRule($v)) {
|
||||
$c = $v->class;
|
||||
$class = new $c(["request" => $this->request, "response" => $this->response]);
|
||||
call_user_func_array([$class, $v->method], []);
|
||||
if ($class->block_continue) break;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function responseStatus(int $int) {
|
||||
$this->response->status($int);
|
||||
$this->response->end();
|
||||
}
|
||||
|
||||
private function parseSwooleRule($v) {
|
||||
switch (explode(":", $v->rule)[0]) {
|
||||
case "containsGet":
|
||||
case "containsPost":
|
||||
if ($v->callback instanceof Closure) return call_user_func($v->callback, $this->request);
|
||||
break;
|
||||
case "containsJson":
|
||||
$content = $this->request->rawContent();
|
||||
$content = json_decode($content, true);
|
||||
if ($content === null) return false;
|
||||
if ($v->callback instanceof Closure) return call_user_func($v->callback, $content);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\Swoole;
|
||||
|
||||
|
||||
use ZM\Event\Event;
|
||||
|
||||
interface SwooleEventInterface extends Event
|
||||
{
|
||||
/**
|
||||
* @return SwooleEventInterface
|
||||
*/
|
||||
public function onActivate();
|
||||
|
||||
/**
|
||||
* @return SwooleEventInterface
|
||||
*/
|
||||
public function onAfter();
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\Swoole;
|
||||
|
||||
|
||||
use Closure;
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use ZM\ConnectionManager\ManagerGM;
|
||||
use ZM\Console\Console;
|
||||
use Swoole\Server;
|
||||
use ZM\Annotation\Swoole\SwooleEventAfter;
|
||||
use ZM\Annotation\Swoole\SwooleEvent;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
class WSCloseEvent implements SwooleEventInterface
|
||||
{
|
||||
public $server;
|
||||
|
||||
public $fd;
|
||||
|
||||
public function __construct(Server $server, int $fd) {
|
||||
$this->server = $server;
|
||||
$this->fd = $fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onActivate() {
|
||||
Console::debug("Websocket closed #{$this->fd}");
|
||||
set_coroutine_params(["server" => $this->server, "fd" => $this->fd, "connection" => ManagerGM::get($this->fd)]);
|
||||
foreach(ZMBuf::$events[SwooleEvent::class] ?? [] as $v) {
|
||||
if(strtolower($v->type) == "close" && $this->parseSwooleRule($v)) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware($c, $v->method, ["server" => $this->server, "fd" => $this->fd], []);
|
||||
if(context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
ManagerGM::popConnect($this->fd);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onAfter() {
|
||||
foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) {
|
||||
if (strtolower($v->type) == "close" && $this->parseSwooleRule($v) === true) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware($c, $v->method, ["server" => $this->server, "fd" => $this->fd], []);
|
||||
if(context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function parseSwooleRule($v) {
|
||||
switch (explode(":", $v->rule)[0]) {
|
||||
case "connectType": //websocket连接类型
|
||||
if ($v->callback instanceof Closure) return call_user_func($v->callback, ManagerGM::get($this->fd));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Event\Swoole;
|
||||
|
||||
|
||||
use Closure;
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\ConnectionManager\ConnectionObject;
|
||||
use ZM\ConnectionManager\ManagerGM;
|
||||
use ZM\Console\Console;
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\WebSocket\Server;
|
||||
use ZM\Annotation\Swoole\SwooleEventAfter;
|
||||
use ZM\Annotation\Swoole\SwooleEvent;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Store\ZMBuf;
|
||||
|
||||
class WSOpenEvent implements SwooleEventInterface
|
||||
{
|
||||
/**
|
||||
* @var Server
|
||||
*/
|
||||
private $server;
|
||||
/**
|
||||
* @var Request
|
||||
*/
|
||||
private $request;
|
||||
/** @var ConnectionObject */
|
||||
private $conn;
|
||||
|
||||
public function __construct(Server $server, Request $request) {
|
||||
$this->server = $server;
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onActivate() {
|
||||
$type = strtolower($this->request->get["type"] ?? $this->request->header["x-client-role"] ?? "");
|
||||
$type_conn = $this->getTypeClassName($type);
|
||||
ManagerGM::pushConnect($this->request->fd, $type_conn);
|
||||
if ($type_conn == "qq") {
|
||||
ManagerGM::setName($this->request->fd, "qq");
|
||||
$qq = $this->request->get["qq"] ?? $this->request->header["x-self-id"] ?? "";
|
||||
$self_token = ZMConfig::get("global", "access_token") ?? "";
|
||||
if (isset($this->request->header["authorization"])) {
|
||||
Console::debug($this->request->header["authorization"]);
|
||||
}
|
||||
$remote_token = $this->request->get["token"] ?? (isset($this->request->header["authorization"]) ? explode(" ", $this->request->header["authorization"])[1] : "");
|
||||
if ($qq != "" && ($self_token == $remote_token)) {
|
||||
ManagerGM::setOption($this->request->fd, "connect_id", $qq);
|
||||
$this->conn = ManagerGM::get($this->request->fd);
|
||||
} else {
|
||||
$this->conn = ManagerGM::get($this->request->fd);
|
||||
Console::warning("connection of CQ has invalid QQ or token!");
|
||||
Console::debug("Remote token: " . $remote_token);
|
||||
}
|
||||
} else {
|
||||
$this->conn = ManagerGM::get($this->request->fd);
|
||||
}
|
||||
set_coroutine_params(["server" => $this->server, "request" => $this->request, "connection" => $this->conn]);
|
||||
foreach (ZMBuf::$events[SwooleEvent::class] ?? [] as $v) {
|
||||
if (strtolower($v->type) == "open" && $this->parseSwooleRule($v) === true) {
|
||||
$c = $v->class;
|
||||
EventHandler::callWithMiddleware(
|
||||
$c,
|
||||
$v->method,
|
||||
["server" => $this->server, "request" => $this->request, "connection" => $this->conn],
|
||||
[$this->conn]
|
||||
);
|
||||
if (context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function onAfter() {
|
||||
if (!$this->server->exists($this->conn->getFd())) return $this;
|
||||
foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) {
|
||||
if (strtolower($v->type) == "open" && $this->parseSwooleRule($v) === true) {
|
||||
$class = new $v["class"]();
|
||||
call_user_func_array([$class, $v["method"]], [$this->conn]);
|
||||
if (context()->getCache("block_continue") === true) break;
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function parseSwooleRule($v) {
|
||||
switch (explode(":", $v->rule)[0]) {
|
||||
case "connectType": //websocket连接类型
|
||||
if ($v->callback instanceof Closure) return call_user_func($v->callback, $this->conn);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user