diff options
author | Sadie Powell <sadie@witchery.services> | 2025-02-24 03:21:42 +0000 |
---|---|---|
committer | Sadie Powell <sadie@witchery.services> | 2025-02-24 03:41:06 +0000 |
commit | a111b40560bf305653b07d8f7289484793a32588 (patch) | |
tree | b90c6a1070120b5115641414ac2c806efde7c8fa | |
parent | 2ccd182d2e6689877eba911452eaa8a06e82ac0b (diff) |
Allow use of a non-map type as the root RPC element.
-rw-r--r-- | include/modules/rpc.h | 17 | ||||
-rw-r--r-- | modules/extra/xmlrpc.cpp | 8 | ||||
-rw-r--r-- | modules/rpc/jsonrpc.cpp | 5 | ||||
-rw-r--r-- | modules/rpc/rpc_main.cpp | 70 |
4 files changed, 59 insertions, 41 deletions
diff --git a/include/modules/rpc.h b/include/modules/rpc.h index 3af6e81c5..1f136b1e2 100644 --- a/include/modules/rpc.h +++ b/include/modules/rpc.h @@ -58,7 +58,7 @@ public: inline Map &ReplyMap(); }; -class RPC::Map +class RPC::Map final { private: Anope::map<Value> replies; @@ -137,10 +137,10 @@ public: }; class RPC::Request final - : public RPC::Map { private: std::optional<std::pair<int64_t, Anope::string>> error; + std::optional<Value> root; public: Anope::string name; @@ -158,7 +158,12 @@ public: this->error.emplace(errcode, errstr); } + template<typename T = Map> + inline T &Root(); + inline const auto &GetError() const { return this->error; } + + inline const auto &GetRoot() const { return this->root; } }; class RPC::Event @@ -219,3 +224,11 @@ inline RPC::Map &RPC::Map::ReplyMap(const Anope::string &key) auto it = this->replies.emplace(key, RPC::Map()); return std::get<RPC::Map>(it.first->second.Get()); } + +template<typename T> +inline T &RPC::Request::Root() +{ + if (!this->root.has_value()) + this->root = RPC::Value(T()); + return std::get<T>(this->root.value().Get()); +} diff --git a/modules/extra/xmlrpc.cpp b/modules/extra/xmlrpc.cpp index 1d9ab7762..681b230dc 100644 --- a/modules/extra/xmlrpc.cpp +++ b/modules/extra/xmlrpc.cpp @@ -116,7 +116,6 @@ public: Anope::string param; if (xmlrpc_value_type(value) != XMLRPC_TYPE_STRING) { - // TODO: error; xmlrpc_env_set_fault(&env, RPC::ERR_INVALID_REQUEST, "Anope XML-RPC only supports strings"); SendError(reply, env); xmlrpc_DECREF(value); @@ -160,8 +159,11 @@ public: return; } - auto *value = xmlrpc_struct_new(&env); - SerializeMap(env, value, request); + xmlrpc_value *value; + if (request.GetRoot()) + value = SerializeElement(env, request.GetRoot().value()); + else + value = xmlrpc_nil_new(&env); auto *response = xmlrpc_mem_block_new(&env, 0); xmlrpc_serialize_response(&env, response, value); diff --git a/modules/rpc/jsonrpc.cpp b/modules/rpc/jsonrpc.cpp index ad46bcb13..22c00b118 100644 --- a/modules/rpc/jsonrpc.cpp +++ b/modules/rpc/jsonrpc.cpp @@ -171,10 +171,9 @@ public: else yyjson_mut_obj_add_strn(doc, root, "id", request.id.c_str(), request.id.length()); - if (!request.GetReplies().empty()) + if (request.GetRoot()) { - auto *result = yyjson_mut_obj(doc); - SerializeMap(doc, result, request); + auto *result = SerializeElement(doc, request.GetRoot().value()); yyjson_mut_obj_add_val(doc, root, "result", result); } diff --git a/modules/rpc/rpc_main.cpp b/modules/rpc/rpc_main.cpp index c1e53e8dd..2f22e82c7 100644 --- a/modules/rpc/rpc_main.cpp +++ b/modules/rpc/rpc_main.cpp @@ -37,7 +37,7 @@ public: request.reply = this->repl; - request.Reply("account", GetAccount()); + request.Root().Reply("account", GetAccount()); xinterface->Reply(request); client->SendReply(&request.reply); @@ -108,7 +108,7 @@ public: Command::Run(source, command); if (!out.empty()) - request.Reply("return", out); + request.Root().Reply("return", out); return true; } @@ -152,16 +152,17 @@ public: bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override { - request.Reply("uptime", Anope::CurTime - Anope::StartTime); - request.Reply("uplinkname", Me->GetLinks().front()->GetName()); + auto &root = request.Root(); + root.Reply("uptime", Anope::CurTime - Anope::StartTime); + root.Reply("uplinkname", Me->GetLinks().front()->GetName()); { - auto &uplinkcapab = request.ReplyArray("uplinkcapab"); + auto &uplinkcapab = root.ReplyArray("uplinkcapab"); for (const auto &capab : Servers::Capab) uplinkcapab.Reply(capab); } - request.Reply("usercount", UserListByNick.size()); - request.Reply("maxusercount", MaxUserCount); - request.Reply("channelcount", ChannelList.size()); + root.Reply("usercount", UserListByNick.size()); + root.Reply("maxusercount", MaxUserCount); + root.Reply("channelcount", ChannelList.size()); return true; } }; @@ -185,37 +186,38 @@ public: Channel *c = Channel::Find(request.data[0]); - request.Reply("name", c ? c->name : request.data[0]); + auto &root = request.Root(); + root.Reply("name", c ? c->name : request.data[0]); if (c) { - request.Reply("bancount", c->HasMode("BAN")); - auto &bans = request.ReplyArray("bans"); + root.Reply("bancount", c->HasMode("BAN")); + auto &bans = root.ReplyArray("bans"); for (auto &ban : c->GetModeList("BAN")) bans.Reply(ban); - request.Reply("exceptcount", c->HasMode("EXCEPT")); - auto &excepts = request.ReplyArray("excepts"); + root.Reply("exceptcount", c->HasMode("EXCEPT")); + auto &excepts = root.ReplyArray("excepts"); for (auto &except : c->GetModeList("EXCEPT")) excepts.Reply(except); - request.Reply("invitecount", c->HasMode("INVITEOVERRIDE")); - auto &invites = request.ReplyArray("invites"); + root.Reply("invitecount", c->HasMode("INVITEOVERRIDE")); + auto &invites = root.ReplyArray("invites"); for (auto &invite : c->GetModeList("INVITEOVERRIDE")) invites.Reply(invite); - auto &users = request.ReplyArray("users"); + auto &users = root.ReplyArray("users"); for (const auto &[_, uc] : c->users) users.Reply(uc->status.BuildModePrefixList() + uc->user->nick); if (!c->topic.empty()) - request.Reply("topic", c->topic); + root.Reply("topic", c->topic); if (!c->topic_setter.empty()) - request.Reply("topicsetter", c->topic_setter); + root.Reply("topicsetter", c->topic_setter); - request.Reply("topictime", c->topic_time); - request.Reply("topicts", c->topic_ts); + root.Reply("topictime", c->topic_time); + root.Reply("topicts", c->topic_ts); } return true; } @@ -240,28 +242,29 @@ public: User *u = User::Find(request.data[0]); - request.Reply("nick", u ? u->nick : request.data[0]); + auto &root = request.Root(); + root.Reply("nick", u ? u->nick : request.data[0]); if (u) { - request.Reply("ident", u->GetIdent()); - request.Reply("vident", u->GetVIdent()); - request.Reply("host", u->host); + root.Reply("ident", u->GetIdent()); + root.Reply("vident", u->GetVIdent()); + root.Reply("host", u->host); if (!u->vhost.empty()) - request.Reply("vhost", u->vhost); + root.Reply("vhost", u->vhost); if (!u->chost.empty()) - request.Reply("chost", u->chost); - request.Reply("ip", u->ip.addr()); - request.Reply("timestamp", u->timestamp); - request.Reply("signon", u->signon); + root.Reply("chost", u->chost); + root.Reply("ip", u->ip.addr()); + root.Reply("timestamp", u->timestamp); + root.Reply("signon", u->signon); if (u->IsIdentified()) { - request.Reply("account", u->Account()->display); + root.Reply("account", u->Account()->display); if (u->Account()->o) - request.Reply("opertype", u->Account()->o->ot->GetName()); + root.Reply("opertype", u->Account()->o->ot->GetName()); } - auto &channels = request.ReplyArray("channels"); + auto &channels = root.ReplyArray("channels"); for (const auto &[_, cc] : u->chans) channels.Reply(cc->status.BuildModePrefixList() + cc->chan->name); } @@ -280,6 +283,7 @@ public: bool Run(RPC::ServiceInterface *iface, HTTPClient *client, RPC::Request &request) override { + auto &root = request.Root(); for (auto *ot : Config->MyOperTypes) { Anope::string perms; @@ -287,7 +291,7 @@ public: perms += " " + priv; for (const auto &command : ot->GetCommands()) perms += " " + command; - request.Reply(ot->GetName(), perms); + root.Reply(ot->GetName(), perms); } return true; } |