diff options
author | Adam <Adam@anope.org> | 2017-02-07 17:20:07 -0500 |
---|---|---|
committer | Adam <Adam@anope.org> | 2017-02-07 17:20:07 -0500 |
commit | 09dca29c8898916772c2a2a6b86b625c812007ed (patch) | |
tree | 1b28f4751feec3ea2b46fa0afb061da7926f3a47 | |
parent | 8b694bc392c36551e428b84454efb81cdbc8bcd3 (diff) |
Normalize databases by not allowing generic Object references
Remove redis database support
36 files changed, 223 insertions, 1397 deletions
diff --git a/data/anope.example.conf b/data/anope.example.conf index 89c63ebfd..f6abe70db 100644 --- a/data/anope.example.conf +++ b/data/anope.example.conf @@ -1087,22 +1087,6 @@ module } /* - * db_redis. - * - * This module allows using Redis (http://redis.io) as a database backend. - * This module requires the module redis to be loaded and configured properly. - */ -#module -{ - name = "database/redis" - - /* - * Redis database to use. This must be configured with the module redis. - */ - engine = "redis/main" -} - -/* * [RECOMMENDED] Encryption modules. * * The encryption modules are used when dealing with passwords. This determines how diff --git a/data/modules.example.conf b/data/modules.example.conf index 0f22a7c72..725130137 100644 --- a/data/modules.example.conf +++ b/data/modules.example.conf @@ -384,31 +384,6 @@ module { name = "help" } } /* - * redis - * - * This module allows other modules to use Redis. - */ -#module -{ - name = "redis" - - /* A redis database */ - redis - { - /* The name of this service */ - name = "redis/main" - - /* - * The redis database to use. New connections default to 0. - */ - db = 0 - - ip = "127.0.0.1" - port = 6379 - } -} - -/* * rest [EXTRA] * * This module exposes a RESTful API using JSON via the httpd module. diff --git a/docs/SQLite.md b/docs/SQLite.md index be25bbb27..30e0d7b12 100644 --- a/docs/SQLite.md +++ b/docs/SQLite.md @@ -6,21 +6,21 @@ It does this by using SQLites support for having indexes on expressions https:// For example the account table could look like: ``` -CREATE TABLE `anope_db_account` ( +CREATE TABLE `anope_account` ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, `display`, `pass`, `email`, - `language`, - `id` NOT NULL PRIMARY KEY, - FOREIGN KEY (id) REFERENCES anope_db_objects(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED + `language` ); -CREATE INDEX idx_display ON `anope_db_account` (anope_canonicalize(display)); + +CREATE INDEX idx_display ON `anope_account` (anope_canonicalize(display)); ``` So, to do a SELECT which utilizes the indicies, Anope does something like: ``` -SELECT id FROM `anope_db_account` WHERE anope_canonicalize(display) = anope_canonicalize('Adam'); +SELECT id FROM `anope_account` WHERE anope_canonicalize(display) = anope_canonicalize('Adam'); ``` If you are using your own SQLite instance, like the sqlite command line interface, the anope_canonicalize function @@ -31,13 +31,13 @@ or libanope_sqlite_rfc1459.so into SQLite, depending on your casemap configurati sqlite> .load lib/libanope_sqlite_ascii.so ``` -## Example of adding a new operator via SQLite +## Example of registering a new user via SQLite ``` BEGIN TRANSACTION; --- Allocate new ID and insert into objects table -INSERT INTO anope_db_objects (id, type) SELECT MAX(id + 1), 'oper' FROM anope_db_objects; --- Insert new operator using previously allocated id -INSERT INTO anope_db_oper (name, type, require_oper, id) VALUES ('Adam', 'Services Root', 1, last_insert_rowid()); +-- Insert new account +INSERT INTO anope_account (display, email, private, autoop, killprotect) VALUES ('Adam', 'adam@anope.org', 1, 1, 1); +-- Insert nickname, linking it to the account +INSERT INTO anope_nick (nick, account) VALUES ('Adam', last_insert_rowid()); COMMIT; ``` diff --git a/include/event.h b/include/event.h index 85e406795..bcc04cc0a 100644 --- a/include/event.h +++ b/include/event.h @@ -1202,7 +1202,7 @@ namespace Event virtual EventReturn OnSerializeDeref(Serialize::ID value, Serialize::TypeBase *type) anope_abstract; - virtual EventReturn OnSerializableGetId(Serialize::ID &id) anope_abstract; + virtual EventReturn OnSerializableGetId(Serialize::TypeBase *type, Serialize::ID &id) anope_abstract; virtual void OnSerializableDelete(Serialize::Object *) anope_abstract; diff --git a/include/modules/chanserv/chanaccess.h b/include/modules/chanserv/chanaccess.h index faaf48175..dff39c0f8 100644 --- a/include/modules/chanserv/chanaccess.h +++ b/include/modules/chanserv/chanaccess.h @@ -35,7 +35,7 @@ class CoreExport ChanAccess : public Serialize::Object static constexpr const char *const NAME = "access"; Serialize::Storage<Channel *> channel; - Serialize::Storage<Serialize::Object *> object; + Serialize::Storage<NickServ::Account *> account; Serialize::Storage<Anope::string> creator, mask; Serialize::Storage<time_t> last_seen, created; @@ -56,11 +56,10 @@ class CoreExport ChanAccess : public Serialize::Object virtual Anope::string GetMask() anope_abstract; virtual void SetMask(const Anope::string &) anope_abstract; - virtual Serialize::Object *GetObj() anope_abstract; - virtual void SetObj(Serialize::Object *) anope_abstract; + virtual NickServ::Account *GetAccount() anope_abstract; + virtual void SetAccount(NickServ::Account *) anope_abstract; virtual Anope::string Mask() anope_abstract; - virtual NickServ::Account *GetAccount() anope_abstract; /** Check if this access entry matches the given user or account * @param u The user diff --git a/include/modules/chanserv/main/chanaccess.h b/include/modules/chanserv/main/chanaccess.h index a126da685..fb78056ea 100644 --- a/include/modules/chanserv/main/chanaccess.h +++ b/include/modules/chanserv/main/chanaccess.h @@ -22,8 +22,7 @@ class ChanAccessImpl : public ChanServ::ChanAccess { public: - ChanAccessImpl(Serialize::TypeBase *type) : ChanServ::ChanAccess(type) { } - ChanAccessImpl(Serialize::TypeBase *type, Serialize::ID id) : ChanServ::ChanAccess(type, id) { } + using ChanServ::ChanAccess::ChanAccess; ChanServ::Channel *GetChannel() override; void SetChannel(ChanServ::Channel *ci) override; @@ -40,11 +39,10 @@ class ChanAccessImpl : public ChanServ::ChanAccess Anope::string GetMask() override; void SetMask(const Anope::string &) override; - Serialize::Object *GetObj() override; - void SetObj(Serialize::Object *) override; + NickServ::Account *GetAccount() override; + void SetAccount(NickServ::Account *) override; Anope::string Mask() override; - NickServ::Account *GetAccount() override; bool Matches(const User *u, NickServ::Account *acc) override; }; diff --git a/include/modules/hostserv.h b/include/modules/hostserv.h index 6934c813e..f2ec9a187 100644 --- a/include/modules/hostserv.h +++ b/include/modules/hostserv.h @@ -31,8 +31,8 @@ namespace HostServ public: static constexpr const char *const NAME = "vhost"; - virtual Serialize::Object *GetOwner() anope_abstract; - virtual void SetOwner(Serialize::Object *) anope_abstract; + virtual NickServ::Account *GetAccount() anope_abstract; + virtual void SetAccount(NickServ::Account *) anope_abstract; virtual Anope::string GetIdent() anope_abstract; virtual void SetIdent(const Anope::string &) anope_abstract; diff --git a/include/modules/memoserv.h b/include/modules/memoserv.h index 8c39b5a5e..888f793fe 100644 --- a/include/modules/memoserv.h +++ b/include/modules/memoserv.h @@ -138,8 +138,11 @@ namespace MemoServ virtual bool HasIgnore(User *u) anope_abstract; - virtual Serialize::Object *GetOwner() anope_abstract; - virtual void SetOwner(Serialize::Object *) anope_abstract; + virtual NickServ::Account *GetAccount() anope_abstract; + virtual void SetAccount(NickServ::Account *) anope_abstract; + + virtual ChanServ::Channel *GetChannel() anope_abstract; + virtual void SetChannel(ChanServ::Channel *) anope_abstract; virtual int16_t GetMemoMax() anope_abstract; virtual void SetMemoMax(const int16_t &) anope_abstract; diff --git a/include/modules/operserv/info.h b/include/modules/operserv/info.h index 0e2198880..0ab6d65b6 100644 --- a/include/modules/operserv/info.h +++ b/include/modules/operserv/info.h @@ -25,8 +25,11 @@ class OperInfo : public Serialize::Object public: static constexpr const char *const NAME = "operinfo"; - virtual Serialize::Object *GetTarget() anope_abstract; - virtual void SetTarget(Serialize::Object *) anope_abstract; + virtual NickServ::Account *GetAccount() anope_abstract; + virtual void SetAccount(NickServ::Account *) anope_abstract; + + virtual ChanServ::Channel *GetChannel() anope_abstract; + virtual void SetChannel(ChanServ::Channel *) anope_abstract; virtual Anope::string GetInfo() anope_abstract; virtual void SetInfo(const Anope::string &) anope_abstract; diff --git a/include/modules/sql.h b/include/modules/sql.h index 263b99fd1..31e7af0bf 100644 --- a/include/modules/sql.h +++ b/include/modules/sql.h @@ -210,7 +210,7 @@ namespace SQL virtual Query BeginTransaction() anope_abstract; virtual Query Commit() anope_abstract; - virtual Serialize::ID GetID(const Anope::string &) anope_abstract; + virtual Serialize::ID GetID(const Anope::string &prefix, const Anope::string &type) anope_abstract; virtual Query GetTables(const Anope::string &prefix) anope_abstract; }; diff --git a/include/serialize.h b/include/serialize.h index 90aedc7ae..10ec14d16 100644 --- a/include/serialize.h +++ b/include/serialize.h @@ -41,11 +41,9 @@ namespace Serialize template<typename T, typename> class Type; template<typename T> class Reference; - // by id - extern std::unordered_map<ID, Object *> objects; extern std::vector<FieldBase *> serializableFields; - extern Object *GetID(ID id); + extern Object *GetID(Serialize::TypeBase *type, ID id); template<typename T> inline T GetObject(); @@ -240,7 +238,6 @@ class CoreExport Serialize::TypeBase : public Service std::set<Object *> objects; TypeBase(Module *owner, const Anope::string &n); - ~TypeBase(); void Unregister(); @@ -292,7 +289,7 @@ class Serialize::Type : public Base T* RequireID(ID id) { - Object *s = Serialize::GetID(id); + Object *s = Serialize::GetID(this, id); if (s == nullptr) return new T(this, id); @@ -353,7 +350,7 @@ class Serialize::Reference if (!valid) return nullptr; - Object *targ = GetID(id); + Object *targ = GetID(type, id); if (targ != nullptr && targ->GetSerializableType() == type) return anope_dynamic_static_cast<T*>(targ); diff --git a/modules/chanserv/access.cpp b/modules/chanserv/access.cpp index 44d21734e..a29524a73 100644 --- a/modules/chanserv/access.cpp +++ b/modules/chanserv/access.cpp @@ -202,7 +202,7 @@ class CommandCSAccess : public Command access = Serialize::New<AccessChanAccess *>(); if (na) - access->SetObj(na->GetAccount()); + access->SetAccount(na->GetAccount()); access->SetChannel(ci); access->SetMask(mask); access->SetCreator(source.GetNick()); @@ -263,7 +263,7 @@ class CommandCSAccess : public Command ChanServ::AccessGroup ag = source.AccessFor(ci); ChanServ::ChanAccess *u_highest = ag.Highest(); - if ((!u_highest || *u_highest <= *access) && !ag.founder && !source.IsOverride() && access->GetObj() != source.nc) + if ((!u_highest || *u_highest <= *access) && !ag.founder && !source.IsOverride() && access->GetAccount() != source.nc) { denied = true; return; @@ -305,7 +305,7 @@ class CommandCSAccess : public Command ChanServ::ChanAccess *access = ci->GetAccess(i - 1); if (mask.equals_ci(access->Mask())) { - if (access->GetObj() != source.nc && !u_access.founder && (!highest || *highest <= *access) && !source.HasOverridePriv("chanserv/access/modify")) + if (access->GetAccount() != source.nc && !u_access.founder && (!highest || *highest <= *access) && !source.HasOverridePriv("chanserv/access/modify")) { source.Reply(_("Access denied. You do not have enough privileges on \002{0}\002 to remove the access of \002{1}\002."), ci->GetName(), access->Mask()); } @@ -555,9 +555,6 @@ class CommandCSAccess : public Command " Use of this command requires the \002{4}\002 privilege on \037channel\037."), source.GetCommand(), ChanServ::ACCESS_INVALID + 1, ChanServ::ACCESS_FOUNDER - 1, "AUTOOP", "ACCESS_CHANGE"); - if (!Config->GetModule("chanserv/main")->Get<bool>("disallow_channel_access")) - source.Reply(_("The given \037mask\037 may also be a channel, which will use the access list from the other channel up to the given \037level\037.")); - //XXX show def levels source.Reply(_("\n" diff --git a/modules/chanserv/flags.cpp b/modules/chanserv/flags.cpp index 6ec65d104..f535aa136 100644 --- a/modules/chanserv/flags.cpp +++ b/modules/chanserv/flags.cpp @@ -108,55 +108,28 @@ class CommandCSFlags : public Command ChanServ::AccessGroup u_access = source.AccessFor(ci); ChanServ::ChanAccess *highest = u_access.Highest(); - NickServ::Nick *na = nullptr; - ChanServ::Channel *targ_ci = nullptr; - - if (IRCD->IsChannelValid(mask)) + NickServ::Nick *na = NickServ::FindNick(mask); + if (!na && Config->GetModule("chanserv/main")->Get<bool>("disallow_hostmask_access")) { - if (Config->GetModule("chanserv/main")->Get<bool>("disallow_channel_access")) - { - source.Reply(_("Channels may not be on access lists.")); - return; - } - - targ_ci = ChanServ::Find(mask); - if (targ_ci == NULL) - { - source.Reply(_("Channel \002{0}\002 isn't registered."), mask); - return; - } - else if (ci == targ_ci) - { - source.Reply(_("You can't add a channel to its own access list.")); - return; - } - - mask = targ_ci->GetName(); + source.Reply(_("Masks and unregistered users may not be on access lists.")); + return; } - else + + if (mask.find_first_of("!*@") == Anope::string::npos && !na) { - na = NickServ::FindNick(mask); - if (!na && Config->GetModule("chanserv/main")->Get<bool>("disallow_hostmask_access")) + User *targ = User::Find(mask, true); + if (targ != NULL) + mask = "*!*@" + targ->GetDisplayedHost(); + else { - source.Reply(_("Masks and unregistered users may not be on access lists.")); + source.Reply(_("\002{0}\002 isn't registered."), mask); return; } - else if (mask.find_first_of("!*@") == Anope::string::npos && !na) - { - User *targ = User::Find(mask, true); - if (targ != NULL) - mask = "*!*@" + targ->GetDisplayedHost(); - else - { - source.Reply(_("\002{0}\002 isn't registered."), mask); - return; - } - } - - if (na) - mask = na->GetNick(); } + if (na) + mask = na->GetNick(); + ChanServ::ChanAccess *current = NULL; unsigned current_idx; std::set<char> current_flags; @@ -275,9 +248,7 @@ class CommandCSFlags : public Command FlagsChanAccess *access = Serialize::New<FlagsChanAccess *>(); if (na) - access->SetObj(na->GetAccount()); - else if (targ_ci) - access->SetObj(targ_ci); + access->SetAccount(na->GetAccount()); access->SetChannel(ci); access->SetMask(mask); access->SetCreator(source.GetNick()); diff --git a/modules/chanserv/main/chanaccess.cpp b/modules/chanserv/main/chanaccess.cpp index 75c70ed9c..f2b170989 100644 --- a/modules/chanserv/main/chanaccess.cpp +++ b/modules/chanserv/main/chanaccess.cpp @@ -71,14 +71,14 @@ void ChanAccessImpl::SetMask(const Anope::string &n) Object::Set(&ChanAccessType<ChanServ::ChanAccess>::mask, n); } -Serialize::Object *ChanAccessImpl::GetObj() +NickServ::Account *ChanAccessImpl::GetAccount() { - return Get(&ChanAccessType<ChanServ::ChanAccess>::obj); + return Get(&ChanAccessType<ChanServ::ChanAccess>::account); } -void ChanAccessImpl::SetObj(Serialize::Object *o) +void ChanAccessImpl::SetAccount(NickServ::Account *acc) { - Object::Set(&ChanAccessType<ChanServ::ChanAccess>::obj, o); + Object::Set(&ChanAccessType<ChanServ::ChanAccess>::account, acc); } Anope::string ChanAccessImpl::Mask() @@ -89,14 +89,6 @@ Anope::string ChanAccessImpl::Mask() return GetMask(); } -NickServ::Account *ChanAccessImpl::GetAccount() -{ - if (!GetObj() || GetObj()->GetSerializableType()->GetName() != NickServ::Account::NAME) - return nullptr; - - return anope_dynamic_static_cast<NickServ::Account *>(GetObj()); -} - bool ChanAccessImpl::Matches(const User *u, NickServ::Account *acc) { if (this->GetAccount()) diff --git a/modules/chanserv/main/chanaccesstype.h b/modules/chanserv/main/chanaccesstype.h index b93747be7..4d95ee8b7 100644 --- a/modules/chanserv/main/chanaccesstype.h +++ b/modules/chanserv/main/chanaccesstype.h @@ -25,7 +25,7 @@ class ChanAccessType : public Serialize::Type<T> public: Serialize::ObjectField<ChanServ::ChanAccess, ChanServ::Channel *> channel; Serialize::Field<ChanServ::ChanAccess, Anope::string> mask; - Serialize::ObjectField<ChanServ::ChanAccess, Serialize::Object *> obj; + Serialize::ObjectField<ChanServ::ChanAccess, NickServ::Account *> account; Serialize::Field<ChanServ::ChanAccess, Anope::string> creator; Serialize::Field<ChanServ::ChanAccess, time_t> last_seen; Serialize::Field<ChanServ::ChanAccess, time_t> created; @@ -33,7 +33,7 @@ class ChanAccessType : public Serialize::Type<T> ChanAccessType(Module *me) : Serialize::Type<T>(me) , channel(this, "channel", &ChanServ::ChanAccess::channel, true) , mask(this, "mask", &ChanServ::ChanAccess::mask) - , obj(this, "obj", &ChanServ::ChanAccess::object, true) + , account(this, "account", &ChanServ::ChanAccess::account, true) , creator(this, "creator", &ChanServ::ChanAccess::creator) , last_seen(this, "last_seen", &ChanServ::ChanAccess::last_seen) , created(this, "created", &ChanServ::ChanAccess::created) diff --git a/modules/chanserv/xop.cpp b/modules/chanserv/xop.cpp index 91fc7e4f1..d41ed7ae6 100644 --- a/modules/chanserv/xop.cpp +++ b/modules/chanserv/xop.cpp @@ -153,58 +153,29 @@ class CommandCSXOP : public Command } } - NickServ::Nick *na = nullptr; - ChanServ::Channel *targ_ci = nullptr; + NickServ::Nick *na = NickServ::FindNick(mask); - if (IRCD->IsChannelValid(mask)) + if (!na && Config->GetModule("chanserv/main")->Get<bool>("disallow_hostmask_access")) { - if (Config->GetModule("chanserv/main")->Get<bool>("disallow_channel_access")) - { - source.Reply(_("Channels may not be on access lists.")); - return; - } - - targ_ci = ChanServ::Find(mask); - if (targ_ci == NULL) - { - source.Reply(_("Channel \002{0}\002 isn't registered."), mask); - return; - } - - if (ci == targ_ci) - { - source.Reply(_("You can't add a channel to its own access list.")); - return; - } - - mask = targ_ci->GetName(); + source.Reply(_("Masks and unregistered users may not be on access lists.")); + return; } - else - { - na = NickServ::FindNick(mask); - if (!na && Config->GetModule("chanserv/main")->Get<bool>("disallow_hostmask_access")) + if (mask.find_first_of("!*@") == Anope::string::npos && !na) + { + User *targ = User::Find(mask, true); + if (targ != NULL) + mask = "*!*@" + targ->GetDisplayedHost(); + else { - source.Reply(_("Masks and unregistered users may not be on access lists.")); + source.Reply(_("\002{0}\002 isn't registered."), mask); return; } - - if (mask.find_first_of("!*@") == Anope::string::npos && !na) - { - User *targ = User::Find(mask, true); - if (targ != NULL) - mask = "*!*@" + targ->GetDisplayedHost(); - else - { - source.Reply(_("\002{0}\002 isn't registered."), mask); - return; - } - } - - if (na) - mask = na->GetNick(); } + if (na) + mask = na->GetNick(); + for (unsigned i = 0; i < ci->GetAccessCount(); ++i) { ChanServ::ChanAccess *a = ci->GetAccess(i); @@ -231,9 +202,7 @@ class CommandCSXOP : public Command XOPChanAccess *acc = Serialize::New<XOPChanAccess *>(); if (na) - acc->SetObj(na->GetAccount()); - else if (targ_ci) - acc->SetObj(targ_ci); + acc->SetAccount(na->GetAccount()); acc->SetChannel(ci); acc->SetMask(mask); acc->SetCreator(source.GetNick()); diff --git a/modules/database/flatfile.cpp b/modules/database/flatfile.cpp index 27a51539c..ec6911ce2 100644 --- a/modules/database/flatfile.cpp +++ b/modules/database/flatfile.cpp @@ -129,7 +129,7 @@ class DBFlatFile : public Module HostServ::VHost *vhost = Serialize::New<HostServ::VHost *>(); if (vhost != nullptr) { - vhost->SetOwner(acc); + vhost->SetAccount(acc); vhost->SetIdent(data["vhost_ident"]); vhost->SetHost(data["vhost_host"]); vhost->SetCreator(data["vhost_creator"]); @@ -352,7 +352,7 @@ class DBFlatFile : public Module NickServ::Nick *nick = NickServ::FindNick(mask); if (nick != nullptr) - access->SetObj(nick->GetAccount()); + access->SetAccount(nick->GetAccount()); access->AccessUnserialize(data["data"]); } @@ -557,18 +557,18 @@ class DBFlatFile : public Module void LoadOperInfo(const Anope::string &type, std::map<Anope::string, Anope::string> &data) { - Serialize::Object *target = NickServ::FindAccount(data["target"]); - if (target == nullptr) - target = ChanServ::Find(data["target"]); + NickServ::Account *acc = NickServ::FindAccount(data["target"]); + ChanServ::Channel *chan = ChanServ::Find(data["target"]); - if (target == nullptr) + if (acc == nullptr && chan == nullptr) return; OperInfo *o = Serialize::New<OperInfo *>(); if (o == nullptr) return; - o->SetTarget(target); + o->SetAccount(acc); + o->SetChannel(chan); o->SetInfo(data["info"]); o->SetCreator(data["adder"]); try diff --git a/modules/database/old.cpp b/modules/database/old.cpp index 894b9125b..3a2b6ccb6 100644 --- a/modules/database/old.cpp +++ b/modules/database/old.cpp @@ -743,7 +743,7 @@ static void LoadVHosts() if (vhost == nullptr) continue; - vhost->SetOwner(na->GetAccount()); + vhost->SetAccount(na->GetAccount()); vhost->SetIdent(ident); vhost->SetHost(host); vhost->SetCreator(creator); diff --git a/modules/database/redis.cpp b/modules/database/redis.cpp deleted file mode 100644 index b6ce95241..000000000 --- a/modules/database/redis.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Anope IRC Services - * - * Copyright (C) 2013-2016 Anope Team <team@anope.org> - * - * This file is part of Anope. Anope is free software; you can - * redistribute it and/or modify it under the terms of the GNU - * General Public License as published by the Free Software - * Foundation, version 2. - * - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see see <http://www.gnu.org/licenses/>. - */ - -#include "module.h" -#include "modules/redis.h" - -using namespace Redis; - -class DatabaseRedis; -static DatabaseRedis *me; - -class TypeLoader : public Interface -{ - Serialize::TypeBase *type; - - public: - TypeLoader(Module *creator, Serialize::TypeBase *t) : Interface(creator), type(t) { } - - void OnResult(const Reply &r) override; -}; - -class ObjectLoader : public Interface -{ - Serialize::Object *obj; - - public: - ObjectLoader(Module *creator, Serialize::Object *s) : Interface(creator), obj(s) { } - - void OnResult(const Reply &r) override; -}; - -class FieldLoader : public Interface -{ - Serialize::Object *obj; - Serialize::FieldBase *field; - - public: - FieldLoader(Module *creator, Serialize::Object *o, Serialize::FieldBase *f) : Interface(creator), obj(o), field(f) { } - - void OnResult(const Reply &) override; -}; - -class SubscriptionListener : public Interface -{ - public: - SubscriptionListener(Module *creator) : Interface(creator) { } - - void OnResult(const Reply &r) override; -}; - -class DatabaseRedis : public Module - , public EventHook<Event::LoadDatabase> - , public EventHook<Event::SerializeEvents> -{ - SubscriptionListener sl; - - public: - ServiceReference<Provider> redis; - - DatabaseRedis(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) - , EventHook<Event::LoadDatabase>(this) - , EventHook<Event::SerializeEvents>(this) - , sl(this) - { - me = this; - } - - void OnReload(Configuration::Conf *conf) override - { - Configuration::Block *block = conf->GetModule(this); - this->redis = ServiceReference<Provider>(block->Get<Anope::string>("engine", "redis/main")); - } - - EventReturn OnLoadDatabase() override - { - if (!redis) - return EVENT_STOP; - - for (Serialize::TypeBase *type : Serialize::TypeBase::GetTypes()) - this->OnSerializeTypeCreate(type); - - while (redis->BlockAndProcess()); - - redis->Subscribe(&this->sl, "anope"); - - return EVENT_STOP; - } - - void OnSerializeTypeCreate(Serialize::TypeBase *sb) - { - std::vector<Anope::string> args = { "SMEMBERS", "ids:" + sb->GetName() }; - - redis->SendCommand(new TypeLoader(this, sb), args); - } - - EventReturn OnSerializeList(Serialize::TypeBase *type, std::vector<Serialize::ID> &ids) override - { - return EVENT_CONTINUE; - } - - EventReturn OnSerializeFind(Serialize::TypeBase *type, Serialize::FieldBase *field, const Anope::string &value, Serialize::ID &id) override - { - return EVENT_CONTINUE; - } - - EventReturn OnSerializeGet(Serialize::Object *object, Serialize::FieldBase *field, Anope::string &value) override - { - return EVENT_CONTINUE; - } - - EventReturn OnSerializeGetRefs(Serialize::Object *object, Serialize::TypeBase *type, std::vector<Serialize::Edge> &) override - { - return EVENT_CONTINUE; - } - - EventReturn OnSerializeDeref(Serialize::ID id, Serialize::TypeBase *type) override - { - return EVENT_CONTINUE; - } - - EventReturn OnSerializeGetSerializable(Serialize::Object *object, Serialize::FieldBase *field, Anope::string &type, Serialize::ID &value) override - { - return EVENT_CONTINUE; - } - - EventReturn OnSerializeSet(Serialize::Object *object, Serialize::FieldBase *field, const Anope::string &value) override - { - std::vector<Anope::string> args; - - redis->StartTransaction(); - - const Anope::string &old = field->SerializeToString(object); - args = { "SREM", "lookup:" + object->GetSerializableType()->GetName() + ":" + field->serialize_name + ":" + old, stringify(object->id) }; - redis->SendCommand(nullptr, args); - - // add object to type set - args = { "SADD", "ids:" + object->GetSerializableType()->GetName(), stringify(object->id) }; - redis->SendCommand(nullptr, args); - - // add key to key set - args = { "SADD", "keys:" + stringify(object->id), field->serialize_name }; - redis->SendCommand(nullptr, args); - - // set value - args = { "SET", "values:" + stringify(object->id) + ":" + field->serialize_name, value }; - redis->SendCommand(nullptr, args); - - // lookup - args = { "SADD", "lookup:" + object->GetSerializableType()->GetName() + ":" + field->serialize_name + ":" + value, stringify(object->id) }; - redis->SendCommand(nullptr, args); - - redis->CommitTransaction(); - - return EVENT_CONTINUE; - } - - EventReturn OnSerializeSetSerializable(Serialize::Object *object, Serialize::FieldBase *field, Serialize::Object *value) override - { - return OnSerializeSet(object, field, stringify(value->id)); - } - - EventReturn OnSerializeUnset(Serialize::Object *object, Serialize::FieldBase *field) override - { - std::vector<Anope::string> args; - - redis->StartTransaction(); - - const Anope::string &old = field->SerializeToString(object); - args = { "SREM", "lookup:" + object->GetSerializableType()->GetName() + ":" + field->serialize_name + ":" + old, stringify(object->id) }; - redis->SendCommand(nullptr, args); - - // remove field from set - args = { "SREM", "keys:" + stringify(object->id), field->serialize_name }; - redis->SendCommand(nullptr, args); - - redis->CommitTransaction(); - - return EVENT_CONTINUE; - } - - EventReturn OnSerializeUnsetSerializable(Serialize::Object *object, Serialize::FieldBase *field) override - { - return OnSerializeUnset(object, field); - } - - EventReturn OnSerializeHasField(Serialize::Object *object, Serialize::FieldBase *field) override - { - return EVENT_CONTINUE; - } - - EventReturn OnSerializableGetId(Serialize::ID &id) override - { - std::vector<Anope::string> args = { "INCR", "id" }; - - auto f = [&](const Reply &r) - { - id = r.i; - }; - - FInterface inter(this, f); - redis->SendCommand(&inter, args); - while (redis->BlockAndProcess()); - return EVENT_ALLOW; - } - - void OnSerializableCreate(Serialize::Object *) override - { - } - - void OnSerializableDelete(Serialize::Object *obj) override - { - std::vector<Anope::string> args; - - redis->StartTransaction(); - - for (Serialize::FieldBase *field : obj->GetSerializableType()->GetFields()) - { - Anope::string value = field->SerializeToString(obj); - - args = { "SREM", "lookup:" + obj->GetSerializableType()->GetName() + ":" + field->serialize_name + ":" + value, stringify(obj->id) }; - redis->SendCommand(nullptr, args); - - args = { "DEL", "values:" + stringify(obj->id) + ":" + field->serialize_name }; - redis->SendCommand(nullptr, args); - - args = { "SREM", "keys:" + stringify(obj->id), field->serialize_name }; - redis->SendCommand(nullptr, args); - } - - args = { "SREM", "ids:" + obj->GetSerializableType()->GetName(), stringify(obj->id) }; - redis->SendCommand(nullptr, args); - - redis->CommitTransaction(); - } -}; - -void TypeLoader::OnResult(const Reply &r) -{ - if (r.type != Reply::MULTI_BULK || !me->redis) - { - delete this; - return; - } - - for (unsigned i = 0; i < r.multi_bulk.size(); ++i) - { - const Reply *reply = r.multi_bulk[i]; - - if (reply->type != Reply::BULK) - continue; - - int64_t id; - try - { - id = convertTo<int64_t>(reply->bulk); - } - catch (const ConvertException &) - { - continue; - } - - Serialize::Object *obj = type->Require(id); - if (obj == nullptr) - { - Anope::Logger.Debug("Unable to require object #{0} of type {1}", id, type->GetName()); - continue; - } - - std::vector<Anope::string> args = { "SMEMBERS", "keys:" + stringify(id) }; - - me->redis->SendCommand(new ObjectLoader(me, obj), args); - } - - delete this; -} - -void ObjectLoader::OnResult(const Reply &r) -{ - if (r.type != Reply::MULTI_BULK || r.multi_bulk.empty() || !me->redis) - { - delete this; - return; - } - - Serialize::TypeBase *type = obj->GetSerializableType(); - - for (Reply *reply : r.multi_bulk) - { - const Anope::string &key = reply->bulk; - Serialize::FieldBase *field = type->GetField(key); - - if (field == nullptr) - continue; - - std::vector<Anope::string> args = { "GET", "values:" + stringify(obj->id) + ":" + key }; - - me->redis->SendCommand(new FieldLoader(me, obj, field), args); - } - - delete this; -} - -void FieldLoader::OnResult(const Reply &r) -{ - Anope::Logger.Debug2("Setting field {0} of object #{1} of type {2} to {3}", field->serialize_name, obj->id, obj->GetSerializableType()->GetName(), r.bulk); - field->UnserializeFromString(obj, r.bulk); - - delete this; -} - -void SubscriptionListener::OnResult(const Reply &r) -{ - /* - * message - * anope - * message - * - * set 4 email adam@anope.org - * unset 4 email - * create 4 NickCore - * delete 4 - */ - - const Anope::string &message = r.multi_bulk[2]->bulk; - Anope::string command; - spacesepstream sep(message); - - sep.GetToken(command); - - if (command == "set" || command == "unset") - { - Anope::string sid, key, value; - - sep.GetToken(sid); - sep.GetToken(key); - value = sep.GetRemaining(); - - Serialize::ID id; - try - { - id = convertTo<Serialize::ID>(sid); - } - catch (const ConvertException &ex) - { - this->GetOwner()->logger.Debug("unable to get id for SL update key {0}", sid); - return; - } - - Serialize::Object *obj = Serialize::GetID(id); - if (obj == nullptr) - { - this->GetOwner()->logger.Debug("message for unknown object #{0}", id); - return; - } - - Serialize::FieldBase *field = obj->GetSerializableType()->GetField(key); - if (field == nullptr) - { - this->GetOwner()->logger.Debug("message for unknown field of object #{0}: {1}", id, key); - return; - } - - this->GetOwner()->logger.Debug2("Setting field {0} of object #{1} of type {2} to {3}", - field->serialize_name, obj->id, obj->GetSerializableType()->GetName(), value); - - field->UnserializeFromString(obj, value); - } - else if (command == "create") - { - Anope::string sid, stype; - - sep.GetToken(sid); - sep.GetToken(stype); - - Serialize::ID id; - try - { - id = convertTo<Serialize::ID>(sid); - } - catch (const ConvertException &ex) - { - this->GetOwner()->logger.Debug("unable to get id for SL update key {0}", sid); - return; - } - - Serialize::TypeBase *type = Serialize::TypeBase::Find(stype); - if (type == nullptr) - { - this->GetOwner()->logger.Debug("message create for nonexistant type {0}", stype); - return; - } - - Serialize::Object *obj = type->Require(id); - if (obj == nullptr) - { - this->GetOwner()->logger.Debug("require for message create type {0} id #{1} returned nullptr", type->GetName(), id); - return; - } - } - else if (command == "delete") - { - Anope::string sid; - - sep.GetToken(sid); - - Serialize::ID id; - try - { - id = convertTo<Serialize::ID>(sid); - } - catch (const ConvertException &ex) - { - this->GetOwner()->logger.Debug("unable to get id for SL update key {0}", sid); - return; - } - - Serialize::Object *obj = Serialize::GetID(id); - if (obj == nullptr) - { - this->GetOwner()->logger.Debug("message for unknown object #{0}", id); - return; - } - - obj->Delete(); - } - else - { - this->GetOwner()->logger.Debug("unknown message: {0}", message); - } -} - -MODULE_INIT(DatabaseRedis) diff --git a/modules/database/sql.cpp b/modules/database/sql.cpp index 00c45a4bc..bd5a96b90 100644 --- a/modules/database/sql.cpp +++ b/modules/database/sql.cpp @@ -157,14 +157,12 @@ class DBSQL : public Module, public Pipe { for (Serialize::FieldBase *field : type->GetFields()) { - if (field->is_object) + if (field->is_object && object->GetSerializableType()->GetName() == field->GetTypeName()) { Anope::string table = prefix + type->GetName(); - Query query = "SELECT " + table + ".id FROM " + table + - " INNER JOIN " + prefix + "objects AS o ON " + - table + "." + field->serialize_name + " = o.id " - "WHERE o.id = @id@"; + Query query = "SELECT id FROM " + table + + " WHERE " + field->serialize_name + " = @id@"; query.SetValue("id", object->id, false); @@ -234,16 +232,15 @@ class DBSQL : public Module, public Pipe { StartTransaction(); - Query query = "SELECT `" + field->serialize_name + "`,j1.type AS " + field->serialize_name + "_type FROM `" + prefix + object->GetSerializableType()->GetName() + "` " - "JOIN `" + prefix + "objects` AS j1 ON " + prefix + object->GetSerializableType()->GetName() + "." + field->serialize_name + " = j1.id " - "WHERE " + prefix + object->GetSerializableType()->GetName() + ".id = @id@"; + Query query = "SELECT `" + field->serialize_name + "` FROM `" + prefix + object->GetSerializableType()->GetName() + "` " + "WHERE id = @id@"; query.SetValue("id", object->id, false); Result res = Run(query); if (res.Rows() == 0) return EVENT_CONTINUE; - type = res.Get(0, field->serialize_name + "_type"); + type = field->GetTypeName(); try { value = convertTo<Serialize::ID>(res.Get(0, field->serialize_name)); @@ -350,32 +347,31 @@ class DBSQL : public Module, public Pipe } } - EventReturn OnSerializableGetId(Serialize::ID &id) override + EventReturn OnSerializableGetId(Serialize::TypeBase *type, Serialize::ID &id) override { if (!SQL) return EVENT_CONTINUE; StartTransaction(); - id = SQL->GetID(prefix); + for (Query &q : SQL->CreateTable(prefix, type)) + Run(q); + + id = SQL->GetID(prefix, type->GetName()); return EVENT_ALLOW; } void OnSerializableCreate(Serialize::Object *object) override { - StartTransaction(); - - Query q = Query("INSERT INTO `" + prefix + "objects` (`id`,`type`) VALUES (@id@, @type@)"); - q.SetValue("id", object->id, false); - q.SetValue("type", object->GetSerializableType()->GetName()); - Run(q); } void OnSerializableDelete(Serialize::Object *object) override { StartTransaction(); - Query query("DELETE FROM `" + prefix + "objects` WHERE `id` = " + stringify(object->id)); + Serialize::TypeBase *type = object->GetSerializableType(); + + Query query("DELETE FROM `" + prefix + type->GetName() + "` WHERE `id` = " + stringify(object->id)); Run(query); } }; diff --git a/modules/extra/mysql.cpp b/modules/extra/mysql.cpp index 66b4ffa85..a61181f37 100644 --- a/modules/extra/mysql.cpp +++ b/modules/extra/mysql.cpp @@ -83,7 +83,7 @@ class MySQLResult : public Result unsigned num_fields = mysql_num_fields(res); MYSQL_FIELD *fields = mysql_fetch_fields(res); - /* It is not thread safe to log anything here using Log(this->owner) now :( */ + /* It is not thread safe to log anything here using the loggers now :( */ if (!num_fields || !fields) return; @@ -164,7 +164,7 @@ class MySQLService : public Provider Query BeginTransaction() override; Query Commit() override; - Serialize::ID GetID(const Anope::string &) override; + Serialize::ID GetID(const Anope::string &prefix, const Anope::string &type) override; Query GetTables(const Anope::string &prefix) override; @@ -241,7 +241,7 @@ class ModuleSQL : public Module if (i == config->CountBlock("mysql")) { - Log(LogType::NORMAL, "mysql") << "MySQL: Removing server connection " << cname; + logger.Log("Removing server connection {0}", cname); delete s; this->MySQLServices.erase(cname); @@ -266,11 +266,11 @@ class ModuleSQL : public Module MySQLService *ss = new MySQLService(this, connname, database, server, user, password, port); this->MySQLServices.insert(std::make_pair(connname, ss)); - Log(LogType::NORMAL, "mysql") << "MySQL: Successfully connected to server " << connname << " (" << server << ")"; + logger.Log(_("Successfully connected to server {0} ({1})"), connname, server); } catch (const SQL::Exception &ex) { - Log(LogType::NORMAL, "mysql") << "MySQL: " << ex.GetReason(); + logger.Log(ex.GetReason()); } } } @@ -394,8 +394,6 @@ std::vector<Query> MySQLService::InitSchema(const Anope::string &prefix) { std::vector<Query> queries; - queries.push_back(Query("CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` bigint(20) NOT NULL PRIMARY KEY, `type` TINYTEXT) ENGINE=InnoDB")); - return queries; } @@ -431,11 +429,7 @@ std::vector<Query> MySQLService::CreateTable(const Anope::string &prefix, Serial if (active_schema.find(prefix + base->GetName()) == active_schema.end()) { - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + base->GetName() + "` (`id` bigint(20) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB"; - queries.push_back(t); - - t = "ALTER TABLE `" + prefix + base->GetName() + "` " - "ADD CONSTRAINT `" + base->GetName() + "_id_fk` FOREIGN KEY (`id`) REFERENCES `" + prefix + "objects` (`id`) ON DELETE CASCADE"; + Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + base->GetName() + "` (`id` bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) ENGINE=InnoDB"; queries.push_back(t); active_schema[prefix + base->GetName()]; @@ -455,13 +449,13 @@ std::vector<Query> MySQLService::AlterTable(const Anope::string &prefix, Seriali { Anope::string buf = "ALTER TABLE `" + prefix + table + "` ADD COLUMN `" + field->serialize_name + "` "; - if (!field->object) + if (!field->is_object) { buf += "TINYTEXT"; } else { - buf += "bigint(20), ADD CONSTRAINT `" + table + "_" + field->serialize_name + "_fk` FOREIGN KEY (`" + field->serialize_name + "`) REFERENCES `" + prefix + "objects` (`id`) ON DELETE "; + buf += "bigint(20), ADD CONSTRAINT `" + table + "_" + field->serialize_name + "_fk` FOREIGN KEY (`" + field->serialize_name + "`) REFERENCES `" + prefix + field->GetTypeName() + "` (`id`) ON DELETE "; if (field->depends) buf += "CASCADE"; @@ -506,21 +500,12 @@ Query MySQLService::Commit() return Query("COMMIT"); } -Serialize::ID MySQLService::GetID(const Anope::string &prefix) +Serialize::ID MySQLService::GetID(const Anope::string &prefix, const Anope::string &type) { - Query query = "SELECT `id` FROM `" + prefix + "objects` ORDER BY `id` DESC LIMIT 1"; - Serialize::ID id = 1; - + Query query = "INSERT INTO `" + prefix + type + "` VALUES ()"; Result res = RunQuery(query); - if (res.Rows()) - { - id = convertTo<Serialize::ID>(res.Get(0, "id")); - - /* next id */ - ++id; - } - /* OnSerializableCreate is called immediately after this which does the insert */ + Serialize::ID id = res.GetID(); return id; } @@ -542,7 +527,7 @@ void MySQLService::Connect() if (!connect) throw SQL::Exception("Unable to connect to MySQL service " + this->GetName() + ": " + mysql_error(this->sql)); - Log(LogType::DEBUG) << "Successfully connected to MySQL service " << this->GetName() << " at " << this->server << ":" << this->port; + this->GetOwner()->logger.Debug("Successfully connected to MySQL service {0} at {1}:{2}", this->GetName(), this->server, this->port); } diff --git a/modules/hostserv/add.cpp b/modules/hostserv/add.cpp index 37de7d2bb..9960f407c 100644 --- a/modules/hostserv/add.cpp +++ b/modules/hostserv/add.cpp @@ -110,7 +110,7 @@ class CommandHSAdd : public Command return; } - vhost->SetOwner(na->GetAccount()); + vhost->SetAccount(na->GetAccount()); vhost->SetIdent(user); vhost->SetHost(host); vhost->SetCreator(source.GetNick()); diff --git a/modules/hostserv/main/vhost.cpp b/modules/hostserv/main/vhost.cpp index 635e3a5b4..7c08fe838 100644 --- a/modules/hostserv/main/vhost.cpp +++ b/modules/hostserv/main/vhost.cpp @@ -18,15 +18,16 @@ */ #include "vhosttype.h" +#include "modules/nickserv.h" -Serialize::Object *VHostImpl::GetOwner() +NickServ::Account *VHostImpl::GetAccount() { - return Get(&VHostType::owner); + return Get(&VHostType::account); } -void VHostImpl::SetOwner(Serialize::Object *owner) +void VHostImpl::SetAccount(NickServ::Account *acc) { - Set(&VHostType::owner, owner); + Set(&VHostType::account, acc); } Anope::string VHostImpl::GetIdent() diff --git a/modules/hostserv/main/vhost.h b/modules/hostserv/main/vhost.h index bdc6509d7..b96e20644 100644 --- a/modules/hostserv/main/vhost.h +++ b/modules/hostserv/main/vhost.h @@ -25,7 +25,7 @@ class VHostImpl : public HostServ::VHost { friend class VHostType; - Serialize::Storage<Serialize::Object *> owner; + Serialize::Storage<NickServ::Account *> account; Serialize::Storage<Anope::string> vident; Serialize::Storage<Anope::string> vhost; Serialize::Storage<Anope::string> creator; @@ -35,8 +35,8 @@ class VHostImpl : public HostServ::VHost public: using HostServ::VHost::VHost; - Serialize::Object *GetOwner() override; - void SetOwner(Serialize::Object *) override; + NickServ::Account *GetAccount() override; + void SetAccount(NickServ::Account *) override; Anope::string GetIdent() override; void SetIdent(const Anope::string &) override; diff --git a/modules/hostserv/main/vhosttype.cpp b/modules/hostserv/main/vhosttype.cpp index ee73840bf..76ac5476b 100644 --- a/modules/hostserv/main/vhosttype.cpp +++ b/modules/hostserv/main/vhosttype.cpp @@ -21,7 +21,7 @@ #include "vhosttype.h" VHostType::VHostType(Module *me) : Serialize::Type<VHostImpl>(me) - , owner(this, "owner", &VHostImpl::owner, true) + , account(this, "account", &VHostImpl::account, true) , vident(this, "vident", &VHostImpl::vident) , vhost(this, "vhost", &VHostImpl::vhost) , creator(this, "creator", &VHostImpl::creator) diff --git a/modules/hostserv/main/vhosttype.h b/modules/hostserv/main/vhosttype.h index 3be60f518..945110563 100644 --- a/modules/hostserv/main/vhosttype.h +++ b/modules/hostserv/main/vhosttype.h @@ -22,7 +22,7 @@ class VHostType : public Serialize::Type<VHostImpl> { public: - Serialize::ObjectField<VHostImpl, Serialize::Object *> owner; + Serialize::ObjectField<VHostImpl, NickServ::Account *> account; Serialize::Field<VHostImpl, Anope::string> vident; Serialize::Field<VHostImpl, Anope::string> vhost; Serialize::Field<VHostImpl, Anope::string> creator; diff --git a/modules/hostserv/request.cpp b/modules/hostserv/request.cpp index bef1f1548..a74dcacad 100644 --- a/modules/hostserv/request.cpp +++ b/modules/hostserv/request.cpp @@ -291,7 +291,7 @@ class CommandHSActivate : public Command return; } - vhost->SetOwner(na->GetAccount()); + vhost->SetAccount(na->GetAccount()); vhost->SetIdent(req->GetIdent()); vhost->SetHost(req->GetHost()); vhost->SetCreator(source.GetNick()); diff --git a/modules/memoserv/main/memoinfo.cpp b/modules/memoserv/main/memoinfo.cpp index aa5ca71e4..8f5efc3fd 100644 --- a/modules/memoserv/main/memoinfo.cpp +++ b/modules/memoserv/main/memoinfo.cpp @@ -37,6 +37,7 @@ unsigned MemoInfoImpl::GetIndex(MemoServ::Memo *m) void MemoInfoImpl::Del(unsigned index) { +#warning "delete on serializable" delete GetMemo(index); } @@ -51,14 +52,24 @@ bool MemoInfoImpl::HasIgnore(User *u) return false; } -Serialize::Object *MemoInfoImpl::GetOwner() +NickServ::Account *MemoInfoImpl::GetAccount() { - return Get(&MemoInfoType::owner); + return Get(&MemoInfoType::account); } -void MemoInfoImpl::SetOwner(Serialize::Object *o) +void MemoInfoImpl::SetAccount(NickServ::Account *account) { - Set(&MemoInfoType::owner, o); + Set(&MemoInfoType::account, account); +} + +ChanServ::Channel *MemoInfoImpl::GetChannel() +{ + return Get(&MemoInfoType::channel); +} + +void MemoInfoImpl::SetChannel(ChanServ::Channel *channel) +{ + Set(&MemoInfoType::channel, channel); } int16_t MemoInfoImpl::GetMemoMax() diff --git a/modules/memoserv/main/memoinfo.h b/modules/memoserv/main/memoinfo.h index cbe37e456..78d6f005b 100644 --- a/modules/memoserv/main/memoinfo.h +++ b/modules/memoserv/main/memoinfo.h @@ -23,7 +23,8 @@ class MemoInfoImpl : public MemoServ::MemoInfo { friend class MemoInfoType; - Serialize::Storage<Serialize::Object *> owner; + Serialize::Storage<NickServ::Account *> account; + Serialize::Storage<ChanServ::Channel *> channel; Serialize::Storage<int16_t> memomax; Serialize::Storage<bool> hardmax; @@ -35,8 +36,11 @@ class MemoInfoImpl : public MemoServ::MemoInfo void Del(unsigned index) override; bool HasIgnore(User *u) override; - Serialize::Object *GetOwner() override; - void SetOwner(Serialize::Object *) override; + NickServ::Account *GetAccount() override; + void SetAccount(NickServ::Account *) override; + + ChanServ::Channel *GetChannel() override; + void SetChannel(ChanServ::Channel *) override; int16_t GetMemoMax() override; void SetMemoMax(const int16_t &) override; diff --git a/modules/memoserv/main/memoinfotype.cpp b/modules/memoserv/main/memoinfotype.cpp index 27e3bba75..1dcccec98 100644 --- a/modules/memoserv/main/memoinfotype.cpp +++ b/modules/memoserv/main/memoinfotype.cpp @@ -21,7 +21,8 @@ #include "memoinfotype.h" MemoInfoType::MemoInfoType(Module *me) : Serialize::Type<MemoInfoImpl>(me) - , owner(this, "owner", &MemoInfoImpl::owner, true) + , account(this, "account", &MemoInfoImpl::account, true) + , channel(this, "channel", &MemoInfoImpl::channel, true) , memomax(this, "memomax", &MemoInfoImpl::memomax) , hardmax(this, "hardmax", &MemoInfoImpl::hardmax) { diff --git a/modules/memoserv/main/memoinfotype.h b/modules/memoserv/main/memoinfotype.h index 1a45b361a..94cc8fde4 100644 --- a/modules/memoserv/main/memoinfotype.h +++ b/modules/memoserv/main/memoinfotype.h @@ -22,7 +22,8 @@ class MemoInfoType : public Serialize::Type<MemoInfoImpl> { public: - Serialize::ObjectField<MemoInfoImpl, Serialize::Object *> owner; + Serialize::ObjectField<MemoInfoImpl, NickServ::Account *> account; + Serialize::ObjectField<MemoInfoImpl, ChanServ::Channel *> channel; Serialize::Field<MemoInfoImpl, int16_t> memomax; Serialize::Field<MemoInfoImpl, bool> hardmax; diff --git a/modules/memoserv/main/memoserv.cpp b/modules/memoserv/main/memoserv.cpp index 3b2b7cd17..757b95563 100644 --- a/modules/memoserv/main/memoserv.cpp +++ b/modules/memoserv/main/memoserv.cpp @@ -189,7 +189,7 @@ class MemoServCore : public Module, public MemoServ::MemoServService if (create && !ci->GetMemos()) { MemoServ::MemoInfo *mi = Serialize::New<MemoServ::MemoInfo *>(); - mi->SetOwner(ci); + mi->SetChannel(ci); } return ci->GetMemos(); } @@ -208,7 +208,7 @@ class MemoServCore : public Module, public MemoServ::MemoServService if (create && !na->GetAccount()->GetMemos()) { MemoServ::MemoInfo *mi = Serialize::New<MemoServ::MemoInfo *>(); - mi->SetOwner(na->GetAccount()); + mi->SetAccount(na->GetAccount()); } return na->GetAccount()->GetMemos(); } @@ -238,14 +238,14 @@ class MemoServCore : public Module, public MemoServ::MemoServService void OnNickRegister(User *, NickServ::Nick *na, const Anope::string &) override { MemoServ::MemoInfo *mi = Serialize::New<MemoServ::MemoInfo *>(); - mi->SetOwner(na->GetAccount()); + mi->SetAccount(na->GetAccount()); mi->SetMemoMax(Config->GetModule(this)->Get<int>("maxmemos")); } void OnChanRegistered(ChanServ::Channel *ci) override { MemoServ::MemoInfo *mi = Serialize::New<MemoServ::MemoInfo *>(); - mi->SetOwner(ci); + mi->SetChannel(ci); mi->SetMemoMax(Config->GetModule(this)->Get<int>("maxmemos")); } diff --git a/modules/operserv/info.cpp b/modules/operserv/info.cpp index c052c46ae..7a90c1bf6 100644 --- a/modules/operserv/info.cpp +++ b/modules/operserv/info.cpp @@ -27,15 +27,19 @@ class OperInfoImpl : public OperInfo { friend class OperInfoType; - Serialize::Storage<Serialize::Object *> target; + Serialize::Storage<NickServ::Account *> account; + Serialize::Storage<ChanServ::Channel *> channel; Serialize::Storage<Anope::string> info, creator; Serialize::Storage<time_t> created; public: using OperInfo::OperInfo; - Serialize::Object *GetTarget() override; - void SetTarget(Serialize::Object *) override; + NickServ::Account *GetAccount() override; + void SetAccount(NickServ::Account *) override; + + ChanServ::Channel *GetChannel() override; + void SetChannel(ChanServ::Channel *) override; Anope::string GetInfo() override; void SetInfo(const Anope::string &) override; @@ -50,12 +54,14 @@ class OperInfoImpl : public OperInfo class OperInfoType : public Serialize::Type<OperInfoImpl> { public: - Serialize::ObjectField<OperInfoImpl, Serialize::Object *> target; + Serialize::ObjectField<OperInfoImpl, NickServ::Account *> account; + Serialize::ObjectField<OperInfoImpl, ChanServ::Channel *> channel; Serialize::Field<OperInfoImpl, Anope::string> info, creator; Serialize::Field<OperInfoImpl, time_t> created; OperInfoType(Module *c) : Serialize::Type<OperInfoImpl>(c) - , target(this, "target", &OperInfoImpl::target, true) + , account(this, "account", &OperInfoImpl::account, true) + , channel(this, "channel", &OperInfoImpl::channel, true) , info(this, "info", &OperInfoImpl::info) , creator(this, "adder", &OperInfoImpl::creator) , created(this, "created", &OperInfoImpl::created) @@ -63,14 +69,24 @@ class OperInfoType : public Serialize::Type<OperInfoImpl> } }; -Serialize::Object *OperInfoImpl::GetTarget() +NickServ::Account *OperInfoImpl::GetAccount() +{ + return Get(&OperInfoType::account); +} + +void OperInfoImpl::SetAccount(NickServ::Account *account) { - return Get(&OperInfoType::target); + Set(&OperInfoType::account, account); } -void OperInfoImpl::SetTarget(Serialize::Object *t) +ChanServ::Channel *OperInfoImpl::GetChannel() { - Set(&OperInfoType::target, t); + return Get(&OperInfoType::channel); +} + +void OperInfoImpl::SetChannel(ChanServ::Channel *channel) +{ + Set(&OperInfoType::channel, channel); } Anope::string OperInfoImpl::GetInfo() @@ -118,7 +134,10 @@ class CommandOSInfo : public Command { const Anope::string &cmd = params[0], target = params[1], info = params.size() > 2 ? params[2] : ""; + NickServ::Account *account = nullptr; + ChanServ::Channel *channel = nullptr; Serialize::Object *e; + if (IRCD->IsChannelValid(target)) { ChanServ::Channel *ci = ChanServ::Find(target); @@ -128,6 +147,7 @@ class CommandOSInfo : public Command return; } + channel = ci; e = ci; } else @@ -139,7 +159,8 @@ class CommandOSInfo : public Command return; } - e = na->GetAccount(); + account = na->GetAccount(); + e = account; } if (cmd.equals_ci("ADD")) @@ -165,7 +186,8 @@ class CommandOSInfo : public Command } OperInfo *o = Serialize::New<OperInfo *>(); - o->SetTarget(e); + o->SetAccount(account); + o->SetChannel(channel); o->SetInfo(info); o->SetCreator(source.GetNick()); o->SetCreated(Anope::CurTime); diff --git a/modules/redis.cpp b/modules/redis.cpp deleted file mode 100644 index 47d89ef42..000000000 --- a/modules/redis.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Anope IRC Services - * - * Copyright (C) 2013-2016 Anope Team <team@anope.org> - * - * This file is part of Anope. Anope is free software; you can - * redistribute it and/or modify it under the terms of the GNU - * General Public License as published by the Free Software - * Foundation, version 2. - * - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see see <http://www.gnu.org/licenses/>. - */ - -#include "module.h" -#include "modules/redis.h" - -using namespace Redis; - -class MyRedisService; - -class RedisSocket : public BinarySocket, public ConnectionSocket -{ - size_t ParseReply(Reply &r, const char *buf, size_t l); - public: - MyRedisService *provider; - std::deque<Interface *> interfaces; - std::map<Anope::string, Interface *> subinterfaces; - - RedisSocket(MyRedisService *pro, bool v6) : Socket(-1, v6), provider(pro) { } - - ~RedisSocket(); - - void OnConnect() override; - void OnError(const Anope::string &error) override; - - bool Read(const char *buffer, size_t l) override; -}; - -class Transaction : public Interface -{ - public: - std::deque<Interface *> interfaces; - - Transaction(Module *creator) : Interface(creator) { } - - ~Transaction() - { - for (unsigned i = 0; i < interfaces.size(); ++i) - { - Interface *inter = interfaces[i]; - - if (!inter) - continue; - - inter->OnError("Interface going away"); - } - } - - void OnResult(const Reply &r) override - { - /* This is a multi bulk reply of the results of the queued commands - * in this transaction - */ - - this->GetOwner()->logger.Debug2("transaction complete with {0} results", r.multi_bulk.size()); - - for (unsigned i = 0; i < r.multi_bulk.size(); ++i) - { - const Reply *reply = r.multi_bulk[i]; - - if (interfaces.empty()) - break; - - Interface *inter = interfaces.front(); - interfaces.pop_front(); - - if (inter) - inter->OnResult(*reply); - } - } -}; - -class MyRedisService : public Provider -{ - public: - Anope::string host; - int port; - unsigned db; - - RedisSocket *sock, *sub; - - Transaction ti; - bool in_transaction; - - MyRedisService(Module *c, const Anope::string &n, const Anope::string &h, int p, unsigned d) : Provider(c, n), host(h), port(p), db(d), sock(NULL), sub(NULL), - ti(c), in_transaction(false) - { - sock = new RedisSocket(this, host.find(':') != Anope::string::npos); - sock->Connect(host, port); - - sub = new RedisSocket(this, host.find(':') != Anope::string::npos); - sub->Connect(host, port); - } - - ~MyRedisService() - { - if (sock) - { - sock->flags[SF_DEAD] = true; - sock->provider = NULL; - } - - if (sub) - { - sub->flags[SF_DEAD] = true; - sub->provider = NULL; - } - } - - private: - inline void Pack(std::vector<char> &buffer, const char *buf, size_t sz = 0) - { - if (!sz) - sz = strlen(buf); - - size_t old_size = buffer.size(); - buffer.resize(old_size + sz); - std::copy(buf, buf + sz, buffer.begin() + old_size); - } - - void Send(RedisSocket *s, Interface *i, const std::vector<std::pair<const char *, size_t> > &args) - { - std::vector<char> buffer; - - Pack(buffer, "*"); - Pack(buffer, stringify(args.size()).c_str()); - Pack(buffer, "\r\n"); - - for (unsigned j = 0; j < args.size(); ++j) - { - const std::pair<const char *, size_t> &pair = args[j]; - - Pack(buffer, "$"); - Pack(buffer, stringify(pair.second).c_str()); - Pack(buffer, "\r\n"); - - Pack(buffer, pair.first, pair.second); - Pack(buffer, "\r\n"); - } - - if (buffer.empty()) - return; - - s->Write(&buffer[0], buffer.size()); - if (in_transaction) - { - ti.interfaces.push_back(i); - s->interfaces.push_back(NULL); // For the +Queued response - } - else - s->interfaces.push_back(i); - } - - public: - void SendCommand(RedisSocket *s, Interface *i, const std::vector<Anope::string> &cmds) - { - std::vector<std::pair<const char *, size_t> > args; - for (unsigned j = 0; j < cmds.size(); ++j) - args.push_back(std::make_pair(cmds[j].c_str(), cmds[j].length())); - this->Send(s, i, args); - } - - void Send(Interface *i, const std::vector<std::pair<const char *, size_t> > &args) - { - if (!sock) - { - sock = new RedisSocket(this, host.find(':') != Anope::string::npos); - sock->Connect(host, port); - } - - this->Send(sock, i, args); - } - - void SendCommand(Interface *i, const std::vector<Anope::string> &cmds) override - { - std::vector<std::pair<const char *, size_t> > args; - for (unsigned j = 0; j < cmds.size(); ++j) - args.push_back(std::make_pair(cmds[j].c_str(), cmds[j].length())); - this->Send(i, args); - } - - void SendCommand(Interface *i, const Anope::string &str) override - { - std::vector<Anope::string> args; - spacesepstream(str).GetTokens(args); - this->SendCommand(i, args); - } - - bool BlockAndProcess() override - { - this->sock->ProcessWrite(); - this->sock->SetBlocking(true); - this->sock->ProcessRead(); - this->sock->SetBlocking(false); - return !this->sock->interfaces.empty(); - } - - void Subscribe(Interface *i, const Anope::string &ch) override - { - if (sub == NULL) - { - sub = new RedisSocket(this, host.find(':') != Anope::string::npos); - sub->Connect(host, port); - } - - std::vector<Anope::string> args = { "SUBSCRIBE", ch }; - this->SendCommand(sub, NULL, args); - - sub->subinterfaces[ch] = i; - } - - void Unsubscribe(const Anope::string &pattern) override - { - if (sub) - sub->subinterfaces.erase(pattern); - } - - void StartTransaction() override - { - if (in_transaction) - throw CoreException(); - - this->SendCommand(NULL, "MULTI"); - in_transaction = true; - } - - void CommitTransaction() override - { - /* The result of the transaction comes back to the reply of EXEC as a multi bulk. - * The reply to the individual commands that make up the transaction when executed - * is a simple +QUEUED - */ - in_transaction = false; - this->SendCommand(&this->ti, "EXEC"); - } -}; - -RedisSocket::~RedisSocket() -{ - if (provider) - { - if (provider->sock == this) - provider->sock = NULL; - else if (provider->sub == this) - provider->sub = NULL; - } - - for (unsigned i = 0; i < interfaces.size(); ++i) - { - Interface *inter = interfaces[i]; - - if (!inter) - continue; - - inter->OnError("Interface going away"); - } -} - -void RedisSocket::OnConnect() -{ - provider->GetOwner()->logger.Log(_("Successfully connected to {0}"), provider->GetName() + (this == this->provider->sub ? " (sub)" : "")); - - this->provider->SendCommand(NULL, "CLIENT SETNAME Anope"); - this->provider->SendCommand(NULL, "SELECT " + stringify(provider->db)); -} - -void RedisSocket::OnError(const Anope::string &error) -{ - provider->GetOwner()->logger.Log(_("Error on {0}: {1}"), provider->GetName() + (this == this->provider->sub ? " (sub)" : ""), error); -} - -size_t RedisSocket::ParseReply(Reply &r, const char *buffer, size_t l) -{ - size_t used = 0; - - if (!l) - return used; - - if (r.type == Reply::MULTI_BULK) - goto multi_bulk_cont; - - switch (*buffer) - { - case '+': - { - Anope::string reason(buffer, 1, l - 1); - size_t nl = reason.find("\r\n"); - provider->GetOwner()->logger.Debug2("status ok: {0}", reason.substr(0, nl)); - if (nl != Anope::string::npos) - { - r.type = Reply::OK; - used = 1 + nl + 2; - } - break; - } - case '-': - { - Anope::string reason(buffer, 1, l - 1); - size_t nl = reason.find("\r\n"); - provider->GetOwner()->logger.Debug2("status error: {0}", reason.substr(0, nl)); - if (nl != Anope::string::npos) - { - r.type = Reply::NOT_OK; - used = 1 + nl + 2; - } - break; - } - case ':': - { - Anope::string ibuf(buffer, 1, l - 1); - size_t nl = ibuf.find("\r\n"); - if (nl != Anope::string::npos) - { - try - { - r.i = convertTo<int64_t>(ibuf.substr(0, nl)); - } - catch (const ConvertException &) { } - - r.type = Reply::INT; - used = 1 + nl + 2; - } - break; - } - case '$': - { - Anope::string reply(buffer + 1, l - 1); - /* This assumes one bulk can always fit in our recv buffer */ - size_t nl = reply.find("\r\n"); - if (nl != Anope::string::npos) - { - int len; - try - { - len = convertTo<int>(reply.substr(0, nl)); - if (len >= 0) - { - if (1 + nl + 2 + len + 2 <= l) - { - used = 1 + nl + 2 + len + 2; - r.bulk = reply.substr(nl + 2, len); - r.type = Reply::BULK; - } - } - else - { - used = 1 + nl + 2 + 2; - r.type = Reply::BULK; - } - } - catch (const ConvertException &) { } - } - break; - } - multi_bulk_cont: - case '*': - { - if (r.type != Reply::MULTI_BULK) - { - Anope::string reply(buffer + 1, l - 1); - size_t nl = reply.find("\r\n"); - if (nl != Anope::string::npos) - { - r.type = Reply::MULTI_BULK; - try - { - r.multi_bulk_size = convertTo<int>(reply.substr(0, nl)); - } - catch (const ConvertException &) { } - - used = 1 + nl + 2; - } - else - break; - } - else if (r.multi_bulk_size >= 0 && r.multi_bulk.size() == static_cast<unsigned>(r.multi_bulk_size)) - { - /* This multi bulk is already complete, so check the sub bulks */ - for (unsigned i = 0; i < r.multi_bulk.size(); ++i) - if (r.multi_bulk[i]->type == Reply::MULTI_BULK) - ParseReply(*r.multi_bulk[i], buffer + used, l - used); - break; - } - - for (int i = r.multi_bulk.size(); i < r.multi_bulk_size; ++i) - { - Reply *reply = new Reply(); - size_t u = ParseReply(*reply, buffer + used, l - used); - if (!u) - { - provider->GetOwner()->logger.Debug("ran out of data to parse"); - delete reply; - break; - } - r.multi_bulk.push_back(reply); - used += u; - } - break; - } - default: - provider->GetOwner()->logger.Debug("unknown reply {0}", *buffer); - } - - return used; -} - -bool RedisSocket::Read(const char *buffer, size_t l) -{ - static std::vector<char> save; - std::vector<char> copy; - - if (!save.empty()) - { - std::copy(buffer, buffer + l, std::back_inserter(save)); - - copy = save; - - buffer = ©[0]; - l = copy.size(); - } - - while (l) - { - static Reply r; - - size_t used = this->ParseReply(r, buffer, l); - if (!used) - { - provider->GetOwner()->logger.Debug("used == 0 ?"); - r.Clear(); - break; - } - else if (used > l) - { - provider->GetOwner()->logger.Debug("used > l ?"); - r.Clear(); - break; - } - - /* Full result is not here yet */ - if (r.type == Reply::MULTI_BULK && static_cast<unsigned>(r.multi_bulk_size) != r.multi_bulk.size()) - { - buffer += used; - l -= used; - break; - } - - if (this == provider->sub) - { - std::map<Anope::string, Interface *>::iterator it = this->subinterfaces.find(r.multi_bulk[1]->bulk); - if (it != this->subinterfaces.end()) - it->second->OnResult(r); - } - else - { - if (this->interfaces.empty()) - { - provider->GetOwner()->logger.Debug("no interfaces?"); - } - else - { - Interface *i = this->interfaces.front(); - this->interfaces.pop_front(); - - if (i) - { - if (r.type != Reply::NOT_OK) - i->OnResult(r); - else - i->OnError(r.bulk); - } - } - } - - buffer += used; - l -= used; - - r.Clear(); - } - - if (l) - { - save.resize(l); - std::copy(buffer, buffer + l, save.begin()); - } - else - std::vector<char>().swap(save); - - return true; -} - - -class ModuleRedis : public Module - , public EventHook<Event::ModuleUnload> -{ - std::map<Anope::string, MyRedisService *> services; - - public: - ModuleRedis(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR) - , EventHook<Event::ModuleUnload>(this) - { - } - - ~ModuleRedis() - { - for (std::map<Anope::string, MyRedisService *>::iterator it = services.begin(); it != services.end(); ++it) - { - MyRedisService *p = it->second; - - delete p->sock; - p->sock = NULL; - delete p->sub; - p->sub = NULL; - - delete p; - } - } - - void OnReload(Configuration::Conf *conf) override - { - Configuration::Block *block = conf->GetModule(this); - std::vector<Anope::string> new_services; - - for (int i = 0; i < block->CountBlock("redis"); ++i) - { - Configuration::Block *redis = block->GetBlock("redis", i); - - const Anope::string &n = redis->Get<Anope::string>("name"), - &ip = redis->Get<Anope::string>("ip"); - int port = redis->Get<int>("port"); - unsigned db = redis->Get<unsigned>("db"); - - delete services[n]; - services[n] = new MyRedisService(this, n, ip, port, db); - new_services.push_back(n); - } - - for (std::map<Anope::string, MyRedisService *>::iterator it = services.begin(); it != services.end();) - { - Provider *p = it->second; - ++it; - - if (std::find(new_services.begin(), new_services.end(), p->GetName()) == new_services.end()) - delete it->second; - } - } - - void OnModuleUnload(User *, Module *m) override - { - for (std::map<Anope::string, MyRedisService *>::iterator it = services.begin(); it != services.end(); ++it) - { - MyRedisService *p = it->second; - - if (p->sock) - for (unsigned i = p->sock->interfaces.size(); i > 0; --i) - { - Interface *inter = p->sock->interfaces[i - 1]; - - if (inter && inter->GetOwner() == m) - { - inter->OnError(m->name + " being unloaded"); - p->sock->interfaces.erase(p->sock->interfaces.begin() + i - 1); - } - } - - if (p->sub) - for (unsigned i = p->sub->interfaces.size(); i > 0; --i) - { - Interface *inter = p->sub->interfaces[i - 1]; - - if (inter && inter->GetOwner() == m) - { - inter->OnError(m->name + " being unloaded"); - p->sub->interfaces.erase(p->sub->interfaces.begin() + i - 1); - } - } - - for (unsigned i = p->ti.interfaces.size(); i > 0; --i) - { - Interface *inter = p->ti.interfaces[i - 1]; - - if (inter && inter->GetOwner() == m) - { - inter->OnError(m->name + " being unloaded"); - p->ti.interfaces.erase(p->ti.interfaces.begin() + i - 1); - } - } - } - } -}; - -MODULE_INIT(ModuleRedis) diff --git a/modules/sqlite.cpp b/modules/sqlite.cpp index 3cc618e4c..b9bc063c5 100644 --- a/modules/sqlite.cpp +++ b/modules/sqlite.cpp @@ -96,7 +96,7 @@ class SQLiteService : public Provider Query BeginTransaction() override; Query Commit() override; - Serialize::ID GetID(const Anope::string &) override; + Serialize::ID GetID(const Anope::string &prefix, const Anope::string &type) override; Query GetTables(const Anope::string &prefix); @@ -240,10 +240,6 @@ std::vector<Query> SQLiteService::InitSchema(const Anope::string &prefix) queries.push_back(Query("PRAGMA foreign_keys = ON")); - /* https://sqlite.org/lang_createtable.html#rowid, https://sqlite.org/autoinc.html */ - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `type`)"; - queries.push_back(t); - return queries; } @@ -251,21 +247,7 @@ std::vector<Query> SQLiteService::Replace(const Anope::string &table, const Quer { std::vector<Query> queries; - Anope::string query_text = "INSERT OR IGNORE INTO `" + table + "` ("; - for (const std::pair<Anope::string, QueryData> &p : q.parameters) - query_text += "`" + p.first + "`,"; - query_text.erase(query_text.length() - 1); - query_text += ") VALUES ("; - for (const std::pair<Anope::string, QueryData> &p : q.parameters) - query_text += "@" + p.first + "@,"; - query_text.erase(query_text.length() - 1); - query_text += ")"; - - Query query(query_text); - query.parameters = q.parameters; - queries.push_back(query); - - query_text = "UPDATE `" + table + "` SET "; + Anope::string query_text = "UPDATE `" + table + "` SET "; for (const std::pair<Anope::string, QueryData> &p : q.parameters) if (!keys.count(p.first)) query_text += "`" + p.first + "` = @" + p.first + "@,"; @@ -280,7 +262,7 @@ std::vector<Query> SQLiteService::Replace(const Anope::string &table, const Quer query_text += "`" + key + "` = @" + key + "@"; } - query = query_text; + Query query(query_text); query.parameters = q.parameters; queries.push_back(query); @@ -303,7 +285,7 @@ std::vector<Query> SQLiteService::CreateTable(const Anope::string &prefix, Seria if (field->is_object) { - Anope::string refname = field->GetTypeName() == Serialize::Object::NAME ? "objects" : field->GetTypeName(); + Anope::string refname = field->GetTypeName(); query += " REFERENCES " + prefix + refname + "(id) ON DELETE "; if (field->depends) @@ -321,7 +303,7 @@ std::vector<Query> SQLiteService::CreateTable(const Anope::string &prefix, Seria query += ","; } - query += " `id` INTEGER PRIMARY KEY, FOREIGN KEY (id) REFERENCES " + prefix + "objects(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"; + query += " `id` INTEGER PRIMARY KEY AUTOINCREMENT)"; queries.push_back(query); active_schema[prefix + base->GetName()] = fields; @@ -343,7 +325,8 @@ std::vector<Query> SQLiteService::AlterTable(const Anope::string &prefix, Serial if (field->is_object) { - buf += " REFERENCES " + prefix + "objects(id) ON DELETE "; + Anope::string refname = field->GetTypeName(); + buf += " REFERENCES " + prefix + refname + "(id) ON DELETE "; if (field->depends) { @@ -394,21 +377,12 @@ Query SQLiteService::Commit() return Query("COMMIT"); } -Serialize::ID SQLiteService::GetID(const Anope::string &prefix) +Serialize::ID SQLiteService::GetID(const Anope::string &prefix, const Anope::string &type) { - Query query = "SELECT MAX(id) AS id FROM `" + prefix + "objects`"; - Serialize::ID id = 1; - + Query query = "INSERT INTO `" + prefix + type + "` DEFAULT VALUES"; Result res = RunQuery(query); - if (res.Rows() && !res.IsNull(0, "id")) - { - id = convertTo<Serialize::ID>(res.Get(0, "id")); - - /* next id */ - ++id; - } - /* OnSerializableCreate is called immediately after this which does the insert, within the same transaction */ + Serialize::ID id = res.GetID(); return id; } diff --git a/src/serialize.cpp b/src/serialize.cpp index d27950f36..5315a8469 100644 --- a/src/serialize.cpp +++ b/src/serialize.cpp @@ -25,7 +25,7 @@ using namespace Serialize; -std::unordered_map<ID, Object *> Serialize::objects; +static std::map<Serialize::TypeBase *, std::unordered_map<ID, Object *>> objects; std::vector<FieldBase *> Serialize::serializableFields; @@ -34,33 +34,34 @@ std::multimap<Anope::string, Anope::string> Serialize::child_types; static ID curid; -Object *Serialize::GetID(ID id) +Object *Serialize::GetID(Serialize::TypeBase *type, ID id) { - auto it = objects.find(id); - if (it != objects.end()) + auto it = objects[type].find(id); + if (it != objects[type].end()) return it->second; return nullptr; } void Serialize::GC() { - for (auto it = objects.begin(); it != objects.end();) - { - Object *o = it->second; - - if (!o->CanGC()) + for (auto it = objects.begin(); it != objects.end(); ++it) + for (auto it2 = it->second.begin(); it2 != it->second.end();) { - // Wipe internal storage to force refetch - o->Wipe(); - ++it; - continue; - } + Object *o = it2->second; - Anope::Logger.Debug2("garbage collected object {0}", o->id); + if (!o->CanGC()) + { + // Wipe internal storage to force refetch + o->Wipe(); + ++it2; + continue; + } - it = objects.erase(it); - delete o; - } + Anope::Logger.Debug2("garbage collected object {0}", o->id); + + it2 = it->second.erase(it2); + delete o; + } } void Serialize::Unregister(Module *m) @@ -109,15 +110,15 @@ std::vector<Edge> Object::GetEdges(TypeBase *type) Object::Object(TypeBase *type) { ID i; - EventReturn result = EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializableGetId, i); + EventReturn result = EventManager::Get()->Dispatch(&Event::SerializeEvents::OnSerializableGetId, type, i); if (result != EVENT_ALLOW) { - while (GetID(++curid)); + while (GetID(type, ++curid)); i = curid; } id = i; - objects[id] = this; + objects[type][id] = this; this->s_type = type; @@ -131,7 +132,7 @@ Object::Object(TypeBase *type) Object::Object(TypeBase *type, ID i) { this->id = i; - objects[i] = this; + objects[type][id] = this; this->s_type = type; @@ -142,7 +143,7 @@ Object::Object(TypeBase *type, ID i) Object::~Object() { - Anope::Logger.Debug2("Destructing object id #{0} address {2} type {3}", id, static_cast<void *>(this), s_type->GetName()); + Anope::Logger.Debug2("Destructing object id #{0} address {1} type {2}", id, static_cast<void *>(this), s_type->GetName()); /* Remove in memory edges */ std::map<TypeBase *, std::vector<Edge>> copy = edges; @@ -161,7 +162,7 @@ Object::~Object() } } - objects.erase(id); + objects[s_type].erase(id); s_type->objects.erase(this); } @@ -230,18 +231,16 @@ TypeBase::TypeBase(Module *o, const Anope::string &n) : Service(o, TypeBase::NAM { } -TypeBase::~TypeBase() -{ - if (!Serialize::GetObjects<Object *>(this->GetName()).empty()) - throw CoreException("Type destructing with objects still alive"); -} - void TypeBase::Unregister() { Anope::Logger.Debug2("Unregistering type {0}", this->GetName()); - for (Object *obj : GetObjects<Object *>(this->GetName())) - obj->Delete(); + // Delete in memory objects + std::unordered_map<ID, Object *> objs = ::objects[this]; + for (auto &pair : objs) + delete pair.second; + + ::objects.erase(this); for (FieldBase *field : serializableFields) { |