mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-03-17 20:54:52 +08:00
initial 2.0.0-a3 commit
This commit is contained in:
parent
f91d24aaaa
commit
da584e0542
@ -31,7 +31,7 @@
|
||||
"symfony/console": "^5.1",
|
||||
"symfony/polyfill-ctype": "^1.18",
|
||||
"zhamao/connection-manager": "^1.0",
|
||||
"zhamao/console": "^1.0",
|
||||
"zhamao/console": "*@dev",
|
||||
"zhamao/config": "^1.0",
|
||||
"zhamao/request": "^1.0",
|
||||
"symfony/routing": "^5.1"
|
||||
@ -61,5 +61,11 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.3"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "/Users/jerry/project/git-project/zhamao-console"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
<?php
|
||||
/** @noinspection PhpFullyQualifiedNameUsageInspection */
|
||||
/** @noinspection PhpComposerExtensionStubsInspection */
|
||||
global $config;
|
||||
|
||||
/** bind host */
|
||||
@ -25,7 +27,7 @@ $config['crash_dir'] = $config['zm_data'] . 'crash/';
|
||||
/** 对应swoole的server->set参数 */
|
||||
$config['swoole'] = [
|
||||
'log_file' => $config['crash_dir'] . 'swoole_error.log',
|
||||
'worker_num' => 2,
|
||||
'worker_num' => 8,
|
||||
'dispatch_mode' => 2,
|
||||
'max_coroutine' => 30000,
|
||||
//'task_worker_num' => 4,
|
||||
@ -37,7 +39,8 @@ $config['light_cache'] = [
|
||||
"status" => true,
|
||||
"size" => 2048, //最多允许储存的条数(需要2的倍数)
|
||||
"max_strlen" => 4096, //单行字符串最大长度(需要2的倍数)
|
||||
"hash_conflict_proportion" => 0.6 //Hash冲突率(越大越好,但是需要的内存更多)
|
||||
"hash_conflict_proportion" => 0.6, //Hash冲突率(越大越好,但是需要的内存更多)
|
||||
"persistence_path" => $config['zm_data']."_cache.json"
|
||||
];
|
||||
|
||||
/** MySQL数据库连接信息,host留空则启动时不创建sql连接池 */
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Module\Example;
|
||||
|
||||
use ZM\Annotation\Swoole\OnStart;
|
||||
use ZM\Annotation\Swoole\OnWorkerStart;
|
||||
use ZM\Annotation\Swoole\OnTick;
|
||||
use ZM\ConnectionManager\ConnectionObject;
|
||||
use ZM\Console\Console;
|
||||
@ -10,6 +10,8 @@ use ZM\Annotation\CQ\CQCommand;
|
||||
use ZM\Annotation\Http\Middleware;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Annotation\Swoole\SwooleEvent;
|
||||
use ZM\Store\LightCache;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
/**
|
||||
@ -72,9 +74,9 @@ class Hello
|
||||
/**
|
||||
* 中间件测试的一个示例函数
|
||||
* @RequestMapping("/httpTimer")
|
||||
* @Middleware("timer")
|
||||
*/
|
||||
public function timer() {
|
||||
ZMBuf::atomic("_tmp_2")->add(1);
|
||||
return "This page is used as testing TimerMiddleware! Do not use it in production.";
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ use Co;
|
||||
use ZM\ConnectionManager\ConnectionObject;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Event\EventHandler;
|
||||
use ZM\Store\LightCache;
|
||||
use ZM\Store\ZMBuf;
|
||||
|
||||
trait CQAPI
|
||||
@ -26,27 +27,20 @@ trait CQAPI
|
||||
|
||||
}
|
||||
|
||||
public function processWebsocketAPI($connection, $reply, $function = null) {
|
||||
public function processWebsocketAPI($connection, $reply, $function = false) {
|
||||
$api_id = ZMBuf::atomic("wait_msg_id")->get();
|
||||
$reply["echo"] = $api_id;
|
||||
ZMBuf::atomic("wait_msg_id")->add(1);
|
||||
EventHandler::callCQAPISend($reply, $connection);
|
||||
if (is_callable($function)) {
|
||||
ZMBuf::appendKey("sent_api", $api_id, [
|
||||
"data" => $reply,
|
||||
"time" => microtime(true),
|
||||
"func" => $function,
|
||||
"self_id" => $connection->getOption("connect_id")
|
||||
]);
|
||||
} elseif ($function === true) {
|
||||
ZMBuf::appendKey("sent_api", $api_id, [
|
||||
if ($function === true) {
|
||||
LightCache::set("sent_api_".$api_id, [
|
||||
"data" => $reply,
|
||||
"time" => microtime(true),
|
||||
"coroutine" => Co::getuid(),
|
||||
"self_id" => $connection->getOption("connect_id")
|
||||
]);
|
||||
} else {
|
||||
ZMBuf::appendKey("sent_api", $api_id, [
|
||||
LightCache::set("sent_api_".$api_id, [
|
||||
"data" => $reply,
|
||||
"time" => microtime(true),
|
||||
"self_id" => $connection->getOption("connect_id")
|
||||
@ -56,8 +50,8 @@ trait CQAPI
|
||||
if (server()->push($connection->getFd(), json_encode($reply))) {
|
||||
if ($function === true) {
|
||||
Co::suspend();
|
||||
$data = ZMBuf::get("sent_api")[$api_id];
|
||||
ZMBuf::unsetByValue("sent_api", $reply["echo"]);
|
||||
$data = LightCache::get("sent_api_".$api_id);
|
||||
LightCache::unset("sent_api_".$api_id);
|
||||
return isset($data['result']) ? $data['result'] : null;
|
||||
}
|
||||
return true;
|
||||
@ -69,10 +63,10 @@ trait CQAPI
|
||||
"data" => null,
|
||||
"self_id" => $connection->getOption("connect_id")
|
||||
];
|
||||
$s = ZMBuf::get("sent_api")[$reply["echo"]];
|
||||
$s = LightCache::get("sent_api_".$reply["echo"]);
|
||||
if (($s["func"] ?? null) !== null)
|
||||
call_user_func($s["func"], $response, $reply);
|
||||
ZMBuf::unsetByValue("sent_api", $reply["echo"]);
|
||||
LightCache::unset("sent_api_".$reply["echo"]);
|
||||
if ($function === true) return $response;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -7,12 +7,12 @@ use Doctrine\Common\Annotations\Annotation\Target;
|
||||
use ZM\Annotation\AnnotationBase;
|
||||
|
||||
/**
|
||||
* Class OnStart
|
||||
* Class OnWorkerStart
|
||||
* @package ZM\Annotation\Swoole
|
||||
* @Annotation
|
||||
* @Target("ALL")
|
||||
*/
|
||||
class OnStart extends AnnotationBase
|
||||
class OnWorkerStart extends AnnotationBase
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
@ -4,6 +4,8 @@
|
||||
namespace ZM\Command;
|
||||
|
||||
|
||||
use Swoole\Atomic;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Http\Response;
|
||||
use Swoole\Http\Server;
|
||||
@ -15,6 +17,7 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Utils\HttpUtil;
|
||||
|
||||
class PureHttpCommand extends Command
|
||||
@ -37,9 +40,15 @@ class PureHttpCommand extends Command
|
||||
$host = $input->getOption("host") ?? $global["host"];
|
||||
$port = $input->getOption("port") ?? $global["port"];
|
||||
$server = new Server($host, $port);
|
||||
Console::init(2, $server);
|
||||
$server->set(ZMConfig::get("global", "swoole"));
|
||||
Console::init(0, $server);
|
||||
ZMBuf::$atomics["request"] = [];
|
||||
for ($i = 0; $i < 32; ++$i) {
|
||||
ZMBuf::$atomics["request"][$i] = new Atomic(0);
|
||||
}
|
||||
$index = ["index.html", "index.htm"];
|
||||
$server->on("request", function (Request $request, Response $response) use ($input, $index){
|
||||
$server->on("request", function (Request $request, Response $response) use ($input, $index, $server) {
|
||||
ZMBuf::$atomics["request"][$server->worker_id]->add(1);
|
||||
HttpUtil::handleStaticPage(
|
||||
$request->server["request_uri"],
|
||||
$response,
|
||||
@ -47,10 +56,16 @@ class PureHttpCommand extends Command
|
||||
"document_root" => realpath($input->getArgument('dir') ?? '.'),
|
||||
"document_index" => $index
|
||||
]);
|
||||
echo "\r".Coroutine::stats()["coroutine_peak_num"];
|
||||
});
|
||||
$server->on("start", function($server){
|
||||
Process::signal(SIGINT, function () use ($server){
|
||||
$server->on("start", function ($server) {
|
||||
Process::signal(SIGINT, function () use ($server) {
|
||||
Console::warning("Server interrupted by keyboard.");
|
||||
for ($i = 0; $i < 32; ++$i) {
|
||||
$num = ZMBuf::$atomics["request"][$i]->get();
|
||||
if($num != 0)
|
||||
echo "[$i]: ".$num."\n";
|
||||
}
|
||||
$server->shutdown();
|
||||
$server->stop();
|
||||
});
|
||||
|
||||
@ -7,7 +7,6 @@ namespace ZM;
|
||||
use Exception;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use TypeError;
|
||||
use ZM\Command\BuildCommand;
|
||||
use ZM\Command\InitCommand;
|
||||
use ZM\Command\PureHttpCommand;
|
||||
use ZM\Command\RunServerCommand;
|
||||
@ -25,6 +24,7 @@ class ConsoleApplication extends Application
|
||||
}
|
||||
|
||||
public function initEnv() {
|
||||
$this->selfCheck();
|
||||
$this->addCommands([
|
||||
new RunServerCommand(), //运行主服务的指令控制器
|
||||
new InitCommand(), //初始化用的,用于项目初始化和phar初始化
|
||||
@ -77,4 +77,16 @@ class ConsoleApplication extends Application
|
||||
die("{$e->getMessage()} at {$e->getFile()}({$e->getLine()})");
|
||||
}
|
||||
}
|
||||
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ use ZM\Exception\InvalidArgumentException;
|
||||
use ZM\Exception\WaitTimeoutException;
|
||||
use ZM\Http\Response;
|
||||
use ZM\API\ZMRobot;
|
||||
use ZM\Store\LightCache;
|
||||
use ZM\Store\ZMBuf;
|
||||
|
||||
class Context implements ContextInterface
|
||||
@ -153,17 +154,17 @@ class Context implements ContextInterface
|
||||
if ($hang["message_type"] == "group" || $hang["message_type"] == "discuss") {
|
||||
$hang[$hang["message_type"] . "_id"] = $this->getData()[$this->getData()["message_type"] . "_id"];
|
||||
}
|
||||
ZMBuf::appendKey("wait_api", $api_id, $hang);
|
||||
LightCache::set("wait_api_".$api_id, $hang);
|
||||
$id = swoole_timer_after($timeout * 1000, function () use ($api_id, $timeout_prompt) {
|
||||
$r = ZMBuf::get("wait_api")[$api_id] ?? null;
|
||||
if ($r !== null) {
|
||||
$r = LightCache::get("wait_api_".$api_id);
|
||||
if (is_array($r)) {
|
||||
Co::resume($r["coroutine"]);
|
||||
}
|
||||
});
|
||||
|
||||
Co::suspend();
|
||||
$sess = ZMBuf::get("wait_api")[$api_id];
|
||||
ZMBuf::unsetByValue("wait_api", $api_id);
|
||||
$sess = LightCache::get("wait_api_".$api_id);
|
||||
LightCache::unset("wait_api_".$api_id);
|
||||
$result = $sess["result"];
|
||||
if (isset($id)) swoole_timer_clear($id);
|
||||
if ($result === null) throw new WaitTimeoutException($this, $timeout_prompt);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php /** @noinspection PhpComposerExtensionStubsInspection */
|
||||
|
||||
|
||||
namespace ZM\DB;
|
||||
@ -10,7 +10,6 @@ use ZM\Console\Console;
|
||||
use ZM\Store\ZMBuf;
|
||||
use PDOException;
|
||||
use PDOStatement;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Database\PDOStatementProxy;
|
||||
use ZM\Exception\DbException;
|
||||
|
||||
@ -63,9 +62,6 @@ class DB
|
||||
* @throws DbException
|
||||
*/
|
||||
public static function unprepared($line) {
|
||||
if (ZMBuf::get("sql_log") === true) {
|
||||
$starttime = microtime(true);
|
||||
}
|
||||
try {
|
||||
$conn = ZMBuf::$sql_pool->get();
|
||||
if ($conn === false) {
|
||||
@ -76,13 +72,6 @@ class DB
|
||||
ZMBuf::$sql_pool->put($conn);
|
||||
return $result;
|
||||
} catch (DBException $e) {
|
||||
if (ZMBuf::get("sql_log") === true) {
|
||||
$log =
|
||||
"[" . date("Y-m-d H:i:s") .
|
||||
" " . round(microtime(true) - $starttime, 5) .
|
||||
"] " . $line . " (Error:" . $e->getMessage() . ")\n";
|
||||
Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND);
|
||||
}
|
||||
Console::warning($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
@ -96,9 +85,6 @@ class DB
|
||||
* @throws DbException
|
||||
*/
|
||||
public static function rawQuery(string $line, $params = [], $fetch_mode = ZM_DEFAULT_FETCH_MODE) {
|
||||
if (ZMBuf::get("sql_log") === true) {
|
||||
$starttime = microtime(true);
|
||||
}
|
||||
Console::debug("MySQL: ".$line." | ". implode(", ", $params));
|
||||
try {
|
||||
$conn = ZMBuf::$sql_pool->get();
|
||||
@ -126,23 +112,9 @@ class DB
|
||||
//echo json_encode(debug_backtrace(), 128 | 256);
|
||||
}
|
||||
ZMBuf::$sql_pool->put($conn);
|
||||
if (ZMBuf::get("sql_log") === true) {
|
||||
$log =
|
||||
"[" . date("Y-m-d H:i:s") .
|
||||
" " . round(microtime(true) - $starttime, 4) .
|
||||
"] " . $line . " " . json_encode($params, JSON_UNESCAPED_UNICODE) . "\n";
|
||||
Coroutine::writeFile(CRASH_DIR . "sql.log", $log, FILE_APPEND);
|
||||
}
|
||||
return $ps->fetchAll($fetch_mode);
|
||||
}
|
||||
} catch (DbException $e) {
|
||||
if (ZMBuf::get("sql_log") === true) {
|
||||
$log =
|
||||
"[" . date("Y-m-d H:i:s") .
|
||||
" " . round(microtime(true) - $starttime, 4) .
|
||||
"] " . $line . " " . json_encode($params, JSON_UNESCAPED_UNICODE) . " (Error:" . $e->getMessage() . ")\n";
|
||||
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!");
|
||||
@ -151,13 +123,6 @@ class DB
|
||||
Console::warning($e->getMessage());
|
||||
throw $e;
|
||||
} catch (PDOException $e) {
|
||||
if (ZMBuf::get("sql_log") === true) {
|
||||
$log =
|
||||
"[" . date("Y-m-d H:i:s") .
|
||||
" " . round(microtime(true) - $starttime, 4) .
|
||||
"] " . $line . " " . json_encode($params, JSON_UNESCAPED_UNICODE) . " (Error:" . $e->getMessage() . ")\n";
|
||||
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!");
|
||||
|
||||
@ -85,7 +85,6 @@ class MessageEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AnnotationException
|
||||
* @noinspection PhpRedundantCatchClauseInspection
|
||||
*/
|
||||
public function onActivate() {
|
||||
@ -122,7 +121,7 @@ class MessageEvent
|
||||
EventDispatcher::interrupt();
|
||||
});
|
||||
$r = $dispatcher->dispatchEvents($word);
|
||||
if ($r === false) return;
|
||||
if ($r === null) return;
|
||||
|
||||
//分发CQMessage事件
|
||||
$msg_dispatcher = new EventDispatcher(CQMessage::class);
|
||||
|
||||
@ -7,7 +7,6 @@ namespace ZM\Event;
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use Exception;
|
||||
use ZM\Annotation\AnnotationBase;
|
||||
use ZM\Annotation\Interfaces\Rule;
|
||||
use ZM\Exception\InterruptException;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
@ -20,6 +19,9 @@ class EventDispatcher
|
||||
/** @var null|callable */
|
||||
private $return_func = null;
|
||||
|
||||
/**
|
||||
* @throws InterruptException
|
||||
*/
|
||||
public static function interrupt() {
|
||||
throw new InterruptException('interrupt');
|
||||
}
|
||||
@ -46,12 +48,20 @@ class EventDispatcher
|
||||
}
|
||||
return true;
|
||||
} catch (InterruptException $e) {
|
||||
return false;
|
||||
return null;
|
||||
} catch (AnnotationException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AnnotationBase|null $v
|
||||
* @param null $rule_func
|
||||
* @param mixed ...$params
|
||||
* @return bool
|
||||
* @throws AnnotationException
|
||||
* @throws InterruptException
|
||||
*/
|
||||
public function dispatchEvent(?AnnotationBase $v, $rule_func = null, ...$params) {
|
||||
$q_c = $v->class;
|
||||
$q_f = $v->method;
|
||||
|
||||
@ -22,6 +22,7 @@ use ZM\Annotation\Http\MiddlewareClass;
|
||||
use ZM\Context\Context;
|
||||
use ZM\Http\MiddlewareInterface;
|
||||
use ZM\Http\Response;
|
||||
use ZM\Store\LightCache;
|
||||
use ZM\Store\ZMBuf;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
@ -158,8 +159,8 @@ class EventHandler
|
||||
$status = $req["status"];
|
||||
$retcode = $req["retcode"];
|
||||
$data = $req["data"];
|
||||
if (isset($req["echo"]) && ZMBuf::array_key_exists("sent_api", $req["echo"])) {
|
||||
$origin = ZMBuf::get("sent_api")[$req["echo"]];
|
||||
if (isset($req["echo"]) && LightCache::isset("sent_api_" . $req["echo"])) {
|
||||
$origin = LightCache::get("sent_api_" . $req["echo"]);
|
||||
$self_id = $origin["self_id"];
|
||||
$response = [
|
||||
"status" => $status,
|
||||
@ -188,12 +189,12 @@ class EventHandler
|
||||
if (($origin["func"] ?? null) !== null) {
|
||||
call_user_func($origin["func"], $response, $origin["data"]);
|
||||
} elseif (($origin["coroutine"] ?? false) !== false) {
|
||||
$p = ZMBuf::get("sent_api");
|
||||
$p[$req["echo"]]["result"] = $response;
|
||||
ZMBuf::set("sent_api", $p);
|
||||
$r = LightCache::get("sent_api_" . $req["echo"]);
|
||||
$r["result"] = $response;
|
||||
LightCache::set("sent_api_" . $req["echo"], $r);
|
||||
Co::resume($origin['coroutine']);
|
||||
}
|
||||
ZMBuf::unsetByValue("sent_api", $req["echo"]);
|
||||
LightCache::unset("sent_api_" . $req["echo"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ use Swoole\Process;
|
||||
use Swoole\Timer;
|
||||
use ZM\Annotation\AnnotationParser;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Annotation\Swoole\OnStart;
|
||||
use ZM\Annotation\Swoole\OnWorkerStart;
|
||||
use ZM\Annotation\Swoole\SwooleEvent;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\ConnectionManager\ManagerGM;
|
||||
@ -54,21 +54,23 @@ class ServerEventHandler
|
||||
try {
|
||||
Terminal::executeCommand($var, $r);
|
||||
} catch (Exception $e) {
|
||||
Console::error("Uncaught exception ".get_class($e).": ".$e->getMessage()." at ".$e->getFile()."(".$e->getLine().")");
|
||||
Console::error("Uncaught exception " . get_class($e) . ": " . $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")");
|
||||
} catch (Error $e) {
|
||||
Console::error("Uncaught error ".get_class($e).": ".$e->getMessage()." at ".$e->getFile()."(".$e->getLine().")");
|
||||
Console::error("Uncaught error " . get_class($e) . ": " . $e->getMessage() . " at " . $e->getFile() . "(" . $e->getLine() . ")");
|
||||
}
|
||||
});
|
||||
}
|
||||
Process::signal(SIGINT, function () use ($r) {
|
||||
echo "\r";
|
||||
Console::warning("Server interrupted by keyboard on Master.");
|
||||
if ((Framework::$server->inotify ?? null) !== null)
|
||||
/** @noinspection PhpUndefinedFieldInspection */ Event::del(Framework::$server->inotify);
|
||||
ZMUtil::stop();
|
||||
});
|
||||
if(Framework::$argv["watch"]) {
|
||||
if (Framework::$argv["watch"]) {
|
||||
if (extension_loaded('inotify')) {
|
||||
Console::warning("Enabled File watcher, do not use in production.");
|
||||
/** @noinspection PhpUndefinedFieldInspection */
|
||||
Framework::$server->inotify = $fd = inotify_init();
|
||||
$this->addWatcher(DataProvider::getWorkingDir() . "/src", $fd);
|
||||
Event::add($fd, function () use ($fd) {
|
||||
@ -117,7 +119,7 @@ class ServerEventHandler
|
||||
if ($error["type"] != 0) {
|
||||
Console::error("Internal fatal error: " . $error["message"] . " at " . $error["file"] . "({$error["line"]})");
|
||||
}
|
||||
DataProvider::saveBuffer();
|
||||
//DataProvider::saveBuffer();
|
||||
/** @var Server $server */
|
||||
if (server() === null) $server->shutdown();
|
||||
else server()->shutdown();
|
||||
@ -125,7 +127,7 @@ class ServerEventHandler
|
||||
|
||||
Console::info("Worker #{$server->worker_id} 启动中");
|
||||
Framework::$server = $server;
|
||||
ZMBuf::resetCache(); //清空变量缓存
|
||||
//ZMBuf::resetCache(); //清空变量缓存
|
||||
//ZMBuf::set("wait_start", []); //添加队列,在workerStart运行完成前先让其他协程等待执行
|
||||
foreach ($server->connections as $v) {
|
||||
$server->close($v);
|
||||
@ -193,12 +195,12 @@ class ServerEventHandler
|
||||
EventManager::registerTimerTick(); //启动计时器
|
||||
//ZMBuf::unsetCache("wait_start");
|
||||
set_coroutine_params(["server" => $server, "worker_id" => $worker_id]);
|
||||
$dispatcher = new EventDispatcher(OnStart::class);
|
||||
$dispatcher = new EventDispatcher(OnWorkerStart::class);
|
||||
$dispatcher->setRuleFunction(function ($v) {
|
||||
return server()->worker_id === $v->worker_id || $v->worker_id === -1;
|
||||
});
|
||||
$dispatcher->dispatchEvents($server, $worker_id);
|
||||
Console::debug("@OnStart 执行完毕");
|
||||
Console::debug("@OnWorkerStart 执行完毕");
|
||||
} catch (Exception $e) {
|
||||
Console::error("Worker加载出错!停止服务!");
|
||||
Console::error($e->getMessage() . "\n" . $e->getTraceAsString());
|
||||
@ -289,9 +291,9 @@ class ServerEventHandler
|
||||
|
||||
try {
|
||||
$no_interrupt = $dis->dispatchEvents($request, $response);
|
||||
if (!$no_interrupt) {
|
||||
if ($no_interrupt !== null) {
|
||||
$result = HttpUtil::parseUri($request, $response, $request->server["request_uri"], $node, $params);
|
||||
if (!$result) {
|
||||
if ($result === true) {
|
||||
ctx()->setCache("params", $params);
|
||||
$dispatcher = new EventDispatcher(RequestMapping::class);
|
||||
$div = new RequestMapping();
|
||||
@ -300,11 +302,13 @@ class ServerEventHandler
|
||||
$div->method = $node["method"];
|
||||
$div->request_method = $node["request_method"];
|
||||
$div->class = $node["class"];
|
||||
//Console::success("正在执行路由:".$node["method"]);
|
||||
$r = $dispatcher->dispatchEvent($div, null, $params, $request, $response);
|
||||
if (is_string($r) && !$response->isEnd()) $response->end($r);
|
||||
}
|
||||
}
|
||||
if (!$response->isEnd()) {
|
||||
//Console::warning('返回了404');
|
||||
HttpUtil::responseCodePage($response, 404);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
@ -380,9 +384,10 @@ class ServerEventHandler
|
||||
* @param $fd
|
||||
*/
|
||||
public function onClose($server, $fd) {
|
||||
Console::debug("Calling Swoole \"close\" event from fd=" . $fd);
|
||||
unset(Context::$context[Co::getCid()]);
|
||||
$conn = ManagerGM::get($fd);
|
||||
if ($conn === null) return;
|
||||
Console::debug("Calling Swoole \"close\" event from fd=" . $fd);
|
||||
set_coroutine_params(["server" => $server, "connection" => $conn, "fd" => $fd]);
|
||||
$dispatcher = new EventDispatcher(SwooleEvent::class);
|
||||
$dispatcher->setRuleFunction(function ($v) {
|
||||
|
||||
@ -65,8 +65,6 @@ class Framework
|
||||
} catch (ConnectionManager\TableException $e) {
|
||||
die($e->getMessage());
|
||||
}
|
||||
//start swoole Framework
|
||||
$this->selfCheck();
|
||||
try {
|
||||
self::$server = new Server(ZMConfig::get("global", "host"), ZMConfig::get("global", "port"));
|
||||
$this->server_set = ZMConfig::get("global", "swoole");
|
||||
@ -118,6 +116,7 @@ class Framework
|
||||
"size" => 2048,
|
||||
"max_strlen" => 4096,
|
||||
"hash_conflict_proportion" => 0.6,
|
||||
"persistence_path" => realpath(DataProvider::getDataFolder()."_cache.json")
|
||||
]);
|
||||
self::$server->start();
|
||||
} catch (Exception $e) {
|
||||
@ -127,18 +126,6 @@ class Framework
|
||||
}
|
||||
}
|
||||
|
||||
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 (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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从全局配置文件里读取注入系统事件的类
|
||||
* @throws ReflectionException
|
||||
|
||||
@ -4,10 +4,9 @@
|
||||
namespace ZM\Http;
|
||||
|
||||
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use Framework\ZMBuf;
|
||||
use ZM\Utils\HttpUtil;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
class StaticFileHandler
|
||||
{
|
||||
@ -23,7 +22,7 @@ class StaticFileHandler
|
||||
} 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->setHeader("Content-Type", ZMConfig::get("file_header")[$exp] ?? "application/octet-stream");
|
||||
$response->end(file_get_contents($full_path));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -5,7 +5,8 @@ namespace ZM\Module;
|
||||
|
||||
/**
|
||||
* Class QQBot
|
||||
* @package ZM\Plugins
|
||||
* @package ZM\Module
|
||||
* @ExternalModule("qqbot")
|
||||
*/
|
||||
class QQBot
|
||||
{
|
||||
|
||||
@ -6,6 +6,7 @@ namespace ZM\Store;
|
||||
|
||||
use Exception;
|
||||
use Swoole\Table;
|
||||
use ZM\Console\Console;
|
||||
|
||||
class LightCache
|
||||
{
|
||||
@ -14,13 +15,31 @@ class LightCache
|
||||
|
||||
private static $config = [];
|
||||
|
||||
public static $last_error = '';
|
||||
|
||||
public static function init($config) {
|
||||
self::$config = $config;
|
||||
self::$kv_table = new Table($config["size"], $config["hash_conflict_proportion"]);
|
||||
self::$kv_table->column("value", Table::TYPE_STRING, $config["max_strlen"]);
|
||||
self::$kv_table->column("expire", Table::TYPE_INT);
|
||||
self::$kv_table->column("data_type", Table::TYPE_STRING, 12);
|
||||
return self::$kv_table->create();
|
||||
$result = self::$kv_table->create();
|
||||
if ($result === true && isset($config["persistence_path"])) {
|
||||
$r = json_decode(file_get_contents($config["persistence_path"]), true);
|
||||
if ($r === null) $r = [];
|
||||
foreach ($r as $k => $v) {
|
||||
$write = self::set($k, $v);
|
||||
Console::debug("Writing LightCache: " . $k);
|
||||
if ($write === false) {
|
||||
self::$last_error = '可能是由于 Hash 冲突过多导致动态空间无法分配内存';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($result === false) {
|
||||
self::$last_error = '系统内存不足,申请失败';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,12 +75,14 @@ class LightCache
|
||||
*/
|
||||
public static function set(string $key, $value, int $expire = -1) {
|
||||
if (self::$kv_table === null) throw new Exception("not initialized LightCache");
|
||||
if (is_array($value) || is_int($value)) {
|
||||
if (is_array($value)) {
|
||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
if (strlen($value) >= self::$config["max_strlen"]) return false;
|
||||
$data_type = "json";
|
||||
} elseif (is_string($value)) {
|
||||
$data_type = "";
|
||||
} elseif (is_int($value)) {
|
||||
$data_type = "int";
|
||||
} else {
|
||||
throw new Exception("Only can set string, array and int");
|
||||
}
|
||||
@ -97,20 +118,31 @@ class LightCache
|
||||
$r = [];
|
||||
$del = [];
|
||||
foreach (self::$kv_table as $k => $v) {
|
||||
if ($v["expire"] <= time()) {
|
||||
$del[]=$k;
|
||||
if ($v["expire"] <= time() && $v["expire"] >= 0) {
|
||||
$del[] = $k;
|
||||
continue;
|
||||
}
|
||||
$r[$k] = self::parseGet($v);
|
||||
}
|
||||
foreach($del as $v) {
|
||||
foreach ($del as $v) {
|
||||
self::unset($v);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
public static function savePersistence() {
|
||||
$r = [];
|
||||
foreach (self::$kv_table as $k => $v) {
|
||||
if ($v["expire"] === -2) {
|
||||
$r[$k] = self::parseGet($v);
|
||||
}
|
||||
}
|
||||
$r = file_put_contents(self::$config["persistence_path"], json_encode($r, 128 | 256));
|
||||
if($r === false) Console::error("Not saved, please check your \"persistence_path\"!");
|
||||
}
|
||||
|
||||
private static function checkExpire($key) {
|
||||
if (($expire = self::$kv_table->get($key, "expire")) !== -1) {
|
||||
if (($expire = self::$kv_table->get($key, "expire")) >= 0) {
|
||||
if ($expire <= time()) {
|
||||
self::$kv_table->del($key);
|
||||
}
|
||||
@ -120,6 +152,7 @@ class LightCache
|
||||
private static function parseGet($r) {
|
||||
switch ($r["data_type"]) {
|
||||
case "json":
|
||||
case "int":
|
||||
return json_decode($r["value"], true);
|
||||
case "":
|
||||
default:
|
||||
|
||||
9
src/ZM/Store/Redis/Redis.php
Normal file
9
src/ZM/Store/Redis/Redis.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Store\Redis;
|
||||
|
||||
|
||||
class Redis
|
||||
{
|
||||
}
|
||||
@ -15,68 +15,20 @@ use ZM\Config\ZMConfig;
|
||||
class ZMBuf
|
||||
{
|
||||
//读写的缓存数据,需要在worker_num = 1下才能正常使用
|
||||
/** @var mixed[] ZMBuf的data */
|
||||
private static $cache = [];
|
||||
//Swoole SQL连接池,多进程下每个进程一个连接池
|
||||
/** @var PDOPool */
|
||||
static $sql_pool = null;//保存sql连接池的类
|
||||
|
||||
/** @var array Http请求uri路径根节点 */
|
||||
public static $req_mapping_node;
|
||||
/** @var array 事件注解的绑定对 */
|
||||
public static $events = [];
|
||||
|
||||
// 下面的有用,上面的没用了
|
||||
/** @var Atomic[] */
|
||||
public static $atomics;
|
||||
public static $instance = [];
|
||||
public static $context_class = [];
|
||||
public static $terminal = null;
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
public static function resetCache() {
|
||||
self::$cache = [];
|
||||
self::$instance = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化atomic计数器
|
||||
*/
|
||||
@ -86,6 +38,9 @@ class ZMBuf
|
||||
}
|
||||
self::$atomics["stop_signal"] = new Atomic(0);
|
||||
self::$atomics["wait_msg_id"] = new Atomic(0);
|
||||
for($i = 0; $i < 10; ++$i) {
|
||||
self::$atomics["_tmp_".$i] = new Atomic(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,9 +5,6 @@ namespace ZM\Utils;
|
||||
|
||||
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Annotation\Swoole\OnSave;
|
||||
use ZM\Store\ZMBuf;
|
||||
|
||||
class DataProvider
|
||||
{
|
||||
@ -24,57 +21,10 @@ class DataProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getDataConfig() {
|
||||
return CONFIG_DIR;
|
||||
}
|
||||
|
||||
public static function addSaveBuffer($buf_name, $sub_folder = null) {
|
||||
$name = ($sub_folder ?? "") . "/" . $buf_name . ".json";
|
||||
self::$buffer_list[$buf_name] = $name;
|
||||
Console::debug("Added " . $buf_name . " at $sub_folder");
|
||||
ZMBuf::set($buf_name, self::getJsonData($name));
|
||||
}
|
||||
|
||||
public static function saveBuffer() {
|
||||
$head = Console::setColor(date("[H:i:s] ") . "[V] Saving buffer......", "blue");
|
||||
if (Console::getLevel() >= 3)
|
||||
echo $head;
|
||||
foreach (self::$buffer_list as $k => $v) {
|
||||
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 (Console::getLevel() >= 3)
|
||||
echo Console::setColor("saved", "blue") . PHP_EOL;
|
||||
}
|
||||
|
||||
public static function getFrameworkLink() {
|
||||
return ZMConfig::get("global", "http_reverse_link");
|
||||
}
|
||||
|
||||
public static function getJsonData(string $string) {
|
||||
if (!file_exists(self::getDataConfig() . $string)) return [];
|
||||
return json_decode(file_get_contents(self::getDataConfig() . $string), true);
|
||||
}
|
||||
|
||||
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"]);
|
||||
mkdir(self::getDataConfig() . $pathinfo["dirname"]);
|
||||
}
|
||||
$r = file_put_contents(self::getDataConfig() . $filename, json_encode($args, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_BIGINT_AS_STRING));
|
||||
if ($r === false) {
|
||||
Console::warning("无法保存文件: " . $filename);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getDataFolder() {
|
||||
return ZM_DATA;
|
||||
}
|
||||
|
||||
@ -52,10 +52,10 @@ class HttpUtil
|
||||
}
|
||||
if (ZMConfig::get("global", "static_file_server")["status"]) {
|
||||
HttpUtil::handleStaticPage($request->server["request_uri"], $response);
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return !isset($node["route"]) ? false : true;
|
||||
}
|
||||
|
||||
public static function getHttpCodePage(int $http_code) {
|
||||
|
||||
@ -5,6 +5,7 @@ namespace ZM\Utils;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Psy\Shell;
|
||||
use Swoole\Event;
|
||||
use ZM\Console\Console;
|
||||
use ZM\Framework;
|
||||
@ -35,8 +36,9 @@ class Terminal
|
||||
$class->$function_name();
|
||||
return true;
|
||||
case 'psysh':
|
||||
if (Framework::$argv["disable-coroutine"])
|
||||
eval(\Psy\sh());
|
||||
if (Framework::$argv["disable-coroutine"]) {
|
||||
(new Shell())->run();
|
||||
}
|
||||
else
|
||||
Console::error("Only \"--disable-coroutine\" mode can use psysh!!!");
|
||||
return true;
|
||||
|
||||
@ -30,13 +30,14 @@ class ZMUtil
|
||||
public static function reload($delay = 800) {
|
||||
Console::info(Console::setColor("Reloading server...", "gold"));
|
||||
usleep($delay * 1000);
|
||||
foreach (ZMBuf::get("wait_api", []) as $k => $v) {
|
||||
if ($v["result"] === null) Co::resume($v["coroutine"]);
|
||||
foreach (LightCache::getAll() as $k => $v) {
|
||||
if (mb_substr($k, 0, 8) == "wait_api")
|
||||
if ($v["result"] === null) Co::resume($v["coroutine"]);
|
||||
}
|
||||
foreach (server()->connections as $v) {
|
||||
server()->close($v);
|
||||
}
|
||||
DataProvider::saveBuffer();
|
||||
//DataProvider::saveBuffer();
|
||||
Timer::clearAll();
|
||||
server()->reload();
|
||||
}
|
||||
|
||||
256
test/ZMTest/Mock/Context.php
Normal file
256
test/ZMTest/Mock/Context.php
Normal file
@ -0,0 +1,256 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZMTest\Mock;
|
||||
|
||||
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\WebSocket\Frame;
|
||||
use Swoole\WebSocket\Server;
|
||||
use ZM\API\ZMRobot;
|
||||
use ZM\ConnectionManager\ConnectionObject;
|
||||
use ZM\Context\ContextInterface;
|
||||
use ZM\Http\Response;
|
||||
|
||||
class Context implements ContextInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Context constructor.
|
||||
* @param $cid
|
||||
*/
|
||||
public function __construct($cid) { }
|
||||
|
||||
/**
|
||||
* @return Server
|
||||
*/
|
||||
public function getServer() {
|
||||
// TODO: Implement getServer() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Frame
|
||||
*/
|
||||
public function getFrame() {
|
||||
// TODO: Implement getFrame() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getData() {
|
||||
// TODO: Implement getData() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function setData($data) {
|
||||
// TODO: Implement setData() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ConnectionObject
|
||||
*/
|
||||
public function getConnection() {
|
||||
// TODO: Implement getConnection() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getFd() {
|
||||
// TODO: Implement getFd() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCid() {
|
||||
// TODO: Implement getCid() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function getResponse() {
|
||||
// TODO: Implement getResponse() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Request
|
||||
*/
|
||||
public function getRequest() {
|
||||
// TODO: Implement getRequest() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ZMRobot
|
||||
*/
|
||||
public function getRobot() {
|
||||
// TODO: Implement getRobot() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUserId() {
|
||||
// TODO: Implement getUserId() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getGroupId() {
|
||||
// TODO: Implement getGroupId() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDiscussId() {
|
||||
// TODO: Implement getDiscussId() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMessageType() {
|
||||
// TODO: Implement getMessageType() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRobotId() {
|
||||
// TODO: Implement getRobotId() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMessage() {
|
||||
// TODO: Implement getMessage() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $msg
|
||||
* @return mixed
|
||||
*/
|
||||
public function setMessage($msg) {
|
||||
// TODO: Implement setMessage() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function setUserId($id) {
|
||||
// TODO: Implement setUserId() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function setGroupId($id) {
|
||||
// TODO: Implement setGroupId() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function setDiscussId($id) {
|
||||
// TODO: Implement setDiscussId() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function setMessageType($type) {
|
||||
// TODO: Implement setMessageType() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCQResponse() {
|
||||
// TODO: Implement getCQResponse() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $msg
|
||||
* @param bool $yield
|
||||
* @return mixed
|
||||
*/
|
||||
public function reply($msg, $yield = false) {
|
||||
echo $msg.PHP_EOL;
|
||||
// TODO: Implement reply() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $msg
|
||||
* @param bool $yield
|
||||
* @return mixed
|
||||
*/
|
||||
public function finalReply($msg, $yield = false) {
|
||||
// TODO: Implement finalReply() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prompt
|
||||
* @param int $timeout
|
||||
* @param string $timeout_prompt
|
||||
* @return mixed
|
||||
*/
|
||||
public function waitMessage($prompt = "", $timeout = 600, $timeout_prompt = "") {
|
||||
// TODO: Implement waitMessage() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $arg
|
||||
* @param $mode
|
||||
* @param $prompt_msg
|
||||
* @return mixed
|
||||
*/
|
||||
public function getArgs(&$arg, $mode, $prompt_msg) {
|
||||
$r = $arg;
|
||||
array_shift($r);
|
||||
return array_shift($r);
|
||||
// TODO: Implement getArgs() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function setCache($key, $value) {
|
||||
// TODO: Implement setCache() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCache($key) {
|
||||
// TODO: Implement getCache() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function cloneFromParent() {
|
||||
// TODO: Implement cloneFromParent() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function copy() {
|
||||
// TODO: Implement copy() method.
|
||||
}
|
||||
}
|
||||
114
test/ZMTest/Mock/global.php
Normal file
114
test/ZMTest/Mock/global.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/** @noinspection PhpFullyQualifiedNameUsageInspection */
|
||||
/** @noinspection PhpComposerExtensionStubsInspection */
|
||||
global $config;
|
||||
|
||||
/** bind host */
|
||||
$config['host'] = '0.0.0.0';
|
||||
|
||||
/** bind port */
|
||||
$config['port'] = 20001;
|
||||
|
||||
/** 框架开到公网或外部的HTTP访问链接,通过 DataProvider::getFrameworkLink() 获取 */
|
||||
$config['http_reverse_link'] = "http://127.0.0.1:" . $config['port'];
|
||||
|
||||
/** 框架是否启动debug模式 */
|
||||
$config['debug_mode'] = false;
|
||||
|
||||
/** 存放框架内文件数据的目录 */
|
||||
$config['zm_data'] = realpath(__DIR__ . "/../") . '/zm_data/';
|
||||
|
||||
/** 存放各个模块配置文件的目录 */
|
||||
$config['config_dir'] = $config['zm_data'] . 'config/';
|
||||
|
||||
/** 存放崩溃和运行日志的目录 */
|
||||
$config['crash_dir'] = $config['zm_data'] . 'crash/';
|
||||
|
||||
/** 对应swoole的server->set参数 */
|
||||
$config['swoole'] = [
|
||||
'log_file' => $config['crash_dir'] . 'swoole_error.log',
|
||||
'worker_num' => 8,
|
||||
'dispatch_mode' => 2,
|
||||
'max_coroutine' => 30000,
|
||||
//'task_worker_num' => 4,
|
||||
//'task_enable_coroutine' => true
|
||||
];
|
||||
|
||||
/** 轻量字符串缓存,默认开启 */
|
||||
$config['light_cache'] = [
|
||||
"status" => true,
|
||||
"size" => 2048, //最多允许储存的条数(需要2的倍数)
|
||||
"max_strlen" => 4096, //单行字符串最大长度(需要2的倍数)
|
||||
"hash_conflict_proportion" => 0.6 //Hash冲突率(越大越好,但是需要的内存更多)
|
||||
];
|
||||
|
||||
/** MySQL数据库连接信息,host留空则启动时不创建sql连接池 */
|
||||
$config['sql_config'] = [
|
||||
'sql_host' => '',
|
||||
'sql_port' => 3306,
|
||||
'sql_username' => 'name',
|
||||
'sql_database' => 'db_name',
|
||||
'sql_password' => '',
|
||||
'sql_enable_cache' => true,
|
||||
'sql_reset_cache' => '0300',
|
||||
'sql_options' => [
|
||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
||||
PDO::ATTR_EMULATE_PREPARES => false
|
||||
],
|
||||
'sql_no_exception' => false,
|
||||
'sql_default_fetch_mode' => PDO::FETCH_ASSOC // added in 1.5.6
|
||||
];
|
||||
|
||||
/** CQHTTP连接约定的token */
|
||||
$config["access_token"] = "";
|
||||
|
||||
/** HTTP服务器固定请求头的返回 */
|
||||
$config['http_header'] = [
|
||||
'X-Powered-By' => 'zhamao-framework',
|
||||
'Content-Type' => 'text/html; charset=utf-8'
|
||||
];
|
||||
|
||||
/** HTTP服务器在指定状态码下回复的页面(默认) */
|
||||
$config['http_default_code_page'] = [
|
||||
'404' => '404.html'
|
||||
];
|
||||
|
||||
/** zhamao-framework在框架启动时初始化的atomic们 */
|
||||
$config['init_atomics'] = [
|
||||
//'custom_atomic_name' => 0, //自定义添加的Atomic
|
||||
];
|
||||
|
||||
/** 终端日志显示等级(0-4) */
|
||||
$config["info_level"] = 2;
|
||||
|
||||
/** 自动保存计时器的缓存保存时间(秒) */
|
||||
$config['auto_save_interval'] = 900;
|
||||
|
||||
/** 上下文接口类 implemented from ContextInterface */
|
||||
$config['context_class'] = \ZMTest\Mock\Context::class;
|
||||
|
||||
/** 静态文件访问 */
|
||||
$config['static_file_server'] = [
|
||||
'status' => false,
|
||||
'document_root' => realpath(__DIR__ . "/../") . '/resources/html',
|
||||
'document_index' => [
|
||||
'index.html'
|
||||
]
|
||||
];
|
||||
|
||||
/** 注册 Swoole Server 事件注解的类列表 */
|
||||
$config['server_event_handler_class'] = [
|
||||
\ZM\Event\ServerEventHandler::class,
|
||||
];
|
||||
|
||||
/** 注册自定义指令的类 */
|
||||
$config['command_register_class'] = [
|
||||
//\Custom\Command\CustomCommand::class
|
||||
];
|
||||
|
||||
/** 服务器启用的外部第三方和内部插件 */
|
||||
$config['plugins'] = [
|
||||
'qqbot' => true, // QQ机器人事件解析器,如果取消此项则默认为 true 开启状态,否则你手动填写 false 才会关闭
|
||||
];
|
||||
|
||||
return $config;
|
||||
@ -9,7 +9,7 @@ use Module\Example\Hello;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ReflectionException;
|
||||
use ZM\Annotation\AnnotationParser;
|
||||
use ZM\Annotation\Swoole\OnStart;
|
||||
use ZM\Annotation\Swoole\OnWorkerStart;
|
||||
use ZM\Console\Console;
|
||||
|
||||
class AnnotationParserRegisterTest extends TestCase
|
||||
@ -34,8 +34,8 @@ class AnnotationParserRegisterTest extends TestCase
|
||||
public function testAnnotation() {
|
||||
ob_start();
|
||||
$gen = $this->parser->generateAnnotationEvents();
|
||||
$m = $gen[OnStart::class][0]->method;
|
||||
$class = $gen[OnStart::class][0]->class;
|
||||
$m = $gen[OnWorkerStart::class][0]->method;
|
||||
$class = $gen[OnWorkerStart::class][0]->class;
|
||||
$c = new $class();
|
||||
try {
|
||||
$c->$m();
|
||||
|
||||
27
test/ZMTest/Testing/ModuleTest.php
Normal file
27
test/ZMTest/Testing/ModuleTest.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZMTest\Testing;
|
||||
|
||||
|
||||
use Module\Example\Hello;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ZM\Config\ZMConfig;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
class ModuleTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void {
|
||||
ZMConfig::setDirectory(realpath(__DIR__."/../Mock"));
|
||||
set_coroutine_params([]);
|
||||
require_once __DIR__ . '/../../../src/ZM/global_defines.php';
|
||||
}
|
||||
|
||||
public function testCtx() {
|
||||
$r = ZMUtil::getModInstance(Hello::class);
|
||||
ob_start();
|
||||
$r->randNum(["随机数", "1", "5"]);
|
||||
$out = ob_get_clean();
|
||||
$this->assertEquals("随机数是:1\n", $out);
|
||||
}
|
||||
}
|
||||
@ -25,7 +25,15 @@ $route = new Route(
|
||||
|
||||
// ...
|
||||
|
||||
$routes->add('date', $route);
|
||||
$routes->add('date', new Route(
|
||||
'/archive/{month}', // path
|
||||
array('controller' => 'showArchive', 'asd' => 'feswf'), // default values
|
||||
array('month' => '[0-9]{4}-[0-9]{2}', 'subdomain' => 'www|m'), // requirements
|
||||
array(), // options
|
||||
'', // host
|
||||
array(), // schemes
|
||||
array() // methods
|
||||
));
|
||||
|
||||
$route = new Route('/archive/test');
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user