prerelease of beta1

This commit is contained in:
crazywhalecc
2022-12-20 20:10:40 +08:00
parent 04247048d4
commit c9bf0fb13c
16 changed files with 585 additions and 43 deletions

View File

@@ -6,10 +6,21 @@ namespace ZM\Plugin;
use Choir\Http\HttpFactory;
use OneBot\Driver\Event\StopException;
use OneBot\Driver\Event\WebSocket\WebSocketMessageEvent;
use OneBot\Driver\Event\WebSocket\WebSocketOpenEvent;
use OneBot\V12\Exception\OneBotException;
use OneBot\V12\Object\ActionResponse;
use OneBot\V12\Object\OneBotEvent;
use OneBot\V12\Validator;
use ZM\Annotation\AnnotationHandler;
use ZM\Annotation\AnnotationMap;
use ZM\Annotation\AnnotationParser;
use ZM\Annotation\OneBot\BotActionResponse;
use ZM\Annotation\OneBot\BotCommand;
use ZM\Annotation\OneBot\BotEvent;
use ZM\Annotation\OneBot\CommandArgument;
use ZM\Container\ContainerServicesProvider;
use ZM\Context\BotContext;
use ZM\Utils\ConnectionUtil;
class OneBot12Adapter extends ZMPlugin
@@ -21,7 +32,11 @@ class OneBot12Adapter extends ZMPlugin
case '':
case 'onebot12':
// 处理所有 OneBot 12 的反向 WS 握手事件
$this->addEvent(WebSocketOpenEvent::class, [$this, 'handleWSReverseInput']);
$this->addEvent(WebSocketOpenEvent::class, [$this, 'handleWSReverseOpen']);
$this->addEvent(\WebSocketMessageEvent::class, [$this, 'handleWSReverseMessage']);
// 在 BotEvent 内处理 BotCommand
// $cmd_event = BotEvent::make(type: 'message', level: 15)->on([$this, 'handleBotCommand']);
// $this->addBotEvent($cmd_event);
// 处理和声明所有 BotCommand 下的 CommandArgument
$parser->addSpecialParser(BotCommand::class, [$this, 'parseBotCommand']);
// 不需要给列表写入 CommandArgument
@@ -61,6 +76,33 @@ class OneBot12Adapter extends ZMPlugin
return true;
}
/**
* 调用 BotCommand 注解的方法
*
* @param BotEvent $event BotEvent 事件
* @param BotContext $ctx 机器人环境上下文
*/
public function handleBotCommand(BotEvent $event, BotContext $ctx)
{
$handler = new AnnotationHandler(BotCommand::class);
$handler->setReturnCallback(function ($result) use ($ctx) {
if (is_string($result)) {
$ctx->reply($result);
return;
}
try {
Validator::validateMessageSegment($result);
$ctx->reply($result);
} catch (\Throwable) {
}
if ($ctx->hasReplied()) {
AnnotationHandler::interrupt();
}
});
// 匹配消息
$match_result = $this->matchBotCommand($ctx->getEvent());
}
/**
* @throws StopException
*/
@@ -79,14 +121,16 @@ class OneBot12Adapter extends ZMPlugin
* 接入和认证反向 WS 的连接
* @throws StopException
*/
public function handleWSReverseInput(WebSocketOpenEvent $event): void
public function handleWSReverseOpen(WebSocketOpenEvent $event): void
{
logger()->info('收到握手请求:' . json_encode($event->getRequest()->getHeaders(), JSON_PRETTY_PRINT));
// 判断是不是 OneBot 12 反向 WS 连进来的,通过 Sec-WebSocket-Protocol 头
$line = explode('.', $event->getRequest()->getHeaderLine('Sec-WebSocket-Protocol'), 2);
if ($line[0] === '12') {
logger()->info('检测到 OneBot 12 反向 WS 连接,正在进行认证...');
// 是 OneBot 12 标准的,准许接入,进行鉴权
$request = $event->getRequest();
$info = ['impl' => $line[1] ?? 'unknown'];
if (($stored_token = $event->getSocketConfig()['access_token'] ?? '') !== '') {
// 测试 Header
$token = $request->getHeaderLine('Authorization');
@@ -95,15 +139,94 @@ class OneBot12Adapter extends ZMPlugin
$token = $request->getQueryParams()['access_token'] ?? '';
}
$token = explode('Bearer ', $token);
$info = ['impl' => $line[1] ?? 'unknown'];
if (!isset($token[1]) || $token[1] !== $stored_token) { // 没有 token鉴权失败
logger()->warning('OneBot 12 反向 WS 连接鉴权失败,拒绝接入');
$event->withResponse(HttpFactory::createResponse(401, 'Unauthorized'));
$event->stopPropagation();
}
}
logger()->info('OneBot 12 反向 WS 连接鉴权成功,接入成功[' . $event->getFd() . ']');
}
// 设置 OneBot 相关的东西
ConnectionUtil::setConnection($event->getFd(), $info ?? []);
}
/**
* 处理 WebSocket 消息
*
* @param WebSocketMessageEvent $event 事件对象
* @throws OneBotException
* @throws \Throwable
*/
public function handleWSReverseMessage(WebSocketMessageEvent $event): void
{
// 忽略非 OneBot 12 的消息
$impl = ConnectionUtil::getConnection($event->getFd())['impl'] ?? null;
if ($impl === null) {
return;
}
// 处理
resolve(ContainerServicesProvider::class)->registerServices('message');
// 解析 Frame 到 UTF-8 JSON
$body = $event->getFrame()->getData();
$body = json_decode($body, true);
if ($body === null) {
logger()->warning('收到非 JSON 格式的消息,已忽略');
return;
}
if (isset($body['type'], $body['detail_type'])) {
// 如果含有 typedetail_type 字段,表明是 event
try {
$obj = new OneBotEvent($body);
} catch (OneBotException $e) {
logger()->debug('收到非 OneBot 12 标准的消息,已忽略');
return;
}
// 绑定容器
container()->instance(OneBotEvent::class, $obj);
container()->alias(OneBotEvent::class, 'bot.event');
// 调用 BotEvent 事件
$handler = new AnnotationHandler(BotEvent::class);
$handler->setRuleCallback(function (BotEvent $event) use ($obj) {
return ($event->type === null || $event->type === $obj->type)
&& ($event->sub_type === null || $event->sub_type === $obj->sub_type)
&& ($event->detail_type === null || $event->detail_type === $obj->detail_type);
});
$handler->handleAll($obj);
} elseif (isset($body['status'], $body['retcode'])) {
// 如果含有 statusretcode 字段,表明是 action 的 response
$resp = new ActionResponse();
$resp->retcode = $body['retcode'];
$resp->status = $body['status'];
$resp->message = $body['message'] ?? '';
$resp->data = $body['data'] ?? null;
container()->instance(ActionResponse::class, $resp);
container()->alias(ActionResponse::class, 'bot.action.response');
// 调用 BotActionResponse 事件
$handler = new AnnotationHandler(BotActionResponse::class);
$handler->setRuleCallback(function (BotActionResponse $event) use ($resp) {
return $event->retcode === null || $event->retcode === $resp->retcode;
});
$handler->handleAll($resp);
$act = bot()->getEchoAction($resp->echo);
if ($act !== null) {
}
}
}
private function matchBotCommand(OneBotEvent $event): array
{
$ls = AnnotationMap::$_list[BotCommand::class] ?? [];
$msg = $event->getMessageString();
// TODO: 还没写完匹配 BotCommand
return [];
}
}