mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-21 15:45:36 +08:00
update to version 1.4
This commit is contained in:
@@ -8,12 +8,19 @@
|
||||
|
||||
namespace Framework;
|
||||
|
||||
use co;
|
||||
use ZM\Annotation\Swoole\SwooleEventAt;
|
||||
use ZM\Connection\WSConnection;
|
||||
use ZM\Utils\ZMUtil;
|
||||
use Exception;
|
||||
|
||||
class Console
|
||||
{
|
||||
/**
|
||||
* @var false|resource
|
||||
*/
|
||||
public static $console_proc = null;
|
||||
public static $pipes = [];
|
||||
|
||||
static function setColor($string, $color = "") {
|
||||
switch ($color) {
|
||||
case "red":
|
||||
@@ -119,8 +126,8 @@ class Console
|
||||
}
|
||||
}
|
||||
|
||||
static function debug($obj) {
|
||||
debug($obj);
|
||||
static function debug($msg) {
|
||||
if (ZMBuf::$atomics["info_level"]->get() >= 4) Console::log(date("[H:i:s] ") . "[D] " . $msg, 'gray');
|
||||
}
|
||||
|
||||
static function log($obj, $color = "") {
|
||||
@@ -157,11 +164,51 @@ class Console
|
||||
self::info("ConsoleCommand disabled.");
|
||||
return;
|
||||
}
|
||||
go(function () {
|
||||
while (true) {
|
||||
$cmd = trim(co::fread(STDIN));
|
||||
if (self::executeCommand($cmd) === false) break;
|
||||
global $terminal_id;
|
||||
global $port;
|
||||
$port = ZMBuf::globals("port");
|
||||
$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;
|
||||
case 'save':
|
||||
$origin = ZMBuf::$atomics["info_level"]->get();
|
||||
ZMBuf::$atomics["info_level"]->set(3);
|
||||
//ZMBuf::$atomics["info_level"]->set(3);
|
||||
DataProvider::saveBuffer();
|
||||
ZMBuf::$atomics["info_level"]->set($origin);
|
||||
//ZMBuf::$atomics["info_level"]->set($origin);
|
||||
return true;
|
||||
case '':
|
||||
return true;
|
||||
default:
|
||||
Console::info("Command not found: " . $it[0]);
|
||||
Console::info("Command not found: " . $cmd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
namespace Framework;
|
||||
|
||||
|
||||
use ZM\Annotation\Swoole\OnSave;
|
||||
|
||||
class DataProvider
|
||||
{
|
||||
public static $buffer_list = [];
|
||||
@@ -40,6 +42,13 @@ class DataProvider
|
||||
Console::debug("Saving " . $k . " to " . $v);
|
||||
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)
|
||||
echo Console::setColor("saved", "blue") . PHP_EOL;
|
||||
}
|
||||
@@ -53,7 +62,7 @@ class DataProvider
|
||||
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);
|
||||
if (!is_dir(self::getDataConfig() . $pathinfo["dirname"])) {
|
||||
Console::debug("Making Directory: " . self::getDataConfig() . $pathinfo["dirname"]);
|
||||
|
||||
@@ -39,7 +39,8 @@ class FrameworkLoader
|
||||
public function __construct($args = []) {
|
||||
if (self::$instance !== null) die("Cannot run two FrameworkLoader in one process!");
|
||||
self::$instance = $this;
|
||||
self::$argv = $args;
|
||||
|
||||
|
||||
$this->requireGlobalFunctions();
|
||||
if (!isPharMode()) {
|
||||
define('WORKING_DIR', getcwd());
|
||||
@@ -47,7 +48,15 @@ class FrameworkLoader
|
||||
echo "Phar mode: " . WORKING_DIR . PHP_EOL;
|
||||
}
|
||||
$this->registerAutoloader('classLoader');
|
||||
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
|
||||
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);
|
||||
}
|
||||
self::$settings = new GlobalConfig();
|
||||
ZMBuf::$globals = self::$settings;
|
||||
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)
|
||||
);
|
||||
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();
|
||||
} catch (Exception $e) {
|
||||
Console::error("Framework初始化出现错误,请检查!");
|
||||
@@ -126,12 +141,15 @@ class FrameworkLoader
|
||||
define("ZM_MATCH_FIRST", 1);
|
||||
define("ZM_MATCH_NUMBER", 2);
|
||||
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() {
|
||||
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("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 (substr(PHP_VERSION, 0, 1) != "7") die("PHP >=7 required.\n");
|
||||
//if (!function_exists("curl_exec")) die("Can not find curl extension.\n");
|
||||
@@ -160,5 +178,6 @@ $motd = <<<EOL
|
||||
/ /_| | | | (_| | | | | | | (_| | (_) |
|
||||
/____|_| |_|\__,_|_| |_| |_|\__,_|\___/
|
||||
|
||||
|
||||
EOL;
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
namespace Framework;
|
||||
|
||||
use Swoole\Atomic;
|
||||
use Swoole\Database\PDOPool;
|
||||
use swoole_atomic;
|
||||
use ZM\connection\WSConnection;
|
||||
use ZM\Utils\SQLPool;
|
||||
|
||||
class ZMBuf
|
||||
{
|
||||
@@ -24,7 +24,7 @@ class ZMBuf
|
||||
static $scheduler = null; //This is stupid warning...
|
||||
|
||||
//Swoole SQL连接池,多进程下每个进程一个连接池
|
||||
/** @var SQLPool */
|
||||
/** @var PDOPool */
|
||||
static $sql_pool = null;//保存sql连接池的类
|
||||
|
||||
//只读的数据,可以在多worker_num下使用
|
||||
@@ -51,6 +51,7 @@ class ZMBuf
|
||||
public static $config = [];
|
||||
public static $context = [];
|
||||
public static $instance = [];
|
||||
public static $context_class = [];
|
||||
|
||||
static function get($name, $default = null) {
|
||||
return self::$cache[$name] ?? $default;
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
use Framework\Console;
|
||||
use Framework\DataProvider;
|
||||
use Framework\ZMBuf;
|
||||
use Swoole\Coroutine\System;
|
||||
use ZM\Context\ContextInterface;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
function isPharMode() {
|
||||
return substr(__DIR__, 0, 7) == 'phar://';
|
||||
@@ -162,10 +164,10 @@ function matchArgs($pattern, $context) {
|
||||
function set_coroutine_params($array) {
|
||||
$cid = Co::getCid();
|
||||
if ($cid == -1) die("Cannot set coroutine params at none coroutine mode.");
|
||||
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;
|
||||
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
|
||||
*/
|
||||
function context() {
|
||||
return ctx();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContextInterface|null
|
||||
*/
|
||||
function ctx() {
|
||||
$cid = Co::getCid();
|
||||
$c_class = ZMBuf::globals("context_class");
|
||||
if (isset(ZMBuf::$context[$cid])) {
|
||||
return new $c_class($cid);
|
||||
return ZMBuf::$context_class[$cid] ?? (ZMBuf::$context_class[$cid] = new $c_class($cid));
|
||||
} else {
|
||||
Console::debug("未找到当前协程的上下文($cid),正在找父进程的上下文");
|
||||
while (($pcid = Co::getPcid($cid)) !== -1) {
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
function ctx() { return context(); }
|
||||
function debug($msg) { Console::debug($msg); }
|
||||
|
||||
function debug($msg) {
|
||||
if (ZMBuf::$atomics["info_level"]->get() >= 4)
|
||||
Console::log(date("[H:i:s] ") . "[D] " . $msg, 'gray');
|
||||
function zm_sleep($s = 1) { Co::sleep($s); }
|
||||
|
||||
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";
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user