mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-03-18 05:04:51 +08:00
update to 1.5 version
This commit is contained in:
parent
a8183757be
commit
59fde3d075
@ -2,7 +2,7 @@
|
||||
|
||||
[]()
|
||||
[](https://github.com/zhamao-robot/zhamao-framework/blob/master/LICENSE)
|
||||
[]()
|
||||
[]()
|
||||
|
||||
[](https://github.com/zhamao-robot/zhamao-framework/search?q=stupid)
|
||||
[](https://github.com/zhamao-robot/zhamao-framework/search?q=TODO)
|
||||
@ -19,8 +19,9 @@ zhamao-framework 是一个基于 酷Q 的 PHP Swoole 的机器人框架,它会
|
||||
除了起到解析消息的作用,炸毛框架 还提供了完整的 WebSocket + HTTP 服务器,你还能用此框架构建出高性能的 API 接口服务器。
|
||||
|
||||
## 开始
|
||||
1. 你可以使用项目的 `Use this template` 功能将框架克隆到你的公开或私有仓库进行开发
|
||||
2. 你也可以直接到 **Release** 中下载最新的 phar 包,放入文件夹后快速启动框架
|
||||
先安装环境,环境安装见下方文档。
|
||||
1. `composer create-project zhamao/framework-starter` 从模板新建基础文档结构进行使用
|
||||
2. 你也可以直接到 **Release** 中下载最新的 phar 包,放入文件夹后 `php server.phar` 快速启动框架
|
||||
3. 还可以使用 Dockerfile 构建 Docker 容器
|
||||
|
||||
## 文档
|
||||
|
||||
File diff suppressed because one or more lines are too long
26
bin/start
26
bin/start
@ -10,6 +10,14 @@ require __DIR__ . '/../src/Scheduler/Scheduler.php';
|
||||
Swoole\Coroutine::set([
|
||||
'max_coroutine' => 30000,
|
||||
]);
|
||||
global $vendor_mode;
|
||||
$vendor_mode = false;
|
||||
if (mb_strpos(__DIR__, getcwd()) !== false && substr(str_replace(getcwd(), "", __DIR__), 0, 8) == "/vendor/") {
|
||||
define("LOAD_MODE", 1); //composer项目模式
|
||||
define("LOAD_MODE_COMPOSER_PATH", getcwd());
|
||||
} else {
|
||||
define("LOAD_MODE", 0); //正常模式
|
||||
}
|
||||
|
||||
date_default_timezone_set("Asia/Shanghai");
|
||||
|
||||
@ -24,13 +32,21 @@ switch ($argv[1] ?? '') {
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'phar-build':
|
||||
array_shift($argv);
|
||||
require_once 'phar-build';
|
||||
break;
|
||||
case 'systemd':
|
||||
array_shift($argv);
|
||||
require_once 'systemd';
|
||||
break;
|
||||
case '':
|
||||
case 'framework':
|
||||
case 'server':
|
||||
if(!is_dir(__DIR__.'/../vendor/')){
|
||||
if (!is_dir(__DIR__ . '/../vendor/') && LOAD_MODE == 0) {
|
||||
echo "Warning: you have not update composer!\n";
|
||||
exec("composer update", $out, $var);
|
||||
if($var != 0) {
|
||||
if ($var != 0) {
|
||||
echo "You need to run \"composer update\" at root of zhamao-framework!\n";
|
||||
die;
|
||||
}
|
||||
@ -39,10 +55,12 @@ switch ($argv[1] ?? '') {
|
||||
break;
|
||||
case '--help':
|
||||
case '-h':
|
||||
echo "\nUsage: ".$argv[0]." [OPTION]\n";
|
||||
echo "\nUsage: " . $argv[0] . " [OPTION]\n";
|
||||
echo "\nzhamao-framework start script, provides several startup arguments.";
|
||||
echo "\n\n -h, --help\t\tShow this help menu";
|
||||
echo "\n framework, server\tstart main framework, this is default option\n\n";
|
||||
echo "\n framework, server\tstart main framework, this is default option";
|
||||
echo "\n phar-build\t\tbuild a new phar archive";
|
||||
echo "\n systemd\t\tgenerate a new systemd \".service\" file to use\n\n";
|
||||
break;
|
||||
default:
|
||||
echo "Unknown option \"{$argv[1]}\"!\n\"--help\" for more information\n";
|
||||
|
||||
11
bin/systemd
11
bin/systemd
@ -2,7 +2,8 @@
|
||||
<?php /** @since 1.2 */
|
||||
switch ($argv[1] ?? '') {
|
||||
case '--generate':
|
||||
generate();
|
||||
case '':
|
||||
generate($argv);
|
||||
break;
|
||||
case '--help':
|
||||
case '-h':
|
||||
@ -14,13 +15,17 @@ switch ($argv[1] ?? '') {
|
||||
break;
|
||||
}
|
||||
|
||||
function generate() {
|
||||
function generate($argv) {
|
||||
$s = "[Unit]\nDescription=zhamao-framework Daemon\nAfter=rc-local.service\n\n[Service]\nType=simple";
|
||||
$s .= "\nUser=" . exec("whoami");
|
||||
$s .= "\nGroup=" . exec("groups | awk '{print $1}'");
|
||||
$s .= "\nWorkingDirectory=" . getcwd();
|
||||
$s .= "\nExecStart=" . getcwd() . "/bin/start server --disable-console-input";
|
||||
if ($argv[0] == "systemd" && !file_exists(getcwd() . '/systemd'))
|
||||
$s .= "\nExecStart=" . getcwd() . "/vendor/bin/start server --disable-console-input";
|
||||
else
|
||||
$s .= "\nExecStart=" . getcwd() . "/bin/start server --disable-console-input";
|
||||
$s .= "\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n";
|
||||
@mkdir(getcwd() . "/resources/");
|
||||
file_put_contents(getcwd() . "/resources/zhamao.service", $s);
|
||||
echo "File successfully generated. Path: " . getcwd() . "/resources/zhamao.service\n";
|
||||
}
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
composer update
|
||||
@ -3,7 +3,7 @@
|
||||
"description": "high-performance intelligent assistant",
|
||||
"minimum-stability": "stable",
|
||||
"license": "Apache-2.0",
|
||||
"version": "1.4.1",
|
||||
"version": "1.5",
|
||||
"authors": [
|
||||
{
|
||||
"name": "whale",
|
||||
@ -14,6 +14,10 @@
|
||||
"email": "hugo_swift@yahoo.com"
|
||||
}
|
||||
],
|
||||
"prefer-stable": true,
|
||||
"bin": [
|
||||
"bin/start"
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"swoole/ide-helper": "@dev",
|
||||
@ -25,11 +29,5 @@
|
||||
"ext-ctype": "*",
|
||||
"ext-pdo": "*",
|
||||
"psy/psysh": "@stable"
|
||||
},
|
||||
"repositories": {
|
||||
"packagist": {
|
||||
"type": "composer",
|
||||
"url": "https://mirrors.aliyun.com/composer/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ $config['http_reverse_link'] = "http://127.0.0.1:".$config['port'];
|
||||
$config['debug_mode'] = false;
|
||||
|
||||
/** 存放框架内文件数据的目录 */
|
||||
$config['zm_data'] = WORKING_DIR.'/zm_data/';
|
||||
$config['zm_data'] = realpath(__DIR__ . "/../").'/zm_data/';
|
||||
|
||||
/** 存放各个模块配置文件的目录 */
|
||||
$config['config_dir'] = $config['zm_data'].'config/';
|
||||
@ -73,7 +73,7 @@ $config['context_class'] = \ZM\Context\Context::class;
|
||||
/** 静态文件访问 */
|
||||
$config['static_file_server'] = [
|
||||
'status' => false,
|
||||
'document_root' => WORKING_DIR . '/resources/html',
|
||||
'document_root' => realpath(__DIR__ . "/../") . '/resources/html',
|
||||
'document_index' => [
|
||||
'index.html'
|
||||
]
|
||||
|
||||
@ -30,6 +30,8 @@ Swoole\Coroutine::set([
|
||||
date_default_timezone_set("Asia/Shanghai");
|
||||
|
||||
define('WORKING_DIR', __DIR__);
|
||||
define('FRAMEWORK_DIR', __DIR__);
|
||||
define('LOAD_MODE', 2);
|
||||
|
||||
$s = new FrameworkLoader($argv);
|
||||
|
||||
|
||||
@ -15,12 +15,10 @@ class DataProvider
|
||||
}
|
||||
|
||||
public static function getWorkingDir() {
|
||||
global $is_phar;
|
||||
if ($is_phar === true) {
|
||||
return realpath('.');
|
||||
} else {
|
||||
return WORKING_DIR;
|
||||
}
|
||||
if(LOAD_MODE == 0) return WORKING_DIR;
|
||||
elseif (LOAD_MODE == 1) return LOAD_MODE_COMPOSER_PATH;
|
||||
elseif (LOAD_MODE == 2) return realpath('.');
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getDataConfig() {
|
||||
|
||||
@ -42,11 +42,9 @@ class FrameworkLoader
|
||||
|
||||
|
||||
$this->requireGlobalFunctions();
|
||||
if (!isPharMode()) {
|
||||
define('WORKING_DIR', getcwd());
|
||||
} else {
|
||||
echo "Phar mode: " . WORKING_DIR . PHP_EOL;
|
||||
}
|
||||
if (LOAD_MODE == 0) define("WORKING_DIR", getcwd());
|
||||
elseif(LOAD_MODE == 1) define("WORKING_DIR", realpath(__DIR__ . "/../../"));
|
||||
elseif (LOAD_MODE == 2) echo "Phar mode: " . WORKING_DIR . PHP_EOL;
|
||||
$this->registerAutoloader('classLoader');
|
||||
self::$settings = new GlobalConfig();
|
||||
if (self::$settings->get("debug_mode") === true) {
|
||||
@ -66,7 +64,6 @@ class FrameworkLoader
|
||||
$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");
|
||||
$settings = self::$settings->get("swoole");
|
||||
if (in_array("--daemon", $args)) {
|
||||
$settings["daemonize"] = 1;
|
||||
@ -93,6 +90,7 @@ class FrameworkLoader
|
||||
EventHandler::callSwooleEvent("close", $server, $fd);
|
||||
});
|
||||
ZMBuf::initAtomic();
|
||||
if (in_array("--remote-shell", $args)) RemoteShell::listen($this->server, "127.0.0.1");
|
||||
if (in_array("--log-error", $args)) ZMBuf::$atomics["info_level"]->set(0);
|
||||
if (in_array("--log-warning", $args)) ZMBuf::$atomics["info_level"]->set(1);
|
||||
if (in_array("--log-info", $args)) ZMBuf::$atomics["info_level"]->set(2);
|
||||
@ -103,7 +101,7 @@ class FrameworkLoader
|
||||
", port: " . self::$settings->get("port") .
|
||||
", log_level: " . ZMBuf::$atomics["info_level"]->get() .
|
||||
", version: " . json_decode(file_get_contents(WORKING_DIR . "/composer.json"), true)["version"] .
|
||||
"\nworking_dir: " . (isPharMode() ? realpath('.') : WORKING_DIR)
|
||||
"\nworking_dir: " . DataProvider::getWorkingDir()
|
||||
);
|
||||
global $motd;
|
||||
if (!file_exists(DataProvider::getWorkingDir() . "/config/motd.txt")) {
|
||||
|
||||
@ -7,9 +7,6 @@ use Swoole\Coroutine\System;
|
||||
use ZM\Context\ContextInterface;
|
||||
use ZM\Utils\ZMUtil;
|
||||
|
||||
function isPharMode() {
|
||||
return substr(__DIR__, 0, 7) == 'phar://';
|
||||
}
|
||||
|
||||
function classLoader($p) {
|
||||
$filepath = getClassPath($p);
|
||||
@ -72,6 +69,7 @@ function unicode_decode($str) {
|
||||
* @return array
|
||||
*/
|
||||
function getAllClasses($dir, $indoor_name) {
|
||||
if(!is_dir($dir)) return [];
|
||||
$list = scandir($dir);
|
||||
$classes = [];
|
||||
unset($list[0], $list[1]);
|
||||
|
||||
@ -67,6 +67,7 @@ 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.";
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,16 @@ class SelectBody
|
||||
*/
|
||||
public function get() { return $this->fetchAll(); }
|
||||
|
||||
/**
|
||||
* @throws DbException
|
||||
*/
|
||||
public function count() {
|
||||
$this->select_thing = ["count(*)"];
|
||||
$str = $this->queryPrepare();
|
||||
$this->result = DB::rawQuery($str[0], $str[1]);
|
||||
return intval($this->result[0]["count(*)"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
* @throws DbException
|
||||
|
||||
@ -42,6 +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);
|
||||
$uri = explode("/", $uri);
|
||||
$uri = array_diff($uri, ["..", "", "."]);
|
||||
$node = ZMBuf::$req_mapping;
|
||||
|
||||
@ -7,6 +7,7 @@ namespace ZM\Event\Swoole;
|
||||
use Co;
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use Exception;
|
||||
use PDO;
|
||||
use ReflectionException;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Database\PDOConfig;
|
||||
@ -101,6 +102,7 @@ class WorkerStartEvent implements SwooleEvent
|
||||
->withCharset('utf8mb4')
|
||||
->withUsername($sql["sql_username"])
|
||||
->withPassword($sql["sql_password"])
|
||||
->withOptions([PDO::ATTR_STRINGIFY_FETCHES => false])
|
||||
);
|
||||
DB::initTableList();
|
||||
}
|
||||
@ -180,7 +182,7 @@ class WorkerStartEvent implements SwooleEvent
|
||||
if (file_exists(DataProvider::getWorkingDir() . "/vendor/autoload.php")) {
|
||||
require_once DataProvider::getWorkingDir() . "/vendor/autoload.php";
|
||||
}
|
||||
if (isPharMode()) require_once WORKING_DIR . "/vendor/autoload.php";
|
||||
if (LOAD_MODE == 2) require_once FRAMEWORK_DIR . "/vendor/autoload.php";
|
||||
|
||||
//加载各个模块的注解类,以及反射
|
||||
Console::info("检索Module中");
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
namespace ZM\Utils;
|
||||
|
||||
|
||||
use Framework\Console;
|
||||
use Swlib\Saber;
|
||||
use Swoole\Coroutine\Http\Client;
|
||||
|
||||
@ -11,18 +12,23 @@ class ZMRequest
|
||||
{
|
||||
/**
|
||||
* 使用Swoole协程客户端发起HTTP GET请求
|
||||
* @version 1.1
|
||||
* 返回请求后的body
|
||||
* 如果请求失败或返回状态不是200,则返回 false
|
||||
* @param $url
|
||||
* @param array $headers
|
||||
* @param array $set
|
||||
* @param bool $return_body
|
||||
* @return bool|string|Client
|
||||
* @version 1.1
|
||||
* 返回请求后的body
|
||||
* 如果请求失败或返回状态不是200,则返回 false
|
||||
*/
|
||||
public static function get($url, $headers = [], $set = [], $return_body = true) {
|
||||
$parse = parse_url($url);
|
||||
$cli = new Client($parse["host"], ($parse["scheme"] == "https" ? 443 : (isset($parse["port"]) ? $parse["port"] : 80)), ($parse["scheme"] == "https" ? true : false));
|
||||
if (!isset($parse["host"])) {
|
||||
Console::warning("ZMRequest: url must contains scheme such as \"http(s)\"");
|
||||
return false;
|
||||
}
|
||||
$port = $parse["port"] ?? (($parse["scheme"] ?? "http") == "https" ? 443 : 80);
|
||||
$cli = new Client($parse["host"], $port, (($parse["scheme"] ?? "http") == "https" ? true : false));
|
||||
$cli->setHeaders($headers);
|
||||
$cli->set($set == [] ? ['timeout' => 15.0] : $set);
|
||||
$cli->get($parse["path"] . (isset($parse["query"]) ? "?" . $parse["query"] : ""));
|
||||
@ -50,7 +56,12 @@ class ZMRequest
|
||||
*/
|
||||
public static function post($url, array $header, $data, $set = [], $return_body = true) {
|
||||
$parse = parse_url($url);
|
||||
$cli = new Client($parse["host"], ($parse["scheme"] == "https" ? 443 : (isset($parse["port"]) ? $parse["port"] : 80)), ($parse["scheme"] == "https" ? true : false));
|
||||
if (!isset($parse["host"])) {
|
||||
Console::warning("ZMRequest: url must contains scheme such as \"http(s)://\"");
|
||||
return false;
|
||||
}
|
||||
$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);
|
||||
$cli->setHeaders($header);
|
||||
$cli->post($parse["path"] . (isset($parse["query"]) ? ("?" . $parse["query"]) : ""), $data);
|
||||
@ -65,6 +76,17 @@ class ZMRequest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @param array $set
|
||||
* @param array $header
|
||||
* @return ZMWebSocket
|
||||
* @since 1.5
|
||||
*/
|
||||
public static function websocket($url, $set = ['websocket_mask' => true], $header = []) {
|
||||
return new ZMWebSocket($url, $set, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $option
|
||||
* @return Saber
|
||||
@ -72,4 +94,4 @@ class ZMRequest
|
||||
public static function session($option) {
|
||||
return Saber::session($option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
105
src/ZM/Utils/ZMWebSocket.php
Normal file
105
src/ZM/Utils/ZMWebSocket.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace ZM\Utils;
|
||||
|
||||
|
||||
use Framework\Console;
|
||||
use Swoole\Coroutine\Http\Client;
|
||||
use Swoole\WebSocket\Frame;
|
||||
|
||||
/**
|
||||
* Class ZMWebSocket
|
||||
* @package ZM\Utils
|
||||
* @since 1.5
|
||||
*/
|
||||
class ZMWebSocket
|
||||
{
|
||||
private $parse;
|
||||
private $client;
|
||||
|
||||
public $is_available = false;
|
||||
|
||||
private $close_func;
|
||||
private $message_func;
|
||||
|
||||
public function __construct($url, $set = ['websocket_mask' => true], $header = []) {
|
||||
$this->parse = parse_url($url);
|
||||
if (!isset($this->parse["host"])) {
|
||||
Console::warning("ZMRequest: url must contains scheme such as \"ws(s)://\"");
|
||||
return;
|
||||
}
|
||||
$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);
|
||||
if ($header != []) $this->client->setHeaders($header);
|
||||
$this->is_available = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function upgrade() {
|
||||
if (!$this->is_available) return false;
|
||||
$r = $this->client->upgrade($this->parse["path"] . (isset($this->parse["query"]) ? ("?" . $this->parse["query"]) : ""));
|
||||
if ($r) {
|
||||
go(function () {
|
||||
while (true) {
|
||||
$result = $this->client->recv(60);
|
||||
if ($result === false) {
|
||||
if ($this->client->connected === false) {
|
||||
go(function () {
|
||||
call_user_func($this->close_func, $this->client);
|
||||
});
|
||||
break;
|
||||
}
|
||||
} elseif ($result instanceof Frame) {
|
||||
go(function () use ($result) {
|
||||
$this->is_available = false;
|
||||
call_user_func($this->message_func, $result, $this->client);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callable
|
||||
* @return $this
|
||||
*/
|
||||
public function onMessage(callable $callable) {
|
||||
$this->message_func = $callable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callable
|
||||
* @return $this
|
||||
*/
|
||||
public function onClose(callable $callable) {
|
||||
$this->close_func = $callable;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
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){
|
||||
var_dump($frame);
|
||||
});
|
||||
$cli->onClose(function($client){
|
||||
echo "Connection closed.\n";
|
||||
});
|
||||
if($cli->upgrade()){
|
||||
echo "成功连接!\n";
|
||||
} else {
|
||||
echo "连接失败!\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user