2020-09-29 15:07:43 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
2022-03-15 18:05:33 +08:00
|
|
|
|
declare(strict_types=1);
|
2020-09-29 15:07:43 +08:00
|
|
|
|
|
|
|
|
|
|
namespace ZM\Module;
|
|
|
|
|
|
|
2021-01-29 23:34:34 +08:00
|
|
|
|
use Exception;
|
2022-04-02 23:37:22 +08:00
|
|
|
|
use Iterator;
|
2021-12-07 13:21:29 +08:00
|
|
|
|
use ZM\Annotation\CQ\CQAfter;
|
2020-11-03 21:02:24 +08:00
|
|
|
|
use ZM\Annotation\CQ\CQAPIResponse;
|
|
|
|
|
|
use ZM\Annotation\CQ\CQBefore;
|
|
|
|
|
|
use ZM\Annotation\CQ\CQCommand;
|
|
|
|
|
|
use ZM\Annotation\CQ\CQMessage;
|
|
|
|
|
|
use ZM\Annotation\CQ\CQMetaEvent;
|
|
|
|
|
|
use ZM\Annotation\CQ\CQNotice;
|
|
|
|
|
|
use ZM\Annotation\CQ\CQRequest;
|
2021-12-07 13:21:29 +08:00
|
|
|
|
use ZM\Config\ZMConfig;
|
2020-11-03 21:02:24 +08:00
|
|
|
|
use ZM\Event\EventDispatcher;
|
|
|
|
|
|
use ZM\Exception\InterruptException;
|
|
|
|
|
|
use ZM\Exception\WaitTimeoutException;
|
2022-04-02 23:37:22 +08:00
|
|
|
|
use ZM\Exception\ZMKnownException;
|
2020-11-03 21:02:24 +08:00
|
|
|
|
use ZM\Utils\CoMessage;
|
2021-03-24 23:34:46 +08:00
|
|
|
|
use ZM\Utils\MessageUtil;
|
|
|
|
|
|
use ZM\Utils\SingletonTrait;
|
2020-11-03 21:02:24 +08:00
|
|
|
|
|
2020-09-29 15:07:43 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* Class QQBot
|
|
|
|
|
|
*/
|
|
|
|
|
|
class QQBot
|
|
|
|
|
|
{
|
2021-03-24 23:34:46 +08:00
|
|
|
|
use SingletonTrait;
|
|
|
|
|
|
|
2022-04-02 23:37:22 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @throws ZMKnownException
|
|
|
|
|
|
* @throws InterruptException
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
public function handleByEvent()
|
|
|
|
|
|
{
|
2022-04-02 23:37:22 +08:00
|
|
|
|
$data = json_decode(ctx()->getFrame()->data, true);
|
2021-03-24 23:34:46 +08:00
|
|
|
|
$this->handle($data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-11-03 21:02:24 +08:00
|
|
|
|
/**
|
2022-04-02 23:37:22 +08:00
|
|
|
|
* @param array|Iterator $data 数据包
|
|
|
|
|
|
* @param int $level 递归等级
|
2020-11-03 21:02:24 +08:00
|
|
|
|
* @throws InterruptException
|
2022-04-02 23:37:22 +08:00
|
|
|
|
* @throws ZMKnownException
|
|
|
|
|
|
* @throws Exception
|
2020-11-03 21:02:24 +08:00
|
|
|
|
*/
|
2022-04-02 23:37:22 +08:00
|
|
|
|
public function handle($data, int $level = 0)
|
2022-03-15 18:05:33 +08:00
|
|
|
|
{
|
2020-11-03 21:02:24 +08:00
|
|
|
|
try {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($level > 10) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
set_coroutine_params(['data' => $data]);
|
|
|
|
|
|
if (isset($data['post_type'])) {
|
2022-03-20 16:23:07 +08:00
|
|
|
|
// echo TermColor::ITALIC.json_encode($data, 128|256).TermColor::RESET.PHP_EOL;
|
2022-03-15 18:05:33 +08:00
|
|
|
|
ctx()->setCache('level', $level);
|
2022-03-20 16:23:07 +08:00
|
|
|
|
// Console::debug("Calling CQ Event from fd=" . ctx()->getConnection()->getFd());
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($data['post_type'] != 'meta_event') {
|
|
|
|
|
|
$r = $this->dispatchBeforeEvents($data, 'pre'); // before在这里执行,元事件不执行before为减少不必要的调试日志
|
|
|
|
|
|
if ($r->store === 'block') {
|
|
|
|
|
|
EventDispatcher::interrupt();
|
|
|
|
|
|
}
|
2021-01-02 13:15:50 +08:00
|
|
|
|
}
|
2022-03-20 16:23:07 +08:00
|
|
|
|
// Console::warning("最上数据包:".json_encode($data));
|
2020-11-03 21:02:24 +08:00
|
|
|
|
}
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if (isset($data['echo']) || isset($data['post_type'])) {
|
|
|
|
|
|
if (CoMessage::resumeByWS()) {
|
|
|
|
|
|
EventDispatcher::interrupt();
|
|
|
|
|
|
}
|
2021-01-30 00:06:42 +08:00
|
|
|
|
}
|
2022-03-15 18:05:33 +08:00
|
|
|
|
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);
|
2021-03-24 23:34:46 +08:00
|
|
|
|
}
|
2021-12-07 13:21:29 +08:00
|
|
|
|
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if (($data['post_type'] ?? 'meta_event') != 'meta_event') {
|
2021-12-07 13:21:29 +08:00
|
|
|
|
$r = $this->dispatchAfterEvents($data); // before在这里执行,元事件不执行before为减少不必要的调试日志
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($r->store === 'block') {
|
|
|
|
|
|
EventDispatcher::interrupt();
|
|
|
|
|
|
}
|
2021-12-07 13:21:29 +08:00
|
|
|
|
}
|
2022-03-15 18:05:33 +08:00
|
|
|
|
} /* @noinspection PhpRedundantCatchClauseInspection */ catch (WaitTimeoutException $e) {
|
|
|
|
|
|
if (($data['post_type'] ?? 'meta_event') != 'meta_event') {
|
2021-12-07 13:21:29 +08:00
|
|
|
|
$r = $this->dispatchAfterEvents($data); // before在这里执行,元事件不执行before为减少不必要的调试日志
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($r->store === 'block') {
|
|
|
|
|
|
EventDispatcher::interrupt();
|
|
|
|
|
|
}
|
2021-12-07 13:21:29 +08:00
|
|
|
|
}
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$e->module->finalReply($e->getMessage());
|
2021-12-07 13:21:29 +08:00
|
|
|
|
} catch (InterruptException $e) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if (($data['post_type'] ?? 'meta_event') != 'meta_event') {
|
2021-12-07 13:21:29 +08:00
|
|
|
|
$r = $this->dispatchAfterEvents($data); // before在这里执行,元事件不执行before为减少不必要的调试日志
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($r->store === 'block') {
|
|
|
|
|
|
EventDispatcher::interrupt();
|
|
|
|
|
|
}
|
2021-12-07 13:21:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
throw $e;
|
2020-11-03 21:02:24 +08:00
|
|
|
|
}
|
2021-12-07 13:21:29 +08:00
|
|
|
|
// 这里修复CQAfter不能使用的问题,我竟然一直没写,绝了
|
2020-11-03 21:02:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-02 13:15:50 +08:00
|
|
|
|
/**
|
2022-04-02 23:37:22 +08:00
|
|
|
|
* @param array|Iterator $data 数据包
|
|
|
|
|
|
* @param string $time 类型(pre或post)
|
2021-01-29 23:34:34 +08:00
|
|
|
|
* @throws Exception
|
2021-01-02 13:15:50 +08:00
|
|
|
|
*/
|
2022-04-02 23:37:22 +08:00
|
|
|
|
public function dispatchBeforeEvents($data, string $time): EventDispatcher
|
2022-03-15 18:05:33 +08:00
|
|
|
|
{
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$before = new EventDispatcher(CQBefore::class);
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if ($time === 'pre') {
|
2021-11-16 16:49:32 +08:00
|
|
|
|
$before->setRuleFunction(function ($v) use ($data) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
return $v->level >= 200 && $v->cq_event == $data['post_type'];
|
2021-03-24 23:34:46 +08:00
|
|
|
|
});
|
|
|
|
|
|
} else {
|
2021-11-16 16:49:32 +08:00
|
|
|
|
$before->setRuleFunction(function ($v) use ($data) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
return $v->level < 200 && $v->cq_event == $data['post_type'];
|
2021-03-24 23:34:46 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$before->setReturnFunction(function ($result) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if (!$result) {
|
|
|
|
|
|
EventDispatcher::interrupt('block');
|
|
|
|
|
|
}
|
2020-11-03 21:02:24 +08:00
|
|
|
|
});
|
|
|
|
|
|
$before->dispatchEvents($data);
|
2021-01-02 13:15:50 +08:00
|
|
|
|
return $before;
|
2020-11-03 21:02:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-02 13:15:50 +08:00
|
|
|
|
/**
|
2022-04-02 23:37:22 +08:00
|
|
|
|
* @param array|Iterator $data 数据包
|
2021-01-02 13:15:50 +08:00
|
|
|
|
* @throws InterruptException
|
2021-03-18 14:56:35 +08:00
|
|
|
|
* @throws Exception
|
2021-01-02 13:15:50 +08:00
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
private function dispatchEvents($data)
|
|
|
|
|
|
{
|
2022-03-20 16:23:07 +08:00
|
|
|
|
// Console::warning("最xia数据包:".json_encode($data));
|
2022-03-15 18:05:33 +08:00
|
|
|
|
switch ($data['post_type']) {
|
|
|
|
|
|
case 'message':
|
2022-03-20 16:23:07 +08:00
|
|
|
|
// 分发CQCommand事件
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$dispatcher = new EventDispatcher(CQCommand::class);
|
|
|
|
|
|
$dispatcher->setReturnFunction(function ($result) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if (is_string($result)) {
|
|
|
|
|
|
ctx()->reply($result);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ctx()->getCache('has_reply') === true) {
|
|
|
|
|
|
EventDispatcher::interrupt();
|
|
|
|
|
|
}
|
2020-11-03 21:02:24 +08:00
|
|
|
|
});
|
2022-04-02 23:37:22 +08:00
|
|
|
|
$msg = $data['message'];
|
|
|
|
|
|
if (is_array($msg)) {
|
|
|
|
|
|
$msg = MessageUtil::arrayToStr($msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
$s = MessageUtil::matchCommand($msg, ctx()->getData());
|
2021-03-24 23:34:46 +08:00
|
|
|
|
if ($s->status !== false) {
|
2022-05-03 10:06:57 +08:00
|
|
|
|
$match = $s->match;
|
|
|
|
|
|
|
|
|
|
|
|
$input_arguments = MessageUtil::checkArguments($s->object->class, $s->object->method, $match);
|
|
|
|
|
|
if (!empty($match)) {
|
|
|
|
|
|
ctx()->setCache('match', $match);
|
2022-03-15 18:05:33 +08:00
|
|
|
|
}
|
2022-05-03 10:06:57 +08:00
|
|
|
|
$dispatcher->dispatchEvent($s->object, null, ...$input_arguments);
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if (is_string($dispatcher->store)) {
|
|
|
|
|
|
ctx()->reply($dispatcher->store);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ctx()->getCache('has_reply') === true) {
|
|
|
|
|
|
$policy = ZMConfig::get('global', 'onebot')['message_command_policy'] ?? 'interrupt';
|
2021-12-07 13:21:29 +08:00
|
|
|
|
switch ($policy) {
|
|
|
|
|
|
case 'interrupt':
|
|
|
|
|
|
EventDispatcher::interrupt();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'continue':
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
2022-03-15 18:05:33 +08:00
|
|
|
|
throw new Exception('未知的消息命令策略:' . $policy);
|
2021-12-07 13:21:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-03-24 23:34:46 +08:00
|
|
|
|
}
|
2020-11-03 21:02:24 +08:00
|
|
|
|
|
2022-03-20 16:23:07 +08:00
|
|
|
|
// 分发CQMessage事件
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$msg_dispatcher = new EventDispatcher(CQMessage::class);
|
|
|
|
|
|
$msg_dispatcher->setRuleFunction(function ($v) {
|
2022-04-02 23:37:22 +08:00
|
|
|
|
return ($v->message == '' || ($v->message == ctx()->getMessage()))
|
2022-03-15 18:05:33 +08:00
|
|
|
|
&& ($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']));
|
2020-11-03 21:02:24 +08:00
|
|
|
|
});
|
|
|
|
|
|
$msg_dispatcher->setReturnFunction(function ($result) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
if (is_string($result)) {
|
|
|
|
|
|
ctx()->reply($result);
|
|
|
|
|
|
}
|
2020-11-03 21:02:24 +08:00
|
|
|
|
});
|
|
|
|
|
|
$msg_dispatcher->dispatchEvents(ctx()->getMessage());
|
|
|
|
|
|
return;
|
2022-03-15 18:05:33 +08:00
|
|
|
|
case 'meta_event':
|
2022-03-20 16:23:07 +08:00
|
|
|
|
// Console::success("当前数据包:".json_encode(ctx()->getData()));
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$dispatcher = new EventDispatcher(CQMetaEvent::class);
|
|
|
|
|
|
$dispatcher->setRuleFunction(function (CQMetaEvent $v) {
|
2022-04-02 23:37:22 +08:00
|
|
|
|
return $v->meta_event_type == '' || ($v->meta_event_type == ctx()->getData()['meta_event_type']);
|
2020-11-03 21:02:24 +08:00
|
|
|
|
});
|
2022-03-20 16:23:07 +08:00
|
|
|
|
// eval(BP);
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$dispatcher->dispatchEvents(ctx()->getData());
|
|
|
|
|
|
return;
|
2022-03-15 18:05:33 +08:00
|
|
|
|
case 'notice':
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$dispatcher = new EventDispatcher(CQNotice::class);
|
|
|
|
|
|
$dispatcher->setRuleFunction(function (CQNotice $v) {
|
|
|
|
|
|
return
|
2022-04-02 23:37:22 +08:00
|
|
|
|
($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']));
|
2020-11-03 21:02:24 +08:00
|
|
|
|
});
|
|
|
|
|
|
$dispatcher->dispatchEvents(ctx()->getData());
|
|
|
|
|
|
return;
|
2022-03-15 18:05:33 +08:00
|
|
|
|
case 'request':
|
2020-11-03 21:02:24 +08:00
|
|
|
|
$dispatcher = new EventDispatcher(CQRequest::class);
|
|
|
|
|
|
$dispatcher->setRuleFunction(function (CQRequest $v) {
|
2022-04-02 23:37:22 +08:00
|
|
|
|
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']));
|
2020-11-03 21:02:24 +08:00
|
|
|
|
});
|
|
|
|
|
|
$dispatcher->dispatchEvents(ctx()->getData());
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-04-02 23:37:22 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @param mixed $data 分发事件数据包
|
|
|
|
|
|
* @throws Exception
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
private function dispatchAfterEvents($data): EventDispatcher
|
|
|
|
|
|
{
|
2021-12-07 13:21:29 +08:00
|
|
|
|
$after = new EventDispatcher(CQAfter::class);
|
|
|
|
|
|
$after->setRuleFunction(function ($v) use ($data) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
return $v->cq_event == $data['post_type'];
|
2021-12-07 13:21:29 +08:00
|
|
|
|
});
|
|
|
|
|
|
$after->dispatchEvents($data);
|
|
|
|
|
|
return $after;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-29 23:34:34 +08:00
|
|
|
|
/**
|
2022-04-02 23:37:22 +08:00
|
|
|
|
* @param mixed $req
|
2021-01-29 23:34:34 +08:00
|
|
|
|
* @throws Exception
|
|
|
|
|
|
*/
|
2022-03-15 18:05:33 +08:00
|
|
|
|
private function dispatchAPIResponse($req)
|
|
|
|
|
|
{
|
|
|
|
|
|
set_coroutine_params(['cq_response' => $req]);
|
2021-01-29 23:34:34 +08:00
|
|
|
|
$dispatcher = new EventDispatcher(CQAPIResponse::class);
|
|
|
|
|
|
$dispatcher->setRuleFunction(function (CQAPIResponse $response) {
|
2022-03-15 18:05:33 +08:00
|
|
|
|
return $response->retcode == ctx()->getCQResponse()['retcode'];
|
2021-01-29 23:34:34 +08:00
|
|
|
|
});
|
|
|
|
|
|
$dispatcher->dispatchEvents($req);
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|