Files
zhamao-framework/src/ZM/Context/Context.php

369 lines
10 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
2020-04-15 10:55:10 +08:00
namespace ZM\Context;
2020-11-08 19:40:16 +08:00
use Exception;
2022-04-02 23:37:22 +08:00
use Stringable;
2021-06-16 00:17:30 +08:00
use Swoole\Coroutine;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
use ZM\API\ZMRobot;
2021-11-16 15:41:01 +08:00
use ZM\Config\ZMConfig;
2020-08-31 10:11:06 +08:00
use ZM\ConnectionManager\ConnectionObject;
use ZM\ConnectionManager\ManagerGM;
use ZM\Console\Console;
use ZM\Event\EventDispatcher;
use ZM\Exception\InterruptException;
2020-05-06 17:26:50 +08:00
use ZM\Exception\InvalidArgumentException;
use ZM\Exception\WaitTimeoutException;
2022-04-02 23:37:22 +08:00
use ZM\Exception\ZMKnownException;
use ZM\Http\Response;
2020-11-03 21:02:24 +08:00
use ZM\Utils\CoMessage;
2021-11-16 15:41:01 +08:00
use ZM\Utils\MessageUtil;
2020-04-15 10:55:10 +08:00
class Context implements ContextInterface
{
2020-09-29 15:07:43 +08:00
public static $context = [];
private $cid;
public function __construct($cid)
{
$this->cid = $cid;
}
/**
* @return Server
*/
public function getServer(): ?Server
{
return self::$context[$this->cid]['server'] ?? server();
}
public function getFrame(): ?Frame
{
return self::$context[$this->cid]['frame'] ?? null;
}
2020-05-06 17:26:50 +08:00
public function getFd(): ?int
{
return self::$context[$this->cid]['fd'] ?? $this->getFrame()->fd ?? null;
}
/**
* @return mixed
*/
public function getData()
{
return self::$context[$this->cid]['data'] ?? null;
}
2020-05-06 17:26:50 +08:00
public function setData($data)
{
self::$context[$this->cid]['data'] = $data;
}
public function getRequest(): ?Request
{
return self::$context[$this->cid]['request'] ?? null;
}
public function getResponse(): ?Response
{
return self::$context[$this->cid]['response'] ?? null;
}
2020-05-06 17:26:50 +08:00
public function getConnection(): ?ConnectionObject
{
return ManagerGM::get($this->getFd());
}
public function getCid(): ?int
{
return $this->cid;
}
public function getRobot(): ?ZMRobot
{
2020-08-31 10:11:06 +08:00
$conn = ManagerGM::get($this->getFrame()->fd);
return $conn instanceof ConnectionObject ? new ZMRobot($conn) : null;
}
2020-05-06 17:26:50 +08:00
public function getMessage()
{
if ((ZMConfig::get('global', 'onebot')['message_convert_string'] ?? true) === true && is_array($msg = $this->getOriginMessage())) {
2021-11-16 15:41:01 +08:00
return MessageUtil::arrayToStr($msg);
}
return self::$context[$this->cid]['data']['message'] ?? null;
2021-11-16 15:41:01 +08:00
}
2020-05-06 17:26:50 +08:00
public function setMessage($msg)
{
2021-11-16 15:41:01 +08:00
if (is_string($msg) && is_array($this->getOriginMessage())) {
$msg = MessageUtil::strToArray($msg);
}
self::$context[$this->cid]['data']['message'] = $msg;
2021-11-16 15:41:01 +08:00
}
2020-05-06 17:26:50 +08:00
public function getUserId()
{
return $this->getData()['user_id'] ?? null;
}
2020-05-06 17:26:50 +08:00
public function setUserId($id)
{
self::$context[$this->cid]['data']['user_id'] = $id;
}
2020-05-06 17:26:50 +08:00
public function getGroupId()
{
return $this->getData()['group_id'] ?? null;
}
2020-05-06 17:26:50 +08:00
public function setGroupId($id)
{
self::$context[$this->cid]['data']['group_id'] = $id;
}
2020-05-06 17:26:50 +08:00
public function getDiscussId()
{
return $this->getData()['discuss_id'] ?? null;
}
2020-05-06 17:26:50 +08:00
public function setDiscussId($id)
{
self::$context[$this->cid]['data']['discuss_id'] = $id;
}
2020-05-06 17:26:50 +08:00
public function getMessageType(): ?string
{
return $this->getData()['message_type'] ?? null;
}
2020-05-06 17:26:50 +08:00
public function setMessageType($type)
{
self::$context[$this->cid]['data']['message_type'] = $type;
}
2020-05-06 17:26:50 +08:00
public function getRobotId()
{
return $this->getData()['self_id'] ?? null;
}
2020-05-06 17:26:50 +08:00
public function getCache($key)
{
return self::$context[$this->cid]['cache'][$key] ?? null;
}
2020-05-06 17:26:50 +08:00
public function setCache($key, $value)
{
self::$context[$this->cid]['cache'][$key] = $value;
}
2020-05-06 17:26:50 +08:00
public function getCQResponse()
{
return self::$context[$this->cid]['cq_response'] ?? null;
}
2020-05-23 17:23:29 +08:00
2020-05-06 17:26:50 +08:00
/**
* only can used by cq->message event function
2022-04-02 23:37:22 +08:00
* @param array|string $msg 要回复的消息
* @param bool $yield 是否协程挂起true是否绑定异步事件Closure
* @return array|bool 返回API调用结果
2020-05-06 17:26:50 +08:00
*/
public function reply($msg, $yield = false)
{
$data = $this->getData();
$conn = $this->getConnection();
if (!is_array($msg)) {
switch ($this->getData()['message_type']) {
case 'group':
case 'private':
case 'discuss':
$this->setCache('has_reply', true);
$operation['reply'] = $msg;
$operation['at_sender'] = false;
return (new ZMRobot($conn))->setCallback($yield)->callExtendedAPI('.handle_quick_operation', [
'context' => $data,
'operation' => $operation,
]);
}
return false;
2020-05-06 17:26:50 +08:00
}
$operation = $msg;
return (new ZMRobot($conn))->setCallback(false)->callExtendedAPI('.handle_quick_operation', [
'context' => $data,
'operation' => $operation,
]);
2020-05-06 17:26:50 +08:00
}
/**
2022-04-02 23:37:22 +08:00
* @param array|string $msg 要回复的消息
* @param bool $yield 是否协程挂起true是否绑定异步事件Closure
* @throws InterruptException 阻止消息被后续插件处理
*/
public function finalReply($msg, $yield = false)
{
self::$context[$this->cid]['cache']['block_continue'] = true;
if ($msg != '') {
$this->reply($msg, $yield);
}
EventDispatcher::interrupt();
2020-05-06 17:26:50 +08:00
}
/**
* @param string $prompt
* @param int $timeout
* @param string $timeout_prompt
2020-05-06 17:26:50 +08:00
* @throws WaitTimeoutException
2022-03-21 20:49:09 +08:00
* @throws InvalidArgumentException
2022-04-02 23:37:22 +08:00
* @return string 返回用户输入的内容
2020-05-06 17:26:50 +08:00
*/
public function waitMessage($prompt = '', $timeout = 600, $timeout_prompt = '')
{
if (!isset($this->getData()['user_id'], $this->getData()['message'], $this->getData()['self_id'])) {
throw new InvalidArgumentException('协程等待参数缺失');
}
2020-11-03 21:02:24 +08:00
Console::debug('==== 开始等待输入 ====');
if ($prompt != '') {
$this->reply($prompt);
}
2020-11-03 21:02:24 +08:00
2020-11-08 19:40:16 +08:00
try {
2022-03-21 20:49:09 +08:00
$r = CoMessage::yieldByWS($this->getData(), ['user_id', 'self_id', 'message_type', get_onebot_target_id_name($this->getMessageType())], $timeout);
2020-11-08 19:40:16 +08:00
} catch (Exception $e) {
$r = false;
}
if ($r === false) {
2020-11-03 21:02:24 +08:00
throw new WaitTimeoutException($this, $timeout_prompt);
}
if (is_array($r['message']) && (ZMConfig::get('global', 'onebot')['message_convert_string'] ?? true) === true) {
return MessageUtil::arrayToStr($r['message']);
2021-11-16 16:49:32 +08:00
}
return $r['message'];
2020-05-06 17:26:50 +08:00
}
/**
2022-04-02 23:37:22 +08:00
* 根据选定的模式获取消息参数
* @param int|string $mode 获取的模式
* @param string|Stringable $prompt_msg 提示语回复
2022-03-21 20:49:09 +08:00
* @throws InvalidArgumentException
2022-04-02 23:37:22 +08:00
* @throws ZMKnownException
* @throws WaitTimeoutException
* @return mixed|string
2020-05-06 17:26:50 +08:00
*/
public function getArgs($mode, $prompt_msg)
{
$arg = ctx()->getCache('match') ?? [];
2020-05-06 17:26:50 +08:00
switch ($mode) {
case ZM_MATCH_ALL:
$p = $arg;
return trim(implode(' ', $p)) == '' ? $this->waitMessage($prompt_msg) : trim(implode(' ', $p));
2020-05-06 17:26:50 +08:00
case ZM_MATCH_NUMBER:
foreach ($arg as $k => $v) {
if (is_numeric($v)) {
array_splice($arg, $k, 1);
ctx()->setCache('match', $arg);
2020-05-06 17:26:50 +08:00
return $v;
}
}
return $this->waitMessage($prompt_msg);
case ZM_MATCH_FIRST:
if (isset($arg[0])) {
$a = $arg[0];
array_splice($arg, 0, 1);
ctx()->setCache('match', $arg);
2020-05-06 17:26:50 +08:00
return $a;
}
2022-03-21 20:49:09 +08:00
return $this->waitMessage($prompt_msg);
2020-05-06 17:26:50 +08:00
}
throw new InvalidArgumentException();
}
/**
2022-04-02 23:37:22 +08:00
* 获取下一个参数
* @param string $prompt_msg 提示语回复
2022-03-21 20:49:09 +08:00
* @throws InvalidArgumentException
2022-04-02 23:37:22 +08:00
* @throws ZMKnownException
* @throws WaitTimeoutException
* @return int|mixed|string 返回获取的参数
*/
public function getNextArg($prompt_msg = '')
{
return $this->getArgs(ZM_MATCH_FIRST, $prompt_msg);
}
/**
2022-04-02 23:37:22 +08:00
* 获取接下来所有的消息当成一个完整的参数(包含空格)
* @param string $prompt_msg 提示语回复
2022-03-21 20:49:09 +08:00
* @throws InvalidArgumentException
2022-04-02 23:37:22 +08:00
* @throws ZMKnownException
* @throws WaitTimeoutException
* @return int|mixed|string 返回获取的参数
*/
public function getFullArg($prompt_msg = '')
{
return $this->getArgs(ZM_MATCH_ALL, $prompt_msg);
}
2021-01-05 16:19:35 +08:00
/**
2022-04-02 23:37:22 +08:00
* 获取下一个数字类型的参数
* @param string $prompt_msg 提示语回复
2022-03-21 20:49:09 +08:00
* @throws InvalidArgumentException
2022-04-02 23:37:22 +08:00
* @throws ZMKnownException
* @throws WaitTimeoutException
* @return int|mixed|string 返回获取的参数
2021-01-05 16:19:35 +08:00
*/
public function getNumArg($prompt_msg = '')
{
return $this->getArgs(ZM_MATCH_NUMBER, $prompt_msg);
}
2021-01-05 16:19:35 +08:00
2022-04-02 23:37:22 +08:00
/**
* @throws ZMKnownException
* @return ContextInterface 返回上下文
*/
public function cloneFromParent(): ContextInterface
{
2021-06-16 00:17:30 +08:00
set_coroutine_params(self::$context[Coroutine::getPcid()] ?? self::$context[$this->cid]);
2020-05-06 17:26:50 +08:00
return context();
}
public function copy()
{
return self::$context[$this->cid];
2021-11-16 16:49:32 +08:00
}
public function getOption()
{
return self::getCache('match');
}
public function getOriginMessage()
{
return self::$context[$this->cid]['data']['message'] ?? null;
}
public function getArrayMessage(): array
{
2021-11-16 16:49:32 +08:00
$msg = $this->getOriginMessage();
if (is_array($msg)) {
return $msg;
}
return MessageUtil::strToArray($msg);
}
public function getStringMessage(): string
{
$msg = $this->getOriginMessage();
if (is_string($msg)) {
return $msg;
}
return MessageUtil::arrayToStr($msg);
2021-11-16 16:49:32 +08:00
}
}