diff --git a/src/ZM/Context/Trait/BotActionTrait.php b/src/ZM/Context/Trait/BotActionTrait.php index f8db6c0e..b39db513 100644 --- a/src/ZM/Context/Trait/BotActionTrait.php +++ b/src/ZM/Context/Trait/BotActionTrait.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace ZM\Context\Trait; use Choir\Http\HttpFactory; +use OneBot\Driver\Coroutine\Adaptive; use OneBot\Driver\Event\Http\HttpRequestEvent; use OneBot\Driver\Event\WebSocket\WebSocketMessageEvent; use OneBot\Util\Utils; @@ -18,9 +19,28 @@ use ZM\Utils\MessageUtil; trait BotActionTrait { + /** + * @var array 一个记录 echo 对应协程 ID 的列表,用于恢复协程 + */ + private static array $coroutine_list = []; + private null|WebSocketMessageEvent|HttpRequestEvent $base_event; /** + * @internal 只允许内部调用 + * @param ActionResponse $response 尝试调用看看有没有协程等待的 + */ + public static function tryResume(ActionResponse $response): void + { + if (($co = Adaptive::getCoroutine()) !== null && isset(self::$coroutine_list[$response->echo ?? ''])) { + $co->resume(self::$coroutine_list[$response->echo ?? ''], $response); + } + } + + /** + * 发送一条机器人消息 + * + * @param array|MessageSegment|string|\Stringable $message 消息内容,可以是消息段、字符串 * @throws \Throwable */ public function sendMessage(\Stringable|array|MessageSegment|string $message, string $detail_type, array $params = []): ActionResponse|bool @@ -40,7 +60,6 @@ trait BotActionTrait { // 声明 Action 对象 $a = new Action($action, $params, ob_uuidgen(), $self); - self::$echo_id_list[$a->echo] = $a; // 调用事件在回复之前的回调 $handler = new AnnotationHandler(BotAction::class); container()->set(Action::class, $a); @@ -51,7 +70,7 @@ trait BotActionTrait return false; } - // 调用机器人连接发送 Action + // 调用机器人连接发送 Action,首先试试看是不是 WebSocket if ($this->base_event instanceof WebSocketMessageEvent) { $result = $this->base_event->send(json_encode($a->jsonSerialize())); } @@ -69,13 +88,19 @@ trait BotActionTrait container()->get('http.request.event')->withResponse($response); $result = true; } + // 如果开启了协程,并且成功发送,那就进入协程等待,挂起等待结果返回一个 ActionResponse 对象 + if (($result ?? false) === true && ($co = Adaptive::getCoroutine()) !== null) { + self::$coroutine_list[$a->echo] = $co->getCid(); + $response = $co->suspend(); + if ($response instanceof ActionResponse) { + return $response; + } + return false; + } if (isset($result)) { return $result; } - /* TODO: 协程支持 - if (($result ?? false) === true && ($co = Adaptive::getCoroutine()) !== null) { - return $result ?? false; - }*/ + // 到这里表明你调用时候不在 WS 或 HTTP 上下文 throw new OneBot12Exception('No bot connection found.'); } }