mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-23 00:25:35 +08:00
update to 2.5.0-b1 (build 408)
This commit is contained in:
@@ -4,10 +4,11 @@
|
||||
namespace ZM\Utils;
|
||||
|
||||
|
||||
use Co;
|
||||
use Swoole\Coroutine;
|
||||
use ZM\Store\LightCacheInside;
|
||||
use ZM\Store\Lock\SpinLock;
|
||||
use ZM\Store\ZMAtomic;
|
||||
use ZM\Utils\Manager\ProcessManager;
|
||||
|
||||
class CoMessage
|
||||
{
|
||||
@@ -16,10 +17,9 @@ class CoMessage
|
||||
* @param array $compare
|
||||
* @param int $timeout
|
||||
* @return mixed
|
||||
* @noinspection PhpMissingReturnTypeInspection
|
||||
*/
|
||||
public static function yieldByWS(array $hang, array $compare, $timeout = 600) {
|
||||
$cid = Co::getuid();
|
||||
$cid = Coroutine::getuid();
|
||||
$api_id = ZMAtomic::get("wait_msg_id")->add(1);
|
||||
$hang["compare"] = $compare;
|
||||
$hang["coroutine"] = $cid;
|
||||
@@ -33,10 +33,10 @@ class CoMessage
|
||||
$id = swoole_timer_after($timeout * 1000, function () use ($api_id) {
|
||||
$r = LightCacheInside::get("wait_api", "wait_api")[$api_id] ?? null;
|
||||
if (is_array($r)) {
|
||||
Co::resume($r["coroutine"]);
|
||||
Coroutine::resume($r["coroutine"]);
|
||||
}
|
||||
});
|
||||
Co::suspend();
|
||||
Coroutine::suspend();
|
||||
SpinLock::lock("wait_api");
|
||||
$sess = LightCacheInside::get("wait_api", "wait_api");
|
||||
$result = $sess[$api_id]["result"] ?? null;
|
||||
@@ -70,7 +70,7 @@ class CoMessage
|
||||
if ($all[$last]["worker_id"] != server()->worker_id) {
|
||||
ProcessManager::sendActionToWorker($all[$last]["worker_id"], "resume_ws_message", $all[$last]);
|
||||
} else {
|
||||
Co::resume($all[$last]["coroutine"]);
|
||||
Coroutine::resume($all[$last]["coroutine"]);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -38,6 +38,10 @@ class CoroutinePool
|
||||
self::$sizes[$name] = $size;
|
||||
}
|
||||
|
||||
public static function getRunningCoroutineCount($name = "default") {
|
||||
return count(self::$cids[$name]);
|
||||
}
|
||||
|
||||
private static function checkCids($name) {
|
||||
if (in_array(Coroutine::getCid(), self::$cids[$name])) {
|
||||
$a = array_search(Coroutine::getCid(), self::$cids[$name]);
|
||||
|
||||
@@ -11,44 +11,139 @@ class DataProvider
|
||||
{
|
||||
public static $buffer_list = [];
|
||||
|
||||
/**
|
||||
* 返回资源目录
|
||||
* @return string
|
||||
*/
|
||||
public static function getResourceFolder(): string {
|
||||
return self::getWorkingDir() . '/resources/';
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回工作目录,不带最右边文件夹的斜杠(/)
|
||||
* @return false|string
|
||||
*/
|
||||
public static function getWorkingDir() {
|
||||
return WORKING_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取框架所在根目录
|
||||
* @return false|string
|
||||
*/
|
||||
public static function getFrameworkRootDir() {
|
||||
return FRAMEWORK_ROOT_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取源码根目录,除Phar模式外均与工作目录相同
|
||||
* @return false|string
|
||||
*/
|
||||
public static function getSourceRootDir() {
|
||||
return defined("SOURCE_ROOT_DIR") ? SOURCE_ROOT_DIR : WORKING_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取框架反代链接
|
||||
* @return array|false|mixed|null
|
||||
*/
|
||||
public static function getFrameworkLink() {
|
||||
return ZMConfig::get("global", "http_reverse_link");
|
||||
}
|
||||
|
||||
public static function getDataFolder() {
|
||||
/**
|
||||
* 获取zm_data数据目录,如果二级目录不为空,则自动创建目录并返回
|
||||
* @param string $second
|
||||
* @return array|false|mixed|string|null
|
||||
*/
|
||||
public static function getDataFolder(string $second = '') {
|
||||
if ($second !== '') {
|
||||
@mkdir(ZM_DATA . $second);
|
||||
if (!is_dir(ZM_DATA . $second)) return false;
|
||||
return realpath(ZM_DATA . $second) . "/";
|
||||
}
|
||||
return ZM_DATA;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将变量保存在zm_data下的数据目录,传入数组
|
||||
* @param $filename
|
||||
* @param $file_array
|
||||
* @return false|int
|
||||
*/
|
||||
public static function saveToJson($filename, $file_array) {
|
||||
$path = ZMConfig::get("global", "config_dir");
|
||||
$r = explode("/", $filename);
|
||||
if(count($r) == 2) {
|
||||
$path = $path . $r[0]."/";
|
||||
if(!is_dir($path)) mkdir($path);
|
||||
if (count($r) == 2) {
|
||||
$path = $path . $r[0] . "/";
|
||||
if (!is_dir($path)) mkdir($path);
|
||||
$name = $r[1];
|
||||
} elseif (count($r) != 1) {
|
||||
Console::warning("存储失败,文件名只能有一级目录");
|
||||
Console::warning(zm_internal_errcode("E00057") . "存储失败,文件名只能有一级目录");
|
||||
return false;
|
||||
} else {
|
||||
$name = $r[0];
|
||||
}
|
||||
return file_put_contents($path.$name.".json", json_encode($file_array, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||
return file_put_contents($path . $name . ".json", json_encode($file_array, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从json加载变量到内存
|
||||
* @param $filename
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function loadFromJson($filename) {
|
||||
$path = ZMConfig::get("global", "config_dir");
|
||||
if(file_exists($path.$filename.".json")) {
|
||||
return json_decode(file_get_contents($path.$filename.".json"), true);
|
||||
if (file_exists($path . $filename . ".json")) {
|
||||
return json_decode(file_get_contents($path . $filename . ".json"), true);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归或非递归扫描目录,可返回相对目录的文件列表或绝对目录的文件列表
|
||||
* @param $dir
|
||||
* @param bool $recursive
|
||||
* @param bool|string $relative
|
||||
* @return array|false
|
||||
* @since 2.5
|
||||
*/
|
||||
public static function scanDirFiles($dir, bool $recursive = true, $relative = false) {
|
||||
$dir = rtrim($dir, "/");
|
||||
if (!is_dir($dir)) return false;
|
||||
$r = scandir($dir);
|
||||
if ($r === false) return false;
|
||||
$list = [];
|
||||
if ($relative === true) {
|
||||
$relative = $dir;
|
||||
}
|
||||
foreach ($r as $v) {
|
||||
if ($v == "." || $v == "..") continue;
|
||||
$sub_file = $dir . "/" . $v;
|
||||
if (is_dir($sub_file) && $recursive) {
|
||||
$list = array_merge($list, self::scanDirFiles($sub_file, $recursive, $relative));
|
||||
} elseif (is_file($sub_file)) {
|
||||
if (is_string($relative) && mb_strpos($sub_file, $relative) === 0) {
|
||||
$list [] = ltrim(mb_substr($sub_file, mb_strlen($relative)), "/");
|
||||
} elseif ($relative === false) {
|
||||
$list[] = $sub_file;
|
||||
} else {
|
||||
Console::warning(zm_internal_errcode("E00058") . "Relative path is not generated: wrong base directory ($relative)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查路径是否为相对路径(根据第一个字符是否为"/"来判断)
|
||||
* @param $path
|
||||
* @return bool
|
||||
* @since 2.5
|
||||
*/
|
||||
public static function isRelativePath($path) {
|
||||
return strlen($path) > 0 && $path[0] === '/';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
namespace ZM\Utils;
|
||||
|
||||
|
||||
use Co;
|
||||
use Swoole\Coroutine;
|
||||
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
use Symfony\Component\Routing\Matcher\UrlMatcher;
|
||||
@@ -13,7 +13,7 @@ use Symfony\Component\Routing\RouteCollection;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Http\Response;
|
||||
use ZM\Http\RouteManager;
|
||||
use ZM\Utils\Manager\RouteManager;
|
||||
|
||||
class HttpUtil
|
||||
{
|
||||
@@ -51,7 +51,7 @@ class HttpUtil
|
||||
|
||||
public static function getHttpCodePage(int $http_code) {
|
||||
if (isset(ZMConfig::get("global", "http_default_code_page")[$http_code])) {
|
||||
return Co::readFile(DataProvider::getResourceFolder() . "html/" . ZMConfig::get("global", "http_default_code_page")[$http_code]);
|
||||
return Coroutine::readFile(DataProvider::getResourceFolder() . "html/" . ZMConfig::get("global", "http_default_code_page")[$http_code]);
|
||||
} else return null;
|
||||
}
|
||||
|
||||
|
||||
115
src/ZM/Utils/Manager/ModuleManager.php
Normal file
115
src/ZM/Utils/Manager/ModuleManager.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Utils\Manager;
|
||||
|
||||
|
||||
use ZM\Console\Console;
|
||||
use ZM\Exception\ModulePackException;
|
||||
use ZM\Exception\ZMException;
|
||||
use ZM\Module\ModulePacker;
|
||||
use ZM\Module\ModuleUnpacker;
|
||||
use ZM\Utils\DataProvider;
|
||||
|
||||
/**
|
||||
* 模块管理器,负责打包解包模块
|
||||
* Class ModuleManager
|
||||
* @package ZM\Utils\Manager
|
||||
* @since 2.5
|
||||
*/
|
||||
class ModuleManager
|
||||
{
|
||||
|
||||
/**
|
||||
* 扫描src目录下的所有已经被标注的模块
|
||||
* @return array
|
||||
* @throws ZMException
|
||||
*/
|
||||
public static function getConfiguredModules(): array {
|
||||
$dir = DataProvider::getSourceRootDir() . "/src/";
|
||||
$ls = DataProvider::scanDirFiles($dir, true, true);
|
||||
$modules = [];
|
||||
foreach ($ls as $v) {
|
||||
$pathinfo = pathinfo($v);
|
||||
if ($pathinfo["basename"] == "zm.json") {
|
||||
$json = json_decode(file_get_contents(realpath($dir . "/" . $v)), true);
|
||||
if ($json === null) continue;
|
||||
if (!isset($json["name"])) continue;
|
||||
if ($pathinfo["dirname"] == ".") {
|
||||
throw new ZMException(zm_internal_errcode("E00052") . "在/src/目录下不可以直接标记为模块(zm.json),因为命名空间不能为根空间!");
|
||||
}
|
||||
$json["module-path"] = realpath($dir . "/" . $pathinfo["dirname"]);
|
||||
$json["namespace"] = str_replace("/", "\\", $pathinfo["dirname"]);
|
||||
if (isset($modules[$json["name"]])) {
|
||||
throw new ZMException(zm_internal_errcode("E00053") . "重名模块:" . $json["name"]);
|
||||
}
|
||||
$modules[$json["name"]] = $json;
|
||||
}
|
||||
}
|
||||
return $modules;
|
||||
}
|
||||
|
||||
public static function getPackedModules(): array {
|
||||
$dir = DataProvider::getDataFolder() . "modules";
|
||||
$ls = DataProvider::scanDirFiles($dir, true, false);
|
||||
if ($ls === false) return [];
|
||||
$modules = [];
|
||||
foreach ($ls as $v) {
|
||||
$pathinfo = pathinfo($v);
|
||||
if (($pathinfo["extension"] ?? "") != "phar") continue;
|
||||
$file = "phar://" . $v;
|
||||
if (!is_file($file . "/module_entry.php") || !is_file($file . "/zmplugin.json")) continue;
|
||||
$module_config = json_decode(file_get_contents($file . "/zmplugin.json"), true);
|
||||
if ($module_config === null) continue;
|
||||
if (!is_file($file . "/" . $module_config["module-root-path"] . "/zm.json")) {
|
||||
Console::warning(zm_internal_errcode("E00054") . "模块(插件)文件 " . $pathinfo["basename"] . " 无法找到模块配置文件(zm.json)!");
|
||||
continue;
|
||||
}
|
||||
$module_file = json_decode(file_get_contents($file . "/" . $module_config["module-root-path"] . "/zm.json"), true);
|
||||
if ($module_file === null) {
|
||||
Console::warning(zm_internal_errcode("E000555") . "模块(插件)文件 " . $pathinfo["basename"] . " 无法正常读取模块配置文件(zm.json)!");
|
||||
continue;
|
||||
}
|
||||
$module_config["phar-path"] = $v;
|
||||
$module_config["name"] = $module_file["name"] ?? null;
|
||||
if ($module_config["name"] === null) continue;
|
||||
$module_config["module-config"] = $module_file;
|
||||
$modules[$module_config["name"]] = $module_config;
|
||||
}
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包模块
|
||||
* @param $module
|
||||
* @return bool
|
||||
* @throws ZMException
|
||||
*/
|
||||
public static function packModule($module): bool {
|
||||
try {
|
||||
$packer = new ModulePacker($module);
|
||||
$packer->setOutputPath(DataProvider::getDataFolder() . "output");
|
||||
$packer->setOverride();
|
||||
$packer->pack();
|
||||
return true;
|
||||
} catch (ModulePackException $e) {
|
||||
Console::error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解包模块 TODO
|
||||
* @param $module
|
||||
* @return array|false
|
||||
*/
|
||||
public static function unpackModule($module) {
|
||||
try {
|
||||
$packer = new ModuleUnpacker($module);
|
||||
return $packer->unpack();
|
||||
} catch (ModulePackException $e) {
|
||||
Console::error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php /** @noinspection PhpUnused */
|
||||
|
||||
|
||||
namespace ZM\Utils;
|
||||
namespace ZM\Utils\Manager;
|
||||
|
||||
|
||||
use Co;
|
||||
use Swoole\Coroutine;
|
||||
use ZM\Annotation\CQ\CQCommand;
|
||||
use ZM\Annotation\Swoole\OnPipeMessageEvent;
|
||||
use ZM\Console\Console;
|
||||
@@ -38,7 +38,7 @@ class ProcessManager
|
||||
break;
|
||||
case "resume_ws_message":
|
||||
$obj = $data["data"];
|
||||
Co::resume($obj["coroutine"]);
|
||||
Coroutine::resume($obj["coroutine"]);
|
||||
break;
|
||||
case "getWorkerCache":
|
||||
$r = WorkerCache::get($data["key"]);
|
||||
@@ -99,7 +99,7 @@ class ProcessManager
|
||||
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!");
|
||||
Console::warning(zm_internal_errcode("E00022") . "Cannot send worker action from master or manager process!");
|
||||
return;
|
||||
}
|
||||
if (server()->worker_id == $worker_id) {
|
||||
@@ -114,9 +114,9 @@ class ProcessManager
|
||||
Console::warning("Cannot call '" . __FUNCTION__ . "' in non-worker process!");
|
||||
return;
|
||||
}
|
||||
foreach ((LightCacheInside::get("wait_api", "wait_api") ?? []) as $k => $v) {
|
||||
foreach ((LightCacheInside::get("wait_api", "wait_api") ?? []) as $v) {
|
||||
if (isset($v["coroutine"], $v["worker_id"])) {
|
||||
if (server()->worker_id == $v["worker_id"]) Co::resume($v["coroutine"]);
|
||||
if (server()->worker_id == $v["worker_id"]) Coroutine::resume($v["coroutine"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/ZM/Utils/Manager/RouteManager.php
Normal file
67
src/ZM/Utils/Manager/RouteManager.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Utils\Manager;
|
||||
|
||||
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use ZM\Annotation\Http\Controller;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Http\StaticFileHandler;
|
||||
use ZM\Store\LightCacheInside;
|
||||
|
||||
/**
|
||||
* 路由管理器,2.5版本更改了命名空间
|
||||
* Class RouteManager
|
||||
* @package ZM\Utils\Manager
|
||||
* @since 2.3.0
|
||||
*/
|
||||
class RouteManager
|
||||
{
|
||||
/** @var null|RouteCollection */
|
||||
public static $routes = null;
|
||||
|
||||
public static function importRouteByAnnotation(RequestMapping $vss, $method, $class, $methods_annotations) {
|
||||
if (self::$routes === null) self::$routes = new RouteCollection();
|
||||
|
||||
// 拿到所属方法的类上面有没有控制器的注解
|
||||
$prefix = '';
|
||||
foreach ($methods_annotations as $annotation) {
|
||||
if ($annotation instanceof Controller) {
|
||||
$prefix = $annotation->prefix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$tail = trim($vss->route, "/");
|
||||
$route_name = $prefix . ($tail === "" ? "" : "/") . $tail;
|
||||
Console::debug("添加路由:" . $route_name);
|
||||
$route = new Route($route_name, ['_class' => $class, '_method' => $method]);
|
||||
$route->setMethods($vss->request_method);
|
||||
|
||||
self::$routes->add(md5($route_name), $route);
|
||||
}
|
||||
|
||||
public static function addStaticFileRoute($route, $path) {
|
||||
$tail = trim($route, "/");
|
||||
$route_name = ($tail === "" ? "" : "/") . $tail . "/{filename}";
|
||||
Console::debug("添加静态文件路由:" . $route_name);
|
||||
$route = new Route($route_name, ['_class' => RouteManager::class, '_method' => "onStaticRoute"]);
|
||||
//echo $path.PHP_EOL;
|
||||
LightCacheInside::set("static_route", $route->getPath(), $path);
|
||||
|
||||
self::$routes->add(md5($route_name), $route);
|
||||
}
|
||||
|
||||
public function onStaticRoute($params) {
|
||||
$route_path = self::$routes->get($params["_route"])->getPath();
|
||||
if(($path = LightCacheInside::get("static_route", $route_path)) === null) {
|
||||
ctx()->getResponse()->endWithStatus(404);
|
||||
return false;
|
||||
}
|
||||
unset($params["_route"]);
|
||||
$obj = array_shift($params);
|
||||
return new StaticFileHandler($obj, $path);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php /** @noinspection PhpUnused */
|
||||
|
||||
|
||||
namespace ZM\Utils;
|
||||
namespace ZM\Utils\Manager;
|
||||
|
||||
|
||||
use ZM\Console\Console;
|
||||
@@ -9,15 +9,14 @@ use ZM\Console\Console;
|
||||
class TaskManager
|
||||
{
|
||||
/**
|
||||
* @noinspection PhpMissingReturnTypeInspection
|
||||
* @param $task_name
|
||||
* @param int $timeout
|
||||
* @param mixed ...$params
|
||||
* @return false|mixed
|
||||
*/
|
||||
public static function runTask($task_name, $timeout = -1, ...$params) {
|
||||
public static function runTask($task_name, int $timeout = -1, ...$params) {
|
||||
if (!isset(server()->setting["task_worker_num"])) {
|
||||
Console::warning("未开启 TaskWorker 进程,请先修改 global 配置文件启用!");
|
||||
Console::warning(zm_internal_errcode("E00056") . "未开启 TaskWorker 进程,请先修改 global 配置文件启用!");
|
||||
return false;
|
||||
}
|
||||
$r = server()->taskwait(["task" => $task_name, "params" => $params], $timeout);
|
||||
@@ -11,6 +11,7 @@ use ZM\Console\Console;
|
||||
use ZM\Entity\MatchResult;
|
||||
use ZM\Event\EventManager;
|
||||
use ZM\Requests\ZMRequest;
|
||||
use ZM\Utils\Manager\ProcessManager;
|
||||
|
||||
class MessageUtil
|
||||
{
|
||||
@@ -25,7 +26,7 @@ class MessageUtil
|
||||
if (!is_dir($path)) mkdir($path);
|
||||
$path = realpath($path);
|
||||
if ($path === false) {
|
||||
Console::warning("指定的路径错误不存在!");
|
||||
Console::warning(zm_internal_errcode("E00059") . "指定的路径错误不存在!");
|
||||
return false;
|
||||
}
|
||||
$files = [];
|
||||
@@ -34,7 +35,7 @@ class MessageUtil
|
||||
if ($v->type == "image") {
|
||||
$result = ZMRequest::downloadFile($v->params["url"], $path . "/" . $v->params["file"]);
|
||||
if ($result === false) {
|
||||
Console::warning("图片 " . $v->params["url"] . " 下载失败!");
|
||||
Console::warning(zm_internal_errcode("E00060") . "图片 " . $v->params["url"] . " 下载失败!");
|
||||
return false;
|
||||
}
|
||||
$files[] = $path . "/" . $v->params["file"];
|
||||
@@ -112,7 +113,7 @@ class MessageUtil
|
||||
$ls = EventManager::$events[CQCommand::class] ?? [];
|
||||
$word = self::splitCommand($msg);
|
||||
$matched = new MatchResult();
|
||||
foreach ($ls as $k => $v) {
|
||||
foreach ($ls as $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))) &&
|
||||
|
||||
75
src/ZM/Utils/SignalListener.php
Normal file
75
src/ZM/Utils/SignalListener.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Utils;
|
||||
|
||||
|
||||
use Swoole\Event;
|
||||
use Swoole\Process;
|
||||
use Swoole\Server;
|
||||
use Swoole\Timer;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Framework;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Utils\Manager\ProcessManager;
|
||||
|
||||
/**
|
||||
* 炸毛框架的Linux signal管理类
|
||||
* Class SignalListener
|
||||
* @package ZM\Utils
|
||||
* @since 2.5
|
||||
*/
|
||||
class SignalListener
|
||||
{
|
||||
/**
|
||||
* 监听Master进程的Ctrl+C
|
||||
* @param Server $server
|
||||
*/
|
||||
public static function signalMaster(Server $server) {
|
||||
Process::signal(SIGINT, function () use ($server) {
|
||||
if (zm_atomic("_int_is_reload")->get() === 1) {
|
||||
zm_atomic("_int_is_reload")->set(0);
|
||||
$server->reload();
|
||||
} else {
|
||||
echo "\r";
|
||||
Console::warning("Server interrupted(SIGINT) on Master.");
|
||||
if ((Framework::$server->inotify ?? null) !== null)
|
||||
/** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify);
|
||||
if (ZMBuf::$terminal !== null)
|
||||
Event::del(ZMBuf::$terminal);
|
||||
Process::kill($server->master_pid, SIGTERM);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听Manager进程的Ctrl+C
|
||||
*/
|
||||
public static function signalManager() {
|
||||
$func = function () {
|
||||
Console::verbose("Interrupted in manager!");
|
||||
};
|
||||
if (version_compare(SWOOLE_VERSION, "4.6.7") >= 0) {
|
||||
Process::signal(SIGINT, $func);
|
||||
} elseif (extension_loaded("pcntl")) {
|
||||
pcntl_signal(SIGINT, $func);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听Worker/TaskWorker进程的Ctrl+C
|
||||
* @param Server $server
|
||||
* @param $worker_id
|
||||
*/
|
||||
public static function signalWorker(Server $server, $worker_id) {
|
||||
Process::signal(SIGINT, function () use ($worker_id, $server) {
|
||||
// do nothing
|
||||
});
|
||||
if ($server->taskworker === false) {
|
||||
Process::signal(SIGUSR1, function () use ($worker_id) {
|
||||
Timer::clearAll();
|
||||
ProcessManager::resumeAllWorkerCoroutines();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,13 +33,13 @@ class Terminal
|
||||
$dispatcher = new EventDispatcher(TerminalCommand::class);
|
||||
$dispatcher->setRuleFunction(function ($v) use ($it) {
|
||||
/** @var TerminalCommand $v */
|
||||
return $v->command == $it[0] || $v->alias == $it[0];
|
||||
return !empty($it) && ($v->command == $it[0] || $v->alias == $it[0]);
|
||||
});
|
||||
$dispatcher->setReturnFunction(function () {
|
||||
EventDispatcher::interrupt('none');
|
||||
});
|
||||
$dispatcher->dispatchEvents($it);
|
||||
if ($dispatcher->store !== 'none') {
|
||||
if ($dispatcher->store !== 'none' && $cmd !== "") {
|
||||
Console::info("Command not found: " . $cmd);
|
||||
return true;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ class Terminal
|
||||
Console::$type($log_msg);
|
||||
$r = ob_get_clean();
|
||||
$all = ManagerGM::getAllByName("terminal");
|
||||
foreach ($all as $k => $v) {
|
||||
foreach ($all as $v) {
|
||||
server()->send($v->getFd(), "\r" . $r);
|
||||
server()->send($v->getFd(), ">>> ");
|
||||
}
|
||||
@@ -72,7 +72,7 @@ class Terminal
|
||||
$class = new Terminal();
|
||||
$reader = new AnnotationReader();
|
||||
$reflection = new ReflectionClass($class);
|
||||
foreach ($reflection->getMethods() as $k => $v) {
|
||||
foreach ($reflection->getMethods() as $v) {
|
||||
$r = $reader->getMethodAnnotation($v, TerminalCommand::class);
|
||||
if ($r !== null) {
|
||||
Console::debug("adding command " . $r->command);
|
||||
@@ -176,7 +176,7 @@ class Terminal
|
||||
* @TerminalCommand(command="stop",description="停止框架")
|
||||
*/
|
||||
public function stop() {
|
||||
Process::kill(server()->master_pid, SIGTERM);
|
||||
posix_kill(server()->master_pid, SIGTERM);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,13 +18,13 @@ class ZMUtil
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function stop() {
|
||||
if (SpinLock::tryLock("_stop_signal") === false) return;
|
||||
Console::warning(Console::setColor("Stopping server...", "red"));
|
||||
if (SpinLock::tryLock('_stop_signal') === false) return;
|
||||
Console::warning(Console::setColor('Stopping server...', 'red'));
|
||||
if (Console::getLevel() >= 4) Console::trace();
|
||||
ZMAtomic::get("stop_signal")->set(1);
|
||||
ZMAtomic::get('stop_signal')->set(1);
|
||||
for ($i = 0; $i < ZM_WORKER_NUM; ++$i) {
|
||||
if (Process::kill(zm_atomic("_#worker_" . $i)->get(), 0))
|
||||
Process::kill(zm_atomic("_#worker_" . $i)->get(), SIGUSR1);
|
||||
if (Process::kill(zm_atomic('_#worker_' . $i)->get(), 0))
|
||||
Process::kill(zm_atomic('_#worker_' . $i)->get(), SIGUSR1);
|
||||
}
|
||||
server()->shutdown();
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class ZMUtil
|
||||
|
||||
public static function getModInstance($class) {
|
||||
if (!isset(ZMBuf::$instance[$class])) {
|
||||
//Console::debug("Class instance $class not exist, so I created it.");
|
||||
//Console::debug('Class instance $class not exist, so I created it.');
|
||||
return ZMBuf::$instance[$class] = new $class();
|
||||
} else {
|
||||
return ZMBuf::$instance[$class];
|
||||
@@ -52,11 +52,44 @@ class ZMUtil
|
||||
public static function getReloadableFiles() {
|
||||
return array_map(
|
||||
function ($x) {
|
||||
return str_replace(DataProvider::getWorkingDir() . "/", "", $x);
|
||||
return str_replace(DataProvider::getSourceRootDir() . '/', '', $x);
|
||||
}, array_diff(
|
||||
get_included_files(),
|
||||
Framework::$loaded_files
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Psr-4标准获取目录下的所有类
|
||||
* @param $dir
|
||||
* @param $base_namespace
|
||||
* @param null|mixed $rule
|
||||
* @param bool $return_kv
|
||||
* @return String[]
|
||||
*/
|
||||
public static function getClassesPsr4($dir, $base_namespace, $rule = null, $return_kv = false) {
|
||||
// 预先读取下composer的file列表
|
||||
$composer = json_decode(file_get_contents(DataProvider::getSourceRootDir() . '/composer.json'), true);
|
||||
$classes = [];
|
||||
// 扫描目录,使用递归模式,相对路径模式,因为下面此路径要用作转换成namespace
|
||||
$files = DataProvider::scanDirFiles($dir, true, true);
|
||||
foreach ($files as $v) {
|
||||
$pathinfo = pathinfo($v);
|
||||
if ($pathinfo['extension'] == 'php') {
|
||||
if ($rule === null) { //规则未设置回调时候,使用默认的识别过滤规则
|
||||
if (substr(file_get_contents($dir . '/' . $v), 6, 6) == '#plain') continue;
|
||||
elseif (mb_substr($v, 0, 7) == 'global_' || mb_substr($v, 0, 7) == 'script_') continue;
|
||||
foreach (($composer['autoload']['files'] ?? []) as $fi) {
|
||||
if (md5_file(DataProvider::getSourceRootDir().'/'.$fi) == md5_file($dir.'/'.$v)) continue 2;
|
||||
}
|
||||
} elseif (is_callable($rule) && !($rule($dir, $pathinfo))) continue;
|
||||
$dirname = $pathinfo['dirname'] == '.' ? '' : (str_replace('/', '\\', $pathinfo['dirname']) . '\\');
|
||||
$class_name = $base_namespace . '\\' . $dirname . $pathinfo['filename'];
|
||||
if ($return_kv) $classes[$class_name] = $v;
|
||||
else $classes[] = $class_name;
|
||||
}
|
||||
}
|
||||
return $classes;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user