mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-03 14:55:36 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aad28f1ec4 | ||
|
|
f1949b1bd0 | ||
|
|
3b8aac5d8f | ||
|
|
5fd45c2542 | ||
|
|
af89c1b1f6 | ||
|
|
3287b96f30 | ||
|
|
00a8683658 | ||
|
|
c0ea068d04 | ||
|
|
9ba58ff90f | ||
|
|
1a1cf0ad30 | ||
|
|
1de93b9dc1 | ||
|
|
99e44eea3d | ||
|
|
e67958a8d1 | ||
|
|
23b3dc34e2 | ||
|
|
775672d515 | ||
|
|
40e17fab62 |
@@ -84,6 +84,6 @@ Pages托管:[https://framework.zhamao.xin/](https://framework.zhamao.xin/)
|
||||
|
||||
欢迎随时在 HTTP-API 插件群里提问,当然更好的话可以加作者 QQ(627577391)或提交 Issue 进行疑难解答。
|
||||
|
||||
本项目在更行内容时,请及时关注 GitHub 动态,更新前请将自己的模块代码做好备份。
|
||||
本项目在更新内容时,请及时关注 GitHub 动态,更新前请将自己的模块代码做好备份。
|
||||
|
||||
项目框架采用 Apache-2.0 协议开源,在分发或重写修改等操作时需遵守协议。项目模块部分(`Module` 文件夹) 在非借鉴框架内代码时可不遵守 Apache-2.0 协议进行分发和修改(声明版权)。
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "zhamao/framework",
|
||||
"description": "high-performance intelligent assistant",
|
||||
"description": "High performance QQ robot and web server development framework",
|
||||
"minimum-stability": "stable",
|
||||
"license": "Apache-2.0",
|
||||
"version": "1.5",
|
||||
"version": "1.5.4",
|
||||
"authors": [
|
||||
{
|
||||
"name": "whale",
|
||||
@@ -23,11 +23,19 @@
|
||||
"swoole/ide-helper": "@dev",
|
||||
"ext-mbstring": "*",
|
||||
"swlib/saber": "^1.0",
|
||||
"doctrine/annotations": "<1.10.2",
|
||||
"doctrine/annotations": "~1.10",
|
||||
"ext-json": "*",
|
||||
"ext-posix": "*",
|
||||
"ext-ctype": "*",
|
||||
"ext-pdo": "*",
|
||||
"psy/psysh": "@stable"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Custom\\": "src/Custom",
|
||||
"Framework\\": "src/Framework",
|
||||
"ZM\\": "src/ZM",
|
||||
"Module\\": "src/Module"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,12 @@ $config['sql_config'] = [
|
||||
'sql_database' => 'db_name',
|
||||
'sql_password' => '',
|
||||
'sql_enable_cache' => true,
|
||||
'sql_reset_cache' => '0300'
|
||||
'sql_reset_cache' => '0300',
|
||||
'sql_options' => [
|
||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
||||
PDO::ATTR_EMULATE_PREPARES => false
|
||||
],
|
||||
'sql_no_exception' => false
|
||||
];
|
||||
|
||||
/** CQHTTP连接约定的token */
|
||||
|
||||
@@ -184,7 +184,7 @@ class Console
|
||||
$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()) {
|
||||
if(($req->header["x-terminal-id"] ?? "") != $terminal_id) {
|
||||
$conn->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -43,9 +43,19 @@ class FrameworkLoader
|
||||
|
||||
$this->requireGlobalFunctions();
|
||||
if (LOAD_MODE == 0) define("WORKING_DIR", getcwd());
|
||||
elseif(LOAD_MODE == 1) define("WORKING_DIR", realpath(__DIR__ . "/../../"));
|
||||
elseif (LOAD_MODE == 1) define("WORKING_DIR", realpath(__DIR__ . "/../../"));
|
||||
elseif (LOAD_MODE == 2) echo "Phar mode: " . WORKING_DIR . PHP_EOL;
|
||||
$this->registerAutoloader('classLoader');
|
||||
//$this->registerAutoloader('classLoader');
|
||||
require_once "DataProvider.php";
|
||||
if (file_exists(DataProvider::getWorkingDir() . "/vendor/autoload.php")) {
|
||||
require_once DataProvider::getWorkingDir() . "/vendor/autoload.php";
|
||||
}
|
||||
if (LOAD_MODE == 2) {
|
||||
require_once FRAMEWORK_DIR . "/vendor/autoload.php";
|
||||
spl_autoload_register('phar_classloader');
|
||||
}
|
||||
|
||||
|
||||
self::$settings = new GlobalConfig();
|
||||
if (self::$settings->get("debug_mode") === true) {
|
||||
$args[] = "--debug-mode";
|
||||
@@ -100,7 +110,7 @@ class FrameworkLoader
|
||||
"host: " . self::$settings->get("host") .
|
||||
", port: " . self::$settings->get("port") .
|
||||
", log_level: " . ZMBuf::$atomics["info_level"]->get() .
|
||||
", version: " . json_decode(file_get_contents(WORKING_DIR . "/composer.json"), true)["version"] .
|
||||
", version: " . ZM_VERSION .
|
||||
"\nworking_dir: " . DataProvider::getWorkingDir()
|
||||
);
|
||||
global $motd;
|
||||
@@ -130,6 +140,7 @@ class FrameworkLoader
|
||||
private function defineProperties() {
|
||||
define("ZM_START_TIME", microtime(true));
|
||||
define("ZM_DATA", self::$settings->get("zm_data"));
|
||||
define("ZM_VERSION", json_decode(file_get_contents(__DIR__ . "/../../composer.json"), true)["version"] ?? "unknown");
|
||||
define("CONFIG_DIR", self::$settings->get("config_dir"));
|
||||
define("CRASH_DIR", self::$settings->get("crash_dir"));
|
||||
@mkdir(ZM_DATA);
|
||||
|
||||
@@ -8,11 +8,12 @@ use ZM\Context\ContextInterface;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
|
||||
function classLoader($p) {
|
||||
function phar_classloader($p){
|
||||
$filepath = getClassPath($p);
|
||||
if ($filepath === null)
|
||||
echo "F:Warning: get class path wrongs.$p\n";
|
||||
//else echo "F:DBG: Found " . $p . "\n";
|
||||
if($filepath === null) {
|
||||
Console::debug("F:Warning: get class path wrongs.$p");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
require_once $filepath;
|
||||
} catch (Exception $e) {
|
||||
@@ -222,3 +223,5 @@ function zm_timer_tick($ms, callable $callable) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ use ZM\Annotation\Http\Middleware;
|
||||
use ZM\Annotation\Http\RequestMapping;
|
||||
use ZM\Annotation\Swoole\SwooleEventAt;
|
||||
use ZM\Connection\CQConnection;
|
||||
use ZM\ModBase;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
/**
|
||||
@@ -18,7 +17,7 @@ use ZM\Utils\ZMUtil;
|
||||
* @package Module\Example
|
||||
* @since 1.0
|
||||
*/
|
||||
class Hello extends ModBase
|
||||
class Hello
|
||||
{
|
||||
/**
|
||||
* 在机器人连接后向终端输出信息
|
||||
@@ -31,7 +30,7 @@ class Hello extends ModBase
|
||||
|
||||
/**
|
||||
* 向机器人发送"你好",即可回复这句话
|
||||
* @CQCommand("你好")
|
||||
* @CQCommand(match="你好",alias={"你好啊","你是谁"})
|
||||
*/
|
||||
public function hello() {
|
||||
return "你好啊,我是由炸毛框架构建的机器人!";
|
||||
@@ -67,7 +66,6 @@ class Hello extends ModBase
|
||||
* @Middleware("timer")
|
||||
*/
|
||||
public function timer() {
|
||||
eval(ZM_BREAKPOINT);
|
||||
return "This page is used as testing TimerMiddleware! Do not use it in production.";
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ class CQCommand extends AnnotationBase implements Level
|
||||
public $match = "";
|
||||
/** @var string */
|
||||
public $regexMatch = "";
|
||||
/** @var string[] */
|
||||
public $alias = [];
|
||||
/** @var int */
|
||||
public $level = 20;
|
||||
|
||||
@@ -32,4 +34,4 @@ class CQCommand extends AnnotationBase implements Level
|
||||
*/
|
||||
public function setLevel(int $level) { $this->level = $level; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ trait WhereBody
|
||||
protected $where_thing = [];
|
||||
|
||||
public function where($column, $operation_or_value, $value = null) {
|
||||
if (!in_array($operation_or_value, ['=', '!='])) $this->where_thing['='][$column] = $operation_or_value;
|
||||
if (!in_array($operation_or_value, ['=', '!=', '>', '<', '>=', '<=', 'IN', 'in'])) $this->where_thing['='][$column] = $operation_or_value;
|
||||
elseif ($value !== null) $this->where_thing[$operation_or_value][$column] = $value;
|
||||
else $this->where_thing['='][$column] = $operation_or_value;
|
||||
return $this;
|
||||
|
||||
@@ -38,9 +38,9 @@ class MessageEvent
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
public function onBefore() {
|
||||
$obj_list = ZMBuf::$events[CQBefore::class]["message"];
|
||||
$obj_list = ZMBuf::$events[CQBefore::class]["message"] ?? [];
|
||||
foreach ($obj_list as $v) {
|
||||
if($v->level < 200) break;
|
||||
if ($v->level < 200) break;
|
||||
EventHandler::callWithMiddleware(
|
||||
$v->class,
|
||||
$v->method,
|
||||
@@ -65,7 +65,7 @@ class MessageEvent
|
||||
}
|
||||
}
|
||||
foreach (ZMBuf::$events[CQBefore::class]["message"] ?? [] as $v) {
|
||||
if($v->level >= 200) continue;
|
||||
if ($v->level >= 200) continue;
|
||||
$c = $v->class;
|
||||
if (ctx()->getCache("level") != 0) continue;
|
||||
EventHandler::callWithMiddleware(
|
||||
@@ -117,6 +117,13 @@ class MessageEvent
|
||||
return true;
|
||||
});
|
||||
return;
|
||||
} elseif (in_array($word[0], $v->alias)) {
|
||||
Console::debug("Calling $c -> {$v->method}");
|
||||
$this->function_call = EventHandler::callWithMiddleware($obj[$c], $v->method, $class_construct, [$word], function ($r) {
|
||||
if (is_string($r)) context()->reply($r);
|
||||
return true;
|
||||
});
|
||||
return;
|
||||
} 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) {
|
||||
|
||||
@@ -85,7 +85,7 @@ class EventHandler
|
||||
" [" . $param1->getStatusCode() . "] " . $param0->server["request_uri"]
|
||||
);
|
||||
if (!$param1->isEnd()) $param1->end("Internal server error: " . $e->getMessage());
|
||||
Console::error("Internal server error (500), caused by uncaught exception.");
|
||||
Console::error("Internal server exception (500), caused by ".get_class($e));
|
||||
Console::log($e->getTraceAsString(), "gray");
|
||||
} catch (Error $e) {
|
||||
/** @var Response $param1 */
|
||||
|
||||
@@ -42,7 +42,7 @@ class RequestEvent implements SwooleEvent
|
||||
$this->response->setHeader($k, $v);
|
||||
}
|
||||
$uri = $this->request->server["request_uri"];
|
||||
Console::verbose($this->request->server["remote_addr"]." request ".$uri);
|
||||
Console::verbose($this->request->server["remote_addr"] . " request " . $uri);
|
||||
$uri = explode("/", $uri);
|
||||
$uri = array_diff($uri, ["..", "", "."]);
|
||||
$node = ZMBuf::$req_mapping;
|
||||
|
||||
@@ -102,7 +102,7 @@ class WorkerStartEvent implements SwooleEvent
|
||||
->withCharset('utf8mb4')
|
||||
->withUsername($sql["sql_username"])
|
||||
->withPassword($sql["sql_password"])
|
||||
->withOptions([PDO::ATTR_STRINGIFY_FETCHES => false])
|
||||
->withOptions($sql["sql_options"] ?? [PDO::ATTR_STRINGIFY_FETCHES => false])
|
||||
);
|
||||
DB::initTableList();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ class ZMRequest
|
||||
Console::warning("ZMRequest: url must contains scheme such as \"http(s)\"");
|
||||
return false;
|
||||
}
|
||||
if(!isset($parse["path"])) $parse["path"] = "/";
|
||||
$port = $parse["port"] ?? (($parse["scheme"] ?? "http") == "https" ? 443 : 80);
|
||||
$cli = new Client($parse["host"], $port, (($parse["scheme"] ?? "http") == "https" ? true : false));
|
||||
$cli->setHeaders($headers);
|
||||
@@ -60,6 +61,7 @@ class ZMRequest
|
||||
Console::warning("ZMRequest: url must contains scheme such as \"http(s)://\"");
|
||||
return false;
|
||||
}
|
||||
if(!isset($parse["path"])) $parse["path"] = "/";
|
||||
$port = $parse["port"] ?? (($parse["scheme"] ?? "http") == "https" ? 443 : 80);
|
||||
$cli = new Client($parse["host"], $port, (($parse["scheme"] ?? "http") == "https" ? true : false));
|
||||
$cli->set($set == [] ? ['timeout' => 15.0] : $set);
|
||||
@@ -94,4 +96,34 @@ class ZMRequest
|
||||
public static function session($option) {
|
||||
return Saber::session($option);
|
||||
}
|
||||
|
||||
public static function request($url, $attribute = [], $return_body = true) {
|
||||
$parse = parse_url($url);
|
||||
if (!isset($parse["host"])) {
|
||||
Console::warning("ZMRequest: url must contains scheme such as \"http(s)://\"");
|
||||
return false;
|
||||
}
|
||||
if(!isset($parse["path"])) $parse["path"] = "/";
|
||||
$port = $parse["port"] ?? (($parse["scheme"] ?? "http") == "https" ? 443 : 80);
|
||||
$cli = new Client($parse["host"], $port, (($parse["scheme"] ?? "http") == "https" ? true : false));
|
||||
$cli->set($attribute["set"] ?? ["timeout" => 15.0]);
|
||||
$cli->setMethod($attribute["method"] ?? "GET");
|
||||
$cli->setHeaders($attribute["headers"] ?? []);
|
||||
if(isset($attribute["data"])) $cli->setData($attribute["data"]);
|
||||
if(isset($attribute["file"])) {
|
||||
foreach($attribute["file"] as $k => $v) {
|
||||
$cli->addFile($v["path"], $v["name"], $v["mime_type"] ?? null, $v["filename"] ?? null, $v["offset"] ?? 0, $v["length"] ?? 0);
|
||||
}
|
||||
}
|
||||
$cli->execute($parse["path"] . (isset($parse["query"]) ? "?" . $parse["query"] : ""));
|
||||
if ($return_body) {
|
||||
if ($cli->errCode != 0 || $cli->statusCode != 200) return false;
|
||||
$a = $cli->body;
|
||||
$cli->close();
|
||||
return $a;
|
||||
} else {
|
||||
$cli->close();
|
||||
return $cli;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ class ZMWebSocket
|
||||
Console::warning("ZMRequest: url must contains scheme such as \"ws(s)://\"");
|
||||
return;
|
||||
}
|
||||
if (!isset($this->parse["path"])) $this->parse["path"] = "/";
|
||||
$port = $this->parse["port"] ?? (($this->parse["scheme"] ?? "ws") == "wss" ? 443 : 80);
|
||||
$this->client = new Client($this->parse["host"], $port, (($this->parse["scheme"] ?? "ws") == "wss" ? true : false));
|
||||
$this->client->set($set);
|
||||
@@ -85,18 +86,18 @@ class ZMWebSocket
|
||||
}
|
||||
}
|
||||
|
||||
if(!debug_backtrace()) {
|
||||
if (!debug_backtrace()) {
|
||||
go(function () {
|
||||
require_once __DIR__ . "/../../Framework/Console.php";
|
||||
$cli = new ZMWebSocket("ws://127.0.0.1:20001/");
|
||||
if (!$cli->is_available) die("Error!\n");
|
||||
$cli->onMessage(function ($frame){
|
||||
$cli->onMessage(function (Frame $frame) {
|
||||
var_dump($frame);
|
||||
});
|
||||
$cli->onClose(function($client){
|
||||
$cli->onClose(function () {
|
||||
echo "Connection closed.\n";
|
||||
});
|
||||
if($cli->upgrade()){
|
||||
if ($cli->upgrade()) {
|
||||
echo "成功连接!\n";
|
||||
} else {
|
||||
echo "连接失败!\n";
|
||||
|
||||
Reference in New Issue
Block a user