mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-21 15:45:36 +08:00
tmp connect
This commit is contained in:
@@ -4,9 +4,13 @@
|
||||
namespace ZM\Utils;
|
||||
|
||||
|
||||
use ZM\Annotation\CQ\CQCommand;
|
||||
use ZM\API\CQ;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Entity\MatchResult;
|
||||
use ZM\Event\EventDispatcher;
|
||||
use ZM\Event\EventManager;
|
||||
use ZM\Requests\ZMRequest;
|
||||
|
||||
class MessageUtil
|
||||
@@ -55,6 +59,10 @@ class MessageUtil
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function isAtMe($msg, $me_id) {
|
||||
return strpos($msg, CQ::at($me_id)) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过本地地址返回图片的 CQ 码
|
||||
* type == 0 : 返回图片的 base64 CQ 码
|
||||
@@ -76,4 +84,80 @@ class MessageUtil
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 分割字符,将用户消息通过空格或换行分割为数组
|
||||
* @param $msg
|
||||
* @return array|string[]
|
||||
*/
|
||||
public static function splitCommand($msg) {
|
||||
$word = explodeMsg(str_replace("\r", "", $msg));
|
||||
if (empty($word)) $word = [""];
|
||||
if (count(explode("\n", $word[0])) >= 2) {
|
||||
$enter = explode("\n", $msg);
|
||||
$first = split_explode(" ", array_shift($enter));
|
||||
$word = array_merge($first, $enter);
|
||||
foreach ($word as $k => $v) {
|
||||
$word[$k] = trim($word[$k]);
|
||||
}
|
||||
}
|
||||
return $word;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $msg
|
||||
* @param $obj
|
||||
* @return MatchResult
|
||||
*/
|
||||
public static function matchCommand($msg, $obj) {
|
||||
$ls = EventManager::$events[CQCommand::class];
|
||||
$word = self::splitCommand($msg);
|
||||
$matched = new MatchResult();
|
||||
foreach ($ls as $k => $v) {
|
||||
if (array_diff([$v->match, $v->pattern, $v->regex, $v->keyword, $v->end_with, $v->start_with], [""]) == []) continue;
|
||||
elseif (($v->user_id == 0 || ($v->user_id != 0 && $v->user_id == $obj["user_id"])) &&
|
||||
($v->group_id == 0 || ($v->group_id != 0 && $v->group_id == ($obj["group_id"] ?? 0))) &&
|
||||
($v->message_type == '' || ($v->message_type != '' && $v->message_type == $obj["message_type"]))
|
||||
) {
|
||||
if (($word[0] != "" && $v->match == $word[0]) || in_array($word[0], $v->alias)) {
|
||||
array_shift($word);
|
||||
$matched->match = $word;
|
||||
$matched->object = $v;
|
||||
$matched->status = true;
|
||||
break;
|
||||
} elseif ($v->start_with != "" && mb_strpos($msg, $v->start_with) === 0) {
|
||||
$matched->match = [mb_substr($msg, mb_strlen($v->start_with))];
|
||||
$matched->object = $v;
|
||||
$matched->status = true;
|
||||
break;
|
||||
} elseif ($v->end_with != "" && strlen($msg) == (strripos($msg, $v->end_with) + strlen($v->end_with))) {
|
||||
$matched->match = [substr($msg, 0, strripos($msg, $v->end_with))];
|
||||
$matched->object = $v;
|
||||
$matched->status = true;
|
||||
break;
|
||||
} elseif ($v->keyword != "" && mb_strpos($msg, $v->keyword) !== false) {
|
||||
$matched->match = explode($v->keyword, $msg);
|
||||
$matched->object = $v;
|
||||
$matched->status = true;
|
||||
break;
|
||||
} elseif ($v->pattern != "") {
|
||||
$match = matchArgs($v->pattern, $msg);
|
||||
if ($match !== false) {
|
||||
$matched->match = $match;
|
||||
$matched->object = $v;
|
||||
$matched->status = true;
|
||||
break;
|
||||
}
|
||||
} elseif ($v->regex != "") {
|
||||
if (preg_match("/" . $v->regex . "/u", $msg, $word2) != 0) {
|
||||
$matched->match = $word2;
|
||||
$matched->object = $v;
|
||||
$matched->status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $matched;
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,110 @@
|
||||
namespace ZM\Utils;
|
||||
|
||||
|
||||
use Co;
|
||||
use ZM\Annotation\Swoole\OnPipeMessageEvent;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Event\EventDispatcher;
|
||||
use ZM\Store\LightCache;
|
||||
use ZM\Store\LightCacheInside;
|
||||
use ZM\Store\WorkerCache;
|
||||
|
||||
class ProcessManager
|
||||
{
|
||||
public static function runOnTask($param, $timeout = 0.5, $dst_worker_id = -1) {
|
||||
return server()->taskwait([
|
||||
"action" => "runMethod",
|
||||
"class" => $param["class"],
|
||||
"method" => $param["method"],
|
||||
"params" => $param["params"]
|
||||
], $timeout, $dst_worker_id);
|
||||
public static function workerAction($src_worker_id, $data) {
|
||||
$server = server();
|
||||
switch ($data["action"] ?? '') {
|
||||
case "eval":
|
||||
eval($data["data"]);
|
||||
break;
|
||||
case "call_static":
|
||||
call_user_func_array([$data["data"]["class"], $data["data"]["method"]], $data["data"]["params"]);
|
||||
break;
|
||||
case "save_persistence":
|
||||
LightCache::savePersistence();
|
||||
break;
|
||||
case "resume_ws_message":
|
||||
$obj = $data["data"];
|
||||
Co::resume($obj["coroutine"]);
|
||||
break;
|
||||
case "getWorkerCache":
|
||||
$r = WorkerCache::get($data["key"]);
|
||||
$action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r];
|
||||
$server->sendMessage(json_encode($action, 256), $src_worker_id);
|
||||
break;
|
||||
case "setWorkerCache":
|
||||
$r = WorkerCache::set($data["key"], $data["value"]);
|
||||
$action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r];
|
||||
$server->sendMessage(json_encode($action, 256), $src_worker_id);
|
||||
break;
|
||||
case "unsetWorkerCache":
|
||||
$r = WorkerCache::unset($data["key"]);
|
||||
$action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r];
|
||||
$server->sendMessage(json_encode($action, 256), $src_worker_id);
|
||||
break;
|
||||
case "hasKeyWorkerCache":
|
||||
$r = WorkerCache::hasKey($data["key"], $data["subkey"]);
|
||||
$action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r];
|
||||
$server->sendMessage(json_encode($action, 256), $src_worker_id);
|
||||
break;
|
||||
case "asyncAddWorkerCache":
|
||||
WorkerCache::add($data["key"], $data["value"], true);
|
||||
break;
|
||||
case "asyncSubWorkerCache":
|
||||
WorkerCache::sub($data["key"], $data["value"], true);
|
||||
break;
|
||||
case "asyncSetWorkerCache":
|
||||
WorkerCache::set($data["key"], $data["value"], true);
|
||||
break;
|
||||
case "asyncUnsetWorkerCache":
|
||||
WorkerCache::unset($data["key"], true);
|
||||
break;
|
||||
case "addWorkerCache":
|
||||
$r = WorkerCache::add($data["key"], $data["value"]);
|
||||
$action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r];
|
||||
$server->sendMessage(json_encode($action, 256), $src_worker_id);
|
||||
break;
|
||||
case "subWorkerCache":
|
||||
$r = WorkerCache::sub($data["key"], $data["value"]);
|
||||
$action = ["action" => "returnWorkerCache", "cid" => $data["cid"], "value" => $r];
|
||||
$server->sendMessage(json_encode($action, 256), $src_worker_id);
|
||||
break;
|
||||
case "returnWorkerCache":
|
||||
WorkerCache::$transfer[$data["cid"]] = $data["value"];
|
||||
zm_resume($data["cid"]);
|
||||
break;
|
||||
default:
|
||||
$dispatcher = new EventDispatcher(OnPipeMessageEvent::class);
|
||||
$dispatcher->setRuleFunction(function (OnPipeMessageEvent $v) use ($data) {
|
||||
return $v->action == $data["action"];
|
||||
});
|
||||
$dispatcher->dispatchEvents($data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static function sendActionToWorker($worker_id, $action, $data) {
|
||||
$obj = ["action" => $action, "data" => $data];
|
||||
if (server()->worker_id === -1 && server()->getManagerPid() != posix_getpid()) {
|
||||
Console::warning("Cannot send worker action from master or manager process!");
|
||||
return;
|
||||
}
|
||||
if (server()->worker_id == $worker_id) {
|
||||
self::workerAction($worker_id, $obj);
|
||||
} else {
|
||||
server()->sendMessage(json_encode($obj), $worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
public static function resumeAllWorkerCoroutines() {
|
||||
if (server()->worker_id === -1) {
|
||||
Console::warning("Cannot call '".__FUNCTION__."' in non-worker process!");
|
||||
return;
|
||||
}
|
||||
foreach ((LightCacheInside::get("wait_api", "wait_api") ?? []) as $k => $v) {
|
||||
if (($v["result"] ?? false) === null && isset($v["coroutine"], $v["worker_id"])) {
|
||||
if (server()->worker_id == $v["worker_id"]) Co::resume($v["coroutine"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,22 +6,38 @@ namespace ZM\Utils;
|
||||
|
||||
use Exception;
|
||||
use Psy\Shell;
|
||||
use Swoole\Event;
|
||||
use ZM\Annotation\Command\TerminalCommand;
|
||||
use ZM\ConnectionManager\ManagerGM;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Event\EventDispatcher;
|
||||
use ZM\Event\EventManager;
|
||||
use ZM\Framework;
|
||||
|
||||
class Terminal
|
||||
{
|
||||
/**
|
||||
* @param string $cmd
|
||||
* @param $resource
|
||||
* @return bool
|
||||
* @noinspection PhpMissingReturnTypeInspection
|
||||
* @noinspection PhpUnused
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function executeCommand(string $cmd, $resource) {
|
||||
public static function executeCommand(string $cmd) {
|
||||
$it = explodeMsg($cmd);
|
||||
switch ($it[0] ?? '') {
|
||||
case 'help':
|
||||
$help[] = "exit | q:\t断开远程终端";
|
||||
$help[] = "logtest:\t输出所有可以打印的log等级示例消息,用于测试Console";
|
||||
$help[] = "call:\t\t用于执行不需要参数的动态函数,比如 `call \Module\Example\Hello hitokoto`";
|
||||
$help[] = "level:\t\t设置log等级,例如 `level 0|1|2|3|4`";
|
||||
$help[] = "bc:\t\teval执行代码,但输入必须是将代码base64之后的,如 `bc em1faW5mbygn5L2g5aW9Jyk7`";
|
||||
$help[] = "stop:\t\t停止服务器";
|
||||
$help[] = "reload | r:\t热重启用户编写的模块代码";
|
||||
foreach(EventManager::$events[TerminalCommand::class] as $v) {
|
||||
$help[]=$v->command.":\t\t".(empty($v->description) ? "<用户自定义指令>" : $v->description);
|
||||
}
|
||||
echo implode("\n", $help) . PHP_EOL;
|
||||
return true;
|
||||
case 'logtest':
|
||||
Console::log(date("[H:i:s]") . " [L] This is normal msg. (0)");
|
||||
Console::error("This is error msg. (0)");
|
||||
@@ -35,7 +51,8 @@ class Terminal
|
||||
$class_name = $it[1];
|
||||
$function_name = $it[2];
|
||||
$class = new $class_name([]);
|
||||
$class->$function_name();
|
||||
$r = $class->$function_name();
|
||||
if (is_string($r)) Console::success($r);
|
||||
return true;
|
||||
case 'psysh':
|
||||
if (Framework::$argv["disable-coroutine"]) {
|
||||
@@ -43,6 +60,11 @@ class Terminal
|
||||
} else
|
||||
Console::error("Only \"--disable-coroutine\" mode can use psysh!!!");
|
||||
return true;
|
||||
case 'level':
|
||||
$level = intval(is_numeric($it[1] ?? 99) ? ($it[1] ?? 99) : 99);
|
||||
if ($level > 4 || $level < 0) Console::warning("Usage: 'level 0|1|2|3|4'");
|
||||
else Console::setLevel($level) || Console::success("Success!!");
|
||||
break;
|
||||
case 'bc':
|
||||
$code = base64_decode($it[1] ?? '', true);
|
||||
try {
|
||||
@@ -57,7 +79,6 @@ class Terminal
|
||||
Console::log($it[2], $it[1]);
|
||||
return true;
|
||||
case 'stop':
|
||||
Event::del($resource);
|
||||
ZMUtil::stop();
|
||||
return false;
|
||||
case 'reload':
|
||||
@@ -67,8 +88,35 @@ class Terminal
|
||||
case '':
|
||||
return true;
|
||||
default:
|
||||
Console::info("Command not found: " . $cmd);
|
||||
return true;
|
||||
$dispatcher = new EventDispatcher(TerminalCommand::class);
|
||||
$dispatcher->setRuleFunction(function ($v) use ($it) {
|
||||
/** @var TerminalCommand $v */
|
||||
return $v->command == $it[0];
|
||||
});
|
||||
$dispatcher->setReturnFunction(function () {
|
||||
EventDispatcher::interrupt('none');
|
||||
});
|
||||
$dispatcher->dispatchEvents($it);
|
||||
if ($dispatcher->store !== 'none') {
|
||||
Console::info("Command not found: " . $cmd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function log($type, $log_msg) {
|
||||
ob_start();
|
||||
if (!in_array($type, ["log", "info", "debug", "success", "warning", "error", "verbose"])) {
|
||||
ob_get_clean();
|
||||
return;
|
||||
}
|
||||
Console::$type($log_msg);
|
||||
$r = ob_get_clean();
|
||||
$all = ManagerGM::getAllByName("terminal");
|
||||
foreach ($all as $k => $v) {
|
||||
server()->send($v->getFd(), "\r" . $r);
|
||||
server()->send($v->getFd(), ">>> ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,10 @@
|
||||
namespace ZM\Utils;
|
||||
|
||||
|
||||
use Co;
|
||||
use Exception;
|
||||
use Swoole\Event;
|
||||
use Swoole\Timer;
|
||||
use Swoole\Process;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Store\LightCache;
|
||||
use ZM\Store\LightCacheInside;
|
||||
use ZM\Framework;
|
||||
use ZM\Store\Lock\SpinLock;
|
||||
use ZM\Store\ZMAtomic;
|
||||
use ZM\Store\ZMBuf;
|
||||
@@ -24,39 +21,20 @@ class ZMUtil
|
||||
if (SpinLock::tryLock("_stop_signal") === false) return;
|
||||
Console::warning(Console::setColor("Stopping server...", "red"));
|
||||
if (Console::getLevel() >= 4) Console::trace();
|
||||
LightCache::savePersistence();
|
||||
if (ZMBuf::$terminal !== null)
|
||||
Event::del(ZMBuf::$terminal);
|
||||
ZMAtomic::get("stop_signal")->set(1);
|
||||
try {
|
||||
LightCache::set('stop', 'OK');
|
||||
} catch (Exception $e) {
|
||||
for($i = 0; $i < ZM_WORKER_NUM; ++$i) {
|
||||
Process::kill(zm_atomic("_#worker_".$i)->get(), SIGUSR1);
|
||||
}
|
||||
server()->shutdown();
|
||||
server()->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $delay
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function reload($delay = 800) {
|
||||
if (server()->worker_id !== -1) {
|
||||
Console::info(server()->worker_id);
|
||||
zm_atomic("_int_is_reload")->set(1);
|
||||
system("kill -INT " . intval(server()->master_pid));
|
||||
return;
|
||||
}
|
||||
Console::info(Console::setColor("Reloading server...", "gold"));
|
||||
usleep($delay * 1000);
|
||||
foreach ((LightCacheInside::get("wait_api", "wait_api") ?? []) as $k => $v) {
|
||||
if (($v["result"] ?? false) === null && isset($v["coroutine"])) Co::resume($v["coroutine"]);
|
||||
}
|
||||
LightCacheInside::unset("wait_api", "wait_api");
|
||||
LightCache::savePersistence();
|
||||
//DataProvider::saveBuffer();
|
||||
Timer::clearAll();
|
||||
server()->reload();
|
||||
public static function reload() {
|
||||
zm_atomic("_int_is_reload")->set(1);
|
||||
system("kill -INT " . intval(server()->master_pid));
|
||||
}
|
||||
|
||||
public static function getModInstance($class) {
|
||||
@@ -69,6 +47,22 @@ class ZMUtil
|
||||
}
|
||||
|
||||
public static function sendActionToWorker($target_id, $action, $data) {
|
||||
Console::verbose($action . ": " . $data);
|
||||
server()->sendMessage(json_encode(["action" => $action, "data" => $data]), $target_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在工作进程中返回可以通过reload重新加载的php文件列表
|
||||
* @return string[]|string[][]
|
||||
*/
|
||||
public static function getReloadableFiles() {
|
||||
return array_map(
|
||||
function ($x) {
|
||||
return str_replace(DataProvider::getWorkingDir() . "/", "", $x);
|
||||
}, array_diff(
|
||||
get_included_files(),
|
||||
Framework::$loaded_files
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user