Lucas-Bot/single_include/MiraiCP/MiraiCP.cpp

1608 lines
68 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// This file is generated automatically by buildScript;
// When contributing to this repository, please DO NOT edit this file.
// Copyright (c) 2020 - 2022. 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 <http://www.gnu.org/licenses/>.
//
#include <MiraiCP.hpp>
//from include/Bot.cpp
namespace MiraiCP {
Group Bot::getGroup(QQID groupid) const {
return {groupid, this->id};
}
Friend Bot::getFriend(QQID i) const {
return Friend(i, this->id);
}
bool Bot::operator==(const Contact &c) const {
return this->id == c.id();
}
void Bot::refreshInfo() {
if (this->id == 0)
return;
nlohmann::json j;
j["source"] = Contact(4, 0, 0, "", this->id).toString();
LowLevelAPI::info tmp = LowLevelAPI::info0(KtOperation::ktOperation(KtOperation::RefreshInfo, j));
this->_avatarUrl = tmp.avatarUrl;
this->_nick = tmp.nickornamecard;
}
std::vector<QQID> Bot::getFriendList() const {
nlohmann::json j;
j["botid"] = this->id;
std::string temp = KtOperation::ktOperation(KtOperation::QueryBFL, j);
return Tools::StringToVector(std::move(temp));
}
std::string Bot::FriendListToString() {
return Tools::VectorToString(getFriendList());
}
std::vector<QQID> Bot::getGroupList() const {
nlohmann::json j;
j["botid"] = this->id;
std::string temp = KtOperation::ktOperation(KtOperation::QueryBGL, j);
return Tools::StringToVector(std::move(temp));
}
std::string Bot::GroupListToString() const {
return Tools::VectorToString(getGroupList());
}
} // namespace MiraiCP
//from include/CPPPlugin.cpp
namespace MiraiCP {
// 静态区代码一般不会使用logger虽是ub但应该不会造成影响
// 静态区强行调用的话因为loggerInterface尚未传入若logger尚未初始化访问Logger::logger将是ub
// 可以考虑把logger做成纯静态实现以及最好做成 Logger * const
Logger *CPPPlugin::pluginLogger = &Logger::logger;
std::unique_ptr<CPPPlugin> CPPPlugin::plugin = nullptr;
} // namespace MiraiCP
//from include/Command.cpp
namespace MiraiCP {
CommandManager CommandManager::commandManager = CommandManager();
}
//from include/Contact.cpp
namespace MiraiCP {
using json = nlohmann::json;
MessageSource Contact::sendMsg0(const std::string &msg, int retryTime, bool miraicode) const {
if (msg.empty()) {
throw IllegalArgumentException("不能发送空信息, 位置: Contact::SendMsg", MIRAICP_EXCEPTION_WHERE);
}
std::string re = LowLevelAPI::send0(msg, this->toJson(), retryTime, miraicode, "reach a error area, Contact::SendMiraiCode");
ErrorHandle(re, "");
return MessageSource::deserializeFromString(re);
}
MessageSource Contact::quoteAndSend0(const std::string &msg, MessageSource ms) {
json obj;
json sign;
obj["messageSource"] = ms.serializeToString();
obj["msg"] = msg;
sign["MiraiCode"] = true;
sign["groupid"] = this->groupid();
obj["sign"] = sign.dump();
std::string re = KtOperation::ktOperation(KtOperation::SendWithQuote, obj);
ErrorHandle(re, "");
return MessageSource::deserializeFromString(re);
}
Image Contact::uploadImg(const std::string &path) const {
std::string re = LowLevelAPI::uploadImg0(path, this->toString());
if (re == "E2")
throw UploadException("上传图片大小超过30MB,路径:" + path, MIRAICP_EXCEPTION_WHERE);
return Image::deserialize(re);
}
FlashImage Contact::uploadFlashImg(const std::string &path) const {
std::string re = LowLevelAPI::uploadImg0(path, this->toString());
if (re == "E2")
throw UploadException("上传图片大小超过30MB,路径:" + path, MIRAICP_EXCEPTION_WHERE);
return FlashImage::deserialize(re);
}
Contact Contact::deserialize(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::deserialize(j);
}
Contact Contact::deserialize(nlohmann::json j) {
return Contact(j["type"],
j["id"],
j["groupid"],
j["nickornamecard"],
j["botid"],
j["anonymous"]);
}
MessageSource Contact::sendVoice0(const std::string &path) {
json j;
json source;
source["path"] = path;
j["source"] = source.dump();
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::Voice, j);
if (re == "E1") {
throw UploadException("上传语音文件格式不对(必须为.amr/.silk)", MIRAICP_EXCEPTION_WHERE);
} else if (re == "E2") {
throw UploadException("上传语音文件大小超过服务器限制一般限制在1MB上下", MIRAICP_EXCEPTION_WHERE);
}
return MessageSource::deserializeFromString(re);
}
} // namespace MiraiCP
//from include/Event.cpp
namespace MiraiCP {
using json = nlohmann::json;
Event Event::processor;
void GroupInviteEvent::operation0(const std::string &source, QQID botid, bool accept) {
nlohmann::json j;
j["text"] = source;
j["accept"] = accept;
j["botid"] = botid;
std::string re = KtOperation::ktOperation(KtOperation::Gioperation, j);
if (re == "E") Logger::logger.error("群聊邀请事件同意失败(可能因为重复处理),id:" + source);
}
MessageChain PrivateMessageEvent::nextMessage(long time, bool halt) const {
json j;
j["contactSource"] = this->sender.toString();
j["time"] = time;
j["halt"] = halt;
std::string r = KtOperation::ktOperation(KtOperation::NextMsg, j);
if (r == "E1")
throw TimeOutException("取下一条信息超时", MIRAICP_EXCEPTION_WHERE);
json re = json::parse(r);
return MessageChain::deserializationFromMessageSourceJson(json::parse(re["messageSource"].get<std::string>())).plus(MessageSource::deserializeFromString(re["messageSource"]));
}
MessageChain GroupMessageEvent::nextMessage(long time, bool halt) const {
json j;
j["contactSource"] = this->group.toString();
j["time"] = time;
j["halt"] = halt;
std::string r = KtOperation::ktOperation(KtOperation::NextMsg, j);
if (r == "E1")
throw TimeOutException("取下一条信息超时", MIRAICP_EXCEPTION_WHERE);
json re = json::parse(r);
return MessageChain::deserializationFromMessageSourceJson(json::parse(re["messageSource"].get<std::string>())).plus(MessageSource::deserializeFromString(re["messageSource"]));
}
MessageChain GroupMessageEvent::senderNextMessage(long time, bool halt) const {
json j;
j["contactSource"] = this->sender.toString();
j["time"] = time;
j["halt"] = halt;
std::string r = KtOperation::ktOperation(KtOperation::NextMsg, j);
if (r == "E1")
throw TimeOutException("取下一条信息超时", MIRAICP_EXCEPTION_WHERE);
json re = json::parse(r);
return MessageChain::deserializationFromMessageSourceJson(json::parse(re["messageSource"].get<std::string>())).plus(MessageSource::deserializeFromString(re["messageSource"]));
}
void NewFriendRequestEvent::operation0(const std::string &source, QQID botid, bool accept, bool ban) {
nlohmann::json j;
j["text"] = source;
j["accept"] = accept;
j["botid"] = botid;
j["ban"] = ban;
std::string re = KtOperation::ktOperation(KtOperation::Nfroperation, j);
if (re == "E") Logger::logger.error("好友申请事件同意失败(可能因为重复处理),id:" + source);
}
void MemberJoinRequestEvent::operate(std::string_view s, QQID botid, bool sign, const std::string &msg) {
nlohmann::json j;
j["source"] = s;
j["botid"] = botid;
j["sign"] = sign;
j["msg"] = msg;
KtOperation::ktOperation(KtOperation::MemberJoinRequest, j);
}
void Event::incomingEvent(json j, int type) {
switch (type) {
case eventTypes::GroupMessageEvent: {
//GroupMessage
Event::broadcast<GroupMessageEvent>(
GroupMessageEvent(j["group"]["botid"],
Group(Group::deserialize(j["group"])),
Member(Member::deserialize(j["member"])),
MessageChain::deserializationFromMessageSourceJson(json::parse(j["source"].get<std::string>()))
.plus(MessageSource::deserializeFromString(j["source"].get<std::string>()))));
break;
}
case eventTypes::PrivateMessageEvent: {
//私聊消息
Event::broadcast<PrivateMessageEvent>(
PrivateMessageEvent(j["friend"]["botid"],
Friend(Friend::deserialize(j["friend"])),
MessageChain::deserializationFromMessageSourceJson(json::parse(j["source"].get<std::string>()))
.plus(MessageSource::deserializeFromString(j["source"].get<std::string>()))));
break;
}
case eventTypes::GroupInviteEvent:
//群聊邀请
Event::broadcast<GroupInviteEvent>(
GroupInviteEvent(
j["source"]["botid"],
j["request"],
j["source"]["inviternick"],
j["source"]["inviterid"],
j["source"]["groupname"],
j["source"]["groupid"]));
break;
case eventTypes::NewFriendRequestEvent:
//好友
Event::broadcast<NewFriendRequestEvent>(
NewFriendRequestEvent(
j["source"]["botid"],
j["request"],
j["source"]["fromid"],
j["source"]["fromgroupid"],
j["source"]["fromnick"],
j["source"]["message"]));
break;
case eventTypes::MemberJoinEvent:
//新成员加入
Event::broadcast<MemberJoinEvent>(
MemberJoinEvent(
j["group"]["botid"],
j["jointype"],
Member(Member::deserialize(j["member"])),
Group(Group::deserialize(j["group"])),
j["inviterid"]));
break;
case eventTypes::MemberLeaveEvent:
//群成员退出
Event::broadcast<MemberLeaveEvent>(MemberLeaveEvent(
j["group"]["botid"],
j["leavetype"],
j["memberid"],
Group(Group::deserialize(j["group"])),
j["operatorid"]));
break;
case eventTypes::RecallEvent:
Event::broadcast<RecallEvent>(RecallEvent(
j["botid"],
j["etype"],
j["time"],
j["authorid"],
j["operatorid"],
j["ids"],
j["internalids"],
j["groupid"]));
break;
case eventTypes::BotJoinGroupEvent:
Event::broadcast<BotJoinGroupEvent>(BotJoinGroupEvent(
j["group"]["botid"],
j["etype"],
Group(Group::deserialize(j["group"])),
j["inviterid"]));
break;
case eventTypes::GroupTempMessageEvent:
Event::broadcast<GroupTempMessageEvent>(GroupTempMessageEvent(
j["group"]["botid"],
Group(Group::deserialize(j["group"])),
Member(Member::deserialize(j["member"])),
MessageChain::deserializationFromMessageSourceJson(json::parse(j["message"].get<std::string>()))
.plus(MessageSource::deserializeFromString(j["source"]))));
break;
case eventTypes::TimeOutEvent:
Event::broadcast(TimeOutEvent(j["msg"]));
break;
case eventTypes::BotOnlineEvent:
Event::broadcast(BotOnlineEvent(j["botid"]));
break;
case eventTypes::NudgeEvent:
Event::broadcast(NudgeEvent(Contact::deserialize(j["from"]),
Contact::deserialize(j["target"]),
Contact::deserialize(j["subject"]),
j["botid"]));
break;
case eventTypes::BotLeaveEvent:
Event::broadcast(BotLeaveEvent(j["groupid"], j["botid"]));
break;
case eventTypes::MemberJoinRequestEvent: {
std::optional<Group> a;
std::optional<Member> b;
Contact temp = Contact::deserialize(j["group"]);
if (temp.id() == 0)
a = std::nullopt;
else
a = Group(temp);
temp = Contact::deserialize(j["inviter"]);
if (temp.id() == 0)
b = std::nullopt;
else
b = Member(temp);
Event::broadcast(MemberJoinRequestEvent(a, b, temp.botid(), j["requester"], j["requestData"]));
break;
}
case eventTypes::MessagePreSendEvent: {
Event::broadcast(MessagePreSendEvent(Contact::deserialize(j["target"]), MessageChain::deserializationFromMessageSourceJson(j["message"].get<std::string>(), false), j["botid"]));
break;
}
case eventTypes::Command: {
// command
std::optional<Contact> c = std::nullopt;
if (j.contains("contact")) c = Contact::deserialize(j["contact"]);
CommandManager::commandManager[j["bindId"]]->onCommand(c, Bot(j["botid"]), MessageChain::deserializationFromMessageSourceJson((j.contains("message") ? j["message"].get<std::string>() : ""), false));
break;
}
default:
throw APIException("Unreachable code", MIRAICP_EXCEPTION_WHERE);
}
}
} // namespace MiraiCP
//from include/Exception.cpp
namespace MiraiCP {
void MiraiCPExceptionBase::basicRaise() const {
Logger::logger.error(this->what());
}
void MiraiCPExceptionBase::raise() const {
this->basicRaise();
if (!filename.empty() && lineNum != 0) {
Logger::logger.error("文件名:" + filename + "\n行号:" + std::to_string(lineNum));
}
}
} // namespace MiraiCP
//from include/ForwardedMessage.cpp
#include <utility>
namespace MiraiCP {
using json = nlohmann::json;
json ForwardedMessage::nodesToJson() {
json value;
for (const ForwardedNode &node: nodes) {
json temp;
temp["id"] = node.id;
temp["time"] = node.time;
if (node.isForwarded()) {
temp["isForwardedMessage"] = true;
temp["message"] = std::get<std::shared_ptr<ForwardedMessage>>(node.message)->nodesToJson().dump();
if (display.has_value())
temp["display"] = display->toJson();
} else
temp["message"] = std::get<MessageChain>(node.message).toMiraiCode();
temp["name"] = node.name;
value.emplace_back(std::move(temp));
}
json tmp = this->sendmsg;
tmp["value"] = std::move(value);
return tmp;
}
//发送这个聊天记录
MessageSource ForwardedMessage::sendTo(Contact *c) {
json temp;
json text;
text["id"] = c->id();
text["groupid"] = c->groupid();
text["type"] = c->type();
text["content"] = this->nodesToJson();
temp["text"] = text.dump();
temp["botid"] = c->botid();
if (display.has_value())
temp["display"] = display->toJson();
std::string re = KtOperation::ktOperation(KtOperation::Buildforward, temp);
ErrorHandle(re, "");
return MessageSource::deserializeFromString(re);
}
ForwardedMessage ForwardedMessage::deserializationFromMessageSourceJson(const json &j) {
std::vector<ForwardedNode> nodes;
try {
for (auto &&a: j) {
if (a["messageChain"][0].contains("kind") && a["messageChain"][0]["kind"] == "FORWARD") {
nodes.emplace_back(a["senderId"], a["senderName"], ForwardedMessage::deserializationFromMessageSourceJson(a["messageChain"][1]["nodeList"]), a["time"], ForwardedMessageDisplayStrategy::defaultStrategy());
} else {
nodes.emplace_back(a["senderId"], a["senderName"], MessageChain::deserializationFromMessageSourceJson(a["messageChain"], false), a["time"]);
}
}
} catch (json::exception &e) {
throw APIException("ForwardedMessage格式化异常", MIRAICP_EXCEPTION_WHERE);
}
return {std::move(nodes), ForwardedMessageDisplayStrategy::defaultStrategy()};
}
OnlineForwardedMessage OnlineForwardedMessage::deserializationFromMessageSourceJson(const json &j) {
std::vector<ForwardedNode> nodes;
try {
for (auto &&a: j[1]["nodeList"]) {
if (a["messageChain"][0].contains("kind") && a["messageChain"][0]["kind"] == "FORWARD") {
nodes.emplace_back(a["senderId"], a["senderName"], ForwardedMessage::deserializationFromMessageSourceJson(a["messageChain"][1]["nodeList"]), a["time"], ForwardedMessageDisplayStrategy::defaultStrategy());
} else {
nodes.emplace_back(a["senderId"], a["senderName"], MessageChain::deserializationFromMessageSourceJson(a["messageChain"], false), a["time"]);
}
}
} catch (json::parse_error &e) {
throw APIException("OnlineForwardedMessage格式化异常", MIRAICP_EXCEPTION_WHERE);
}
//if (j[0].contains("resourceId") && !j[0]["resourceId"].is_null())
return OnlineForwardedMessage(j[0]["origin"], /*j[0]["resourceId"],*/ std::move(nodes));
//else
// return OnlineForwardedMessage(j[0]["origin"], std::nullopt, std::move(nodes));
}
ForwardedNode::ForwardedNode(QQID id, std::string name, ForwardedMessage _message, int t, std::optional<ForwardedMessageDisplayStrategy> display)
: id(id), name(std::move(name)),
message(std::make_shared<ForwardedMessage>(std::move(_message))),
time(t), isForwardedMessage(true), display(std::move(display)) {}
/*
ForwardedNode::ForwardedNode(Contact *c, MessageChain message, int t) : id(c->id()), name(c->nickOrNameCard()),
message(std::move(message)),
time(t) {}
ForwardedNode::ForwardedNode(QQID id, std::string name, ForwardedMessage &message, int t) : id(id), name(std::move(name)), forwardedMsg(&message), time(t) {}
*/
bool OnlineForwardedMessage::operator==(const OnlineForwardedMessage &m) const {
if (this->nodelist.size() != m.nodelist.size())
return false;
int i = 0;
return std::all_of(this->nodelist.begin(), this->nodelist.end(), [&](const auto &n) {
return n.message == m[i++].message;
});
// for (int i = 0; i < this->nodelist.size(); i++)
// if (this->nodelist[i].message != m[i].message)
// return false;
// return true;
}
ForwardedMessage OnlineForwardedMessage::toForwardedMessage(std::optional<ForwardedMessageDisplayStrategy> display) const {
return {this->nodelist, std::move(display)};
}
} // namespace MiraiCP
//from include/Friend.cpp
namespace MiraiCP {
using json = nlohmann::json;
/*好友类实现*/
Friend::Friend(QQID id, QQID botid) : Contact() {
this->_type = MIRAI_FRIEND;
this->_id = id;
this->_botid = botid;
refreshInfo();
}
void Friend::deleteFriend() {
json j;
j["source"] = this->toString();
j["quit"] = true;
KtOperation::ktOperation(KtOperation::RefreshInfo, j);
}
void Friend::refreshInfo() {
std::string temp = LowLevelAPI::getInfoSource(this->toString());
if (temp == "E1") {
throw FriendException(MIRAICP_EXCEPTION_WHERE);
}
LowLevelAPI::info tmp = LowLevelAPI::info0(temp);
this->_nickOrNameCard = tmp.nickornamecard;
this->_avatarUrl = tmp.avatarUrl;
}
void Friend::sendNudge() {
json j;
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::SendNudge, j);
if (re == "E1")
throw IllegalStateException("发送戳一戳失败登录协议不为phone/ipad", MIRAICP_EXCEPTION_WHERE);
}
} // namespace MiraiCP
//from include/Group.cpp
namespace MiraiCP {
using json = nlohmann::json;
std::string Group::MemberListToString() {
return Tools::VectorToString(getMemberList());
}
std::vector<Group::OnlineAnnouncement> Group::getAnnouncementsList() {
json j;
j["source"] = this->toString();
j["announcement"] = true;
std::string re = KtOperation::ktOperation(KtOperation::RefreshInfo, j);
std::vector<OnlineAnnouncement> oa;
for (const json &e: json::parse(re)) {
oa.push_back(Group::OnlineAnnouncement::deserializeFromJson(e));
}
return oa;
}
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 = KtOperation::ktOperation(KtOperation::Announcement, j);
if (re == "E1")
throw IllegalArgumentException("无法根据fid找到群公告(群公告不存在)", MIRAICP_EXCEPTION_WHERE);
if (re == "E3")
throw IllegalStateException("群公告状态异常", MIRAICP_EXCEPTION_WHERE);
}
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 = KtOperation::ktOperation(KtOperation::Announcement, j);
return Group::OnlineAnnouncement::deserializeFromJson(json::parse(re));
}
Group::OnlineAnnouncement Group::OnlineAnnouncement::deserializeFromJson(const 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"]);
}
std::vector<unsigned long long> Group::getMemberList() {
nlohmann::json j;
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::QueryML, j);
if (re == "E1") {
throw GroupException(MIRAICP_EXCEPTION_WHERE);
}
return Tools::StringToVector(std::move(re));
}
Group::Group(QQID groupid, QQID botid) : Contact() {
this->_type = MIRAI_GROUP;
this->_id = groupid;
this->_botid = botid;
refreshInfo();
}
void Group::quit() {
nlohmann::json j;
j["source"] = this->toString();
j["quit"] = true;
KtOperation::ktOperation(KtOperation::RefreshInfo, j);
}
void Group::refreshInfo() {
std::string re = LowLevelAPI::getInfoSource(this->toString());
LowLevelAPI::info tmp = LowLevelAPI::info0(re);
this->_nickOrNameCard = std::move(tmp.nickornamecard);
this->_avatarUrl = std::move(tmp.avatarUrl);
nlohmann::json j = nlohmann::json::parse(re)["setting"];
this->setting.name = j["name"];
this->setting.isMuteAll = j["isMuteAll"];
this->setting.isAllowMemberInvite = j["isAllowMemberInvite"];
this->setting.isAutoApproveEnabled = j["isAutoApproveEnabled"];
this->setting.isAnonymousChatEnabled = j["isAnonymousChatEnabled"];
}
void Group::updateSetting() {
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->toString();
std::string re = KtOperation::ktOperation(KtOperation::GroupSetting, tmp);
refreshInfo();
}
RemoteFile Group::sendFile(const std::string &path, const std::string &filepath) {
json tmp;
json source;
source["path"] = path;
source["filepath"] = filepath;
tmp["source"] = source.dump();
tmp["contactSource"] = this->toString();
std::string callback = KtOperation::ktOperation(KtOperation::SendFile, tmp);
if (callback == "E2") throw UploadException("找不到" + filepath + "位置:C-uploadfile", MIRAICP_EXCEPTION_WHERE);
if (callback == "E3")
throw UploadException("Upload error:路径格式异常,应为'/xxx.xxx'或'/xx/xxx.xxx'目前只支持群文件和单层路径, path:" + path, MIRAICP_EXCEPTION_WHERE);
return RemoteFile::deserializeFromString(callback);
}
RemoteFile Group::getFile(const std::string &path, const std::string &id) {
// source 参数
if (path.empty() || path == "/")
return this->getFileById(id);
json tmp;
json j;
tmp["id"] = id;
tmp["path"] = path;
j["source"] = tmp.dump();
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::RemoteFileInfo, j);
if (re == "E2") throw RemoteAssetException("Get error: 文件路径不存在, path:" + path + ",id:" + id, MIRAICP_EXCEPTION_WHERE);
return RemoteFile::deserializeFromString(re);
}
RemoteFile Group::getFileById(const std::string &id) {
json tmp;
json j;
tmp["id"] = id;
j["source"] = tmp.dump();
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::RemoteFileInfo, j);
if (re == "E1") throw RemoteAssetException("Get error: 文件路径不存在, id:" + id, MIRAICP_EXCEPTION_WHERE);
return RemoteFile::deserializeFromString(re);
}
Member Group::getOwner() {
json j;
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::QueryOwner, j);
return Member(stoi(re), this->id(), this->botid());
}
std::string Group::getFileListString(const std::string &path) {
json temp;
json j;
temp["id"] = "-1";
temp["path"] = path;
j["source"] = temp.dump();
j["contactSource"] = this->toString();
return KtOperation::ktOperation(KtOperation::RemoteFileInfo, j);
}
std::vector<Group::file_short_info> Group::getFileList(const std::string &path) {
std::vector<file_short_info> re = std::vector<file_short_info>();
std::string tmp = getFileListString(path);
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;
}
Member Group::getMember(QQID memberid) {
return Member(memberid, this->id(), this->botid());
}
Member Group::operator[](QQID a) {
return getMember(a);
}
} // namespace MiraiCP
//from include/KtOperation.cpp
namespace MiraiCP::KtOperation {
std::string ktOperation(operation_set type, nlohmann::json data, bool catchErr, const std::string &errorInfo) {
nlohmann::json j;
j["type"] = type;
j["data"] = std::move(data);
auto tmp = j.dump();
std::string re = LibLoader::LoaderApi::pluginOperation(tmp.c_str());
if (catchErr) ErrorHandle(re, errorInfo);
return re;
}
} // namespace MiraiCP::KtOperation
//from include/Logger.cpp
namespace MiraiCP {
Logger Logger::logger;
void Logger::log_interface(const std::string &content, int level) {
LibLoader::LoaderApi::loggerInterface(content.c_str(), ("plugin/" + MiraiCP::CPPPlugin::config.getName()).c_str(), -1, level);
}
void IdLogger::log_interface(const std::string &content, int level) {
LibLoader::LoaderApi::loggerInterface(content.c_str(), "", static_cast<long long>(id), level);
}
} // namespace MiraiCP
//from include/LowLevelAPI.cpp
#include <utility>
namespace MiraiCP {
using json = nlohmann::json;
std::string LowLevelAPI::send0(const std::string &content, json c, int retryTime, bool miraicode,
const std::string &errorInfo) {
nlohmann::json j;
nlohmann::json tmp;
tmp["content"] = content;
tmp["contact"] = std::move(c);
j["source"] = tmp.dump();
j["miraiCode"] = miraicode;
j["retryTime"] = retryTime;
return KtOperation::ktOperation(KtOperation::Send, j, true, errorInfo);
}
LowLevelAPI::info LowLevelAPI::info0(const std::string &source) {
info re;
ErrorHandle(source, "");
nlohmann::json j = nlohmann::json::parse(source);
re.avatarUrl = j["avatarUrl"];
re.nickornamecard = j["nickornamecard"];
return re;
}
std::string LowLevelAPI::getInfoSource(const std::string &c) {
nlohmann::json j;
j["source"] = c;
return KtOperation::ktOperation(KtOperation::RefreshInfo, j);
}
std::string LowLevelAPI::uploadImg0(const std::string &path, const std::string &c) {
nlohmann::json j;
j["fileName"] = path;
j["source"] = c;
return KtOperation::ktOperation(KtOperation::UploadImg, j);
}
} // namespace MiraiCP
//from include/Member.cpp
namespace MiraiCP {
using json = nlohmann::json;
/*成员类实现*/
Member::Member(QQID id, QQID groupid, QQID botid)
: Contact() {
this->_type = MIRAI_MEMBER;
this->_id = id;
this->_groupid = groupid;
this->_botid = botid;
refreshInfo();
}
void Member::refreshInfo() {
if (isAnonymous)
return;
std::string temp = LowLevelAPI::getInfoSource(this->toString());
if (temp == "E1")
throw MemberException(1, MIRAICP_EXCEPTION_WHERE);
if (temp == "E2")
throw MemberException(2, MIRAICP_EXCEPTION_WHERE);
LowLevelAPI::info tmp = LowLevelAPI::info0(temp);
this->_nickOrNameCard = tmp.nickornamecard;
this->_avatarUrl = tmp.avatarUrl;
this->permission = getPermission();
if (temp == "E1") {
throw MemberException(1, MIRAICP_EXCEPTION_WHERE);
}
if (temp == "E2") {
throw MemberException(2, MIRAICP_EXCEPTION_WHERE);
}
}
unsigned int Member::getPermission() const {
if (isAnonymous) return 0;
json j;
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::QueryM, j);
return stoi(re);
}
void Member::mute(int time) {
json j;
j["time"] = time;
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::MuteM, j);
if (re == "E4")
throw MuteException(MIRAICP_EXCEPTION_WHERE);
}
void Member::kick(const std::string &reason) {
json j;
j["message"] = reason;
j["contactSource"] = this->toString();
KtOperation::ktOperation(KtOperation::KickM, j);
}
void Member::modifyAdmin(bool admin) {
if (isAnonymous) return;
json j;
j["admin"] = admin;
j["contactSource"] = this->toString();
KtOperation::ktOperation(KtOperation::ModifyAdmin, j);
refreshInfo();
}
void Member::changeNameCard(std::string_view newName) {
if (isAnonymous) return;
json j;
j["contactSource"] = this->toString();
j["newName"] = newName;
KtOperation::ktOperation(KtOperation::ChangeNameCard, j);
refreshInfo();
}
void Member::sendNudge() {
if (isAnonymous) return;
json j;
j["contactSource"] = this->toString();
std::string re = KtOperation::ktOperation(KtOperation::SendNudge, j);
if (re == "E1")
throw IllegalStateException("发送戳一戳失败登录协议不为phone", MIRAICP_EXCEPTION_WHERE);
}
} // namespace MiraiCP
//from include/MessageChain.cpp
namespace MiraiCP {
using json = nlohmann::json;
std::string MessageChain::toMiraiCode() const {
return Tools::VectorToString(this->toMiraiCodeVector(), "");
}
MessageSource MessageChain::quoteAndSend0(std::string msg, QQID groupid) {
json obj;
json sign;
obj["messageSource"] = this->source->serializeToString();
obj["msg"] = std::move(msg);
sign["MiraiCode"] = true;
sign["groupid"] = groupid;
obj["sign"] = sign.dump();
std::string re = KtOperation::ktOperation(KtOperation::SendWithQuote, obj);
return MessageSource::deserializeFromString(re);
}
//message chain
MessageChain MessageChain::deserializationFromMiraiCode(const std::string &m) {
size_t pos = 0;
size_t lastPos = -1;
MessageChain mc;
if (m.length() <= 7) {
return MessageChain(PlainText(m));
}
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);
if (back == -1) throw IllegalStateException("", MIRAICP_EXCEPTION_WHERE);
std::string tmp = m.substr(pos, back - pos);
tmp = Tools::replace(std::move(tmp), "[mirai:", "");
size_t i = tmp.find(':'); // first :
int t = SingleMessage::getKey(tmp.substr(0, i));
switch (t) {
case 0:
// no miraiCode key is PlainText
Logger::logger.error("无法预料的错误, 信息: " + m);
break;
case 1:
mc.add(At(std::stoll(tmp.substr(i + 1, tmp.length() - i - 1))));
break;
case 2:
mc.add(AtAll());
break;
case 3:
mc.add(Image(tmp.substr(i + 1, tmp.length() - i - 1)));
break;
case 4:
mc.add(LightApp(tmp.substr(i + 1, tmp.length() - i - 1)));
break;
case 5: {
size_t comma = tmp.find(',');
mc.add(ServiceMessage(std::stoi(tmp.substr(i + 1, comma - i - 1)),
tmp.substr(comma + 1, tmp.length() - comma - 1)));
break;
}
case 6: {
//[mirai:file:/b53231e8-46dd-11ec-8ba5-5452007bd6c0,102,run.bat,55]
size_t comma1 = tmp.find(',');
size_t comma2 = tmp.find(',', comma1 + 1);
size_t comma3 = tmp.find(',', comma2 + 1);
mc.add(RemoteFile(tmp.substr(i + 1, comma1 - i - 1), std::stoi(tmp.substr(comma1 + 1, comma2 - comma1 - 1)), tmp.substr(comma2 + 1, comma3 - comma2 - 1), std::stoll(tmp.substr(comma3 + 1, tmp.length() - comma3 - 1))));
break;
}
case 7:
mc.add(Face(std::stoi(tmp.substr(i + 1, tmp.length() - i - 1))));
break;
case 8:
mc.add(FlashImage(tmp.substr(i + 1, tmp.length() - i - 1)));
break;
case 9: {
//[mirai:musicshare:name,title,summary,jUrl,pUrl,mUrl,brief]
auto temp = Tools::split(tmp.substr(i + 1, tmp.length() - i - 1), ",");
mc.add(MusicShare(temp[0], temp[1], temp[2], temp[3], temp[4], temp[5], temp[6]));
break;
}
default:
Logger::logger.error(
"MiraiCP碰到了意料之中的错误(原因:部分SimpleMessage在MiraiCode解析支持之外)\n请到MiraiCP(github.com/Nambers/MiraiCP)发送issue并复制本段信息使MiraiCP可以支持这种消息: MiraiCode:" +
m);
mc.add(UnSupportMessage("[mirai:" + tmp));
break;
}
pos = back;
lastPos = pos;
if (t == 1)
lastPos++;
}
pos++;
} while (pos < m.length());
if (lastPos + 1 < m.length())
mc.add(PlainText(m.substr(lastPos + 1, m.length() - lastPos - 1))); // plain text
return mc;
}
MessageChain MessageChain::deserializationFromMessageSourceJson(const json &tmp, bool origin) {
json j = tmp;
if (origin)
j = tmp["originalMessage"];
MessageChain mc;
if (j.empty()) return mc;
if (j[0]["type"] == "MessageOrigin") {
if (j[0]["kind"] == "MUSIC_SHARE") {
mc.add(MusicShare(j[1]["kind"], j[1]["title"], j[1]["summary"], j[1]["jumpUrl"], j[1]["pictureUrl"], j[1]["musicUrl"], j[1]["brief"]));
return mc;
}
mc.add(OnlineForwardedMessage::deserializationFromMessageSourceJson(j));
return mc;
}
for (auto node: j) {
if (node["type"] == "SimpleServiceMessage") {
mc.add(ServiceMessage(node["serviceId"], node["content"]));
continue;
}
if (node["type"] == "LightApp") {
mc.add(LightApp(node["content"]));
continue;
}
if (node["type"] == "OnlineAudio") {
mc.add(OnlineAudio(node["filename"], node["fileMd5"], node["fileSize"], node["codec"], node["length"],
node["urlForDownload"]));
continue;
}
if (node["type"] == "FileMessage") {
mc.add(Group(tmp["targetId"].get<QQID>(), tmp["botId"].get<QQID>()).getFileById(node["id"]).plus(node["internalId"]));
continue;
}
if (node["type"] == "MarketFace") {
mc.add(MarketFace(node["delegate"]["faceId"]));
break;
}
switch (SingleMessage::getKey(node["type"])) {
case -2:
mc.add(QuoteReply(MessageSource::deserializeFromString(node["source"].dump())));
break;
case 0:
mc.add(PlainText(node["content"].get<std::string>()));
break;
case 1:
mc.add(At(node["target"]));
break;
case 2:
mc.add(AtAll());
break;
case 3:
mc.add(Image(node["imageId"]));
break;
case 7:
mc.add(Face(node["id"]));
break;
case 8:
mc.add(FlashImage(node["imageId"]));
break;
default:
Logger::logger.warning(
"MiraiCP碰到了意料之中的错误(原因:接受到的SimpleMessage在MessageSource解析支持之外)\n请到MiraiCP(github.com/Nambers/MiraiCP)发送issue并复制本段信息使MiraiCP可以支持这种消息: MessageSource:" +
j.dump());
mc.add(UnSupportMessage(node.dump()));
}
}
return mc;
}
} // namespace MiraiCP
//from include/MessageSource.cpp
namespace MiraiCP {
using json = nlohmann::json;
void MessageSource::recall() const {
json j;
j["source"] = this->serializeToString();
std::string re = KtOperation::ktOperation(KtOperation::Recall, j);
if (re == "Y") return;
if (re == "E2") throw RecallException(MIRAICP_EXCEPTION_WHERE);
}
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 IllegalArgumentException(std::string("消息源序列化出错,格式不符合(MessageSource::deserializeFromString), ") + e.what(), MIRAICP_EXCEPTION_WHERE);
}
}
} // namespace MiraiCP
//from include/MiraiCode.cpp
namespace MiraiCP {
std::string MiraiCode::toString() {
return Tools::escapeFromMiraiCode(this->content);
}
MiraiCode::MiraiCode(const std::string &a, bool convert) { // NOLINT(google-explicit-constructor)
if (!convert)
content = a;
else
content = Tools::escapeToMiraiCode(a);
}
} // namespace MiraiCP
//from include/SingleMessage.cpp
#include <json.hpp>
namespace MiraiCP {
using json = nlohmann::json;
// 静态成员
std::unordered_map<int, std::string> SingleMessage::messageType{
{-5, "MarketFace"},
{-4, "OnlineForwardedMessage"},
{-3, "OnlineAudio"},
{-2, "QuoteReply"},
{-1, "unSupportMessage"},
{0, "plainText"},
{1, "at"},
{2, "atAll"},
{3, "image"},
{4, "app"},
{5, "service"},
{6, "file"},
{7, "face"},
{8, "FlashImage"},
{9, "MusicShare"}};
QuoteReply::QuoteReply(const SingleMessage &m) : SingleMessage(m) {
if (m.type != -2) throw IllegalArgumentException("cannot convert type(" + std::to_string(m.type) + "to QuoteReply", MIRAICP_EXCEPTION_WHERE);
source = MessageSource::deserializeFromString(m.content);
}
// 结束静态成员
nlohmann::json PlainText::toJson() const {
nlohmann::json j;
j["key"] = "plaintext";
j["content"] = content;
return j;
}
int SingleMessage::getKey(const std::string &value) {
for (const auto &a: messageType) {
if (Tools::iequal(a.second, value)) return a.first;
}
return -1;
}
std::string SingleMessage::toMiraiCode() const {
// Logger::logger.info("base");
if (type > 0)
if (type == 1)
return "[mirai:at:" + content + "] ";
else if (type == 2)
return "[mirai:atall] ";
else
return "[mirai:" + messageType[type] + this->prefix + Tools::escapeToMiraiCode(content) + "]";
else
return content;
}
PlainText::PlainText(const SingleMessage &sg) : SingleMessage(sg) {
if (sg.type != 0)
throw IllegalArgumentException(
"Cannot convert(" + MiraiCP::SingleMessage::messageType[sg.type] + ") to PlainText", MIRAICP_EXCEPTION_WHERE);
this->content = sg.content;
}
nlohmann::json At::toJson() const {
nlohmann::json j;
j["key"] = "at";
j["content"] = std::to_string(this->target);
return j;
}
At::At(const SingleMessage &sg) : SingleMessage(sg) {
if (sg.type != 1)
throw IllegalArgumentException(
"Cannot convert(" + MiraiCP::SingleMessage::messageType[sg.type] + ") to At", MIRAICP_EXCEPTION_WHERE);
this->target = std::stol(sg.content);
}
nlohmann::json AtAll::toJson() const {
nlohmann::json j;
j["key"] = "atall";
return j;
}
nlohmann::json Image::toJson() const {
nlohmann::json j;
j["key"] = "image";
j["imageid"] = this->id;
j["size"] = this->size;
j["width"] = this->width;
j["height"] = this->height;
j["type"] = this->imageType;
return j;
}
Image::Image(const SingleMessage &sg) : SingleMessage(sg) {
if (sg.type != 3 && sg.type != 8) throw IllegalArgumentException("传入的SingleMessage应该是Image类型", MIRAICP_EXCEPTION_WHERE);
this->id = sg.content;
this->size = this->width = this->height = 0;
this->imageType = 5;
}
bool Image::isUploaded(QQID botid) {
if (!this->md5.has_value()) this->refreshInfo();
if (this->size == 0) throw IllegalArgumentException("size不能为0", MIRAICP_EXCEPTION_WHERE);
nlohmann::json tmp = this->toJson();
tmp["botid"] = botid;
std::string re = KtOperation::ktOperation(KtOperation::ImageUploaded, tmp);
return re == "true";
}
nlohmann::json FlashImage::toJson() const {
nlohmann::json j;
j["key"] = "Flashimage";
j["imageid"] = this->id;
j["size"] = this->size;
j["width"] = this->width;
j["height"] = this->height;
j["type"] = this->imageType;
return j;
}
nlohmann::json LightApp::toJson() const {
nlohmann::json j;
j["key"] = "lightapp";
j["content"] = this->content;
return j;
}
LightApp::LightApp(const SingleMessage &sg) : SingleMessage(sg) {
if (sg.type != 3)
throw IllegalArgumentException(
"Cannot convert(" + MiraiCP::SingleMessage::messageType[sg.type] + ") to LighApp", MIRAICP_EXCEPTION_WHERE);
}
std::string LightApp::toMiraiCode() const {
return "[mirai:app:" + Tools::escapeToMiraiCode(content) + "]";
}
nlohmann::json ServiceMessage::toJson() const {
nlohmann::json j;
j["key"] = "servicemessage";
j["content"] = this->content;
j["id"] = this->id;
return j;
}
std::string ServiceMessage::toMiraiCode() const {
return "[mirai:service" + this->prefix + Tools::escapeToMiraiCode(content) + "]";
}
ServiceMessage::ServiceMessage(const SingleMessage &sg) : SingleMessage(sg) {
if (sg.type != 4)
throw IllegalArgumentException(
"Cannot convert(" + MiraiCP::SingleMessage::messageType[sg.type] + ") to ServiceMessage", MIRAICP_EXCEPTION_WHERE);
}
nlohmann::json Face::toJson() const {
nlohmann::json j;
j["key"] = "face";
j["id"] = this->id;
return j;
}
nlohmann::json UnSupportMessage::toJson() const {
nlohmann::json j;
j["key"] = "unsupportmessage";
j["content"] = this->content;
return j;
}
//远程文件(群文件)
RemoteFile::RemoteFile(const std::string &i, unsigned int ii, std::string n, long long s, std::string p,
struct Dinfo d, struct Finfo f) : SingleMessage(RemoteFile::type(), i + "," + std::to_string(ii) + "," +
Tools::escapeToMiraiCode(std::move(n)) +
"," +
std::to_string(s)),
id(i),
internalid(ii),
name(std::move(n)),
size(s),
path(std::move(p)),
dinfo(std::move(d)),
finfo(f) {}
RemoteFile::RemoteFile(const std::string &i, unsigned int ii, std::string n, long long s) : SingleMessage(6, i + "," + std::to_string(ii) + "," +
Tools::escapeToMiraiCode(std::move(n)) +
"," +
std::to_string(s)),
id(i),
internalid(ii),
name(std::move(n)),
size(s) {}
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 {
auto re = RemoteFile(j["id"], j["internalid"], j["name"], j["finfo"]["size"]);
if (j.contains("dinfo")) {
struct Dinfo d {
j["dinfo"]["url"],
j["dinfo"]["md5"],
j["dinfo"]["sha1"]
};
re.dinfo = d;
}
if (j["finfo"].contains("uploaderid")) {
struct Finfo f {
j["finfo"]["size"],
j["finfo"]["uploaderid"],
j["finfo"]["expirytime"],
j["finfo"]["uploadtime"],
j["finfo"]["lastmodifytime"]
};
re.finfo = f;
}
if (j.contains("path"))
re.path = j["path"];
return re;
} catch (json::type_error &e) {
Logger::logger.error("json格式化失败位置:RemoteFile");
Logger::logger.error(source);
Logger::logger.error(e.what());
throw e;
}
}
RemoteFile RemoteFile::plus(unsigned int ii) {
RemoteFile tmp(*this);
tmp.internalid = ii;
tmp.content = id + "," + std::to_string(ii) + "," + Tools::escapeToMiraiCode(std::move(name)) + "," +
std::to_string(size);
return tmp;
}
std::string RemoteFile::serializeToString() {
json j;
if (this->dinfo.has_value()) {
j["dinfo"]["url"] = this->dinfo->url;
j["dinfo"]["md5"] = this->dinfo->md5;
j["dinfo"]["shar1"] = this->dinfo->sha1;
}
if (this->finfo.has_value()) {
j["finfo"]["size"] = this->finfo->size;
j["finfo"]["uploaderid"] = this->finfo->uploaderid;
j["finfo"]["expirytime"] = this->finfo->expirytime;
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;
if (this->path.has_value())
j["path"] = this->path.value();
return j.dump();
}
/*图片类实现*/
void Image::refreshInfo() {
std::string re = KtOperation::ktOperation(KtOperation::QueryImgInfo, this->toJson());
if (re == "E1")
throw RemoteAssetException("图片id格式错误", MIRAICP_EXCEPTION_WHERE);
json j = json::parse(re);
this->url = j["url"];
this->md5 = j["md5"];
this->size = j["size"];
this->width = j["width"];
this->height = j["height"];
this->imageType = j["type"];
}
Image Image::deserialize(const std::string &str) {
json j = json::parse(str);
return Image(
j["imageid"],
j["size"],
j["width"],
j["height"],
j["type"]);
}
FlashImage FlashImage::deserialize(const std::string &str) {
json j = json::parse(str);
return FlashImage(
j["imageid"],
j["size"],
j["width"],
j["height"],
j["type"]);
}
} // namespace MiraiCP
//from include/Tools.cpp
#include <regex>
#include <utf8.h>
namespace MiraiCP::Tools {
// 工具函数实现
std::string replace(std::string str, std::string_view from, std::string_view to) {
size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substd::string of 'from'
}
return str;
}
std::vector<QQID> StringToVector(std::string temp) {
std::vector<QQID> result;
temp.erase(temp.begin());
temp.pop_back();
std::regex ws_re("[,]+");
std::vector<std::string> v(std::sregex_token_iterator(temp.begin(), temp.end(), ws_re, -1),
std::sregex_token_iterator());
result.reserve(v.size());
std::for_each(v.begin(), v.end(), [&](auto &&s) { result.emplace_back(std::stoull(s)); });
// for (auto &&s: v)
// result.emplace_back(std::stoull(s));
return result;
}
std::string escapeFromMiraiCode(const std::string &s) {
//[ \[
//] \]
//: \:
//, \,
//\ \\ /
return replace(replace(replace(replace(replace(s,
"\\\\", "\\"),
"\\,", ","),
"\\:", ":"),
"\\]", "]"),
"\\[", "[");
}
std::string escapeToMiraiCode(const std::string &s) {
//[ \[
//] \]
//: \:
//, \,
//\ \\ /
return replace(replace(replace(replace(replace(s,
"\\", "\\\\"),
",", "\\,"),
":", "\\:"),
"]", "\\]"),
"[", "\\[");
}
bool starts_with(std::string_view f, std::string_view s) { return f.rfind(s, 0) == 0; }
bool icompareChar(const char &c1, const char &c2) {
return c1 == c2 || std::toupper(c1) == std::toupper(c2);
}
bool iequal(std::string_view str1, std::string_view str2) {
return ((str1.size() == str2.size()) &&
std::equal(str1.begin(), str1.end(), str2.begin(), &icompareChar));
}
std::vector<std::string> split(const std::string &text, const std::string &delim) {
std::regex ws_re(delim + "+");
return {std::sregex_token_iterator(text.begin(), text.end(), ws_re, -1), std::sregex_token_iterator()};
}
} // namespace MiraiCP::Tools
//from include/loaderApi.cpp
#include <string>
#include <utility>
#include <vector>
namespace LibLoader::LoaderApi {
static const interface_funcs *loader_apis = nullptr;
void set_loader_apis(const LibLoader::LoaderApi::interface_funcs *apis) {
loader_apis = apis;
}
void reset_loader_apis() {
loader_apis = nullptr;
}
/// 这个函数是给本cpp以外的文件使用的大概率用不到
const interface_funcs *get_loader_apis() {
return loader_apis;
}
using MiraiCP::PluginNotAuthorizedException;
using MiraiCP::PluginNotEnabledException;
// check the func ptr existance before use it
inline void checkApi(void *funcptr) {
if (loader_apis == nullptr) [[unlikely]] {
throw PluginNotEnabledException(MIRAICP_EXCEPTION_WHERE);
} else if (funcptr == nullptr) [[unlikely]] {
throw PluginNotAuthorizedException(MIRAICP_EXCEPTION_WHERE);
}
}
/// interfaces for plugins
MiraiCPString pluginOperation(const MiraiCPString &s) {
checkApi((void *) loader_apis->_pluginOperation);
return loader_apis->_pluginOperation(s);
}
void loggerInterface(const MiraiCPString &content, const MiraiCPString &name, long long id, int level) {
checkApi((void *) loader_apis->_loggerInterface);
loader_apis->_loggerInterface(content, name, id, level);
}
// todo(ea): 返回可用类型而不是中间类型
MiraiCPString showAllPluginId() {
checkApi((void *) loader_apis->_showAllPluginId);
return loader_apis->_showAllPluginId();
}
void enablePluginById(const MiraiCPString &id) {
checkApi((void *) loader_apis->_enablePluginById);
loader_apis->_enablePluginById(id);
}
void disablePluginById(const MiraiCPString &id) {
checkApi((void *) loader_apis->_disablePluginById);
loader_apis->_disablePluginById(id);
}
void enableAllPlugins() {
checkApi((void *) loader_apis->_enableAllPlugins);
loader_apis->_enableAllPlugins();
}
void disableAllPlugins() {
checkApi((void *) loader_apis->_disableAllPlugins);
loader_apis->_disableAllPlugins();
}
void loadNewPlugin(const MiraiCPString &path, bool activateNow) {
checkApi((void *) loader_apis->_loadNewPlugin);
loader_apis->_loadNewPlugin(path, activateNow);
}
void unloadPluginById(const MiraiCPString &id) {
checkApi((void *) loader_apis->_unloadPluginById);
loader_apis->_unloadPluginById(id);
}
void reloadPluginById(const MiraiCPString &id) {
checkApi((void *) loader_apis->_reloadPluginById);
loader_apis->_reloadPluginById(id);
}
} // namespace LibLoader::LoaderApi
//from include/utils.cpp
// 开始对接libloader接口代码
using json = nlohmann::json;
namespace LibLoader::LoaderApi {
const interface_funcs *get_loader_apis();
void set_loader_apis(const LibLoader::LoaderApi::interface_funcs *apis);
void reset_loader_apis();
} // namespace LibLoader::LoaderApi
extern "C" {
/// 插件开启入口
MIRAICP_EXPORT void FUNC_ENTRANCE(const LibLoader::LoaderApi::interface_funcs &funcs) {
static_assert(std::is_same_v<decltype(&FUNC_ENTRANCE), LibLoader::plugin_entrance_func_ptr>);
using namespace MiraiCP;
Event::clear();
LibLoader::LoaderApi::set_loader_apis(&funcs);
assert(LibLoader::LoaderApi::get_loader_apis() != nullptr);
Logger::logger.info("开始启动插件: " + MiraiCP::CPPPlugin::config.getId());
try {
enrollPlugin();
// plugin == nullptr 无插件实例加载
if (CPPPlugin::plugin != nullptr) {
CPPPlugin::plugin->onEnable();
}
} catch (const MiraiCPExceptionBase &e) {
e.raise();
Logger::logger.error("插件(id=" + CPPPlugin::config.getId() + ", name=" + CPPPlugin::config.name + ")启动失败");
throw IllegalStateException(e.what(), e.filename, e.lineNum);
} catch (const std::exception &e) {
Logger::logger.error(e.what());
Logger::logger.error("插件(id=" + CPPPlugin::config.getId() + ", name=" + CPPPlugin::config.name + ")启动失败");
throw IllegalStateException(e.what(), MIRAICP_EXCEPTION_WHERE);
} catch (...) {
Logger::logger.error("插件(id=" + CPPPlugin::config.getId() + ", name=" + CPPPlugin::config.name + ")启动失败");
throw IllegalStateException("", MIRAICP_EXCEPTION_WHERE);
}
}
/// 插件结束(也可能是暂时的disable)
MIRAICP_EXPORT void FUNC_EXIT() {
static_assert(std::is_same_v<decltype(&FUNC_EXIT), LibLoader::plugin_func_ptr>);
using namespace MiraiCP;
Logger::logger.info("开始禁用插件:" + MiraiCP::CPPPlugin::config.getId());
Event::clear();
if (CPPPlugin::plugin != nullptr) CPPPlugin::plugin->onDisable();
CPPPlugin::plugin.reset();
// 无法保证用户插件析构函数是否调用api在plugin.reset()之前不可reset loader api
LibLoader::LoaderApi::reset_loader_apis();
}
/// 消息解析分流
/// env != null, call from jni
MIRAICP_EXPORT void FUNC_EVENT(const char *c) {
static_assert(std::is_same_v<decltype(&FUNC_EVENT), LibLoader::plugin_event_func_ptr>);
using namespace MiraiCP;
std::string content = c;
json j;
try {
j = json::parse(content);
} catch (json::parse_error &e) {
Logger::logger.error("消息解析分流格式化json错误");
Logger::logger.error("For debug: " + content);
Logger::logger.error(e.what());
return;
}
int type = j["type"].get<int>();
if (type != eventTypes::Command && Event::noRegistered(type)) return;
try {
Event::incomingEvent(std::move(j), type);
} catch (json::type_error &e) {
Logger::logger.error("json格式化异常,位置C-Handle");
Logger::logger.error(e.what());
Logger::logger.error("info:", content);
} catch (MiraiCPExceptionBase &e) {
Event::broadcast<MiraiCPExceptionEvent>(MiraiCPExceptionEvent(&e));
e.raise();
} catch (const std::exception &e) {
Logger::logger.error(e.what());
Logger::logger.error("info:", content);
}
// 如果产生了无法处理的异常,直接退出插件
// loader端将处理这个异常并将绑定的线程结束掉
// 如果存在其他线程,可能导致段错误
}
/// 获取 Plugin Info
/// 如果未正确定义,插件无法正确加载
/// 该函数不可调用loader api因为会在入口函数调用前先调用loader api未初始化
MIRAICP_EXPORT const MiraiCP::PluginConfig &PLUGIN_INFO() {
static_assert(std::is_same_v<decltype(&PLUGIN_INFO), LibLoader::plugin_info_func_ptr>);
if (MiraiCP::CPPPlugin::config.getId().empty())
throw std::exception();
return MiraiCP::CPPPlugin::config;
}
}
//结束对接JNI接口代码
//from common/PluginConfig.cpp
namespace MiraiCP {
using json = nlohmann::json;
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;
}
std::string PluginConfig::serialize2string() {
return serialize().dump();
}
} // namespace MiraiCP
//from common/miraicpString.cpp
// Copyright (c) 2022. 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 <http://www.gnu.org/licenses/>.
//
#ifdef MIRAICP_LIB_LOADER
#endif
#include <cstring>
namespace MiraiCP {
void swap(MiraiCPString &a, MiraiCPString &b) noexcept {
std::swap(a.str, b.str);
std::swap(a._size, b._size);
std::swap(a.free_this, b.free_this);
}
// avoid calling this if _size == 0
void MiraiCPString::construction() {
str = (char *) ::std::malloc(sizeof(char) * (_size + 1));
if (str == nullptr) {
#ifdef MIRAICP_LIB_LOADER
LibLoader::logger.error("MiraiCPString::construction: malloc failed when trying to malloc size " + std::to_string(_size + 1));
#endif
throw std::bad_alloc();
}
}
MiraiCPString::~MiraiCPString() { // do not inherit MiraiCPString!!
if (str != nullptr) {
// ensure deconstruction is paired to construction
free_this(str);
str = nullptr;
}
}
MiraiCPString::MiraiCPString(const MiraiCPString &other) : str(nullptr), _size(other._size), free_this(std_free_ptr) {
if (_size == 0) return;
construction();
assert(str != nullptr);
memcpy(str, other.str, _size * sizeof(char));
str[_size] = 0;
}
MiraiCPString::MiraiCPString(MiraiCPString &&temp) noexcept : MiraiCPString() {
swap(*this, temp);
}
MiraiCPString::MiraiCPString(const char *char_str) : MiraiCPString() {
if (char_str == nullptr) return;
_size = strlen(char_str);
if (0 == _size) return;
construction();
assert(str != nullptr);
memcpy(str, char_str, _size * sizeof(char));
str[_size] = 0;
}
MiraiCPString::MiraiCPString(const std::string &string_str) {
_size = string_str.size();
if (!_size) return;
construction();
assert(str != nullptr);
memcpy(str, string_str.c_str(), _size * sizeof(char));
str[_size] = 0;
}
const char *MiraiCPString::copyToCharPtr() const {
if (str == nullptr || _size == 0) return new char[1]{0};
char *t = new char[_size + 1];
memcpy(t, str, (_size + 1) * sizeof(char));
return t;
}
bool MiraiCPString::operator==(const MiraiCPString &another) const {
return another._size == _size && (_size == 0 || strcmp(another.str, str) == 0);
}
MiraiCPString &MiraiCPString::operator=(const MiraiCPString &another) {
MiraiCPString temp(another);
std::swap(*this, temp);
return *this;
}
MiraiCPString &MiraiCPString::operator=(MiraiCPString &&another) noexcept {
std::swap(*this, another);
return *this;
}
} // namespace MiraiCP