更新下一个大版本,基本上算是重写了一遍吧~

This commit is contained in:
jerry 2018-06-03 15:40:28 +08:00
parent 0890a9bf6c
commit cfef2620ef
20 changed files with 906 additions and 260 deletions

View File

@ -9,9 +9,9 @@
class Framework
{
public static $super_user;
private $host = "127.0.0.1";
private $api_port = 10000;
private $event_port = 20000;
public $host = "127.0.0.1";
public $api_port = 10000;
public $event_port = 20000;
/** @var \swoole_websocket_server $event */
public $event;
@ -27,85 +27,61 @@ class Framework
private $log_file;
public $tick_time;
/** @var Scheduler */
public $scheduler = null;
public function __construct(){ }
/**
* @param string $host
* @return $this
*/
public function setHost($host = ""){
$this->host = $host;
return $this;
}
public function setHost($host = ""){ $this->host = $host; }
public function setApiPort($port = 10000){
$this->api_port = $port;
return $this;
}
public function setApiPort($port = 10000){ $this->api_port = $port; }
public function setEventPort($port = 20000){
$this->event_port = $port;
return $this;
}
public function setEventPort($port = 20000){ $this->event_port = $port; }
public function setAdminGroup($group){
self::$admin_group = $group;
return $this;
}
public function setAdminGroup($group){ self::$admin_group = $group; }
public function setInfoLevel($level){
$this->info_level = $level;
return $this;
}
public function setInfoLevel($level){ $this->info_level = $level; }
public function eventServerStart(){
$this->event->start();
}
public function eventServerStart(){ $this->event->start(); }
public static function getInstance(){
return self::$obj;
}
public static function getInstance(){ return self::$obj; }
public function init($option = null){
self::$super_user = ($option !== null ? $option : "");
self::$obj = $this;
public function init($option = []){
$this->selfCheck();
$this->checkFiles();
self::$super_user = $option;
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);
//设置swoole基本参数
$worker_num = 1;
Console::info("Current worker count: " . $worker_num);
$dispatch_mode = 2;
Console::info("Current dispatch mode: " . $dispatch_mode);
$this->checkFiles();
$this->event->set([
"log_file" => Buffer::$log_file,
"worker_num" => 1,
"dispatch_mode" => 2
"worker_num" =>$worker_num,
"dispatch_mode" => $dispatch_mode
]);
//swoole服务器启动时运行的函数
$this->event->on('WorkerStart', [$this, 'onWorkerStart']);
//swoole服务端收到WebSocket信息时运行的函数
$this->event->on('message', [$this, 'onEventMessage']);
//$this->event->on('open', [$this, 'onConnect']);
$this->event->on('open', function ($server, $request){
Console::put("EVENT connection established", "lightblue");
});
//收到ws连接和断开连接回调的函数
$this->event->on('open', [$this, 'onEventOpen']);
$this->event->on('close', [$this, "onEventClose"]);
//设置接收HTTP接口接收的内容兼容微信公众号和其他服务用
$this->event->on("request", [$this, "onRequest"]);
$this->event->on('close', function ($serv, $fd){
Console::info(Console::setColor("EVENT connection closed","red"));
//put your connection close method here.
});
//设置原子计数器
Buffer::$in_count = new \swoole_atomic(1);
Buffer::$out_count = new \swoole_atomic(1);
Buffer::$api_id = new \swoole_atomic(1);
return $this;
}
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());
}
/* Callback function down here */
@ -116,173 +92,78 @@ class Framework
* @param \swoole_server $server
* @param $worker_id
*/
public function onWorkerStart(\swoole_server $server, $worker_id){
public function onWorkerStart(\swoole_server $server, $worker_id) {
self::$obj = $this;
$this->run_time = time();
Buffer::set("info_level", $this->info_level);//设置info等级
Console::info("Starting worker: " . $worker_id);
require_once(WORKING_DIR . "src/cqbot/loader.php");
CQUtil::loadAllFiles();
foreach (get_included_files() as $file)
Console::debug("Loaded " . $file);
//计时器ms
$server->tick(1000, [$this, "processTick"]);
//API连接部分
$this->api = new \swoole_http_client($this->host, $this->api_port);
$this->api->set(['websocket_mask' => true]);
$this->api->on('message', [$this, "onApiMessage"]);
$this->api->on("close", function ($cli){
Console::info(Console::setColor("API connection closed", "red"));
});
$this->api->upgrade('/api/', [$this, "onUpgrade"]);
Console::debug("master_pid = " . $server->master_pid);
Console::debug("worker_id = " . $worker_id);
Console::put("\n==========STARTUP DONE==========\n");
new WorkerStartEvent($server, $worker_id);
}
public function onUpgrade($cli){
Console::info("Upgraded API websocket");
Buffer::$api = $this->api;
Buffer::$event = $this->event;
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("检测到重复引起异常,停止服务器", 0);
file_put_contents(CONFIG_DIR."log/last_error.log", "");
$this->event->shutdown();
return;
}
CQUtil::sendDebugMsg("检测到异常", 0);
$msg = "";
foreach ($data as $e) {
$msg = $msg . $e . "\n";
}
CQUtil::sendDebugMsg($msg, 0);
CQUtil::sendDebugMsg("[CQBot] 成功开启!", 0);
file_put_contents(CONFIG_DIR . "error_flag", time());
file_put_contents(CONFIG_DIR . "last_error.log", "");
}
else {
CQUtil::sendDebugMsg("[CQBot] 成功开启!", 0);
}
}
/**
* 回调函数API连接升级为WebSocket时候调用可用于成功和酷Qhttp建立连接的检测依据
* @param $cli
*/
public function onUpgrade($cli){ new ApiUpgradeEvent($cli); }
/**
* 回调函数有客户端或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); }
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){
$in_count = Buffer::$in_count->get();
Buffer::$in_count->add(1);
$req = json_decode($frame->data, true);
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($this->executeType($req), "gold")));
}
//传入业务逻辑CQBot
try {
$c = new CQBot($this);
$c->execute($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);
} catch (Exception $e) {
CQUtil::errorlog("处理消息时异常,消息处理中断\n" . $e->getMessage() . "\n" . $e->getTraceAsString());
CQUtil::sendDebugMsg("引起异常的消息:\n" . var_export($req, true));
}
}
public function onEventMessage($server, $frame){ new WSMessageEvent($server, $frame); }
/******************* 微信HTTP 响应 ******************
/**
* 回调函数当IP:event端口收到相关HTTP请求时候调用
* 你可在此编写HTTP请求回复的内容比如做一个web界面
* 也可以在这里处理微信公众号的请求(可能需要端口转发)
* @param swoole_http_request $request
* @param swoole_http_response $response
*/
public function onRequest($request, $response){ new HTTPEvent($request, $response); }
public function onRequest($request, $response){
$response->end("Hello world");
}
/******************* API 响应 ******************
/**
* 回调函数API响应函数用于发送api请求后返回的状态包的检查比如rescode = 200
* @param swoole_http_client $client
* @param $frame
*/
public function onApiMessage($client, $frame){
public function onApiMessage($client, $frame){ new ApiMessageEvent($client, $frame); }
}
/***************** 计时器 ******************
/**
* 回调函数:异步计时器,一秒执行一次。请勿在此使用过多的阻塞方法
* @param $id
*/
public function processTick($id){
$this->tick_time = time();
new TickTask($this, $id);
public function processTick($id){ $this->scheduler->tick($id, ($this->tick_time = time())); }
/**
* 开启时候的自检模块
* 检测项目在下面列举
*/
public function selfCheck() {
if (!extension_loaded("swoole")) die("无法找到swoole扩展请先安装.\n");
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");
return true;
}
/**
* 此函数用于解析其他非消息类型事件显示在log里
* @param $req
* @return string
* 检查必需的文件是否存在
*/
public function executeType($req){
switch($req["post_type"]){
case "message":
return "消息";
case "event":
switch($req["event"]){
case "group_upload":
return "群[".$req["group_id"]."] 文件上传:".$req["file"]["name"]."".intval($req["file"]["size"] / 1024)."kb";
case "group_admin":
switch($req["sub_type"]){
case "set":
return "群[".$req["group_id"]."] 设置管理员:".$req["user_id"];
case "unset":
return "群[".$req["group_id"]."] 取消管理员:".$req["user_id"];
default:
return "unknown_group_admin_type";
}
case "group_decrease":
switch($req["sub_type"]){
case "leave":
return "群[".$req["group_id"]."] 成员主动退群:".$req["user_id"];
case "kick":
return "群[".$req["group_id"]."] 管理员[".$req["operator_id"]."]踢出了:".$req["user_id"];
case "kick_me":
return "群[".$req["group_id"]."] 本账号被踢出";
default:
return "unknown_group_decrease_type";
}
case "group_increase":
return "群[".$req["group_id"]."] ".$req["operator_id"]." 同意 ".$req["user_id"]." 加入了群";
default:
return "unknown_event";
}
case "request":
switch($req["request_type"]){
case "friend":
return "加好友请求:".$req["user_id"].",验证信息:".$req["message"];
case "group":
switch($req["sub_type"]){
case "add":
return "加群[".$req["group_id"]."] 请求:".$req["user_id"].",请求信息:".$req["message"];
case "invite":
return "用户".$req["user_id"]."邀请机器人进入群:".$req["group_id"];
default:
return "unknown_group_type";
}
default:
return "unknown_request_type";
}
default:
return "unknown_post_type";
}
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());
}
}

View File

@ -0,0 +1,15 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/5/26
* Time: 下午4:01
*/
class ApiMessageEvent extends Event
{
public function __construct(swoole_http_client $client, swoole_websocket_frame $frame) {
$res = json_decode($frame->data, true);
if (isset($res["echo"])) APIHandler::execute($res["echo"], $res);
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/5/26
* Time: 下午3:54
*/
class ApiUpgradeEvent extends Event
{
public function __construct(swoole_http_client $cli) {
Console::info("Upgraded API websocket");
if(!$this->getFramework()->api->isConnected()) {
echo "API connection lost.\nI will try next time after 30 second.\n";
//这里本来该用异步计时器的但是我太懒了直接睡30秒先。
//需要改用异步计时器的话告诉我我会改的233333。
sleep(30);
$this->getFramework()->api = new \swoole_http_client($this->getFramework()->host, $this->getFramework()->api_port);
$this->getFramework()->api->set(['websocket_mask' => true]);
$this->getFramework()->api->on('message', [$this->getFramework(), "onApiMessage"]);
$this->getFramework()->api->on("close", function ($cli){
Console::info(Console::setColor("API connection closed", "red"));
});
$this->getFramework()->api->upgrade('/api/', [$this->getFramework(), "onUpgrade"]);
return;
}
Buffer::$api = $this->getFramework()->api;
Buffer::$event = $this->getFramework()->event;
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("检测到重复引起异常,停止服务器", 0);
file_put_contents(CONFIG_DIR."log/last_error.log", "");
$this->getFramework()->event->shutdown();
return;
}
CQUtil::sendDebugMsg("检测到异常", 0);
$msg = "";
foreach ($data as $e) {
$msg = $msg . $e . "\n";
}
CQUtil::sendDebugMsg($msg, 0);
CQUtil::sendDebugMsg("[CQBot] 成功开启!", 0);
file_put_contents(CONFIG_DIR . "error_flag", time());
file_put_contents(CONFIG_DIR . "last_error.log", "");
}
else {
CQUtil::sendDebugMsg("[CQBot] 成功开启!", 0);
}
CQUtil::sendAPI("_get_friend_list", ["get_friend_list"]);
CQUtil::sendAPI("get_group_list", ["get_group_list"]);
CQUtil::sendAPI("get_version_info", ["get_version_info"]);
}
}

17
src/cqbot/event/Event.php Normal file
View File

@ -0,0 +1,17 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/5/26
* Time: 下午3:10
*/
abstract class Event
{
/**
* @return Framework
*/
public function getFramework(){
return Framework::getInstance();
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/5/16
* Time: 下午2:05
*/
class HTTPEvent extends Event
{
public $content;
public $isValid = false;
/**
* HTTPEvent constructor.
* @param swoole_http_request $request
* @param swoole_http_response $response
*/
public function __construct(swoole_http_request $request, swoole_http_response $response) {
$response->end("Hello world!");
//此为HTTP请求的回复更多设置回复头、传送文件、POST、GET请求解析等内容请查阅文档https://www.swoole.com
}
/**
* 此函数为炸毛机器人中的函数,为此预留
* 作用是判断传入的请求数据是合法的
* @param $param
* @return bool
*/
public function isValidParam($param) {
if ($param === null) return false;
if (!isset($param["event"])) return false;
if (!isset($param["timestamp"])) return false;
if (!isset($param[$param["event"]])) return false;
if(($param["timestamp"] > (time() + 10)) || ($param["timestamp"] < (time() - 10))) return false;
return true;
}
}

View File

@ -0,0 +1,14 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/5/26
* Time: 下午4:14
*/
class WSCloseEvent extends Event
{
public function __construct(swoole_server $server, int $fd) {
}
}

View File

@ -0,0 +1,38 @@
<?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) {
$in_count = Buffer::$in_count->get();
Buffer::$in_count->add(1);
$req = json_decode($frame->data, true);
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());
$c->execute($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);
} catch (Exception $e) {
CQUtil::errorlog("处理消息时异常,消息处理中断\n" . $e->getMessage() . "\n" . $e->getTraceAsString());
CQUtil::sendDebugMsg("引起异常的消息:\n" . var_export($req, true));
}
}
}

View File

@ -0,0 +1,12 @@
<?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) { }
}

View File

@ -0,0 +1,36 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/5/26
* Time: 下午3:15
*/
class WorkerStartEvent extends Event
{
public function __construct(swoole_server $server, $worker_id){
Console::info("Starting worker: " . $worker_id);
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"]);
//API连接部分
$this->getFramework()->api = new \swoole_http_client($this->getFramework()->host, $this->getFramework()->api_port);
$this->getFramework()->api->set(['websocket_mask' => true]);
$this->getFramework()->api->on('message', [$this->getFramework(), "onApiMessage"]);
$this->getFramework()->api->on("close", function ($cli){
Console::info(Console::setColor("API connection closed", "red"));
});
$this->getFramework()->api->upgrade('/api/', [$this->getFramework(), "onUpgrade"]);
Console::debug("master_pid = " . $server->master_pid);
Console::debug("worker_id = " . $worker_id);
Console::put("\n==========STARTUP DONE==========\n");
}
}

105
src/cqbot/item/Group.php Normal file
View File

@ -0,0 +1,105 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/5/2
* Time: 下午1:59
*/
class Group
{
private $group_id;
private $group_name;
private $prefix;
private $members = [];
public function __construct($group_id, $info) {
$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 mixed
*/
public function getPrefix() {
return $this->prefix;
}
/**
* @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 mixed $prefix
*/
public function setPrefix($prefix) {
$this->prefix = $prefix;
}
/**
* 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) {
CQUtil::sendAPI(["action" => "get_group_list"], ["update_group_info", $this->getGroupId()]);
if ($with_members) {
CQUtil::sendAPI(["action" => "get_group_member_list", "params" => ["group_id" => $this->getGroupId()]], ["update_group_member_list", strval($this->getGroupId())]);
}
}
}

View File

@ -0,0 +1,138 @@
<?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($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([
"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

@ -22,6 +22,8 @@ function loadAllClass($dir){
//加载需要优先加载的文件
require_once(WORKING_DIR."src/cqbot/mods/ModBase.php");
require_once(WORKING_DIR."src/cqbot/item/User.php");
require_once(WORKING_DIR."src/cqbot/event/Event.php");
loadAllClass(WORKING_DIR."src/cqbot/");

View File

@ -0,0 +1,25 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/6/3
* Time: 下午3:12
*/
class Example extends ModBase
{
protected $cmds;
public function __construct(CQBot $main, $data){
parent::__construct($main, $data);
}
public function execute($it){
switch ($it[0]) {
case "ping":
$this->reply("pong");
return true;
}
return false;
}
}

View File

@ -0,0 +1,33 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/6/3
* Time: 下午2:06
*/
class Scheduler
{
/** @var null|Scheduler */
public static $obj = null;
private $framework;
/**
* ScheduleTask constructor.
* @param Framework $framework
*/
public function __construct(Framework $framework) {
$this->framework = $framework;
self::$obj = $this;
}
public static function getInstance() {
return self::$obj;
}
public function tick($id, $tick_time) {
if($tick_time - $this->framework->run_time % 900 == 0) CQUtil::saveAllFiles();
//这里添加计时器上处理的内容
}
}

View File

@ -1,17 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: jerry
* Date: 2018/4/28
* Time: 下午4:00
*/
class TickTask
{
public function __construct(Framework $framework, $timer_id) {
$interval = ($framework->tick_time - $framework->run_time);
if ($interval % 900 == 0) CQUtil::saveAllFiles();//15分钟存一次数据
//这里可以放置你的定时器内执行的功能,自由扩展
}
}

View File

@ -8,5 +8,83 @@
class APIHandler
{
static function execute($cmd, $res = null) {
if (!isset($cmd[0])) return;
switch ($cmd[0]) {
case "set_friend_add_request":
$id = $cmd[1];
$msg = "Hi你好";
$msg .= "\n第一次见面请多关照!";
CQUtil::sendPrivateMsg($id, $msg);
break;
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"));
break;
case "update_group_member_list":
$group_id = $cmd[1];
$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();
}
break;
case "update_group_member_info":
$info_data = $res["data"];
$group = $cmd[1];
$user = $cmd[2];
$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);
break;
case "update_group_info":
$group = $res["data"];
$current = $cmd[1];
$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);
break;
}
$g = CQUtil::getGroup($current);
$g->setGroupName($list[$current]["group_name"]);
$g->setPrefix($list[$current]["prefix"]);
break;
case "get_group_member_list":
$group_data = $res["data"];
$ls = Buffer::get("group_list");
$group_id = $cmd[1];
$ls[$group_id]["member"] = $group_data;
$group = new Group($group_id, $ls[$group_id]);
Buffer::appendKey("groups", $group_id, $group);
break;
case "get_group_list":
$group = $res["data"];
$list = [];
foreach ($group as $k => $v) {
$list[$v["group_id"]] = $group[$k];
CQUtil::sendAPI(["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"));
break;
case "get_version_info":
Buffer::set("version_info", $res["data"]);
break;
}
}
}

View File

@ -49,4 +49,30 @@ class Buffer
if(!is_array((self::$data[$name] ?? 1))) return false;
return in_array($value, self::$data[$name]);
}
////////////预留部分为redis更新作准备/////////////
/** @var string[] 为未来支持redis数据库做准备 */
static $vars = [];
static $ls = [];
static function _get(string $name){
}
static function _setString(string $key, string $value){
}
static function _setList(string $key, array $value){
}
static function _appendList(string $key, string $value){
}
static function _ping(){
}
}

View File

@ -12,12 +12,9 @@ class CQUtil
{
public static function loadAllFiles() {
Console::debug("loading configs...");
Buffer::set("su", DP::getJsonData("su.json"));//超级管理员用户列表
if (count(Buffer::get("su")) < 1 && Framework::$super_user !== "") {
Console::info("Added super user");
Buffer::set("su", [Framework::$super_user]);
}
Buffer::set("mods", self::getMods());//加载模块列表
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"] ?? "");//设置指令的前缀符号
@ -26,11 +23,11 @@ class CQUtil
public static function saveAllFiles() {
Console::info("Saving files...");
DP::setJsonData("su.json", Buffer::get("su"));//保存超级管理员的QQ列表
//保存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);
//保存用户数据
@ -519,4 +516,73 @@ class CQUtil
Buffer::$api->close();
Buffer::$event->shutdown();
}
/**
* 此函数用于解析其他非消息类型事件显示在log里
* @param $req
* @return string
*/
public static function executeType($req){
switch($req["post_type"]){
case "message":
return "消息";
case "event":
switch($req["event"]){
case "group_upload":
return "群[".$req["group_id"]."] 文件上传:".$req["file"]["name"]."".intval($req["file"]["size"] / 1024)."kb";
case "group_admin":
switch($req["sub_type"]){
case "set":
return "群[".$req["group_id"]."] 设置管理员:".$req["user_id"];
case "unset":
return "群[".$req["group_id"]."] 取消管理员:".$req["user_id"];
default:
return "unknown_group_admin_type";
}
case "group_decrease":
switch($req["sub_type"]){
case "leave":
return "群[".$req["group_id"]."] 成员主动退群:".$req["user_id"];
case "kick":
return "群[".$req["group_id"]."] 管理员[".$req["operator_id"]."]踢出了:".$req["user_id"];
case "kick_me":
return "群[".$req["group_id"]."] 本账号被踢出";
default:
return "unknown_group_decrease_type";
}
case "group_increase":
return "群[".$req["group_id"]."] ".$req["operator_id"]." 同意 ".$req["user_id"]." 加入了群";
default:
return "unknown_event";
}
case "request":
switch($req["request_type"]){
case "friend":
return "加好友请求:".$req["user_id"].",验证信息:".$req["message"];
case "group":
switch($req["sub_type"]){
case "add":
return "加群[".$req["group_id"]."] 请求:".$req["user_id"].",请求信息:".$req["message"];
case "invite":
return "用户".$req["user_id"]."邀请机器人进入群:".$req["group_id"];
default:
return "unknown_group_type";
}
default:
return "unknown_request_type";
}
default:
return "unknown_post_type";
}
}
/**
* 返回群的类
* @param $group_id
* @return Group|null
*/
static function getGroup($group_id){
$d = Buffer::get("groups");
return $d[$group_id] ?? null;
}
}

154
start.php
View File

@ -7,9 +7,14 @@
*/
date_default_timezone_set("Asia/Shanghai");
//工作目录设置
define("WORKING_DIR", __DIR__ . "/");
echo "工作目录:".WORKING_DIR."\n";
define("CONFIG_DIR", WORKING_DIR . "config/");
define("USER_DIR", WORKING_DIR . "users");
//启动时间
define("START_TIME", time());
@mkdir(CONFIG_DIR, 0777, true);
@mkdir(USER_DIR, 0777, true);
@ -74,47 +79,126 @@ function CQMsg($msg, $type, $id) {
}
return $reply;
}
$host = "0.0.0.0";
$api_host = "127.0.0.1";
$api_port = 10000;
$event_port = 20000;
$admin_group = "";
$info_level = 1;
$super_user = "";
//check argv option.
if(count($argv) >= 3){
echo "detected options.\n";
//var_dump($argv);
array_shift($argv);
for($i = 0; $i < count($argv); $i++){
if(substr($argv[$i],0,2) == '--'){
$option = substr($argv[$i],2);
if(isset($argv[$i+1])){
switch($option){
case "host":
$host = $argv[$i+1];
break;
case "api-port":
$api_port = $argv[$i+1];
break;
case "event-port":
$event_port = $argv[$i+1];
break;
case "admin-group":
$admin_group = $argv[$i+1];
break;
case "info-level":
$info_level = $argv[$i+1];
break;
case "super-user":
$super_user = $argv[$i+1];
break;
default:
break;
}
}
}
}
$super_user = [];
if (!file_exists(CONFIG_DIR . "config.json")) {
file_put_contents(CONFIG_DIR . "config.json", json_encode([]));
}
$json = json_decode(file_get_contents(CONFIG_DIR . "config.json"), true);
if (!isset($json["host"])) {
echo "请输入你要监听的Event IP(默认0.0.0.0) ";
$r = strtolower(trim(fgets(STDIN)));
if ($r == "") {
echo "监听地址0.0.0.0(默认)\n";
$json["host"] = $host;
} else {
$host = $r;
echo "监听地址:" . $r . "\n";
$json["host"] = $host;
}
} else {
$host = $json["host"];
}
if (!isset($json["event_port"])) {
a3:
echo "请输入你要监听的Event端口(默认20000) ";
$r = strtolower(trim(fgets(STDIN)));
if ($r == "") {
echo "监听地址20000(默认)\n";
$json["event_port"] = $event_port;
} else {
if (!is_numeric($r)) {
echo "输入错误请输入数字1-65535\n";
goto a3;
}
$event_port = $r;
echo "监听地址:" . $r . "\n";
$json["event_port"] = $event_port;
}
} else {
$event_port = $json["event_port"];
}
if (!isset($json["api_host"])) {
echo "请输入你要连接的api server IP(默认127.0.0.1) ";
$r = strtolower(trim(fgets(STDIN)));
if ($r == "") {
echo "API地址127.0.0.1(默认)\n";
$json["api_host"] = $api_host;
} else {
$api_host = $r;
echo "监听地址:" . $r . "\n";
$json["api_host"] = $api_host;
}
} else {
$api_host = $json["api_host"];
}
if (!isset($json["api_port"])) {
a2:
echo "请输入你要监听的API端口(默认10000) ";
$r = strtolower(trim(fgets(STDIN)));
if ($r == "") {
echo "监听地址10000(默认)\n";
$json["api_port"] = $api_port;
} else {
if (!is_numeric($r)) {
echo "输入错误请输入数字1-65535\n";
goto a2;
}
$api_port = $r;
echo "监听地址:" . $r . "\n";
$json["api_port"] = $api_port;
}
} else {
$api_port = $json["api_port"];
}
if (!isset($json["admin_group"])) {
a4:
echo "请输入你要设置的管理员群:";
$r = strtolower(trim(fgets(STDIN)));
if ($r == "") {
echo "检测到你没有设置管理员群,本次跳过\n";
} else {
if (!is_numeric($r)) {
echo "输入错误!请输入数字群号!\n";
goto a4;
}
$admin_group = $r;
echo "管理群:" . $r . "\n";
$json["admin_group"] = $admin_group;
}
} else {
$admin_group = $json["admin_group"];
}
if (!isset($json["super_user"])) {
a5:
echo "请输入你要设置的高级管理员:";
$r = strtolower(trim(fgets(STDIN)));
if ($r == "") {
echo "检测到你没有设置高级管理员,本次跳过\n";
} else {
if (!is_numeric($r)) {
echo "输入错误请输入数字QQ号\n";
goto a5;
}
$super_user[] = $r;
echo "管理员:" . $r . "\n";
$json["super_user"][] = $r;
}
} else {
$super_user = $json["super_user"];
}
file_put_contents(CONFIG_DIR."config.json", json_encode($json, 128 | 256));
//loading projects
require(WORKING_DIR . "src/cqbot/Framework.php");