mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-20 23:25:35 +08:00
initial commit
This commit is contained in:
212
src/Framework/Console.php
Executable file
212
src/Framework/Console.php
Executable file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/2/10
|
||||
* Time: 下午6:13
|
||||
*/
|
||||
|
||||
namespace Framework;
|
||||
|
||||
use co;
|
||||
use ZM\Utils\ZMUtil;
|
||||
use Exception;
|
||||
|
||||
class Console
|
||||
{
|
||||
static function setColor($string, $color = "") {
|
||||
switch ($color) {
|
||||
case "red":
|
||||
return "\x1b[38;5;203m" . $string . "\x1b[m";
|
||||
case "green":
|
||||
return "\x1b[38;5;83m" . $string . "\x1b[m";
|
||||
case "yellow":
|
||||
return "\x1b[38;5;227m" . $string . "\x1b[m";
|
||||
case "blue":
|
||||
return "\033[34m" . $string . "\033[0m";
|
||||
case "lightpurple":
|
||||
return "\x1b[38;5;207m" . $string . "\x1b[m";
|
||||
case "lightblue":
|
||||
return "\x1b[38;5;87m" . $string . "\x1b[m";
|
||||
case "gold":
|
||||
return "\x1b[38;5;214m" . $string . "\x1b[m";
|
||||
case "gray":
|
||||
return "\x1b[38;5;59m" . $string . "\x1b[m";
|
||||
case "pink":
|
||||
return "\x1b[38;5;207m" . $string . "\x1b[m";
|
||||
case "lightlightblue":
|
||||
return "\x1b[38;5;63m" . $string . "\x1b[m";
|
||||
default:
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
static function error($obj, $head = null) {
|
||||
if ($head === null) $head = date("[H:i:s ") . "ERROR] ";
|
||||
if (ZMBuf::$info_level !== null && in_array(ZMBuf::$info_level->get(), [1, 2])) {
|
||||
$trace = debug_backtrace()[1] ?? ['file' => '', 'function' => ''];
|
||||
$trace = "[" . basename($trace["file"], ".php") . ":" . $trace["function"] . "] ";
|
||||
}
|
||||
if (!is_string($obj)) {
|
||||
if (isset($trace)) {
|
||||
var_dump($obj);
|
||||
return;
|
||||
} else $obj = "{Object}";
|
||||
}
|
||||
echo(self::setColor($head . ($trace ?? "") . $obj, "red") . "\n");
|
||||
}
|
||||
|
||||
static function warning($obj, $head = null) {
|
||||
if ($head === null) $head = date("[H:i:s") . " WARN] ";
|
||||
if (ZMBuf::$info_level !== null && in_array(ZMBuf::$info_level->get(), [1, 2])) {
|
||||
$trace = debug_backtrace()[1] ?? ['file' => '', 'function' => ''];
|
||||
$trace = "[" . basename($trace["file"], ".php") . ":" . $trace["function"] . "] ";
|
||||
}
|
||||
if (!is_string($obj)) {
|
||||
if (isset($trace)) {
|
||||
var_dump($obj);
|
||||
return;
|
||||
} else $obj = "{Object}";
|
||||
}
|
||||
echo(self::setColor($head . ($trace ?? "") . $obj, "yellow") . "\n");
|
||||
}
|
||||
|
||||
static function info($obj, $head = null) {
|
||||
if ($head === null) $head = date("[H:i:s ") . "INFO] ";
|
||||
if (ZMBuf::$info_level !== null && in_array(ZMBuf::$info_level->get(), [1, 2])) {
|
||||
$trace = debug_backtrace()[1] ?? ['file' => '', 'function' => ''];
|
||||
$trace = "[" . basename($trace["file"], ".php") . ":" . $trace["function"] . "] ";
|
||||
}
|
||||
if (!is_string($obj)) {
|
||||
if (isset($trace)) {
|
||||
var_dump($obj);
|
||||
return;
|
||||
} else $obj = "{Object}";
|
||||
}
|
||||
echo(self::setColor($head . ($trace ?? "") . $obj, "lightblue") . "\n");
|
||||
}
|
||||
|
||||
static function log($obj, $color = "") {
|
||||
if (!is_string($obj)) var_dump($obj);
|
||||
else echo(self::setColor($obj, $color) . "\n");
|
||||
}
|
||||
|
||||
static function msg($obj, $self_id = "") {
|
||||
if (ZMBuf::$info_level !== null && ZMBuf::$info_level->get() == 3) {
|
||||
if (!isset($obj["post_type"])) {
|
||||
switch ($obj["action"]) {
|
||||
case "send_private_msg":
|
||||
$msg = Console::setColor(date("H:i:s ") . "[" . (ZMBuf::globals("robot_alias")[$self_id] ?? "Null") . "] ", "lightlightblue");
|
||||
$msg .= Console::setColor("私聊↑(" . $obj["params"]["user_id"] . ")", "lightlightblue");
|
||||
$msg .= Console::setColor(" > ", "gray");
|
||||
$msg .= $obj["params"]["message"];
|
||||
Console::log($msg);
|
||||
break;
|
||||
case "send_group_msg":
|
||||
//TODO: 写新的控制台消息(API消息处理)
|
||||
Console::log(Console::setColor("[" . date("H:i:s") . " GROUP:" . $obj["params"]["group_id"] . "] ", "blue") . Console::setColor($obj["params"]["user_id"] ?? "", "yellow") . Console::setColor(" > ", "gray") . ($obj["params"]["message"] ?? ""));
|
||||
break;
|
||||
case "send_discuss_msg":
|
||||
Console::log(Console::setColor("[" . date("H:i:s") . " DISCUSS:" . $obj["params"]["discuss_id"] . "] ", "blue") . Console::setColor($obj["params"]["user_id"] ?? "", "yellow") . Console::setColor(" > ", "gray") . ($obj["params"]["message"] ?? ""));
|
||||
break;
|
||||
case "send_msg":
|
||||
$obj["action"] = "send_" . $obj["message_type"] . "_msg";
|
||||
self::msg($obj);
|
||||
break;
|
||||
case "send_wechat_msg":
|
||||
Console::log(Console::setColor("[" . date("H:i:s") . " WECHAT] ", "blue") . Console::setColor($obj["params"]["user_id"] ?? "", "yellow") . Console::setColor(" > ", "gray") . ($obj["params"]["message"] ?? ""));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ($obj["post_type"] == "message") {
|
||||
switch ($obj["message_type"]) {
|
||||
case "group":
|
||||
//
|
||||
//TODO: 写新的控制台消息(event处理)
|
||||
case "private":
|
||||
case "discuss":
|
||||
case "wechat":
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function stackTrace(){
|
||||
$log = "Stack trace:\n";
|
||||
$trace = debug_backtrace();
|
||||
//array_shift($trace);
|
||||
foreach ($trace as $i => $t) {
|
||||
if (!isset($t['file'])) {
|
||||
$t['file'] = 'unknown';
|
||||
}
|
||||
if (!isset($t['line'])) {
|
||||
$t['line'] = 0;
|
||||
}
|
||||
if (!isset($t['function'])) {
|
||||
$t['function'] = 'unknown';
|
||||
}
|
||||
$log .= "#$i {$t['file']}({$t['line']}): ";
|
||||
if (isset($t['object']) and is_object($t['object'])) {
|
||||
$log .= get_class($t['object']) . '->';
|
||||
}
|
||||
$log .= "{$t['function']}()\n";
|
||||
}
|
||||
$log = Console::setColor($log, "gray");
|
||||
echo $log;
|
||||
}
|
||||
|
||||
static function listenConsole(){
|
||||
go(function () {
|
||||
while (true) {
|
||||
$cmd = trim(co::fread(STDIN));
|
||||
if (self::executeCommand($cmd) === false) break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cmd
|
||||
* @return bool
|
||||
*/
|
||||
private static function executeCommand(string $cmd) {
|
||||
$it = explodeMsg($cmd);
|
||||
switch ($it[0] ?? '') {
|
||||
case 'call':
|
||||
$class_name = $it[1];
|
||||
$function_name = $it[2];
|
||||
$class = new $class_name([]);
|
||||
call_user_func_array([$class, $function_name],[]);
|
||||
return true;
|
||||
case 'bc':
|
||||
$code = base64_decode($it[1] ?? '', true);
|
||||
try {
|
||||
eval($code);
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
return true;
|
||||
case 'echo':
|
||||
Console::info($it[1]);
|
||||
return true;
|
||||
case 'stop':
|
||||
ZMUtil::stop();
|
||||
return false;
|
||||
case 'reload':
|
||||
case 'r':
|
||||
ZMUtil::reload();
|
||||
return false;
|
||||
case '':
|
||||
return true;
|
||||
default:
|
||||
Console::info("Command not found: " . $it[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static function withSleep(string $string, int $int) {
|
||||
self::info($string);
|
||||
sleep($int);
|
||||
}
|
||||
}
|
||||
106
src/Framework/FrameworkLoader.php
Normal file
106
src/Framework/FrameworkLoader.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Framework;
|
||||
|
||||
use ZM\Event\EventHandler;
|
||||
use Exception;
|
||||
use Swoole\WebSocket\Server;
|
||||
use ZM\Http\Response;
|
||||
|
||||
/**
|
||||
* Class FrameworkLoader
|
||||
* Everything is beginning from here
|
||||
* @package Framework
|
||||
*/
|
||||
class FrameworkLoader
|
||||
{
|
||||
/** @var GlobalConfig */
|
||||
public static $settings;
|
||||
|
||||
/** @var FrameworkLoader|null */
|
||||
public static $instance = null;
|
||||
|
||||
/** @var float|string */
|
||||
public static $run_time;
|
||||
|
||||
/** @var Server */
|
||||
private $server;
|
||||
|
||||
public function __construct($args = []) {
|
||||
if (self::$instance !== null) die("Cannot run two FrameworkLoader in one process!");
|
||||
self::$instance = $this;
|
||||
|
||||
chdir(__DIR__ . '/../..');
|
||||
define('WORKING_DIR', getcwd());
|
||||
$this->requireGlobalFunctions();
|
||||
$this->registerAutoloader('classLoader');
|
||||
self::$settings = new GlobalConfig();
|
||||
ZMBuf::$globals = self::$settings;
|
||||
if (!self::$settings->success) die("Failed to load global config. Please check config/global.php file");
|
||||
$this->defineProperties();
|
||||
|
||||
//start swoole Framework
|
||||
$this->selfCheck();
|
||||
try {
|
||||
$this->server = new Server(self::$settings->get("host"), self::$settings->get("port"));
|
||||
if (in_array("--remote-shell", $args)) RemoteShell::listen($this->server, "127.0.0.1");
|
||||
$this->server->set(self::$settings->get("swoole"));
|
||||
$this->server->on("WorkerStart", [$this, "onWorkerStart"]);
|
||||
$this->server->on("message", function ($server, $frame) { EventHandler::callSwooleEvent("message", $server, $frame); });
|
||||
$this->server->on("request", function ($request, $response) {
|
||||
$response = new Response($response);
|
||||
EventHandler::callSwooleEvent("request", $request, $response);
|
||||
});
|
||||
$this->server->on("open", function ($server, $request) { EventHandler::callSwooleEvent("open", $server, $request); });
|
||||
$this->server->on("close", function ($server, $fd) { EventHandler::callSwooleEvent("close", $server, $fd); });
|
||||
ZMBuf::initAtomic();
|
||||
Console::info("host: ".self::$settings->get("host").", port: ".self::$settings->get("port"));
|
||||
$this->server->start();
|
||||
} catch (Exception $e) {
|
||||
Console::error("Framework初始化出现错误,请检查!");
|
||||
Console::error($e->getMessage());
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
private function requireGlobalFunctions() {
|
||||
require __DIR__ . '/global_functions.php';
|
||||
}
|
||||
|
||||
private function registerAutoloader(string $string) {
|
||||
if (!spl_autoload_register($string)) die("Failed to register autoloader named \"$string\" !");
|
||||
}
|
||||
|
||||
private function defineProperties() {
|
||||
define("ZM_START_TIME", microtime(true));
|
||||
define("ZM_DATA", self::$settings->get("zm_data"));
|
||||
define("CONFIG_DIR", self::$settings->get("config_dir"));
|
||||
define("CRASH_DIR", self::$settings->get("crash_dir"));
|
||||
@mkdir(ZM_DATA);
|
||||
@mkdir(CONFIG_DIR);
|
||||
@mkdir(CRASH_DIR);
|
||||
define("ZM_MATCH_ALL", 0);
|
||||
define("ZM_MATCH_FIRST", 1);
|
||||
define("ZM_MATCH_NUMBER", 2);
|
||||
define("ZM_MATCH_SECOND", 3);
|
||||
}
|
||||
|
||||
private function selfCheck() {
|
||||
if (!extension_loaded("swoole")) die("Can not find swoole 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 (!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");
|
||||
//if (!class_exists("ZipArchive")) die("Can not find Zip extension.\n");
|
||||
//if (!file_exists(CRASH_DIR . "last_error.log")) die("Can not find log file.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onWorkerStart(\Swoole\Server $server, $worker_id) {
|
||||
self::$instance = $this;
|
||||
self::$run_time = microtime(true);
|
||||
EventHandler::callSwooleEvent("WorkerStart", $server, $worker_id);
|
||||
}
|
||||
}
|
||||
33
src/Framework/GlobalConfig.php
Normal file
33
src/Framework/GlobalConfig.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2019-03-16
|
||||
* Time: 13:58
|
||||
*/
|
||||
|
||||
namespace Framework;
|
||||
|
||||
/**
|
||||
* 请不要diss此class的语法。可能写的很糟糕。
|
||||
* Class GlobalConfig
|
||||
*/
|
||||
class GlobalConfig
|
||||
{
|
||||
private $config = null;
|
||||
public $success = false;
|
||||
|
||||
public function __construct() {
|
||||
/** @noinspection PhpIncludeInspection */
|
||||
include_once WORKING_DIR.'/config/global.php';
|
||||
global $config;
|
||||
$this->success = true;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function get($key) {
|
||||
$r = $this->config[$key] ?? null;
|
||||
if ($r === null) return null;
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
10
src/Framework/InfoLevel.php
Normal file
10
src/Framework/InfoLevel.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Framework;
|
||||
|
||||
|
||||
class InfoLevel
|
||||
{
|
||||
const INFO = 0;
|
||||
}
|
||||
18
src/Framework/Logger.php
Normal file
18
src/Framework/Logger.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Framework;
|
||||
|
||||
|
||||
use Swoole\Coroutine\System;
|
||||
|
||||
class Logger
|
||||
{
|
||||
private static function getTimeFormat($type = "I") {
|
||||
return "[" . date("Y-m-d H:i:s") . "]\t[" . $type . "]\t";
|
||||
}
|
||||
|
||||
public static function writeSwooleLog($log) {
|
||||
System::writeFile(CRASH_DIR . "swoole_error.log", "\n" . self::getTimeFormat() . $log, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
264
src/Framework/RemoteShell.php
Normal file
264
src/Framework/RemoteShell.php
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Framework;
|
||||
|
||||
|
||||
use Co;
|
||||
use Exception;
|
||||
use Swoole\Coroutine;
|
||||
use swoole\server;
|
||||
|
||||
class RemoteShell
|
||||
{
|
||||
const STX = "DEBUG";
|
||||
private static $contexts = array();
|
||||
static $oriPipeMessageCallback = null;
|
||||
/**
|
||||
* @var server
|
||||
*/
|
||||
static $serv;
|
||||
static $menu = array(
|
||||
"p|print [variant]\t打印一个PHP变量的值",
|
||||
"e|exec [code]\t执行一段PHP代码",
|
||||
"w|worker [id]\t切换Worker进程",
|
||||
"l|list\t打印服务器所有连接的fd",
|
||||
"s|stats\t打印服务器状态",
|
||||
"c|coros\t打印协程列表",
|
||||
"b|bt\t打印协程调用栈",
|
||||
"i|info [fd]\t显示某个连接的信息",
|
||||
"h|help\t显示帮助界面",
|
||||
"q|quit\t退出终端",
|
||||
);
|
||||
const PAGESIZE = 20;
|
||||
|
||||
/**
|
||||
* @param $serv server
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @throws Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
static function listen($serv, $host = "127.0.0.1", $port = 9599) {
|
||||
Console::warning("正在监听".$host.":".strval($port)."的调试接口,请注意安全");
|
||||
$port = $serv->listen($host, $port, SWOOLE_SOCK_TCP);
|
||||
if (!$port) {
|
||||
throw new Exception("listen fail.");
|
||||
}
|
||||
$port->set(array(
|
||||
"open_eof_split" => true,
|
||||
'package_eof' => "\r\n",
|
||||
));
|
||||
$port->on("Connect", array(__CLASS__, 'onConnect'));
|
||||
$port->on("Close", array(__CLASS__, 'onClose'));
|
||||
$port->on("Receive", array(__CLASS__, 'onReceive'));
|
||||
if (method_exists($serv, 'getCallback')) {
|
||||
self::$oriPipeMessageCallback = $serv->getCallback('PipeMessage');
|
||||
}
|
||||
$serv->on("PipeMessage", array(__CLASS__, 'onPipeMessage'));
|
||||
self::$serv = $serv;
|
||||
}
|
||||
|
||||
static function onConnect($serv, $fd, $reactor_id) {
|
||||
self::$contexts[$fd]['worker_id'] = $serv->worker_id;
|
||||
self::output($fd, implode("\r\n", self::$menu));
|
||||
}
|
||||
|
||||
static function output($fd, $msg) {
|
||||
if (!isset(self::$contexts[$fd]['worker_id'])) {
|
||||
$msg .= "\r\nworker#" . self::$serv->worker_id . "$ ";
|
||||
} else {
|
||||
$msg .= "\r\nworker#" . self::$contexts[$fd]['worker_id'] . "$ ";
|
||||
}
|
||||
self::$serv->send($fd, $msg);
|
||||
}
|
||||
|
||||
static function onClose($serv, $fd, $reactor_id) {
|
||||
unset(self::$contexts[$fd]);
|
||||
}
|
||||
|
||||
static function onPipeMessage($serv, $src_worker_id, $message) {
|
||||
//不是 debug 消息
|
||||
if (!is_string($message) or substr($message, 0, strlen(self::STX)) != self::STX) {
|
||||
if (self::$oriPipeMessageCallback == null) {
|
||||
trigger_error("require swoole-4.3.0 or later.", E_USER_WARNING);
|
||||
return true;
|
||||
}
|
||||
return call_user_func(self::$oriPipeMessageCallback, $serv, $src_worker_id, $message);
|
||||
} else {
|
||||
$request = unserialize(substr($message, strlen(self::STX)));
|
||||
self::call($request['fd'], $request['func'], $request['args']);
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
static protected function call($fd, $func, $args) {
|
||||
ob_start();
|
||||
call_user_func_array($func, $args);
|
||||
self::output($fd, ob_get_clean());
|
||||
}
|
||||
|
||||
static protected function exec($fd, $func, $args) {
|
||||
//不在当前Worker进程
|
||||
if (self::$contexts[$fd]['worker_id'] != self::$serv->worker_id) {
|
||||
self::$serv->sendMessage(self::STX . serialize(['fd' => $fd, 'func' => $func, 'args' => $args]), self::$contexts[$fd]['worker_id']);
|
||||
} else {
|
||||
self::call($fd, $func, $args);
|
||||
}
|
||||
}
|
||||
|
||||
static function getCoros() {
|
||||
var_export(iterator_to_array(Coroutine::listCoroutines()));
|
||||
}
|
||||
|
||||
static function getBackTrace($_cid) {
|
||||
$info = Co::getBackTrace($_cid);
|
||||
if (!$info) {
|
||||
echo "coroutine $_cid not found.";
|
||||
} else {
|
||||
echo get_debug_print_backtrace($info);
|
||||
}
|
||||
}
|
||||
|
||||
static function printVariant($var) {
|
||||
$var = ltrim($var, '$ ');
|
||||
var_dump($var);
|
||||
var_dump($$var);
|
||||
}
|
||||
|
||||
static function evalCode($code) {
|
||||
eval($code . ';');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $serv server
|
||||
* @param $fd
|
||||
* @param $reactor_id
|
||||
* @param $data
|
||||
*/
|
||||
static function onReceive($serv, $fd, $reactor_id, $data) {
|
||||
$args = explode(" ", $data, 2);
|
||||
$cmd = trim($args[0]);
|
||||
unset($args[0]);
|
||||
switch ($cmd) {
|
||||
case 'w':
|
||||
case 'worker':
|
||||
if (!isset($args[1])) {
|
||||
self::output($fd, "invalid command.");
|
||||
break;
|
||||
}
|
||||
$dstWorkerId = intval($args[1]);
|
||||
self::$contexts[$fd]['worker_id'] = $dstWorkerId;
|
||||
self::output($fd, "[switching to worker " . self::$contexts[$fd]['worker_id'] . "]");
|
||||
break;
|
||||
case 'e':
|
||||
case 'exec':
|
||||
if (!isset($args[1])) {
|
||||
self::output($fd, "invalid command.");
|
||||
break;
|
||||
}
|
||||
$var = trim($args[1]);
|
||||
self::exec($fd, 'self::evalCode', [$var]);
|
||||
break;
|
||||
case 'p':
|
||||
case 'print':
|
||||
$var = trim($args[1]);
|
||||
self::exec($fd, 'self::printVariant', [$var]);
|
||||
break;
|
||||
case 'h':
|
||||
case 'help':
|
||||
self::output($fd, implode("\r\n", self::$menu));
|
||||
break;
|
||||
case 's':
|
||||
case 'stats':
|
||||
$stats = $serv->stats();
|
||||
self::output($fd, var_export($stats, true));
|
||||
break;
|
||||
case 'c':
|
||||
case 'coros':
|
||||
self::exec($fd, 'self::getCoros', []);
|
||||
break;
|
||||
/**
|
||||
* 查看协程堆栈
|
||||
*/
|
||||
case 'bt':
|
||||
case 'b':
|
||||
case 'backtrace':
|
||||
if (empty($args[1])) {
|
||||
self::output($fd, "invalid command [" . trim($args[1]) . "].");
|
||||
break;
|
||||
}
|
||||
$_cid = intval($args[1]);
|
||||
self::exec($fd, 'self::getBackTrace', [$_cid]);
|
||||
break;
|
||||
case 'i':
|
||||
case 'info':
|
||||
if (empty($args[1])) {
|
||||
self::output($fd, "invalid command [" . trim($args[1]) . "].");
|
||||
break;
|
||||
}
|
||||
$_fd = intval($args[1]);
|
||||
$info = $serv->getClientInfo($_fd);
|
||||
if (!$info) {
|
||||
self::output($fd, "connection $_fd not found.");
|
||||
} else {
|
||||
self::output($fd, var_export($info, true));
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
case 'list':
|
||||
$tmp = array();
|
||||
foreach ($serv->connections as $fd) {
|
||||
$tmp[] = $fd;
|
||||
if (count($tmp) > self::PAGESIZE) {
|
||||
self::output($fd, json_encode($tmp));
|
||||
$tmp = array();
|
||||
}
|
||||
}
|
||||
if (count($tmp) > 0) {
|
||||
self::output($fd, json_encode($tmp));
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
case 'quit':
|
||||
$serv->close($fd);
|
||||
break;
|
||||
default:
|
||||
self::output($fd, "unknow command[$cmd]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function get_debug_print_backtrace($traces) {
|
||||
$ret = array();
|
||||
foreach ($traces as $i => $call) {
|
||||
$object = '';
|
||||
if (isset($call['class'])) {
|
||||
$object = $call['class'] . $call['type'];
|
||||
if (is_array($call['args'])) {
|
||||
foreach ($call['args'] as &$arg) {
|
||||
get_arg($arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
$ret[] = '#' . str_pad($i, 3, ' ')
|
||||
. $object . $call['function'] . '(' . implode(', ', $call['args'])
|
||||
. ') called at [' . $call['file'] . ':' . $call['line'] . ']';
|
||||
}
|
||||
return implode("\n", $ret);
|
||||
}
|
||||
|
||||
function get_arg(&$arg) {
|
||||
if (is_object($arg)) {
|
||||
$arr = (array)$arg;
|
||||
$args = array();
|
||||
foreach ($arr as $key => $value) {
|
||||
if (strpos($key, chr(0)) !== false) {
|
||||
$key = ''; // Private variable found
|
||||
}
|
||||
$args[] = '[' . $key . '] => ' . get_arg($value);
|
||||
}
|
||||
$arg = get_class($arg) . ' Object (' . implode(',', $args) . ')';
|
||||
}
|
||||
}
|
||||
95
src/Framework/ZMBuf.php
Executable file
95
src/Framework/ZMBuf.php
Executable file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/2/25
|
||||
* Time: 下午11:11
|
||||
*/
|
||||
|
||||
namespace Framework;
|
||||
|
||||
use Swoole\Atomic;
|
||||
use swoole_atomic;
|
||||
use ZM\Annotation\MappingNode;
|
||||
use ZM\connection\WSConnection;
|
||||
use ZM\Utils\Scheduler;
|
||||
use ZM\Utils\SQLPool;
|
||||
|
||||
class ZMBuf
|
||||
{
|
||||
//读写的缓存数据,需要在worker_num = 1下才能正常使用
|
||||
/** @var mixed[] ZMBuf的data */
|
||||
private static $cache = [];
|
||||
/** @var WSConnection[] */
|
||||
static $connect = [];//储存连接实例的数组
|
||||
//Scheduler计划任务连接实例,只可以在单worker_num时使用
|
||||
/** @var Scheduler|null */
|
||||
static $scheduler = null;
|
||||
|
||||
//Swoole SQL连接池,多进程下每个进程一个连接池
|
||||
/** @var SQLPool */
|
||||
static $sql_pool = null;//保存sql连接池的类
|
||||
|
||||
//只读的数据,可以在多worker_num下使用
|
||||
/** @var null|\Framework\GlobalConfig */
|
||||
static $globals = null;
|
||||
|
||||
// swoole server操作对象,每个进程均分配
|
||||
/** @var swoole_websocket_server $server */
|
||||
static $server;
|
||||
/** @var MappingNode Http请求uri路径根节点 */
|
||||
public static $req_mapping_node;
|
||||
/** @var mixed TimeNLP初始化后的对象,每个进程均可初始化 */
|
||||
public static $time_nlp;
|
||||
/** @var string[] $custom_connection_class */
|
||||
public static $custom_connection_class = [];//保存自定义的ws connection连接类型的
|
||||
|
||||
// Atomic:可跨进程读写的原子计数,任何地方均可使用
|
||||
/** @var null|swoole_atomic */
|
||||
static $info_level = null;//保存log等级的原子计数
|
||||
/** @var swoole_atomic $reload_time */
|
||||
|
||||
public static $events = [];
|
||||
/** @var Atomic[] */
|
||||
public static $atomics;
|
||||
|
||||
static function get($name, $default = null) { return self::$cache[$name] ?? $default; }
|
||||
|
||||
static function set($name, $value) { self::$cache[$name] = $value; }
|
||||
|
||||
static function append($name, $value) { self::$cache[$name][] = $value; }
|
||||
|
||||
static function appendKey($name, $key, $value) { self::$cache[$name][$key] = $value; }
|
||||
|
||||
static function appendKeyInKey($name, $key, $value) { self::$cache[$name][$key][] = $value; }
|
||||
|
||||
static function unsetCache($name) { unset(self::$cache[$name]); }
|
||||
|
||||
static function unsetByValue($name, $vale) {
|
||||
$key = array_search($vale, self::$cache[$name]);
|
||||
array_splice(self::$cache[$name], $key, 1);
|
||||
}
|
||||
|
||||
static function isset($name) { return isset(self::$cache[$name]); }
|
||||
|
||||
static function array_key_exists($name, $key) { return isset(self::$cache[$name][$key]); }
|
||||
|
||||
static function in_array($name, $val) { return in_array($val, self::$cache[$name]); }
|
||||
|
||||
static function globals($key) { return self::$globals->get($key); }
|
||||
|
||||
public static function resetCache() {
|
||||
self::$cache = [];
|
||||
self::$connect = [];
|
||||
self::$time_nlp = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化atomic计数器
|
||||
*/
|
||||
public static function initAtomic() {
|
||||
foreach(ZMBuf::globals("init_atomics") as $k => $v) {
|
||||
self::$atomics[$k] = new Atomic($v);
|
||||
}
|
||||
}
|
||||
}
|
||||
146
src/Framework/global_functions.php
Normal file
146
src/Framework/global_functions.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
function classLoader($p) {
|
||||
$filepath = getClassPath($p);
|
||||
if ($filepath === null)
|
||||
echo "F:Warning: get class path wrongs.$p\n";
|
||||
//else echo "F:DBG: Found " . $p . "\n";
|
||||
try {
|
||||
require_once $filepath;
|
||||
} catch (Exception $e) {
|
||||
echo "Error when finding class: ".$p.PHP_EOL;
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
function getClassPath($class_name) {
|
||||
$dir = str_replace("\\", "/", $class_name);
|
||||
$dir = WORKING_DIR . "/src/" . $dir . ".php";
|
||||
//echo "@@@".$dir.PHP_EOL;
|
||||
$dir = str_replace("\\", "/", $dir);
|
||||
if (file_exists($dir)) return $dir;
|
||||
else return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用自己定义的万(san)能分割函数
|
||||
* @param $msg
|
||||
* @param bool $ban_comma
|
||||
* @return array
|
||||
*/
|
||||
function explodeMsg($msg, $ban_comma = false) {
|
||||
$msg = str_replace(" ", "\n", trim($msg));
|
||||
if (!$ban_comma) {
|
||||
//$msg = str_replace(",", "\n", $msg);
|
||||
$msg = str_replace("\t", "\n", $msg);
|
||||
}
|
||||
$msgs = explode("\n", $msg);
|
||||
$ls = [];
|
||||
foreach ($msgs as $k => $v) {
|
||||
if (trim($v) == "") continue;
|
||||
$ls[] = trim($v);
|
||||
}
|
||||
return $ls;
|
||||
}
|
||||
|
||||
function unicode_decode($str) {
|
||||
return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function ($matches) {
|
||||
return mb_convert_encoding(pack("H*", $matches[1]), "UTF-8", "UCS-2BE");
|
||||
}, $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块文件夹下的每个类文件的类名称
|
||||
* @param $dir
|
||||
* @param string $indoor_name
|
||||
* @return array
|
||||
*/
|
||||
function getAllClasses($dir, $indoor_name) {
|
||||
$list = scandir($dir);
|
||||
$classes = [];
|
||||
unset($list[0], $list[1]);
|
||||
foreach ($list as $v) {
|
||||
//echo "Finding " . $dir . $v . PHP_EOL;
|
||||
//echo "At " . $indoor_name . PHP_EOL;
|
||||
if (is_dir($dir . $v)) $classes = array_merge($classes, getAllClasses($dir . $v . "/", $indoor_name . "\\" . $v));
|
||||
elseif (mb_substr($v, -4) == ".php") {
|
||||
$class_name = $indoor_name . "\\" . mb_substr($v, 0, -4);
|
||||
$classes [] = $class_name;
|
||||
}
|
||||
}
|
||||
return $classes;
|
||||
}
|
||||
|
||||
function matchPattern($pattern, $context) {
|
||||
if (mb_substr($pattern, 0, 1) == "" && mb_substr($context, 0, 1) == "")
|
||||
return true;
|
||||
if ('*' == mb_substr($pattern, 0, 1) && "" != mb_substr($pattern, 1, 1) && "" == mb_substr($context, 0, 1))
|
||||
return false;
|
||||
if (mb_substr($pattern, 0, 1) == mb_substr($context, 0, 1))
|
||||
return matchPattern(mb_substr($pattern, 1), mb_substr($context, 1));
|
||||
if (mb_substr($pattern, 0, 1) == "*")
|
||||
return matchPattern(mb_substr($pattern, 1), $context) || matchPattern($pattern, mb_substr($context, 1));
|
||||
return false;
|
||||
}
|
||||
|
||||
function split_explode($del, $str, $divide_en = false) {
|
||||
$str = explode($del, $str);
|
||||
for ($i = 0; $i < mb_strlen($str[0]); $i++) {
|
||||
if (
|
||||
is_numeric(mb_substr($str[0], $i, 1)) &&
|
||||
(
|
||||
!is_numeric(mb_substr($str[0], $i - 1, 1)) &&
|
||||
mb_substr($str[0], $i - 1, 1) != ' ' &&
|
||||
ctype_alpha(mb_substr($str[0], $i - 1, 1)) === false
|
||||
)
|
||||
) {
|
||||
$str[0] = mb_substr($str[0], 0, $i) . " " . mb_substr($str[0], $i);
|
||||
} elseif (
|
||||
$divide_en &&
|
||||
ctype_alnum(mb_substr($str[0], $i, 1)) &&
|
||||
!ctype_alnum(mb_substr($str[0], $i - 1, 1)) &&
|
||||
mb_substr($str[0], $i - 1, 1) != ' '
|
||||
) {
|
||||
$str[0] = mb_substr($str[0], 0, $i) . ' ' . mb_substr($str[0], $i);
|
||||
}
|
||||
}
|
||||
$str = implode($del, $str);
|
||||
//echo $str."\n";
|
||||
$ls = [];
|
||||
foreach (explode($del, $str) as $k => $v) {
|
||||
if (trim($v) == "") continue;
|
||||
$ls[] = $v;
|
||||
}
|
||||
//var_dump($ls);
|
||||
return $ls == [] ? [""] : $ls;
|
||||
}
|
||||
|
||||
function matchArgs($pattern, $context) {
|
||||
$result = [];
|
||||
if (matchPattern($pattern, $context)) {
|
||||
if (mb_strpos($pattern, "*") === false) return [];
|
||||
$exp = explode("*", $pattern);
|
||||
$i = 0;
|
||||
foreach ($exp as $k => $v) {
|
||||
//echo "[MATCH$k] " . $v . PHP_EOL;
|
||||
if ($v == "" && $k == 0) continue;
|
||||
elseif ($v == "" && $k == count($exp) - 1) {
|
||||
$context = $context . "^EOL";
|
||||
$v = "^EOL";
|
||||
}
|
||||
$cur_var = "";
|
||||
//echo mb_substr($context, $i) . "|" . $v . PHP_EOL;
|
||||
$ori = $i;
|
||||
while (($a = mb_substr($context, $i, mb_strlen($v))) != $v && $a != "") {
|
||||
$cur_var .= mb_substr($context, $i, 1);
|
||||
++$i;
|
||||
}
|
||||
if ($i != $ori || $k == 1 || $k == count($exp) - 1) {
|
||||
//echo $cur_var . PHP_EOL;
|
||||
$result[] = $cur_var;
|
||||
}
|
||||
$i += mb_strlen($v);
|
||||
}
|
||||
return $result;
|
||||
} else return false;
|
||||
}
|
||||
Reference in New Issue
Block a user