diff --git a/.gitignore b/.gitignore new file mode 100755 index 00000000..fe7871cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +out +gen diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/src/cqbot/CQBot.php b/src/cqbot/CQBot.php new file mode 100755 index 00000000..850cf2f2 --- /dev/null +++ b/src/cqbot/CQBot.php @@ -0,0 +1,161 @@ +starttime = microtime(true); + $this->framework = $framework; + } + + public function execute($it){ + $this->data = $it; + if ($it["post_type"] == "message") { + try { + $this->callTask($it); + } catch (\Exception $e) { + CQUtil::errorLog("请求执行任务时异常\n" . $e->getMessage()); + CQUtil::sendDebugMsg("引起异常的消息:\n" . $it["message"]); + } + $msg_arr = explode("&&", $this->replace($it["message"], $it)); + foreach ($msg_arr as $item) { + $msg = trim($item); + $msg = explode(" ", $msg); + $this->checkFunction($msg, $it); + } + } + } + + public function checkFunction($msgCut, $it){ + $cmdList = Buffer::get("commands"); + if (isset($cmdList[$msgCut[0]])) { + Console::debug("Call CQFunction:" . $msgCut[0]); + $temp = $cmdList[$msgCut[0]]; + /** @var ModBase $class */ + $class = new $temp($this, $it); + $class->execute($msgCut); + return true; + } + Console::debug("未找到指令:[" . $msgCut[0] . "]"); + return false; + } + + public function callTask($it){ + if ($this->data["post_type"] == "message") { + foreach(Buffer::get("mod_task") as $v){ + new $v($this, $this->data); + } + } + } + + public function reply($msg){ + $this->function_called = true; + switch ($this->data["message_type"]) { + case "group": + $this->sendGroupMsg($this->data["group_id"], $msg); + break; + case "private": + $this->sendPrivateMsg($this->data["user_id"], $msg); + break; + case "discuss": + $reply = json_encode(["action" => "send_discuss_msg", "params" => ["discuss_id" => $this->data["discuss_id"], "message" => $msg]]); + if (CQUtil::APIPush($reply)) { + $out_count = Buffer::$out_count->get(); + if (Buffer::$data["info_level"] == 2) { + Console::put("************API PUSHED***********"); + } + if (Buffer::$data["info_level"] >= 1) { + Console::put(Console::setColor(date("H:i:s "), "lightpurple") . Console::setColor("[$out_count]REPLY", "blue") . Console::setColor(" > ", "gray") . json_decode($reply, true)['params']["message"]); + } + Buffer::$out_count->add(1); + } + break; + case "wechat": + //TODO: add wechat account support in the future + break; + } + } + + public function sendGroupMsg($groupId, $msg){ + $this->function_called = true; + CQUtil::sendGroupMsg($groupId, $msg); + } + + public function sendPrivateMsg($userId, $msg){ + $this->function_called = true; + CQUtil::sendPrivateMsg($userId, $msg); + } + + public function isAdmin($user){ + if (in_array($user, Buffer::get("su"))) return true; + else return false; + } + + public function replace($msg, $dat){ + $msg = str_replace("{at}", '[CQ:at,qq=' . $dat["user_id"] . ']', $msg); + $msg = str_replace("{and}", '&', $msg); + while (strpos($msg, '{') !== false && strpos($msg, '}') !== false) { + if (strpos($msg, '{') > strpos($msg, '}')) return $msg; + $start = strpos($msg, '{'); + $end = strpos($msg, '}'); + $sub = explode("=", substr($msg, $start + 1, $end - $start - 1)); + switch ($sub[0]) { + case "at": + $qq = $sub[1]; + $msg = str_replace(substr($msg, $start, $end - $start + 1), '[CQ:at,qq=' . $qq . ']', $msg); + break; + case "image": + case "record": + $pictFile = $sub[1]; + $msg = str_replace(substr($msg, $start, $end - $start + 1), '[CQ:' . $sub[0] . ',file=' . $pictFile . ']', $msg); + break; + case "dice": + $file = $sub[1]; + $msg = str_replace(substr($msg, $start, $end - $start + 1), '[CQ:dice,type=' . $file . ']', $msg); + break; + case "shake": + $msg = str_replace(substr($msg, $start, $end - $start + 1), '[CQ:shake]', $msg); + break; + case "music": + $id = $sub[1]; + $msg = str_replace(substr($msg, $start, $end - $start + 1), '[CQ:music,type=163,id=' . $id . ']', $msg); + break; + case "internet": + array_shift($sub); + $id = implode("=", $sub); + if (substr($id, 0, 7) != "http://") $id = "http://" . $id; + $is = file_get_contents($id, false, NULL, 0, 1024); + if ($is == false) $is = "[请求时发生了错误] 如有疑问,请联系管理员"; + $msg = str_replace(substr($msg, $start, $end - $start + 1), $is, $msg); + break 2; + default: + break 2; + } + } + return $msg; + } +} \ No newline at end of file diff --git a/src/cqbot/Framework.php b/src/cqbot/Framework.php new file mode 100755 index 00000000..218a91f0 --- /dev/null +++ b/src/cqbot/Framework.php @@ -0,0 +1,169 @@ +host = $host; + return $this; + } + + public function setApiPort($port = 10000){ + $this->api_port = $port; + return $this; + } + + public function setEventPort($port = 20000){ + $this->event_port = $port; + return $this; + } + + public function setAdminGroup($group){ + self::$admin_group = $group; + return $this; + } + + public function setInfoLevel($level){ + $this->info_level = $level; + return $this; + } + + public function eventServerStart(){ + $this->event->start(); + } + + public static function getInstance(){ + return self::$obj; + } + + public function init(){ + self::$obj = $this; + Console::put("CQBot Framework starting..."); + $this->event = new \swoole_websocket_server($this->host, $this->event_port); + Buffer::$log_file = CONFIG_DIR . "log/swoole.log"; + Console::put("Current log file: " . Buffer::$log_file); + $worker_num = 1; + Console::put("Current worker count: " . $worker_num); + $dispatch_mode = 2; + Console::put("Current dispatch mode: " . $dispatch_mode); + $this->checkFiles(); + $this->event->set([ + "log_file" => Buffer::$log_file, + "worker_num" => 1, + "dispatch_mode" => 2 + ]); + $this->event->on('WorkerStart', [$this, 'onWorkerStart']); + $this->event->on('message', [$this, 'onEventMessage']); + $this->event->on('open', [$this, 'onConnect']); + $this->event->on('close', function ($serv, $fd){ + //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(WORKING_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 */ + + /** + * This is async function in EventLoop + * When it reload, it will run this function again. + * @param \swoole_server $server + * @param $worker_id + */ + public function onWorkerStart(\swoole_server $server, $worker_id){ + $this->run_time = time(); + Console::info("Starting worker " . $worker_id); + Console::info("Loading source code..."); + require_once(WORKING_DIR . "src/cqbot/loader.php"); + CQUtil::loadAllFiles(); + Buffer::set("info_level", $this->info_level);//设置info等级 + foreach (get_included_files() as $file) + Console::debug("Loaded " . $file); + echo("\n"); + + //计时器(ms) + $server->tick(1000, [$this, "processTick"]); + + $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====================\n"); + } + + public function onUpgrade($cli){ + Console::info("Upgraded API websocket"); + Buffer::$api = $this->api; + Buffer::$event = $this->event; + if ($data = file(CONFIG_DIR . "last_error.log")) { + $last_time = file_get_contents(CONFIG_DIR . "error_flag"); + if (time() - $last_time < 2) { + CQUtil::sendDebugMsg("检测到重复引起异常,停止服务器", 0); + file_put_contents(CONFIG_DIR."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); + } + } +} \ No newline at end of file diff --git a/src/cqbot/User.php b/src/cqbot/User.php new file mode 100755 index 00000000..3e8d0d31 --- /dev/null +++ b/src/cqbot/User.php @@ -0,0 +1,81 @@ +id = $qid; + $this->permission = DP::getJsonData("permissions.json")[$qid] ?? 0; + $this->is_friend = isset(Buffer::get("friend_list")[$qid]) ? true : false; + } + + /** + * 获取用户QQ号 + * @return mixed + */ + public function getId(){ return $this->id; } + + /** + * 获取用户添加词库的状态 + * @return array + */ + public function getWordStatus() : array{ return $this->word_status; } + + /** + * 获取用户权限值 + * @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; + } + + /** + * @param int $permission + * @return User + */ + public function setPermission(int $permission): User{ + $this->permission = $permission; + return $this; + } + + /** + * 和用户是否是好友//TODO功能 + * @return bool + */ + public function isFriend(): bool{ + return $this->is_friend; + } + + public function getBuffer(){ + return $this->buffer; + } + + public function setBuffer($buffer){ + $this->buffer = $buffer; + return $this; + } +} \ No newline at end of file diff --git a/src/cqbot/loader.php b/src/cqbot/loader.php new file mode 100755 index 00000000..1fae19a3 --- /dev/null +++ b/src/cqbot/loader.php @@ -0,0 +1,37 @@ +main->isAdmin($this->getUserId())) return false; + switch ($it[0]) { + case "add-cmd": + if (count($it) < 3) { + $this->reply("用法:add-cmd 指令 模块名"); + return true; + } + if(!CQUtil::isModExists($it[2])){ + $this->reply("对不起,模块 ".$it[2]." 不存在!"); + return true; + } + } + } +} \ No newline at end of file diff --git a/src/cqbot/mods/ModBase.php b/src/cqbot/mods/ModBase.php new file mode 100755 index 00000000..8acd1d49 --- /dev/null +++ b/src/cqbot/mods/ModBase.php @@ -0,0 +1,44 @@ +main = $main; + $this->data = $data; + $this->cmds = $mod_cmd; + } + + 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 abstract function execute($it); + + public function reply($msg){ $this->main->reply($msg); } + + public function sendPrivateMsg($user, $msg){ $this->main->sendPrivateMsg($user, $msg); } + + public function sendGroupMsg($user, $msg){ $this->main->sendGroupMsg($user, $msg); } + + public function getMessageType(){ return $this->data["message_type"]; } + + public function getCommands(){ return $this->cmds; } +} \ No newline at end of file diff --git a/src/cqbot/utils/Buffer.php b/src/cqbot/utils/Buffer.php new file mode 100755 index 00000000..20a2e4f0 --- /dev/null +++ b/src/cqbot/utils/Buffer.php @@ -0,0 +1,49 @@ +isConnected() === false) { + //链接被断开 + Buffer::$api->upgrade('/api/', function ($cli){ + self::sendDebugMsg("API重新链接成功"); + self::APIPushDelayMsg(); + }); + return 0; + } + return 1; + } + + /** + * 推送API,给API端口 + * @param $data + * @return bool + */ + static function APIPush($data){ + if ($data == null || $data == "") { + Console::error("EMPTY DATA PUSH"); + return false; + } + if (self::checkAPIConnection() === -1) { + //忽略掉framework链接API之前的消息 + self::errorlog("API推送失败,未发送的消息: \n" . $data, "API ERROR", 0); + return false; + } + if (self::checkAPIConnection() === 0) { + self::APIPushAfterConnected($data); + return true; + } + if (Buffer::$api->push($data) === false) { + $data = self::unicodeDecode($data); + self::errorlog("API推送失败,未发送的消息: \n" . $data, "API ERROR", 0); + self::sendErrorEmail("API推送失败", "未成功推送的消息:
$data
请检查酷q是否开启及网络链接情况
在此期间,机器人会中断所有消息处理
请及时处理"); + return false; + } + return true; + } + + static function APIPushDelayMsg(){ + $delay_push_list = Buffer::get("delay_push"); + $cur_time = time(); + foreach ($delay_push_list as $item) { + $data = $item["data"]; + $time = $item["time"]; + if ($cur_time - $time <= 10) { + self::APIPush($data); + } + } + Buffer::set("delay_push", []); + } + + /** + * 推迟推送API,用于酷Q重启后的重新连接API + * @param $data + */ + static function APIPushAfterConnected($data){ + $delay_push_list = Buffer::get("delay_push"); + $delay_push_list[] = ["data" => $data, "time" => time()]; + Buffer::set("delay_push", $delay_push_list); + } + + /** + * 解码unicode中文编码 + * @param $str + * @return null|string|string[] + */ + static function unicodeDecode($str){ + return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function ($matches){ + return mb_convert_encoding(pack("H*", $matches[1]), "UTF-8", "UCS-2BE"); + }, + $str); + } + + /** + * 模拟发送一个HTML-get请求 + * @param $url + * @return mixed + */ + static function getHTML($url){ + $ch = curl_init(); + $timeout = 5; + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); + $r = curl_exec($ch); + curl_close($ch); + return $r; + } + + /** + * 获取字符串的反转结果 + * @param $str + * @param string $encoding + * @return string + */ + static public function getRev($str, $encoding = 'utf-8'){ + $result = ''; + $len = mb_strlen($str); + for ($i = $len - 1; $i >= 0; $i--) { + $result .= mb_substr($str, $i, 1, $encoding); + } + return $result; + } + + /** + * 发送邮件功能,基于PHPMailer模块,需先安装phpmailer。默认此工程demo里已包含有phpmailer了。 + * 请根据实际自己的邮箱更新下面的用户名、密码、smtp服务器地址、端口等。 + * 此功能非基于本作者编写的代码,如有问题请在github上找PHPMailer项目进行反馈 + * @param $address + * @param $title + * @param $content + * @param string $name + * @param int $send_debug_message + * @return bool|string + */ + static function sendEmail($address, $title, $content, $name = "CQ开发团队", $send_debug_message = 1){ + $mail = new \PHPMailer(true); + try { + $mail->isSMTP(); + $mail->Host = 'here your smtp host'; + $mail->SMTPAuth = true; + $mail->Username = 'here your mailbox address'; + $mail->Password = 'here your password'; + $mail->SMTPSecure = 'ssl'; + $mail->Port = 465; + $mail->setFrom('here your mailbox address', $name); + if (is_array($address)) { + foreach ($address as $item) + $mail->addAddress($item); + } + else { + $mail->addAddress($address); + } + //Content + $mail->isHTML(true); + $mail->Subject = $title; + $mail->CharSet = "UTF-8"; + $mail->Body = $content; + $mail->send(); + if (is_array($address)) + $address = implode(",", $address); + Console::info("向 $address 发送的邮件完成"); + unset($mail); + return true; + } catch (\Exception $e) { + self::errorLog("发送邮件错误!错误信息:" . $info = $mail->ErrorInfo, "ERROR", $send_debug_message); + unset($mail); + return $info; + } + } + + /** + * 获取运行时间 + * @param $time + * @return array + */ + static function getRunTime($time){ + $time_len = time() - $time; + $run_time = []; + if (intval($time_len / 86400) > 0) { + $run_time[0] = intval($time_len / 86400); + $time_len = $time_len % 86400; + } + else { + $run_time[0] = 0; + } + if (intval($time_len / 3600) > 0) { + $run_time[1] = intval($time_len / 3600); + $time_len = $time_len % 3600; + } + else { + $run_time[1] = 0; + } + if (intval($time_len / 60) > 0) { + $run_time[2] = intval($time_len / 60); + $time_len = $time_len % 60; + } + else { + $run_time[2] = 0; + } + $run_time[3] = $time_len; + return $run_time; + } + + /** + * 获取格式化的运行时间 + * @param $time + * @return string + */ + static function getRunTimeFormat($time){ + $time_len = time() - $time; + $msg = ""; + if (intval($time_len / 86400) > 0) { + $msg .= intval($time_len / 86400) . "天"; + $time_len = $time_len % 86400; + } + if (intval($time_len / 3600) > 0) { + $msg .= intval($time_len / 3600) . "小时"; + $time_len = $time_len % 3600; + } + if (intval($time_len / 60) > 0) { + $msg .= intval($time_len / 60) . "分"; + $time_len = $time_len % 60; + } + $msg .= $time_len . "秒"; + return $msg; + } + + /** + * 检查是否为群组管理员或群主功能,此功能需要先获取群组列表,否则会产生一个warning + * @param $group + * @param $user_id + * @return bool + */ + static function isGroupAdmin($group, $user_id){ + $ls = Buffer::get("group_list")[$group]["member"]; + $is_admin = false; + foreach ($ls as $k => $v) { + if ($v["user_id"] == $user_id) { + if ($v["role"] == "admin" || $v["role"] == "owner") { + $is_admin = true; + break; + } + } + } + return $is_admin; + } + + /** + * 用于发送错误日志邮件的功能,请根据实际情况填写邮箱。 + * 此功能基于sendMail,请看上方sendMail函数的介绍 + * @param $title + * @param $content + * @param string $name + */ + static function sendErrorEmail($title, $content, $name = "机器人错误提示"){ + self::sendEmail(["here your receive email address"], $title, $content, $name, 0); + } + + /** + * 获取所有已经加载到内存的用户。 + * read_all为true时,会加载所有User.dat到内存中,false时仅会读取已经加载到内存的用户 + * @param bool $real_all + * @return array[User] + */ + static function getAllUsers($real_all = false): array{ + if ($real_all === true) { + $dir = scandir(DP::getUserFolder()); + unset($dir[0], $dir[1]); + foreach ($dir as $d => $v) { + $vs = explode(".", $v); + if (array_pop($vs) == "dat") { + $class = unserialize(file_get_contents(DP::getUserFolder() . $v)); + if (!Buffer::array_key_exists("user", $vs[0])) { + Buffer::appendKey("user", $vs[0], $class); + } + } + } + } + return Buffer::get("user"); + } + + /** + * 获取用户实例 + * @param $id + * @return User + */ + static function getUser($id){ + $d = Buffer::get("user"); + if (!isset($d[$id])) { + self::initUser($id); + $d = Buffer::get("user"); + } + /** @var User $class */ + $class = $d[$id]; + return $class; + } + + /** + * 初始化用户实例。如果没有此用户的实例数据,会创建 + * @param $id + */ + static function initUser($id){ + if (file_exists(DP::getUserFolder() . $id . ".dat")) $class = unserialize(file_get_contents(DP::getUserFolder() . $id . ".dat")); + else { + Console::info("无法找到用户 " . $id . " 的数据,正在创建..."); + $class = new User($id); + } + Buffer::appendKey("user", $id, $class); + } + + /** + * 发送群组消息,含控制台推出 + * @param $groupId + * @param $msg + * @return bool + */ + static function sendGroupMsg($groupId, $msg){ + $reply = ["action" => "send_group_msg", "params" => ["group_id" => $groupId, "message" => $msg]]; + $reply["echo"] = $reply; + $reply["echo"]["time"] = time(); + $reply = json_encode($reply); + if (self::APIPush($reply)) { + if (Buffer::$data["info_level"] == 1) { + $out_count = Buffer::$out_count->get(); + Console::put(Console::setColor(date("H:i:s "), "lightpurple") . Console::setColor("[{$out_count}]GROUP", "blue") . Console::setColor(" " . $groupId, "yellow") . Console::setColor(" > ", "gray") . $msg); + Buffer::$out_count->add(1); + } + return true; + } + return false; + } + + /** + * 发送私聊消息 + * @param $userId + * @param $msg + * @return bool + */ + static function sendPrivateMsg($userId, $msg){ + $reply = ["action" => "send_private_msg", "params" => ["user_id" => $userId, "message" => $msg]]; + $reply["echo"] = $reply; + $reply["echo"]["time"] = time(); + $reply = json_encode($reply); + if (self::APIPush($reply)) { + if (Buffer::$data["info_level"] == 1) { + $out_count = Buffer::$out_count->get(); + Console::put(Console::setColor(date("H:i:s "), "lightpurple") . Console::setColor("[{$out_count}]PRIVATE", "blue") . Console::setColor(" " . $userId, "yellow") . Console::setColor(" > ", "gray") . $msg); + Buffer::$out_count->add(1); + } + return true; + } + return false; + } + + + static function getFriendName($qq){ return Buffer::get("friend_list")[$qq]["nickname"] ?? "unknown"; } + + static function getGroupName($group){ return Buffer::get("group_list")[$group]["group_name"] ?? "unknown"; } + + /** + * 发送其他API,HTTP插件支持的其他API都可以发送。 + * echo是返回内容,可以在APIHandler.php里面解析 + * @param $data + * @param $echo + */ + static function sendAPI($data, $echo){ + if (!is_array($data)) { + $api = []; + $api["action"] = $data; + } + else { + $api = $data; + } + $api["echo"] = $echo; + self::APIPush(json_encode($api)); + } + + /** + * 删除一个和模块相关联的指令 + * @param $name + * @return bool + */ + static function removeCommand($name){ + $list = Buffer::get("commands"); + if (!isset($list[$name])) return false; + unset($list[$name]); + Buffer::set("commands", $list); + DP::setJsonData("commands.json", $list); + return true; + } + + /** + * 添加一个指令给非callTask方式激活的模块。 + * 注意:如果给callTask方式激活的模块添加指令,则在使用对应功能时会回复多次同样的内容 + * @param $name + * @param $class + * @return bool + */ + static function addCommand($name, $class){ + if (!is_file(WORKING_DIR.'src/cqbot/mods/' . $class . '.php')) { + return false; + } + $list = Buffer::get("commands"); + $list[$name] = $class; + DP::setJsonData("commands.json", $list); + Buffer::set("commands", $list); + return true; + } + + /** + * 获取模块列表的通用方法 + * @return array + */ + static function getMods(){ + $dir = WORKING_DIR."src/cqbot/mods/"; + $dirs = scandir($dir); + $ls = []; + unset($dirs[0], $dirs[1]); + foreach($dirs as $v){ + if($v != "ModBase.php" && (strstr($v,".php") !== false)){ + $name = substr($v, 0, -4); + $ls[]=$name; + } + } + return $ls; + } + + /** + * 判断模块是否存在 + * @param $mod_name + * @return bool + */ + static function isModExists($mod_name){ + $ls = self::getMods(); + return in_array($mod_name, $ls); + } +} \ No newline at end of file diff --git a/src/cqbot/utils/Console.php b/src/cqbot/utils/Console.php new file mode 100755 index 00000000..552f720c --- /dev/null +++ b/src/cqbot/utils/Console.php @@ -0,0 +1,67 @@ + "POST 请求的正文格式不正确", + 1404 => "API 不存在", + 100 => "参数缺失或参数无效", + 102 => "酷q操作权限不足", + 103 => "用户权限不足或文件系统异常", + 201 => "工作线程池未正确初始化", + -1 => "请求发送失败", + -2 => "未收到服务器回复,可能未发送成功", + -3 => "消息过长或为空", + -4 => "消息解析过程异常", + -5 => "日志功能未启用", + -6 => "日志优先级错误", + -7 => "数据入库失败", + -8 => "不支持对系统帐号操作", + -9 => "帐号不在该群内,消息无法发送", + -10 => "该用户不存在/不在群内", + -11 => "数据错误,无法请求发送", + -12 => "不支持对匿名成员解除禁言", + -13 => "无法解析要禁言的匿名成员数据", + -14 => "由于未知原因,操作失败", + -15 => "群未开启匿名发言功能,或匿名帐号被禁言", + -16 => "帐号不在群内或网络错误,无法退出/解散该群", + -17 => "帐号为群主,无法退出该群", + -18 => "帐号非群主,无法解散该群", + -19 => "临时消息已失效或未建立", + -20 => "参数错误", + -21 => "临时消息已失效或未建立", + -22 => "获取QQ信息失败", + -23 => "找不到与目标QQ的关系,消息无法发送", + -26 => "消息过长" + ]; + + static function getMessage($retcode){ + return self::$error[$retcode] ?? "未知错误"; + } +} \ No newline at end of file diff --git a/src/extension/PHPMailer.phar b/src/extension/PHPMailer.phar new file mode 100755 index 00000000..3367ed46 Binary files /dev/null and b/src/extension/PHPMailer.phar differ diff --git a/start.php b/start.php new file mode 100755 index 00000000..aac8efdc --- /dev/null +++ b/start.php @@ -0,0 +1,100 @@ + $t) { + if (!isset($t['file'])) { + $t['file'] = 'unknown'; + } + if (!isset($t['line'])) { + $t['line'] = 0; + } + if (!isset($t['function'])) { + $t['function'] = 'unknown'; + } + $log .= "#$i {$t['file']}({$t['line']}): "; + if (isset($t['object']) and is_object($t['object'])) { + $log .= get_class($t['object']) . '->'; + } + $log .= "{$t['function']}()\n"; + } + + file_put_contents(CONFIG_DIR . "last_error.log", $log); + break; + default: + break; + } + } + } + + function CQMsg($msg, $type, $id){ + if ($type === "group") { + $reply = ["action" => "send_group_msg", "params" => ["group_id" => $id, "message" => $msg]]; + $reply["echo"] = $reply; + $reply["echo"]["time"] = time(); + $reply = json_encode($reply); + } + else if ($type === "private") { + $reply = ["action" => "send_private_msg", "params" => ["user_id" => $id, "message" => $msg]]; + $reply["echo"] = $reply; + $reply["echo"]["time"] = time(); + $reply = json_encode($reply); + } + else if ($type === "discuss") { + $reply = ["action" => "send_discuss_msg", "params" => ["discuss_id" => $id, "message" => $msg]]; + $reply["echo"] = $reply; + $reply["echo"]["time"] = time(); + $reply = json_encode($reply); + } + else { + $reply = false; + } + return $reply; + } + + //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"); + $cqbot = new Framework(); + $cqbot->setHost("127.0.0.1"); + $cqbot->setApiPort("10000"); + $cqbot->setEventPort("20000"); + $cqbot->setAdminGroup(""); + $cqbot->setInfoLevel(1); + $cqbot->init(); + $cqbot->eventServerStart(); +} \ No newline at end of file