getFrame()->data, true); $this->handle($data); } /** * @param array|Iterator $data 数据包 * @param int $level 递归等级 * @throws InterruptException * @throws ZMKnownException * @throws Exception */ public function handle($data, int $level = 0) { try { if ($level > 10) { return; } set_coroutine_params(['data' => $data]); if (isset($data['post_type'])) { // echo TermColor::ITALIC.json_encode($data, 128|256).TermColor::RESET.PHP_EOL; ctx()->setCache('level', $level); // Console::debug("Calling CQ Event from fd=" . ctx()->getConnection()->getFd()); if ($data['post_type'] != 'meta_event') { $r = $this->dispatchBeforeEvents($data, 'pre'); // before在这里执行,元事件不执行before为减少不必要的调试日志 if ($r->store === 'block') { EventDispatcher::interrupt(); } } // Console::warning("最上数据包:".json_encode($data)); } if (isset($data['echo']) || isset($data['post_type'])) { if (CoMessage::resumeByWS()) { EventDispatcher::interrupt(); } } if (($data['post_type'] ?? 'meta_event') != 'meta_event') { $r = $this->dispatchBeforeEvents($data, 'post'); // before在这里执行,元事件不执行before为减少不必要的调试日志 if ($r->store === 'block') { EventDispatcher::interrupt(); } } if (isset($data['post_type'])) { $this->dispatchEvents($data); } else { $this->dispatchAPIResponse($data); } if (($data['post_type'] ?? 'meta_event') != 'meta_event') { $r = $this->dispatchAfterEvents($data); // before在这里执行,元事件不执行before为减少不必要的调试日志 if ($r->store === 'block') { EventDispatcher::interrupt(); } } } /* @noinspection PhpRedundantCatchClauseInspection */ catch (WaitTimeoutException $e) { if (($data['post_type'] ?? 'meta_event') != 'meta_event') { $r = $this->dispatchAfterEvents($data); // before在这里执行,元事件不执行before为减少不必要的调试日志 if ($r->store === 'block') { EventDispatcher::interrupt(); } } $e->module->finalReply($e->getMessage()); } catch (InterruptException $e) { if (($data['post_type'] ?? 'meta_event') != 'meta_event') { $r = $this->dispatchAfterEvents($data); // before在这里执行,元事件不执行before为减少不必要的调试日志 if ($r->store === 'block') { EventDispatcher::interrupt(); } } throw $e; } // 这里修复CQAfter不能使用的问题,我竟然一直没写,绝了 } /** * @param array|Iterator $data 数据包 * @param string $time 类型(pre或post) * @throws Exception */ public function dispatchBeforeEvents($data, string $time): EventDispatcher { $before = new EventDispatcher(CQBefore::class); if ($time === 'pre') { $before->setRuleFunction(function ($v) use ($data) { return $v->level >= 200 && $v->cq_event == $data['post_type']; }); } else { $before->setRuleFunction(function ($v) use ($data) { return $v->level < 200 && $v->cq_event == $data['post_type']; }); } $before->setReturnFunction(function ($result) { if (!$result) { EventDispatcher::interrupt('block'); } }); $before->dispatchEvents($data); return $before; } /** * @param array|Iterator $data 数据包 * @throws InterruptException * @throws Exception */ private function dispatchEvents($data) { // Console::warning("最xia数据包:".json_encode($data)); switch ($data['post_type']) { case 'message': // 分发CQCommand事件 $dispatcher = new EventDispatcher(CQCommand::class); $dispatcher->setReturnFunction(function ($result) { if (is_string($result)) { ctx()->reply($result); } if (ctx()->getCache('has_reply') === true) { EventDispatcher::interrupt(); } }); $msg = $data['message']; if (is_array($msg)) { $msg = MessageUtil::arrayToStr($msg); } $s = MessageUtil::matchCommand($msg, ctx()->getData()); if ($s->status !== false) { $match = $s->match; $input_arguments = MessageUtil::checkArguments($s->object->class, $s->object->method, $match); if (!empty($match)) { ctx()->setCache('match', $match); } $dispatcher->dispatchEvent($s->object, null, ...$input_arguments); if (is_string($dispatcher->store)) { ctx()->reply($dispatcher->store); } if (ctx()->getCache('has_reply') === true) { $policy = ZMConfig::get('global', 'onebot')['message_command_policy'] ?? 'interrupt'; switch ($policy) { case 'interrupt': EventDispatcher::interrupt(); break; case 'continue': break; default: throw new Exception('未知的消息命令策略:' . $policy); } } } // 分发CQMessage事件 $msg_dispatcher = new EventDispatcher(CQMessage::class); $msg_dispatcher->setRuleFunction(function ($v) { return ($v->message == '' || ($v->message == ctx()->getMessage())) && ($v->user_id == 0 || ($v->user_id == ctx()->getUserId())) && ($v->group_id == 0 || ($v->group_id == (ctx()->getGroupId() ?? 0))) && ($v->message_type == '' || ($v->message_type == ctx()->getMessageType())) && ($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()); return; case 'meta_event': // Console::success("当前数据包:".json_encode(ctx()->getData())); $dispatcher = new EventDispatcher(CQMetaEvent::class); $dispatcher->setRuleFunction(function (CQMetaEvent $v) { return $v->meta_event_type == '' || ($v->meta_event_type == ctx()->getData()['meta_event_type']); }); // eval(BP); $dispatcher->dispatchEvents(ctx()->getData()); return; case 'notice': $dispatcher = new EventDispatcher(CQNotice::class); $dispatcher->setRuleFunction(function (CQNotice $v) { return ($v->notice_type == '' || ($v->notice_type == ctx()->getData()['notice_type'])) && ($v->sub_type == '' || ($v->sub_type == ctx()->getData()['sub_type'])) && ($v->group_id == '' || ($v->group_id == ctx()->getData()['group_id'])) && ($v->operator_id == '' || ($v->operator_id == ctx()->getData()['operator_id'])); }); $dispatcher->dispatchEvents(ctx()->getData()); return; case 'request': $dispatcher = new EventDispatcher(CQRequest::class); $dispatcher->setRuleFunction(function (CQRequest $v) { return ($v->request_type == '' || ($v->request_type == ctx()->getData()['request_type'])) && ($v->sub_type == '' || ($v->sub_type == ctx()->getData()['sub_type'])) && ($v->user_id == 0 || ($v->user_id == ctx()->getData()['user_id'])) && ($v->comment == '' || ($v->comment == ctx()->getData()['comment'])); }); $dispatcher->dispatchEvents(ctx()->getData()); return; } } /** * @param mixed $data 分发事件数据包 * @throws Exception */ private function dispatchAfterEvents($data): EventDispatcher { $after = new EventDispatcher(CQAfter::class); $after->setRuleFunction(function ($v) use ($data) { return $v->cq_event == $data['post_type']; }); $after->dispatchEvents($data); return $after; } /** * @param mixed $req * @throws Exception */ private function dispatchAPIResponse($req) { set_coroutine_params(['cq_response' => $req]); $dispatcher = new EventDispatcher(CQAPIResponse::class); $dispatcher->setRuleFunction(function (CQAPIResponse $response) { return $response->retcode == ctx()->getCQResponse()['retcode']; }); $dispatcher->dispatchEvents($req); } }