1
0
mirror of https://github.com/anope/anope.git synced 2026-07-06 15:13:13 +02:00

Rework how the RPC interface stores its events.

This commit is contained in:
Sadie Powell
2025-02-18 17:01:33 +00:00
parent 98320d130f
commit 3c55fbe650
4 changed files with 155 additions and 88 deletions
+15 -3
View File
@@ -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;
};
+20 -27
View File
@@ -20,7 +20,7 @@ class MyXMLRPCServiceInterface final
, public HTTPPage
{
private:
std::deque<RPCEvent *> events;
Anope::map<RPCEvent *> 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<RPCEvent *>::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;
}
+18 -24
View File
@@ -23,7 +23,7 @@ class MyJSONRPCServiceInterface final
, public HTTPPage
{
private:
std::deque<RPCEvent *> events;
Anope::map<RPCEvent *> 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;
}
+102 -34
View File
@@ -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<RPCServiceInterface> 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(&noticerpcevent);
}
~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(&noticerpcevent);
}
};