Lucas-Bot/single_include/MiraiCP/MiraiCP.cpp

1608 lines
68 KiB
C++
Raw Normal View History

2022-10-08 22:47:18 +08:00
// 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