From 3c55fbe6509c1706d21136392a4bfb2295a99a35 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Tue, 18 Feb 2025 17:01:33 +0000 Subject: [PATCH] Rework how the RPC interface stores its events. --- include/modules/rpc.h | 18 +++++- modules/extra/xmlrpc.cpp | 47 ++++++-------- modules/rpc/jsonrpc.cpp | 42 ++++++------ modules/rpc/rpc_main.cpp | 136 +++++++++++++++++++++++++++++---------- 4 files changed, 155 insertions(+), 88 deletions(-) diff --git a/include/modules/rpc.h b/include/modules/rpc.h index 76ecf3542..f7e361d5c 100644 --- a/include/modules/rpc.h +++ b/include/modules/rpc.h @@ -46,9 +46,21 @@ class RPCServiceInterface; class RPCEvent { +private: + Anope::string event; + +protected: + RPCEvent(const Anope::string& e) + : event(e) + { + } + public: virtual ~RPCEvent() = default; - virtual bool Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) = 0; + + const auto &GetEvent() const { return event; } + + virtual void Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) = 0; }; class RPCServiceInterface @@ -57,9 +69,9 @@ class RPCServiceInterface public: RPCServiceInterface(Module *creator, const Anope::string &sname) : Service(creator, "RPCServiceInterface", sname) { } - virtual void Register(RPCEvent *event) = 0; + virtual bool Register(RPCEvent *event) = 0; - virtual void Unregister(RPCEvent *event) = 0; + virtual bool Unregister(RPCEvent *event) = 0; virtual void Reply(RPCRequest &request) = 0; }; diff --git a/modules/extra/xmlrpc.cpp b/modules/extra/xmlrpc.cpp index 582a5ab25..ca6856fd2 100644 --- a/modules/extra/xmlrpc.cpp +++ b/modules/extra/xmlrpc.cpp @@ -20,7 +20,7 @@ class MyXMLRPCServiceInterface final , public HTTPPage { private: - std::deque events; + Anope::map events; void SendError(HTTPReply &reply, xmlrpc_env &env) { @@ -46,17 +46,14 @@ public: { } - void Register(RPCEvent *event) override + bool Register(RPCEvent *event) override { - this->events.push_back(event); + return this->events.emplace(event->GetEvent(), event).second; } - void Unregister(RPCEvent *event) override + bool Unregister(RPCEvent *event) override { - std::deque::iterator it = std::find(this->events.begin(), this->events.end(), event); - - if (it != this->events.end()) - this->events.erase(it); + return this->events.erase(event->GetEvent()) != 0; } bool OnRequest(HTTPProvider *provider, const Anope::string &page_name, HTTPClient *client, HTTPMessage &message, HTTPReply &reply) override @@ -79,6 +76,14 @@ public: request.name = method; delete method; + auto event = this->events.find(request.name); + if (event == this->events.end()) + { + xmlrpc_env_set_fault(&env, -32601, "Method not found"); + SendError(reply, env); + return true; + } + auto paramcount = xmlrpc_array_size(&env, params); for (auto idx = 0; idx < paramcount; ++idx) { @@ -113,28 +118,16 @@ public: } xmlrpc_DECREF(params); - for (auto *e : this->events) + event->second->Run(this, client, request); + + if (request.GetError()) { - if (!e->Run(this, client, request)) - return false; - - if (request.GetError()) - { - xmlrpc_env_set_fault(&env, request.GetError()->first, request.GetError()->second.c_str()); - SendError(reply, env); - return true; - } - - if (!request.GetReplies().empty()) - { - this->Reply(request); - return true; - } + xmlrpc_env_set_fault(&env, request.GetError()->first, request.GetError()->second.c_str()); + SendError(reply, env); + return true; } - // If we reached this point nobody handled the event. - xmlrpc_env_set_fault(&env, -32601, "Method not found"); - SendError(reply, env); + this->Reply(request); return true; } diff --git a/modules/rpc/jsonrpc.cpp b/modules/rpc/jsonrpc.cpp index 92a4765e9..8c16f4cc8 100644 --- a/modules/rpc/jsonrpc.cpp +++ b/modules/rpc/jsonrpc.cpp @@ -23,7 +23,7 @@ class MyJSONRPCServiceInterface final , public HTTPPage { private: - std::deque events; + Anope::map events; void SendError(HTTPReply &reply, int64_t code, const Anope::string &message, const Anope::string &id) { @@ -63,16 +63,14 @@ public: { } - void Register(RPCEvent *event) override + bool Register(RPCEvent *event) override { - this->events.push_back(event); + return this->events.emplace(event->GetEvent(), event).second; } - void Unregister(RPCEvent *event) override + bool Unregister(RPCEvent *event) override { - auto it = std::find(this->events.begin(), this->events.end(), event); - if (it != this->events.end()) - this->events.erase(it); + return this->events.erase(event->GetEvent()) != 0; } bool OnRequest(HTTPProvider *provider, const Anope::string &page_name, HTTPClient *client, HTTPMessage &message, HTTPReply &reply) override @@ -117,26 +115,22 @@ public: yyjson_doc_free(doc); - for (auto *e : this->events) + auto event = this->events.find(request.name); + if (event == this->events.end()) { - if (!e->Run(this, client, request)) - return false; - - else if (request.GetError()) - { - SendError(reply, request.GetError()->first, request.GetError()->second, id); - return true; - } - - else if (!request.GetReplies().empty()) - { - this->Reply(request); - return true; - } + SendError(reply, -32601, "Method not found", id); + return true; } - // If we reached this point nobody handled the event. - SendError(reply, -32601, "Method not found", id); + event->second->Run(this, client, request); + + if (request.GetError()) + { + SendError(reply, request.GetError()->first, request.GetError()->second, id); + return true; + } + + this->Reply(request); return true; } diff --git a/modules/rpc/rpc_main.cpp b/modules/rpc/rpc_main.cpp index 5e33447ff..b5c263be1 100644 --- a/modules/rpc/rpc_main.cpp +++ b/modules/rpc/rpc_main.cpp @@ -57,32 +57,16 @@ public: } }; -class MyRPCEvent final +class CommandRPCEvent final : public RPCEvent { public: - bool Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) override + CommandRPCEvent() + : RPCEvent("command") { - if (request.name == "command") - this->DoCommand(iface, client, request); - else if (request.name == "checkAuthentication") - return this->DoCheckAuthentication(iface, client, request); - else if (request.name == "stats") - this->DoStats(iface, client, request); - else if (request.name == "channel") - this->DoChannel(iface, client, request); - else if (request.name == "user") - this->DoUser(iface, client, request); - else if (request.name == "opers") - this->DoOperType(iface, client, request); - else if (request.name == "notice") - this->DoNotice(iface, client, request); - - return true; } -private: - void DoCommand(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) + void Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) override { Anope::string service = request.data.size() > 0 ? request.data[0] : ""; Anope::string user = request.data.size() > 1 ? request.data[1] : ""; @@ -126,8 +110,18 @@ private: if (!out.empty()) request.Reply("return", out); } +}; - static bool DoCheckAuthentication(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) +class CheckAuthenticationRPCEvent final + : public RPCEvent +{ +public: + CheckAuthenticationRPCEvent() + : RPCEvent("checkAuthentication") + { + } + + void Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) override { Anope::string username = request.data.size() > 0 ? request.data[0] : ""; Anope::string password = request.data.size() > 1 ? request.data[1] : ""; @@ -135,16 +129,25 @@ private: if (username.empty() || password.empty()) { request.Error(-32602, "Invalid parameters"); - return true; + return; } auto *req = new RPCIdentifyRequest(me, request, client, iface, username, password); FOREACH_MOD(OnCheckAuthentication, (NULL, req)); req->Dispatch(); - return false; + } +}; + +class StatsRPCEvent final + : public RPCEvent +{ +public: + StatsRPCEvent() + : RPCEvent("stats") + { } - static void DoStats(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) + void Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) override { request.Reply("uptime", Anope::ToString(Anope::CurTime - Anope::StartTime)); request.Reply("uplinkname", Me->GetLinks().front()->GetName()); @@ -160,8 +163,18 @@ private: request.Reply("maxusercount", Anope::ToString(MaxUserCount)); request.Reply("channelcount", Anope::ToString(ChannelList.size())); } +}; - static void DoChannel(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) +class ChannelRPCEvent final + : public RPCEvent +{ +public: + ChannelRPCEvent() + : RPCEvent("channel") + { + } + + void Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) override { if (request.data.empty()) return; @@ -209,8 +222,18 @@ private: request.Reply("topicts", Anope::ToString(c->topic_ts)); } } +}; - static void DoUser(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) +class UserRPCEvent final + : public RPCEvent +{ +public: + UserRPCEvent() + : RPCEvent("user") + { + } + + void Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) override { if (request.data.empty()) return; @@ -251,8 +274,18 @@ private: } } } +}; - static void DoOperType(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) +class OpersRPCEvent final + : public RPCEvent +{ +public: + OpersRPCEvent() + : RPCEvent("opers") + { + } + + void Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) override { for (auto *ot : Config->MyOperTypes) { @@ -264,8 +297,18 @@ private: request.Reply(ot->GetName(), perms); } } +}; - static void DoNotice(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) +class NoticeRPCEvent final + : public RPCEvent +{ +public: + NoticeRPCEvent() + : RPCEvent("notice") + { + } + + void Run(RPCServiceInterface *iface, HTTPClient *client, RPCRequest &request) override { Anope::string from = request.data.size() > 0 ? request.data[0] : ""; Anope::string to = request.data.size() > 1 ? request.data[1] : ""; @@ -275,7 +318,10 @@ private: User *u = User::Find(to, true); if (!bi || !u || message.empty()) + { + request.Error(-32602, "Invalid parameters"); return; + } u->SendMessage(bi, message); } @@ -284,25 +330,47 @@ private: class ModuleRPCMain final : public Module { +private: ServiceReference rpc; - - MyRPCEvent stats; + CommandRPCEvent commandrpcevent; + CheckAuthenticationRPCEvent checkauthenticationrpcevent; + StatsRPCEvent statsrpcevent; + ChannelRPCEvent channelrpcevent; + UserRPCEvent userrpcevent; + OpersRPCEvent opersrpcevent; + NoticeRPCEvent noticerpcevent; public: - ModuleRPCMain(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), rpc("RPCServiceInterface", "rpc") + ModuleRPCMain(const Anope::string &modname, const Anope::string &creator) + : Module(modname, creator, EXTRA | VENDOR) + , rpc("RPCServiceInterface", "rpc") { me = this; if (!rpc) throw ModuleException("Unable to find RPC interface, is jsonrpc/xmlrpc loaded?"); - rpc->Register(&stats); + rpc->Register(&commandrpcevent); + rpc->Register(&checkauthenticationrpcevent); + rpc->Register(&statsrpcevent); + rpc->Register(&channelrpcevent); + rpc->Register(&userrpcevent); + rpc->Register(&opersrpcevent); + rpc->Register(¬icerpcevent); } ~ModuleRPCMain() override { - if (rpc) - rpc->Unregister(&stats); + if (!rpc) + return; + + rpc->Unregister(&commandrpcevent); + rpc->Unregister(&checkauthenticationrpcevent); + rpc->Unregister(&statsrpcevent); + rpc->Unregister(&channelrpcevent); + rpc->Unregister(&userrpcevent); + rpc->Unregister(&opersrpcevent); + rpc->Unregister(¬icerpcevent); } };