重构完成

This commit is contained in:
jerry 2018-10-29 11:47:58 +08:00
parent 76dd436093
commit 0ff0feabca
42 changed files with 1173 additions and 1037 deletions

3
.gitignore vendored
View File

@ -6,3 +6,6 @@
.idea
out
gen
config/
cq_data/
composer.lock

15
cqbot.json Normal file
View 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": []
}

View File

@ -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;
}
}

View File

@ -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']);
}
}
}
}

View File

@ -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);
}
}

View 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);
}
}

View 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;
}
}
}

View 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) {
}
}

View 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;
}
}
}
}

View 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.");
}
}

View 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());
}
}

View File

@ -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);
}
}

View 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;
}
}
}

View 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;
}
}
}

View File

@ -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");

View 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
View 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("&", "&amp;", $str);
$str = str_replace("[", "&#91;", $str);
$str = str_replace("]", "&#93;", $str);
return $str;
}
/**
* 反转义字符串中的CQ码敏感符号
* @param $str
* @return mixed
*/
public static function decode($str) {
$str = str_replace("&amp;", "&", $str);
$str = str_replace("&#91;", "[", $str);
$str = str_replace("&#93;", "]", $str);
return $str;
}
public static function replace($str) {
$str = str_replace("{{", "[", $str);
$str = str_replace("}}", "]", $str);
return $str;
}
}

View File

@ -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;
}
}

View File

@ -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]);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}
}
}

View File

@ -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");

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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"]; }
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View 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"]);
}
}
}

View 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"]);
}
}
}

View 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;
}
}

View File

@ -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; }

View File

@ -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");
}

View File

@ -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
View File

@ -0,0 +1,9 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/10/28
* Time: 4:41 PM
*/
loadAllClass(WORKING_DIR . "src/framework/");

View File

@ -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
View File

@ -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
View 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;