mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-24 00:55:35 +08:00
update to version 1.4
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[]()
|
[]()
|
||||||
[](https://github.com/zhamao-robot/zhamao-framework/blob/master/LICENSE)
|
[](https://github.com/zhamao-robot/zhamao-framework/blob/master/LICENSE)
|
||||||
[]()
|
[]()
|
||||||
|
|
||||||
[](https://github.com/zhamao-robot/zhamao-framework/search?q=stupid)
|
[](https://github.com/zhamao-robot/zhamao-framework/search?q=stupid)
|
||||||
[](https://github.com/zhamao-robot/zhamao-framework/search?q=TODO)
|
[](https://github.com/zhamao-robot/zhamao-framework/search?q=TODO)
|
||||||
@@ -31,6 +31,7 @@ Pages托管:[https://framework.zhamao.xin/](https://framework.zhamao.xin/)
|
|||||||
## 特点
|
## 特点
|
||||||
- 支持多账号
|
- 支持多账号
|
||||||
- 灵活的注解事件绑定机制
|
- 灵活的注解事件绑定机制
|
||||||
|
- 支持下断点调试(Psysh)
|
||||||
- 易用的上下文,模块内随处可用
|
- 易用的上下文,模块内随处可用
|
||||||
- 采用模块化编写,功能之间高内聚低耦合
|
- 采用模块化编写,功能之间高内聚低耦合
|
||||||
- 常驻内存,全局缓存变量随处使用
|
- 常驻内存,全局缓存变量随处使用
|
||||||
@@ -47,11 +48,10 @@ Pages托管:[https://framework.zhamao.xin/](https://framework.zhamao.xin/)
|
|||||||
| 通用模块 | 图片上传和下载模块 | [zhamao-general-tools](https://github.com/zhamao-robot/zhamao-general-tools) |
|
| 通用模块 | 图片上传和下载模块 | [zhamao-general-tools](https://github.com/zhamao-robot/zhamao-general-tools) |
|
||||||
|
|
||||||
## 计划开发内容
|
## 计划开发内容
|
||||||
- [ ] WebSocket测试脚本(客户端)
|
- [X] WebSocket测试脚本(客户端)
|
||||||
- [X] Session 和中间层管理模块
|
- [X] Session 和中间层管理模块
|
||||||
- [ ] 支持本地和远程两种方式的定时器(计划任务)
|
|
||||||
- [X] 常驻服务脚本
|
- [X] 常驻服务脚本
|
||||||
- [ ] 一些常用的通用 API 例如经济(用户积分、亲密度等)的模块
|
- [X] 一些常用的通用 API 例如经济(用户积分、亲密度等)的模块
|
||||||
- [ ] 图灵机器人/腾讯AI 聊天模块
|
- [ ] 图灵机器人/腾讯AI 聊天模块
|
||||||
- [ ] 分词模块(可能会放弃计划,因为目前好用的分词都是其他语言的)
|
- [ ] 分词模块(可能会放弃计划,因为目前好用的分词都是其他语言的)
|
||||||
- [ ] HTTP 过滤器、Auth 模块、完整的 MVC 兼容(可能会放弃计划,因为框架主打机器人开发)
|
- [ ] HTTP 过滤器、Auth 模块、完整的 MVC 兼容(可能会放弃计划,因为框架主打机器人开发)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "high-performance intelligent assistant",
|
"description": "high-performance intelligent assistant",
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"version": "1.3.2",
|
"version": "1.4.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "whale",
|
"name": "whale",
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
|
"php": ">=7.2",
|
||||||
"swoole/ide-helper": "@dev",
|
"swoole/ide-helper": "@dev",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"swlib/saber": "^1.0",
|
"swlib/saber": "^1.0",
|
||||||
@@ -22,7 +23,8 @@
|
|||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-posix": "*",
|
"ext-posix": "*",
|
||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
"ext-pdo": "*"
|
"ext-pdo": "*",
|
||||||
|
"psy/psysh": "@stable"
|
||||||
},
|
},
|
||||||
"repositories": {
|
"repositories": {
|
||||||
"packagist": {
|
"packagist": {
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ $config['port'] = 20001;
|
|||||||
/** 框架开到公网或外部的HTTP访问链接,通过 DataProvider::getFrameworkLink() 获取 */
|
/** 框架开到公网或外部的HTTP访问链接,通过 DataProvider::getFrameworkLink() 获取 */
|
||||||
$config['http_reverse_link'] = "http://127.0.0.1:".$config['port'];
|
$config['http_reverse_link'] = "http://127.0.0.1:".$config['port'];
|
||||||
|
|
||||||
|
/** 框架是否启动debug模式 */
|
||||||
|
$config['debug_mode'] = false;
|
||||||
|
|
||||||
/** 存放框架内文件数据的目录 */
|
/** 存放框架内文件数据的目录 */
|
||||||
$config['zm_data'] = WORKING_DIR.'/zm_data/';
|
$config['zm_data'] = WORKING_DIR.'/zm_data/';
|
||||||
|
|
||||||
|
|||||||
6
config/motd.txt
Normal file
6
config/motd.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
______
|
||||||
|
|__ / |__ __ _ _ __ ___ __ _ ___
|
||||||
|
/ /| '_ \ / _` | '_ ` _ \ / _` |/ _ \
|
||||||
|
/ /_| | | | (_| | | | | | | (_| | (_) |
|
||||||
|
/____|_| |_|\__,_|_| |_| |_|\__,_|\___/
|
||||||
|
|
||||||
@@ -41,6 +41,7 @@ function loadPhp($dir) {
|
|||||||
loadPhp($path);
|
loadPhp($path);
|
||||||
} else {
|
} else {
|
||||||
if (pathinfo($dir . '/' . $v)['extension'] == 'php') {
|
if (pathinfo($dir . '/' . $v)['extension'] == 'php') {
|
||||||
|
if(pathinfo($dir . '/' . $v)['basename'] == 'terminal_listener.php') continue;
|
||||||
//echo 'loading '.$path.PHP_EOL;
|
//echo 'loading '.$path.PHP_EOL;
|
||||||
require_once $path;
|
require_once $path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,19 @@
|
|||||||
|
|
||||||
namespace Framework;
|
namespace Framework;
|
||||||
|
|
||||||
use co;
|
use ZM\Annotation\Swoole\SwooleEventAt;
|
||||||
|
use ZM\Connection\WSConnection;
|
||||||
use ZM\Utils\ZMUtil;
|
use ZM\Utils\ZMUtil;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class Console
|
class Console
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var false|resource
|
||||||
|
*/
|
||||||
|
public static $console_proc = null;
|
||||||
|
public static $pipes = [];
|
||||||
|
|
||||||
static function setColor($string, $color = "") {
|
static function setColor($string, $color = "") {
|
||||||
switch ($color) {
|
switch ($color) {
|
||||||
case "red":
|
case "red":
|
||||||
@@ -119,8 +126,8 @@ class Console
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static function debug($obj) {
|
static function debug($msg) {
|
||||||
debug($obj);
|
if (ZMBuf::$atomics["info_level"]->get() >= 4) Console::log(date("[H:i:s] ") . "[D] " . $msg, 'gray');
|
||||||
}
|
}
|
||||||
|
|
||||||
static function log($obj, $color = "") {
|
static function log($obj, $color = "") {
|
||||||
@@ -157,11 +164,51 @@ class Console
|
|||||||
self::info("ConsoleCommand disabled.");
|
self::info("ConsoleCommand disabled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
go(function () {
|
global $terminal_id;
|
||||||
while (true) {
|
global $port;
|
||||||
$cmd = trim(co::fread(STDIN));
|
$port = ZMBuf::globals("port");
|
||||||
if (self::executeCommand($cmd) === false) break;
|
$vss = new SwooleEventAt();
|
||||||
|
$vss->type = "open";
|
||||||
|
$vss->level = 256;
|
||||||
|
$vss->rule = "connectType:terminal";
|
||||||
|
$terminal_id = call_user_func(function () {
|
||||||
|
try {
|
||||||
|
$data = random_bytes(16);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
|
||||||
|
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
|
||||||
|
return strtoupper(vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)));
|
||||||
|
});
|
||||||
|
$vss->callback = function(?WSConnection $conn) use ($terminal_id){
|
||||||
|
$req = ctx()->getRequest();
|
||||||
|
if($conn->getType() != "terminal") return false;
|
||||||
|
if(($req->header["x-terminal-id"] ?? "") != $terminal_id || ($req->header["x-pid"] ?? "") != posix_getpid()) {
|
||||||
|
$conn->close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
ZMBuf::$events[SwooleEventAt::class][] = $vss;
|
||||||
|
$vss2 = new SwooleEventAt();
|
||||||
|
$vss2->type = "message";
|
||||||
|
$vss2->rule = "connectType:terminal";
|
||||||
|
$vss2->callback = function(?WSConnection $conn){
|
||||||
|
if($conn->getType() != "terminal") return false;
|
||||||
|
$cmd = ctx()->getFrame()->data;
|
||||||
|
self::executeCommand($cmd);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
ZMBuf::$events[SwooleEventAt::class][] = $vss2;
|
||||||
|
go(function () {
|
||||||
|
global $terminal_id, $port;
|
||||||
|
$descriptorspec = array(
|
||||||
|
0 => STDIN,
|
||||||
|
1 => STDOUT,
|
||||||
|
2 => STDERR
|
||||||
|
);
|
||||||
|
self::$console_proc = proc_open('php -r \'$terminal_id = "'.$terminal_id.'";$port = '.$port.';require "'.__DIR__.'/terminal_listener.php";\'', $descriptorspec, $pipes);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,14 +256,14 @@ class Console
|
|||||||
return false;
|
return false;
|
||||||
case 'save':
|
case 'save':
|
||||||
$origin = ZMBuf::$atomics["info_level"]->get();
|
$origin = ZMBuf::$atomics["info_level"]->get();
|
||||||
ZMBuf::$atomics["info_level"]->set(3);
|
//ZMBuf::$atomics["info_level"]->set(3);
|
||||||
DataProvider::saveBuffer();
|
DataProvider::saveBuffer();
|
||||||
ZMBuf::$atomics["info_level"]->set($origin);
|
//ZMBuf::$atomics["info_level"]->set($origin);
|
||||||
return true;
|
return true;
|
||||||
case '':
|
case '':
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
Console::info("Command not found: " . $it[0]);
|
Console::info("Command not found: " . $cmd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
namespace Framework;
|
namespace Framework;
|
||||||
|
|
||||||
|
|
||||||
|
use ZM\Annotation\Swoole\OnSave;
|
||||||
|
|
||||||
class DataProvider
|
class DataProvider
|
||||||
{
|
{
|
||||||
public static $buffer_list = [];
|
public static $buffer_list = [];
|
||||||
@@ -40,6 +42,13 @@ class DataProvider
|
|||||||
Console::debug("Saving " . $k . " to " . $v);
|
Console::debug("Saving " . $k . " to " . $v);
|
||||||
self::setJsonData($v, ZMBuf::get($k));
|
self::setJsonData($v, ZMBuf::get($k));
|
||||||
}
|
}
|
||||||
|
foreach (ZMBuf::$events[OnSave::class] ?? [] as $v) {
|
||||||
|
$c = $v->class;
|
||||||
|
$method = $v->method;
|
||||||
|
$class = new $c();
|
||||||
|
Console::debug("Calling @OnSave: $c -> $method");
|
||||||
|
$class->$method();
|
||||||
|
}
|
||||||
if (ZMBuf::$atomics["info_level"]->get() >= 3)
|
if (ZMBuf::$atomics["info_level"]->get() >= 3)
|
||||||
echo Console::setColor("saved", "blue") . PHP_EOL;
|
echo Console::setColor("saved", "blue") . PHP_EOL;
|
||||||
}
|
}
|
||||||
@@ -53,7 +62,7 @@ class DataProvider
|
|||||||
return json_decode(file_get_contents(self::getDataConfig() . $string), true);
|
return json_decode(file_get_contents(self::getDataConfig() . $string), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function setJsonData($filename, array $args) {
|
public static function setJsonData($filename, array $args) {
|
||||||
$pathinfo = pathinfo($filename);
|
$pathinfo = pathinfo($filename);
|
||||||
if (!is_dir(self::getDataConfig() . $pathinfo["dirname"])) {
|
if (!is_dir(self::getDataConfig() . $pathinfo["dirname"])) {
|
||||||
Console::debug("Making Directory: " . self::getDataConfig() . $pathinfo["dirname"]);
|
Console::debug("Making Directory: " . self::getDataConfig() . $pathinfo["dirname"]);
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ class FrameworkLoader
|
|||||||
public function __construct($args = []) {
|
public function __construct($args = []) {
|
||||||
if (self::$instance !== null) die("Cannot run two FrameworkLoader in one process!");
|
if (self::$instance !== null) die("Cannot run two FrameworkLoader in one process!");
|
||||||
self::$instance = $this;
|
self::$instance = $this;
|
||||||
self::$argv = $args;
|
|
||||||
|
|
||||||
$this->requireGlobalFunctions();
|
$this->requireGlobalFunctions();
|
||||||
if (!isPharMode()) {
|
if (!isPharMode()) {
|
||||||
define('WORKING_DIR', getcwd());
|
define('WORKING_DIR', getcwd());
|
||||||
@@ -47,7 +48,15 @@ class FrameworkLoader
|
|||||||
echo "Phar mode: " . WORKING_DIR . PHP_EOL;
|
echo "Phar mode: " . WORKING_DIR . PHP_EOL;
|
||||||
}
|
}
|
||||||
$this->registerAutoloader('classLoader');
|
$this->registerAutoloader('classLoader');
|
||||||
|
self::$settings = new GlobalConfig();
|
||||||
|
if (self::$settings->get("debug_mode") === true) {
|
||||||
|
$args[] = "--debug-mode";
|
||||||
|
$args[] = "--disable-console-input";
|
||||||
|
}
|
||||||
|
self::$argv = $args;
|
||||||
|
if (!in_array("--debug-mode", self::$argv)) {
|
||||||
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
|
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
|
||||||
|
}
|
||||||
self::$settings = new GlobalConfig();
|
self::$settings = new GlobalConfig();
|
||||||
ZMBuf::$globals = self::$settings;
|
ZMBuf::$globals = self::$settings;
|
||||||
if (!self::$settings->success) die("Failed to load global config. Please check config/global.php file");
|
if (!self::$settings->success) die("Failed to load global config. Please check config/global.php file");
|
||||||
@@ -97,7 +106,13 @@ class FrameworkLoader
|
|||||||
"\nworking_dir: " . (isPharMode() ? realpath('.') : WORKING_DIR)
|
"\nworking_dir: " . (isPharMode() ? realpath('.') : WORKING_DIR)
|
||||||
);
|
);
|
||||||
global $motd;
|
global $motd;
|
||||||
echo $motd . PHP_EOL;
|
if (!file_exists(DataProvider::getWorkingDir() . "/config/motd.txt")) {
|
||||||
|
echo $motd;
|
||||||
|
} else {
|
||||||
|
echo file_get_contents(DataProvider::getWorkingDir() . "/config/motd.txt");
|
||||||
|
}
|
||||||
|
if (in_array("--debug-mode", self::$argv))
|
||||||
|
Console::warning("You are in debug mode, do not use in production!");
|
||||||
$this->server->start();
|
$this->server->start();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Console::error("Framework初始化出现错误,请检查!");
|
Console::error("Framework初始化出现错误,请检查!");
|
||||||
@@ -126,12 +141,15 @@ class FrameworkLoader
|
|||||||
define("ZM_MATCH_FIRST", 1);
|
define("ZM_MATCH_FIRST", 1);
|
||||||
define("ZM_MATCH_NUMBER", 2);
|
define("ZM_MATCH_NUMBER", 2);
|
||||||
define("ZM_MATCH_SECOND", 3);
|
define("ZM_MATCH_SECOND", 3);
|
||||||
|
define("ZM_BREAKPOINT", 'if(in_array("--debug-mode", \Framework\FrameworkLoader::$argv)) extract(\Psy\debug(get_defined_vars(), isset($this) ? $this : @get_called_class()));');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function selfCheck() {
|
private function selfCheck() {
|
||||||
if (!extension_loaded("swoole")) die("Can not find swoole extension.\n");
|
if (!extension_loaded("swoole")) die("Can not find swoole extension.\n");
|
||||||
|
if (version_compare(SWOOLE_VERSION, "4.4.13") == -1) die("You must install swoole version >= 4.4.13 !");
|
||||||
//if (!extension_loaded("gd")) die("Can not find gd extension.\n");
|
//if (!extension_loaded("gd")) die("Can not find gd extension.\n");
|
||||||
if (!extension_loaded("sockets")) die("Can not find sockets extension.\n");
|
if (!extension_loaded("sockets")) die("Can not find sockets extension.\n");
|
||||||
|
if (!extension_loaded("ctype")) die("Can not find ctype extension.\n");
|
||||||
if (!function_exists("mb_substr")) die("Can not find mbstring extension.\n");
|
if (!function_exists("mb_substr")) die("Can not find mbstring extension.\n");
|
||||||
if (substr(PHP_VERSION, 0, 1) != "7") die("PHP >=7 required.\n");
|
if (substr(PHP_VERSION, 0, 1) != "7") die("PHP >=7 required.\n");
|
||||||
//if (!function_exists("curl_exec")) die("Can not find curl extension.\n");
|
//if (!function_exists("curl_exec")) die("Can not find curl extension.\n");
|
||||||
@@ -160,5 +178,6 @@ $motd = <<<EOL
|
|||||||
/ /_| | | | (_| | | | | | | (_| | (_) |
|
/ /_| | | | (_| | | | | | | (_| | (_) |
|
||||||
/____|_| |_|\__,_|_| |_| |_|\__,_|\___/
|
/____|_| |_|\__,_|_| |_| |_|\__,_|\___/
|
||||||
|
|
||||||
|
|
||||||
EOL;
|
EOL;
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
namespace Framework;
|
namespace Framework;
|
||||||
|
|
||||||
use Swoole\Atomic;
|
use Swoole\Atomic;
|
||||||
|
use Swoole\Database\PDOPool;
|
||||||
use swoole_atomic;
|
use swoole_atomic;
|
||||||
use ZM\connection\WSConnection;
|
use ZM\connection\WSConnection;
|
||||||
use ZM\Utils\SQLPool;
|
|
||||||
|
|
||||||
class ZMBuf
|
class ZMBuf
|
||||||
{
|
{
|
||||||
@@ -24,7 +24,7 @@ class ZMBuf
|
|||||||
static $scheduler = null; //This is stupid warning...
|
static $scheduler = null; //This is stupid warning...
|
||||||
|
|
||||||
//Swoole SQL连接池,多进程下每个进程一个连接池
|
//Swoole SQL连接池,多进程下每个进程一个连接池
|
||||||
/** @var SQLPool */
|
/** @var PDOPool */
|
||||||
static $sql_pool = null;//保存sql连接池的类
|
static $sql_pool = null;//保存sql连接池的类
|
||||||
|
|
||||||
//只读的数据,可以在多worker_num下使用
|
//只读的数据,可以在多worker_num下使用
|
||||||
@@ -51,6 +51,7 @@ class ZMBuf
|
|||||||
public static $config = [];
|
public static $config = [];
|
||||||
public static $context = [];
|
public static $context = [];
|
||||||
public static $instance = [];
|
public static $instance = [];
|
||||||
|
public static $context_class = [];
|
||||||
|
|
||||||
static function get($name, $default = null) {
|
static function get($name, $default = null) {
|
||||||
return self::$cache[$name] ?? $default;
|
return self::$cache[$name] ?? $default;
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
use Framework\Console;
|
use Framework\Console;
|
||||||
use Framework\DataProvider;
|
use Framework\DataProvider;
|
||||||
use Framework\ZMBuf;
|
use Framework\ZMBuf;
|
||||||
|
use Swoole\Coroutine\System;
|
||||||
use ZM\Context\ContextInterface;
|
use ZM\Context\ContextInterface;
|
||||||
|
use ZM\Utils\ZMUtil;
|
||||||
|
|
||||||
function isPharMode() {
|
function isPharMode() {
|
||||||
return substr(__DIR__, 0, 7) == 'phar://';
|
return substr(__DIR__, 0, 7) == 'phar://';
|
||||||
@@ -165,7 +167,7 @@ function set_coroutine_params($array) {
|
|||||||
if (isset(ZMBuf::$context[$cid])) ZMBuf::$context[$cid] = array_merge(ZMBuf::$context[$cid], $array);
|
if (isset(ZMBuf::$context[$cid])) ZMBuf::$context[$cid] = array_merge(ZMBuf::$context[$cid], $array);
|
||||||
else ZMBuf::$context[$cid] = $array;
|
else ZMBuf::$context[$cid] = $array;
|
||||||
foreach (ZMBuf::$context as $c => $v) {
|
foreach (ZMBuf::$context as $c => $v) {
|
||||||
if (!Co::exists($c)) unset(ZMBuf::$context[$c]);
|
if (!Co::exists($c)) unset(ZMBuf::$context[$c], ZMBuf::$context_class[$c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,23 +175,52 @@ function set_coroutine_params($array) {
|
|||||||
* @return ContextInterface|null
|
* @return ContextInterface|null
|
||||||
*/
|
*/
|
||||||
function context() {
|
function context() {
|
||||||
|
return ctx();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ContextInterface|null
|
||||||
|
*/
|
||||||
|
function ctx() {
|
||||||
$cid = Co::getCid();
|
$cid = Co::getCid();
|
||||||
$c_class = ZMBuf::globals("context_class");
|
$c_class = ZMBuf::globals("context_class");
|
||||||
if (isset(ZMBuf::$context[$cid])) {
|
if (isset(ZMBuf::$context[$cid])) {
|
||||||
return new $c_class($cid);
|
return ZMBuf::$context_class[$cid] ?? (ZMBuf::$context_class[$cid] = new $c_class($cid));
|
||||||
} else {
|
} else {
|
||||||
Console::debug("未找到当前协程的上下文($cid),正在找父进程的上下文");
|
Console::debug("未找到当前协程的上下文($cid),正在找父进程的上下文");
|
||||||
while (($pcid = Co::getPcid($cid)) !== -1) {
|
while (($pcid = Co::getPcid($cid)) !== -1) {
|
||||||
$cid = $pcid;
|
$cid = $pcid;
|
||||||
if (isset(ZMBuf::$context[$cid])) return new $c_class($cid);
|
if (isset(ZMBuf::$context[$cid])) return ZMBuf::$context_class[$cid] ?? (ZMBuf::$context_class[$cid] = new $c_class($cid));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ctx() { return context(); }
|
function debug($msg) { Console::debug($msg); }
|
||||||
|
|
||||||
function debug($msg) {
|
function zm_sleep($s = 1) { Co::sleep($s); }
|
||||||
if (ZMBuf::$atomics["info_level"]->get() >= 4)
|
|
||||||
Console::log(date("[H:i:s] ") . "[D] " . $msg, 'gray');
|
function zm_exec($cmd): array { return System::exec($cmd); }
|
||||||
|
|
||||||
|
function zm_cid() { return Co::getCid(); }
|
||||||
|
|
||||||
|
function zm_yield() { Co::yield(); }
|
||||||
|
|
||||||
|
function zm_resume(int $cid) { Co::resume($cid); }
|
||||||
|
|
||||||
|
function zm_timer_after($ms, callable $callable) {
|
||||||
|
go(function () use ($ms, $callable) {
|
||||||
|
ZMUtil::checkWait();
|
||||||
|
Swoole\Timer::after($ms, $callable);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zm_timer_tick($ms, callable $callable) {
|
||||||
|
go(function () use ($ms, $callable) {
|
||||||
|
ZMUtil::checkWait();
|
||||||
|
Console::debug("Adding extra timer tick of " . $ms . " ms");
|
||||||
|
Swoole\Timer::tick($ms, $callable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
31
src/Framework/terminal_listener.php
Normal file
31
src/Framework/terminal_listener.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Swoole\Coroutine\Http\Client;
|
||||||
|
|
||||||
|
Co\run(function (){
|
||||||
|
global $terminal_id, $port;
|
||||||
|
$client = new Client("127.0.0.1", $port);
|
||||||
|
$client->set(['websocket_mask' => true]);
|
||||||
|
$client->setHeaders(["x-terminal-id" => $terminal_id, 'x-pid' => posix_getppid()]);
|
||||||
|
$ret = $client->upgrade("/?type=terminal");
|
||||||
|
if ($ret) {
|
||||||
|
while (true) {
|
||||||
|
$line = fgets(STDIN);
|
||||||
|
if ($line !== false) {
|
||||||
|
$r = $client->push(trim($line));
|
||||||
|
if (trim($line) == "reload" || trim($line) == "r" || trim($line) == "stop") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if($r === false) {
|
||||||
|
echo "Unable to connect framework terminal, connection closed.\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo "Unable to connect framework terminal. port: $port\n";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ class CQAPI
|
|||||||
* @param CQConnection $connection
|
* @param CQConnection $connection
|
||||||
* @param $reply
|
* @param $reply
|
||||||
* @param |null $function
|
* @param |null $function
|
||||||
* @return bool
|
* @return bool|array
|
||||||
*/
|
*/
|
||||||
public static function processAPI($connection, $reply, $function = null) {
|
public static function processAPI($connection, $reply, $function = null) {
|
||||||
$api_id = ZMBuf::$atomics["wait_msg_id"]->get();
|
$api_id = ZMBuf::$atomics["wait_msg_id"]->get();
|
||||||
@@ -243,7 +243,7 @@ class CQAPI
|
|||||||
Console::warning("CQAPI send failed, websocket push error.");
|
Console::warning("CQAPI send failed, websocket push error.");
|
||||||
$response = [
|
$response = [
|
||||||
"status" => "failed",
|
"status" => "failed",
|
||||||
"retcode" => 999,
|
"retcode" => -1000,
|
||||||
"data" => null,
|
"data" => null,
|
||||||
"self_id" => $connection->getQQ()
|
"self_id" => $connection->getQQ()
|
||||||
];
|
];
|
||||||
@@ -251,7 +251,7 @@ class CQAPI
|
|||||||
if (($s["func"] ?? null) !== null)
|
if (($s["func"] ?? null) !== null)
|
||||||
call_user_func($s["func"], $response, $reply);
|
call_user_func($s["func"], $response, $reply);
|
||||||
ZMBuf::unsetByValue("sent_api", $reply["echo"]);
|
ZMBuf::unsetByValue("sent_api", $reply["echo"]);
|
||||||
if ($function === true) return null;
|
if ($function === true) return $response;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,10 @@
|
|||||||
namespace ZM\Annotation;
|
namespace ZM\Annotation;
|
||||||
|
|
||||||
use Doctrine\Common\Annotations\{AnnotationException, AnnotationReader};
|
use Doctrine\Common\Annotations\{AnnotationException, AnnotationReader};
|
||||||
|
use Co;
|
||||||
use Framework\{Console, ZMBuf};
|
use Framework\{Console, ZMBuf};
|
||||||
|
use Error;
|
||||||
|
use Exception;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
use ReflectionMethod;
|
use ReflectionMethod;
|
||||||
@@ -22,15 +25,14 @@ use ZM\Annotation\Http\{After, Before, Controller, HandleException, Middleware,
|
|||||||
use Swoole\Timer;
|
use Swoole\Timer;
|
||||||
use ZM\Annotation\Interfaces\CustomAnnotation;
|
use ZM\Annotation\Interfaces\CustomAnnotation;
|
||||||
use ZM\Annotation\Interfaces\Level;
|
use ZM\Annotation\Interfaces\Level;
|
||||||
use ZM\Annotation\Module\{Closed, InitBuffer, SaveBuffer};
|
use ZM\Annotation\Module\{Closed, InitBuffer, LoadBuffer, SaveBuffer};
|
||||||
use ZM\Annotation\Swoole\{OnStart, OnTick, SwooleEventAfter, SwooleEventAt};
|
use ZM\Annotation\Swoole\{OnSave, OnStart, OnTick, SwooleEventAfter, SwooleEventAt};
|
||||||
use ZM\Annotation\Interfaces\Rule;
|
use ZM\Annotation\Interfaces\Rule;
|
||||||
use ZM\Connection\WSConnection;
|
use ZM\Connection\WSConnection;
|
||||||
use ZM\Event\EventHandler;
|
use ZM\Event\EventHandler;
|
||||||
use ZM\Http\MiddlewareInterface;
|
use ZM\Http\MiddlewareInterface;
|
||||||
use Framework\DataProvider;
|
use Framework\DataProvider;
|
||||||
use ZM\Utils\ZMUtil;
|
use ZM\Utils\ZMUtil;
|
||||||
use function foo\func;
|
|
||||||
|
|
||||||
class AnnotationParser
|
class AnnotationParser
|
||||||
{
|
{
|
||||||
@@ -64,6 +66,9 @@ class AnnotationParser
|
|||||||
} elseif ($vs instanceof SaveBuffer) {
|
} elseif ($vs instanceof SaveBuffer) {
|
||||||
Console::debug("注册自动保存的缓存变量: " . $vs->buf_name . " (Dir:" . $vs->sub_folder . ")");
|
Console::debug("注册自动保存的缓存变量: " . $vs->buf_name . " (Dir:" . $vs->sub_folder . ")");
|
||||||
DataProvider::addSaveBuffer($vs->buf_name, $vs->sub_folder);
|
DataProvider::addSaveBuffer($vs->buf_name, $vs->sub_folder);
|
||||||
|
} elseif ($vs instanceof LoadBuffer) {
|
||||||
|
Console::debug("注册到内存的缓存变量: " . $vs->buf_name . " (Dir:" . $vs->sub_folder . ")");
|
||||||
|
ZMBuf::set($vs->buf_name, DataProvider::getJsonData(($vs->sub_folder ?? "") . "/" . $vs->buf_name . ".json"));
|
||||||
} elseif ($vs instanceof InitBuffer) {
|
} elseif ($vs instanceof InitBuffer) {
|
||||||
ZMBuf::set($vs->buf_name, []);
|
ZMBuf::set($vs->buf_name, []);
|
||||||
} elseif ($vs instanceof MiddlewareClass) {
|
} elseif ($vs instanceof MiddlewareClass) {
|
||||||
@@ -119,6 +124,7 @@ class AnnotationParser
|
|||||||
elseif ($vss instanceof CQBefore) ZMBuf::$events[CQBefore::class][$vss->cq_event][] = $vss;
|
elseif ($vss instanceof CQBefore) ZMBuf::$events[CQBefore::class][$vss->cq_event][] = $vss;
|
||||||
elseif ($vss instanceof CQAfter) ZMBuf::$events[CQAfter::class][$vss->cq_event][] = $vss;
|
elseif ($vss instanceof CQAfter) ZMBuf::$events[CQAfter::class][$vss->cq_event][] = $vss;
|
||||||
elseif ($vss instanceof OnStart) ZMBuf::$events[OnStart::class][] = $vss;
|
elseif ($vss instanceof OnStart) ZMBuf::$events[OnStart::class][] = $vss;
|
||||||
|
elseif ($vss instanceof OnSave) ZMBuf::$events[OnSave::class][] = $vss;
|
||||||
elseif ($vss instanceof Middleware) ZMBuf::$events[MiddlewareInterface::class][$vss->class][$vss->method][] = $vss->middleware;
|
elseif ($vss instanceof Middleware) ZMBuf::$events[MiddlewareInterface::class][$vss->class][$vss->method][] = $vss->middleware;
|
||||||
elseif ($vss instanceof OnTick) self::addTimerTick($vss);
|
elseif ($vss instanceof OnTick) self::addTimerTick($vss);
|
||||||
elseif ($vss instanceof CQAPISend) ZMBuf::$events[CQAPISend::class][] = $vss;
|
elseif ($vss instanceof CQAPISend) ZMBuf::$events[CQAPISend::class][] = $vss;
|
||||||
@@ -144,13 +150,14 @@ class AnnotationParser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Console::debug("解析注解完毕!");
|
||||||
if (ZMBuf::isset("timer_count")) {
|
if (ZMBuf::isset("timer_count")) {
|
||||||
Console::info("Added " . ZMBuf::get("timer_count") . " timer(s)!");
|
Console::info("Added " . ZMBuf::get("timer_count") . " timer(s)!");
|
||||||
ZMBuf::unsetCache("timer_count");
|
ZMBuf::unsetCache("timer_count");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getRuleCallback($rule_str) {
|
public static function getRuleCallback($rule_str) {
|
||||||
$func = null;
|
$func = null;
|
||||||
$rule = $rule_str;
|
$rule = $rule_str;
|
||||||
if ($rule != "") {
|
if ($rule != "") {
|
||||||
@@ -228,14 +235,14 @@ class AnnotationParser
|
|||||||
return $func;
|
return $func;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function registerRuleEvent(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) {
|
public static function registerRuleEvent(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) {
|
||||||
$vss->callback = self::getRuleCallback($vss->getRule());
|
$vss->callback = self::getRuleCallback($vss->getRule());
|
||||||
$vss->method = $method->getName();
|
$vss->method = $method->getName();
|
||||||
$vss->class = $class->getName();
|
$vss->class = $class->getName();
|
||||||
return $vss;
|
return $vss;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function registerMethod(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) {
|
public static function registerMethod(?AnnotationBase $vss, ReflectionMethod $method, ReflectionClass $class) {
|
||||||
$vss->method = $method->getName();
|
$vss->method = $method->getName();
|
||||||
$vss->class = $class->getName();
|
$vss->class = $class->getName();
|
||||||
return $vss;
|
return $vss;
|
||||||
@@ -336,10 +343,9 @@ class AnnotationParser
|
|||||||
ZMBuf::set("timer_count", ZMBuf::get("timer_count", 0) + 1);
|
ZMBuf::set("timer_count", ZMBuf::get("timer_count", 0) + 1);
|
||||||
$class = ZMUtil::getModInstance($vss->class);
|
$class = ZMUtil::getModInstance($vss->class);
|
||||||
$method = $vss->method;
|
$method = $vss->method;
|
||||||
$has_middleware = false;
|
|
||||||
$ms = $vss->tick_ms;
|
$ms = $vss->tick_ms;
|
||||||
$cid = go(function () use ($class, $method, $ms) {
|
$cid = go(function () use ($class, $method, $ms) {
|
||||||
\Co::suspend();
|
Co::suspend();
|
||||||
$plain_class = get_class($class);
|
$plain_class = get_class($class);
|
||||||
if (!isset(ZMBuf::$events[MiddlewareInterface::class][$plain_class][$method])) {
|
if (!isset(ZMBuf::$events[MiddlewareInterface::class][$plain_class][$method])) {
|
||||||
Console::debug("Added timer: " . $plain_class . " -> " . $method);
|
Console::debug("Added timer: " . $plain_class . " -> " . $method);
|
||||||
@@ -347,9 +353,9 @@ class AnnotationParser
|
|||||||
set_coroutine_params([]);
|
set_coroutine_params([]);
|
||||||
try {
|
try {
|
||||||
$class->$method();
|
$class->$method();
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
Console::error("Uncaught error from TimerTick: " . $e->getMessage() . " at " . $e->getFile() . "({$e->getLine()})");
|
Console::error("Uncaught error from TimerTick: " . $e->getMessage() . " at " . $e->getFile() . "({$e->getLine()})");
|
||||||
} catch (\Error $e) {
|
} catch (Error $e) {
|
||||||
Console::error("Uncaught fatal error from TimerTick: " . $e->getMessage());
|
Console::error("Uncaught fatal error from TimerTick: " . $e->getMessage());
|
||||||
echo Console::setColor($e->getTraceAsString(), "gray");
|
echo Console::setColor($e->getTraceAsString(), "gray");
|
||||||
Console::error("Please check your code!");
|
Console::error("Please check your code!");
|
||||||
@@ -361,9 +367,9 @@ class AnnotationParser
|
|||||||
set_coroutine_params([]);
|
set_coroutine_params([]);
|
||||||
try {
|
try {
|
||||||
EventHandler::callWithMiddleware($class, $method, [], []);
|
EventHandler::callWithMiddleware($class, $method, [], []);
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
Console::error("Uncaught error from TimerTick: " . $e->getMessage() . " at " . $e->getFile() . "({$e->getLine()})");
|
Console::error("Uncaught error from TimerTick: " . $e->getMessage() . " at " . $e->getFile() . "({$e->getLine()})");
|
||||||
} catch (\Error $e) {
|
} catch (Error $e) {
|
||||||
Console::error("Uncaught fatal error from TimerTick: " . $e->getMessage());
|
Console::error("Uncaught fatal error from TimerTick: " . $e->getMessage());
|
||||||
echo Console::setColor($e->getTraceAsString(), "gray");
|
echo Console::setColor($e->getTraceAsString(), "gray");
|
||||||
Console::error("Please check your code!");
|
Console::error("Please check your code!");
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ class CQAPISend extends AnnotationBase implements Level
|
|||||||
*/
|
*/
|
||||||
public $action = "";
|
public $action = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $with_result = false;
|
||||||
|
|
||||||
public $level = 20;
|
public $level = 20;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
24
src/ZM/Annotation/Module/LoadBuffer.php
Normal file
24
src/ZM/Annotation/Module/LoadBuffer.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Annotation\Module;
|
||||||
|
|
||||||
|
use Doctrine\Common\Annotations\Annotation\Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class LoadBuffer
|
||||||
|
* @package ZM\Annotation\Module
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
*/
|
||||||
|
class LoadBuffer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
* @Required()
|
||||||
|
*/
|
||||||
|
public $buf_name;
|
||||||
|
|
||||||
|
/** @var string $sub_folder */
|
||||||
|
public $sub_folder = null;
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ class SaveBuffer
|
|||||||
* @Required()
|
* @Required()
|
||||||
*/
|
*/
|
||||||
public $buf_name;
|
public $buf_name;
|
||||||
|
|
||||||
/** @var string $sub_folder */
|
/** @var string $sub_folder */
|
||||||
public $sub_folder = null;
|
public $sub_folder = null;
|
||||||
}
|
}
|
||||||
18
src/ZM/Annotation/Swoole/OnSave.php
Normal file
18
src/ZM/Annotation/Swoole/OnSave.php
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Annotation\Swoole;
|
||||||
|
|
||||||
|
use Doctrine\Common\Annotations\Annotation\Target;
|
||||||
|
use ZM\Annotation\AnnotationBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class OnSave
|
||||||
|
* @package ZM\Annotation\Swoole
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
*/
|
||||||
|
class OnSave extends AnnotationBase
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -47,6 +47,8 @@ class ConnectionManager
|
|||||||
return WCConnection::class;
|
return WCConnection::class;
|
||||||
case "proxy":
|
case "proxy":
|
||||||
return ProxyConnection::class;
|
return ProxyConnection::class;
|
||||||
|
case "terminal":
|
||||||
|
return TerminalConnection::class;
|
||||||
default:
|
default:
|
||||||
foreach (ZMBuf::$custom_connection_class as $v) {
|
foreach (ZMBuf::$custom_connection_class as $v) {
|
||||||
/** @var WSConnection $r */
|
/** @var WSConnection $r */
|
||||||
|
|||||||
13
src/ZM/Connection/TerminalConnection.php
Normal file
13
src/ZM/Connection/TerminalConnection.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Connection;
|
||||||
|
|
||||||
|
|
||||||
|
class TerminalConnection extends WSConnection
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getType() {
|
||||||
|
return "terminal";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,7 +54,7 @@ class Context implements ContextInterface
|
|||||||
public function getResponse() { return ZMBuf::$context[$this->cid]["response"] ?? null; }
|
public function getResponse() { return ZMBuf::$context[$this->cid]["response"] ?? null; }
|
||||||
|
|
||||||
/** @return WSConnection */
|
/** @return WSConnection */
|
||||||
public function getConnection() { return ConnectionManager::get($this->getFrame()->fd); }
|
public function getConnection() { return ConnectionManager::get($this->getFd()); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int|null
|
* @return int|null
|
||||||
@@ -95,6 +95,8 @@ class Context implements ContextInterface
|
|||||||
|
|
||||||
public function setCache($key, $value) { ZMBuf::$context[$this->cid]["cache"][$key] = $value; }
|
public function setCache($key, $value) { ZMBuf::$context[$this->cid]["cache"][$key] = $value; }
|
||||||
|
|
||||||
|
public function getCQResponse() { return ZMBuf::$context[$this->cid]["cq_response"] ?? null; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* only can used by cq->message event function
|
* only can used by cq->message event function
|
||||||
* @param $msg
|
* @param $msg
|
||||||
@@ -106,6 +108,7 @@ class Context implements ContextInterface
|
|||||||
case "group":
|
case "group":
|
||||||
case "private":
|
case "private":
|
||||||
case "discuss":
|
case "discuss":
|
||||||
|
$this->setCache("has_reply", true);
|
||||||
return CQAPI::quick_reply(ConnectionManager::get($this->getFrame()->fd), $this->getData(), $msg, $yield);
|
return CQAPI::quick_reply(ConnectionManager::get($this->getFrame()->fd), $this->getData(), $msg, $yield);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ interface ContextInterface
|
|||||||
|
|
||||||
public function setMessageType($type);
|
public function setMessageType($type);
|
||||||
|
|
||||||
|
public function getCQResponse();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $msg
|
* @param $msg
|
||||||
* @param bool $yield
|
* @param bool $yield
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use framework\Console;
|
|||||||
use framework\ZMBuf;
|
use framework\ZMBuf;
|
||||||
use PDOStatement;
|
use PDOStatement;
|
||||||
use Swoole\Coroutine;
|
use Swoole\Coroutine;
|
||||||
|
use Swoole\Database\PDOStatementProxy;
|
||||||
use ZM\Exception\DbException;
|
use ZM\Exception\DbException;
|
||||||
|
|
||||||
class DB
|
class DB
|
||||||
@@ -66,9 +67,10 @@ class DB
|
|||||||
try {
|
try {
|
||||||
$conn = ZMBuf::$sql_pool->get();
|
$conn = ZMBuf::$sql_pool->get();
|
||||||
if ($conn === false) {
|
if ($conn === false) {
|
||||||
|
ZMBuf::$sql_pool->put(null);
|
||||||
throw new DbException("无法连接SQL!" . $line);
|
throw new DbException("无法连接SQL!" . $line);
|
||||||
}
|
}
|
||||||
$result = $conn->query($line) === false ? false : ($conn->errno != 0 ? false : true);
|
$result = $conn->query($line) === false ? false : true;
|
||||||
ZMBuf::$sql_pool->put($conn);
|
ZMBuf::$sql_pool->put($conn);
|
||||||
return $result;
|
return $result;
|
||||||
} catch (DBException $e) {
|
} catch (DBException $e) {
|
||||||
@@ -98,25 +100,29 @@ class DB
|
|||||||
try {
|
try {
|
||||||
$conn = ZMBuf::$sql_pool->get();
|
$conn = ZMBuf::$sql_pool->get();
|
||||||
if ($conn === false) {
|
if ($conn === false) {
|
||||||
|
ZMBuf::$sql_pool->put(null);
|
||||||
throw new DbException("无法连接SQL!" . $line);
|
throw new DbException("无法连接SQL!" . $line);
|
||||||
}
|
}
|
||||||
$ps = $conn->prepare($line);
|
$ps = $conn->prepare($line);
|
||||||
if ($ps === false) {
|
if ($ps === false) {
|
||||||
ZMBuf::$sql_pool->connect_cnt -= 1;
|
ZMBuf::$sql_pool->put(null);
|
||||||
throw new DbException("SQL语句查询错误," . $line . ",错误信息:" . $conn->error);
|
throw new DbException("SQL语句查询错误," . $line . ",错误信息:" . $conn->error);
|
||||||
} else {
|
} else {
|
||||||
if (!($ps instanceof PDOStatement)) {
|
if (!($ps instanceof PDOStatement) && !($ps instanceof PDOStatementProxy)) {
|
||||||
throw new DbException("语句查询错误!" . $line);
|
var_dump($ps);
|
||||||
|
ZMBuf::$sql_pool->put(null);
|
||||||
|
throw new DbException("语句查询错误!返回的不是 PDOStatement" . $line);
|
||||||
}
|
}
|
||||||
if ($params == []) $result = $ps->execute();
|
if ($params == []) $result = $ps->execute();
|
||||||
elseif (!is_array($params)) {
|
elseif (!is_array($params)) {
|
||||||
$result = $ps->execute([$params]);
|
$result = $ps->execute([$params]);
|
||||||
} else $result = $ps->execute($params);
|
} else $result = $ps->execute($params);
|
||||||
ZMBuf::$sql_pool->put($conn);
|
|
||||||
if ($result !== true) {
|
if ($result !== true) {
|
||||||
|
ZMBuf::$sql_pool->put(null);
|
||||||
throw new DBException("语句[$line]错误!" . $ps->errorInfo()[2]);
|
throw new DBException("语句[$line]错误!" . $ps->errorInfo()[2]);
|
||||||
//echo json_encode(debug_backtrace(), 128 | 256);
|
//echo json_encode(debug_backtrace(), 128 | 256);
|
||||||
}
|
}
|
||||||
|
ZMBuf::$sql_pool->put($conn);
|
||||||
if (ZMBuf::get("sql_log") === true) {
|
if (ZMBuf::get("sql_log") === true) {
|
||||||
$log =
|
$log =
|
||||||
"[" . date("Y-m-d H:i:s") .
|
"[" . date("Y-m-d H:i:s") .
|
||||||
@@ -134,8 +140,12 @@ class DB
|
|||||||
"] " . $line . " " . json_encode($params, JSON_UNESCAPED_UNICODE) . " (Error:" . $e->getMessage() . ")\n";
|
"] " . $line . " " . json_encode($params, JSON_UNESCAPED_UNICODE) . " (Error:" . $e->getMessage() . ")\n";
|
||||||
Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND);
|
Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND);
|
||||||
}
|
}
|
||||||
|
if(mb_strpos($e->getMessage(), "has gone away") !== false) {
|
||||||
|
zm_sleep(0.2);
|
||||||
|
Console::warning("Gone away of MySQL! retrying!");
|
||||||
|
return self::rawQuery($line, $params);
|
||||||
|
}
|
||||||
Console::warning($e->getMessage());
|
Console::warning($e->getMessage());
|
||||||
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ trait WhereBody
|
|||||||
$param []=$vs;
|
$param []=$vs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($msg == '') $msg = 1;
|
||||||
return [$msg, $param];
|
return [$msg, $param];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,10 +38,11 @@ class MessageEvent
|
|||||||
* @throws AnnotationException
|
* @throws AnnotationException
|
||||||
*/
|
*/
|
||||||
public function onBefore() {
|
public function onBefore() {
|
||||||
foreach (ZMBuf::$events[CQBefore::class]["message"] ?? [] as $v) {
|
$obj_list = ZMBuf::$events[CQBefore::class]["message"];
|
||||||
$c = $v->class;
|
foreach ($obj_list as $v) {
|
||||||
|
if($v->level < 200) break;
|
||||||
EventHandler::callWithMiddleware(
|
EventHandler::callWithMiddleware(
|
||||||
$c,
|
$v->class,
|
||||||
$v->method,
|
$v->method,
|
||||||
["data" => context()->getData(), "connection" => $this->connection],
|
["data" => context()->getData(), "connection" => $this->connection],
|
||||||
[],
|
[],
|
||||||
@@ -63,6 +64,21 @@ class MessageEvent
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (ZMBuf::$events[CQBefore::class]["message"] ?? [] as $v) {
|
||||||
|
if($v->level >= 200) continue;
|
||||||
|
$c = $v->class;
|
||||||
|
if (ctx()->getCache("level") != 0) continue;
|
||||||
|
EventHandler::callWithMiddleware(
|
||||||
|
$c,
|
||||||
|
$v->method,
|
||||||
|
["data" => context()->getData(), "connection" => $this->connection],
|
||||||
|
[],
|
||||||
|
function ($r) {
|
||||||
|
if (!$r) context()->setCache("block_continue", true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (context()->getCache("block_continue") === true) return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +118,7 @@ class MessageEvent
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} elseif ($v->regexMatch != "" && ($args = matchArgs($v->regexMatch, context()->getMessage())) !== false) {
|
} elseif ($v->regexMatch != "" && ($args = matchArgs($v->regexMatch, context()->getMessage())) !== false) {
|
||||||
|
Console::debug("Calling $c -> {$v->method}");
|
||||||
$this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, $class_construct, [$args], function ($r) {
|
$this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, $class_construct, [$args], function ($r) {
|
||||||
if (is_string($r)) context()->reply($r);
|
if (is_string($r)) context()->reply($r);
|
||||||
return true;
|
return true;
|
||||||
@@ -120,6 +137,7 @@ class MessageEvent
|
|||||||
($v->message_type == '' || ($v->message_type != '' && $v->message_type == context()->getData()["message_type"])) &&
|
($v->message_type == '' || ($v->message_type != '' && $v->message_type == context()->getData()["message_type"])) &&
|
||||||
($v->raw_message == '' || ($v->raw_message != '' && $v->raw_message == context()->getData()["raw_message"]))) {
|
($v->raw_message == '' || ($v->raw_message != '' && $v->raw_message == context()->getData()["raw_message"]))) {
|
||||||
$c = $v->class;
|
$c = $v->class;
|
||||||
|
Console::debug("Calling CQMessage: $c -> {$v->method}");
|
||||||
if (!isset($obj[$c]))
|
if (!isset($obj[$c]))
|
||||||
$obj[$c] = new $c([
|
$obj[$c] = new $c([
|
||||||
"data" => context()->getData(),
|
"data" => context()->getData(),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Exception;
|
|||||||
use Framework\Console;
|
use Framework\Console;
|
||||||
use Framework\ZMBuf;
|
use Framework\ZMBuf;
|
||||||
use ZM\Event\Swoole\{MessageEvent, RequestEvent, WorkerStartEvent, WSCloseEvent, WSOpenEvent};
|
use ZM\Event\Swoole\{MessageEvent, RequestEvent, WorkerStartEvent, WSCloseEvent, WSOpenEvent};
|
||||||
|
use Swoole\Http\Request;
|
||||||
use Swoole\Server;
|
use Swoole\Server;
|
||||||
use Swoole\WebSocket\Frame;
|
use Swoole\WebSocket\Frame;
|
||||||
use ZM\Annotation\CQ\CQAPIResponse;
|
use ZM\Annotation\CQ\CQAPIResponse;
|
||||||
@@ -46,8 +47,9 @@ class EventHandler
|
|||||||
DataProvider::saveBuffer();
|
DataProvider::saveBuffer();
|
||||||
ZMBuf::$server->shutdown();
|
ZMBuf::$server->shutdown();
|
||||||
});
|
});
|
||||||
(new WorkerStartEvent($param0, $param1))->onActivate()->onAfter();
|
$r = (new WorkerStartEvent($param0, $param1))->onActivate();
|
||||||
Console::log("\n=== Worker #" . $param0->worker_id . " 已启动 ===\n", "gold");
|
Console::log("\n=== Worker #" . $param0->worker_id . " 已启动 ===\n", "gold");
|
||||||
|
$r->onAfter();
|
||||||
self::startTick();
|
self::startTick();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Console::error("Worker加载出错!停止服务!");
|
Console::error("Worker加载出错!停止服务!");
|
||||||
@@ -69,6 +71,7 @@ class EventHandler
|
|||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
||||||
|
Console::stackTrace();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "request":
|
case "request":
|
||||||
@@ -99,12 +102,14 @@ class EventHandler
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "open":
|
case "open":
|
||||||
set_coroutine_params(["server" => $param0, "request" => $param1]);
|
/** @var Request $param1 */
|
||||||
|
set_coroutine_params(["server" => $param0, "request" => $param1, "fd" => $param1->fd]);
|
||||||
try {
|
try {
|
||||||
(new WSOpenEvent($param0, $param1))->onActivate()->onAfter();
|
(new WSOpenEvent($param0, $param1))->onActivate()->onAfter();
|
||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
||||||
|
Console::stackTrace();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "close":
|
case "close":
|
||||||
@@ -114,6 +119,7 @@ class EventHandler
|
|||||||
} catch (Error $e) {
|
} catch (Error $e) {
|
||||||
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
$error_msg = $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")";
|
||||||
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
Console::error("Fatal error when calling $event_name: " . $error_msg);
|
||||||
|
Console::stackTrace();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -128,6 +134,7 @@ class EventHandler
|
|||||||
* @throws AnnotationException
|
* @throws AnnotationException
|
||||||
*/
|
*/
|
||||||
public static function callCQEvent($event_data, $conn_or_response, int $level = 0) {
|
public static function callCQEvent($event_data, $conn_or_response, int $level = 0) {
|
||||||
|
ctx()->setCache("level",$level);
|
||||||
if ($level >= 5) {
|
if ($level >= 5) {
|
||||||
Console::warning("Recursive call reached " . $level . " times");
|
Console::warning("Recursive call reached " . $level . " times");
|
||||||
Console::stackTrace();
|
Console::stackTrace();
|
||||||
@@ -160,8 +167,12 @@ class EventHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $req
|
||||||
|
* @throws AnnotationException
|
||||||
|
*/
|
||||||
public static function callCQResponse($req) {
|
public static function callCQResponse($req) {
|
||||||
//Console::info("收到来自API连接的回复:".json_encode($req, 128|256));
|
Console::debug("收到来自API连接的回复:".json_encode($req, 128|256));
|
||||||
$status = $req["status"];
|
$status = $req["status"];
|
||||||
$retcode = $req["retcode"];
|
$retcode = $req["retcode"];
|
||||||
$data = $req["data"];
|
$data = $req["data"];
|
||||||
@@ -172,13 +183,26 @@ class EventHandler
|
|||||||
"status" => $status,
|
"status" => $status,
|
||||||
"retcode" => $retcode,
|
"retcode" => $retcode,
|
||||||
"data" => $data,
|
"data" => $data,
|
||||||
"self_id" => $self_id
|
"self_id" => $self_id,
|
||||||
|
"echo" => $req["echo"]
|
||||||
];
|
];
|
||||||
|
set_coroutine_params(["cq_response" => $response]);
|
||||||
if (isset(ZMBuf::$events[CQAPIResponse::class][$req["retcode"]])) {
|
if (isset(ZMBuf::$events[CQAPIResponse::class][$req["retcode"]])) {
|
||||||
list($c, $method) = ZMBuf::$events[CQAPIResponse::class][$req["retcode"]];
|
list($c, $method) = ZMBuf::$events[CQAPIResponse::class][$req["retcode"]];
|
||||||
$class = new $c(["data" => $origin["data"]]);
|
$class = new $c(["data" => $origin["data"]]);
|
||||||
call_user_func_array([$class, $method], [$origin["data"], $req]);
|
call_user_func_array([$class, $method], [$origin["data"], $req]);
|
||||||
}
|
}
|
||||||
|
$origin_ctx = ctx()->copy();
|
||||||
|
ctx()->setCache("action", $origin["data"]["action"] ?? "unknown");
|
||||||
|
ctx()->setData($origin["data"]);
|
||||||
|
foreach (ZMBuf::$events[CQAPISend::class] ?? [] as $k => $v) {
|
||||||
|
if (($v->action == "" || $v->action == ctx()->getCache("action")) && $v->with_result) {
|
||||||
|
$c = $v->class;
|
||||||
|
self::callWithMiddleware($c, $v->method, context()->copy(), [ctx()->getCache("action"), $origin["data"]["params"] ?? [], ctx()->getRobotId()]);
|
||||||
|
if (context()->getCache("block_continue") === true) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_coroutine_params($origin_ctx);
|
||||||
if (($origin["func"] ?? null) !== null) {
|
if (($origin["func"] ?? null) !== null) {
|
||||||
call_user_func($origin["func"], $response, $origin["data"]);
|
call_user_func($origin["func"], $response, $origin["data"]);
|
||||||
} elseif (($origin["coroutine"] ?? false) !== false) {
|
} elseif (($origin["coroutine"] ?? false) !== false) {
|
||||||
@@ -204,7 +228,7 @@ class EventHandler
|
|||||||
context()->setCache("action", $action);
|
context()->setCache("action", $action);
|
||||||
context()->setCache("reply", $reply);
|
context()->setCache("reply", $reply);
|
||||||
foreach (ZMBuf::$events[CQAPISend::class] ?? [] as $k => $v) {
|
foreach (ZMBuf::$events[CQAPISend::class] ?? [] as $k => $v) {
|
||||||
if ($v->action == "" || $v->action == $action) {
|
if (($v->action == "" || $v->action == $action) && !$v->with_result) {
|
||||||
$c = $v->class;
|
$c = $v->class;
|
||||||
self::callWithMiddleware($c, $v->method, context()->copy(), [$reply["action"], $reply["params"] ?? [], $connection->getQQ()]);
|
self::callWithMiddleware($c, $v->method, context()->copy(), [$reply["action"], $reply["params"] ?? [], $connection->getQQ()]);
|
||||||
if (context()->getCache("block_continue") === true) break;
|
if (context()->getCache("block_continue") === true) break;
|
||||||
@@ -286,5 +310,6 @@ class EventHandler
|
|||||||
foreach (ZMBuf::get("paused_tick", []) as $cid) {
|
foreach (ZMBuf::get("paused_tick", []) as $cid) {
|
||||||
Co::resume($cid);
|
Co::resume($cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,11 @@ class MessageEvent implements SwooleEvent
|
|||||||
ctx()->setCache("level", 0);
|
ctx()->setCache("level", 0);
|
||||||
Console::debug("Calling CQ Event from fd=" . $conn->fd);
|
Console::debug("Calling CQ Event from fd=" . $conn->fd);
|
||||||
EventHandler::callCQEvent($data, ConnectionManager::get(context()->getFrame()->fd), 0);
|
EventHandler::callCQEvent($data, ConnectionManager::get(context()->getFrame()->fd), 0);
|
||||||
} else
|
} else{
|
||||||
|
set_coroutine_params(["connection" => $conn]);
|
||||||
EventHandler::callCQResponse($data);
|
EventHandler::callCQResponse($data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
foreach (ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) {
|
foreach (ZMBuf::$events[SwooleEventAt::class] ?? [] as $v) {
|
||||||
if (strtolower($v->type) == "message" && $this->parseSwooleRule($v)) {
|
if (strtolower($v->type) == "message" && $this->parseSwooleRule($v)) {
|
||||||
$c = $v->class;
|
$c = $v->class;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace ZM\Event\Swoole;
|
|||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Doctrine\Common\Annotations\AnnotationException;
|
use Doctrine\Common\Annotations\AnnotationException;
|
||||||
|
use Framework\Console;
|
||||||
use Framework\ZMBuf;
|
use Framework\ZMBuf;
|
||||||
use Swoole\Http\Request;
|
use Swoole\Http\Request;
|
||||||
use Swoole\WebSocket\Server;
|
use Swoole\WebSocket\Server;
|
||||||
@@ -51,9 +52,16 @@ class WSOpenEvent implements SwooleEvent
|
|||||||
if ($type_conn == CQConnection::class) {
|
if ($type_conn == CQConnection::class) {
|
||||||
$qq = $this->request->get["qq"] ?? $this->request->header["x-self-id"] ?? "";
|
$qq = $this->request->get["qq"] ?? $this->request->header["x-self-id"] ?? "";
|
||||||
$self_token = ZMBuf::globals("access_token") ?? "";
|
$self_token = ZMBuf::globals("access_token") ?? "";
|
||||||
$remote_token = $this->request->get["token"] ?? (isset($header["authorization"]) ? explode(" ", $this->request->header["authorization"])[1] : "");
|
if(isset($this->request->header["authorization"])) {
|
||||||
|
Console::debug($this->request->header["authorization"]);
|
||||||
|
}
|
||||||
|
$remote_token = $this->request->get["token"] ?? (isset($this->request->header["authorization"]) ? explode(" ", $this->request->header["authorization"])[1] : "");
|
||||||
if ($qq != "" && ($self_token == $remote_token)) $this->conn = new CQConnection($this->server, $this->request->fd, $qq);
|
if ($qq != "" && ($self_token == $remote_token)) $this->conn = new CQConnection($this->server, $this->request->fd, $qq);
|
||||||
else $this->conn = new UnknownConnection($this->server, $this->request->fd);
|
else {
|
||||||
|
$this->conn = new UnknownConnection($this->server, $this->request->fd);
|
||||||
|
Console::warning("connection of CQ has invalid QQ or token!");
|
||||||
|
Console::debug("Remote token: ".$remote_token);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->conn = new $type_conn($this->server, $this->request->fd);
|
$this->conn = new $type_conn($this->server, $this->request->fd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ use Doctrine\Common\Annotations\AnnotationException;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use ReflectionException;
|
use ReflectionException;
|
||||||
use Swoole\Coroutine;
|
use Swoole\Coroutine;
|
||||||
|
use Swoole\Database\PDOConfig;
|
||||||
|
use Swoole\Database\PDOPool;
|
||||||
use Swoole\Process;
|
use Swoole\Process;
|
||||||
use Swoole\Timer;
|
use Swoole\Timer;
|
||||||
use ZM\Annotation\AnnotationBase;
|
use ZM\Annotation\AnnotationBase;
|
||||||
@@ -25,7 +27,6 @@ use Swoole\Server;
|
|||||||
use ZM\Event\EventHandler;
|
use ZM\Event\EventHandler;
|
||||||
use ZM\Exception\DbException;
|
use ZM\Exception\DbException;
|
||||||
use Framework\DataProvider;
|
use Framework\DataProvider;
|
||||||
use ZM\Utils\SQLPool;
|
|
||||||
use ZM\Utils\ZMUtil;
|
use ZM\Utils\ZMUtil;
|
||||||
|
|
||||||
class WorkerStartEvent implements SwooleEvent
|
class WorkerStartEvent implements SwooleEvent
|
||||||
@@ -49,6 +50,9 @@ class WorkerStartEvent implements SwooleEvent
|
|||||||
*/
|
*/
|
||||||
public function onActivate(): WorkerStartEvent {
|
public function onActivate(): WorkerStartEvent {
|
||||||
Console::info("Worker启动中");
|
Console::info("Worker启动中");
|
||||||
|
ZMBuf::$server = $this->server;
|
||||||
|
Console::listenConsole(); //这个方法只能在这里调用,且如果worker_num不为1的话,此功能不可用
|
||||||
|
|
||||||
Process::signal(SIGINT, function () {
|
Process::signal(SIGINT, function () {
|
||||||
Console::warning("Server interrupted by keyboard.");
|
Console::warning("Server interrupted by keyboard.");
|
||||||
ZMUtil::stop(true);
|
ZMUtil::stop(true);
|
||||||
@@ -76,14 +80,35 @@ class WorkerStartEvent implements SwooleEvent
|
|||||||
}
|
}
|
||||||
if (ZMBuf::globals("sql_config")["sql_host"] != "") {
|
if (ZMBuf::globals("sql_config")["sql_host"] != "") {
|
||||||
Console::info("新建SQL连接池中");
|
Console::info("新建SQL连接池中");
|
||||||
ZMBuf::$sql_pool = new SQLPool();
|
ob_start();
|
||||||
|
phpinfo();
|
||||||
|
$str = ob_get_clean();
|
||||||
|
$str = explode("\n", $str);
|
||||||
|
foreach($str as $k => $v) {
|
||||||
|
$v = trim($v);
|
||||||
|
if($v == "") continue;
|
||||||
|
if(mb_strpos($v, "API Extensions") === false) continue;
|
||||||
|
if(mb_strpos($v, "pdo_mysql") === false) {
|
||||||
|
throw new DbException("未安装 mysqlnd php-mysql扩展。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$sql = ZMBuf::globals("sql_config");
|
||||||
|
ZMBuf::$sql_pool = new PDOPool((new PDOConfig())
|
||||||
|
->withHost($sql["sql_host"])
|
||||||
|
->withPort($sql["sql_port"])
|
||||||
|
// ->withUnixSocket('/tmp/mysql.sock')
|
||||||
|
->withDbName($sql["sql_database"])
|
||||||
|
->withCharset('utf8mb4')
|
||||||
|
->withUsername($sql["sql_username"])
|
||||||
|
->withPassword($sql["sql_password"])
|
||||||
|
);
|
||||||
DB::initTableList();
|
DB::initTableList();
|
||||||
}
|
}
|
||||||
ZMBuf::$server = $this->server;
|
|
||||||
ZMBuf::$atomics['reload_time']->add(1);
|
ZMBuf::$atomics['reload_time']->add(1);
|
||||||
|
|
||||||
Console::info("监听console输入");
|
Console::info("监听console输入");
|
||||||
Console::listenConsole(); //这个方法只能在这里调用,且如果worker_num不为1的话,此功能不可用
|
|
||||||
$this->setAutosaveTimer(ZMBuf::globals("auto_save_interval"));
|
$this->setAutosaveTimer(ZMBuf::globals("auto_save_interval"));
|
||||||
$this->loadAllClass(); //加载composer资源、phar外置包、注解解析注册等
|
$this->loadAllClass(); //加载composer资源、phar外置包、注解解析注册等
|
||||||
return $this;
|
return $this;
|
||||||
@@ -99,18 +124,22 @@ class WorkerStartEvent implements SwooleEvent
|
|||||||
}
|
}
|
||||||
ZMBuf::unsetCache("wait_start");
|
ZMBuf::unsetCache("wait_start");
|
||||||
set_coroutine_params(["server" => $this->server, "worker_id" => $this->worker_id]);
|
set_coroutine_params(["server" => $this->server, "worker_id" => $this->worker_id]);
|
||||||
|
|
||||||
foreach (ZMBuf::$events[OnStart::class] ?? [] as $v) {
|
foreach (ZMBuf::$events[OnStart::class] ?? [] as $v) {
|
||||||
$class_name = $v->class;
|
$class_name = $v->class;
|
||||||
|
Console::debug("正在调用启动时函数: " . $class_name . " -> " . $v->method);
|
||||||
EventHandler::callWithMiddleware($class_name, $v->method, ["server" => $this->server, "worker_id" => $this->worker_id], []);
|
EventHandler::callWithMiddleware($class_name, $v->method, ["server" => $this->server, "worker_id" => $this->worker_id], []);
|
||||||
}
|
}
|
||||||
foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) {
|
foreach (ZMBuf::$events[SwooleEventAfter::class] ?? [] as $v) {
|
||||||
/** @var AnnotationBase $v */
|
/** @var AnnotationBase $v */
|
||||||
if (strtolower($v->type) == "workerstart") {
|
if (strtolower($v->type) == "workerstart") {
|
||||||
$class_name = $v->class;
|
$class_name = $v->class;
|
||||||
|
Console::debug("正在调用启动时函数after: " . $class_name . " -> " . $v->method);
|
||||||
EventHandler::callWithMiddleware($class_name, $v->method, ["server" => $this->server, "worker_id" => $this->worker_id], []);
|
EventHandler::callWithMiddleware($class_name, $v->method, ["server" => $this->server, "worker_id" => $this->worker_id], []);
|
||||||
if (context()->getCache("block_continue") === true) break;
|
if (context()->getCache("block_continue") === true) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Console::debug("调用完毕!");
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,8 +147,8 @@ class WorkerStartEvent implements SwooleEvent
|
|||||||
foreach ($this->server->connections as $v) {
|
foreach ($this->server->connections as $v) {
|
||||||
$this->server->close($v);
|
$this->server->close($v);
|
||||||
}
|
}
|
||||||
if (ZMBuf::$sql_pool instanceof SqlPool) {
|
if (ZMBuf::$sql_pool !== null) {
|
||||||
ZMBuf::$sql_pool->destruct();
|
ZMBuf::$sql_pool->close();
|
||||||
ZMBuf::$sql_pool = null;
|
ZMBuf::$sql_pool = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,12 +176,11 @@ class WorkerStartEvent implements SwooleEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
//加载composer类
|
//加载composer类
|
||||||
if (file_exists(DataProvider::getWorkingDir() . "/vendor/autoload.php")) {
|
|
||||||
Console::info("加载composer资源中");
|
Console::info("加载composer资源中");
|
||||||
|
if (file_exists(DataProvider::getWorkingDir() . "/vendor/autoload.php")) {
|
||||||
require_once DataProvider::getWorkingDir() . "/vendor/autoload.php";
|
require_once DataProvider::getWorkingDir() . "/vendor/autoload.php";
|
||||||
} else {
|
|
||||||
if (isPharMode()) require_once WORKING_DIR . "/vendor/autoload.php";
|
|
||||||
}
|
}
|
||||||
|
if (isPharMode()) require_once WORKING_DIR . "/vendor/autoload.php";
|
||||||
|
|
||||||
//加载各个模块的注解类,以及反射
|
//加载各个模块的注解类,以及反射
|
||||||
Console::info("检索Module中");
|
Console::info("检索Module中");
|
||||||
@@ -162,6 +190,7 @@ class WorkerStartEvent implements SwooleEvent
|
|||||||
ConnectionManager::registerCustomClass();
|
ConnectionManager::registerCustomClass();
|
||||||
|
|
||||||
//加载自定义的全局函数
|
//加载自定义的全局函数
|
||||||
|
Console::debug("加载自定义的全局函数中");
|
||||||
if (file_exists(DataProvider::getWorkingDir() . "/src/Custom/global_function.php"))
|
if (file_exists(DataProvider::getWorkingDir() . "/src/Custom/global_function.php"))
|
||||||
require_once DataProvider::getWorkingDir() . "/src/Custom/global_function.php";
|
require_once DataProvider::getWorkingDir() . "/src/Custom/global_function.php";
|
||||||
$this->afterCheck();
|
$this->afterCheck();
|
||||||
@@ -169,7 +198,7 @@ class WorkerStartEvent implements SwooleEvent
|
|||||||
|
|
||||||
private function setAutosaveTimer($globals) {
|
private function setAutosaveTimer($globals) {
|
||||||
DataProvider::$buffer_list = [];
|
DataProvider::$buffer_list = [];
|
||||||
Timer::tick($globals * 1000, function () {
|
zm_timer_tick($globals * 1000, function () {
|
||||||
DataProvider::saveBuffer();
|
DataProvider::saveBuffer();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/ZM/Http/StaticFileHandler.php
Normal file
35
src/ZM/Http/StaticFileHandler.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZM\Http;
|
||||||
|
|
||||||
|
|
||||||
|
use Framework\Console;
|
||||||
|
use Framework\ZMBuf;
|
||||||
|
use ZM\Utils\ZMUtil;
|
||||||
|
|
||||||
|
class StaticFileHandler
|
||||||
|
{
|
||||||
|
public function __construct($filename, $path) {
|
||||||
|
$full_path = realpath($path . "/" . $filename);
|
||||||
|
$response = ctx()->getResponse();
|
||||||
|
Console::debug("Full path: ".$full_path);
|
||||||
|
if ($full_path !== false) {
|
||||||
|
if (strpos($full_path, $path) !== 0) {
|
||||||
|
$response->status(403);
|
||||||
|
$response->end("403 Forbidden");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if(is_file($full_path)) {
|
||||||
|
$exp = strtolower(pathinfo($full_path)['extension'] ?? "unknown");
|
||||||
|
$response->setHeader("Content-Type", ZMBuf::config("file_header")[$exp] ?? "application/octet-stream");
|
||||||
|
$response->end(file_get_contents($full_path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$response->status(404);
|
||||||
|
$response->end(ZMUtil::getHttpCodePage(404));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,6 @@ use PDO;
|
|||||||
use PDOException;
|
use PDOException;
|
||||||
use SplQueue;
|
use SplQueue;
|
||||||
use Swoole\Coroutine;
|
use Swoole\Coroutine;
|
||||||
use Swoole\Coroutine\Mysql;
|
|
||||||
|
|
||||||
class SQLPool
|
class SQLPool
|
||||||
{
|
{
|
||||||
@@ -34,6 +33,26 @@ class SQLPool
|
|||||||
"password" => ZMBuf::globals("sql_config")["sql_password"],
|
"password" => ZMBuf::globals("sql_config")["sql_password"],
|
||||||
"database" => ZMBuf::globals("sql_config")["sql_database"]
|
"database" => ZMBuf::globals("sql_config")["sql_database"]
|
||||||
];
|
];
|
||||||
|
Console::debug("新建检测 MySQL 连接的计时器");
|
||||||
|
zm_timer_tick(10000, function () {
|
||||||
|
//Console::debug("正在检测是否有坏死的MySQL连接,当前连接池有 ".count($this->pool) . " 个连接");
|
||||||
|
if (count($this->pool) > 0) {
|
||||||
|
/** @var PDO $cnn */
|
||||||
|
$cnn = $this->pool->pop();
|
||||||
|
$this->connect_cnt -= 1;
|
||||||
|
try {
|
||||||
|
$cnn->getAttribute(PDO::ATTR_SERVER_INFO);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if (strpos($e->getMessage(), 'MySQL server has gone away') !== false) {
|
||||||
|
Console::info("MySQL 长连接丢失,取消连接");
|
||||||
|
unset($cnn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->pool->push($cnn);
|
||||||
|
$this->connect_cnt += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,8 +109,7 @@ class SQLPool
|
|||||||
|
|
||||||
private function newConnect() {
|
private function newConnect() {
|
||||||
//无空闲连接,创建新连接
|
//无空闲连接,创建新连接
|
||||||
$mysql = new Mysql();
|
$dsn = "mysql:host=" . $this->info["host"] . ";dbname=" . $this->info["database"] . ";charset=utf8";
|
||||||
$dsn = "mysql:host=" . $this->info["host"] . ";dbname=" . $this->info["database"];
|
|
||||||
try {
|
try {
|
||||||
$mysql = new PDO($dsn, $this->info["user"], $this->info["password"], array(PDO::ATTR_PERSISTENT => true));
|
$mysql = new PDO($dsn, $this->info["user"], $this->info["password"], array(PDO::ATTR_PERSISTENT => true));
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user