mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-03-17 20:54:52 +08:00
重构完成
This commit is contained in:
parent
76dd436093
commit
0ff0feabca
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,3 +6,6 @@
|
||||
.idea
|
||||
out
|
||||
gen
|
||||
config/
|
||||
cq_data/
|
||||
composer.lock
|
||||
15
cqbot.json
Normal file
15
cqbot.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"robot_name": "CQBot",
|
||||
"framework_version": "1.0.0",
|
||||
"cqbot_version": "1.0.0",
|
||||
"config_dir": "cq_data\/config\/",
|
||||
"crash_dir": "cq_data\/crash\/",
|
||||
"user_dir": "cq_data/users\/",
|
||||
"cq_data": "cq_data\/",
|
||||
"admin_group": "",
|
||||
"host": "",
|
||||
"port": "",
|
||||
"access_token": "",
|
||||
"info_level": 0,
|
||||
"admin": []
|
||||
}
|
||||
@ -20,46 +20,38 @@ class CQBot
|
||||
public $starttime;
|
||||
public $endtime;
|
||||
public $current_id;
|
||||
public $circle;
|
||||
|
||||
public function __construct(Framework $framework, $package) {
|
||||
public function __construct(Framework $framework, $circle, $package) {
|
||||
$this->circle = $circle;
|
||||
$this->starttime = microtime(true);
|
||||
$this->framework = $framework;
|
||||
if ($package === null) return;
|
||||
$this->data = $package;
|
||||
$this->current_id = $this->data["self_id"];
|
||||
if ($package["post_type"] == "message") {
|
||||
try {
|
||||
$this->callTask($package);
|
||||
} catch (\Exception $e) {
|
||||
CQUtil::errorLog("请求执行任务时异常\n" . $e->getMessage(), $this->current_id);
|
||||
CQUtil::sendDebugMsg("引起异常的消息:\n" . $package["message"], $this->current_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function execute($it) {
|
||||
|
||||
}
|
||||
|
||||
public function callTask($it){
|
||||
if ($this->data["post_type"] == "message") {
|
||||
foreach(Buffer::get("mods") as $v){
|
||||
Console::info("Activating module ".$v);
|
||||
/** @var ModBase $w */
|
||||
$w = new $v($this, $this->data);
|
||||
if($w->call_task === false){
|
||||
$msg = trim($this->data["message"]);
|
||||
$msg = explode(" ", $msg);
|
||||
$prefix = Buffer::get("cmd_prefix");
|
||||
if($prefix != ""){
|
||||
if(mb_substr($msg[0],0,mb_strlen($prefix)) == $prefix){
|
||||
$msg[0] = mb_substr($msg[0], mb_strlen($prefix));
|
||||
}
|
||||
}
|
||||
$w->execute($msg);
|
||||
}
|
||||
public function execute() {
|
||||
if ($this->circle >= 5) return false;
|
||||
if ($this->data === null) return false;
|
||||
if (isset($it["user_id"]) && CQUtil::isRobot($this->data["user_id"])) return false;
|
||||
if (isset($it["group_id"]) && $this->data["group_id"] == Buffer::get("admin_group")) {
|
||||
if ($this->getRobotId() != Buffer::get("admin_active")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($this->data["message"] == "")
|
||||
return false;
|
||||
foreach (Buffer::get("mods") as $v) {
|
||||
/** @var ModBase $r */
|
||||
$r = new $v($this, $this->data);
|
||||
if ($r->function_call === false) {
|
||||
$msg = trim($this->data["message"]);
|
||||
$msg = explode(" ", $msg);
|
||||
$r->execute($msg);
|
||||
}
|
||||
}
|
||||
$this->endtime = microtime(true);
|
||||
return $this->function_called;
|
||||
}
|
||||
|
||||
public function reply($msg){
|
||||
@ -102,7 +94,7 @@ class CQBot
|
||||
}
|
||||
|
||||
public function isAdmin($user){
|
||||
if (in_array($user, Buffer::get("su"))) return true;
|
||||
if (in_array($user, Buffer::get("admin"))) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
@ -149,4 +141,12 @@ class CQBot
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前机器人的id
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRobotId() {
|
||||
return $this->data["self_id"] ?? null;
|
||||
}
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/5/26
|
||||
* Time: 下午4:04
|
||||
*/
|
||||
|
||||
class WSMessageEvent extends Event
|
||||
{
|
||||
public function __construct(swoole_websocket_server $server, swoole_websocket_frame $frame) {
|
||||
$req = json_decode($frame->data, true);
|
||||
if (isset($req["echo"])) if (APIHandler::execute($req["echo"], $req)) return;
|
||||
//echo Console::setColor(json_encode($req, 128|256), "gold");
|
||||
if (isset($req["echo"]["type"]) && $req["echo"]["type"] == "handshake") {
|
||||
$fd_id = $frame->fd;
|
||||
$req["user_id"] = $req["data"]["user_id"];
|
||||
$connect = CQUtil::getConnection($fd_id);
|
||||
$connect->setQQ($req["user_id"]);
|
||||
$connect->setType(1);
|
||||
$connect->findSub();
|
||||
if ($data = file(CONFIG_DIR . "log/last_error.log")) {
|
||||
$last_time = file_get_contents(CONFIG_DIR . "log/error_flag");
|
||||
if (time() - $last_time < 2) {
|
||||
CQUtil::sendDebugMsg("检测到重复引起异常,停止服务器", $req["user_id"], 0);
|
||||
file_put_contents(CONFIG_DIR . "log/last_error.log", "");
|
||||
$this->getFramework()->event->shutdown();
|
||||
return;
|
||||
}
|
||||
CQUtil::sendDebugMsg("检测到异常", $req["user_id"], 0);
|
||||
$msg = "";
|
||||
foreach ($data as $e) {
|
||||
$msg = $msg . $e . "\n";
|
||||
}
|
||||
CQUtil::sendDebugMsg($msg, strval($req["user_id"]), 0);
|
||||
CQUtil::sendDebugMsg("[CQBot] 成功开启!", $req["user_id"], 0);
|
||||
file_put_contents(CONFIG_DIR . "error_flag", time());
|
||||
file_put_contents(CONFIG_DIR . "last_error.log", "");
|
||||
} else {
|
||||
Console::info("监测到API连接,已经完成初始化!");
|
||||
CQUtil::sendDebugMsg("[CQBot] 成功开启!", $req["user_id"], 0);
|
||||
}
|
||||
CQUtil::sendAPI($frame->fd, "_get_friend_list", ["get_friend_list"]);
|
||||
CQUtil::sendAPI($frame->fd, "get_group_list", ["get_group_list"]);
|
||||
CQUtil::sendAPI($frame->fd, "get_version_info", ["get_version_info"]);
|
||||
return;
|
||||
}
|
||||
$connect = CQUtil::getConnection($frame->fd);
|
||||
switch ($connect->getType()) {
|
||||
case 0:
|
||||
$connect->setQQ($req["self_id"]);
|
||||
$connect->findSub();
|
||||
$in_count = Buffer::$in_count->get();
|
||||
Buffer::$in_count->add(1);
|
||||
if (Buffer::$data["info_level"] == 2) {
|
||||
Console::put("************EVENT RECEIVED***********");
|
||||
Console::put("msg_id = " . $in_count);
|
||||
Console::put("worker_id = " . $server->worker_id);
|
||||
}
|
||||
if (Buffer::$data["info_level"] >= 1) {
|
||||
$type = $req["post_type"] == "message" ? ($req["message_type"] == "group" ? "GROUP_MSG:" . $req["group_id"] : ($req["message_type"] == "private" ? "PRIVATE_MSG" : "DISCUSS_MSG:" . $req["discuss_id"])) : strtoupper($req["post_type"]);
|
||||
Console::put(Console::setColor(date("H:i:s"), "green") . Console::setColor(" [$in_count]" . $type, "lightlightblue") . Console::setColor(" " . $req["user_id"], "yellow") . Console::setColor(" > ", "gray") . ($req["post_type"] == "message" ? $req["message"] : Console::setColor(CQUtil::executeType($req), "gold")));
|
||||
}
|
||||
//传入业务逻辑:CQBot
|
||||
try {
|
||||
$c = new CQBot($this->getFramework(), $req);
|
||||
$c->endtime = microtime(true);
|
||||
$value = $c->endtime - $c->starttime;
|
||||
Console::debug("Using time: " . $value);
|
||||
if (Buffer::get("time_send") === true)
|
||||
CQUtil::sendDebugMsg("Using time: " . $value, $req["self_id"]);
|
||||
} catch (Exception $e) {
|
||||
CQUtil::errorlog("处理消息时异常,消息处理中断\n" . $e->getMessage() . "\n" . $e->getTraceAsString(), $req["self_id"]);
|
||||
CQUtil::sendDebugMsg("引起异常的消息:\n" . var_export($req, true), $req['self_id']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/5/26
|
||||
* Time: 下午4:10
|
||||
*/
|
||||
|
||||
class WSOpenEvent extends Event
|
||||
{
|
||||
public function __construct(swoole_websocket_server $server, swoole_http_request $request) {
|
||||
$fd = $request->fd;
|
||||
//Console::info("收到连接:".$fd);
|
||||
CQUtil::getConnection($fd);
|
||||
}
|
||||
}
|
||||
31
src/cqbot/event/post/MessageEvent.php
Normal file
31
src/cqbot/event/post/MessageEvent.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/10/15
|
||||
* Time: 10:35 AM
|
||||
*/
|
||||
|
||||
class MessageEvent extends Event
|
||||
{
|
||||
public function __construct($req) {
|
||||
if (CQUtil::isRobot($req["user_id"])) return;
|
||||
|
||||
$in_count = Buffer::$in_count->get();
|
||||
Buffer::$in_count->add(1);
|
||||
if (Buffer::$data["info_level"] >= 1) {
|
||||
$num = CQUtil::getRobotNum($req["self_id"]);
|
||||
$type = $req["post_type"] == "message" ? ($req["message_type"] == "group" ? "GROUP_MSG" . $num . ":" . $req["group_id"] : ($req["message_type"] == "private" ? "PRIVATE_MSG" . $num : "DISCUSS_MSG" . $num . ":" . $req["discuss_id"])) : strtoupper($req["post_type"]);
|
||||
Console::put(Console::setColor(date("H:i:s"), "green") . Console::setColor(" [$in_count]" . $type, "lightlightblue") . Console::setColor(" " . $req["user_id"], "yellow") . Console::setColor(" > ", "gray") . $req["message"]);
|
||||
}
|
||||
|
||||
CQUtil::updateMsg();//更新消息速度
|
||||
|
||||
//传入消息处理的逻辑
|
||||
$c = new CQBot($this->getFramework(), 0, $req);
|
||||
$c->execute();
|
||||
$value = $c->endtime - $c->starttime;
|
||||
Console::debug("Using time: " . $value);
|
||||
|
||||
}
|
||||
}
|
||||
29
src/cqbot/event/post/MetaEvent.php
Normal file
29
src/cqbot/event/post/MetaEvent.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/10/15
|
||||
* Time: 11:06 AM
|
||||
*/
|
||||
|
||||
class MetaEvent extends Event
|
||||
{
|
||||
public function __construct($req) {
|
||||
switch ($req["meta_event_type"]) {
|
||||
case "lifecycle":
|
||||
//插件生命周期事件
|
||||
switch ($req["sub_type"]) {
|
||||
case "enable":
|
||||
Console::info("机器人" . $req["self_id"] . "的HTTP插件" . Console::setColor("启动", "green") . "运行");
|
||||
break;
|
||||
case "disable":
|
||||
Console::info("机器人" . $req["self_id"] . "的HTTP插件" . Console::setColor("停止", "red") . "运行");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "heartbeat":
|
||||
//处理心跳包中的status事件目前炸毛不需要。
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/cqbot/event/post/NoticeEvent.php
Normal file
14
src/cqbot/event/post/NoticeEvent.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/10/15
|
||||
* Time: 10:36 AM
|
||||
*/
|
||||
|
||||
class NoticeEvent extends Event
|
||||
{
|
||||
public function __construct($req) {
|
||||
|
||||
}
|
||||
}
|
||||
47
src/cqbot/event/post/RequestEvent.php
Normal file
47
src/cqbot/event/post/RequestEvent.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/10/15
|
||||
* Time: 10:36 AM
|
||||
*/
|
||||
|
||||
class RequestEvent extends Event
|
||||
{
|
||||
public function __construct($req) {
|
||||
switch ($req["request_type"]) {
|
||||
case "friend":
|
||||
//好友添加请求处理
|
||||
$comment = $req["comment"];//验证信息
|
||||
$flag = $req["flag"];//添加好友用的flag,用于处理好友
|
||||
$user_id = $req["user_id"];
|
||||
|
||||
//如果不需要将好友添加信息发到群里,请注释下面这行
|
||||
CQUtil::sendDebugMsg("有用户请求添加好友啦!\n用户QQ:" . $user_id . "\n验证信息:" . $comment . "\n添加flag:" . $flag, $req["self_id"], 0);
|
||||
|
||||
//如果不需要要自动同意,请注释下面这几行
|
||||
$params = ["flag" => $flag, "approve" => true];
|
||||
CQUtil::sendAPI(CQUtil::getApiConnectionByQQ($req["self_id"])->fd, ["action" => "set_friend_add_request", "params" => $params], ["set_friend_add_request", $req["user_id"]]);
|
||||
CQUtil::sendGroupMsg(Buffer::get("admin_group"), "已自动同意 " . $req["user_id"], $req["self_id"]);
|
||||
break;
|
||||
case "group":
|
||||
switch ($req["sub_type"]) {
|
||||
case "invite":
|
||||
$comment = $req["comment"];//验证信息
|
||||
$user_id = $req["user_id"];//用户QQ
|
||||
$group_id = $req["group_id"];//被邀请进群的群号
|
||||
$flag = $req["flag"];//同意加群用的flag,用于处理是否加群
|
||||
//TODO: 邀请登录号入群事件处理
|
||||
break;
|
||||
case "add":
|
||||
$comment = $req["comment"];//验证信息
|
||||
$user_id = $req["user_id"];//用户QQ
|
||||
$group_id = $req["group_id"];//用户申请加群的群号
|
||||
$flag = $req["flag"];//同意加群用的flag,用于处理是否同意其入群
|
||||
//TODO: 机器人是管理员,处理入群请求事件
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/cqbot/event/post/UnknownEvent.php
Normal file
14
src/cqbot/event/post/UnknownEvent.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/10/15
|
||||
* Time: 10:40 AM
|
||||
*/
|
||||
|
||||
class UnknownEvent extends Event
|
||||
{
|
||||
public function __construct($req) {
|
||||
Console::info("Unknown event.");
|
||||
}
|
||||
}
|
||||
20
src/cqbot/event/server/APIConnectEvent.php
Normal file
20
src/cqbot/event/server/APIConnectEvent.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/10/13
|
||||
* Time: 3:53 PM
|
||||
*/
|
||||
|
||||
class APIConnectEvent extends Event
|
||||
{
|
||||
public function __construct(WSConnection $connection, swoole_websocket_server $server) {
|
||||
$alias = [
|
||||
"10001" => '小马哥'
|
||||
//这里放机器人连接的别名
|
||||
//"QQ" => "别名"
|
||||
];
|
||||
CQUtil::sendDebugMsg("[CQBot] 机器人 " . ($alias[$connection->getQQ()] ?? $connection->getQQ()) . " 已连接", strval($connection->getQQ()), false);
|
||||
Buffer::set("admin_active", $connection->getQQ());
|
||||
}
|
||||
}
|
||||
@ -10,9 +10,8 @@ class WSCloseEvent extends Event
|
||||
{
|
||||
public function __construct(swoole_server $server, int $fd) {
|
||||
$connect = CQUtil::getConnection($fd);
|
||||
if ($connect->getPair() !== null) {
|
||||
$connect->setPair(null);
|
||||
}
|
||||
unset(Buffer::$connect[$fd]);
|
||||
if ($connect !== null)
|
||||
unset(Buffer::$connect[$fd]);
|
||||
Console::info("WebSocket Connection closed. fd: " . $fd);
|
||||
}
|
||||
}
|
||||
48
src/cqbot/event/server/WSMessageEvent.php
Normal file
48
src/cqbot/event/server/WSMessageEvent.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/5/26
|
||||
* Time: 下午4:04
|
||||
*/
|
||||
|
||||
class WSMessageEvent extends Event
|
||||
{
|
||||
public function __construct(swoole_websocket_server $server, swoole_websocket_frame $frame) {
|
||||
$fd = $frame->fd;
|
||||
$req = json_decode($frame->data, true);
|
||||
$connect = CQUtil::getConnection($fd);
|
||||
if ($connect === null) {
|
||||
Console::info("收到一个未知链接发来的消息。" . $fd);
|
||||
return;
|
||||
}
|
||||
switch ($connect->getType()) {
|
||||
case 0:
|
||||
//处理酷Q HTTP事件接口消息(Event)
|
||||
switch ($req["post_type"]) {
|
||||
case "message":
|
||||
new MessageEvent($req);
|
||||
break 2;
|
||||
case "notice":
|
||||
new NoticeEvent($req);
|
||||
break 2;
|
||||
case "request":
|
||||
new RequestEvent($req);
|
||||
break 2;
|
||||
case "meta_event":
|
||||
new MetaEvent($req);
|
||||
break 2;
|
||||
default:
|
||||
new UnknownEvent($req);
|
||||
break 2;
|
||||
}
|
||||
case 1:
|
||||
Console::debug("收到来自API[" . $fd . "]连接的回复:" . json_encode($req, 128 | 256));
|
||||
if (isset($req["echo"])) CQAPIHandler::execute($req["echo"], $req);
|
||||
break;
|
||||
default:
|
||||
Console::info("收到未知链接的消息, 来自: " . $fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/cqbot/event/server/WSOpenEvent.php
Normal file
53
src/cqbot/event/server/WSOpenEvent.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/5/26
|
||||
* Time: 下午4:10
|
||||
*/
|
||||
|
||||
class WSOpenEvent extends Event
|
||||
{
|
||||
public function __construct(swoole_websocket_server $server, swoole_http_request $request) {
|
||||
$fd = $request->fd;
|
||||
$get = $request->get;
|
||||
$header = $request->header;
|
||||
//echo json_encode($header, 128|256);
|
||||
$connect_type = $get["type"] ?? (isset($header["x-client-role"]) ? strtolower($header["x-client-role"]) : "");
|
||||
$access_token = $get["token"] ?? (isset($header["authorization"]) ? explode(" ", $header["authorization"])[1] : "");
|
||||
//Console::info("链接类型:".$connect_type."\n链接token:".$access_token);
|
||||
if ($connect_type == "") {
|
||||
Console::info("未指定连接类型,关闭连接.");
|
||||
$server->close($fd);
|
||||
return;
|
||||
}
|
||||
if ($access_token == "") {
|
||||
Console::info("未指定连接token,关闭连接.");
|
||||
$server->close($fd);
|
||||
return;
|
||||
}
|
||||
//if (isset($request->header["authorization"])) {
|
||||
//$tokens = explode(" ", $request->header["authorization"]);
|
||||
//$tokens = trim($tokens[1]);
|
||||
if ($access_token !== Buffer::get("access_token")) {
|
||||
Console::info("监测到WS连接,但是token不对,无法匹配。");
|
||||
$server->close($fd);
|
||||
return;
|
||||
}
|
||||
switch ($connect_type) {
|
||||
case "event":
|
||||
case "api":
|
||||
$self_id = $get["qq"] ?? ($header["x-self-id"] ?? "");
|
||||
Console::info("收到 " . $connect_type . " 连接,来自机器人:" . $self_id . ",fd:" . $fd);
|
||||
CQUtil::getConnection($fd, $connect_type, $self_id);
|
||||
$robots = [];
|
||||
foreach (Buffer::get("robots") as $v) {
|
||||
$robots[] = $v["qq"];
|
||||
}
|
||||
if (!in_array($self_id, $robots)) {
|
||||
Buffer::append("robots", ["qq" => $self_id, "addr" => $request->server["remote_addr"]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,17 +9,14 @@
|
||||
class WorkerStartEvent extends Event
|
||||
{
|
||||
public function __construct(swoole_server $server, $worker_id){
|
||||
|
||||
Console::info("Starting worker: " . $worker_id);
|
||||
|
||||
Buffer::$reload_time->add(1);
|
||||
Buffer::$connect = [];
|
||||
CQUtil::loadAllFiles();
|
||||
foreach (get_included_files() as $file)
|
||||
Console::debug("Loaded " . $file);
|
||||
|
||||
//计时器(ms)
|
||||
$this->getFramework()->scheduler = new Scheduler($this->getFramework());
|
||||
$server->tick(1000, [$this->getFramework(), "processTick"]);
|
||||
|
||||
Console::debug("master_pid = " . $server->master_pid);
|
||||
Console::debug("worker_id = " . $worker_id);
|
||||
Console::put("\n==========STARTUP DONE==========\n");
|
||||
92
src/cqbot/handler/CQAPIHandler.php
Normal file
92
src/cqbot/handler/CQAPIHandler.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/4/26
|
||||
* Time: 下午1:42
|
||||
*/
|
||||
|
||||
class CQAPIHandler
|
||||
{
|
||||
static function execute($cmd, $res = null) {
|
||||
if (!isset($cmd["type"])) return false;
|
||||
if ($res["status"] != "ok" && $res["status"] != "async") {
|
||||
$email_contact = [103, 201, -1, -2, -14];
|
||||
if (in_array($res["retcode"], $email_contact)) {
|
||||
CQUtil::errorLog("API推送失败, retcode = " . $res["retcode"], "API ERROR", 0);
|
||||
} else {
|
||||
CQUtil::errorLog("API推送失败, retcode = " . $res["retcode"] . "\n说明 = " . ErrorStatus::getMessage($res["retcode"]) . "\n" . json_encode($res["echo"], 128 | 256), "API ERROR");
|
||||
}
|
||||
echo("\n\n");
|
||||
}
|
||||
switch ($cmd["type"]) {
|
||||
case "get_group_list"://Done
|
||||
self::getGroupList($cmd["self_id"], $cmd["params"], $res["data"]);
|
||||
break;
|
||||
case "get_friend_list"://Done
|
||||
self::getFriendList($cmd["self_id"], $cmd["params"], $res["data"]["friends"]);
|
||||
break;
|
||||
case "set_friend_add_request":
|
||||
$id = $cmd["params"][0];
|
||||
$msg = "Hi~你好!";
|
||||
$msg .= "\n第一次见面请多关照!";
|
||||
CQUtil::sendPrivateMsg($id, $msg, $cmd["self_id"]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新群列表API
|
||||
* @param $self_id
|
||||
* @param $param
|
||||
* @param $data
|
||||
*/
|
||||
static function getGroupList($self_id, $param, $data) {
|
||||
switch ($param[0]) {
|
||||
case "step1":
|
||||
$list = Buffer::get("group_list");
|
||||
foreach ($data as $k => $v) {
|
||||
if (!isset($list[$v["group_id"]])) {
|
||||
$list[$v["group_id"]] = [
|
||||
"group_id" => $v["group_id"],
|
||||
"group_name" => $v["group_name"],
|
||||
"fetch_members" => false,
|
||||
"joiner" => [$self_id]
|
||||
];
|
||||
} elseif (!in_array($self_id, $list[$v["group_id"]]["joiner"])) {
|
||||
$list[$v["group_id"]]["joiner"][] = $self_id;
|
||||
}
|
||||
}
|
||||
Buffer::set("group_list", $list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新好友列表API
|
||||
* @param $self_id
|
||||
* @param $param
|
||||
* @param $data
|
||||
*/
|
||||
static function getFriendList($self_id, $param, $data) {
|
||||
switch ($param[0]) {
|
||||
case "step1":
|
||||
foreach ($data as $k => $v) {
|
||||
$user = CQUtil::getUser($v["user_id"]);
|
||||
$ls = $user->getFriend();
|
||||
if (!in_array($self_id, $ls)) {
|
||||
$ls[] = $self_id;
|
||||
}
|
||||
$user->setFriend($ls);
|
||||
$user->setNickname($v["nickname"]);
|
||||
}
|
||||
foreach (CQUtil::getAllUsers() as $k => $v) {
|
||||
$serial = serialize($v);
|
||||
file_put_contents(DataProvider::getUserFolder() . $k . ".dat", $serial);
|
||||
}
|
||||
Buffer::set("user", []);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
212
src/cqbot/item/CQ.php
Normal file
212
src/cqbot/item/CQ.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/8/27
|
||||
* Time: 7:17 PM
|
||||
*/
|
||||
|
||||
class CQ
|
||||
{
|
||||
/**
|
||||
* at一下QQ用户(仅在QQ群支持at全体)
|
||||
* @param $qq
|
||||
* @return string
|
||||
*/
|
||||
public static function at($qq) {
|
||||
if (is_numeric($qq) || $qq === "all") {
|
||||
return "[CQ:at,qq=" . $qq . "]";
|
||||
}
|
||||
Console::error("传入的QQ号码($qq)错误!");
|
||||
return " ";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送QQ原生表情
|
||||
* @param $id
|
||||
* @return string
|
||||
*/
|
||||
public static function face($id) {
|
||||
if (is_numeric($id)) {
|
||||
return "[CQ:face,id=" . $id . "]";
|
||||
}
|
||||
Console::error("传入的face id($id)错误!");
|
||||
return " ";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送emoji表情
|
||||
* @param $id
|
||||
* @return string
|
||||
*/
|
||||
public static function emoji($id) {
|
||||
if (is_numeric($id)) {
|
||||
return "[CQ:emoji,id=" . $id . "]";
|
||||
}
|
||||
Console::error("传入的emoji id($id)错误!");
|
||||
return " ";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送原创表情,存放在酷Q目录的data/bface/下
|
||||
* @param $id
|
||||
* @return string
|
||||
*/
|
||||
public static function bface($id) {
|
||||
return "[CQ:bface,id=" . $id . "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送小表情
|
||||
* @param $id
|
||||
* @return string
|
||||
*/
|
||||
public static function sface($id) {
|
||||
if (is_numeric($id)) {
|
||||
return "[CQ:sface,id=" . $id . "]";
|
||||
}
|
||||
Console::error("传入的sface id($id)错误!");
|
||||
return " ";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送图片
|
||||
* cache为<FALSE>时禁用CQ-HTTP-API插件的缓存
|
||||
* @param $file
|
||||
* @param bool $cache
|
||||
* @return string
|
||||
*/
|
||||
public static function image($file, $cache = true) {
|
||||
if ($cache === false)
|
||||
return "[CQ:image,file=" . $file . ",cache=0]";
|
||||
else
|
||||
return "[CQ:image,file=" . $file . "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送语音
|
||||
* cache为<FALSE>时禁用CQ-HTTP-API插件的缓存
|
||||
* magic为<TRUE>时标记为变声
|
||||
* @param $file
|
||||
* @param bool $magic
|
||||
* @param bool $cache
|
||||
* @return string
|
||||
*/
|
||||
public static function record($file, $magic = false, $cache = true) {
|
||||
if ($cache === false) $c = ",cache=0";
|
||||
else $c = "";
|
||||
if ($magic === true) $m = ",magic=true";
|
||||
else $m = "";
|
||||
return "[CQ:record,file=" . $file . $c . $m . "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送投掷骰子(只能在单条回复中单独使用)
|
||||
* @return string
|
||||
*/
|
||||
public static function rps() {
|
||||
return "[CQ:rps]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送掷骰子表情(只能在单条回复中单独使用)
|
||||
* @return string
|
||||
*/
|
||||
public static function dice() {
|
||||
return "[CQ:dice]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 戳一戳(原窗口抖动,仅支持好友消息使用)
|
||||
* @return string
|
||||
*/
|
||||
public static function shake() {
|
||||
return "[CQ:shake]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送音乐分享(只能在单条回复中单独使用)
|
||||
* qq、163、xiami为内置分享,需要先通过搜索功能获取id后使用
|
||||
* custom为自定义分享
|
||||
* 当为自定义分享时:
|
||||
* $id_or_url 为音乐卡片点进去打开的链接(一般是音乐介绍界面啦什么的)
|
||||
* $audio 为音乐(如mp3文件)的HTTP链接地址(不可为空)
|
||||
* $title 为音乐卡片的标题,建议12字以内(不可为空)
|
||||
* $content 为音乐卡片的简介(可忽略)
|
||||
* $image 为音乐卡片的图片链接地址(可忽略)
|
||||
* @param $type
|
||||
* @param $id_or_url
|
||||
* @param string $audio
|
||||
* @param string $title
|
||||
* @param string $content
|
||||
* @param string $image
|
||||
* @return string
|
||||
*/
|
||||
public static function music($type, $id_or_url, $audio = null, $title = null, $content = null, $image = null) {
|
||||
switch ($type) {
|
||||
case "qq":
|
||||
case "163":
|
||||
case "xiami":
|
||||
return "[CQ:music,id=" . $id_or_url . "]";
|
||||
case "custom":
|
||||
if ($title === null || $audio === null) {
|
||||
Console::error("传入CQ码实例的标题和音频链接不能为空!");
|
||||
return " ";
|
||||
}
|
||||
if ($content === null) $c = "";
|
||||
else $c = ",content=" . $content;
|
||||
if ($image === null) $i = "";
|
||||
else $i = ",image=" . $image;
|
||||
return "[CQ:music,type=custom,url=" . $id_or_url . ",audio=" . $audio . ",title=" . $title . $c . $i . "]";
|
||||
default:
|
||||
Console::error("传入的music type($type)错误!");
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送链接分享(只能在单条回复中单独使用)
|
||||
* @param $url
|
||||
* @param $title
|
||||
* @param null $content
|
||||
* @param null $image
|
||||
* @return string
|
||||
*/
|
||||
public static function share($url, $title, $content = null, $image = null) {
|
||||
if ($content === null) $c = "";
|
||||
else $c = ",content=" . $content;
|
||||
if ($image === null) $i = "";
|
||||
else $i = ",image=" . $image;
|
||||
return "[CQ:share,url=" . $url . ",title=" . $title . $c . $i . "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串中的CQ码敏感符号进行转义
|
||||
* @param $str
|
||||
* @return mixed
|
||||
*/
|
||||
public static function encode($str) {
|
||||
$str = str_replace("&", "&", $str);
|
||||
$str = str_replace("[", "[", $str);
|
||||
$str = str_replace("]", "]", $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 反转义字符串中的CQ码敏感符号
|
||||
* @param $str
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode($str) {
|
||||
$str = str_replace("&", "&", $str);
|
||||
$str = str_replace("[", "[", $str);
|
||||
$str = str_replace("]", "]", $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
public static function replace($str) {
|
||||
$str = str_replace("{{", "[", $str);
|
||||
$str = str_replace("}}", "]", $str);
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
@ -1,100 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/5/2
|
||||
* Time: 下午1:59
|
||||
*/
|
||||
|
||||
class Group
|
||||
{
|
||||
private $group_id;
|
||||
private $group_name;
|
||||
private $self_id;
|
||||
//private $prefix;
|
||||
private $members = [];
|
||||
|
||||
public function __construct($group_id, $info, $self_id) {
|
||||
$this->self_id = $self_id;
|
||||
$this->group_id = $group_id;
|
||||
$this->group_name = $info["group_name"];
|
||||
//$this->prefix = $info["prefix"];
|
||||
$member_list = $info["member"];
|
||||
$this->members = [];
|
||||
foreach ($member_list as $k => $v) {
|
||||
$this->members[$v["user_id"]] = new GroupMember($v["user_id"], $this, $v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getGroupId() {
|
||||
return $this->group_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getGroupName() {
|
||||
return $this->group_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMembers(): array {
|
||||
return $this->members;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $user_id
|
||||
* @return GroupMember|null
|
||||
*/
|
||||
public function getMember($user_id) {
|
||||
return isset($this->members[$user_id]) ? $this->members[$user_id] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $group_name
|
||||
*/
|
||||
public function setGroupName($group_name) {
|
||||
$this->group_name = $group_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* set群成员的类
|
||||
* @param array $members
|
||||
*/
|
||||
public function setMembers(array $members) {
|
||||
$this->members = $members;
|
||||
}
|
||||
|
||||
/**
|
||||
* set群成员的类
|
||||
* @param $user_id
|
||||
* @param GroupMember $member
|
||||
*/
|
||||
public function setMember($user_id, GroupMember $member) {
|
||||
$this->members[$user_id] = $member;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新群信息
|
||||
* @param bool $with_members
|
||||
*/
|
||||
public function updateData($with_members = false) {
|
||||
$connection = CQUtil::getApiConnectionByQQ($this->getSelfId());
|
||||
CQUtil::sendAPI($connection->fd, ["action" => "get_group_list"], ["update_group_info", $this->getGroupId()]);
|
||||
if ($with_members) {
|
||||
CQUtil::sendAPI($connection->fd, ["action" => "get_group_member_list", "params" => ["group_id" => $this->getGroupId()]], ["update_group_member_list", strval($this->getGroupId())]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSelfId() {
|
||||
return $this->self_id;
|
||||
}
|
||||
}
|
||||
@ -1,138 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/5/2
|
||||
* Time: 下午2:43
|
||||
*/
|
||||
|
||||
class GroupMember extends User
|
||||
{
|
||||
private $group = 0;
|
||||
private $card = "";
|
||||
private $join_time = 0;
|
||||
private $last_sent_time = 0;
|
||||
private $role = "member";
|
||||
private $attribute = [];
|
||||
|
||||
public function __construct($qid, Group $group, $data) {
|
||||
parent::__construct($qid);
|
||||
$this->group = $group;
|
||||
$this->card = $data["card"];
|
||||
$this->join_time = $data["join_time"];
|
||||
$this->last_sent_time = $data["last_sent_time"];
|
||||
$this->role = $data["role"];
|
||||
$this->attribute = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Group
|
||||
*/
|
||||
public function getGroup(): Group {
|
||||
return $this->group;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCard() {
|
||||
return $this->card;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getJoinTime() {
|
||||
return $this->join_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLastSentTime() {
|
||||
return $this->last_sent_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回角色
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRole() {
|
||||
return $this->role;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回用户是不是群管理员
|
||||
* @return bool
|
||||
*/
|
||||
public function isAdmin() {
|
||||
return in_array($this->getRole(), ["owner", "admin"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $card
|
||||
*/
|
||||
public function setCard(string $card) {
|
||||
$this->card = $card;
|
||||
$data = [
|
||||
"action" => "set_group_card",
|
||||
"params" => [
|
||||
"group_id" => $this->getGroup()->getGroupId(),
|
||||
"user_id" => $this->getId(),
|
||||
"card" => $card
|
||||
]
|
||||
];
|
||||
CQUtil::sendAPI(CQUtil::getApiConnectionByQQ($this->getGroup()->getSelfId())->fd, $data, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $join_time
|
||||
*/
|
||||
public function setJoinTime(int $join_time) {
|
||||
$this->join_time = $join_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $last_sent_time
|
||||
*/
|
||||
public function setLastSentTime(int $last_sent_time) {
|
||||
$this->last_sent_time = $last_sent_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $role
|
||||
*/
|
||||
public function setRole(string $role) {
|
||||
$this->role = $role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAttribute(): array {
|
||||
return $this->attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $attribute
|
||||
*/
|
||||
public function setAttribute(array $attribute) {
|
||||
$this->attribute = $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新群组成员信息
|
||||
*/
|
||||
public function updateData() {
|
||||
$user_id = $this->getId();
|
||||
CQUtil::sendAPI(CQUtil::getApiConnectionByQQ($this->getGroup()->getSelfId())->fd, [
|
||||
"action" => "get_group_member_info",
|
||||
"params" => [
|
||||
"group_id" => $this->getGroup()->getGroupId(),
|
||||
"user_id" => $user_id,
|
||||
"no_cache" => true
|
||||
]
|
||||
], ["update_group_member_info", $this->getGroup()->getGroupId(), $user_id]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -11,68 +11,126 @@ use DataProvider as DP;
|
||||
class User
|
||||
{
|
||||
private $id;
|
||||
private $word_status = [];
|
||||
private $permission;
|
||||
private $is_friend = false;
|
||||
|
||||
private $buffer = null;
|
||||
protected $nickname = "";
|
||||
protected $permission = 0;
|
||||
protected $friend = [];
|
||||
protected $lexicon = [];
|
||||
protected $user_type = 0;//预留位置,0为QQ用户,1为为微信公众号用户
|
||||
|
||||
public function __construct($qid){
|
||||
protected $function = [];
|
||||
|
||||
public $buffer = null;
|
||||
|
||||
public function __construct($qid) {
|
||||
$this->id = $qid;
|
||||
if (strlen($qid) >= 15) $this->user_type = 1;
|
||||
$this->permission = DP::getJsonData("permissions.json")[$qid] ?? 0;
|
||||
$this->is_friend = isset(Buffer::get("friend_list")[$qid]) ? true : false;
|
||||
$this->friend = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户QQ号
|
||||
* @return mixed
|
||||
*/
|
||||
public function getId(){ return $this->id; }
|
||||
|
||||
/**
|
||||
* 获取用户添加词库的状态
|
||||
* @return array
|
||||
*/
|
||||
public function getWordStatus() : array{ return $this->word_status; }
|
||||
public function getId() { return $this->id; }
|
||||
|
||||
/**
|
||||
* 获取用户权限值
|
||||
* @return int
|
||||
*/
|
||||
public function getPermission() : int{ return $this->permission; }
|
||||
|
||||
/**
|
||||
* @param array $word_status
|
||||
* @return User
|
||||
*/
|
||||
public function setWordStatus(array $word_status): User{
|
||||
$this->word_status = $word_status;
|
||||
return $this;
|
||||
}
|
||||
public function getPermission() { return $this->permission; }
|
||||
|
||||
/**
|
||||
* @param int $permission
|
||||
* @return User
|
||||
*/
|
||||
public function setPermission(int $permission): User{
|
||||
public function setPermission(int $permission) {
|
||||
$this->permission = $permission;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 和用户是否是好友//TODO功能
|
||||
* @return bool
|
||||
*/
|
||||
public function isFriend(): bool{
|
||||
return $this->is_friend;
|
||||
}
|
||||
|
||||
public function getBuffer(){
|
||||
public function getBuffer() {
|
||||
return $this->buffer;
|
||||
}
|
||||
|
||||
public function setBuffer($buffer){
|
||||
public function setBuffer($buffer) {
|
||||
$this->buffer = $buffer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNickname() {
|
||||
return $this->nickname;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFriend() {
|
||||
return $this->friend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $friend
|
||||
*/
|
||||
public function setFriend(array $friend) {
|
||||
$this->friend = $friend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nickname
|
||||
*/
|
||||
public function setNickname(string $nickname) {
|
||||
$this->nickname = $nickname;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getLexicon() {
|
||||
return $this->lexicon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $lexicon
|
||||
*/
|
||||
public function setLexicon(array $lexicon) {
|
||||
$this->lexicon = $lexicon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFunction() {
|
||||
return $this->function;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $function
|
||||
*/
|
||||
public function setFunction(array $function) {
|
||||
$this->function = $function;
|
||||
}
|
||||
|
||||
public function closeFunction($name) {
|
||||
unset($this->function[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getUserType() {
|
||||
return $this->user_type;
|
||||
}
|
||||
|
||||
public function toJson() {
|
||||
$ls = [];
|
||||
foreach ($this as $k => $v) {
|
||||
$ls[$k] = $v;
|
||||
}
|
||||
return json_encode($ls, 128 | 256);
|
||||
}
|
||||
}
|
||||
@ -1,148 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/6/13
|
||||
* Time: 8:10 PM
|
||||
*/
|
||||
|
||||
class WSConnection
|
||||
{
|
||||
public $fd;
|
||||
|
||||
/**
|
||||
* 0 = event连接
|
||||
* 1 = api连接
|
||||
* 默认为event连接,如果可以收到返回的get_status则标记为1
|
||||
* @var int
|
||||
*/
|
||||
protected $type = 0;
|
||||
|
||||
protected $server;
|
||||
|
||||
/** @var WSConnection */
|
||||
protected $pair = null;
|
||||
|
||||
protected $qq = "";
|
||||
|
||||
public function __construct(swoole_websocket_server $server, $fd) {
|
||||
$this->server = $server;
|
||||
$this->fd = $fd;
|
||||
$this->manageType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回swoole server
|
||||
* @return swoole_websocket_server
|
||||
*/
|
||||
public function getServer() {
|
||||
return $this->server;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回本连接是什么类型的
|
||||
* @return int
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用来确认此连接是API还是event
|
||||
* 如果此fd连接是event,则不会返回任何信息,关于QQ的匹配,则会在接收入第一条消息后设置
|
||||
* 如果此连接是api,则此操作后,HTTP API会返回登录号的号码,如果返回了则标记此连接为api并记录这个api连接属于的QQ号
|
||||
*/
|
||||
private function manageType() {
|
||||
$this->server->push($this->fd, '{"action":"get_login_info","echo":{"type":"handshake"}}');
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此连接相关联的event连接,使用前需初始化完成
|
||||
* @return $this|null|WSConnection
|
||||
*/
|
||||
public function getEventConnection() {
|
||||
switch ($this->type) {
|
||||
case 0:
|
||||
return $this;
|
||||
case 1:
|
||||
return $this->pair;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此链接相关联的api连接,使用前需初始化完成
|
||||
* @return $this|null|WSConnection
|
||||
*/
|
||||
public function getApiConnection() {
|
||||
switch ($this->type) {
|
||||
case 0:
|
||||
return $this->pair;
|
||||
case 1:
|
||||
return $this;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查此连接对应的QQ,此部分较为复杂,先留着
|
||||
* @param $qq
|
||||
*/
|
||||
public function manageQQ($qq) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回此连接属于的QQ号
|
||||
* @return string
|
||||
*/
|
||||
public function getQQ() {
|
||||
return $this->qq;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回关联连接(experiment)
|
||||
* @return WSConnection
|
||||
*/
|
||||
public function getPair() {
|
||||
return $this->pair;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置关联连接
|
||||
* @param WSConnection $pair
|
||||
*/
|
||||
public function setPair(WSConnection $pair) {
|
||||
$this->pair = $pair;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $qq
|
||||
*/
|
||||
public function setQQ($qq) {
|
||||
$this->qq = $qq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type
|
||||
*/
|
||||
public function setType(int $type) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function findSub() {
|
||||
if ($this->qq != "") {
|
||||
foreach (CQUtil::getConnections() as $fd => $cn) {
|
||||
if ($cn->getQQ() == $this->qq && $cn->getType() != $this->getType()) {
|
||||
$this->setPair($cn);
|
||||
$cn->setPair($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,20 +6,6 @@
|
||||
* Time: 10:32
|
||||
*/
|
||||
|
||||
function loadAllClass($dir){
|
||||
$dir_obj = scandir($dir);
|
||||
unset($dir_obj[0], $dir_obj[1]);
|
||||
foreach ($dir_obj as $m) {
|
||||
$taskFileName = explode(".", $m);
|
||||
if (is_dir($dir . $m . "/")) loadAllClass($dir . $m . "/");
|
||||
else {
|
||||
if (count($taskFileName) < 2 || $taskFileName[1] != "php") continue;
|
||||
require_once($dir . $m);
|
||||
Console::debug("Loading PHP file ".$dir.$m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//加载需要优先加载的文件
|
||||
require_once(WORKING_DIR."src/cqbot/mods/ModBase.php");
|
||||
require_once(WORKING_DIR."src/cqbot/item/User.php");
|
||||
|
||||
@ -10,41 +10,44 @@ class Admin extends ModBase
|
||||
{
|
||||
protected $cmds;
|
||||
|
||||
public function __construct(CQBot $main, $data){
|
||||
public function __construct(CQBot $main, $data) {
|
||||
parent::__construct($main, $data);
|
||||
}
|
||||
|
||||
public function execute($it){
|
||||
public static function initValues() {
|
||||
Buffer::set("msg_speed", []);//消息速度列表(存的是时间戳)
|
||||
Buffer::set("admin_active", "");
|
||||
}
|
||||
|
||||
public static function onTick($tick) {
|
||||
if ($tick % 900 == 0) CQUtil::saveAllFiles();//900秒储存一次数据
|
||||
if ($tick % 21600 == 0) {//21600秒刷新一次好友列表
|
||||
GroupManager::updateGroupList();
|
||||
FriendManager::updateFriendList();
|
||||
}
|
||||
}
|
||||
|
||||
public function execute($it) {
|
||||
if (!$this->main->isAdmin($this->getUserId())) return false;
|
||||
switch ($it[0]) {
|
||||
case "reload":
|
||||
case "reload"://管理员重载代码
|
||||
$this->reply("正在重新启动...");
|
||||
if (file_get_contents("/home/ubuntu/CrazyBotFramework/src/Framework.php") != Buffer::get("res_code"))
|
||||
$this->reply("检测到改变了Framework文件的内容!如需完全重载,请重启完整进程!");
|
||||
CQUtil::reload();
|
||||
return true;
|
||||
case "stop":
|
||||
case "stop"://管理员停止server
|
||||
$this->reply("正在停止服务器...");
|
||||
CQUtil::stop();
|
||||
return true;
|
||||
case "set-prefix":
|
||||
if(count($it) < 2) return $this->sendDefaultHelp($it[0],["set-prefix","新前缀/空"],"设置新的前缀或设置不需要前缀(不需要前缀输入\"空\"即可)");
|
||||
$prefix = $it[1];
|
||||
if(mb_strlen($prefix) > 2){
|
||||
$this->reply("指令前缀最长为两个字符");
|
||||
return true;
|
||||
}
|
||||
Buffer::set("cmd_prefix", $prefix);
|
||||
$this->reply("成功设置新前缀!\n下次输入指令时需前面带 ".$prefix);
|
||||
return true;
|
||||
case "op":
|
||||
case "op"://添加管理员
|
||||
$user = $it[1];
|
||||
Buffer::append("su", $user);
|
||||
Buffer::append("admin", $user);
|
||||
$this->reply("added operator $user");
|
||||
return true;
|
||||
case "deop":
|
||||
case "deop"://删除管理员
|
||||
$user = $it[1];
|
||||
if(Buffer::in_array("su", $user)) Buffer::unsetByValue("su", $user);
|
||||
if (Buffer::in_array("admin", $user)) Buffer::unsetByValue("admin", $user);
|
||||
$this->reply("removed operator $user");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 这是一个示例模块php文件,你可以直接复制此文件中的代码
|
||||
* 然后修改其class的名字(注意要和.php文件的文件名相同)
|
||||
* 例如,新建一个Mailer模块,则Mailer模块的文件名字为
|
||||
* Mailer.php
|
||||
* 然后更改class Entertain为class Mailer即可
|
||||
* 功能在execute中编写即可
|
||||
* 如果需要写判断所有文本的功能,则直接在__construct的parent::__construct下方编写自己的内容即可
|
||||
*/
|
||||
class Entertain extends ModBase
|
||||
{
|
||||
public function __construct(CQBot $main, $data, bool $mod_cmd = false) { parent::__construct($main, $data, $mod_cmd); }
|
||||
|
||||
public function execute($it) {
|
||||
switch ($it[0]) {
|
||||
case "你好":
|
||||
$this->reply("你好,我是CQBot!");
|
||||
return true;
|
||||
case "robot":
|
||||
$this->reply("机器人!\n机器人!");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,71 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/6/3
|
||||
* Time: 下午3:12
|
||||
*/
|
||||
|
||||
/**
|
||||
* 这是一个示例模块php文件,你可以直接复制此文件中的代码
|
||||
* 然后修改其class的名字(注意要和.php文件的文件名相同)
|
||||
* 例如,新建一个Mailer模块,则Mailer模块的文件名字为
|
||||
* Mailer.php
|
||||
* 然后更改class Entertain为class Mailer即可
|
||||
* 功能在execute中编写即可
|
||||
* 如果需要写判断所有文本的功能,则直接在__construct的parent::__construct下方编写自己的内容即可
|
||||
*/
|
||||
class Example extends ModBase
|
||||
{
|
||||
protected $cmds;
|
||||
|
||||
public function __construct(CQBot $main, $data){
|
||||
public function __construct(CQBot $main, $data) {
|
||||
parent::__construct($main, $data);
|
||||
$message = $data["message"];
|
||||
|
||||
//这里可以写一些匹配所有文本的功能,例如下面的一个简单的debug
|
||||
if (mb_substr($message, 0, 3) == "dbg") {
|
||||
$this->reply("你输入了:" . mb_substr($message, 3));
|
||||
}
|
||||
}
|
||||
|
||||
public function execute($it){
|
||||
public function execute($it) {
|
||||
switch ($it[0]) {
|
||||
case "ping":
|
||||
$this->reply("pong");
|
||||
return true;
|
||||
case "王境泽动图":
|
||||
$msg_help = "【王境泽动图帮助】";
|
||||
$msg_help .= "\n用法1:\n王境泽动图 第一句 第二句 第三句 第四句";
|
||||
$msg_help .= "\n[如果需要输入空格的话,用下面的方法]";
|
||||
$msg_help .= "\n王境泽动图 多行\n第一句\n第二句\n第三句\n第四句";
|
||||
$api = "https://sorry.xuty.tk/api/wangjingze/make";
|
||||
if (strstr($it[1], "\n") === false && count($it) < 5) {
|
||||
$this->reply($msg_help);
|
||||
return true;
|
||||
}
|
||||
array_shift($it);
|
||||
if (mb_substr($it[0], 0, 2) == "多行") {
|
||||
$ms = implode(" ", $it);
|
||||
$ms = mb_substr($ms, 2);
|
||||
$ms = trim($ms);
|
||||
$ms = explode("\n", $ms);
|
||||
if (count($ms) < 4) {
|
||||
$this->reply($msg_help);
|
||||
return true;
|
||||
}
|
||||
$content = [
|
||||
"3" => $ms[3],
|
||||
"2" => $ms[2],
|
||||
"1" => $ms[1],
|
||||
"0" => $ms[0]
|
||||
];
|
||||
} elseif (count($it) >= 4) {
|
||||
$content = [
|
||||
"3" => $it[3],
|
||||
"0" => $it[0],
|
||||
"1" => $it[1],
|
||||
"2" => $it[2]
|
||||
];
|
||||
} else {
|
||||
$this->reply($msg_help);
|
||||
return true;
|
||||
}
|
||||
$opts = array('http' => array('method' => 'POST', 'header' => 'Content-Type: application/json; charset=utf-8', 'content' => json_encode($content, JSON_UNESCAPED_UNICODE)));
|
||||
$context = stream_context_create($opts);
|
||||
$this->reply("正在生成,请稍等");
|
||||
$result = file_get_contents($api, false, $context);
|
||||
if ($result == false) {
|
||||
$this->reply("抱歉,请求失败,请过一会儿再试吧~");
|
||||
return true;
|
||||
}
|
||||
$result = "https://sorry.xuty.tk" . $result;
|
||||
$this->reply("[CQ:image,file=" . $result . "]");
|
||||
case "你好":
|
||||
$this->reply("你好,我是CQBot!");
|
||||
return true;
|
||||
case "随机数":
|
||||
if (!isset($it[1]) || !isset($it[2])) {
|
||||
@ -80,9 +44,6 @@ class Example extends ModBase
|
||||
}
|
||||
$this->reply("生成的随机数是 " . mt_rand($c1, $c2));
|
||||
return true;
|
||||
case "test":
|
||||
$this->reply("Hello world");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -8,25 +8,23 @@
|
||||
|
||||
class Help extends ModBase
|
||||
{
|
||||
public function __construct(CQBot $main, $data, bool $mod_cmd = false) { parent::__construct($main, $data, $mod_cmd); }
|
||||
public function __construct(CQBot $main, $data) { parent::__construct($main, $data); }
|
||||
|
||||
public function execute($it) {
|
||||
switch ($it[0]) {
|
||||
case "帮助":
|
||||
$msg = "「机器人帮助」";
|
||||
$msg .= "\n王境泽动图:用来生成表情包";
|
||||
$msg .= "\ntest:测试机器人回复是否正常";
|
||||
$msg .= "\n随机数:生成一个随机数";
|
||||
$this->reply($msg);
|
||||
return true;
|
||||
case "如何增加机器人功能":
|
||||
$msg = "机器人功能是在框架中src/cqbot/mods/xxx.php文件中编写的。";
|
||||
$msg .= "CQBot采用关键词系统,你可以直接像现有源码一样添加case在switch里面,";
|
||||
$msg .= "也可以自己新建一个任意名称的Mod名称,例如Entertain.php,你可以在里面编写娱乐功能。";
|
||||
$msg .= "你可以直接复制框架中Entertain.php文件的内容进行编辑。";
|
||||
$msg .= "你也可以在tasks/Scheduler.php中tick函数里添加自己的定时执行的功能。";
|
||||
$msg .= "预先封装好的机器人函数均在CQUtil类中,只需直接使用静态方法调用即可!";
|
||||
$msg .= "更多示例功能会逐渐添加到框架中,记得更新哦~";
|
||||
$msg .= "\nCQBot采用关键词系统,你可以直接像现有源码一样添加case在switch里面,";
|
||||
$msg .= "\n也可以自己新建一个任意名称的Mod名称,例如Entertain.php,你可以在里面编写娱乐功能。";
|
||||
$msg .= "\n你可以直接复制框架中Example.php文件的内容进行编辑。";
|
||||
$msg .= "\n你也可以在tasks/Scheduler.php中tick函数里添加自己的定时执行的功能。";
|
||||
$msg .= "\n预先封装好的机器人函数均在CQUtil类中,只需直接使用静态方法调用即可!";
|
||||
$msg .= "\n更多示例功能会逐渐添加到框架中,记得更新哦~";
|
||||
$this->reply($msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -10,43 +10,36 @@ abstract class ModBase
|
||||
{
|
||||
protected $main;
|
||||
protected $data;
|
||||
protected $cmds;
|
||||
public $call_task = false;
|
||||
|
||||
public function __construct(CQBot $main, $data, $mod_cmd = false){
|
||||
/**
|
||||
* 控制模块是否调用execute函数的变量
|
||||
* 当function_call 为 TRUE时,表明CQBot主实例不需要调用execute函数
|
||||
* 当为FALSE时,CQBot在实例化模块对象后会执行execute函数
|
||||
* @var bool
|
||||
*/
|
||||
public $function_call = false;
|
||||
|
||||
public function __construct(CQBot $main, $data) {
|
||||
$this->main = $main;
|
||||
$this->data = $data;
|
||||
$this->cmds = $mod_cmd;
|
||||
}
|
||||
|
||||
public function getUser($data = null){
|
||||
public function getUser($data = null) {
|
||||
return CQUtil::getUser($data === null ? $this->data["user_id"] : $data["user_id"]);
|
||||
}
|
||||
|
||||
public function getUserId($data = null){ return $data === null ? strval($this->data["user_id"]) : strval($data["user_id"]); }
|
||||
public function getUserId($data = null) { return $data === null ? strval($this->data["user_id"]) : strval($data["user_id"]); }
|
||||
|
||||
public abstract function execute($it);
|
||||
public function execute($it) { }
|
||||
|
||||
public function reply($msg){ $this->main->reply($msg); }
|
||||
public function reply($msg) { $this->main->reply($msg); }
|
||||
|
||||
public function sendPrivateMsg($user, $msg){ $this->main->sendPrivateMsg($user, $msg); }
|
||||
public function sendPrivateMsg($user, $msg) { $this->main->sendPrivateMsg($user, $msg); }
|
||||
|
||||
public function sendGroupMsg($user, $msg){ $this->main->sendGroupMsg($user, $msg); }
|
||||
public function sendGroupMsg($user, $msg) { $this->main->sendGroupMsg($user, $msg); }
|
||||
|
||||
public function getMessageType(){ return $this->data["message_type"]; }
|
||||
public function getMessageType() { return $this->data["message_type"]; }
|
||||
|
||||
public function getCommands(){ return $this->cmds; }
|
||||
|
||||
public function sendDefaultHelp($cmd, $args = [], $help = ""){
|
||||
$msg = "「".$cmd."使用帮助」";
|
||||
$msg .= "\n用法:".Buffer::get("cmd_prefix").$cmd;
|
||||
if($args != []){
|
||||
$msg .= " ".implode(" ", $args);
|
||||
}
|
||||
if($help != ""){
|
||||
$msg .= ":".$help;
|
||||
}
|
||||
$this->reply($msg);
|
||||
return true;
|
||||
}
|
||||
public function getRobotId() { return $this->data["self_id"]; }
|
||||
}
|
||||
@ -27,9 +27,12 @@ class Scheduler
|
||||
}
|
||||
|
||||
public function tick($id, $tick_time) {
|
||||
//900秒执行一次文件保存功能
|
||||
if($tick_time - $this->framework->run_time % 900 == 0) CQUtil::saveAllFiles();
|
||||
|
||||
//这里添加计时器上处理的内容
|
||||
/** @var array $ls */
|
||||
$ls = Buffer::get("mods");
|
||||
foreach ($ls as $v) {
|
||||
if (in_array("onTick", get_class_methods($v))) {
|
||||
$v::onTick($tick_time - $this->framework->run_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,91 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/4/26
|
||||
* Time: 下午1:42
|
||||
*/
|
||||
|
||||
class APIHandler
|
||||
{
|
||||
static function execute($cmd, $res = null) {
|
||||
if (!isset($cmd["type"])) return false;
|
||||
switch ($cmd["type"]) {
|
||||
case "set_friend_add_request":
|
||||
$id = $cmd["params"][0];
|
||||
$msg = "Hi~你好!";
|
||||
$msg .= "\n第一次见面请多关照!";
|
||||
CQUtil::sendPrivateMsg($id, $msg, $cmd["self_id"]);
|
||||
return true;
|
||||
case "get_friend_list":
|
||||
$friend = $res["data"][0]["friends"];
|
||||
$list = [];
|
||||
foreach ($friend as $k => $v) {
|
||||
$list[$v["user_id"]] = $friend[$k];
|
||||
}
|
||||
Buffer::set("friend_list", $list);
|
||||
Console::put(Console::setColor("已读取" . count(Buffer::get("friend_list")) . "个好友", "blue"));
|
||||
return true;
|
||||
case "update_group_member_list":
|
||||
$group_id = $cmd["params"][0];
|
||||
$info_data = $res["data"];
|
||||
Console::info(Console::setColor("Updating group $group_id members, it will take several minutes.", "yellow"));
|
||||
foreach ($info_data as $k => $v) {
|
||||
$s = new GroupMember($v["user_id"], CQUtil::getGroup($group_id), $v);
|
||||
CQUtil::getGroup($group_id)->setMember($v["user_id"], $s);
|
||||
$s->updateData();
|
||||
}
|
||||
return true;
|
||||
case "update_group_member_info":
|
||||
$info_data = $res["data"];
|
||||
$group = $cmd["params"][0];
|
||||
$user = $cmd["params"][1];
|
||||
$g = CQUtil::getGroup($group);
|
||||
$member = $g->getMember($user);
|
||||
$member->setAttribute($info_data);
|
||||
$member->setCard($info_data["card"]);
|
||||
$member->setJoinTime($info_data["join_time"]);
|
||||
$member->setLastSentTime($info_data["last_sent_time"]);
|
||||
$member->setRole($info_data["role"]);
|
||||
Console::info("Updated group member information: " . $group . ":" . $user);
|
||||
return true;
|
||||
case "update_group_info":
|
||||
$group = $res["data"];
|
||||
$current = $cmd["params"][0];
|
||||
$list = [];
|
||||
foreach ($group as $k => $v) {
|
||||
$list[$v["group_id"]] = $group[$k];
|
||||
}
|
||||
if (!isset($list[$current]) && Buffer::array_key_exists("groups", $current)) {
|
||||
Buffer::unset("groups", $current);
|
||||
return true;
|
||||
}
|
||||
$g = CQUtil::getGroup($current);
|
||||
$g->setGroupName($list[$current]["group_name"]);
|
||||
return true;
|
||||
case "get_group_member_list":
|
||||
$group_data = $res["data"];
|
||||
$ls = Buffer::get("group_list");
|
||||
$group_id = $cmd["params"][0];
|
||||
$ls[$group_id]["member"] = $group_data;
|
||||
$group = new Group($group_id, $ls[$group_id], $cmd["self_id"]);
|
||||
//TODO: 添加获取API时多账号对群的实例化的支持
|
||||
Buffer::appendKey("groups", $group_id, $group);
|
||||
return true;
|
||||
case "get_group_list":
|
||||
$group = $res["data"];
|
||||
$list = [];
|
||||
foreach ($group as $k => $v) {
|
||||
$list[$v["group_id"]] = $group[$k];
|
||||
CQUtil::sendAPI(CQUtil::getApiConnectionByQQ($cmd["self_id"])->fd, ["action" => "get_group_member_list", "params" => ["group_id" => $v["group_id"]]], ["get_group_member_list", $v["group_id"]]);
|
||||
}
|
||||
Buffer::set("group_list", $list);
|
||||
Console::put(Console::setColor("已读取" . count(Buffer::get("group_list")) . "个群", "blue"));
|
||||
return true;
|
||||
case "get_version_info":
|
||||
Buffer::set("version_info", $res["data"]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -12,13 +12,17 @@ class CQUtil
|
||||
{
|
||||
public static function loadAllFiles() {
|
||||
Console::debug("loading configs...");
|
||||
Buffer::set("su", Framework::$super_user);//超级管理员用户列表
|
||||
|
||||
Buffer::set("mods", self::getMods());//加载的模块列表
|
||||
Buffer::set("user", []);//清空用户列表
|
||||
Buffer::set("time_send", false);//发送Timing数据到管理群
|
||||
Buffer::set("cmd_prefix", DP::getJsonData("config.json")["cmd_prefix"] ?? "");//设置指令的前缀符号
|
||||
Buffer::set("res_code", file_get_contents(WORKING_DIR . "src/cqbot/Framework.php"));
|
||||
Buffer::set("res_code", file_get_contents(WORKING_DIR . "src/framework/Framework.php"));
|
||||
Buffer::set("group_list", DP::getJsonData("group_list.json"));//获取群组列表
|
||||
|
||||
|
||||
//加载全局屏蔽的机器人列表
|
||||
Buffer::set("bots", DP::getJsonData("bots.json"));
|
||||
|
||||
//调用各个模块单独的Buffer数据
|
||||
foreach (self::getMods() as $v) {
|
||||
if (in_array("initValues", get_class_methods($v))) {
|
||||
$v::initValues();
|
||||
@ -29,11 +33,9 @@ class CQUtil
|
||||
public static function saveAllFiles() {
|
||||
Console::info("Saving files...");
|
||||
|
||||
//保存cmd_prefix(指令前缀)
|
||||
$config = DP::getJsonData("config.json");
|
||||
$config["cmd_prefix"] = Buffer::get("cmd_prefix");
|
||||
$config["super_user"] = Buffer::get("su");
|
||||
DP::setJsonData("config.json", $config);
|
||||
DP::setJsonData("bots.json", Buffer::get("bots"));
|
||||
DP::setJsonData("group_list.json", Buffer::get("group_list"));
|
||||
|
||||
|
||||
//保存用户数据
|
||||
foreach (self::getAllUsers() as $k => $v) {
|
||||
@ -46,17 +48,16 @@ class CQUtil
|
||||
/**
|
||||
* 生成报错日志
|
||||
* @param $log
|
||||
* @param $self_id
|
||||
* @param string $head
|
||||
* @param int $send_debug_message
|
||||
*/
|
||||
public static function errorLog($log, $self_id, $head = "ERROR", $send_debug_message = 1) {
|
||||
public static function errorLog($log, $head = "ERROR", $send_debug_message = 1) {
|
||||
Console::error($log, ($head === "ERROR") ? null : "[" . $head . "] ");
|
||||
$time = date("Y-m-d H:i:s");
|
||||
$msg = "[$head @ $time]: $log\n";
|
||||
file_put_contents(DP::getDataFolder() . "log_error.txt", $msg, FILE_APPEND);
|
||||
if ($send_debug_message)
|
||||
self::sendDebugMsg($msg, $self_id);
|
||||
self::sendDebugMsg($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,16 +67,26 @@ class CQUtil
|
||||
* @param int $need_head
|
||||
* @return null
|
||||
*/
|
||||
static function sendDebugMsg($msg, $self_id, $need_head = 1) {
|
||||
if (Framework::$admin_group[strval($self_id)] == "") return null;
|
||||
static function sendDebugMsg($msg, $self_id = null, $need_head = 1) {
|
||||
if ($self_id === null) $self_id = self::findRobot();
|
||||
if ($self_id === null) return null;
|
||||
|
||||
if ((Buffer::get("admin_group") ?? "") == "") return null;
|
||||
if ($need_head)
|
||||
$data = CQMsg("[DEBUG] " . date("H:i:s") . ": " . $msg, "group", Framework::$admin_group);
|
||||
$data = CQMsg("[DEBUG] " . date("H:i:s") . ": " . $msg, "group", Buffer::get("admin_group"));
|
||||
else
|
||||
$data = CQMsg($msg, "group", Framework::$admin_group);
|
||||
$data = CQMsg($msg, "group", Buffer::get("admin_group"));
|
||||
$connect = CQUtil::getApiConnectionByQQ($self_id);
|
||||
return self::sendAPI($connect->fd, $data, ["send_debug_msg"]);
|
||||
}
|
||||
|
||||
static function findRobot() {
|
||||
foreach (self::getConnections("api") as $v) {
|
||||
return $v->getQQ();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送API,给API端口
|
||||
* @param $fd
|
||||
@ -98,9 +109,7 @@ class CQUtil
|
||||
}*/
|
||||
if (Buffer::$event->push($fd, $data) === false) {
|
||||
$data = self::unicodeDecode($data);
|
||||
$connect = self::getConnection($fd);
|
||||
self::errorlog("API推送失败,未发送的消息: \n" . $data, $connect->getQQ(), "API ERROR", 0);
|
||||
self::sendErrorEmail("API推送失败", "未成功推送的消息:<br>$data<br>请检查酷q是否开启及网络链接情况<br>在此期间,机器人会中断所有消息处理<br>请及时处理", $connect->getQQ());
|
||||
self::errorlog("API推送失败,未发送的消息: \n" . $data, "API ERROR", 0);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -218,7 +227,7 @@ class CQUtil
|
||||
unset($mail);
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
self::errorLog("发送邮件错误!错误信息:" . $info = $mail->ErrorInfo, $self_id, "ERROR", $send_debug_message);
|
||||
self::errorLog("发送邮件错误!错误信息:" . $info = $mail->ErrorInfo, "ERROR", 0);
|
||||
unset($mail);
|
||||
return $info;
|
||||
}
|
||||
@ -257,15 +266,22 @@ class CQUtil
|
||||
|
||||
/**
|
||||
* @param $fd
|
||||
* @param null $type
|
||||
* @param null $qq
|
||||
* @return WSConnection
|
||||
*/
|
||||
static function getConnection($fd) {
|
||||
static function getConnection($fd, $type = null, $qq = null) {
|
||||
//var_dump(Buffer::$connect);
|
||||
if (!isset(Buffer::$connect[$fd])) {
|
||||
$s = new WSConnection(Buffer::$event, $fd);
|
||||
Buffer::$connect[$fd] = $s;
|
||||
if (!isset(Buffer::$connect[$fd]) && $type !== null && $qq !== null) {
|
||||
Console::info("创建连接 " . $fd . " 中...");
|
||||
$s = new WSConnection(Buffer::$event, $fd, $type, $qq);
|
||||
if ($s->create_success) {
|
||||
Buffer::$connect[$fd] = $s;
|
||||
Console::debug("创建成功!");
|
||||
$s->initConnection();
|
||||
} else return null;
|
||||
}
|
||||
return Buffer::$connect[$fd];
|
||||
return Buffer::$connect[$fd] ?? null;
|
||||
}
|
||||
|
||||
static function getApiConnectionByQQ($qq) {
|
||||
@ -367,7 +383,7 @@ class CQUtil
|
||||
* 获取所有已经加载到内存的用户。
|
||||
* read_all为true时,会加载所有User.dat到内存中,false时仅会读取已经加载到内存的用户
|
||||
* @param bool $real_all
|
||||
* @return array[User]
|
||||
* @return User[]
|
||||
*/
|
||||
static function getAllUsers($real_all = false): array {
|
||||
if ($real_all === true) {
|
||||
@ -640,16 +656,6 @@ class CQUtil
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回群的类
|
||||
* @param $group_id
|
||||
* @return Group|null
|
||||
*/
|
||||
static function getGroup($group_id) {
|
||||
$d = Buffer::get("groups");
|
||||
return $d[$group_id] ?? null;
|
||||
}
|
||||
|
||||
static function getCQ($msg) {
|
||||
if (($start = mb_strpos($msg, '[')) === false) return null;
|
||||
if (($end = mb_strpos($msg, ']')) === false) return null;
|
||||
@ -666,4 +672,41 @@ class CQUtil
|
||||
}
|
||||
return ["type" => $type, "params" => $array, "start" => $start, "end" => $end];
|
||||
}
|
||||
|
||||
static function isRobot($user_id) {
|
||||
$robots = [];
|
||||
foreach (Buffer::get("robots") as $v) {
|
||||
$robots[] = $v["qq"];
|
||||
}
|
||||
foreach (Buffer::get("bots") as $v) {
|
||||
$robots[] = $v;
|
||||
}
|
||||
return in_array($user_id, $robots);
|
||||
}
|
||||
|
||||
static function getRobotNum($qq) {
|
||||
$ls = Buffer::get("robots");
|
||||
foreach ($ls as $k => $v) {
|
||||
if ($v["qq"] == $qq)
|
||||
return $k;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新消息速率(每分钟)
|
||||
* 当 $insert 为 true 时,表明运行此函数时收到了一条消息
|
||||
* @param bool $insert
|
||||
*/
|
||||
static function updateMsg($insert = true) {
|
||||
$ls = Buffer::get("msg_speed");
|
||||
if ($insert === true)
|
||||
$ls [] = time();
|
||||
foreach ($ls as $k => $v) {
|
||||
if ((time() - $v) > 60) {
|
||||
array_splice($ls, $k, 1);
|
||||
}
|
||||
}
|
||||
Buffer::set("msg_speed", $ls);
|
||||
}
|
||||
}
|
||||
24
src/cqbot/utils/FriendManager.php
Normal file
24
src/cqbot/utils/FriendManager.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/9/17
|
||||
* Time: 2:02 PM
|
||||
*/
|
||||
|
||||
class FriendManager
|
||||
{
|
||||
|
||||
public static function updateFriendList() {
|
||||
$list = CQUtil::getAllUsers(true);
|
||||
foreach ($list as $k => $v) {
|
||||
$v->setFriend([]);
|
||||
}
|
||||
foreach (CQUtil::getConnections("api") as $k => $v) {
|
||||
$fd = $v->fd;
|
||||
$robot_id = $v->getQQ();
|
||||
Console::put("正在获取机器人 " . $robot_id . " 的好友列表...");
|
||||
CQUtil::sendAPI($fd, ["action" => "_get_friend_list", "params" => ["flat" => "true"]], ["get_friend_list", "step1"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/cqbot/utils/GroupManager.php
Normal file
24
src/cqbot/utils/GroupManager.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/9/17
|
||||
* Time: 2:00 PM
|
||||
*/
|
||||
|
||||
class GroupManager
|
||||
{
|
||||
/**
|
||||
* 更新群组列表
|
||||
* @param null $qq
|
||||
*/
|
||||
public static function updateGroupList($qq = null) {
|
||||
Buffer::set("group_list", []);
|
||||
foreach (CQUtil::getConnections("api") as $k => $v) {
|
||||
$fd = $v->fd;
|
||||
$robot_id = $v->getQQ();
|
||||
Console::put("正在获取机器人 " . $robot_id . " 的群组列表...");
|
||||
CQUtil::sendAPI($fd, "get_group_list", ["get_group_list", "step1"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/cqbot/utils/WSConnection.php
Normal file
70
src/cqbot/utils/WSConnection.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/6/13
|
||||
* Time: 8:10 PM
|
||||
*/
|
||||
|
||||
class WSConnection
|
||||
{
|
||||
public $fd;
|
||||
|
||||
/**
|
||||
* 0 = event连接
|
||||
* 1 = api连接
|
||||
* 默认为event连接,如果可以收到返回的get_status则标记为1
|
||||
* @var int
|
||||
*/
|
||||
protected $type = 0;
|
||||
|
||||
protected $server;
|
||||
|
||||
protected $qq = "";
|
||||
|
||||
public $create_success = false;
|
||||
|
||||
public function __construct(swoole_websocket_server $server, $fd, $type, $qq) {
|
||||
$this->server = $server;
|
||||
$this->fd = $fd;
|
||||
if ($type = null || $qq === null) return;
|
||||
$this->type = ($type == "event" ? 0 : 1);
|
||||
$this->qq = $qq;
|
||||
$this->create_success = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回swoole server
|
||||
* @return swoole_websocket_server
|
||||
*/
|
||||
public function getServer() {
|
||||
return $this->server;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回本连接是什么类型的
|
||||
* @return int
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function initConnection() {
|
||||
foreach (CQUtil::getConnections(($this->getType() == 0 ? "event" : "api")) as $k => $v) {
|
||||
if ($v->getQQ() == $this->getQQ() && $k != $this->fd) {
|
||||
$this->server->close($k);
|
||||
unset(Buffer::$connect[$k]);
|
||||
}
|
||||
}
|
||||
if ($this->type === 1) {
|
||||
new APIConnectEvent($this, $this->server);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getQQ() {
|
||||
return $this->qq;
|
||||
}
|
||||
}
|
||||
@ -23,10 +23,10 @@ class Buffer
|
||||
static $in_count;//接收消息
|
||||
/** @var \swoole_atomic $out_count */
|
||||
static $out_count;//发送消息数量
|
||||
/** @var \swoole_atomic $out_count */
|
||||
static $api_id;//API调用ID
|
||||
/** @var WSConnection[] */
|
||||
static $connect = [];
|
||||
/** @var swoole_atomic $reload_time */
|
||||
static $reload_time;
|
||||
|
||||
static function get($name){ return self::$data[$name] ?? null; }
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
class Console
|
||||
{
|
||||
static function setColor($string, $color = ""){
|
||||
static function setColor($string, $color = "") {
|
||||
switch ($color) {
|
||||
case "red":
|
||||
return "\x1b[38;5;203m" . $string . "\x1b[m";
|
||||
@ -36,26 +36,30 @@ class Console
|
||||
}
|
||||
|
||||
|
||||
static function debug($obj, $head = null){
|
||||
if ($head === null) $head = "[DEBUG] " . date("H:i:s") . " ";
|
||||
if (Buffer::get("info_level") < 2) return;
|
||||
static function debug($obj, $head = null) {
|
||||
if ($head === null) $head = "[" . date("H:i:s") . " DEBUG]";
|
||||
if ((Buffer::get("info_level") ?? 0) < 2) return;
|
||||
if (!is_string($obj)) var_dump($obj);
|
||||
else echo(self::setColor($head . $obj, "green") . "\n");
|
||||
}
|
||||
|
||||
static function error($obj, $head = null){
|
||||
if ($head === null) $head = "[ERROR] " . date("H:i:s") . " ";
|
||||
static function error($obj, $head = null) {
|
||||
if ($head === null) $head = "[" . date("H:i:s") . " ERROR]";
|
||||
if (!is_string($obj)) var_dump($obj);
|
||||
else echo(self::setColor($head . $obj, "red") . "\n");
|
||||
}
|
||||
|
||||
static function info($obj, $head = null){
|
||||
if ($head === null) $head = "[INFO] " . date("H:i:s") . " ";
|
||||
static function info($obj, $head = null) {
|
||||
if ($head === null) $head = "[" . date("H:i:s") . " INFO] ";
|
||||
if (!is_string($obj)) var_dump($obj);
|
||||
else echo(self::setColor($head . $obj, "blue") . "\n");
|
||||
}
|
||||
|
||||
static function put($obj, $color = ""){
|
||||
static function chatLog($head, $msg) {
|
||||
|
||||
}
|
||||
|
||||
static function put($obj, $color = "") {
|
||||
if (!is_string($obj)) var_dump($obj);
|
||||
else echo(self::setColor($obj, $color) . "\n");
|
||||
}
|
||||
@ -10,7 +10,6 @@ class Framework
|
||||
{
|
||||
public static $super_user;
|
||||
public $host = "127.0.0.1";
|
||||
public $api_port = 10000;
|
||||
public $event_port = 20000;
|
||||
|
||||
/** @var \swoole_websocket_server $event */
|
||||
@ -19,7 +18,6 @@ class Framework
|
||||
public static $obj = null;
|
||||
|
||||
public $run_time;
|
||||
public static $admin_group;
|
||||
public $info_level = 1;
|
||||
|
||||
/** @var \swoole_http_client $api */
|
||||
@ -30,39 +28,26 @@ class Framework
|
||||
/** @var Scheduler */
|
||||
public $scheduler = null;
|
||||
|
||||
public function __construct(){ }
|
||||
public function __construct($config) {
|
||||
$this->host = $config["host"];
|
||||
$this->event_port = $config["port"];
|
||||
Buffer::set("access_token", $config["access_token"] ?? "");
|
||||
Buffer::set("info_level", $config["info_level"]);
|
||||
Buffer::set("admin_group", $config["admin_group"]);
|
||||
|
||||
public function setHost($host = ""){ $this->host = $host; }
|
||||
|
||||
public function setApiPort($port = 10000){ $this->api_port = $port; }
|
||||
|
||||
public function setEventPort($port = 20000){ $this->event_port = $port; }
|
||||
|
||||
public function setAdminGroup($group){ self::$admin_group = $group; }
|
||||
|
||||
public function setInfoLevel($level){ $this->info_level = $level; }
|
||||
|
||||
public function setSuperUser($option) { self::$super_user = $option; }
|
||||
|
||||
public function eventServerStart(){ $this->event->start(); }
|
||||
|
||||
public static function getInstance(){ return self::$obj; }
|
||||
|
||||
public function init() {
|
||||
$this->selfCheck();
|
||||
$this->checkFiles();
|
||||
Console::info("CQBot Framework starting...");
|
||||
$this->event = new \swoole_websocket_server($this->host, $this->event_port);
|
||||
|
||||
Buffer::$log_file = CONFIG_DIR . "log/swoole.log";
|
||||
Console::info("Current log file: " . Buffer::$log_file);
|
||||
Console::info("CQBot Framework starting...");
|
||||
$this->event = new swoole_websocket_server($this->host, $this->event_port);
|
||||
|
||||
Buffer::$log_file = CRASH_DIR . "swoole.log";
|
||||
|
||||
//设置swoole基本参数
|
||||
$worker_num = 1;
|
||||
$dispatch_mode = 2;
|
||||
$worker_num = 1;//进程数调整,默认为1,如果调整worker为多个,则需要自行修改Buffer类的储存方式到redis、或其他数据库等数据结构
|
||||
$dispatch_mode = 2;//解析模式,详见wiki.swoole.com
|
||||
$this->event->set([
|
||||
"log_file" => Buffer::$log_file,
|
||||
"worker_num" =>$worker_num,
|
||||
"worker_num" => $worker_num,
|
||||
"dispatch_mode" => $dispatch_mode
|
||||
]);
|
||||
|
||||
@ -73,8 +58,8 @@ class Framework
|
||||
$this->event->on('message', [$this, 'onEventMessage']);
|
||||
|
||||
//收到ws连接和断开连接回调的函数
|
||||
$this->event->on('open', [$this, 'onEventOpen']);
|
||||
$this->event->on('close', [$this, "onEventClose"]);
|
||||
$this->event->on('open', function (\swoole_websocket_server $server, \swoole_http_request $request) { new WSOpenEvent($server, $request); });
|
||||
$this->event->on('close', function (\swoole_server $server, int $fd) { new WSCloseEvent($server, $fd); });
|
||||
|
||||
//设置接收HTTP接口接收的内容,兼容微信公众号和其他服务用
|
||||
$this->event->on("request", [$this, "onRequest"]);
|
||||
@ -82,9 +67,13 @@ class Framework
|
||||
//设置原子计数器
|
||||
Buffer::$in_count = new \swoole_atomic(1);
|
||||
Buffer::$out_count = new \swoole_atomic(1);
|
||||
Buffer::$api_id = new \swoole_atomic(1);
|
||||
Buffer::$reload_time = new \swoole_atomic(0);
|
||||
}
|
||||
|
||||
public function start() { $this->event->start(); }
|
||||
|
||||
public static function getInstance() { return self::$obj; }
|
||||
|
||||
/* Callback function down here */
|
||||
|
||||
/**
|
||||
@ -102,26 +91,12 @@ class Framework
|
||||
new WorkerStartEvent($server, $worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回调函数:有客户端或HTTP插件反向客户端连接时调用
|
||||
* @param swoole_websocket_server $server
|
||||
* @param swoole_http_request $request
|
||||
*/
|
||||
public function onEventOpen(\swoole_websocket_server $server, \swoole_http_request $request){ new WSOpenEvent($server, $request); }
|
||||
|
||||
/**
|
||||
* 回调函数:断开连接时候回调的函数
|
||||
* @param swoole_server $server
|
||||
* @param int $fd
|
||||
*/
|
||||
public function onEventClose(\swoole_server $server, int $fd) { new WSCloseEvent($server, $fd); }
|
||||
|
||||
/**
|
||||
* 回调函数:当HTTP插件发来json包后激活此函数
|
||||
* @param swoole_websocket_server $server
|
||||
* @param $frame
|
||||
*/
|
||||
public function onEventMessage($server, $frame){ new WSMessageEvent($server, $frame); }
|
||||
public function onEventMessage($server, $frame) { new WSMessageEvent($server, $frame); }
|
||||
|
||||
/**
|
||||
* 回调函数:当IP:event端口收到相关HTTP请求时候调用
|
||||
@ -130,13 +105,13 @@ class Framework
|
||||
* @param swoole_http_request $request
|
||||
* @param swoole_http_response $response
|
||||
*/
|
||||
public function onRequest($request, $response){ new HTTPEvent($request, $response); }
|
||||
public function onRequest($request, $response) { new HTTPEvent($request, $response); }
|
||||
|
||||
/**
|
||||
* 回调函数:异步计时器,一秒执行一次。请勿在此使用过多的阻塞方法
|
||||
* 回调函数:异步计时器,一秒执行一次。请勿在此使用阻塞IO方法
|
||||
* @param $id
|
||||
*/
|
||||
public function processTick($id){ $this->scheduler->tick($id, ($this->tick_time = time())); }
|
||||
public function processTick($id) { $this->scheduler->tick($id, ($this->tick_time = time())); }
|
||||
|
||||
/**
|
||||
* 开启时候的自检模块
|
||||
@ -147,18 +122,8 @@ class Framework
|
||||
if (!function_exists("mb_substr")) die("无法找到mbstring扩展,请先安装.\n");
|
||||
if (substr(PHP_VERSION, 0, 1) != "7") die("PHP >=7 required.\n");
|
||||
if (!function_exists("curl_exec")) die("无法找到curl扩展,请先安装.\n");
|
||||
if (!class_exists("ZipArchive")) die("无法找到zip扩展,请先安装.(如果不需要zip功能可以删除此条自检)\n");
|
||||
//if (!class_exists("ZipArchive")) die("无法找到zip扩展,请先安装.(如果不需要zip功能可以删除此条自检)\n");
|
||||
if (!is_file(CRASH_DIR . "swoole.log")) file_put_contents(CRASH_DIR . "swoole.log", "");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查必需的文件是否存在
|
||||
*/
|
||||
public function checkFiles(){
|
||||
@mkdir(CONFIG_DIR."log/", 0777, true);
|
||||
if(!is_file(CONFIG_DIR."log/last_error.log"))
|
||||
file_put_contents(CONFIG_DIR."log/last_error.log", "");
|
||||
if(!is_file(CONFIG_DIR."log/error_flag"))
|
||||
file_put_contents(CONFIG_DIR."log/error_flag", time());
|
||||
}
|
||||
}
|
||||
9
src/framework/loader.php
Normal file
9
src/framework/loader.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/10/28
|
||||
* Time: 4:41 PM
|
||||
*/
|
||||
|
||||
loadAllClass(WORKING_DIR . "src/framework/");
|
||||
66
start.php
66
start.php
@ -1,35 +1,51 @@
|
||||
<?php
|
||||
|
||||
function loadAllClass($dir) {
|
||||
$dir_obj = scandir($dir);
|
||||
unset($dir_obj[0], $dir_obj[1]);
|
||||
foreach ($dir_obj as $m) {
|
||||
$taskFileName = explode(".", $m);
|
||||
if (is_dir($dir . $m . "/")) loadAllClass($dir . $m . "/");
|
||||
else {
|
||||
if (count($taskFileName) < 2 || ($taskFileName[1] != "php" && $taskFileName[1] != "phar")) continue;
|
||||
require_once($dir . $m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//工作目录设置
|
||||
define("WORKING_DIR", __DIR__ . "/");
|
||||
define("CONFIG_DIR", WORKING_DIR . "config/");
|
||||
define("USER_DIR", WORKING_DIR . "users");
|
||||
|
||||
function settings() { return json_decode(file_get_contents(WORKING_DIR . "/cqbot.json"), true); }
|
||||
|
||||
if (settings() === null) die("Start failed. Please check cqbot.json file.\n");
|
||||
|
||||
//启动时间
|
||||
define("START_TIME", time());
|
||||
|
||||
//设置dir常量
|
||||
define("CQ_DATA", WORKING_DIR . settings()["cq_data"]);
|
||||
define("CONFIG_DIR", WORKING_DIR . settings()["config_dir"]);
|
||||
define("USER_DIR", WORKING_DIR . settings()["user_dir"]);
|
||||
define("CRASH_DIR", WORKING_DIR . settings()["crash_dir"]);
|
||||
@mkdir(CQ_DATA, 0777, true);
|
||||
@mkdir(CONFIG_DIR, 0777, true);
|
||||
@mkdir(USER_DIR, 0777, true);
|
||||
@mkdir(CRASH_DIR, 0777, true);
|
||||
|
||||
//设置时区(如果非国内用户请自行注释或更改)
|
||||
date_default_timezone_set("Asia/Shanghai");
|
||||
|
||||
//加载框架
|
||||
require(WORKING_DIR . "src/framework/loader.php");
|
||||
|
||||
//加载全局函数
|
||||
require("tools.php");
|
||||
|
||||
//loading projects
|
||||
require(WORKING_DIR . "src/cqbot/Framework.php");
|
||||
require(WORKING_DIR . "src/cqbot/utils/Buffer.php");
|
||||
require(WORKING_DIR . "src/cqbot/utils/ErrorStatus.php");
|
||||
require(WORKING_DIR . "src/cqbot/utils/Console.php");
|
||||
|
||||
//初始参数设置:host、端口、多个机器人号对应的admin_group、事件等级、多个机器人号对应的超级管理员
|
||||
$properties["host"] = "0.0.0.0";
|
||||
$properties["port"] = 20000;
|
||||
$properties["admin_group"] = [];
|
||||
$properties["info_level"] = 1;
|
||||
$properties["super_user"] = [];
|
||||
|
||||
$json = json_decode(file_get_contents(CONFIG_DIR . "config.json"), true);
|
||||
|
||||
if (!isset($json["host"]) || !isset($json["port"])) setupWizard($json, $properties);
|
||||
//如果是第一次启动或监听地址为空,则启动配置向导
|
||||
if (settings()["host"] == "" || settings()["port"] == "") include("wizard.php");
|
||||
|
||||
//initializing framework
|
||||
$cqbot = new Framework();
|
||||
$cqbot->setHost($properties["host"]);
|
||||
$cqbot->setEventPort($properties["port"]);
|
||||
$cqbot->setAdminGroup($properties["admin_group"]);
|
||||
$cqbot->setInfoLevel($properties["info_level"]);
|
||||
$cqbot->setSuperUser($properties["super_user"]);
|
||||
$cqbot->init();
|
||||
$cqbot->eventServerStart();
|
||||
$cqbot = new Framework(settings());
|
||||
$cqbot->start();
|
||||
107
tools.php
107
tools.php
@ -6,17 +6,7 @@
|
||||
* Time: 11:04 AM
|
||||
*/
|
||||
|
||||
date_default_timezone_set("Asia/Shanghai");
|
||||
|
||||
//启动时间
|
||||
define("START_TIME", time());
|
||||
@mkdir(CONFIG_DIR, 0777, true);
|
||||
@mkdir(USER_DIR, 0777, true);
|
||||
register_shutdown_function('handleFatal');
|
||||
|
||||
if (!file_exists(CONFIG_DIR . "config.json")) file_put_contents(CONFIG_DIR . "config.json", json_encode([]));
|
||||
|
||||
function handleFatal() {
|
||||
register_shutdown_function(function () {
|
||||
$error = error_get_last();
|
||||
if (isset($error['type'])) {
|
||||
switch ($error['type']) {
|
||||
@ -47,13 +37,14 @@ function handleFatal() {
|
||||
$log .= "{$t['function']}()\n";
|
||||
}
|
||||
|
||||
file_put_contents(CONFIG_DIR . "last_error.log", $log);
|
||||
file_put_contents(CRASH_DIR . "last_error.log", $log);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function CQMsg($msg, $type, $id) {
|
||||
if ($type === "group") {
|
||||
@ -77,96 +68,6 @@ function CQMsg($msg, $type, $id) {
|
||||
return $reply;
|
||||
}
|
||||
|
||||
function printHelp() {
|
||||
echo color("{gold}=====CQBot-swoole=====");
|
||||
echo color("{gold}* 首次使用设置 *");
|
||||
echo color("[{green}?{r}] {lightlightblue}查看此列表");
|
||||
echo color("[{green}1{r}] {yellow}设置监听地址");
|
||||
echo color("[{green}2{r}] {yellow}设置监听端口");
|
||||
echo color("[{green}3{r}] {yellow}设置管理群");
|
||||
echo color("[{green}4{r}] {yellow}设置管理员");
|
||||
echo color("[{green}5{r}] {lightlightblue}开始运行");
|
||||
}
|
||||
|
||||
function setupWizard(&$json, &$properties) {
|
||||
printHelp();
|
||||
while (true) {
|
||||
echo color("> ", "");
|
||||
$id = trim(fgets(STDIN));
|
||||
switch ($id) {
|
||||
case "1":
|
||||
echo color("请输入监听地址(默认0.0.0.0):", "");
|
||||
$host = trim(fgets(STDIN));
|
||||
if ($host == "") {
|
||||
$properties["host"] = "0.0.0.0";
|
||||
echo color("{gray}已设置地址:0.0.0.0(默认)");
|
||||
} else {
|
||||
$properties["host"] = $host;
|
||||
echo color("{gray}已设置地址:" . $host);
|
||||
}
|
||||
break;
|
||||
case "2":
|
||||
echo color("请输入监听端口(默认20000):", "");
|
||||
$host = trim(fgets(STDIN));
|
||||
if ($host == "") {
|
||||
$properties["port"] = 20000;
|
||||
echo color("{gray}已设置端口:20000(默认)");
|
||||
} else {
|
||||
$properties["port"] = $host;
|
||||
echo color("{gray}已设置端口:" . $host);
|
||||
}
|
||||
break;
|
||||
case "3":
|
||||
echo color("请输入机器人QQ号:", "");
|
||||
$self_id = trim(fgets(STDIN));
|
||||
if ($self_id == "") {
|
||||
echo color("{red}请勿输入空数据!");
|
||||
break;
|
||||
}
|
||||
echo color("请输入本机器人QQ的管理群(机器人必须已经在群内):", "");
|
||||
$group = trim(fgets(STDIN));
|
||||
if ($group == "") {
|
||||
echo color("{red}请勿输入空数据!");
|
||||
break;
|
||||
}
|
||||
$properties["admin_group"][$self_id][] = $group;
|
||||
echo color("{gray}已设置机器人" . $self_id . "的管理群:" . $group);
|
||||
break;
|
||||
case "4":
|
||||
echo color("请输入机器人QQ号:", "");
|
||||
$self_id = trim(fgets(STDIN));
|
||||
if ($self_id == "") {
|
||||
echo color("{red}请勿输入空数据!");
|
||||
break;
|
||||
}
|
||||
echo color("请输入本机器人QQ的管理员QQ:", "");
|
||||
$group = trim(fgets(STDIN));
|
||||
if ($group == "") {
|
||||
echo color("{red}请勿输入空数据!");
|
||||
break;
|
||||
}
|
||||
$properties["super_user"][$self_id][] = $group;
|
||||
echo color("{gray}已设置机器人" . $self_id . "的管理员:" . $group);
|
||||
break;
|
||||
case "5":
|
||||
break 2;
|
||||
case "?":
|
||||
case "?":
|
||||
printHelp();
|
||||
break;
|
||||
default:
|
||||
echo color("{red}请输入正确的编号进行操作!\n在设置监听端口和监听地址后可开始运行服务器");
|
||||
break;
|
||||
}
|
||||
}
|
||||
$json["host"] = $properties["host"];
|
||||
$json["port"] = $properties["port"];
|
||||
$json["admin_group"] = $properties["admin_group"];
|
||||
$json["super_user"] = $properties["super_user"];
|
||||
$json["info_level"] = $properties["info_level"];
|
||||
file_put_contents(CONFIG_DIR . "config.json", json_encode($json, 128 | 256));
|
||||
}
|
||||
|
||||
function color($str, $end = "\n") {
|
||||
$str = str_replace("{red}", "\e[38;5;203m", $str);
|
||||
$str = str_replace("{green}", "\e[38;5;83m", $str);
|
||||
|
||||
103
wizard.php
Normal file
103
wizard.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: jerry
|
||||
* Date: 2018/10/28
|
||||
* Time: 4:43 PM
|
||||
*/
|
||||
|
||||
function printHelp() {
|
||||
echo color("{gold}=======CQBot-swoole=======");
|
||||
echo color("{gold}* 首次使用设置 *");
|
||||
echo color("{red}红色{r}为未设置,{green}绿色{r}为已设置,其他颜色为可选设置");
|
||||
echo color("[{green}1{r}] {" . (settings()["host"] == "" ? "red" : "green") . "}设置监听地址");
|
||||
echo color("[{green}2{r}] {" . (settings()["port"] == "" ? "red" : "green") . "}设置监听端口");
|
||||
echo color("[{green}3{r}] {" . (settings()["admin_group"] == "" ? "red" : "green") . "}设置管理群");
|
||||
echo color("[{green}4{r}] {yellow}设置管理员");
|
||||
echo color("[{green}5{r}] {yellow}设置连接token");
|
||||
echo color("[{green}6{r}] {lightlightblue}开始运行");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
printHelp();
|
||||
echo color("> ", "");
|
||||
$id = trim(fgets(STDIN));
|
||||
switch ($id) {
|
||||
case "1":
|
||||
echo color("请输入监听地址(默认0.0.0.0):", "");
|
||||
$host = trim(fgets(STDIN));
|
||||
if ($host == "") {
|
||||
$properties["host"] = "0.0.0.0";
|
||||
echo color("{gray}已设置地址:0.0.0.0(默认)");
|
||||
} else {
|
||||
$properties["host"] = $host;
|
||||
echo color("{gray}已设置地址:" . $host);
|
||||
}
|
||||
$ls = settings();
|
||||
$ls["host"] = $properties["host"];
|
||||
file_put_contents("cqbot.json", json_encode($ls, 128 | 256));
|
||||
break;
|
||||
case "2":
|
||||
echo color("请输入监听端口(默认20000):", "");
|
||||
$host = trim(fgets(STDIN));
|
||||
if ($host == "") {
|
||||
$properties["port"] = 20000;
|
||||
echo color("{gray}已设置端口:20000(默认)");
|
||||
} else {
|
||||
$properties["port"] = $host;
|
||||
echo color("{gray}已设置端口:" . $host);
|
||||
}
|
||||
$ls = settings();
|
||||
$ls["port"] = $properties["port"];
|
||||
file_put_contents("cqbot.json", json_encode($ls, 128 | 256));
|
||||
break;
|
||||
case "3":
|
||||
echo color("请输入机器人QQ的管理群(机器人必须已经在群内):", "");
|
||||
$group = trim(fgets(STDIN));
|
||||
if ($group == "") {
|
||||
echo color("{red}请勿输入空数据!");
|
||||
break;
|
||||
}
|
||||
$properties["admin_group"] = $group;
|
||||
echo color("{gray}已设置机器人的管理群:" . $group);
|
||||
$ls = settings();
|
||||
$ls["admin_group"] = $properties["admin_group"];
|
||||
file_put_contents("cqbot.json", json_encode($ls, 128 | 256));
|
||||
break;
|
||||
case "4":
|
||||
echo color("请输入机器人管理员QQ:", "");
|
||||
$group = trim(fgets(STDIN));
|
||||
if ($group == "") {
|
||||
echo color("{red}请勿输入空数据!");
|
||||
break;
|
||||
}
|
||||
$properties["admin"][] = $group;
|
||||
echo color("{gray}已设置机器人的管理员:" . $group);
|
||||
$ls = settings();
|
||||
$ls["admin"] = $properties["admin"];
|
||||
file_put_contents("cqbot.json", json_encode($ls, 128 | 256));
|
||||
break;
|
||||
case "5":
|
||||
echo color("请输入连接框架的access_token:", "");
|
||||
$group = trim(fgets(STDIN));
|
||||
$properties["access_token"] = $group;
|
||||
if ($group == "") echo color("{gray}token为空,将不检测验证token!");
|
||||
else echo color("{gray}已设置websocket连接token:" . $group);
|
||||
$ls = settings();
|
||||
$ls["access_token"] = $properties["access_token"];
|
||||
file_put_contents("cqbot.json", json_encode($ls, 128 | 256));
|
||||
break;
|
||||
case "6":
|
||||
break 2;
|
||||
case "?":
|
||||
case "?":
|
||||
case "0":
|
||||
printHelp();
|
||||
break;
|
||||
default:
|
||||
echo color("{red}请输入正确的编号进行操作!\n在设置监听端口和监听地址后可开始运行服务器");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (settings()["host"] != "") return true;
|
||||
else return false;
|
||||
Loading…
x
Reference in New Issue
Block a user