initial 2.0 commit

This commit is contained in:
jerry
2020-08-31 10:11:06 +08:00
parent b6756179f5
commit beb1f5f063
69 changed files with 1237 additions and 2090 deletions

View File

@@ -0,0 +1,81 @@
<?php
namespace ZM\Utils;
use ZM\Config\ZMConfig;
use ZM\Console\Console;
use ZM\Annotation\Swoole\OnSave;
use ZM\Store\ZMBuf;
class DataProvider
{
public static $buffer_list = [];
public static function getResourceFolder() {
return self::getWorkingDir() . '/resources/';
}
public static function getWorkingDir() {
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() {
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;
}
}

View File

@@ -0,0 +1,263 @@
<?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) {
$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) . ')';
}
}

View File

@@ -1,122 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2019/1/5
* Time: 4:48 PM
*/
namespace ZM\Utils;
use framework\Console;
use framework\ZMBuf;
use PDO;
use PDOException;
use SplQueue;
use Swoole\Coroutine;
class SQLPool
{
protected $available = true;
protected $pool;
private $info;
public $co_list = [];
public $connect_cnt = 0;
public function __construct() {
$this->pool = new SplQueue;
$this->info = [
"host" => ZMBuf::globals("sql_config")["sql_host"],
"port" => ZMBuf::globals("sql_config")["sql_port"],
"user" => ZMBuf::globals("sql_config")["sql_username"],
"password" => ZMBuf::globals("sql_config")["sql_password"],
"database" => ZMBuf::globals("sql_config")["sql_database"]
];
Console::debug("新建检测 MySQL 连接的计时器");
zm_timer_tick(10000, function () {
//Console::debug("正在检测是否有坏死的MySQL连接当前连接池有 ".count($this->pool) . " 个连接");
if (count($this->pool) > 0) {
/** @var PDO $cnn */
$cnn = $this->pool->pop();
$this->connect_cnt -= 1;
try {
$cnn->getAttribute(PDO::ATTR_SERVER_INFO);
} catch (PDOException $e) {
if (strpos($e->getMessage(), 'MySQL server has gone away') !== false) {
Console::info("MySQL 长连接丢失,取消连接");
unset($cnn);
return;
}
}
$this->pool->push($cnn);
$this->connect_cnt += 1;
}
});
}
/**
* 将利用过的连接入队
* @param $mysql
*/
public function put($mysql) {
$this->pool->push($mysql);
if (($a = array_shift($this->co_list)) !== null) {
Coroutine::resume($a);
}
}
/**
* 获取队中的连接,如果不存在则创建新的
* @param bool $no_new_conn
* @return bool|mixed|PDO
*/
public function get($no_new_conn = false) {
if (count($this->pool) == 0 && $this->connect_cnt <= 70) {
if ($no_new_conn) return false;
$this->connect_cnt += 1;
$r = $this->newConnect();
if ($r !== false) {
return $r;
} else {
$this->connect_cnt -= 1;
return false;
}
} elseif (count($this->pool) > 0) {
/** @var PDO $con */
$con = $this->pool->pop();
return $con;
} elseif ($this->connect_cnt > 70) {
$this->co_list[] = Coroutine::getuid();
Console::warning("数据库连接过多,协程等待重复利用中...当前协程数 " . Coroutine::stats()["coroutine_num"]);
Coroutine::suspend();
return $this->get($no_new_conn);
}
return false;
}
public function getCount() {
return $this->pool->count();
}
public function destruct() {
// 连接池销毁, 置不可用状态, 防止新的客户端进入常驻连接池, 导致服务器无法平滑退出
$this->available = false;
while (!$this->pool->isEmpty()) {
$this->pool->pop();
}
}
private function newConnect() {
//无空闲连接,创建新连接
$dsn = "mysql:host=" . $this->info["host"] . ";dbname=" . $this->info["database"] . ";charset=utf8";
try {
$mysql = new PDO($dsn, $this->info["user"], $this->info["password"], array(PDO::ATTR_PERSISTENT => true));
} catch (PDOException $e) {
Console::error("PDO Error: " . $e->getMessage());
return false;
}
Console::info("创建SQL连接中当前有" . $this->connect_cnt . "个连接");
return $mysql;
}
}

View File

@@ -1,10 +0,0 @@
<?php
namespace ZM\Utils;
class ScheduleManager
{
//TODO: 写framework部分的schedule控制代码
}

126
src/ZM/Utils/Terminal.php Normal file
View File

@@ -0,0 +1,126 @@
<?php
namespace ZM\Utils;
use Exception;
use ZM\Config\ZMConfig;
use ZM\ConnectionManager\ConnectionObject;
use ZM\Console\Console;
use ZM\Store\ZMBuf;
use ZM\Annotation\Swoole\SwooleEventAt;
class Terminal
{
/**
* @var false|resource
*/
public static $console_proc = null;
public static $pipes = [];
static function listenConsole($terminal_id) {
if ($terminal_id === null) {
if (ZMBuf::$server->worker_id === 0) Console::info("ConsoleCommand disabled.");
return;
}
global $terminal_id;
global $port;
$port = ZMConfig::get("global", "port");
$vss = new SwooleEventAt();
$vss->type = "open";
$vss->level = 256;
$vss->rule = "connectType:terminal";
$vss->callback = function (?ConnectionObject $conn) use ($terminal_id) {
$req = ctx()->getRequest();
if ($conn->getName() != "terminal") return false;
Console::debug("Terminal fd: " . $conn->getFd());
ZMBuf::set("terminal_fd", $conn->getFd());
if (($req->header["x-terminal-id"] ?? "") != $terminal_id) {
ZMBuf::$server->close($conn->getFd());
return false;
}
return false;
};
ZMBuf::$events[SwooleEventAt::class][] = $vss;
$vss2 = new SwooleEventAt();
$vss2->type = "message";
$vss2->rule = "connectType:terminal";
$vss2->callback = function (?ConnectionObject $conn) {
if ($conn === null) return false;
if ($conn->getName() != "terminal") return false;
$cmd = ctx()->getFrame()->data;
self::executeCommand($cmd);
return false;
};
ZMBuf::$events[SwooleEventAt::class][] = $vss2;
if (ZMBuf::$server->worker_id === 0) {
go(function () {
global $terminal_id, $port;
$descriptorspec = array(
0 => STDIN,
1 => STDOUT,
2 => STDERR
);
self::$console_proc = proc_open('php -r \'$terminal_id = "' . $terminal_id . '";$port = ' . $port . ';require "' . __DIR__ . '/terminal_listener.php";\'', $descriptorspec, self::$pipes);
});
}
}
/**
* @param string $cmd
* @return bool
*/
private static function executeCommand(string $cmd) {
$it = explodeMsg($cmd);
switch ($it[0] ?? '') {
case 'logtest':
Console::log(date("[H:i:s]") . " [L] This is normal msg. (0)");
Console::error("This is error msg. (0)");
Console::warning("This is warning msg. (1)");
Console::info("This is info msg. (2)");
Console::success("This is success msg. (2)");
Console::verbose("This is verbose msg. (3)");
Console::debug("This is debug msg. (4)");
return true;
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 'color':
Console::log($it[2], $it[1]);
return true;
case 'stop':
ZMUtil::stop();
return false;
case 'reload':
case 'r':
ZMUtil::reload();
return false;
case 'save':
//$origin = ZMBuf::$atomics["info_level"]->get();
//ZMBuf::$atomics["info_level"]->set(3);
DataProvider::saveBuffer();
//ZMBuf::$atomics["info_level"]->set($origin);
return true;
case '':
return true;
default:
Console::info("Command not found: " . $cmd);
return true;
}
}
}

View File

@@ -4,8 +4,7 @@
namespace ZM\Utils;
use Framework\Console;
use Swlib\Saber;
use ZM\Console\Console;
use Swoole\Coroutine\Http\Client;
class ZMRequest
@@ -79,14 +78,6 @@ class ZMRequest
return new ZMWebSocket($url, $set, $header);
}
/**
* @param $option
* @return Saber
*/
public static function session($option) {
return Saber::session($option);
}
/**
* @param $url
* @param array $attribute

View File

@@ -1,412 +0,0 @@
<?php
namespace ZM\Utils;
use ZM\API\CQAPI;
use ZM\Connection\ConnectionManager;
use ZM\Connection\CQConnection;
use ZM\Exception\RobotNotFoundException;
/**
* Class ZMRobot
* @package ZM\Utils
* @since 1.2
*/
class ZMRobot
{
const API_ASYNC = 1;
const API_NORMAL = 0;
const API_RATE_LIMITED = 2;
private $connection;
private $callback = null;
private $prefix = 0;
/**
* @param $robot_id
* @return ZMRobot
* @throws RobotNotFoundException
*/
public static function get($robot_id) {
$r = ConnectionManager::getByType("qq", ["self_id" => $robot_id]);
if ($r == []) throw new RobotNotFoundException("机器人 " . $robot_id . " 未连接到框架!");
return new ZMRobot($r[0]);
}
/**
* @throws RobotNotFoundException
* @return ZMRobot
*/
public static function getRandom() {
$r = ConnectionManager::getByType("qq");
if($r == []) throw new RobotNotFoundException("没有任何机器人连接到框架!");
return new ZMRobot($r[array_rand($r)]);
}
public function __construct(CQConnection $connection) {
$this->connection = $connection;
}
public function setCallback($callback = true) {
$this->callback = $callback;
return $this;
}
public function setPrefix($prefix = self::API_NORMAL) {
$this->prefix = $prefix;
return $this;
}
public function sendPrivateMsg($user_id, $message, $auto_escape = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'user_id' => $user_id,
'message' => $message,
'auto_escape' => $auto_escape
]
], $this->callback);
}
public function sendGroupMsg($group_id, $message, $auto_escape = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'message' => $message,
'auto_escape' => $auto_escape
]
], $this->callback);
}
public function sendDiscussMsg($discuss_id, $message, $auto_escape = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'discuss_id' => $discuss_id,
'message' => $message,
'auto_escape' => $auto_escape
]
], $this->callback);
}
public function sendMsg($message_type, $target_id, $message, $auto_escape = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'message_type' => $message_type,
($message_type == 'private' ? 'user' : $message_type) . '_id' => $target_id,
'message' => $message,
'auto_escape' => $auto_escape
]
], $this->callback);
}
public function deleteMsg($message_id) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'message_id' => $message_id
]
], $this->callback);
}
public function sendLike($user_id, $times = 1) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'user_id' => $user_id,
'times' => $times
]
], $this->callback);
}
public function setGroupKick($group_id, $user_id, $reject_add_request = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'user_id' => $user_id,
'reject_add_request' => $reject_add_request
]
], $this->callback);
}
public function setGroupBan($group_id, $user_id, $duration = 1800) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'user_id' => $user_id,
'duration' => $duration
]
], $this->callback);
}
public function setGroupAnonymousBan($group_id, $anonymous_or_flag, $duration = 1800) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
(is_string($anonymous_or_flag) ? 'flag' : 'anonymous') => $anonymous_or_flag,
'duration' => $duration
]
], $this->callback);
}
public function setGroupWholeBan($group_id, $enable = true) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'enable' => $enable
]
], $this->callback);
}
public function setGroupAdmin($group_id, $user_id, $enable = true) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'user_id' => $user_id,
'enable' => $enable
]
], $this->callback);
}
public function setGroupAnonymous($group_id, $enable = true) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'enable' => $enable
]
], $this->callback);
}
public function setGroupCard($group_id, $user_id, $card = "") {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'user_id' => $user_id,
'card' => $card
]
], $this->callback);
}
public function setGroupLeave($group_id, $is_dismiss = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'is_dismiss' => $is_dismiss
]
], $this->callback);
}
public function setGroupSpecialTitle($group_id, $user_id, $special_title = "", $duration = -1) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'user_id' => $user_id,
'special_title' => $special_title,
'duration' => $duration
]
], $this->callback);
}
public function setDiscussLeave($discuss_id) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'discuss_id' => $discuss_id
]
], $this->callback);
}
public function setFriendAddRequest($flag, $approve = true, $remark = "") {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'flag' => $flag,
'approve' => $approve,
'remark' => $remark
]
], $this->callback);
}
public function setGroupAddRequest($flag, $sub_type, $approve = true, $reason = "") {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'flag' => $flag,
'sub_type' => $sub_type,
'approve' => $approve,
'reason' => $reason
]
], $this->callback);
}
public function getLoginInfo() {
return CQAPI::processAPI($this->connection, ['action' => $this->getActionName(__FUNCTION__)], $this->callback);
}
public function getStrangerInfo($user_id, $no_cache = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'user_id' => $user_id,
'no_cache' => $no_cache
]
], $this->callback);
}
public function getFriendList() {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__)
], $this->callback);
}
public function getGroupList() {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__)
], $this->callback);
}
public function getGroupInfo($group_id, $no_cache = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'no_cache' => $no_cache
]
], $this->callback);
}
public function getGroupMemberInfo($group_id, $user_id, $no_cache = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'user_id' => $user_id,
'no_cache' => $no_cache
]
], $this->callback);
}
public function getGroupMemberList($group_id) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id
]
]);
}
public function getCookies($domain = "") {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'domain' => $domain
]
]);
}
public function getCsrfToken() {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__)
], $this->callback);
}
public function getCredentials($domain = "") {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'domain' => $domain
]
], $this->callback);
}
public function getRecord($file, $out_format, $full_path = false) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'file' => $file,
'out_format' => $out_format,
'full_path' => $full_path
]
], $this->callback);
}
public function getImage($file) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'file' => $file
]
], $this->callback);
}
public function canSendImage() {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__)
], $this->callback);
}
public function canSendRecord() {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__)
], $this->callback);
}
public function getStatus() {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__)
], $this->callback);
}
public function getVersionInfo() {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__)
], $this->callback);
}
public function setRestartPlugin($delay = 0) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'delay' => $delay
]
], $this->callback);
}
public function cleanDataDir($data_dir) {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__),
'params' => [
'data_dir' => $data_dir
]
], $this->callback);
}
public function cleanPluginLog() {
return CQAPI::processAPI($this->connection, [
'action' => $this->getActionName(__FUNCTION__)
], $this->callback);
}
public function getExperimentAPI() {
return new ZMRobotExperiment($this->connection, $this->callback, $this->prefix);
}
private function getActionName(string $method) {
$prefix = ($this->prefix == self::API_ASYNC ? '_async' : ($this->prefix == self::API_RATE_LIMITED ? '_rate_limited' : ''));
$func_name = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $method));
return $func_name . $prefix;
}
}

View File

@@ -1,104 +0,0 @@
<?php
namespace ZM\Utils;
use ZM\API\CQAPI;
use ZM\Connection\CQConnection;
/**
* Class ZMRobotExperiment
* @package ZM\Utils
* @since 1.2
*/
class ZMRobotExperiment
{
/**
* @var CQConnection
*/
private $connection;
private $callback = null;
private $prefix = 0;
public function __construct(CQConnection $connection, $callback, $prefix) {
$this->connection = $connection;
$this->callback = $callback;
$this->prefix = $prefix;
}
public function setCallback($callback = true) {
$this->callback = $callback;
return $this;
}
public function setPrefix($prefix = ZMRobot::API_NORMAL) {
$this->prefix = $prefix;
return $this;
}
public function getFriendList($flat = false) {
return CQAPI::processAPI($this->connection, [
'action' => '_' . $this->getActionName(__FUNCTION__),
'params' => [
'flat' => $flat
]
], $this->callback);
}
public function getGroupInfo($group_id) {
return CQAPI::processAPI($this->connection, [
'action' => '_' . $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id
]
], $this->callback);
}
public function getVipInfo($user_id) {
return CQAPI::processAPI($this->connection, [
'action' => '_' . $this->getActionName(__FUNCTION__),
'params' => [
'user_id' => $user_id
]
], $this->callback);
}
public function getGroupNotice($group_id) {
return CQAPI::processAPI($this->connection, [
'action' => '_' . $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id
]
], $this->callback);
}
public function sendGroupNotice($group_id, $title, $content) {
return CQAPI::processAPI($this->connection, [
'action' => '_' . $this->getActionName(__FUNCTION__),
'params' => [
'group_id' => $group_id,
'title' => $title,
'content' => $content
]
], $this->callback);
}
public function setRestart($clean_log = false, $clean_cache = false, $clean_event = false) {
return CQAPI::processAPI($this->connection, [
'action' => '_' . $this->getActionName(__FUNCTION__),
'params' => [
'clean_log' => $clean_log,
'clean_cache' => $clean_cache,
'clean_event' => $clean_event
]
], $this->callback);
}
private function getActionName(string $method) {
$prefix = ($this->prefix == ZMRobot::API_ASYNC ? '_async' : ($this->prefix == ZMRobot::API_RATE_LIMITED ? '_rate_limited' : ''));
$func_name = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $method));
return $prefix . $func_name;
}
}

View File

@@ -5,10 +5,10 @@ namespace ZM\Utils;
use Co;
use framework\Console;
use Framework\DataProvider;
use Framework\ZMBuf;
use ZM\Config\ZMConfig;
use ZM\Console\Console;
use ZM\API\CQ;
use ZM\Store\ZMBuf;
class ZMUtil
{
@@ -34,8 +34,8 @@ class ZMUtil
}
public static function getHttpCodePage(int $http_code) {
if (isset(ZMBuf::globals("http_default_code_page")[$http_code])) {
return Co::readFile(DataProvider::getResourceFolder() . "html/" . ZMBuf::globals("http_default_code_page")[$http_code]);
if (isset(ZMConfig::get("global", "http_default_code_page")[$http_code])) {
return Co::readFile(DataProvider::getResourceFolder() . "html/" . ZMConfig::get("global", "http_default_code_page")[$http_code]);
} else return null;
}
@@ -51,20 +51,10 @@ class ZMUtil
ZMBuf::$server->reload();
}
/**
* 解析CQ码
* @param $msg
* @return array|null
*/
static function getCQ($msg) {
return CQ::getCQ($msg);
}
public static function getModInstance($class) {
if (!isset(ZMBuf::$instance[$class])) {
Console::debug("Class instance $class not exist, so I created it.");
ZMBuf::$instance[$class] = new $class();
return ZMBuf::$instance[$class];
return ZMBuf::$instance[$class] = new $class();
} else {
return ZMBuf::$instance[$class];
}

View File

@@ -4,7 +4,7 @@
namespace ZM\Utils;
use Framework\Console;
use ZM\Console\Console;
use Swoole\Coroutine\Http\Client;
use Swoole\WebSocket\Frame;

View File

@@ -0,0 +1,33 @@
<?php
use Swoole\Coroutine\Http\Client;
Co\run(function (){
hello:
global $terminal_id, $port;
$client = new Client("127.0.0.1", $port);
$client->set(['websocket_mask' => true]);
$client->setHeaders(["x-terminal-id" => $terminal_id, 'x-pid' => posix_getppid()]);
$ret = $client->upgrade("/?type=terminal");
if ($ret) {
while (true) {
$line = fgets(STDIN);
if ($line !== false) {
$r = $client->push(trim($line));
if (trim($line) == "reload" || trim($line) == "r" || trim($line) == "stop") {
break;
}
if($r === false) {
echo "Unable to connect framework terminal, connection closed. Trying to reconnect after 5s.\n";
sleep(5);
goto hello;
}
} else {
break;
}
}
} else {
echo "Unable to connect framework terminal. port: $port\n";
}
});