From 9fb01d13a7f7d5a55219629cd6963b8514d9a4ab Mon Sep 17 00:00:00 2001 From: Eritque arcus <1930893235@qq.com> Date: Thu, 21 Oct 2021 17:27:54 +0800 Subject: [PATCH] perf(cpp): separater implementation into `miraiCP.cpp` to try to fix #96 Former-commit-id: e2ea7bdfd3707666e3d02fd162f212d7c210bfde --- cpp/CMakeLists.txt | 2 + cpp/include/miraiCP.cpp | 1008 ++++++++++++++++++++++++++++++++ cpp/include/miraiCP.hpp | 1116 +++--------------------------------- cpp/include/test/test2.cpp | 21 + 4 files changed, 1109 insertions(+), 1038 deletions(-) create mode 100644 cpp/include/miraiCP.cpp create mode 100644 cpp/include/test/test2.cpp diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index cd8028b0a..619b3f267 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -15,6 +15,7 @@ set(BUILD_USE_64BITS on) add_library( MiraiCP SHARED + include/miraiCP.cpp demo.cpp) # 设置输出的dll文件的名字(最后一个参数),目前是MiraiCP.dll set_target_properties(MiraiCP PROPERTIES OUTPUT_NAME MiraiCP) @@ -23,6 +24,7 @@ set_target_properties(MiraiCP PROPERTIES OUTPUT_NAME MiraiCP) add_library( MiraiCP_Test SHARED + include/miraiCP.cpp include/test/test.cpp include/test/test2.cpp) set_target_properties(MiraiCP_Test PROPERTIES OUTPUT_NAME MiraiCP) diff --git a/cpp/include/miraiCP.cpp b/cpp/include/miraiCP.cpp new file mode 100644 index 000000000..cbe3cfc60 --- /dev/null +++ b/cpp/include/miraiCP.cpp @@ -0,0 +1,1008 @@ +// Copyright (C) 2020-2021 Eritque arcus and contributors. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or any later version(in your opinion). +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// + +#include + +namespace MiraiCP { + +// 开始MiraiCP实现代码 + +// 静态成员 + + std::map ThreadManager::threads = std::map(); + std::recursive_mutex ThreadManager::mtx = std::recursive_mutex(); + JavaVM *ThreadManager::gvm = nullptr; + long ThreadManager::JNIVersion = 0; + + jclass Config::CPP_lib = nullptr; + jmethodID Config::KOperation = nullptr; + + Logger Logger::logger = Logger(); + [[deprecated("Use Logger::logger instead")]] + Logger *const logger = &Logger::logger; + + PluginLogger *CPPPlugin::pluginLogger = nullptr; + CPPPlugin *CPPPlugin::plugin = nullptr; + + std::map SingleMessage::messageType = { + {-2, "QuoteReply"}, + {-1, "unSupportMessage"}, + {0, "plainText"}, + {1, "at"}, + {2, "atAll"}, + {3, "image"}, + {4, "app"}, + {5, "service"} + }; + + Event Event::processor = Event(); + [[deprecated("Use Event::processor instead")]] + Event *const procession = &Event::processor; + +// 结束静态成员 + + void ThreadManager::setEnv(JNIEnv *e) { + mtx.lock(); + if (!ThreadManager::included(ThreadManager::getThreadId())) { + ThreadInfo tmp{ + e, + false + }; + ThreadManager::threads.insert(std::pair(ThreadManager::getThreadId(), tmp)); + } else { + ThreadManager::threads[ThreadManager::getThreadId()].e = e; + } + mtx.unlock(); + } + + void ThreadManager::newEnv(const char *threadName) { + JNIEnv *env = nullptr; + JavaVMAttachArgs args{ + JNIVersion, + const_cast(threadName), + nullptr + }; + gvm->AttachCurrentThread((void **) &env, &args); + ThreadInfo tmp{env, true}; + ThreadManager::threads.insert(std::pair(ThreadManager::getThreadId(), tmp)); + Logger::logger.info("refresh env"); + }; + + void ThreadManager::detach() { + mtx.lock(); + if (ThreadManager::included(ThreadManager::getThreadId())) { + bool att = ThreadManager::threads[ThreadManager::getThreadId()].attach; + ThreadManager::threads.erase(ThreadManager::getThreadId()); + if (att) + gvm->DetachCurrentThread(); + } + mtx.unlock(); + } + + bool ThreadManager::included(const std::string &id) { + if (ThreadManager::threads.empty() || ThreadManager::threads.count(id) == 0) + return false; + return true; + } + + JNIEnv *ThreadManager::getEnv(const std::string &file, int loc, const std::string &func) { + mtx.lock(); + if (!ThreadManager::included(getThreadId())) { + ThreadManager::newEnv(); + } + JNIEnv *tmp = ThreadManager::threads[ThreadManager::getThreadId()].e; + ThreadManager::threads[ThreadManager::getThreadId()].stack.push(file, loc, func); + mtx.unlock(); + return tmp; + } + +/* +日志类实现 +throw: InitException 即找不到签名 +*/ + + void Logger_interface::init(JNIEnv *env) { + this->log = env->GetStaticMethodID(Config::CPP_lib, "KSendLog", "(Ljava/lang/String;I)V"); + } + + void Logger_interface::registerHandle(Logger_interface::Action action) { + this->loggerhandler.action = std::move(action); + } + + void Logger_interface::setHandleState(bool state) { + this->loggerhandler.enable = state; + } + + void Logger_interface::warning(const std::string &content, JNIEnv *env) { + this->log0(content, 1, env); + } + + void Logger_interface::error(const std::string &content, bool printStack, JNIEnv *env) { + ThreadManager::StackTracer a = ThreadManager::getThread()->stack; + if (printStack) + this->log0(content + "\n" + a.print(), 2, env); + else + this->log0(content, 2, env); + } + + void Logger_interface::info(const std::string &content, JNIEnv *env) { + this->log0(content, 0, env); + } + + void Logger::log0(const std::string &content, int level, JNIEnv *env) { + if (this->loggerhandler.enable) + this->loggerhandler.action(content, level); + json j; + j["id"] = -2; + j["log"] = content; + env->CallStaticVoidMethod(Config::CPP_lib, log, Tools::str2jstring(j.dump().c_str()), (jint) level); + } + + void IdLogger::log0(const std::string &content, int level, JNIEnv *env) { + if (this->loggerhandler.enable) + this->loggerhandler.action(content, level); + json j; + j["id"] = id; + j["log"] = content; + env->CallStaticVoidMethod(Config::CPP_lib, log, Tools::str2jstring(j.dump().c_str()), (jint) level); + } + + void PluginLogger::log0(const std::string &content, int level, JNIEnv *env) { + if (this->loggerhandler.enable) + this->loggerhandler.action(content, level); + json j; + j["id"] = -1; + j["name"] = CPPPlugin::plugin->config.id; + j["log"] = content; + env->CallStaticVoidMethod(Config::CPP_lib, log, Tools::str2jstring(j.dump().c_str()), (jint) level); + } + +/* +配置类实现 +throw: InitxException 即找不到对应签名 +*/ + + void Config::construct(JNIEnv *env) { + Config::CPP_lib = reinterpret_cast(env->NewGlobalRef( + env->FindClass("tech/eritquearcus/miraicp/shared/CPP_lib"))); + if (Config::CPP_lib == nullptr) { + throw APIException("初始化错误,找不到CPP_lib类"); + } + Config::KOperation = env->GetStaticMethodID(CPP_lib, "KOperation", "(Ljava/lang/String;)Ljava/lang/String;"); + } + + void Config::destruct() { + ThreadManager::getEnv(__FILE__, __LINE__)->DeleteGlobalRef(Config::CPP_lib); + } + + std::string + Config::koperation(operation_set type, json &data, JNIEnv *env, bool catchErr, const std::string &errorInfo) { + json j; + j["type"] = type; + j["data"] = data; + std::string re = Tools::jstring2str((jstring) env->CallStaticObjectMethod(Config::CPP_lib, Config::KOperation, + Tools::str2jstring(j.dump().c_str(), + env)), env); + if (catchErr) ErrorHandle(re, errorInfo); + return re; + } + + Event::~Event() { + Node0 *temp[] = {GMHead, PMHead, GHead, NFHead, MJHead, MLHead, RHead, BHead, TOHead}; + for (Node0 *ptr: temp) { + Node0 *now = ptr; + Node0 *t = nullptr; + while (true) { + t = now; + if (now->nextNode == nullptr) { + delete now; + break; + } + now = now->nextNode; + delete t; + } + } + } + + void MessageSource::recall(JNIEnv *env) const { + json j; + j["source"] = this->serializeToString(); + std::string re = Config::koperation(Config::Recall, j, env); + if (re == "Y") return; + if (re == "E1") throw BotException(); + if (re == "E2") throw RecallException(); + } + + MessageSource::MessageSource(std::string ids, std::string internalids, std::string source) : ids(std::move( + ids)), internalids(std::move(internalids)), source(std::move(source)) {} + + std::string MessageSource::serializeToString() const { + return source; + } + + MessageSource MessageSource::deserializeFromString(const std::string &source) { + json j = json::parse(source); + try { + return {j["ids"].dump(), j["internalIds"].dump(), source}; + } + catch (json::type_error &e) { + Logger::logger.error("消息源序列化出错,格式不符合(MessageSource::deserializeFromString)"); + Logger::logger.error(source); + Logger::logger.error(e.what()); + throw e; + } + } + +//远程文件(群文件) + RemoteFile RemoteFile::deserializeFromString(const std::string &source) { + json j; + try { + j = json::parse(source); + } + catch (json::parse_error &e) { + Logger::logger.error("格式化json失败,RemoteFile::deserializeFromString"); + Logger::logger.error(source); + Logger::logger.error(e.what()); + throw e; + } + try { + struct Dinfo d{ + j["dinfo"]["url"], + j["dinfo"]["md5"], + j["dinfo"]["sha1"] + }; + struct Finfo f{ + j["finfo"]["size"], + j["finfo"]["uploaderid"], + j["finfo"]["downloadtime"], + j["finfo"]["uploadtime"], + j["finfo"]["lastmodifytime"] + }; + return RemoteFile(j["id"], j["internalid"], j["name"], j["finfo"]["size"], j["path"], d, f); + } + catch (json::type_error &e) { + Logger::logger.error("json格式化失败,位置:RemoteFile"); + Logger::logger.error(source); + Logger::logger.error(e.what()); + throw e; + } + } + + std::string RemoteFile::serializeToString() { + json j; + j["dinfo"]["url"] = this->dinfo.url; + j["dinfo"]["md5"] = this->dinfo.md5; + j["dinfo"]["shar1"] = this->dinfo.sha1; + j["finfo"]["size"] = this->finfo.size; + j["finfo"]["uploaderid"] = this->finfo.uploaderid; + j["finfo"]["downloadtime"] = this->finfo.downloadtime; + j["finfo"]["uploadtime"] = this->finfo.uploadtime; + j["finfo"]["lastmodifytime"] = this->finfo.lastmodifytime; + j["id"] = this->id; + j["internalid"] = this->internalid; + j["name"] = this->name; + j["size"] = this->size; + return j.dump(); + } + +//发送这个聊天记录 + MessageSource ForwardMessage::sendTo(Contact *c, JNIEnv *env) { + json temp; + json text; + text["id"] = c->id(); + text["groupid"] = c->groupid(); + text["type"] = c->type(); + text["content"] = sendmsg; + temp["text"] = text.dump(); + temp["botid"] = c->botid(); + std::string re = Config::koperation(Config::Buildforward, temp, env); + //TODO:https://github.com/mamoe/mirai/issues/1371 + return MessageSource::deserializeFromString(re); + } + + ForwardMessage::ForwardMessage(Contact *c, std::initializer_list nodes) { + json root; + json value; + root["type"] = c->type(); + root["id"] = c->id(); + root["id2"] = c->groupid(); + for (const ForwardNode &node: nodes) { + json temp; + temp["id"] = node.id; + temp["time"] = node.time; + temp["message"] = node.message; + temp["name"] = node.name; + value.push_back(temp); + } + root["value"] = value; + sendmsg = root; + } + +/*图片类实现*/ + + std::string Image::queryURL(JNIEnv *env) { + json j; + j["id"] = this->id; + std::string re = Config::koperation(Config::QueryImgUrl, j, env); + if (re == "E1") + throw RemoteAssetException("图片id格式错误"); + return re; + } + + std::string Image::toMiraiCode() const { + return "[mirai:image:" + Tools::escapeToMiraiCode(this->id) + "]"; + } + + MessageSource MessageSource::quoteAndSendMiraiCode(const std::string &content, QQID groupid, JNIEnv *env) const { + json obj; + json sign; + obj["messageSource"] = this->serializeToString(); + obj["msg"] = content; + sign["MiraiCode"] = true; + sign["groupid"] = groupid; + obj["sign"] = sign.dump(); + std::string re = Config::koperation(Config::SendWithQuote, obj, env); + return MessageSource::deserializeFromString(re); + } + + MessageSource MessageSource::quoteAndSendMsg(const std::string &content, QQID groupid, JNIEnv *env) const { + json obj; + json sign; + obj["messageSource"] = this->serializeToString(); + obj["msg"] = content; + sign["MiraiCode"] = false; + sign["groupid"] = groupid; + obj["sign"] = sign.dump(); + std::string re = Config::koperation(Config::SendWithQuote, obj, env); + return MessageSource::deserializeFromString(re); + } + + MessageSource Contact::sendMsg0(const std::string &msg, int retryTime, bool miraicode, JNIEnv *env) { + if (msg.empty()) { + Logger::logger.warning("警告:发送空信息, 位置: Contact::SendMsg"); + throw IllegalArgumentException("参数不能为空, 位置: Contact::SendMsg"); + } + std::string re = LowLevelAPI::send0(msg, this, retryTime, miraicode, env, + "reach a error area, Contact::SendMiraiCode"); + if (re == "ET") + throw TimeOutException("发送消息过于频繁导致的tx服务器未能即使响应, 位置: Contact::SendMsg"); + if (Tools::starts_with(re, "EBM")) + throw BotIsBeingMutedException(std::stoi(re.substr(3))); + return MessageSource::deserializeFromString(re); + } + + Image Contact::uploadImg(const std::string &path, JNIEnv *env) { + std::string re = LowLevelAPI::uploadImg0(path, this, env); + if (re == "E2") + throw UploadException("上传图片大小超过30MB,路径:" + path); + return Image(re); + } + +/*好友类实现*/ + Friend::Friend(QQID id, QQID botid, JNIEnv *env) : Contact() { + this->_type = 1; + this->_id = id; + this->_botid = botid; + refreshInfo(env); + } + +/*成员类实现*/ + Member::Member(QQID id, QQID groupid, QQID botid, JNIEnv *env) + : Contact() { + this->_type = 3; + this->_id = id; + this->_groupid = groupid; + this->_botid = botid; + refreshInfo(env); + } + + unsigned int Member::getPermission(JNIEnv *env) { + if (isAnonymous) return 0; + json j; + j["contactSource"] = this->serializationToString(); + std::string re = Config::koperation(Config::QueryM, j, env); + return stoi(re); + } + + void Member::mute(int time, JNIEnv *env) { + json j; + j["time"] = time; + j["contactSource"] = this->serializationToString(); + std::string re = Config::koperation(Config::MuteM, j, env); + if (re == "E3") { + throw BotException(); + } + if (re == "E4") { + throw MuteException(); + } + } + + void Member::kick(const std::string &reason, JNIEnv *env) { + json j; + j["message"] = reason; + j["contactSource"] = this->serializationToString(); + std::string re = Config::koperation(Config::KickM, j, env); + if (re == "E3") { + throw BotException(); + } + } + + void Member::modifyAdmin(bool admin, JNIEnv *env) { + if (isAnonymous)return; + json j; + j["admin"] = admin; + j["contactSource"] = this->serializationToString(); + std::string re = Config::koperation(Config::ModifyAdmin, j, env); + if (re == "E1") { + throw BotException(); + } + } + +/*群聊类实现*/ + Group::Group(QQID groupid, QQID botid, JNIEnv *env) : Contact() { + this->_type = 2; + this->_id = groupid; + this->_botid = botid; + refreshInfo(env); + } + + void Group::OnlineAnnouncement::deleteThis() { + json j, i; + i["botid"] = this->botid; + i["groupid"] = this->groupid; + i["fid"] = this->fid; + i["type"] = 1; + j["identify"] = i.dump(); + std::string re = Config::koperation(Config::Announcement, j); + if (re == "E1") + throw IllegalArgumentException("无法根据fid找到群公告(群公告不存在)"); + if (re == "E2") + throw BotException(); + if (re == "E3") + throw IllegalStateException("群公告状态异常"); + } + + json Group::AnnouncementParams::serializeToJson() { + json j; + j["sendToNewMember"] = this->send2new; + j["isPinned"] = this->pinned; + j["showEditCard"] = this->showEditCard; + j["showPopup"] = this->showPopup; + j["requireConfirmation"] = this->requireConfirm; + return j; + } + + Group::OnlineAnnouncement Group::OfflineAnnouncement::publishTo(const Group &g) { + json j, i, s; + i["botid"] = g.botid(); + i["groupid"] = g.id(); + i["type"] = 2; + j["identify"] = i.dump(); + s["content"] = this->content; + s["params"] = this->params.serializeToJson(); + j["source"] = s.dump(); + std::string re = Config::koperation(Config::Announcement, j); + if (re == "E1") + throw BotException(); + return Group::OnlineAnnouncement::deserializeFromJson(json::parse(re)); + } + + Group::OnlineAnnouncement Group::OnlineAnnouncement::deserializeFromJson(json j) { + Group::AnnouncementParams ap( + j["params"]["sendToNewMember"], + j["params"]["requireConfirmation"], + j["params"]["isPinned"], + j["params"]["showEditCard"], + j["params"]["showPopup"] + ); + return Group::OnlineAnnouncement( + j["content"], + ap, + j["groupid"], + j["senderid"], + j["botid"], + j["time"], + j["fid"], + j["confirmationNum"], + j["imageid"] + ); + } + + void Group::updateSetting(JNIEnv *env) { + json j; + json tmp; + j["name"] = this->setting.name; + j["isMuteAll"] = this->setting.isMuteAll; + j["isAllowMemberInvite"] = this->setting.isAllowMemberInvite; + j["isAutoApproveEnabled"] = this->setting.isAutoApproveEnabled; + j["isAnonymousChatEnabled"] = this->setting.isAnonymousChatEnabled; + tmp["source"] = j.dump(); + tmp["contactSource"] = this->serializationToString(); + std::string re = Config::koperation(Config::GroupSetting, tmp, env); + if (re == "E1") + throw BotException(); + refreshInfo(env); + } + + RemoteFile Group::sendFile(const std::string &path, const std::string &filepath, JNIEnv *env) { + json tmp; + json source; + source["path"] = path; + source["filepath"] = filepath; + tmp["source"] = source.dump(); + tmp["contactSource"] = this->serializationToString(); + std::string callback = Config::koperation(Config::SendFile, tmp, env); + if (callback == "E2") throw UploadException("找不到" + filepath + "位置:C-uploadfile"); + if (callback == "E3") + throw UploadException("Upload error:路径格式异常,应为'/xxx.xxx'或'/xx/xxx.xxx'目前只支持群文件和单层路径, path:" + path); + return RemoteFile::deserializeFromString(callback); + } + + RemoteFile Group::getFile(const std::string &path, const std::string &id, JNIEnv *env) { + // source 参数 + json tmp; + json j; + tmp["id"] = id; + tmp["path"] = path; + j["source"] = tmp.dump(); + j["contactSource"] = this->serializationToString(); + std::string re = Config::koperation(Config::RemoteFileInfo, j, env); + if (re == "E2") throw RemoteAssetException("Get error: 文件路径不存在, path:" + path); + return RemoteFile::deserializeFromString(re); + } + + Member Group::getOwner(JNIEnv *env) { + json j; + j["contactSource"] = this->serializationToString(); + std::string re = Config::koperation(Config::QueryOwner, j, env); + return Member(stoi(re), this->id(), this->botid()); + } + + std::string Group::getFileListString(const std::string &path, JNIEnv *env) { + json temp; + json j; + temp["id"] = "-1"; + temp["path"] = path; + j["source"] = temp.dump(); + j["contactSource"] = this->serializationToString(); + return Config::koperation(Config::RemoteFileInfo, j, env); + } + + std::vector Group::getFileList(const std::string &path, JNIEnv *env) { + std::vector re = std::vector(); + std::string tmp = getFileListString(path, env); + json root = json::parse(tmp); + for (auto &i: root) { + file_short_info t; + t.path = i[0]; + t.id = i[1]; + re.push_back(t); + } + return re; + } + + MessageChain PrivateMessageEvent::nextMessage(long time, bool halt, JNIEnv *env) { + json j; + j["contactSource"] = this->sender.serializationToString(); + j["time"] = time; + j["halt"] = halt; + std::string r = Config::koperation(Config::NextMsg, j, env); + if (r == "-1") + throw TimeOutException("取下一条信息超时"); + json re = json::parse(r); + return MessageChain::deserializationFromMiraiCode(re["message"]).plus( + MessageSource::deserializeFromString(re["messageSource"])); + } + + MessageChain GroupMessageEvent::nextMessage(long time, bool halt, JNIEnv *env) { + json j; + j["contactSource"] = this->group.serializationToString(); + j["time"] = time; + j["halt"] = halt; + std::string r = Config::koperation(Config::NextMsg, j, env); + if (r == "-1") + throw TimeOutException("取下一条信息超时"); + json re = json::parse(r); + return MessageChain::deserializationFromMiraiCode(re["message"]).plus( + MessageSource::deserializeFromString(re["messageSource"])); + } + + MessageChain GroupMessageEvent::senderNextMessage(long time, bool halt, JNIEnv *env) { + json j; + j["contactSource"] = this->sender.serializationToString(); + j["time"] = time; + j["halt"] = halt; + std::string r = Config::koperation(Config::NextMsg, j, env); + if (r == "-1") + throw TimeOutException("取下一条信息超时"); + json re = json::parse(r); + return MessageChain::deserializationFromMiraiCode(re["message"]).plus( + MessageSource::deserializeFromString(re["messageSource"])); + } + +/*工具类实现*/ + std::string Tools::jstring2str(jstring jStr, JNIEnv *env) { + if (!jStr) { + Logger::logger.error("警告:kotlin部分返回空字符串, 位置:Tools::jstring2str"); + return ""; + } + std::u16string s = reinterpret_cast(env->GetStringChars(jStr, nullptr)); + if (s.length() == 0) { + Logger::logger.error("警告:kotlin部分返回空字符串, 位置:Tools::jstring2str"); + return ""; + } + std::string x; + utf8::utf16to8(s.begin(), s.end(), std::back_inserter(x)); + return x; + } + + jstring Tools::str2jstring(const char *stra, JNIEnv *env) { + if (!stra) { + Logger::logger.error("警告:C++部分传入空字符串,位置:Tools::str2jstring"); + } + std::string str(stra); + std::vector utf16line; + utf8::utf8to16(str.begin(), str.end(), std::back_inserter(utf16line)); + auto *c = new jchar[utf16line.size()]; + for (int i = 0; i < utf16line.size(); i++) { + c[i] = utf16line[i]; + } + return env->NewString((jchar *) c, (jsize) utf16line.size()); + } + + template + std::string Tools::VectorToString(std::vector a, const std::string &separator) { + std::stringstream ss; + for (size_t i = 0; i < a.size(); ++i) { + if (i != 0) + ss << separator; + ss << a[i]; + } + std::string s = ss.str(); + return s; + } + + std::vector Tools::StringToVector(std::string temp) { + std::vector result; + temp.erase(temp.begin()); + temp.pop_back(); + std::regex ws_re("[,]+"); + std::vector v(std::sregex_token_iterator(temp.begin(), temp.end(), ws_re, -1), + std::sregex_token_iterator()); + result.reserve(v.size()); + for (auto &&s: v) + result.push_back(std::stoull(s)); + return result; + } + + std::string Tools::escapeFromMiraiCode(const std::string &s) { + //[ \[ + //] \] + //: \: + //, \, + //\ \\ / + return Tools::replace( + Tools::replace( + Tools::replace( + Tools::replace( + Tools::replace(s, + "\\\\", "\\"), + "\\,", ","), + "\\:", ":"), + "\\]", "]"), "\\[", "["); + } + + std::string Tools::escapeToMiraiCode(const std::string &s) { + //[ \[ + //] \] + //: \: + //, \, + //\ \\ / + return Tools::replace(Tools::replace(Tools::replace(Tools::replace(Tools::replace(s, + "\\", "\\\\"), + ",", "\\,"), + ":", "\\:"), + "]", "\\]"), "[", "\\["); + } + + Contact Contact::deserializationFromString(const std::string &source) { + json j; + try { + j = json::parse(source); + } + catch (json::parse_error &e) { + Logger::logger.error("json序列化错误 Contact::deserializationFromString"); + Logger::logger.error(source); + Logger::logger.error(e.what()); + } + return Contact::deserializationFromJson(j); + } + + Contact Contact::deserializationFromJson(nlohmann::json j) { + return Contact(j["type"], + j["id"], + j["groupid"], + j["nickornamecard"], + j["botid"], + j["anonymous"]); + } + + MessageSource Contact::sendVoice0(const std::string &path, JNIEnv *env) { + json j; + json source; + source["path"] = path; + j["source"] = source.dump(); + j["contactSource"] = this->serializationToString(); + std::string re = Config::koperation(Config::Voice, j, env); + if (re == "E1") + throw UploadException("上传语音文件格式不对(必须为.amr/.silk)或文件不存在"); + else if (re == "E2") + throw UploadException("上传语音文件大小超过服务器限制,一般限制在1MB上下"); + return MessageSource::deserializeFromString(re); + } + + json PluginConfig::serialize() { + json j; + j["name"] = name; + j["version"] = version; + j["author"] = author; + j["description"] = description; + j["time"] = time; + j["id"] = id; + return j; + } +// 结束MiraiCP实现代码 +} +//开始对接JNI接口代码 + +/* +* 名称:Java_com_example_plugin_CPP_1lib_Verify +* 作用:判断是否连接上本插件,勿改 +* 参数:env 必备,job 必备 +* 返回值:jstring (用str2jstring把string类型转成jsrting) 发送返回的字符串 +*/ +JNIEXPORT jstring Verify(JNIEnv *env, jobject) { + using namespace MiraiCP; + ThreadManager::setEnv(env); + MiraiCP::ThreadManager::JNIVersion = env->GetVersion(); + try { + //初始化日志模块 + Config::construct(); + Logger::logger.init(); + enrollPlugin(); + if (CPPPlugin::plugin == nullptr) { + Logger::logger.error("无插件实例加载"); + } else { + CPPPlugin::pluginLogger = new PluginLogger(&Logger::logger); + CPPPlugin::plugin->onEnable(); + } + } + catch (MiraiCPException &e) { + e.raise(); + } + json j = CPPPlugin::plugin->config.serialize(); + j["MiraiCPversion"] = MiraiCPVersion; + return Tools::str2jstring(j.dump().c_str());//验证机制,返回当前SDK版本 +} +/* 插件结束事件*/ +JNIEXPORT jobject PluginDisable(JNIEnv *env, jobject job) { + using namespace MiraiCP; + ThreadManager::setEnv(env); + CPPPlugin::plugin->onDisable(); + CPPPlugin::plugin = nullptr; + return job; +} +/*返回空值*/ +JNIEXPORT jstring returnNull() { + return MiraiCP::Tools::str2jstring("MIRAICP_NULL"); +} +/* +* 消息解析分流 +*/ +JNIEXPORT jstring Event(JNIEnv *env, jobject, jstring content) { + using namespace MiraiCP; + ThreadManager::setEnv(env); + std::string tmp = Tools::jstring2str(content, env); + json j; + try { + j = json::parse(tmp); + } + catch (json::parse_error &e) { + APIException("格式化json错误").raise(); + Logger::logger.error("For debug:" + j.dump()); + Logger::logger.error(e.what(), false); + return returnNull(); + } + ThreadManager::getThread()->stack.push(__FILE__, __LINE__, "source: " + tmp); + try { + switch ((int) j["type"]) { + case 1: { + //GroupMessage + Event::processor.broadcast( + GroupMessageEvent(j["group"]["botid"], + Group(Group::deserializationFromJson(j["group"])), + Member(Member::deserializationFromJson(j["member"])), + MessageChain::deserializationFromMiraiCode(j["message"].get()) + .plus(MessageSource::deserializeFromString(j["source"])) + ) + ); + break; + } + case 2: { + //私聊消息 + Event::processor.broadcast( + PrivateMessageEvent(j["friend"]["botid"], + Friend(Friend::deserializationFromJson(j["friend"])), + MessageChain::deserializationFromMiraiCode(j["message"]) + .plus(MessageSource::deserializeFromString(j["source"])) + )); + break; + } + case 3: + //群聊邀请 + Event::processor.broadcast( + GroupInviteEvent( + j["source"]["botid"], + j["request"], + j["source"]["inviternick"], + j["source"]["inviterid"], + j["source"]["groupname"], + j["source"]["groupid"] + )); + break; + case 4: + //好友 + Event::processor.broadcast( + NewFriendRequestEvent( + j["source"]["botid"], + j["request"], + j["source"]["fromid"], + j["source"]["fromgroupid"], + j["source"]["fromnick"], + j["source"]["message"] + )); + break; + case 5: + //新成员加入 + Event::processor.broadcast( + MemberJoinEvent( + j["group"]["botid"], + j["jointype"], + Member(Member::deserializationFromJson(j["member"])), + Group(Group::deserializationFromJson(j["group"])), + j["inviterid"] + )); + break; + case 6: + //群成员退出 + Event::processor.broadcast(MemberLeaveEvent( + j["group"]["botid"], + j["leavetype"], + j["memberid"], + Group(Group::deserializationFromJson(j["group"])), + j["operatorid"] + )); + break; + case 7: + Event::processor.broadcast(RecallEvent( + j["botid"], + j["etype"], + j["time"], + j["authorid"], + j["operatorid"], + j["ids"], + j["internalids"], + j["groupid"] + )); + break; + case 9: + Event::processor.broadcast(BotJoinGroupEvent( + j["group"]["botid"], + j["etype"], + Group(Group::deserializationFromJson(j["group"])), + j["inviterid"] + )); + break; + case 10: + Event::processor.broadcast(GroupTempMessageEvent( + j["group"]["botid"], + Group(Group::deserializationFromJson(j["group"])), + Member(Member::deserializationFromJson(j["member"])), + MessageChain::deserializationFromMiraiCode(j["message"]) + .plus(MessageSource::deserializeFromString(j["source"])) + )); + break; + case 11: + Event::processor.broadcast(BotOnlineEvent(j["botid"])); + break; + case 12: + Event::processor.broadcast(TimeOutEvent(j["msg"])); + break; + case 13: + Event::processor.broadcast(NudgeEvent(Contact::deserializationFromJson(j["from"]), + Contact::deserializationFromJson(j["target"]), + j["botid"])); + break; + case 14: + Event::processor.broadcast(BotLeaveEvent(j["groupid"], j["botid"])); + break; + case 15: { + std::optional a; + std::optional b; + Contact temp = Contact::deserializationFromJson(j["group"]); + if (temp.id() == 0) + a = std::nullopt; + else + a = Group(temp); + temp = Contact::deserializationFromJson(j["inviter"]); + if (temp.id() == 0) + b = std::nullopt; + else + b = Member(temp); + Event::processor.broadcast(MemberJoinRequestEvent(a, b, temp.botid(), j["requestData"])); + break; + } + default: + throw APIException("Unreachable code"); + } + } + catch (json::type_error &e) { + Logger::logger.error("json格式化异常,位置C-Handle"); + Logger::logger.error(e.what(), false); + return Tools::str2jstring("ERROR"); + } catch (MiraiCPException &e) { + Logger::logger.error("MiraiCP error:" + e.what()); + return Tools::str2jstring("ERROR"); + } + return returnNull(); +} + +int registerMethods(JNIEnv *env, const char *className, + JNINativeMethod *gMethods, int numMethods) { + jclass clazz = env->FindClass(className); + if (clazz == nullptr) { + return JNI_FALSE; + } + //注册native方法 + if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { + return JNI_FALSE; + } + return JNI_TRUE; +} + +JNINativeMethod method_table[] = { + {(char *) "Verify", (char *) "()Ljava/lang/String;", (jstring *) Verify}, + {(char *) "Event", (char *) "(Ljava/lang/String;)Ljava/lang/String;", (jstring *) Event}, + {(char *) "PluginDisable", (char *) "()Ljava/lang/Void;", (jobject *) PluginDisable} +}; + +extern "C" +JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) { + JNIEnv *env = nullptr; + if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { + return JNI_ERR; + } + assert(env != nullptr); + MiraiCP::ThreadManager::gvm = vm; + // 注册native方法 + if (!registerMethods(env, "tech/eritquearcus/miraicp/shared/CPP_lib", method_table, 3)) { + return JNI_ERR; + } + + return JNI_VERSION_1_6; +} + +//结束对接JNI接口代码 \ No newline at end of file diff --git a/cpp/include/miraiCP.hpp b/cpp/include/miraiCP.hpp index cc871a57a..43dbb40e0 100644 --- a/cpp/include/miraiCP.hpp +++ b/cpp/include/miraiCP.hpp @@ -14,6 +14,7 @@ // along with this program. If not, see . // +#pragma once // 针对clion #pragma clang diagnostic push // 禁止检查unused @@ -190,10 +191,6 @@ LightApp风格1 // 开始MiraiCP类声明代码 ///@} -/// @brief 全局JavaVM对象,用于多线程管理中新建线程的JNIEnv. - JavaVM *gvm = nullptr; -/// @brief JNI 版本. - int JNIVersion = 0; /*! * @class threadManager @@ -201,14 +198,14 @@ LightApp风格1 */ class ThreadManager { public: - class StackTracer{ + class StackTracer { + private: std::vector stackTrace = std::vector(); public: - /// print all - std::string print(){ + std::string print() { std::string re = "StackTrace:"; - for(const auto& a:stackTrace) + for (const auto &a: stackTrace) re += "\n" + a; return re; } @@ -236,9 +233,16 @@ LightApp风格1 /// 判断该线程id是否包含在线程池里 static bool included(const std::string &id); + ThreadManager() = default; + public: + /// @brief 全局JavaVM对象,用于多线程管理中新建线程的JNIEnv. + static JavaVM *gvm; + /// @brief JNI 版本. + static long JNIVersion; + /// 获取线程 - static ThreadInfo* getThread(){ + static ThreadInfo *getThread() { return &threads[getThreadId()]; } @@ -276,9 +280,6 @@ LightApp风格1 static JNIEnv *getEnv(const std::string& file, int loc, const std::string& func = ""); }; - std::map ThreadManager::threads = std::map(); - std::recursive_mutex ThreadManager::mtx = std::recursive_mutex(); - /// @brief 工具类声明, 常用的一些转换工具, 如需转码使用std::filesystem /// @class Tools class Tools { @@ -440,9 +441,6 @@ LightApp风格1 static void destruct(); }; - jclass Config::CPP_lib = nullptr; - jmethodID Config::KOperation = nullptr; - /// MiraiCode父类, 指可以被转换成miraicode的类型 class MiraiCodeable { public: @@ -452,7 +450,7 @@ LightApp风格1 /// @brief miraicode字符串 /// @attention MiraiCode会把非miraicode组成部分(非[mirai:])转码, 输出转码前的文本用toString, 参考: https://github.com/mamoe/mirai/blob/dev/docs/Messages.md#%E8%BD%AC%E4%B9%89%E8%A7%84%E5%88%99 /// @detail 为了便捷使用,构造函数不以explicit注释 - class MiraiCode:MiraiCodeable { + class MiraiCode : public MiraiCodeable { private: std::string content; public: @@ -488,24 +486,25 @@ LightApp风格1 return {content + a}; } - MiraiCode operator+(const MiraiCode& a){ + MiraiCode operator+(const MiraiCode &a) { return {content + a.content}; } - MiraiCode operator+(MiraiCode* a){ + MiraiCode operator+(MiraiCode *a) { return {content + a->content}; } - MiraiCode operator=(const std::string& a) { - return {a}; + MiraiCode &operator=(const std::string &a) { + this->content = a; + return *this; } MiraiCode plus(MiraiCodeable *a) { return {content + a->toMiraiCode()}; } - MiraiCode plus(const std::string& a) { - return MiraiCode(a)+this; + MiraiCode plus(const std::string &a) { + return MiraiCode(a) + this; } /// 不执行转义,适用于已经被MiraiCode转义过的字符串 @@ -625,10 +624,6 @@ LightApp风格1 public: static Logger logger; }; - Logger Logger::logger = Logger(); - - [[deprecated("Use Logger::logger instead")]] - Logger* const logger = &Logger::logger; /// 带id(一般为bot账号)的logger class IdLogger : public Logger_interface { @@ -662,6 +657,8 @@ LightApp风格1 /// @brief 插件级logger static PluginLogger *pluginLogger; + static CPPPlugin *plugin; + virtual void onEnable() {} virtual void onDisable() {} @@ -669,9 +666,6 @@ LightApp风格1 explicit CPPPlugin(PluginConfig c) : config(std::move(c)) {} }; - PluginLogger *CPPPlugin::pluginLogger = nullptr; - CPPPlugin *plugin = nullptr; - /// @brief 总异常抽象类 /// @interface MiraiCPException class MiraiCPException : public std::exception { @@ -1085,16 +1079,6 @@ LightApp风格1 /// @param prefix 前缀, 默认为`:`, 第二个冒号部分的内容, 目前在serviceMesage有使用 SingleMessage(int type, std::string content, std::string prefix = ":") : type(type), content(std::move(content)), prefix(std::move(prefix)){} }; - std::map SingleMessage::messageType = { - {-2, "QuoteReply"}, - {-1, "unSupportMessage"}, - {0, "plainText"}, - {1, "at"}, - {2, "atAll"}, - {3, "image"}, - {4, "app"}, - {5, "service"} - }; /// 纯文本信息 class PlainText: public SingleMessage{ @@ -1586,21 +1570,37 @@ LightApp风格1 /// - SingleMessage的各种派生类 /// - MessageChain template - MessageSource quoteAndSendMessage(T s, QQID groupid = -1, JNIEnv* env = ThreadManager::getEnv(__FILE__, __LINE__)){ + MessageSource + quoteAndSendMessage(T s, QQID groupid = -1, JNIEnv *env = ThreadManager::getEnv(__FILE__, __LINE__)) { static_assert(std::is_base_of_v, "只支持SingleMessage的派生类"); return this->quoteAndSend0(s.toMiraiCode(), groupid, env); } + template<> + MessageSource quoteAndSendMessage(std::string s, QQID groupid, JNIEnv *env) { + return this->quoteAndSend0(s, groupid, env); + } + + template<> + MessageSource quoteAndSendMessage(const char *s, QQID groupid, JNIEnv *env) { + return this->quoteAndSend0(s, groupid, env); + } + + template<> + MessageSource quoteAndSendMessage(MessageChain mc, QQID groupid, JNIEnv *env) { + return this->quoteAndSend0(mc.toMiraiCode(), groupid, env); + } + /// 从string构建MessageChain, 常用于Incoming message - static MessageChain deserializationFromMiraiCode(const std::string& m){ + static MessageChain deserializationFromMiraiCode(const std::string &m) { size_t pos = 0; size_t lastPos = -1; MessageChain mc; - if(m.length() <= 7){ + if (m.length() <= 7) { return MessageChain(PlainText(m)); } - do{ - if(m.length() - 7 - pos > 0 && m.substr(pos, 7) == "[mirai:"){ + do { + if (m.length() - 7 - pos > 0 && m.substr(pos, 7) == "[mirai:") { if(pos - lastPos > 1) mc.add(PlainText(m.substr(lastPos + 1, pos - lastPos - 1)));// plain text size_t back = MessageChain::findEnd(m, pos); @@ -1694,18 +1694,6 @@ LightApp风格1 return mc; } }; - template<> - MessageSource MessageChain::quoteAndSendMessage(std::string s, QQID groupid, JNIEnv* env){ - return this->quoteAndSend0(s, groupid, env); - } - template<> - MessageSource MessageChain::quoteAndSendMessage(const char* s, QQID groupid, JNIEnv* env){ - return this->quoteAndSend0(s, groupid, env); - } - template<> - MessageSource MessageChain::quoteAndSendMessage(MessageChain mc, QQID groupid, JNIEnv* env){ - return this->quoteAndSend0(mc.toMiraiCode(), groupid, env); - } /*! * @brief group, friend, member的父类 @@ -1831,13 +1819,14 @@ LightApp风格1 /// @return MessageSource /// @throw IllegalArgumentException, TimeOutException, BotIsBeingMutedException [[deprecated("Use sendMessage")]] - MessageSource sendMiraiCode(MiraiCode msg, int retryTime = 3, JNIEnv* env = ThreadManager::getEnv(__FILE__, __LINE__)) { + MessageSource sendMiraiCode(const MiraiCode &msg, int retryTime = 3, + JNIEnv *env = ThreadManager::getEnv(__FILE__, __LINE__)) { return sendMsg0(msg.toMiraiCode(), retryTime, true, env); } template - MessageSource sendMessage(T ... val){ - return this->sendMessage(MessageChain(val...), 3, ThreadManager::getEnv(__FILE__, __LINE__)); + MessageSource sendMessage(T ... msg) { + return this->sendMessage(MessageChain(msg...), 3, ThreadManager::getEnv(__FILE__, __LINE__)); } /// @brief 发送一条Message @@ -1850,18 +1839,39 @@ LightApp风格1 /// @param retryTime 重试次数 /// @return MessageSource template - MessageSource sendMessage(T msg, int retryTime = 3, JNIEnv* env = ThreadManager::getEnv(__FILE__, __LINE__)){ + MessageSource sendMessage(T msg, int retryTime = 3, JNIEnv *env = ThreadManager::getEnv(__FILE__, __LINE__)) { static_assert(std::is_base_of_v, "只支持SingleMessage的派生类"); return sendMsg0(msg.toMiraiCode(), retryTime, true, env); } + template<> + MessageSource sendMessage(MessageChain msg, int retryTime, JNIEnv *env) { + return sendMsg0(msg.toMiraiCode(), retryTime, true, env); + } + + template<> + MessageSource sendMessage(MiraiCode msg, int retryTime, JNIEnv *env) { + return sendMsg0(msg.toMiraiCode(), retryTime, true, env); + } + + template<> + MessageSource sendMessage(std::string msg, int retryTime, JNIEnv *env) { + return sendMsg0(msg, retryTime, false, env); + } + + template<> + MessageSource sendMessage(const char *msg, int retryTime, JNIEnv *env) { + return sendMsg0(std::string(msg), retryTime, false, env); + } + /// @brief 发送纯文本信息 /// @param msg 发送的信息 /// @param retryTime 当服务器无应答(通常由于发送消息频率太快导致)时的重试次数,每次重试相隔1s,-1为无限制,如果在重试次数用完后还是没能成功发送就会抛出TimeOutException /// @return MessageSource /// @throw IllegalArgumentException, TimeOutException, BotIsBeingMutedException [[deprecated("Use sendMessage")]] - MessageSource sendMsg(const std::string& msg, int retryTime = 3, JNIEnv* env = ThreadManager::getEnv(__FILE__, __LINE__)) { + MessageSource + sendMsg(const std::string &msg, int retryTime = 3, JNIEnv *env = ThreadManager::getEnv(__FILE__, __LINE__)) { return sendMsg0(msg, retryTime, false, env); } @@ -1871,7 +1881,8 @@ LightApp风格1 /// @return MessageSource /// @throw IllegalArgumentException, TimeOutException, BotIsBeingMutedException [[deprecated("Use sendMessage")]] - MessageSource sendMsg(MiraiCode msg, int retryTime = 3, JNIEnv* env = ThreadManager::getEnv(__FILE__, __LINE__)){ + MessageSource + sendMsg(const MiraiCode &msg, int retryTime = 3, JNIEnv *env = ThreadManager::getEnv(__FILE__, __LINE__)) { return sendMsg0(msg.toMiraiCode(), retryTime, false, env); } @@ -1899,26 +1910,6 @@ LightApp风格1 virtual void refreshInfo(JNIEnv *) {}; }; - template<> - MessageSource Contact::sendMessage(MessageChain msg, int retryTime, JNIEnv* env){ - return sendMsg0(msg.toMiraiCode(), retryTime, true, env); - } - - template<> - MessageSource Contact::sendMessage(MiraiCode msg, int retryTime, JNIEnv* env){ - return sendMsg0(msg.toMiraiCode(), retryTime, true, env); - } - - template<> - MessageSource Contact::sendMessage(std::string msg, int retryTime, JNIEnv* env){ - return sendMsg0(msg, retryTime, false, env); - } - - template<> - MessageSource Contact::sendMessage(const char* msg, int retryTime, JNIEnv* env){ - return sendMsg0(std::string(msg), retryTime, false, env); - } - // 群文件 /// @brief 下载信息 @@ -2929,7 +2920,7 @@ LightApp风格1 /// @brief 开启一个新的定时任务 /// @param time 延迟多久,毫秒为单位 /// @param msg string类型附带信息,推荐使用json格式方便解析 - void schedule(long time, const std::string& msg, JNIEnv* env = ThreadManager::getEnv(__FILE__, __LINE__)){ + inline void schedule(long time, const std::string &msg, JNIEnv *env = ThreadManager::getEnv(__FILE__, __LINE__)) { json j; j["time"] = time; j["msg"] = msg; @@ -3193,964 +3184,13 @@ LightApp风格1 static Event processor; }; - Event Event::processor = Event(); - - [[deprecated("Use Event::processor instead")]] - Event * const procession = &Event::processor; - -/*线程管理*/ - -// 结束MiraiCP类声明代码 -// 开始MiraiCP实现代码 - - void ThreadManager::setEnv(JNIEnv *e) { - mtx.lock(); - if (!ThreadManager::included(ThreadManager::getThreadId())) { - ThreadInfo tmp{ - e, - false - }; - ThreadManager::threads.insert(std::pair(ThreadManager::getThreadId(), tmp)); - } else { - ThreadManager::threads[ThreadManager::getThreadId()].e = e; - } - mtx.unlock(); - } - - void ThreadManager::newEnv(const char *threadName) { - JNIEnv *env = nullptr; - JavaVMAttachArgs args{ - JNIVersion, - const_cast(threadName), - nullptr - }; - gvm->AttachCurrentThread((void **) &env, &args); - ThreadInfo tmp{env, true}; - ThreadManager::threads.insert(std::pair(ThreadManager::getThreadId(), tmp)); - Logger::logger.info("refresh env"); - }; - - void ThreadManager::detach() { - mtx.lock(); - if (ThreadManager::included(ThreadManager::getThreadId())) { - bool att = ThreadManager::threads[ThreadManager::getThreadId()].attach; - ThreadManager::threads.erase(ThreadManager::getThreadId()); - if (att) - gvm->DetachCurrentThread(); - } - mtx.unlock(); - } - - bool ThreadManager::included(const std::string &id) { - if (ThreadManager::threads.empty() || ThreadManager::threads.count(id) == 0) - return false; - return true; - } - - JNIEnv *ThreadManager::getEnv(const std::string& file, int loc, const std::string& func) { - mtx.lock(); - if (!ThreadManager::included(getThreadId())) { - ThreadManager::newEnv(); - } - JNIEnv *tmp = ThreadManager::threads[ThreadManager::getThreadId()].e; - ThreadManager::threads[ThreadManager::getThreadId()].stack.push(file, loc, func); - mtx.unlock(); - return tmp; - } - -/* -日志类实现 -throw: InitException 即找不到签名 -*/ - - void Logger_interface::init(JNIEnv *env) { - this->log = env->GetStaticMethodID(Config::CPP_lib, "KSendLog", "(Ljava/lang/String;I)V"); - } - - void Logger_interface::registerHandle(Logger_interface::Action action) { - this->loggerhandler.action = std::move(action); - } - - void Logger_interface::setHandleState(bool state) { - this->loggerhandler.enable = state; - } - - void Logger_interface::warning(const std::string &content, JNIEnv *env) { - this->log0(content, 1, env); - } - - void Logger_interface::error(const std::string &content, bool printStack, JNIEnv *env) { - ThreadManager::StackTracer a = ThreadManager::getThread()->stack; - if(printStack) - this->log0(content + "\n" + a.print(), 2, env); - else - this->log0(content, 2, env); - } - - void Logger_interface::info(const std::string &content, JNIEnv *env) { - this->log0(content, 0, env); - } - - void Logger::log0(const std::string &content, int level, JNIEnv *env) { - if (this->loggerhandler.enable) - this->loggerhandler.action(content, level); - json j; - j["id"] = -2; - j["log"] = content; - env->CallStaticVoidMethod(Config::CPP_lib, log, Tools::str2jstring(j.dump().c_str()), (jint) level); - } - - void IdLogger::log0(const std::string &content, int level, JNIEnv *env) { - if (this->loggerhandler.enable) - this->loggerhandler.action(content, level); - json j; - j["id"] = id; - j["log"] = content; - env->CallStaticVoidMethod(Config::CPP_lib, log, Tools::str2jstring(j.dump().c_str()), (jint) level); - } - void PluginLogger::log0(const std::string &content, int level, JNIEnv *env) { - if (this->loggerhandler.enable) - this->loggerhandler.action(content, level); - json j; - j["id"] = -1; - j["name"] = plugin->config.id; - j["log"] = content; - env->CallStaticVoidMethod(Config::CPP_lib, log, Tools::str2jstring(j.dump().c_str()), (jint) level); - } - -/* -配置类实现 -throw: InitxException 即找不到对应签名 -*/ - - void Config::construct(JNIEnv *env) { - Config::CPP_lib = reinterpret_cast(env->NewGlobalRef( - env->FindClass("tech/eritquearcus/miraicp/shared/CPP_lib"))); - if (Config::CPP_lib == nullptr) { - throw APIException("初始化错误,找不到CPP_lib类"); - } - Config::KOperation = env->GetStaticMethodID(CPP_lib, "KOperation", "(Ljava/lang/String;)Ljava/lang/String;"); - } - - void Config::destruct() { - ThreadManager::getEnv(__FILE__, __LINE__)->DeleteGlobalRef(Config::CPP_lib); - } - - std::string Config::koperation(operation_set type, json &data, JNIEnv *env, bool catchErr, const std::string& errorInfo) { - json j; - j["type"] = type; - j["data"] = data; - std::string re = Tools::jstring2str((jstring) env->CallStaticObjectMethod(Config::CPP_lib, Config::KOperation, - Tools::str2jstring(j.dump().c_str(), env)), env); - if(catchErr) ErrorHandle(re, errorInfo); - return re; - } - - Event::~Event() { - Node0 *temp[] = {GMHead, PMHead, GHead, NFHead, MJHead, MLHead, RHead, BHead, TOHead}; - for (Node0 *ptr : temp) { - Node0 *now = ptr; - Node0 *t = nullptr; - while (true) { - t = now; - if (now->nextNode == nullptr) { - delete now; - break; - } - now = now->nextNode; - delete t; - } - } - } - - void MessageSource::recall(JNIEnv *env) const { - json j; - j["source"] = this->serializeToString(); - std::string re = Config::koperation(Config::Recall, j, env); - if (re == "Y") return; - if (re == "E1") throw BotException(); - if (re == "E2") throw RecallException(); - } - - MessageSource::MessageSource(std::string ids, std::string internalids, std::string source) : ids(std::move( - ids)), internalids(std::move(internalids)), source(std::move(source)) {} - - std::string MessageSource::serializeToString() const { - return source; - } - - MessageSource MessageSource::deserializeFromString(const std::string &source) { - json j = json::parse(source); - try { - return {j["ids"].dump(), j["internalIds"].dump(), source}; - } - catch (json::type_error &e) { - Logger::logger.error("消息源序列化出错,格式不符合(MessageSource::deserializeFromString)"); - Logger::logger.error(source); - Logger::logger.error(e.what()); - throw e; - } - } - - //远程文件(群文件) - RemoteFile RemoteFile::deserializeFromString(const std::string &source) { - json j; - try { - j = json::parse(source); - } - catch (json::parse_error &e) { - Logger::logger.error("格式化json失败,RemoteFile::deserializeFromString"); - Logger::logger.error(source); - Logger::logger.error(e.what()); - throw e; - } - try { - struct Dinfo d{ - j["dinfo"]["url"], - j["dinfo"]["md5"], - j["dinfo"]["sha1"] - }; - struct Finfo f{ - j["finfo"]["size"], - j["finfo"]["uploaderid"], - j["finfo"]["downloadtime"], - j["finfo"]["uploadtime"], - j["finfo"]["lastmodifytime"] - }; - return RemoteFile(j["id"], j["internalid"], j["name"], j["finfo"]["size"], j["path"], d, f); - } - catch (json::type_error &e) { - Logger::logger.error("json格式化失败,位置:RemoteFile"); - Logger::logger.error(source); - Logger::logger.error(e.what()); - throw e; - } - } - - std::string RemoteFile::serializeToString() { - json j; - j["dinfo"]["url"] = this->dinfo.url; - j["dinfo"]["md5"] = this->dinfo.md5; - j["dinfo"]["shar1"] = this->dinfo.sha1; - j["finfo"]["size"] = this->finfo.size; - j["finfo"]["uploaderid"] = this->finfo.uploaderid; - j["finfo"]["downloadtime"] = this->finfo.downloadtime; - j["finfo"]["uploadtime"] = this->finfo.uploadtime; - j["finfo"]["lastmodifytime"] = this->finfo.lastmodifytime; - j["id"] = this->id; - j["internalid"] = this->internalid; - j["name"] = this->name; - j["size"] = this->size; - return j.dump(); - } - -//发送这个聊天记录 - MessageSource ForwardMessage::sendTo(Contact *c, JNIEnv *env) { - json temp; - json text; - text["id"] = c->id(); - text["groupid"] = c->groupid(); - text["type"] = c->type(); - text["content"] = sendmsg; - temp["text"] = text.dump(); - temp["botid"] = c->botid(); - std::string re = Config::koperation(Config::Buildforward, temp, env); - //TODO:https://github.com/mamoe/mirai/issues/1371 - return MessageSource::deserializeFromString(re); - } - - ForwardMessage::ForwardMessage(Contact *c, std::initializer_list nodes) { - json root; - json value; - root["type"] = c->type(); - root["id"] = c->id(); - root["id2"] = c->groupid(); - for (const ForwardNode &node : nodes) { - json temp; - temp["id"] = node.id; - temp["time"] = node.time; - temp["message"] = node.message; - temp["name"] = node.name; - value.push_back(temp); - } - root["value"] = value; - sendmsg = root; - } - -/*图片类实现*/ - - std::string Image::queryURL(JNIEnv *env) { - json j; - j["id"] = this->id; - std::string re = Config::koperation(Config::QueryImgUrl, j, env); - if (re == "E1") - throw RemoteAssetException("图片id格式错误"); - return re; - } - - std::string Image::toMiraiCode() const { - return "[mirai:image:" + Tools::escapeToMiraiCode(this->id) + "]"; - } - - MessageSource MessageSource::quoteAndSendMiraiCode(const std::string &content, QQID groupid, JNIEnv *env) const { - json obj; - json sign; - obj["messageSource"] = this->serializeToString(); - obj["msg"] = content; - sign["MiraiCode"] = true; - sign["groupid"] = groupid; - obj["sign"] = sign.dump(); - std::string re = Config::koperation(Config::SendWithQuote, obj, env); - return MessageSource::deserializeFromString(re); - } - - MessageSource MessageSource::quoteAndSendMsg(const std::string &content, QQID groupid, JNIEnv *env) const { - json obj; - json sign; - obj["messageSource"] = this->serializeToString(); - obj["msg"] = content; - sign["MiraiCode"] = false; - sign["groupid"] = groupid; - obj["sign"] = sign.dump(); - std::string re = Config::koperation(Config::SendWithQuote, obj, env); - return MessageSource::deserializeFromString(re); - } - - MessageSource Contact::sendMsg0(const std::string& msg, int retryTime, bool miraicode, JNIEnv *env) { - if (msg.empty()) { - Logger::logger.warning("警告:发送空信息, 位置: Contact::SendMsg"); - throw IllegalArgumentException("参数不能为空, 位置: Contact::SendMsg"); - } - std::string re = LowLevelAPI::send0(msg, this, retryTime, miraicode, env, "reach a error area, Contact::SendMiraiCode"); - if(re == "ET") - throw TimeOutException("发送消息过于频繁导致的tx服务器未能即使响应, 位置: Contact::SendMsg"); - if(Tools::starts_with(re, "EBM")) - throw BotIsBeingMutedException(std::stoi(re.substr(3))); - return MessageSource::deserializeFromString(re); - } - - Image Contact::uploadImg(const std::string &path, JNIEnv *env) { - std::string re = LowLevelAPI::uploadImg0(path, this, env); - if (re == "E2") - throw UploadException("上传图片大小超过30MB,路径:" + path); - return Image(re); - } - -/*好友类实现*/ - Friend::Friend(QQID id, QQID botid, JNIEnv *env) : Contact() { - this->_type = 1; - this->_id = id; - this->_botid = botid; - refreshInfo(env); - } - -/*成员类实现*/ - Member::Member(QQID id, QQID groupid, QQID botid, JNIEnv *env) - : Contact() { - this->_type = 3; - this->_id = id; - this->_groupid = groupid; - this->_botid = botid; - refreshInfo(env); - } - - unsigned int Member::getPermission(JNIEnv *env) { - if(isAnonymous) return 0; - json j; - j["contactSource"] = this->serializationToString(); - std::string re = Config::koperation(Config::QueryM, j, env); - return stoi(re); - } - - void Member::mute(int time, JNIEnv *env) { - json j; - j["time"] = time; - j["contactSource"] = this->serializationToString(); - std::string re = Config::koperation(Config::MuteM, j, env); - if (re == "E3") { - throw BotException(); - } - if (re == "E4") { - throw MuteException(); - } - } - - void Member::kick(const std::string &reason, JNIEnv *env) { - json j; - j["message"] = reason; - j["contactSource"] = this->serializationToString(); - std::string re = Config::koperation(Config::KickM, j, env); - if (re == "E3") { - throw BotException(); - } - } - - void Member::modifyAdmin(bool admin, JNIEnv* env){ - if(isAnonymous)return; - json j; - j["admin"] = admin; - j["contactSource"] = this->serializationToString(); - std::string re = Config::koperation(Config::ModifyAdmin, j, env); - if(re == "E1"){ - throw BotException(); - } - } - -/*群聊类实现*/ - Group::Group(QQID groupid, QQID botid, JNIEnv *env) : Contact() { - this->_type = 2; - this->_id = groupid; - this->_botid = botid; - refreshInfo(env); - } - - void Group::OnlineAnnouncement::deleteThis(){ - json j, i; - i["botid"] = this->botid; - i["groupid"] = this->groupid; - i["fid"] = this->fid; - i["type"] = 1; - j["identify"] = i.dump(); - std::string re = Config::koperation(Config::Announcement, j); - if(re == "E1") - throw IllegalArgumentException("无法根据fid找到群公告(群公告不存在)"); - if(re == "E2") - throw BotException(); - if(re == "E3") - throw IllegalStateException("群公告状态异常"); - } - - json Group::AnnouncementParams::serializeToJson() { - json j; - j["sendToNewMember"] = this->send2new; - j["isPinned"] = this->pinned; - j["showEditCard"] = this->showEditCard; - j["showPopup"] = this->showPopup; - j["requireConfirmation"] = this->requireConfirm; - return j; - } - - Group::OnlineAnnouncement Group::OfflineAnnouncement::publishTo(const Group& g) { - json j, i, s; - i["botid"] = g.botid(); - i["groupid"] = g.id(); - i["type"] = 2; - j["identify"] = i.dump(); - s["content"] = this->content; - s["params"] = this->params.serializeToJson(); - j["source"] = s.dump(); - std::string re = Config::koperation(Config::Announcement, j); - if(re == "E1") - throw BotException(); - return Group::OnlineAnnouncement::deserializeFromJson(json::parse(re)); - } - - Group::OnlineAnnouncement Group::OnlineAnnouncement::deserializeFromJson(json j) { - Group::AnnouncementParams ap( - j["params"]["sendToNewMember"], - j["params"]["requireConfirmation"], - j["params"]["isPinned"], - j["params"]["showEditCard"], - j["params"]["showPopup"] - ); - return Group::OnlineAnnouncement( - j["content"], - ap, - j["groupid"], - j["senderid"], - j["botid"], - j["time"], - j["fid"], - j["confirmationNum"], - j["imageid"] - ); - } - - void Group::updateSetting(JNIEnv *env) { - json j; - json tmp; - j["name"] = this->setting.name; - j["isMuteAll"] = this->setting.isMuteAll; - j["isAllowMemberInvite"] = this->setting.isAllowMemberInvite; - j["isAutoApproveEnabled"] = this->setting.isAutoApproveEnabled; - j["isAnonymousChatEnabled"] = this->setting.isAnonymousChatEnabled; - tmp["source"] = j.dump(); - tmp["contactSource"] = this->serializationToString(); - std::string re = Config::koperation(Config::GroupSetting, tmp, env); - if (re == "E1") - throw BotException(); - refreshInfo(env); - } - - RemoteFile Group::sendFile(const std::string &path, const std::string &filepath, JNIEnv *env) { - json tmp; - json source; - source["path"] = path; - source["filepath"] = filepath; - tmp["source"] = source.dump(); - tmp["contactSource"] = this->serializationToString(); - std::string callback = Config::koperation(Config::SendFile, tmp, env); - if (callback == "E2") throw UploadException("找不到" + filepath + "位置:C-uploadfile"); - if (callback == "E3") throw UploadException("Upload error:路径格式异常,应为'/xxx.xxx'或'/xx/xxx.xxx'目前只支持群文件和单层路径, path:" + path); - return RemoteFile::deserializeFromString(callback); - } - - RemoteFile Group::getFile(const std::string &path, const std::string &id, JNIEnv *env) { - // source 参数 - json tmp; - json j; - tmp["id"] = id; - tmp["path"] = path; - j["source"] = tmp.dump(); - j["contactSource"] = this->serializationToString(); - std::string re = Config::koperation(Config::RemoteFileInfo, j, env); - if (re == "E2") throw RemoteAssetException("Get error: 文件路径不存在, path:" + path); - return RemoteFile::deserializeFromString(re); - } - - Member Group::getOwner(JNIEnv *env) { - json j; - j["contactSource"] = this->serializationToString(); - std::string re = Config::koperation(Config::QueryOwner, j, env); - return Member(stoi(re), this->id(), this->botid()); - } - - std::string Group::getFileListString(const std::string &path, JNIEnv *env) { - json temp; - json j; - temp["id"] = "-1"; - temp["path"] = path; - j["source"] = temp.dump(); - j["contactSource"] = this->serializationToString(); - return Config::koperation(Config::RemoteFileInfo, j, env); - } - - std::vector Group::getFileList(const std::string &path, JNIEnv *env) { - std::vector re = std::vector(); - std::string tmp = getFileListString(path, env); - json root = json::parse(tmp); - for (auto &i : root) { - file_short_info t; - t.path = i[0]; - t.id = i[1]; - re.push_back(t); - } - return re; - } - - MessageChain PrivateMessageEvent::nextMessage(long time, bool halt, JNIEnv* env) { - json j; - j["contactSource"] = this->sender.serializationToString(); - j["time"] = time; - j["halt"] = halt; - std::string r = Config::koperation(Config::NextMsg, j, env); - if(r == "-1") - throw TimeOutException("取下一条信息超时"); - json re = json::parse(r); - return MessageChain::deserializationFromMiraiCode(re["message"]).plus(MessageSource::deserializeFromString(re["messageSource"])); - } - - MessageChain GroupMessageEvent::nextMessage(long time, bool halt, JNIEnv *env) { - json j; - j["contactSource"] = this->group.serializationToString(); - j["time"] = time; - j["halt"] = halt; - std::string r = Config::koperation(Config::NextMsg, j, env); - if(r == "-1") - throw TimeOutException("取下一条信息超时"); - json re = json::parse(r); - return MessageChain::deserializationFromMiraiCode(re["message"]).plus(MessageSource::deserializeFromString(re["messageSource"])); - } - - MessageChain GroupMessageEvent::senderNextMessage(long time, bool halt, JNIEnv *env) { - json j; - j["contactSource"] = this->sender.serializationToString(); - j["time"] = time; - j["halt"] = halt; - std::string r = Config::koperation(Config::NextMsg, j, env); - if(r == "-1") - throw TimeOutException("取下一条信息超时"); - json re = json::parse(r); - return MessageChain::deserializationFromMiraiCode(re["message"]).plus(MessageSource::deserializeFromString(re["messageSource"])); - } - -/*工具类实现*/ - std::string Tools::jstring2str(jstring jStr, JNIEnv *env) { - if (!jStr) { - Logger::logger.error("警告:kotlin部分返回空字符串, 位置:Tools::jstring2str"); - return ""; - } - std::u16string s = reinterpret_cast(env->GetStringChars(jStr, nullptr)); - if (s.length() == 0) { - Logger::logger.error("警告:kotlin部分返回空字符串, 位置:Tools::jstring2str"); - return ""; - } - std::string x; - utf8::utf16to8(s.begin(), s.end(), std::back_inserter(x)); - return x; - } - - jstring Tools::str2jstring(const char *stra, JNIEnv *env) { - if (!stra) { - Logger::logger.error("警告:C++部分传入空字符串,位置:Tools::str2jstring"); - } - std::string str(stra); - std::vector utf16line; - utf8::utf8to16(str.begin(), str.end(), std::back_inserter(utf16line)); - auto *c = new jchar[utf16line.size()]; - for (int i = 0; i < utf16line.size(); i++) { - c[i] = utf16line[i]; - } - return env->NewString((jchar *) c, (jsize) utf16line.size()); - } - - template - std::string Tools::VectorToString(std::vector a, const std::string& separator) { - std::stringstream ss; - for (size_t i = 0; i < a.size(); ++i) { - if (i != 0) - ss << separator; - ss << a[i]; - } - std::string s = ss.str(); - return s; - } - - std::vector Tools::StringToVector(std::string temp) { - std::vector result; - temp.erase(temp.begin()); - temp.pop_back(); - std::regex ws_re("[,]+"); - std::vector v(std::sregex_token_iterator(temp.begin(), temp.end(), ws_re, -1), - std::sregex_token_iterator()); - result.reserve(v.size()); - for (auto &&s : v) - result.push_back(std::stoull(s)); - return result; - } - - std::string Tools::escapeFromMiraiCode(const std::string &s) { - //[ \[ - //] \] - //: \: - //, \, - //\ \\ / - return Tools::replace( - Tools::replace( - Tools::replace( - Tools::replace( - Tools::replace(s, - "\\\\", "\\"), - "\\,", ","), - "\\:", ":"), - "\\]", "]"), "\\[", "["); - } - - std::string Tools::escapeToMiraiCode(const std::string &s) { - //[ \[ - //] \] - //: \: - //, \, - //\ \\ / - return Tools::replace(Tools::replace(Tools::replace(Tools::replace(Tools::replace(s, - "\\", "\\\\"), - ",", "\\,"), - ":", "\\:"), - "]", "\\]"), "[", "\\["); - } - - Contact Contact::deserializationFromString(const std::string &source) { - json j; - try { - j = json::parse(source); - } - catch (json::parse_error &e) { - Logger::logger.error("json序列化错误 Contact::deserializationFromString"); - Logger::logger.error(source); - Logger::logger.error(e.what()); - } - return Contact::deserializationFromJson(j); - } - - Contact Contact::deserializationFromJson(nlohmann::json j) { - return Contact(j["type"], - j["id"], - j["groupid"], - j["nickornamecard"], - j["botid"], - j["anonymous"]); - } - - MessageSource Contact::sendVoice0(const std::string &path, JNIEnv *env) { - json j; - json source; - source["path"] = path; - j["source"] = source.dump(); - j["contactSource"] = this->serializationToString(); - std::string re = Config::koperation(Config::Voice, j, env); - if (re == "E1") - throw UploadException("上传语音文件格式不对(必须为.amr/.silk)或文件不存在"); - else if(re == "E2") - throw UploadException("上传语音文件大小超过服务器限制,一般限制在1MB上下"); - return MessageSource::deserializeFromString(re); - } - void enrollPlugin(); - void enrollPlugin0(CPPPlugin *p) { - plugin = p; - } - - json PluginConfig::serialize() { - json j; - j["name"] = name; - j["version"] = version; - j["author"] = author; - j["description"] = description; - j["time"] = time; - j["id"] = id; - return j; + inline void enrollPlugin0(CPPPlugin *p) { + CPPPlugin::plugin = p; } - // 结束MiraiCP实现代码 -} -//开始对接JNI接口代码 -/* -* 名称:Java_com_example_plugin_CPP_1lib_Verify -* 作用:判断是否连接上本插件,勿改 -* 参数:env 必备,job 必备 -* 返回值:jstring (用str2jstring把string类型转成jsrting) 发送返回的字符串 -*/ -jstring Verify(JNIEnv *env, jobject) { - using namespace MiraiCP; - ThreadManager::setEnv(env); - env->GetJavaVM(&gvm); - JNIVersion = (int) env->GetVersion(); - try { - //初始化日志模块 - Config::construct(); - Logger::logger.init(); - enrollPlugin(); - if (plugin == nullptr) { - Logger::logger.error("无插件实例加载"); - } else { - CPPPlugin::pluginLogger = new PluginLogger(&Logger::logger); - plugin->onEnable(); - } - } - catch (MiraiCPException &e) { - e.raise(); - } - json j = plugin->config.serialize(); - j["MiraiCPversion"] = MiraiCPVersion; - return Tools::str2jstring(j.dump().c_str());//验证机制,返回当前SDK版本 -} -/* 插件结束事件*/ -jobject PluginDisable(JNIEnv *env, jobject job) { - using namespace MiraiCP; - ThreadManager::setEnv(env); - plugin->onDisable(); - plugin = nullptr; - return job; -} -/*返回空值*/ -jstring returnNull() { - return MiraiCP::Tools::str2jstring("MIRAICP_NULL"); -} -/* -* 消息解析分流 -*/ -jstring Event(JNIEnv *env, jobject, jstring content) { - using namespace MiraiCP; - ThreadManager::setEnv(env); - std::string tmp = Tools::jstring2str(content, env); - json j; - try { - j = json::parse(tmp); - } - catch (json::parse_error &e) { - APIException("格式化json错误").raise(); - Logger::logger.error("For debug:" + j.dump()); - Logger::logger.error(e.what(), false); - return returnNull(); - } - ThreadManager::getThread()->stack.push(__FILE__, __LINE__, "source: " + tmp); - try { - switch ((int) j["type"]) { - case 1: { - //GroupMessage - Event::processor.broadcast( - GroupMessageEvent(j["group"]["botid"], - Group(Group::deserializationFromJson(j["group"])), - Member(Member::deserializationFromJson(j["member"])), - MessageChain::deserializationFromMiraiCode(j["message"].get()) - .plus(MessageSource::deserializeFromString(j["source"])) - ) - ); - break; - } - case 2: { - //私聊消息 - Event::processor.broadcast( - PrivateMessageEvent(j["friend"]["botid"], - Friend(Friend::deserializationFromJson(j["friend"])), - MessageChain::deserializationFromMiraiCode(j["message"]) - .plus(MessageSource::deserializeFromString(j["source"])) - )); - break; - } - case 3: - //群聊邀请 - Event::processor.broadcast( - GroupInviteEvent( - j["source"]["botid"], - j["request"], - j["source"]["inviternick"], - j["source"]["inviterid"], - j["source"]["groupname"], - j["source"]["groupid"] - )); - break; - case 4: - //好友 - Event::processor.broadcast( - NewFriendRequestEvent( - j["source"]["botid"], - j["request"], - j["source"]["fromid"], - j["source"]["fromgroupid"], - j["source"]["fromnick"], - j["source"]["message"] - )); - break; - case 5: - //新成员加入 - Event::processor.broadcast( - MemberJoinEvent( - j["group"]["botid"], - j["jointype"], - Member(Member::deserializationFromJson(j["member"])), - Group(Group::deserializationFromJson(j["group"])), - j["inviterid"] - )); - break; - case 6: - //群成员退出 - Event::processor.broadcast(MemberLeaveEvent( - j["group"]["botid"], - j["leavetype"], - j["memberid"], - Group(Group::deserializationFromJson(j["group"])), - j["operatorid"] - )); - break; - case 7: - Event::processor.broadcast(RecallEvent( - j["botid"], - j["etype"], - j["time"], - j["authorid"], - j["operatorid"], - j["ids"], - j["internalids"], - j["groupid"] - )); - break; - case 9: - Event::processor.broadcast(BotJoinGroupEvent( - j["group"]["botid"], - j["etype"], - Group(Group::deserializationFromJson(j["group"])), - j["inviterid"] - )); - break; - case 10: - Event::processor.broadcast(GroupTempMessageEvent( - j["group"]["botid"], - Group(Group::deserializationFromJson(j["group"])), - Member(Member::deserializationFromJson(j["member"])), - MessageChain::deserializationFromMiraiCode(j["message"]) - .plus(MessageSource::deserializeFromString(j["source"])) - )); - break; - case 11: - Event::processor.broadcast(BotOnlineEvent(j["botid"])); - break; - case 12: - Event::processor.broadcast(TimeOutEvent(j["msg"])); - break; - case 13: - Event::processor.broadcast(NudgeEvent(Contact::deserializationFromJson(j["from"]),Contact::deserializationFromJson(j["target"]), j["botid"])); - break; - case 14: - Event::processor.broadcast(BotLeaveEvent(j["groupid"], j["botid"])); - break; - case 15: { - std::optional a; - std::optional b; - Contact temp = Contact::deserializationFromJson(j["group"]); - if(temp.id() == 0) - a = std::nullopt; - else - a = Group(temp); - temp = Contact::deserializationFromJson(j["inviter"]); - if(temp.id() == 0) - b = std::nullopt; - else - b = Member(temp); - Event::processor.broadcast(MemberJoinRequestEvent(a, b, temp.botid(), j["requestData"])); - break; - } - default: - throw APIException("Unreachable code"); - } - } - catch (json::type_error &e) { - Logger::logger.error("json格式化异常,位置C-Handle"); - Logger::logger.error(e.what(), false); - return Tools::str2jstring("ERROR"); - } catch (MiraiCPException &e) { - Logger::logger.error("MiraiCP error:" + e.what()); - return Tools::str2jstring("ERROR"); - } - return returnNull(); -} - -static int registerMethods(JNIEnv *env, const char *className, - JNINativeMethod *gMethods, int numMethods) { - jclass clazz = env->FindClass(className); - if (clazz == nullptr) { - return JNI_FALSE; - } - //注册native方法 - if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { - return JNI_FALSE; - } - return JNI_TRUE; -} - -static JNINativeMethod method_table[] = { - {(char*)"Verify", (char*)"()Ljava/lang/String;", (jstring*)Verify }, - {(char*)"Event", (char*)"(Ljava/lang/String;)Ljava/lang/String;", (jstring *) Event}, - {(char*)"PluginDisable", (char*)"()Ljava/lang/Void;", (jobject*) PluginDisable} - }; - -extern "C" -JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv *env = nullptr; - if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { - return JNI_ERR; - } - assert(env != nullptr); - - // 注册native方法 - if (!registerMethods(env, "tech/eritquearcus/miraicp/shared/CPP_lib", method_table, 3)) { - return JNI_ERR; - } - - return JNI_VERSION_1_6; +// 结束MiraiCP类声明代码 } - -//结束对接JNI接口代码 -#endif +#endif //CPP_MIRAICP_HPP #pragma clang diagnostic pop diff --git a/cpp/include/test/test2.cpp b/cpp/include/test/test2.cpp new file mode 100644 index 000000000..b04e12bee --- /dev/null +++ b/cpp/include/test/test2.cpp @@ -0,0 +1,21 @@ +// Copyright (C) 2020-2021 Eritque arcus and contributors. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or any later version(in your opinion). +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// + +#include + +void useless() { + MiraiCP::Logger::logger.info("x"); +}