diff options
author | Adam <Adam@anope.org> | 2012-12-13 11:12:56 (GMT) |
---|---|---|
committer | Adam <Adam@anope.org> | 2012-12-13 11:12:56 (GMT) |
commit | c1077faa281c5635f85b892e605e23bd6c8fcc3b (patch) | |
tree | 213b5f87a19f182e1efd6110f03ff10d5b10ebf6 | |
parent | 76ba147c22944b67e8522cd2bb7b6e1bae498ced (diff) | |
download | anope-c1077faa281c5635f85b892e605e23bd6c8fcc3b.zip anope-c1077faa281c5635f85b892e605e23bd6c8fcc3b.tar.gz anope-c1077faa281c5635f85b892e605e23bd6c8fcc3b.tar.bz2 |
Optimize much of the database code and serialize code.
60 files changed, 1181 insertions, 1035 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index addc014..ad3b9ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,13 +353,6 @@ check_function_exists(epoll_wait HAVE_EPOLL) check_function_exists(poll HAVE_POLL) check_function_exists(kqueue HAVE_KQUEUE) -# Check if eventfd works -try_run(EVENTFD_TEST_RUN_RESULT EVENTFD_TEST_COMPILE_RESULT ${CMAKE_CURRENT_BINARY_DIR} ${Anope_SOURCE_DIR}/cmake/eventfd_test.cpp) -set(HAVE_EVENTFD FALSE) -if (EVENTFD_TEST_COMPILE_RESULT AND EVENTFD_TEST_RUN_RESULT EQUAL 1) - set(HAVE_EVENTFD TRUE) -endif(EVENTFD_TEST_COMPILE_RESULT AND EVENTFD_TEST_RUN_RESULT EQUAL 1) - # Strip the leading and trailing spaces from the compile flags if(CXXFLAGS) strip_string(${CXXFLAGS} CXXFLAGS) diff --git a/cmake/eventfd_test.cpp b/cmake/eventfd_test.cpp deleted file mode 100644 index ab45b65..0000000 --- a/cmake/eventfd_test.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include <sys/eventfd.h> - -int main() -{ - int i = eventfd(0, EFD_NONBLOCK); - return i >= 0 ? 1 : 0; -} - diff --git a/data/example.conf b/data/example.conf index 8396ffc..205a0ea 100644 --- a/data/example.conf +++ b/data/example.conf @@ -1135,6 +1135,15 @@ db_flatfile * The database name db_flatfile should use */ database = "anope.db" + + /* + * If enabled, services will fork a child process to save databases. + * + * This is only useful with very large databases, with hundreds + * of thousands of objects, that have a noticable delay from + * writing databases. + */ + fork = no } /* @@ -1154,7 +1163,8 @@ db_flatfile * This module allows saving and loading databases using one of the SQL engines. * This module reads and writes to SQL in real time. Changes to the SQL tables * will be immediately reflected into Anope. This module should not be loaded - * in conjunction with db_sql. + * in conjunction with db_sql, except during the initial import of existing + * databases to SQL. */ #module { name = "db_sql_live" } diff --git a/include/access.h b/include/access.h index 918dd7b..f011ed4 100644 --- a/include/access.h +++ b/include/access.h @@ -87,7 +87,7 @@ class CoreExport ChanAccess : public Serializable ChanAccess(AccessProvider *p); virtual ~ChanAccess(); - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); /** Check if this access entry matches the given user or account diff --git a/include/account.h b/include/account.h index a45bf8c..da85548 100644 --- a/include/account.h +++ b/include/account.h @@ -122,7 +122,7 @@ class CoreExport NickAlias : public Serializable, public Extensible, public Flag NickAlias(const Anope::string &nickname, NickCore *nickcore); ~NickAlias(); - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); /** Release a nick @@ -227,7 +227,7 @@ class CoreExport NickCore : public Serializable, public Extensible, public Flags NickCore(const Anope::string &nickdisplay); ~NickCore(); - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); /** Changes the display for this account diff --git a/include/anope.h b/include/anope.h index 30ca48e..c241524 100644 --- a/include/anope.h +++ b/include/anope.h @@ -13,6 +13,8 @@ #ifndef ANOPE_H #define ANOPE_H +#include <signal.h> + #include "hashcomp.h" namespace Anope @@ -282,9 +284,12 @@ namespace Anope * Stream insertion operator, must be friend because they cannot be inside the class. */ friend std::ostream &operator<<(std::ostream &os, const string &_str); + friend std::istream &operator>>(std::istream &is, string &_str); }; inline std::ostream &operator<<(std::ostream &os, const string &_str) { return os << _str._string; } + /* This is not standard to make operator>> behave like operator<< in that it will allow extracting a whole line, not just one word */ + inline std::istream &operator>>(std::istream &is, string &_str) { return std::getline(is, _str._string); } inline const string operator+(char chr, const string &str) { string tmp(chr); tmp += str; return tmp; } inline const string operator+(const char *_str, const string &str) { string tmp(_str); tmp += str; return tmp; } @@ -318,6 +323,8 @@ namespace Anope /** The value to return from main() */ extern int ReturnValue; + + extern sig_atomic_t Signal; extern bool Quitting; extern bool Restarting; extern Anope::string QuitReason; @@ -376,6 +383,10 @@ namespace Anope */ extern void Fork(); + /** Does something with the signal in Anope::Signal + */ + extern void HandleSignal(); + /** One of the first functions called, does general initialization such as reading * command line args, loading the configuration, doing the initial fork() if necessary, * initializating language support, loading modules, and loading databases. diff --git a/include/base.h b/include/base.h index 178bb19..6fb974e 100644 --- a/include/base.h +++ b/include/base.h @@ -17,7 +17,7 @@ class CoreExport Base { /* References to this base class */ - std::set<ReferenceBase *> references; + std::set<ReferenceBase *> *references; public: Base(); virtual ~Base(); diff --git a/include/bots.h b/include/bots.h index 9b61371..01c7521 100644 --- a/include/bots.h +++ b/include/bots.h @@ -63,7 +63,7 @@ class CoreExport BotInfo : public User, public Flags<BotFlag>, public Serializab */ virtual ~BotInfo(); - Serialize::Data Serialize() const; + void Serialize(Serialize::Data &data) const; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); void GenerateUID(); diff --git a/include/extensible.h b/include/extensible.h index bd7c8c7..c1de409 100644 --- a/include/extensible.h +++ b/include/extensible.h @@ -38,22 +38,25 @@ class CoreExport Extensible { private: typedef std::map<Anope::string, ExtensibleItem *> extensible_map; - extensible_map extension_items; + extensible_map *extension_items; public: - /** Default constructor, does nothing + /** Default constructor */ - Extensible() { } + Extensible() : extension_items(NULL) { } /** Destructor, deletes all of the extensible items in this object * then clears the map */ virtual ~Extensible() { - for (extensible_map::iterator it = extension_items.begin(), it_end = extension_items.end(); it != it_end; ++it) - if (it->second) - it->second->OnDelete(); - extension_items.clear(); + if (extension_items) + { + for (extensible_map::iterator it = extension_items->begin(), it_end = extension_items->end(); it != it_end; ++it) + if (it->second) + it->second->OnDelete(); + delete extension_items; + } } /** Extend an Extensible class. @@ -70,7 +73,9 @@ class CoreExport Extensible void Extend(const Anope::string &key, ExtensibleItem *p) { this->Shrink(key); - this->extension_items[key] = p; + if (!extension_items) + extension_items = new extensible_map(); + (*this->extension_items)[key] = p; } /** Shrink an Extensible class. @@ -83,8 +88,11 @@ class CoreExport Extensible */ bool Shrink(const Anope::string &key) { - extensible_map::iterator it = this->extension_items.find(key); - if (it != this->extension_items.end()) + if (!extension_items) + return false; + + extensible_map::iterator it = this->extension_items->find(key); + if (it != this->extension_items->end()) { if (it->second != NULL) it->second->OnDelete(); @@ -92,7 +100,7 @@ class CoreExport Extensible * returns the number of elements removed, std::map * is single-associative so this should only be 0 or 1 */ - return this->extension_items.erase(key) > 0; + return this->extension_items->erase(key) > 0; } return false; @@ -105,9 +113,12 @@ class CoreExport Extensible */ template<typename T> T GetExt(const Anope::string &key) const { - extensible_map::const_iterator it = this->extension_items.find(key); - if (it != this->extension_items.end()) - return anope_dynamic_static_cast<T>(it->second); + if (this->extension_items) + { + extensible_map::const_iterator it = this->extension_items->find(key); + if (it != this->extension_items->end()) + return anope_dynamic_static_cast<T>(it->second); + } return NULL; } @@ -119,7 +130,7 @@ class CoreExport Extensible */ bool HasExt(const Anope::string &key) const { - return this->extension_items.count(key) > 0; + return this->extension_items != NULL && this->extension_items->count(key) > 0; } /** Get a list of all extension items names. @@ -129,8 +140,9 @@ class CoreExport Extensible */ void GetExtList(std::deque<Anope::string> &list) const { - for (extensible_map::const_iterator it = extension_items.begin(), it_end = extension_items.end(); it != it_end; ++it) - list.push_back(it->first); + if (extension_items) + for (extensible_map::const_iterator it = extension_items->begin(), it_end = extension_items->end(); it != it_end; ++it) + list.push_back(it->first); } }; diff --git a/include/memo.h b/include/memo.h index 9fdbb3c..9a7acce 100644 --- a/include/memo.h +++ b/include/memo.h @@ -31,7 +31,7 @@ class CoreExport Memo : public Flags<MemoFlag>, public Serializable public: Memo(); - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); Anope::string owner; diff --git a/include/module.h b/include/module.h index e6b63bd..197899c 100644 --- a/include/module.h +++ b/include/module.h @@ -40,7 +40,6 @@ #include "servers.h" #include "service.h" #include "services.h" -#include "signals.h" #include "socketengine.h" #include "sockets.h" #include "threadengine.h" diff --git a/include/regchannel.h b/include/regchannel.h index 9e01963..1cefe27 100644 --- a/include/regchannel.h +++ b/include/regchannel.h @@ -143,7 +143,7 @@ struct CoreExport BadWord : Serializable BadWordType type; BadWord() : Serializable("BadWord") { } - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); }; @@ -172,7 +172,7 @@ class CoreExport AutoKick : public Flags<AutoKickFlag>, public Serializable time_t last_used; AutoKick(); - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); }; @@ -188,7 +188,7 @@ struct CoreExport ModeLock : Serializable ModeLock(ChannelInfo *ch, bool s, ChannelModeName n, const Anope::string &p, const Anope::string &se = "", time_t c = Anope::CurTime); - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); }; @@ -206,7 +206,7 @@ struct CoreExport LogSetting : Serializable time_t created; LogSetting() : Serializable("LogSetting") { } - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); }; @@ -263,7 +263,7 @@ class CoreExport ChannelInfo : public Serializable, public Extensible, public Fl ~ChannelInfo(); - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &); /** Change the founder of the channek diff --git a/include/serialize.h b/include/serialize.h index 8b8497c..1a16e5b 100644 --- a/include/serialize.h +++ b/include/serialize.h @@ -20,41 +20,24 @@ namespace Serialize { - enum DataType + class Data { - DT_TEXT, - DT_INT - }; - - class CoreExport stringstream : public std::stringstream - { - private: - Serialize::DataType type; - unsigned _max; - public: - stringstream(); - stringstream(const stringstream &ss); - Anope::string astr() const; - - template<typename T> std::istream &operator>>(T &val) + enum Type { - std::istringstream is(this->str()); - is >> val; - return *this; - } - std::istream &operator>>(Anope::string &val); + DT_TEXT, + DT_INT + }; - bool operator==(const stringstream &other) const; - bool operator!=(const stringstream &other) const; + virtual ~Data() { } - stringstream &SetType(Serialize::DataType t); - Serialize::DataType GetType() const; - stringstream &SetMax(unsigned m); - unsigned GetMax() const; - }; + virtual std::iostream& operator[](const Anope::string &key) = 0; - typedef std::map<Anope::string, stringstream> Data; + virtual bool IsEqual(Data *other) { throw CoreException("Not supported"); } + + virtual void SetType(const Anope::string &key, Type t) { } + virtual Type GetType(const Anope::string &key) const { return DT_TEXT; } + }; extern void RegisterTypes(); @@ -64,7 +47,7 @@ namespace Serialize } /** A serialziable object. Serializable objects can be serialized into - * a map of stringstreams (Serialize::Data), and then reconstructed or + * abstract data types (Serialize::Data), and then reconstructed or * updated later at any time. */ class CoreExport Serializable : public virtual Base @@ -82,7 +65,7 @@ class CoreExport Serializable : public virtual Base /* Iterator into serializable_items */ std::list<Serializable *>::iterator s_iter; /* The last serialized form of this object commited to the database */ - Serialize::Data last_commit; + Serialize::Data *last_commit; /* The last time this object was commited to the database */ time_t last_commit_time; @@ -108,8 +91,8 @@ class CoreExport Serializable : public virtual Base */ void QueueUpdate(); - bool IsCached(); - void UpdateCache(); + bool IsCached(Serialize::Data *); + void UpdateCache(Serialize::Data *); bool IsTSCached(); void UpdateTS(); @@ -117,9 +100,9 @@ class CoreExport Serializable : public virtual Base /** Get the type of serializable object this is * @return The serializable object type */ - Serialize::Type* GetSerializableType() const; + Serialize::Type* GetSerializableType() const { return this->s_type; } - virtual Serialize::Data Serialize() const = 0; + virtual void Serialize(Serialize::Data &data) const = 0; static const std::list<Serializable *> &GetItems(); }; @@ -164,7 +147,7 @@ class CoreExport Serialize::Type /** Gets the name for this type * @return The name, eg "NickAlias" */ - const Anope::string &GetName(); + const Anope::string &GetName() { return this->name; } /** Unserialized an object. * @param obj NULL if this object doesn't yet exist. If this isn't NULL, instead @@ -187,7 +170,7 @@ class CoreExport Serialize::Type */ void UpdateTimestamp(); - Module* GetOwner() const; + Module* GetOwner() const { return this->owner; } static Serialize::Type *Find(const Anope::string &name); diff --git a/include/signals.h b/include/signals.h deleted file mode 100644 index 771404f..0000000 --- a/include/signals.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * - * (C) 2003-2012 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. - * - */ - -#ifndef SIGNAL_H -#define SIGNAL_H - -#include <signal.h> - -#include "sockets.h" - -/** Represents a signal handler - */ -class Signal : public Pipe -{ - static std::vector<Signal *> SignalHandlers; - static void SignalHandler(int signal); - - struct sigaction action, old; - public: - int signal; - - /** Constructor - * @param s The signal to listen for - */ - Signal(int s); - ~Signal(); - - /** - * Called when the signal is received. - * Note this is not *immediatly* called when the signal is received, - * but it is saved and called at a later time when we are not doing something - * important. This is always called on the main thread, even on systems that - * spawn threads for signals, like Windows. - */ - virtual void OnNotify() anope_override = 0; -}; - -#endif - diff --git a/include/socketengine.h b/include/socketengine.h index 5f4bc59..696f69c 100644 --- a/include/socketengine.h +++ b/include/socketengine.h @@ -18,7 +18,7 @@ class CoreExport SocketEngine { - static const int DefaultSize = 8; // Uplink, DNS, Signal handlers, Mode stacker + static const int DefaultSize = 2; // Uplink, mode stacker public: /* Map of sockets */ static std::map<int, Socket *> Sockets; diff --git a/include/sockets.h b/include/sockets.h index 1ef10d0..ae7d6e7 100644 --- a/include/sockets.h +++ b/include/sockets.h @@ -225,15 +225,11 @@ class CoreExport Socket : public Flags<SocketFlag> */ bool IsIPv6() const; - /** Mark a socket as blocking + /** Mark a socket as (non)blocking + * @param state true to enable blocking, false to disable blocking * @return true if the socket is now blocking */ - bool SetBlocking(); - - /** Mark a socket as non-blocking - * @return true if the socket is now non-blocking - */ - bool SetNonBlocking(); + bool SetBlocking(bool state); /** Bind the socket to an ip and port * @param ip The ip @@ -456,7 +452,7 @@ class CoreExport ClientSocket : public virtual Socket class CoreExport Pipe : public Socket { public: - /** The FD of the write pipe (if this isn't evenfd) + /** The FD of the write pipe * this->sock is the readfd */ int write_pipe; @@ -468,7 +464,28 @@ class CoreExport Pipe : public Socket */ bool ProcessRead() anope_override; + /** Write data to this pipe + * @param data The data to write + * @param sz The amount of data to wirite + */ + void Write(const char *data, size_t sz); + inline void Write(const Anope::string &data) { this->Write(data.c_str(), data.length() + 1); } + + /** Read data from this pipe + * @param data A buffer to read data into + * @param sz The size of the buffer + * @return The amount of data read + */ + int Read(char *data, size_t sz); + + /** Mark the write end of this pipe (non)blocking + * @param state true to enable blocking, false to disable blocking + * @return true if the socket is now blocking + */ + bool SetWriteBlocking(bool state); + /** Called when this pipe needs to be woken up + * Is the same as Write("\0", 1) */ void Notify(); diff --git a/include/xline.h b/include/xline.h index 5d407d4..374b75a 100644 --- a/include/xline.h +++ b/include/xline.h @@ -42,7 +42,7 @@ class CoreExport XLine : public Serializable bool HasNickOrReal() const; bool IsRegex() const; - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); }; diff --git a/modules/commands/cs_entrymsg.cpp b/modules/commands/cs_entrymsg.cpp index 85e428c..ab9c4d0 100644 --- a/modules/commands/cs_entrymsg.cpp +++ b/modules/commands/cs_entrymsg.cpp @@ -28,16 +28,12 @@ struct EntryMsg : Serializable this->when = ct; } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &data) const anope_override { - Serialize::Data data; - data["ci"] << this->ci->name; data["creator"] << this->creator; data["message"] << this->message; - data["when"].SetType(Serialize::DT_INT) << this->when; - - return data; + data.SetType("when", Serialize::Data::DT_INT); data["when"] << this->when; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); @@ -52,7 +48,13 @@ struct EntryMessageList : Serialize::Checker<std::vector<EntryMsg *> >, Extensib Serializable* EntryMsg::Unserialize(Serializable *obj, Serialize::Data &data) { - ChannelInfo *ci = ChannelInfo::Find(data["ci"].astr()); + Anope::string sci, screator, smessage; + + data["ci"] >> sci; + data["creator"] >> screator; + data["message"] >> smessage; + + ChannelInfo *ci = ChannelInfo::Find(sci); if (!ci) return NULL; @@ -73,7 +75,7 @@ Serializable* EntryMsg::Unserialize(Serializable *obj, Serialize::Data &data) ci->Extend("cs_entrymsg", messages); } - EntryMsg *m = new EntryMsg(ci, data["creator"].astr(), data["message"].astr()); + EntryMsg *m = new EntryMsg(ci, screator, smessage); (*messages)->push_back(m); return m; } diff --git a/modules/commands/cs_fantasy_stats.cpp b/modules/commands/cs_fantasy_stats.cpp index bbe1352..5b25ccc 100644 --- a/modules/commands/cs_fantasy_stats.cpp +++ b/modules/commands/cs_fantasy_stats.cpp @@ -14,16 +14,16 @@ #include "module.h" #include "../extra/sql.h" -class MySQLInterface : public SQLInterface +class MySQLInterface : public SQL::Interface { public: - MySQLInterface(Module *o) : SQLInterface(o) { } + MySQLInterface(Module *o) : SQL::Interface(o) { } - void OnResult(const SQLResult &r) anope_override + void OnResult(const SQL::Result &r) anope_override { } - void OnError(const SQLResult &r) anope_override + void OnError(const SQL::Result &r) anope_override { if (!r.GetQuery().query.empty()) Log(LOG_DEBUG) << "Chanstats: Error executing query " << r.finished_query << ": " << r.GetError(); @@ -66,7 +66,7 @@ class CSStats : public Module { CommandCSStats commandcsstats; CommandCSGStats commandcsgstats; - ServiceReference<SQLProvider> sql; + ServiceReference<SQL::Provider> sql; MySQLInterface sqlinterface; Anope::string prefix; public: @@ -86,17 +86,17 @@ class CSStats : public Module ConfigReader config; prefix = config.ReadValue("chanstats", "prefix", "anope_", 0); Anope::string engine = config.ReadValue("chanstats", "engine", "", 0); - this->sql = ServiceReference<SQLProvider>("SQLProvider", engine); + this->sql = ServiceReference<SQL::Provider>("SQL::Provider", engine); } - SQLResult RunQuery(const SQLQuery &query) + SQL::Result RunQuery(const SQL::Query &query) { if (!this->sql) - throw SQLException("Unable to locate SQL reference, is m_mysql loaded and configured correctly?"); + throw SQL::Exception("Unable to locate SQL reference, is m_mysql loaded and configured correctly?"); - SQLResult res = this->sql->RunQuery(query); + SQL::Result res = this->sql->RunQuery(query); if (!res.GetError().empty()) - throw SQLException(res.GetError()); + throw SQL::Exception(res.GetError()); return res; } @@ -118,16 +118,16 @@ class CSStats : public Module try { - SQLQuery query; + SQL::Query query; query = "SELECT letters, words, line, smileys_happy+smileys_sad+smileys_other as smileys," "actions FROM `" + prefix + "chanstats` " "WHERE `nick` = @nick@ AND `chan` = @channel@ AND `type` = 'total';"; if (is_global) - query.setValue("channel", ""); + query.SetValue("channel", ""); else - query.setValue("channel", source.c->ci->name); - query.setValue("nick", display); - SQLResult res = this->RunQuery(query); + query.SetValue("channel", source.c->ci->name); + query.SetValue("nick", display); + SQL::Result res = this->RunQuery(query); if (res.Rows() > 0) { @@ -144,7 +144,7 @@ class CSStats : public Module else source.Reply(_("No stats for %s"), display.c_str()); } - catch (const SQLException &ex) + catch (const SQL::Exception &ex) { Log(LOG_DEBUG) << ex.GetReason(); } diff --git a/modules/commands/cs_fantasy_top.cpp b/modules/commands/cs_fantasy_top.cpp index 86e25f1..ca95720 100644 --- a/modules/commands/cs_fantasy_top.cpp +++ b/modules/commands/cs_fantasy_top.cpp @@ -14,16 +14,16 @@ #include "module.h" #include "../extra/sql.h" -class MySQLInterface : public SQLInterface +class MySQLInterface : public SQL::Interface { public: - MySQLInterface(Module *o) : SQLInterface(o) { } + MySQLInterface(Module *o) : SQL::Interface(o) { } - void OnResult(const SQLResult &r) anope_override + void OnResult(const SQL::Result &r) anope_override { } - void OnError(const SQLResult &r) anope_override + void OnError(const SQL::Result &r) anope_override { if (!r.GetQuery().query.empty()) Log(LOG_DEBUG) << "Chanstats: Error executing query " << r.finished_query << ": " << r.GetError(); @@ -93,7 +93,7 @@ class CSTop : public Module CommandCSGTop commandcsgtop; CommandCSTop10 commandcstop10; CommandCSGTop10 commandcsgtop10; - ServiceReference<SQLProvider> sql; + ServiceReference<SQL::Provider> sql; MySQLInterface sqlinterface; Anope::string prefix; @@ -115,17 +115,17 @@ class CSTop : public Module ConfigReader config; prefix = config.ReadValue("chanstats", "prefix", "anope_", 0); Anope::string engine = config.ReadValue("chanstats", "engine", "", 0); - this->sql = ServiceReference<SQLProvider>("SQLProvider", engine); + this->sql = ServiceReference<SQL::Provider>("SQL::Provider", engine); } - SQLResult RunQuery(const SQLQuery &query) + SQL::Result RunQuery(const SQL::Query &query) { if (!this->sql) - throw SQLException("Unable to locate SQL reference, is m_mysql loaded and configured correctly?"); + throw SQL::Exception("Unable to locate SQL reference, is m_mysql loaded and configured correctly?"); - SQLResult res = sql->RunQuery(query); + SQL::Result res = sql->RunQuery(query); if (!res.GetError().empty()) - throw SQLException(res.GetError()); + throw SQL::Exception(res.GetError()); return res; } @@ -147,20 +147,20 @@ class CSTop : public Module try { - SQLQuery query; + SQL::Query query; query = "SELECT nick, letters, words, line, actions," "smileys_happy+smileys_sad+smileys_other as smileys " "FROM `" + prefix + "chanstats` " "WHERE `nick` != '' AND `chan` = @channel@ AND `type` = 'total' " "ORDER BY `letters` DESC LIMIT @limit@;"; - query.setValue("limit", limit, false); + query.SetValue("limit", limit, false); if (is_global) - query.setValue("channel", ""); + query.SetValue("channel", ""); else - query.setValue("channel", channel.c_str()); + query.SetValue("channel", channel.c_str()); - SQLResult res = this->RunQuery(query); + SQL::Result res = this->RunQuery(query); if (res.Rows() > 0) { @@ -176,7 +176,7 @@ class CSTop : public Module else source.Reply(_("No stats for %s"), is_global ? "Network" : channel.c_str()); } - catch (const SQLException &ex) + catch (const SQL::Exception &ex) { Log(LOG_DEBUG) << ex.GetReason(); } diff --git a/modules/commands/cs_seen.cpp b/modules/commands/cs_seen.cpp index 18a21d3..8f90e2f 100644 --- a/modules/commands/cs_seen.cpp +++ b/modules/commands/cs_seen.cpp @@ -38,30 +38,30 @@ struct SeenInfo : Serializable { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &data) const anope_override { - Serialize::Data data; - data["nick"] << nick; data["vhost"] << vhost; data["type"] << type; data["nick2"] << nick2; data["channel"] << channel; data["message"] << message; - data["last"].SetType(Serialize::DT_INT) << last; - - return data; + data.SetType("last", Serialize::Data::DT_INT); data["last"] << last; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) { + Anope::string snick; + + data["nick"] >> snick; + SeenInfo *s; if (obj) s = anope_dynamic_static_cast<SeenInfo *>(obj); else { /* ignore duplicate entries in the db, created by an old bug */ - s = FindInfo(data["nick"].str()); + s = FindInfo(snick); if (!s) s = new SeenInfo(); } diff --git a/modules/commands/cs_set_misc.cpp b/modules/commands/cs_set_misc.cpp index 3bf0e9b..1fb25c7 100644 --- a/modules/commands/cs_set_misc.cpp +++ b/modules/commands/cs_set_misc.cpp @@ -22,20 +22,22 @@ struct CSMiscData : ExtensibleItem, Serializable { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &sdata) const anope_override { - Serialize::Data sdata; - sdata["ci"] << this->ci->name; sdata["name"] << this->name; sdata["data"] << this->data; - - return sdata; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) { - ChannelInfo *ci = ChannelInfo::Find(data["ci"].astr()); + Anope::string sci, sname, sdata; + + data["ci"] >> sci; + data["name"] >> sname; + data["data"] >> sdata; + + ChannelInfo *ci = ChannelInfo::Find(sci); if (ci == NULL) return NULL; @@ -49,8 +51,8 @@ struct CSMiscData : ExtensibleItem, Serializable } else { - d = new CSMiscData(ci, data["name"].astr(), data["data"].astr()); - ci->Extend(data["name"].astr(), d); + d = new CSMiscData(ci, sname, sdata); + ci->Extend(sname, d); } return d; diff --git a/modules/commands/cs_suspend.cpp b/modules/commands/cs_suspend.cpp index b380d4c..097de18 100644 --- a/modules/commands/cs_suspend.cpp +++ b/modules/commands/cs_suspend.cpp @@ -22,19 +22,19 @@ struct ChanSuspend : ExtensibleItem, Serializable { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &sd) const anope_override { - Serialize::Data sd; - sd["chan"] << this->chan; sd["when"] << this->when; - - return sd; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &sd) { - ChannelInfo *ci = ChannelInfo::Find(sd["chan"].astr()); + Anope::string schan; + + sd["chan"] >> schan; + + ChannelInfo *ci = ChannelInfo::Find(schan); if (ci == NULL) return NULL; diff --git a/modules/commands/hs_request.cpp b/modules/commands/hs_request.cpp index c7cd75c..6cd2e68 100644 --- a/modules/commands/hs_request.cpp +++ b/modules/commands/hs_request.cpp @@ -32,21 +32,20 @@ struct HostRequest : ExtensibleItem, Serializable HostRequest() : Serializable("HostRequest") { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &data) const anope_override { - Serialize::Data data; - data["nick"] << this->nick; data["ident"] << this->ident; data["host"] << this->host; - data["time"].SetType(Serialize::DT_INT) << this->time; - - return data; + data.SetType("time", Serialize::Data::DT_INT); data["time"] << this->time; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) { - NickAlias *na = NickAlias::Find(data["nick"].astr()); + Anope::string snick; + data["nick"] >> snick; + + NickAlias *na = NickAlias::Find(snick); if (na == NULL) return NULL; diff --git a/modules/commands/ns_ajoin.cpp b/modules/commands/ns_ajoin.cpp index ce92582..3a73772 100644 --- a/modules/commands/ns_ajoin.cpp +++ b/modules/commands/ns_ajoin.cpp @@ -28,23 +28,23 @@ struct AJoinEntry : Serializable AJoinEntry() : Serializable("AJoinEntry") { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &sd) const anope_override { - Serialize::Data sd; - if (!this->owner) - return sd; + return; sd["owner"] << this->owner->display; sd["channel"] << this->channel; sd["key"] << this->key; - - return sd; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &sd) { - NickCore *nc = NickCore::Find(sd["owner"].astr()); + Anope::string sowner; + + sd["owner"] >> sowner; + + NickCore *nc = NickCore::Find(sowner); if (nc == NULL) return NULL; diff --git a/modules/commands/ns_set_misc.cpp b/modules/commands/ns_set_misc.cpp index 1e088a4..b6dd672 100644 --- a/modules/commands/ns_set_misc.cpp +++ b/modules/commands/ns_set_misc.cpp @@ -23,20 +23,22 @@ struct NSMiscData : ExtensibleItem, Serializable { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &sdata) const anope_override { - Serialize::Data sdata; - sdata["nc"] << this->nc->display; sdata["name"] << this->name; sdata["data"] << this->data; - - return sdata; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) { - NickCore *nc = NickCore::Find(data["nc"].astr()); + Anope::string snc, sname, sdata; + + data["nc"] >> snc; + data["name"] >> sname; + data["data"] >> sdata; + + NickCore *nc = NickCore::Find(snc); if (nc == NULL) return NULL; @@ -50,8 +52,8 @@ struct NSMiscData : ExtensibleItem, Serializable } else { - d = new NSMiscData(nc, data["name"].astr(), data["data"].astr()); - nc->Extend(data["name"].astr(), d); + d = new NSMiscData(nc, sname, sdata); + nc->Extend(sname, d); } return d; diff --git a/modules/commands/ns_suspend.cpp b/modules/commands/ns_suspend.cpp index 6ff3554..63710cc 100644 --- a/modules/commands/ns_suspend.cpp +++ b/modules/commands/ns_suspend.cpp @@ -22,19 +22,19 @@ struct NickSuspend : ExtensibleItem, Serializable { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &sd) const anope_override { - Serialize::Data sd; - sd["nick"] << this->nick; sd["when"] << this->when; - - return sd; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &sd) { - const NickAlias *na = NickAlias::Find(sd["nick"].astr()); + Anope::string snick; + + sd["nick"] >> snick; + + const NickAlias *na = NickAlias::Find(snick); if (na == NULL) return NULL; diff --git a/modules/commands/os_dns.cpp b/modules/commands/os_dns.cpp index 769a42f..6e56893 100644 --- a/modules/commands/os_dns.cpp +++ b/modules/commands/os_dns.cpp @@ -49,17 +49,13 @@ class DNSServer : public Serializable } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &data) const anope_override { - Serialize::Data data; - data["server_name"] << server_name; for (unsigned i = 0; i < ips.size(); ++i) data["ip" + stringify(i)] << ips[i]; data["limit"] << limit; data["pooled"] << pooled; - - return data; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) @@ -72,12 +68,16 @@ class DNSServer : public Serializable req = new DNSServer(); data["server_name"] >> req->server_name; - for (unsigned i = 0; data.count("ip" + stringify(i)); ++i) + + for (unsigned i = 0; true; ++i) { Anope::string ip_str; data["ip" + stringify(i)] >> ip_str; + if (ip_str.empty()) + break; req->ips.push_back(ip_str); } + data["limit"] >> req->limit; data["pooled"] >> req->pooled; diff --git a/modules/commands/os_forbid.h b/modules/commands/os_forbid.h index 1fce928..07619f6 100644 --- a/modules/commands/os_forbid.h +++ b/modules/commands/os_forbid.h @@ -19,7 +19,7 @@ struct ForbidData : Serializable ForbidType type; ForbidData() : Serializable("ForbidData") { } - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); }; @@ -39,18 +39,14 @@ class ForbidService : public Service static ServiceReference<ForbidService> forbid_service("ForbidService", "forbid"); -Serialize::Data ForbidData::Serialize() const +void ForbidData::Serialize(Serialize::Data &data) const { - Serialize::Data data; - data["mask"] << this->mask; data["creator"] << this->creator; data["reason"] << this->reason; data["created"] << this->created; data["expires"] << this->expires; data["type"] << this->type; - - return data; } Serializable* ForbidData::Unserialize(Serializable *obj, Serialize::Data &data) diff --git a/modules/commands/os_ignore.h b/modules/commands/os_ignore.h index 003d88b..1990d95 100644 --- a/modules/commands/os_ignore.h +++ b/modules/commands/os_ignore.h @@ -18,7 +18,7 @@ struct IgnoreData : Serializable time_t time; /* When do we stop ignoring them? */ IgnoreData() : Serializable("IgnoreData") { } - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); }; @@ -43,16 +43,12 @@ class IgnoreService : public Service static ServiceReference<IgnoreService> ignore_service("IgnoreService", "ignore"); -Serialize::Data IgnoreData::Serialize() const +void IgnoreData::Serialize(Serialize::Data &data) const { - Serialize::Data data; - data["mask"] << this->mask; data["creator"] << this->creator; data["reason"] << this->reason; data["time"] << this->time; - - return data; } Serializable* IgnoreData::Unserialize(Serializable *obj, Serialize::Data &data) @@ -70,9 +66,14 @@ Serializable* IgnoreData::Unserialize(Serializable *obj, Serialize::Data &data) return ign; } + Anope::string smask, screator, sreason; time_t t; + + data["mask"] >> smask; + data["creator"] >> screator; + data["reason"] >> sreason; data["time"] >> t; - return ignore_service->AddIgnore(data["mask"].astr(), data["creator"].astr(), data["reason"].astr(), t); + return ignore_service->AddIgnore(smask, screator, sreason, t); } diff --git a/modules/commands/os_news.h b/modules/commands/os_news.h index 44525b9..b1e7174 100644 --- a/modules/commands/os_news.h +++ b/modules/commands/os_news.h @@ -23,7 +23,7 @@ struct NewsItem : Serializable time_t time; NewsItem() : Serializable("NewsItem") { } - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); }; @@ -41,16 +41,12 @@ class NewsService : public Service static ServiceReference<NewsService> news_service("NewsService", "news"); -Serialize::Data NewsItem::Serialize() const +void NewsItem::Serialize(Serialize::Data &data) const { - Serialize::Data data; - data["type"] << this->type; data["text"] << this->text; data["who"] << this->who; data["time"] << this->time; - - return data; } Serializable* NewsItem::Unserialize(Serializable *obj, Serialize::Data &data) diff --git a/modules/commands/os_oper.cpp b/modules/commands/os_oper.cpp index 8824558..b014a12 100644 --- a/modules/commands/os_oper.cpp +++ b/modules/commands/os_oper.cpp @@ -17,22 +17,23 @@ struct MyOper : Oper, Serializable { MyOper(const Anope::string &n, OperType *o) : Oper(n, o), Serializable("Oper") { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &data) const anope_override { - Serialize::Data data; - data["name"] << this->name; data["type"] << this->ot->GetName(); - - return data; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) { - OperType *ot = OperType::Find(data["type"].astr()); + Anope::string stype, sname; + + data["type"] >> stype; + data["name"] >> sname; + + OperType *ot = OperType::Find(stype); if (ot == NULL) return NULL; - NickCore *nc = NickCore::Find(data["name"].astr()); + NickCore *nc = NickCore::Find(sname); if (nc == NULL) return NULL; diff --git a/modules/commands/os_session.h b/modules/commands/os_session.h index 7304b21..6d1dd91 100644 --- a/modules/commands/os_session.h +++ b/modules/commands/os_session.h @@ -20,7 +20,7 @@ struct Exception : Serializable time_t expires; /* Time when it expires. 0 == no expiry */ Exception() : Serializable("Exception") { } - Serialize::Data Serialize() const anope_override; + void Serialize(Serialize::Data &data) const anope_override; static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); }; @@ -53,18 +53,14 @@ class SessionService : public Service static ServiceReference<SessionService> session_service("SessionService", "session"); -Serialize::Data Exception::Serialize() const +void Exception::Serialize(Serialize::Data &data) const { - Serialize::Data data; - data["mask"] << this->mask; data["limit"] << this->limit; data["who"] << this->who; data["reason"] << this->reason; data["time"] << this->time; data["expires"] << this->expires; - - return data; } Serializable* Exception::Unserialize(Serializable *obj, Serialize::Data &data) diff --git a/modules/commands/os_stats.cpp b/modules/commands/os_stats.cpp index bb029ee..18e2e89 100644 --- a/modules/commands/os_stats.cpp +++ b/modules/commands/os_stats.cpp @@ -18,14 +18,10 @@ struct Stats : Serializable { Stats() : Serializable("Stats") { } - Serialize::Data Serialize() const anope_override + void Serialize(Serialize::Data &data) const anope_override { - Serialize::Data data; - data["maxusercnt"] << MaxUserCount; data["maxusertime"] << MaxUserTime; - - return data; } static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) diff --git a/modules/database/db_flatfile.cpp b/modules/database/db_flatfile.cpp index acb287c..66715b9 100644 --- a/modules/database/db_flatfile.cpp +++ b/modules/database/db_flatfile.cpp @@ -12,145 +12,202 @@ #include "module.h" -class DBFlatFile : public Module +class SaveData : public Serialize::Data { - Anope::string DatabaseFile; - Anope::string BackupFile; - /* Day the last backup was on */ - int LastDay; - /* Backup file names */ - std::list<Anope::string> Backups; + public: + std::fstream *fs; + + SaveData() : fs(NULL) { } + + std::iostream& operator[](const Anope::string &key) anope_override + { + *fs << "\nDATA " << key << " "; + return *fs; + } +}; +class LoadData : public Serialize::Data +{ public: - DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE) + std::fstream *fs; + std::map<Anope::string, Anope::string> data; + std::stringstream ss; + bool read; + + LoadData() : fs(NULL), read(false) { } + + std::iostream& operator[](const Anope::string &key) anope_override { - this->SetAuthor("Anope"); + if (!read) + { + for (Anope::string token; std::getline(*this->fs, token.str());) + { + if (token.find("DATA ") != 0) + break; - Implementation i[] = { I_OnReload, I_OnLoadDatabase, I_OnSaveDatabase }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + size_t sp = token.find(' ', 5); // Skip DATA + if (sp != Anope::string::npos) + data[token.substr(5, sp - 5)] = token.substr(sp + 1); + } - OnReload(); + read = true; + } - LastDay = 0; + ss.clear(); + this->ss << this->data[key]; + return this->ss; } + + void Reset() + { + read = false; + data.clear(); + } +}; + +class DBFlatFile : public Module, public Pipe +{ + Anope::string database_file; + /* Day the last backup was on */ + int last_day; + /* Backup file names */ + std::map<Anope::string, std::list<Anope::string> > backups; + bool use_fork; void BackupDatabase() { - /* Do not backup a database that doesn't exist */ - if (!Anope::IsFile(DatabaseFile)) - return; - - time_t now = Anope::CurTime; - tm *tm = localtime(&now); + tm *tm = localtime(&Anope::CurTime); - if (tm->tm_mday != LastDay) + if (tm->tm_mday != last_day) { - LastDay = tm->tm_mday; - Anope::string newname = BackupFile + "." + stringify(tm->tm_year) + "." + stringify(tm->tm_mon) + "." + stringify(tm->tm_mday); + last_day = tm->tm_mday; - /* Backup already exists */ - if (IsFile(newname)) - return; + const std::vector<Anope::string> &type_order = Serialize::Type::GetTypeOrder(); - Log(LOG_DEBUG) << "db_flatfile: Attemping to rename " << DatabaseFile << " to " << newname; - if (rename(DatabaseFile.c_str(), newname.c_str())) - { - Log(this) << "Unable to back up database!"; + std::set<Anope::string> dbs; + dbs.insert(database_file); - if (!Config->NoBackupOkay) - Anope::Quitting = true; + for (unsigned i = 0; i < type_order.size(); ++i) + { + Serialize::Type *stype = Serialize::Type::Find(type_order[i]); - return; + if (stype && stype->GetOwner()) + dbs.insert("module_" + stype->GetOwner()->name + ".db"); } - Backups.push_back(newname); - if (Config->KeepBackups > 0 && Backups.size() > static_cast<unsigned>(Config->KeepBackups)) + for (std::set<Anope::string>::const_iterator it = dbs.begin(), it_end = dbs.end(); it != it_end; ++it) { - unlink(Backups.front().c_str()); - Backups.pop_front(); + const Anope::string &oldname = Anope::DataDir + "/" + *it; + Anope::string newname = Anope::DataDir + "/backups/" + *it + "." + stringify(tm->tm_year) + "." + stringify(tm->tm_mon) + "." + stringify(tm->tm_mday); + + /* Backup already exists */ + if (Anope::IsFile(newname)) + continue; + + Log(LOG_DEBUG) << "db_flatfile: Attemping to rename " << *it << " to " << newname; + if (rename(oldname.c_str(), newname.c_str())) + { + Log(this) << "Unable to back up database " << *it << "!"; + + if (!Config->NoBackupOkay) + Anope::Quitting = true; + + continue; + } + + backups[*it].push_back(newname); + + if (Config->KeepBackups > 0 && backups[*it].size() > static_cast<unsigned>(Config->KeepBackups)) + { + unlink(backups[*it].front().c_str()); + backups[*it].pop_front(); + } } } } - void OnReload() anope_override + public: + DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), last_day(0), use_fork(false) { - ConfigReader config; - DatabaseFile = Anope::DataDir + "/" + config.ReadValue("db_flatfile", "database", "anope.db", 0); - BackupFile = Anope::DataDir + "/backups/" + config.ReadValue("db_flatfile", "database", "anope.db", 0); + this->SetAuthor("Anope"); + + Implementation i[] = { I_OnReload, I_OnLoadDatabase, I_OnSaveDatabase }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + OnReload(); } - EventReturn OnLoadDatabase() anope_override + void OnNotify() anope_override { - std::map<Module *, std::fstream *> databases; - databases[NULL] = new std::fstream(DatabaseFile.c_str(), std::ios_base::in); + char buf[512]; + int i = this->Read(buf, sizeof(buf) - 1); + if (i <= 0) + return; + buf[i] = 0; - if (!databases[NULL]->is_open()) + if (!*buf) { - delete databases[NULL]; - Log(this) << "Unable to open " << DatabaseFile << " for reading!"; - return EVENT_CONTINUE; + Log(this) << "Finished saving databases"; + return; } - const std::vector<Anope::string> type_order = Serialize::Type::GetTypeOrder(); + Log(this) << "Error saving databases: " << buf; - for (unsigned i = 0; i < type_order.size(); ++i) - { - Serialize::Type *stype = Serialize::Type::Find(type_order[i]); - if (stype && !databases.count(stype->GetOwner())) - { - Anope::string db_name = Anope::DataDir + "/module_" + stype->GetOwner()->name + ".db"; - databases[stype->GetOwner()] = new std::fstream(db_name.c_str(), std::ios_base::in); - } - } + if (!Config->NoBackupOkay) + Anope::Quitting = true; + } - std::multimap<Serialize::Type *, Serialize::Data> objects; - for (std::map<Module *, std::fstream *>::iterator it = databases.begin(), it_end = databases.end(); it != it_end; ++it) - { - std::fstream *db = it->second; - Serialize::Type *st = NULL; - Serialize::Data data; - for (Anope::string buf, token; std::getline(*db, buf.str());) - { - spacesepstream sep(buf); + void OnReload() anope_override + { + ConfigReader config; + database_file = config.ReadValue("db_flatfile", "database", "anope.db", 0); + use_fork = config.ReadFlag("db_flatfile", "fork", "no", 0); + } - if (!sep.GetToken(token)) - continue; + EventReturn OnLoadDatabase() anope_override + { + const std::vector<Anope::string> &type_order = Serialize::Type::GetTypeOrder(); + std::set<Anope::string> tried_dbs; - if (token == "OBJECT" && sep.GetToken(token)) - { - st = Serialize::Type::Find(token); - data.clear(); - } - else if (token == "DATA" && st != NULL && sep.GetToken(token)) - data[token] << sep.GetRemaining(); - else if (token == "END" && st != NULL) - { - objects.insert(std::make_pair(st, data)); + const Anope::string &db_name = Anope::DataDir + "/" + database_file; - st = NULL; - data.clear(); - } - } + std::fstream fd(db_name.c_str(), std::ios_base::in); + if (!fd.is_open()) + { + Log(this) << "Unable to open " << db_name << " for reading!"; + return EVENT_STOP; } + std::map<Anope::string, std::vector<std::streampos> > positions; + + for (Anope::string buf; std::getline(fd, buf.str());) + if (buf.find("OBJECT ") == 0) + positions[buf.substr(7)].push_back(fd.tellg()); + + LoadData ld; + ld.fs = &fd; + for (unsigned i = 0; i < type_order.size(); ++i) { Serialize::Type *stype = Serialize::Type::Find(type_order[i]); - - std::multimap<Serialize::Type *, Serialize::Data>::iterator it = objects.find(stype), it_end = objects.upper_bound(stype); - if (it == objects.end()) + if (!stype || stype->GetOwner()) continue; - for (; it != it_end; ++it) - it->first->Unserialize(NULL, it->second); - } + + std::vector<std::streampos> &pos = positions[stype->GetName()]; - for (std::map<Module *, std::fstream *>::iterator it = databases.begin(), it_end = databases.end(); it != it_end; ++it) - { - it->second->close(); - delete it->second; + for (unsigned j = 0; j < pos.size(); ++j) + { + fd.clear(); + fd.seekg(pos[j]); + + stype->Unserialize(NULL, ld); + ld.Reset(); + } } + fd.close(); + return EVENT_STOP; } @@ -159,61 +216,92 @@ class DBFlatFile : public Module { BackupDatabase(); - Anope::string tmp_db = DatabaseFile + ".tmp"; - if (IsFile(DatabaseFile)) - rename(DatabaseFile.c_str(), tmp_db.c_str()); - - std::map<Module *, std::fstream *> databases; - databases[NULL] = new std::fstream(DatabaseFile.c_str(), std::ios_base::out | std::ios_base::trunc); - if (!databases[NULL]->is_open()) + int i = -1; + if (use_fork) { - delete databases[NULL]; - Log(this) << "Unable to open " << DatabaseFile << " for writing"; - if (IsFile(tmp_db)) - rename(tmp_db.c_str(), DatabaseFile.c_str()); - return EVENT_CONTINUE; + i = fork(); + if (i > 0) + return EVENT_CONTINUE; + else if (i < 0) + Log(this) << "Unable to fork for database save"; } - const std::list<Serializable *> &items = Serializable::GetItems(); - for (std::list<Serializable *>::const_iterator it = items.begin(), it_end = items.end(); it != it_end; ++it) + try { - Serializable *base = *it; - Serialize::Type *s_type = base->GetSerializableType(); + std::map<Module *, std::fstream *> databases; - if (!s_type) - continue; + SaveData data; + const std::list<Serializable *> &items = Serializable::GetItems(); + for (std::list<Serializable *>::const_iterator it = items.begin(), it_end = items.end(); it != it_end; ++it) + { + Serializable *base = *it; + Serialize::Type *s_type = base->GetSerializableType(); + + if (!s_type) + continue; - Serialize::Data data = base->Serialize(); + data.fs = databases[s_type->GetOwner()]; - if (!databases.count(s_type->GetOwner())) + if (!data.fs) + { + Anope::string db_name; + if (s_type->GetOwner()) + db_name = Anope::DataDir + "/module_" + s_type->GetOwner()->name + ".db"; + else + db_name = Anope::DataDir + "/" + database_file; + + if (Anope::IsFile(db_name)) + rename(db_name.c_str(), (db_name + ".tmp").c_str()); + + data.fs = databases[s_type->GetOwner()] = new std::fstream(db_name.c_str(), std::ios_base::out | std::ios_base::trunc); + + if (!data.fs->is_open()) + { + Log(this) << "Unable to open " << db_name << " for writing"; + continue; + } + } + else if (!data.fs->is_open()) + continue; + + *data.fs << "OBJECT " << s_type->GetName(); + base->Serialize(data); + *data.fs << "\nEND\n"; + } + + for (std::map<Module *, std::fstream *>::iterator it = databases.begin(), it_end = databases.end(); it != it_end; ++it) { - Anope::string db_name = Anope::DataDir + "/module_" + s_type->GetOwner()->name + ".db"; - databases[s_type->GetOwner()] = new std::fstream(db_name.c_str(), std::ios_base::out | std::ios_base::trunc); + std::fstream *f = it->second; + const Anope::string &db_name = Anope::DataDir + "/" + (it->first ? (it->first->name + ".db") : database_file); + + if (!f->is_open() || !f->good()) + { + this->Write("Unable to write database " + db_name); + + f->close(); + + if (Anope::IsFile((db_name + ".tmp").c_str())) + rename((db_name + ".tmp").c_str(), db_name.c_str()); + } + else + { + f->close(); + unlink((db_name + ".tmp").c_str()); + } + + delete f; } - std::fstream *fd = databases[s_type->GetOwner()]; - - *fd << "OBJECT " << s_type->GetName() << "\n"; - for (Serialize::Data::iterator dit = data.begin(), dit_end = data.end(); dit != dit_end; ++dit) - *fd << "DATA " << dit->first << " " << dit->second.astr() << "\n"; - *fd << "END\n"; } - - if (databases[NULL]->good() == false) + catch (...) { - Log(this) << "Unable to write database"; - databases[NULL]->close(); - if (!Config->NoBackupOkay) - Anope::Quitting = true; - if (IsFile(tmp_db)) - rename(tmp_db.c_str(), DatabaseFile.c_str()); + if (i) + throw; } - else - unlink(tmp_db.c_str()); - for (std::map<Module *, std::fstream *>::iterator it = databases.begin(), it_end = databases.end(); it != it_end; ++it) + if (!i) { - it->second->close(); - delete it->second; + this->Notify(); + exit(0); } return EVENT_CONTINUE; diff --git a/modules/database/db_sql.cpp b/modules/database/db_sql.cpp index 60db11c..56db7b8 100644 --- a/modules/database/db_sql.cpp +++ b/modules/database/db_sql.cpp @@ -11,18 +11,19 @@ #include "module.h" #include "../extra/sql.h" -class SQLSQLInterface : public SQLInterface +using namespace SQL; + +class SQLSQLInterface : public Interface { public: - SQLSQLInterface(Module *o) : SQLInterface(o) { } - virtual ~SQLSQLInterface() { } + SQLSQLInterface(Module *o) : Interface(o) { } - void OnResult(const SQLResult &r) anope_override + void OnResult(const Result &r) anope_override { Log(LOG_DEBUG) << "SQL successfully executed query: " << r.finished_query; } - void OnError(const SQLResult &r) anope_override + void OnError(const Result &r) anope_override { if (!r.GetQuery().query.empty()) Log(LOG_DEBUG) << "Error executing query " << r.finished_query << ": " << r.GetError(); @@ -38,7 +39,7 @@ class ResultSQLSQLInterface : public SQLSQLInterface public: ResultSQLSQLInterface(Module *o, Serializable *ob) : SQLSQLInterface(o), obj(ob) { } - void OnResult(const SQLResult &r) anope_override + void OnResult(const Result &r) anope_override { SQLSQLInterface::OnResult(r); if (r.GetID() > 0 && this->obj) @@ -46,7 +47,7 @@ public: delete this; } - void OnError(const SQLResult &r) anope_override + void OnError(const Result &r) anope_override { SQLSQLInterface::OnError(r); delete this; @@ -55,13 +56,14 @@ public: class DBSQL : public Module, public Pipe { - ServiceReference<SQLProvider> sql; + ServiceReference<Provider> sql; SQLSQLInterface sqlinterface; Anope::string prefix; std::set<Reference<Serializable> > updated_items; bool shutting_down; + bool loading_databases; - void RunBackground(const SQLQuery &q, SQLInterface *iface = NULL) + void RunBackground(const Query &q, Interface *iface = NULL) { if (!this->sql) { @@ -83,7 +85,7 @@ class DBSQL : public Module, public Pipe } public: - DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), sql("", ""), sqlinterface(this), shutting_down(false) + DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), sql("", ""), sqlinterface(this), shutting_down(false), loading_databases(false) { this->SetAuthor("Anope"); @@ -101,21 +103,26 @@ class DBSQL : public Module, public Pipe if (obj && this->sql) { - if (obj->IsCached()) + Data *data = new Data(); + obj->Serialize(*data); + + if (obj->IsCached(data)) + { + delete data; continue; - obj->UpdateCache(); + } + + obj->UpdateCache(data); Serialize::Type *s_type = obj->GetSerializableType(); if (!s_type) continue; - Serialize::Data data = obj->Serialize(); - - std::vector<SQLQuery> create = this->sql->CreateTable(this->prefix + s_type->GetName(), data); + std::vector<Query> create = this->sql->CreateTable(this->prefix + s_type->GetName(), *data); for (unsigned i = 0; i < create.size(); ++i) this->RunBackground(create[i]); - SQLQuery insert = this->sql->BuildInsert(this->prefix + s_type->GetName(), obj->id, data); + Query insert = this->sql->BuildInsert(this->prefix + s_type->GetName(), obj->id, *data); this->RunBackground(insert, new ResultSQLSQLInterface(this, obj)); } } @@ -127,7 +134,7 @@ class DBSQL : public Module, public Pipe { ConfigReader config; Anope::string engine = config.ReadValue("db_sql", "engine", "", 0); - this->sql = ServiceReference<SQLProvider>("SQLProvider", engine); + this->sql = ServiceReference<Provider>("SQL::Provider", engine); this->prefix = config.ReadValue("db_sql", "prefix", "anope_db_", 0); } @@ -150,23 +157,25 @@ class DBSQL : public Module, public Pipe return EVENT_CONTINUE; } + this->loading_databases = true; + const std::vector<Anope::string> type_order = Serialize::Type::GetTypeOrder(); for (unsigned i = 0; i < type_order.size(); ++i) { Serialize::Type *sb = Serialize::Type::Find(type_order[i]); - SQLQuery query("SELECT * FROM `" + this->prefix + sb->GetName() + "`"); - SQLResult res = this->sql->RunQuery(query); + Query query("SELECT * FROM `" + this->prefix + sb->GetName() + "`"); + Result res = this->sql->RunQuery(query); for (int j = 0; j < res.Rows(); ++j) { - Serialize::Data data; + Data *data = new Data(); const std::map<Anope::string, Anope::string> &row = res.Row(j); for (std::map<Anope::string, Anope::string>::const_iterator rit = row.begin(), rit_end = row.end(); rit != rit_end; ++rit) - data[rit->first] << rit->second; + (*data)[rit->first] << rit->second; - Serializable *obj = sb->Unserialize(NULL, data); + Serializable *obj = sb->Unserialize(NULL, *data); try { if (obj) @@ -176,15 +185,22 @@ class DBSQL : public Module, public Pipe { Log(this) << "Unable to convert id for object #" << j << " of type " << sb->GetName(); } + + if (obj) + obj->UpdateCache(data); /* We know this is the most up to date copy */ + else + delete data; } } + this->loading_databases = false; + return EVENT_STOP; } void OnSerializableConstruct(Serializable *obj) anope_override { - if (this->shutting_down) + if (this->shutting_down || this->loading_databases) return; this->updated_items.insert(obj); this->Notify(); diff --git a/modules/database/db_sql_live.cpp b/modules/database/db_sql_live.cpp index 0056159..8d88360 100644 --- a/modules/database/db_sql_live.cpp +++ b/modules/database/db_sql_live.cpp @@ -2,12 +2,14 @@ #include "../extra/sql.h" #include "../commands/os_session.h" +using namespace SQL; + class DBMySQL : public Module, public Pipe { private: Anope::string engine; Anope::string prefix; - ServiceReference<SQLProvider> SQL; + ServiceReference<Provider> SQL; time_t lastwarn; bool ro; bool init; @@ -43,24 +45,24 @@ class DBMySQL : public Module, public Pipe return init && SQL; } - void RunQuery(const SQLQuery &query) + void RunQuery(const Query &query) { /* Can this be threaded? */ this->RunQueryResult(query); } - SQLResult RunQueryResult(const SQLQuery &query) + Result RunQueryResult(const Query &query) { if (this->CheckSQL()) { - SQLResult res = SQL->RunQuery(query); + Result res = SQL->RunQuery(query); if (!res.GetError().empty()) Log(LOG_DEBUG) << "SQL-live got error " << res.GetError() << " for " + res.finished_query; else Log(LOG_DEBUG) << "SQL-live got " << res.Rows() << " rows for " << res.finished_query; return res; } - throw SQLException("No SQL!"); + throw SQL::Exception("No SQL!"); } public: @@ -87,21 +89,26 @@ class DBMySQL : public Module, public Pipe if (obj && this->SQL) { - if (obj->IsCached()) + Data *data = new Data(); + obj->Serialize(*data); + + if (obj->IsCached(data)) + { + delete data; continue; - obj->UpdateCache(); + } + + obj->UpdateCache(data); Serialize::Type *s_type = obj->GetSerializableType(); if (!s_type) continue; - Serialize::Data data = obj->Serialize(); - - std::vector<SQLQuery> create = this->SQL->CreateTable(this->prefix + s_type->GetName(), data); + std::vector<Query> create = this->SQL->CreateTable(this->prefix + s_type->GetName(), *data); for (unsigned i = 0; i < create.size(); ++i) this->RunQueryResult(create[i]); - SQLResult res = this->RunQueryResult(this->SQL->BuildInsert(this->prefix + s_type->GetName(), obj->id, data)); + Result res = this->RunQueryResult(this->SQL->BuildInsert(this->prefix + s_type->GetName(), obj->id, *data)); if (obj->id != res.GetID()) { /* In this case obj is new, so place it into the object map */ @@ -129,7 +136,7 @@ class DBMySQL : public Module, public Pipe { ConfigReader config; this->engine = config.ReadValue("db_sql", "engine", "", 0); - this->SQL = ServiceReference<SQLProvider>("SQLProvider", this->engine); + this->SQL = ServiceReference<Provider>("SQL::Provider", this->engine); this->prefix = config.ReadValue("db_sql", "prefix", "anope_db_", 0); } @@ -157,11 +164,11 @@ class DBMySQL : public Module, public Pipe if (!this->CheckInit() || obj->GetTimestamp() == Anope::CurTime) return; - SQLQuery query("SELECT * FROM `" + this->prefix + obj->GetName() + "` WHERE (`timestamp` > " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " OR `timestamp` IS NULL)"); + Query query("SELECT * FROM `" + this->prefix + obj->GetName() + "` WHERE (`timestamp` > " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " OR `timestamp` IS NULL)"); obj->UpdateTimestamp(); - SQLResult res = this->RunQueryResult(query); + Result res = this->RunQueryResult(query); bool clear_null = false; for (int i = 0; i < res.Rows(); ++i) @@ -191,17 +198,17 @@ class DBMySQL : public Module, public Pipe } else { - Serialize::Data data; + Data *data = new Data(); for (std::map<Anope::string, Anope::string>::const_iterator it = row.begin(), it_end = row.end(); it != it_end; ++it) - data[it->first] << it->second; + (*data)[it->first] << it->second; Serializable *s = NULL; std::map<unsigned int, Serializable *>::iterator it = obj->objects.find(id); if (it != obj->objects.end()) s = it->second; - Serializable *new_s = obj->Unserialize(s, data); + Serializable *new_s = obj->Unserialize(s, *data); if (new_s) { // If s == new_s then s->id == new_s->id @@ -209,11 +216,16 @@ class DBMySQL : public Module, public Pipe { new_s->id = id; obj->objects[id] = new_s; - new_s->UpdateCache(); /* We know this is the most up to date copy */ + new_s->UpdateCache(data); /* We know this is the most up to date copy */ } + else + delete data; } else + { + delete data; s->Destroy(); + } } } diff --git a/modules/extra/m_chanstats.cpp b/modules/extra/m_chanstats.cpp index b50592b..7096b39 100644 --- a/modules/extra/m_chanstats.cpp +++ b/modules/extra/m_chanstats.cpp @@ -1,16 +1,16 @@ #include "module.h" #include "../extra/sql.h" -class MySQLInterface : public SQLInterface +class MySQLInterface : public SQL::Interface { public: - MySQLInterface(Module *o) : SQLInterface(o) { } + MySQLInterface(Module *o) : SQL::Interface(o) { } - void OnResult(const SQLResult &r) anope_override + void OnResult(const SQL::Result &r) anope_override { } - void OnError(const SQLResult &r) anope_override + void OnError(const SQL::Result &r) anope_override { if (!r.GetQuery().query.empty()) Log(LOG_DEBUG) << "Chanstats: Error executing query " << r.finished_query << ": " << r.GetError(); @@ -21,13 +21,13 @@ class MySQLInterface : public SQLInterface class MChanstats : public Module { - ServiceReference<SQLProvider> sql; + ServiceReference<SQL::Provider> sql; MySQLInterface sqlinterface; - SQLQuery query; + SQL::Query query; Anope::string SmileysHappy, SmileysSad, SmileysOther, prefix; std::vector<Anope::string> TableList, ProcedureList, EventList; - void RunQuery(const SQLQuery &q) + void RunQuery(const SQL::Query &q) { if (sql) sql->Run(&sqlinterface, q); @@ -70,7 +70,7 @@ class MChanstats : public Module if (!sql) return; - SQLResult r = this->sql->RunQuery(this->sql->GetTables(prefix)); + SQL::Result r = this->sql->RunQuery(this->sql->GetTables(prefix)); for (int i = 0; i < r.Rows(); ++i) { const std::map<Anope::string, Anope::string> &map = r.Row(i); @@ -359,7 +359,7 @@ class MChanstats : public Module SmileysOther = config.ReadValue("chanstats", "SmileysOther", ":/", 0); Anope::string engine = config.ReadValue("chanstats", "engine", "", 0); - this->sql = ServiceReference<SQLProvider>("SQLProvider", engine); + this->sql = ServiceReference<SQL::Provider>("SQL::Provider", engine); if (sql) this->CheckTables(); else @@ -371,8 +371,8 @@ class MChanstats : public Module if (!u || !u->Account() || !c->ci || !c->ci->HasFlag(CI_STATS)) return; query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);"; - query.setValue("channel", c->name); - query.setValue("nick", GetDisplay(u)); + query.SetValue("channel", c->name); + query.SetValue("nick", GetDisplay(u)); this->RunQuery(query); } EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelModeName Name, const Anope::string ¶m) anope_override @@ -392,8 +392,8 @@ class MChanstats : public Module return; query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);"; - query.setValue("channel", c->name); - query.setValue("nick", GetDisplay(u)); + query.SetValue("channel", c->name); + query.SetValue("nick", GetDisplay(u)); this->RunQuery(query); } public: @@ -403,13 +403,13 @@ class MChanstats : public Module return; query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0);"; - query.setValue("channel", c->name); - query.setValue("nick", GetDisplay(target)); + query.SetValue("channel", c->name); + query.SetValue("nick", GetDisplay(target)); this->RunQuery(query); query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);"; - query.setValue("channel", c->name); - query.setValue("nick", GetDisplay(source.GetUser())); + query.SetValue("channel", c->name); + query.SetValue("nick", GetDisplay(source.GetUser())); this->RunQuery(query); } void OnPrivmsg(User *u, Channel *c, Anope::string &msg) anope_override @@ -437,33 +437,33 @@ class MChanstats : public Module words = words - smileys_happy - smileys_sad - smileys_other; query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 1, @letters@, @words@, @action@, " "@smileys_happy@, @smileys_sad@, @smileys_other@, '0', '0', '0', '0');"; - query.setValue("channel", c->name); - query.setValue("nick", GetDisplay(u)); - query.setValue("letters", letters); - query.setValue("words", words); - query.setValue("action", action); - query.setValue("smileys_happy", smileys_happy); - query.setValue("smileys_sad", smileys_sad); - query.setValue("smileys_other", smileys_other); + query.SetValue("channel", c->name); + query.SetValue("nick", GetDisplay(u)); + query.SetValue("letters", letters); + query.SetValue("words", words); + query.SetValue("action", action); + query.SetValue("smileys_happy", smileys_happy); + query.SetValue("smileys_sad", smileys_sad); + query.SetValue("smileys_other", smileys_other); this->RunQuery(query); } void OnDelCore(NickCore *nc) anope_override { query = "DELETE FROM `" + prefix + "chanstats` WHERE `nick` = @nick@;"; - query.setValue("nick", nc->display); + query.SetValue("nick", nc->display); this->RunQuery(query); } void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay) anope_override { query = "CALL " + prefix + "chanstats_proc_chgdisplay(@old_display@, @new_display@);"; - query.setValue("old_display", nc->display); - query.setValue("new_display", newdisplay); + query.SetValue("old_display", nc->display); + query.SetValue("new_display", newdisplay); this->RunQuery(query); } void OnChanDrop(ChannelInfo *ci) anope_override { query = "DELETE FROM `" + prefix + "chanstats` WHERE `chan` = @channel@;"; - query.setValue("channel", ci->name); + query.SetValue("channel", ci->name); this->RunQuery(query); } }; diff --git a/modules/extra/m_mysql.cpp b/modules/extra/m_mysql.cpp index 47f6f41..a8433fd 100644 --- a/modules/extra/m_mysql.cpp +++ b/modules/extra/m_mysql.cpp @@ -5,6 +5,8 @@ #include <mysql/mysql.h> #include "sql.h" +using namespace SQL; + /** Non blocking threaded MySQL API, based loosely from InspIRCd's m_mysql.cpp * * This module spawns a single thread that is used to execute blocking MySQL queries. @@ -24,32 +26,32 @@ struct QueryRequest /* The connection to the database */ MySQLService *service; /* The interface to use once we have the result to send the data back */ - SQLInterface *sqlinterface; + Interface *sqlinterface; /* The actual query */ - SQLQuery query; + Query query; - QueryRequest(MySQLService *s, SQLInterface *i, const SQLQuery &q) : service(s), sqlinterface(i), query(q) { } + QueryRequest(MySQLService *s, Interface *i, const Query &q) : service(s), sqlinterface(i), query(q) { } }; /** A query result */ struct QueryResult { /* The interface to send the data back on */ - SQLInterface *sqlinterface; + Interface *sqlinterface; /* The result */ - SQLResult result; + Result result; - QueryResult(SQLInterface *i, SQLResult &r) : sqlinterface(i), result(r) { } + QueryResult(Interface *i, Result &r) : sqlinterface(i), result(r) { } }; /** A MySQL result */ -class MySQLResult : public SQLResult +class MySQLResult : public Result { MYSQL_RES *res; public: - MySQLResult(unsigned int i, const SQLQuery &q, const Anope::string &fq, MYSQL_RES *r) : SQLResult(i, q, fq), res(r) + MySQLResult(unsigned int i, const Query &q, const Anope::string &fq, MYSQL_RES *r) : Result(i, q, fq), res(r) { unsigned num_fields = res ? mysql_num_fields(res) : 0; @@ -79,7 +81,7 @@ class MySQLResult : public SQLResult } } - MySQLResult(const SQLQuery &q, const Anope::string &fq, const Anope::string &err) : SQLResult(0, q, fq, err), res(NULL) + MySQLResult(const Query &q, const Anope::string &fq, const Anope::string &err) : Result(0, q, fq, err), res(NULL) { } @@ -92,7 +94,7 @@ class MySQLResult : public SQLResult /** A MySQL connection, there can be multiple */ -class MySQLService : public SQLProvider +class MySQLService : public Provider { std::map<Anope::string, std::set<Anope::string> > active_schema; @@ -120,21 +122,21 @@ class MySQLService : public SQLProvider ~MySQLService(); - void Run(SQLInterface *i, const SQLQuery &query) anope_override; + void Run(Interface *i, const Query &query) anope_override; - SQLResult RunQuery(const SQLQuery &query) anope_override; + Result RunQuery(const Query &query) anope_override; - std::vector<SQLQuery> CreateTable(const Anope::string &table, const Serialize::Data &data) anope_override; + std::vector<Query> CreateTable(const Anope::string &table, const Data &data) anope_override; - SQLQuery BuildInsert(const Anope::string &table, unsigned int id, Serialize::Data &data); + Query BuildInsert(const Anope::string &table, unsigned int id, Data &data) anope_override; - SQLQuery GetTables(const Anope::string &prefix) anope_override; + Query GetTables(const Anope::string &prefix) anope_override; void Connect(); bool CheckConnection(); - Anope::string BuildQuery(const SQLQuery &q); + Anope::string BuildQuery(const Query &q); Anope::string FromUnixtime(time_t); }; @@ -235,7 +237,7 @@ class ModuleSQL : public Module, public Pipe Log(LOG_NORMAL, "mysql") << "MySQL: Successfully connected to server " << connname << " (" << server << ")"; } - catch (const SQLException &ex) + catch (const SQL::Exception &ex) { Log(LOG_NORMAL, "mysql") << "MySQL: " << ex.GetReason(); } @@ -280,7 +282,7 @@ class ModuleSQL : public Module, public Pipe const QueryResult &qr = *it; if (!qr.sqlinterface) - throw SQLException("NULL qr.sqlinterface in MySQLPipe::OnNotify() ?"); + throw SQL::Exception("NULL qr.sqlinterface in MySQLPipe::OnNotify() ?"); if (qr.result.GetError().empty()) qr.sqlinterface->OnResult(qr.result); @@ -291,7 +293,7 @@ class ModuleSQL : public Module, public Pipe }; MySQLService::MySQLService(Module *o, const Anope::string &n, const Anope::string &d, const Anope::string &s, const Anope::string &u, const Anope::string &p, int po) -: SQLProvider(o, n), database(d), server(s), user(u), password(p), port(po), sql(NULL) +: Provider(o, n), database(d), server(s), user(u), password(p), port(po), sql(NULL) { Connect(); } @@ -310,7 +312,7 @@ MySQLService::~MySQLService() if (r.service == this) { if (r.sqlinterface) - r.sqlinterface->OnError(SQLResult(0, r.query, "SQL Interface is going away")); + r.sqlinterface->OnError(Result(0, r.query, "SQL Interface is going away")); me->QueryRequests.erase(me->QueryRequests.begin() + i - 1); } } @@ -318,7 +320,7 @@ MySQLService::~MySQLService() me->DThread->Unlock(); } -void MySQLService::Run(SQLInterface *i, const SQLQuery &query) +void MySQLService::Run(Interface *i, const Query &query) { me->DThread->Lock(); me->QueryRequests.push_back(QueryRequest(this, i, query)); @@ -326,7 +328,7 @@ void MySQLService::Run(SQLInterface *i, const SQLQuery &query) me->DThread->Wakeup(); } -SQLResult MySQLService::RunQuery(const SQLQuery &query) +Result MySQLService::RunQuery(const Query &query) { this->Lock.Lock(); @@ -348,16 +350,16 @@ SQLResult MySQLService::RunQuery(const SQLQuery &query) } } -std::vector<SQLQuery> MySQLService::CreateTable(const Anope::string &table, const Serialize::Data &data) +std::vector<Query> MySQLService::CreateTable(const Anope::string &table, const Data &data) { - std::vector<SQLQuery> queries; + std::vector<Query> queries; std::set<Anope::string> &known_cols = this->active_schema[table]; if (known_cols.empty()) { Log(LOG_DEBUG) << "m_mysql: Fetching columns for " << table; - SQLResult columns = this->RunQuery("SHOW COLUMNS FROM `" + table + "`"); + Result columns = this->RunQuery("SHOW COLUMNS FROM `" + table + "`"); for (int i = 0; i < columns.Rows(); ++i) { const Anope::string &column = columns.Get(i, "Field"); @@ -371,15 +373,13 @@ std::vector<SQLQuery> MySQLService::CreateTable(const Anope::string &table, cons { Anope::string query_text = "CREATE TABLE `" + table + "` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT," " `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"; - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) { known_cols.insert(it->first); query_text += ", `" + it->first + "` "; - if (it->second.GetType() == Serialize::DT_INT) + if (data.GetType(it->first) == Serialize::Data::DT_INT) query_text += "int(11)"; - else if (it->second.GetMax() > 0) - query_text += "varchar(" + stringify(it->second.GetMax()) + ")"; else query_text += "text"; } @@ -387,7 +387,7 @@ std::vector<SQLQuery> MySQLService::CreateTable(const Anope::string &table, cons queries.push_back(query_text); } else - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) { if (known_cols.count(it->first) > 0) continue; @@ -395,10 +395,8 @@ std::vector<SQLQuery> MySQLService::CreateTable(const Anope::string &table, cons known_cols.insert(it->first); Anope::string query_text = "ALTER TABLE `" + table + "` ADD `" + it->first + "` "; - if (it->second.GetType() == Serialize::DT_INT) + if (data.GetType(it->first) == Serialize::Data::DT_INT) query_text += "int(11)"; - else if (it->second.GetMax() > 0) - query_text += "varchar(" + stringify(it->second.GetMax()) + ")"; else query_text += "text"; @@ -408,35 +406,39 @@ std::vector<SQLQuery> MySQLService::CreateTable(const Anope::string &table, cons return queries; } -SQLQuery MySQLService::BuildInsert(const Anope::string &table, unsigned int id, Serialize::Data &data) +Query MySQLService::BuildInsert(const Anope::string &table, unsigned int id, Data &data) anope_override { /* Empty columns not present in the data set */ const std::set<Anope::string> &known_cols = this->active_schema[table]; for (std::set<Anope::string>::iterator it = known_cols.begin(), it_end = known_cols.end(); it != it_end; ++it) - if (*it != "id" && *it != "timestamp" && data.count(*it) == 0) + if (*it != "id" && *it != "timestamp" && data.data.count(*it) == 0) data[*it] << ""; Anope::string query_text = "INSERT INTO `" + table + "` (`id`"; - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) query_text += ",`" + it->first + "`"; query_text += ") VALUES (" + stringify(id); - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) query_text += ",@" + it->first + "@"; query_text += ") ON DUPLICATE KEY UPDATE "; - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) query_text += "`" + it->first + "`=VALUES(`" + it->first + "`),"; query_text.erase(query_text.end() - 1); - SQLQuery query(query_text); - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) - query.setValue(it->first, it->second.astr()); + Query query(query_text); + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) + { + Anope::string buf; + *it->second >> buf; + query.SetValue(it->first, buf); + } return query; } -SQLQuery MySQLService::GetTables(const Anope::string &prefix) +Query MySQLService::GetTables(const Anope::string &prefix) { - return SQLQuery("SHOW TABLES LIKE '" + prefix + "%';"); + return Query("SHOW TABLES LIKE '" + prefix + "%';"); } void MySQLService::Connect() @@ -449,7 +451,7 @@ void MySQLService::Connect() bool connect = mysql_real_connect(this->sql, this->server.c_str(), this->user.c_str(), this->password.c_str(), this->database.c_str(), this->port, NULL, CLIENT_MULTI_RESULTS); if (!connect) - throw SQLException("Unable to connect to MySQL service " + this->name + ": " + mysql_error(this->sql)); + throw SQL::Exception("Unable to connect to MySQL service " + this->name + ": " + mysql_error(this->sql)); Log(LOG_DEBUG) << "Successfully connected to MySQL service " << this->name << " at " << this->server << ":" << this->port; } @@ -463,7 +465,7 @@ bool MySQLService::CheckConnection() { this->Connect(); } - catch (const SQLException &) + catch (const SQL::Exception &) { return false; } @@ -479,7 +481,7 @@ Anope::string MySQLService::Escape(const Anope::string &query) return buffer; } -Anope::string MySQLService::BuildQuery(const SQLQuery &q) +Anope::string MySQLService::BuildQuery(const Query &q) { Anope::string real_query = q.query; @@ -505,7 +507,7 @@ void DispatcherThread::Run() QueryRequest &r = me->QueryRequests.front(); this->Unlock(); - SQLResult sresult = r.service->RunQuery(r.query); + Result sresult = r.service->RunQuery(r.query); this->Lock(); if (!me->QueryRequests.empty() && me->QueryRequests.front().query == r.query) diff --git a/modules/extra/m_sql_authentication.cpp b/modules/extra/m_sql_authentication.cpp index ce7a275..e1afbc9 100644 --- a/modules/extra/m_sql_authentication.cpp +++ b/modules/extra/m_sql_authentication.cpp @@ -3,13 +3,13 @@ static Module *me; -class SQLAuthenticationResult : public SQLInterface +class SQLAuthenticationResult : public SQL::Interface { Reference<User> user; IdentifyRequest *req; public: - SQLAuthenticationResult(User *u, IdentifyRequest *r) : SQLInterface(me), user(u), req(r) + SQLAuthenticationResult(User *u, IdentifyRequest *r) : SQL::Interface(me), user(u), req(r) { req->Hold(me); } @@ -19,7 +19,7 @@ class SQLAuthenticationResult : public SQLInterface req->Release(me); } - void OnResult(const SQLResult &r) anope_override + void OnResult(const SQL::Result &r) anope_override { if (r.Rows() == 0) { @@ -35,7 +35,7 @@ class SQLAuthenticationResult : public SQLInterface { email = r.Get(0, "email"); } - catch (const SQLException &) { } + catch (const SQL::Exception &) { } NickAlias *na = NickAlias::Find(req->GetAccount()); if (na == NULL) @@ -62,7 +62,7 @@ class SQLAuthenticationResult : public SQLInterface delete this; } - void OnError(const SQLResult &r) anope_override + void OnError(const SQL::Result &r) anope_override { Log(this->owner) << "m_sql_authentication: Error executing query " << r.GetQuery().query << ": " << r.GetError(); delete this; @@ -76,7 +76,7 @@ class ModuleSQLAuthentication : public Module bool disable_register; Anope::string disable_reason; - ServiceReference<SQLProvider> SQL; + ServiceReference<SQL::Provider> SQL; public: ModuleSQLAuthentication(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED) @@ -100,7 +100,7 @@ class ModuleSQLAuthentication : public Module this->disable_register = config.ReadFlag("m_sql_authentication", "disable_ns_register", "false", 0); this->disable_reason = config.ReadValue("m_sql_authentication", "disable_reason", "", 0); - this->SQL = ServiceReference<SQLProvider>("SQLProvider", this->engine); + this->SQL = ServiceReference<SQL::Provider>("SQL::Provider", this->engine); } EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> ¶ms) anope_override @@ -122,18 +122,18 @@ class ModuleSQLAuthentication : public Module return; } - SQLQuery q(this->query); - q.setValue("a", req->GetAccount()); - q.setValue("p", req->GetPassword()); + SQL::Query q(this->query); + q.SetValue("a", req->GetAccount()); + q.SetValue("p", req->GetPassword()); if (u) { - q.setValue("n", u->nick); - q.setValue("i", u->ip); + q.SetValue("n", u->nick); + q.SetValue("i", u->ip); } else { - q.setValue("n", ""); - q.setValue("i", ""); + q.SetValue("n", ""); + q.SetValue("i", ""); } diff --git a/modules/extra/m_sql_oper.cpp b/modules/extra/m_sql_oper.cpp index 523272a..dd1f13b 100644 --- a/modules/extra/m_sql_oper.cpp +++ b/modules/extra/m_sql_oper.cpp @@ -1,7 +1,7 @@ #include "module.h" #include "sql.h" -class SQLOperResult : public SQLInterface +class SQLOperResult : public SQL::Interface { Reference<User> user; @@ -13,9 +13,9 @@ class SQLOperResult : public SQLInterface }; public: - SQLOperResult(Module *m, User *u) : SQLInterface(m), user(u) { } + SQLOperResult(Module *m, User *u) : SQL::Interface(m), user(u) { } - void OnResult(const SQLResult &r) anope_override + void OnResult(const SQL::Result &r) anope_override { SQLOperResultDeleter d(this); @@ -27,7 +27,7 @@ class SQLOperResult : public SQLInterface { opertype = r.Get(0, "opertype"); } - catch (const SQLException &) + catch (const SQL::Exception &) { return; } @@ -39,7 +39,7 @@ class SQLOperResult : public SQLInterface { modes = r.Get(0, "modes"); } - catch (const SQLException &) { } + catch (const SQL::Exception &) { } if (opertype.empty()) { @@ -79,7 +79,7 @@ class SQLOperResult : public SQLInterface } } - void OnError(const SQLResult &r) anope_override + void OnError(const SQL::Result &r) anope_override { SQLOperResultDeleter d(this); Log(this->owner) << "m_sql_oper: Error executing query " << r.GetQuery().query << ": " << r.GetError(); @@ -91,7 +91,7 @@ class ModuleSQLOper : public Module Anope::string engine; Anope::string query; - ServiceReference<SQLProvider> SQL; + ServiceReference<SQL::Provider> SQL; public: ModuleSQLOper(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED) @@ -111,7 +111,7 @@ class ModuleSQLOper : public Module this->engine = config.ReadValue("m_sql_oper", "engine", "", 0); this->query = config.ReadValue("m_sql_oper", "query", "", 0); - this->SQL = ServiceReference<SQLProvider>("SQLProvider", this->engine); + this->SQL = ServiceReference<SQL::Provider>("SQL::Provider", this->engine); } void OnNickIdentify(User *u) anope_override @@ -122,9 +122,9 @@ class ModuleSQLOper : public Module return; } - SQLQuery q(this->query); - q.setValue("a", u->Account()->display); - q.setValue("i", u->ip); + SQL::Query q(this->query); + q.SetValue("a", u->Account()->display); + q.SetValue("i", u->ip); this->SQL->Run(new SQLOperResult(this, u), q); diff --git a/modules/extra/m_sqlite.cpp b/modules/extra/m_sqlite.cpp index 9713454..5d59c3e 100644 --- a/modules/extra/m_sqlite.cpp +++ b/modules/extra/m_sqlite.cpp @@ -4,22 +4,24 @@ #include <sqlite3.h> #include "sql.h" +using namespace SQL; + /* SQLite3 API, based from InspiRCd */ /** A SQLite result */ -class SQLiteResult : public SQLResult +class SQLiteResult : public Result { public: - SQLiteResult(unsigned int i, const SQLQuery &q, const Anope::string &fq) : SQLResult(i, q, fq) + SQLiteResult(unsigned int i, const Query &q, const Anope::string &fq) : Result(i, q, fq) { } - SQLiteResult(const SQLQuery &q, const Anope::string &fq, const Anope::string &err) : SQLResult(0, q, fq, err) + SQLiteResult(const Query &q, const Anope::string &fq, const Anope::string &err) : Result(0, q, fq, err) { } - void addRow(const std::map<Anope::string, Anope::string> &data) + void AddRow(const std::map<Anope::string, Anope::string> &data) { this->entries.push_back(data); } @@ -27,7 +29,7 @@ class SQLiteResult : public SQLResult /** A SQLite database, there can be multiple */ -class SQLiteService : public SQLProvider +class SQLiteService : public Provider { std::map<Anope::string, std::set<Anope::string> > active_schema; @@ -42,17 +44,17 @@ class SQLiteService : public SQLProvider ~SQLiteService(); - void Run(SQLInterface *i, const SQLQuery &query) anope_override; + void Run(Interface *i, const Query &query) anope_override; - SQLResult RunQuery(const SQLQuery &query); + Result RunQuery(const Query &query); - std::vector<SQLQuery> CreateTable(const Anope::string &table, const Serialize::Data &data) anope_override; + std::vector<Query> CreateTable(const Anope::string &table, const Data &data) anope_override; - SQLQuery BuildInsert(const Anope::string &table, unsigned int id, Serialize::Data &data); + Query BuildInsert(const Anope::string &table, unsigned int id, Data &data); - SQLQuery GetTables(const Anope::string &prefix); + Query GetTables(const Anope::string &prefix); - Anope::string BuildQuery(const SQLQuery &q); + Anope::string BuildQuery(const Query &q); Anope::string FromUnixtime(time_t); }; @@ -116,7 +118,7 @@ class ModuleSQLite : public Module Log(LOG_NORMAL, "sqlite") << "SQLite: Successfully added database " << database; } - catch (const SQLException &ex) + catch (const SQL::Exception &ex) { Log(LOG_NORMAL, "sqlite") << "SQLite: " << ex.GetReason(); } @@ -126,11 +128,11 @@ class ModuleSQLite : public Module }; SQLiteService::SQLiteService(Module *o, const Anope::string &n, const Anope::string &d) -: SQLProvider(o, n), database(d), sql(NULL) +: Provider(o, n), database(d), sql(NULL) { int db = sqlite3_open_v2(database.c_str(), &this->sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); if (db != SQLITE_OK) - throw SQLException("Unable to open SQLite database " + database + ": " + sqlite3_errmsg(this->sql)); + throw SQL::Exception("Unable to open SQLite database " + database + ": " + sqlite3_errmsg(this->sql)); } SQLiteService::~SQLiteService() @@ -139,16 +141,16 @@ SQLiteService::~SQLiteService() sqlite3_close(this->sql); } -void SQLiteService::Run(SQLInterface *i, const SQLQuery &query) +void SQLiteService::Run(Interface *i, const Query &query) { - SQLResult res = this->RunQuery(query); + Result res = this->RunQuery(query); if (!res.GetError().empty()) i->OnError(res); else i->OnResult(res); } -SQLResult SQLiteService::RunQuery(const SQLQuery &query) +Result SQLiteService::RunQuery(const Query &query) { Anope::string real_query = this->BuildQuery(query); sqlite3_stmt *stmt; @@ -173,7 +175,7 @@ SQLResult SQLiteService::RunQuery(const SQLQuery &query) if (data && *data) items[columns[i]] = data; } - result.addRow(items); + result.AddRow(items); } result.id = sqlite3_last_insert_rowid(this->sql); @@ -186,16 +188,16 @@ SQLResult SQLiteService::RunQuery(const SQLQuery &query) return result; } -std::vector<SQLQuery> SQLiteService::CreateTable(const Anope::string &table, const Serialize::Data &data) +std::vector<Query> SQLiteService::CreateTable(const Anope::string &table, const Data &data) { - std::vector<SQLQuery> queries; + std::vector<Query> queries; std::set<Anope::string> &known_cols = this->active_schema[table]; if (known_cols.empty()) { Log(LOG_DEBUG) << "m_sqlite: Fetching columns for " << table; - SQLResult columns = this->RunQuery("PRAGMA table_info(" + table + ")"); + Result columns = this->RunQuery("PRAGMA table_info(" + table + ")"); for (int i = 0; i < columns.Rows(); ++i) { const Anope::string &column = columns.Get(i, "name"); @@ -209,12 +211,12 @@ std::vector<SQLQuery> SQLiteService::CreateTable(const Anope::string &table, con { Anope::string query_text = "CREATE TABLE `" + table + "` (`id` INTEGER PRIMARY KEY, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP"; - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) { known_cols.insert(it->first); query_text += ", `" + it->first + "` "; - if (it->second.GetType() == Serialize::DT_INT) + if (data.GetType(it->first) == Serialize::Data::DT_INT) query_text += "int(11)"; else query_text += "text"; @@ -234,7 +236,7 @@ std::vector<SQLQuery> SQLiteService::CreateTable(const Anope::string &table, con queries.push_back(query_text); } else - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) { if (known_cols.count(it->first) > 0) continue; @@ -242,7 +244,7 @@ std::vector<SQLQuery> SQLiteService::CreateTable(const Anope::string &table, con known_cols.insert(it->first); Anope::string query_text = "ALTER TABLE `" + table + "` ADD `" + it->first + "` "; - if (it->second.GetType() == Serialize::DT_INT) + if (data.GetType(it->first) == Serialize::Data::DT_INT) query_text += "int(11)"; else query_text += "text"; @@ -253,38 +255,42 @@ std::vector<SQLQuery> SQLiteService::CreateTable(const Anope::string &table, con return queries; } -SQLQuery SQLiteService::BuildInsert(const Anope::string &table, unsigned int id, Serialize::Data &data) +Query SQLiteService::BuildInsert(const Anope::string &table, unsigned int id, Data &data) { /* Empty columns not present in the data set */ const std::set<Anope::string> &known_cols = this->active_schema[table]; for (std::set<Anope::string>::iterator it = known_cols.begin(), it_end = known_cols.end(); it != it_end; ++it) - if (*it != "id" && *it != "timestamp" && data.count(*it) == 0) + if (*it != "id" && *it != "timestamp" && data.data.count(*it) == 0) data[*it] << ""; Anope::string query_text = "REPLACE INTO `" + table + "` ("; if (id > 0) query_text += "`id`,"; - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) query_text += "`" + it->first + "`,"; query_text.erase(query_text.length() - 1); query_text += ") VALUES ("; if (id > 0) query_text += stringify(id) + ","; - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) query_text += "@" + it->first + "@,"; query_text.erase(query_text.length() - 1); query_text += ")"; - SQLQuery query(query_text); - for (Serialize::Data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) - query.setValue(it->first, it->second.astr()); + Query query(query_text); + for (Data::Map::const_iterator it = data.data.begin(), it_end = data.data.end(); it != it_end; ++it) + { + Anope::string buf; + *it->second >> buf; + query.SetValue(it->first, buf); + } return query; } -SQLQuery SQLiteService::GetTables(const Anope::string &prefix) +Query SQLiteService::GetTables(const Anope::string &prefix) { - return SQLQuery("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '" + prefix + "%';"); + return Query("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '" + prefix + "%';"); } Anope::string SQLiteService::Escape(const Anope::string &query) @@ -295,7 +301,7 @@ Anope::string SQLiteService::Escape(const Anope::string &query) return buffer; } -Anope::string SQLiteService::BuildQuery(const SQLQuery &q) +Anope::string SQLiteService::BuildQuery(const Query &q) { Anope::string real_query = q.query; diff --git a/modules/extra/sql.h b/modules/extra/sql.h index 89686bf..f8c7a59 100644 --- a/modules/extra/sql.h +++ b/modules/extra/sql.h @@ -1,139 +1,219 @@ - -/** A SQL exception, can be thrown at various points +/* + * (C) 2003-2012 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. */ -class SQLException : public ModuleException + +namespace SQL { - public: - SQLException(const Anope::string &reason) : ModuleException(reason) { } - virtual ~SQLException() throw() { } -}; + class Data : public Serialize::Data + { + public: + typedef std::map<Anope::string, std::stringstream *> Map; + Map data; + std::map<Anope::string, Type> types; -/** A SQL query - */ + ~Data() + { + Clear(); + } -struct QueryData -{ - Anope::string data; - bool escape; -}; + std::iostream& operator[](const Anope::string &key) anope_override + { + std::stringstream *&ss = data[key]; + if (!ss) + ss = new std::stringstream(); + return *ss; + } -struct SQLQuery -{ - Anope::string query; - std::map<Anope::string, QueryData> parameters; + bool IsEqual(Serialize::Data *other) anope_override + { + try + { + Data *o = anope_dynamic_static_cast<Data *>(other); + + for (std::map<Anope::string, std::stringstream *>::const_iterator it = o->data.begin(), it_end = o->data.end(); it != it_end; ++it) + if (!this->data.count(it->first) || it->second->str() != this->data[it->first]->str()) + return false; + + return true; + } + catch (const CoreException &ex) + { + Log(LOG_DEBUG) << ex.GetReason(); + } + + return false; + } - SQLQuery() { } - SQLQuery(const Anope::string &q) : query(q) { } + std::map<Anope::string, std::iostream *> GetData() const + { + std::map<Anope::string, std::iostream *> d; + for (std::map<Anope::string, std::stringstream *>::const_iterator it = this->data.begin(), it_end = this->data.end(); it != it_end; ++it) + d[it->first] = it->second; + return d; + } - SQLQuery& operator=(const Anope::string &q) - { - this->query = q; - this->parameters.clear(); - return *this; - } + void Clear() + { + for (std::map<Anope::string, std::stringstream *>::iterator it = this->data.begin(), it_end = this->data.end(); it != it_end; ++it) + delete it->second; + this->data.clear(); + } + + void SetType(const Anope::string &key, Type t) anope_override + { + this->types[key] = t; + } + + Type GetType(const Anope::string &key) const anope_override + { + std::map<Anope::string, Type>::const_iterator it = this->types.find(key); + if (it != this->types.end()) + return it->second; + return DT_TEXT; + } + }; - bool operator==(const SQLQuery &other) const + /** A SQL exception, can be thrown at various points + */ + class Exception : public ModuleException { - return this->query == other.query; - } + public: + Exception(const Anope::string &reason) : ModuleException(reason) { } + + virtual ~Exception() throw() { } + }; + + /** A SQL query + */ - inline bool operator!=(const SQLQuery &other) const + struct QueryData { - return !(*this == other); - } + Anope::string data; + bool escape; + }; - template<typename T> void setValue(const Anope::string &key, const T& value, bool escape = true) + struct Query { - try + Anope::string query; + std::map<Anope::string, QueryData> parameters; + + Query() { } + Query(const Anope::string &q) : query(q) { } + + Query& operator=(const Anope::string &q) { - Anope::string string_value = stringify(value); - this->parameters[key].data = string_value; - this->parameters[key].escape = escape; + this->query = q; + this->parameters.clear(); + return *this; } - catch (const ConvertException &ex) { } - } -}; -/** A result from a SQL query - */ -class SQLResult -{ - protected: - /* Rows, column, item */ - std::vector<std::map<Anope::string, Anope::string> > entries; - SQLQuery query; - Anope::string error; - public: - unsigned int id; - Anope::string finished_query; + bool operator==(const Query &other) const + { + return this->query == other.query; + } - SQLResult() : id(0) { } - SQLResult(unsigned int i, const SQLQuery &q, const Anope::string &fq, const Anope::string &err = "") : query(q), error(err), id(i), finished_query(fq) { } + inline bool operator!=(const Query &other) const + { + return !(*this == other); + } + + template<typename T> void SetValue(const Anope::string &key, const T& value, bool escape = true) + { + try + { + Anope::string string_value = stringify(value); + this->parameters[key].data = string_value; + this->parameters[key].escape = escape; + } + catch (const ConvertException &ex) { } + } + }; - inline operator bool() const { return this->error.empty(); } + /** A result from a SQL query + */ + class Result + { + protected: + /* Rows, column, item */ + std::vector<std::map<Anope::string, Anope::string> > entries; + Query query; + Anope::string error; + public: + unsigned int id; + Anope::string finished_query; - inline const unsigned int GetID() const { return this->id; } - inline const SQLQuery &GetQuery() const { return this->query; } - inline const Anope::string &GetError() const { return this->error; } + Result() : id(0) { } + Result(unsigned int i, const Query &q, const Anope::string &fq, const Anope::string &err = "") : query(q), error(err), id(i), finished_query(fq) { } - int Rows() const { return this->entries.size(); } + inline operator bool() const { return this->error.empty(); } - const std::map<Anope::string, Anope::string> &Row(size_t index) const - { - try + inline const unsigned int GetID() const { return this->id; } + inline const Query &GetQuery() const { return this->query; } + inline const Anope::string &GetError() const { return this->error; } + + int Rows() const { return this->entries.size(); } + + const std::map<Anope::string, Anope::string> &Row(size_t index) const { - return this->entries.at(index); + try + { + return this->entries.at(index); + } + catch (const std::out_of_range &) + { + throw Exception("Out of bounds access to SQLResult"); + } } - catch (const std::out_of_range &) + + const Anope::string Get(size_t index, const Anope::string &col) const { - throw SQLException("Out of bounds access to SQLResult"); - } - } + const std::map<Anope::string, Anope::string> rows = this->Row(index); - const Anope::string Get(size_t index, const Anope::string &col) const - { - const std::map<Anope::string, Anope::string> rows = this->Row(index); + std::map<Anope::string, Anope::string>::const_iterator it = rows.find(col); + if (it == rows.end()) + throw Exception("Unknown column name in SQLResult: " + col); - std::map<Anope::string, Anope::string>::const_iterator it = rows.find(col); - if (it == rows.end()) - throw SQLException("Unknown column name in SQLResult: " + col); + return it->second; + } + }; - return it->second; - } -}; + /* An interface used by modules to retrieve the results + */ + class Interface + { + public: + Module *owner; -/* An interface used by modules to retrieve the results - */ -class SQLInterface -{ - public: - Module *owner; + Interface(Module *m) : owner(m) { } + virtual ~Interface() { } - SQLInterface(Module *m) : owner(m) { } - virtual ~SQLInterface() { } + virtual void OnResult(const Result &r) = 0; + virtual void OnError(const Result &r) = 0; + }; - virtual void OnResult(const SQLResult &r) = 0; - virtual void OnError(const SQLResult &r) = 0; -}; + /** Class providing the SQL service, modules call this to execute queries + */ + class Provider : public Service + { + public: + Provider(Module *c, const Anope::string &n) : Service(c, "SQL::Provider", n) { } -/** Class providing the SQL service, modules call this to execute queries - */ -class SQLProvider : public Service -{ - public: - SQLProvider(Module *c, const Anope::string &n) : Service(c, "SQLProvider", n) { } + virtual void Run(Interface *i, const Query &query) = 0; - virtual void Run(SQLInterface *i, const SQLQuery &query) = 0; + virtual Result RunQuery(const Query &query) = 0; - virtual SQLResult RunQuery(const SQLQuery &query) = 0; + virtual std::vector<Query> CreateTable(const Anope::string &table, const Data &data) = 0; - virtual std::vector<SQLQuery> CreateTable(const Anope::string &table, const Serialize::Data &data) = 0; + virtual Query BuildInsert(const Anope::string &table, unsigned int id, Data &data) = 0; - virtual SQLQuery BuildInsert(const Anope::string &table, unsigned int id, Serialize::Data &data) = 0; + virtual Query GetTables(const Anope::string &prefix) = 0; - virtual SQLQuery GetTables(const Anope::string &prefix) = 0; + virtual Anope::string FromUnixtime(time_t) = 0; + }; - virtual Anope::string FromUnixtime(time_t) = 0; -}; +} diff --git a/modules/extra/webcpanel/pages/chanserv/access.cpp b/modules/extra/webcpanel/pages/chanserv/access.cpp index d21546c..96fa3dc 100644 --- a/modules/extra/webcpanel/pages/chanserv/access.cpp +++ b/modules/extra/webcpanel/pages/chanserv/access.cpp @@ -100,7 +100,7 @@ bool WebCPanel::ChanServ::Access::OnRequest(HTTPProvider *server, const Anope::s if ((!highest || *highest <= *new_acc) && !u_access.founder && !has_priv) delete new_acc; - else if (new_acc->Serialize().empty()) + else if (new_acc->AccessSerialize().empty()) { replacements["MESSAGES"] = "Invalid access expression for the given type"; delete new_acc; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2c7566e..8012e03 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,14 +11,6 @@ if(WIN32) append_to_list(SRC_SRCS win32/sigaction/sigaction.cpp) endif(WIN32) -# If we have eventfd, use it -if(HAVE_EVENTFD) - append_to_list(SRC_SRCS socketengines/pipeengine_pipe.cpp) -# Else fall back to pipe -else(HAVE_EVENTFD) - append_to_list(SRC_SRCS socketengines/pipeengine_pipe.cpp) -endif(HAVE_EVENTFD) - if(HAVE_EPOLL) append_to_list(SRC_SRCS socketengines/socketengine_epoll.cpp) else(HAVE_EPOLL) diff --git a/src/access.cpp b/src/access.cpp index 863e0d4..c8cd3cf 100644 --- a/src/access.cpp +++ b/src/access.cpp @@ -99,25 +99,26 @@ ChanAccess::~ChanAccess() { } -Serialize::Data ChanAccess::Serialize() const +void ChanAccess::Serialize(Serialize::Data &data) const { - Serialize::Data data; - data["provider"] << this->provider->name; data["ci"] << this->ci->name; data["mask"] << this->mask; data["creator"] << this->creator; - data["last_seen"].SetType(Serialize::DT_INT) << this->last_seen; - data["created"].SetType(Serialize::DT_INT) << this->created; + data.SetType("last_seen", Serialize::Data::DT_INT); data["last_seen"] << this->last_seen; + data.SetType("created", Serialize::Data::DT_INT); data["created"] << this->created; data["data"] << this->AccessSerialize(); - - return data; } Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data) { - ServiceReference<AccessProvider> aprovider("AccessProvider", data["provider"].astr()); - ChannelInfo *ci = ChannelInfo::Find(data["ci"].astr()); + Anope::string provider, chan; + + data["provider"] >> provider; + data["ci"] >>chan; + + ServiceReference<AccessProvider> aprovider("AccessProvider", provider); + ChannelInfo *ci = ChannelInfo::Find(chan); if (!aprovider || !ci) return NULL; @@ -131,7 +132,10 @@ Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data) data["creator"] >> access->creator; data["last_seen"] >> access->last_seen; data["created"] >> access->created; - access->AccessUnserialize(data["data"].astr()); + + Anope::string adata; + data["data"] >> adata; + access->AccessUnserialize(adata); if (!obj) ci->AddAccess(access); diff --git a/src/base.cpp b/src/base.cpp index 5b8d828..b98b688 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -14,25 +14,37 @@ std::map<Anope::string, std::map<Anope::string, Service *> > Service::Services; std::map<Anope::string, std::map<Anope::string, Anope::string> > Service::Aliases; -Base::Base() +Base::Base() : references(NULL) { } Base::~Base() { - for (std::set<ReferenceBase *>::iterator it = this->references.begin(), it_end = this->references.end(); it != it_end; ++it) + if (this->references != NULL) { - (*it)->Invalidate(); + for (std::set<ReferenceBase *>::iterator it = this->references->begin(), it_end = this->references->end(); it != it_end; ++it) + (*it)->Invalidate(); + delete this->references; } } void Base::AddReference(ReferenceBase *r) { - this->references.insert(r); + if (this->references == NULL) + this->references = new std::set<ReferenceBase *>(); + this->references->insert(r); } void Base::DelReference(ReferenceBase *r) { - this->references.erase(r); + if (this->references != NULL) + { + this->references->erase(r); + if (this->references->empty()) + { + delete this->references; + this->references = NULL; + } + } } diff --git a/src/bots.cpp b/src/bots.cpp index 1e48d03..da5fe75 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -82,29 +82,33 @@ BotInfo::~BotInfo() BotListByUID->erase(this->uid); } -Serialize::Data BotInfo::Serialize() const +void BotInfo::Serialize(Serialize::Data &data) const { - Serialize::Data data; - - data["nick"].SetMax(64)/*XXX*/ << this->nick; + data["nick"] << this->nick; data["user"] << this->ident; data["host"] << this->host; data["realname"] << this->realname; data["created"] << this->created; data["flags"] << this->ToString(); - - return data; } Serializable* BotInfo::Unserialize(Serializable *obj, Serialize::Data &data) { + Anope::string nick, user, host, realname, flags; + + data["nick"] >> nick; + data["user"] >> user; + data["host"] >> host; + data["realname"] >> realname; + data["flags"] >> flags; + BotInfo *bi; if (obj) bi = anope_dynamic_static_cast<BotInfo *>(obj); - else if (!(bi = BotInfo::Find(data["nick"].astr()))) - bi = new BotInfo(data["nick"].astr(), data["user"].astr(), data["host"].astr(), data["realname"].astr()); + else if (!(bi = BotInfo::Find(nick))) + bi = new BotInfo(nick, user, host, realname); data["created"] >> bi->created; - bi->FromString(data["flags"].astr()); + bi->FromString(flags); return bi; } diff --git a/src/init.cpp b/src/init.cpp index e45d2a6..14e7d20 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -16,7 +16,6 @@ #include "protocol.h" #include "bots.h" #include "xline.h" -#include "signals.h" #include "socketengine.h" #include "servers.h" #include "language.h" @@ -91,91 +90,6 @@ static bool GetCommandLineArgument(const Anope::string &name, char shortname = 0 return GetCommandLineArgument(name, shortname, Unused); } -/*************************************************************************/ - -/* Remove our PID file. Done at exit. */ - -static void remove_pidfile() -{ - remove(Config->PIDFilename.c_str()); -} - -/*************************************************************************/ - -/* Create our PID file and write the PID to it. */ - -static void write_pidfile() -{ - FILE *pidfile = fopen(Config->PIDFilename.c_str(), "w"); - if (pidfile) - { -#ifdef _WIN32 - fprintf(pidfile, "%d\n", static_cast<int>(GetCurrentProcessId())); -#else - fprintf(pidfile, "%d\n", static_cast<int>(getpid())); -#endif - fclose(pidfile); - atexit(remove_pidfile); - } - else - throw CoreException("Can not write to PID file " + Config->PIDFilename); -} - -/*************************************************************************/ - -class SignalReload : public Signal -{ - public: - SignalReload(int sig) : Signal(sig) { } - - void OnNotify() - { - Log() << "Received SIGHUP: Saving databases & rehashing configuration"; - - Anope::SaveDatabases(); - - ServerConfig *old_config = Config; - try - { - Config = new ServerConfig(); - FOREACH_MOD(I_OnReload, OnReload()); - delete old_config; - } - catch (const ConfigException &ex) - { - Config = old_config; - Log() << "Error reloading configuration file: " << ex.GetReason(); - } - } -}; - -class SignalExit : public Signal -{ - public: - SignalExit(int sig) : Signal(sig) { } - - void OnNotify() - { -#ifndef _WIN32 - Log() << "Received " << strsignal(this->signal) << " signal (" << this->signal << "), exiting."; - Anope::QuitReason = Anope::string("Services terminating via signal ") + strsignal(this->signal) + " (" + stringify(this->signal) + ")"; -#else - Log() << "Received signal " << this->signal << ", exiting."; - Anope::QuitReason = Anope::string("Services terminating via signal ") + stringify(this->signal); -#endif - Anope::SaveDatabases(); - Anope::Quitting = true; - } -}; - -class SignalNothing : public Signal -{ - public: - SignalNothing(int sig) : Signal(sig) { } - - void OnNotify() { } -}; - bool Anope::AtTerm() { return isatty(fileno(stdout)) && isatty(fileno(stdin)) && isatty(fileno(stderr)); @@ -196,6 +110,45 @@ void Anope::Fork() #endif } +void Anope::HandleSignal() +{ + switch (Signal) + { + case SIGHUP: + { + Anope::SaveDatabases(); + + ServerConfig *old_config = Config; + try + { + Config = new ServerConfig(); + FOREACH_MOD(I_OnReload, OnReload()); + delete old_config; + } + catch (const ConfigException &ex) + { + Config = old_config; + Log() << "Error reloading configuration file: " << ex.GetReason(); + } + break; + } + case SIGTERM: + case SIGINT: +#ifndef _WIN32 + Log() << "Received " << strsignal(Signal) << " signal (" << Signal << "), exiting."; + Anope::QuitReason = Anope::string("Services terminating via signal ") + strsignal(Signal) + " (" + stringify(Signal) + ")"; +#else + Log() << "Received signal " << Signal << ", exiting."; + Anope::QuitReason = Anope::string("Services terminating via signal ") + stringify(Signal); +#endif + Anope::SaveDatabases(); + Anope::Quitting = true; + break; + } + + Signal = 0; +} + #ifndef _WIN32 static void parent_signal_handler(int signal) { @@ -215,6 +168,57 @@ static void parent_signal_handler(int signal) } #endif +static void SignalHandler(int sig) +{ + Anope::Signal = sig; +} + +static void InitSignals() +{ + struct sigaction sa; + + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + + sa.sa_handler = SignalHandler; + + sigaction(SIGHUP, &sa, NULL); + + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + sa.sa_handler = SIG_IGN; + + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); +} + +/* Remove our PID file. Done at exit. */ + +static void remove_pidfile() +{ + remove(Config->PIDFilename.c_str()); +} + +/* Create our PID file and write the PID to it. */ + +static void write_pidfile() +{ + FILE *pidfile = fopen(Config->PIDFilename.c_str(), "w"); + if (pidfile) + { +#ifdef _WIN32 + fprintf(pidfile, "%d\n", static_cast<int>(GetCurrentProcessId())); +#else + fprintf(pidfile, "%d\n", static_cast<int>(getpid())); +#endif + fclose(pidfile); + atexit(remove_pidfile); + } + else + throw CoreException("Can not write to PID file " + Config->PIDFilename); +} + void Anope::Init(int ac, char **av) { /* Set file creation mask and group ID. */ @@ -432,10 +436,7 @@ void Anope::Init(int ac, char **av) /* Announce ourselves to the logfile. */ Log() << "Anope " << Anope::Version() << " starting up" << (Anope::Debug || Anope::ReadOnly ? " (options:" : "") << (Anope::Debug ? " debug" : "") << (Anope::ReadOnly ? " readonly" : "") << (Anope::Debug || Anope::ReadOnly ? ")" : ""); - new SignalReload(SIGHUP); - new SignalExit(SIGTERM); - new SignalExit(SIGINT); - new SignalNothing(SIGPIPE); + InitSignals(); /* Initialize multi-language support */ Language::InitLanguages(); diff --git a/src/main.cpp b/src/main.cpp index 82cd1af..c35ee40 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,6 @@ #include "timers.h" #include "config.h" #include "bots.h" -#include "signals.h" #include "socketengine.h" #include "uplink.h" @@ -31,6 +30,7 @@ Anope::string Anope::ServicesDir; Anope::string Anope::ServicesBin; int Anope::ReturnValue = 0; +sig_atomic_t Anope::Signal = 0; bool Anope::Quitting = false; bool Anope::Restarting = false; Anope::string Anope::QuitReason; @@ -63,40 +63,6 @@ void Anope::SaveDatabases() Log(LOG_DEBUG) << "Saving databases"; } -std::vector<Signal *> Signal::SignalHandlers; - -void Signal::SignalHandler(int signal) -{ - for (unsigned i = 0, j = SignalHandlers.size(); i < j; ++i) - if (SignalHandlers[i]->signal == signal) - SignalHandlers[i]->Notify(); -} - -Signal::Signal(int s) : Pipe(), signal(s) -{ - memset(&this->old, 0, sizeof(this->old)); - - this->action.sa_flags = 0; - sigemptyset(&this->action.sa_mask); - this->action.sa_handler = SignalHandler; - - if (sigaction(s, &this->action, &this->old) == -1) - throw CoreException("Unable to install signal " + stringify(s) + ": " + Anope::LastError()); - - SignalHandlers.push_back(this); -} - -Signal::~Signal() -{ - std::vector<Signal *>::iterator it = std::find(SignalHandlers.begin(), SignalHandlers.end(), this); - if (it != SignalHandlers.end()) - SignalHandlers.erase(it); - - sigaction(this->signal, &this->old, NULL); -} - -/*************************************************************************/ - /** The following comes from InspIRCd to get the full path of the Anope executable */ static Anope::string GetFullProgDir(const Anope::string &argv0) @@ -196,6 +162,9 @@ int main(int ac, char **av, char **envp) /* Process the socket engine */ SocketEngine::Process(); + + if (Anope::Signal) + Anope::HandleSignal(); } if (Anope::Restarting) diff --git a/src/memos.cpp b/src/memos.cpp index 2b221b0..2f2672c 100644 --- a/src/memos.cpp +++ b/src/memos.cpp @@ -24,17 +24,13 @@ template<> const Anope::string* Flags<MemoFlag>::flags_strings = MemoFlagString; Memo::Memo() : Serializable("Memo") { } -Serialize::Data Memo::Serialize() const +void Memo::Serialize(Serialize::Data &data) const { - Serialize::Data data; - data["owner"] << this->owner; - data["time"].SetType(Serialize::DT_INT) << this->time; + data.SetType("time", Serialize::Data::DT_INT); data["time"] << this->time; data["sender"] << this->sender; data["text"] << this->text; data["flags"] << this->ToString(); - - return data; } Serializable* Memo::Unserialize(Serializable *obj, Serialize::Data &data) @@ -42,8 +38,13 @@ Serializable* Memo::Unserialize(Serializable *obj, Serialize::Data &data) if (!MemoServService) return NULL; + Anope::string owner, flags; + + data["owner"] >> owner; + data["flags"] >> flags; + bool ischan; - MemoInfo *mi = MemoServService->GetMemoInfo(data["owner"].astr(), ischan); + MemoInfo *mi = MemoServService->GetMemoInfo(owner, ischan); if (!mi) return NULL; @@ -56,7 +57,7 @@ Serializable* Memo::Unserialize(Serializable *obj, Serialize::Data &data) data["time"] >> m->time; data["sender"] >> m->sender; data["text"] >> m->text; - m->FromString(data["flags"].astr()); + m->FromString(flags); if (obj == NULL) mi->memos->push_back(m); diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp index 5e2165e..50eff0c 100644 --- a/src/modulemanager.cpp +++ b/src/modulemanager.cpp @@ -93,16 +93,15 @@ static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &out } int want = s.st_size; - char *buffer = new char[s.st_size]; + char buffer[1024]; while (want > 0 && !source.fail() && !target.fail()) { - source.read(buffer, want); + source.read(buffer, std::min(want, static_cast<int>(sizeof(buffer)))); int read_len = source.gcount(); target.write(buffer, read_len); want -= read_len; } - delete [] buffer; source.close(); target.close(); diff --git a/src/nickalias.cpp b/src/nickalias.cpp index f163c14..4ce8619 100644 --- a/src/nickalias.cpp +++ b/src/nickalias.cpp @@ -238,17 +238,15 @@ NickAlias *NickAlias::Find(const Anope::string &nick) return NULL; } -Serialize::Data NickAlias::Serialize() const +void NickAlias::Serialize(Serialize::Data &data) const { - Serialize::Data data; - - data["nick"].SetMax(Config->NickLen) << this->nick; + data["nick"] << this->nick; data["last_quit"] << this->last_quit; data["last_realname"] << this->last_realname; data["last_usermask"] << this->last_usermask; data["last_realhost"] << this->last_realhost; - data["time_registered"].SetType(Serialize::DT_INT) << this->time_registered; - data["last_seen"].SetType(Serialize::DT_INT) << this->last_seen; + data.SetType("time_registered", Serialize::Data::DT_INT); data["time_registered"] << this->time_registered; + data.SetType("time_registered", Serialize::Data::DT_INT); data["last_seen"] << this->last_seen; data["nc"] << this->nc->display; data["flags"] << this->ToString(); @@ -259,13 +257,16 @@ Serialize::Data NickAlias::Serialize() const data["vhost_creator"] << this->GetVhostCreator(); data["vhost_time"] << this->GetVhostCreated(); } - - return data; } Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data) { - NickCore *core = NickCore::Find(data["nc"].astr()); + Anope::string snc, snick; + + data["nc"] >> snc; + data["nick"] >> snick; + + NickCore *core = NickCore::Find(snc); if (core == NULL) return NULL; @@ -273,7 +274,7 @@ Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data) if (obj) na = anope_dynamic_static_cast<NickAlias *>(obj); else - na = new NickAlias(data["nick"].astr(), core); + na = new NickAlias(snick, core); if (na->nc != core) { @@ -296,11 +297,20 @@ Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data) data["last_realhost"] >> na->last_realhost; data["time_registered"] >> na->time_registered; data["last_seen"] >> na->last_seen; - na->FromString(data["flags"].astr()); + Anope::string flags; + data["flags"] >> flags; + na->FromString(flags); + + Anope::string vhost_ident, vhost_host, vhost_creator; time_t vhost_time; + + data["vhost_ident"] >> vhost_ident; + data["vhost_host"] >> vhost_host; + data["vhost_creator"] >> vhost_creator; data["vhost_time"] >> vhost_time; - na->SetVhost(data["vhost_ident"].astr(), data["vhost_host"].astr(), data["vhost_creator"].astr(), vhost_time); + + na->SetVhost(vhost_ident, vhost_host, vhost_creator, vhost_time); return na; } diff --git a/src/nickcore.cpp b/src/nickcore.cpp index f9ac3ef..304a405 100644 --- a/src/nickcore.cpp +++ b/src/nickcore.cpp @@ -78,11 +78,9 @@ NickCore::~NickCore() } } -Serialize::Data NickCore::Serialize() const +void NickCore::Serialize(Serialize::Data &data) const { - Serialize::Data data; - - data["display"].SetMax(Config->NickLen) << this->display; + data["display"] << this->display; data["pass"] << this->pass; data["email"] << this->email; data["greet"] << this->greet; @@ -95,24 +93,27 @@ Serialize::Data NickCore::Serialize() const data["memomax"] << this->memos.memomax; for (unsigned i = 0; i < this->memos.ignores.size(); ++i) data["memoignores"] << this->memos.ignores[i] << " "; - - return data; } Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data) { NickCore *nc; + Anope::string sdisplay, sflags; + + data["display"] >> sdisplay; + data["flags"] >> sflags; + if (obj) nc = anope_dynamic_static_cast<NickCore *>(obj); else - nc = new NickCore(data["display"].astr()); + nc = new NickCore(sdisplay); data["pass"] >> nc->pass; data["email"] >> nc->email; data["greet"] >> nc->greet; data["language"] >> nc->language; - nc->FromString(data["flags"].astr()); + nc->FromString(sflags); { Anope::string buf; data["access"] >> buf; diff --git a/src/socketengines/pipeengine_pipe.cpp b/src/pipeengine.cpp index d56ffef..6a5b8c3 100644 --- a/src/socketengines/pipeengine_pipe.cpp +++ b/src/pipeengine.cpp @@ -48,15 +48,34 @@ Pipe::~Pipe() bool Pipe::ProcessRead() { + this->OnNotify(); + char dummy[512]; while (read(this->GetFD(), dummy, 512) == 512); - this->OnNotify(); return true; } +void Pipe::Write(const char *data, size_t sz) +{ + write(this->write_pipe, data, sz); +} + +int Pipe::Read(char *data, size_t sz) +{ + return read(this->GetFD(), data, sz); +} + +bool Pipe::SetWriteBlocking(bool state) +{ + int flags = fcntl(this->write_pipe, F_GETFL, 0); + if (state) + return !fcntl(this->write_pipe, F_SETFL, flags & ~O_NONBLOCK); + else + return !fcntl(this->write_pipe, F_SETFL, flags | O_NONBLOCK); +} + void Pipe::Notify() { - const char dummy = '*'; - write(this->write_pipe, &dummy, 1); + this->Write("\0", 1); } diff --git a/src/regchannel.cpp b/src/regchannel.cpp index 3075ea3..43c51d7 100644 --- a/src/regchannel.cpp +++ b/src/regchannel.cpp @@ -34,20 +34,21 @@ template<> const Anope::string* Flags<ChannelInfoFlag>::flags_strings = ChannelI static const Anope::string AutoKickFlagString[] = { "AK_ISNICK", "" }; template<> const Anope::string* Flags<AutoKickFlag>::flags_strings = AutoKickFlagString; -Serialize::Data BadWord::Serialize() const +void BadWord::Serialize(Serialize::Data &data) const { - Serialize::Data data; - - data["ci"].SetMax(64)/*XXX*/ << this->ci->name; - data["word"].SetMax(512) << this->word; - data["type"].SetType(Serialize::DT_INT) << this->type; - - return data; + data["ci"] << this->ci->name; + data["word"] << this->word; + data.SetType("type", Serialize::Data::DT_INT); data["type"] << this->type; } Serializable* BadWord::Unserialize(Serializable *obj, Serialize::Data &data) { - ChannelInfo *ci = ChannelInfo::Find(data["ci"].astr()); + Anope::string sci, sword; + + data["ci"] >> sci; + data["word"] >> sword; + + ChannelInfo *ci = ChannelInfo::Find(sci); if (!ci) return NULL; @@ -62,7 +63,7 @@ Serializable* BadWord::Unserialize(Serializable *obj, Serialize::Data &data) bw->type = static_cast<BadWordType>(n); } else - bw = ci->AddBadWord(data["word"].astr(), static_cast<BadWordType>(n)); + bw = ci->AddBadWord(sword, static_cast<BadWordType>(n)); return bw; } @@ -71,38 +72,39 @@ AutoKick::AutoKick() : Serializable("AutoKick") { } -Serialize::Data AutoKick::Serialize() const +void AutoKick::Serialize(Serialize::Data &data) const { - Serialize::Data data; - - data["ci"].SetMax(64)/*XXX*/ << this->ci->name; + data["ci"] << this->ci->name; if (this->HasFlag(AK_ISNICK) && this->nc) - data["nc"].SetMax(Config->NickLen) << this->nc->display; + data["nc"] << this->nc->display; else - data["mask"].SetMax(Config->NickLen) << this->mask; + data["mask"] << this->mask; data["reason"] << this->reason; data["creator"] << this->creator; - data["addtime"].SetType(Serialize::DT_INT) << this->addtime; - data["last_used"].SetType(Serialize::DT_INT) << this->last_used; + data.SetType("addtime", Serialize::Data::DT_INT); data["addtime"] << this->addtime; + data.SetType("last_used", Serialize::Data::DT_INT); data["last_used"] << this->last_used; data["flags"] << this->ToString(); - - return data; } Serializable* AutoKick::Unserialize(Serializable *obj, Serialize::Data &data) { - ChannelInfo *ci = ChannelInfo::Find(data["ci"].astr()); + Anope::string sci, snc; + + data["ci"] >> sci; + data["nc"] >> snc; + + ChannelInfo *ci = ChannelInfo::Find(sci); if (!ci) return NULL; AutoKick *ak; - NickCore *nc = NickCore::Find(data["nc"].astr()); + NickCore *nc = NickCore::Find(snc); if (obj) { ak = anope_dynamic_static_cast<AutoKick *>(obj); data["creator"] >> ak->creator; data["reason"] >> ak->reason; - ak->nc = NickCore::Find(data["nc"].astr()); + ak->nc = NickCore::Find(snc); data["mask"] >> ak->mask; data["addtime"] >> ak->addtime; data["last_used"] >> ak->last_used; @@ -113,12 +115,22 @@ Serializable* AutoKick::Unserialize(Serializable *obj, Serialize::Data &data) data["addtime"] >> addtime; data["last_used"] >> lastused; + Anope::string screator, sreason, smask; + + data["creator"] >> screator; + data["reason"] >> sreason; + data["mask"] >> smask; + if (nc) - ak = ci->AddAkick(data["creator"].astr(), nc, data["reason"].astr(), addtime, lastused); + ak = ci->AddAkick(screator, nc, sreason, addtime, lastused); else - ak = ci->AddAkick(data["creator"].astr(), data["mask"].astr(), data["reason"].astr(), addtime, lastused); + ak = ci->AddAkick(screator, smask, sreason, addtime, lastused); } + Anope::string sflags; + data["flags"] >> sflags; + ak->FromString(sflags); + return ak; } @@ -126,27 +138,28 @@ ModeLock::ModeLock(ChannelInfo *ch, bool s, ChannelModeName n, const Anope::stri { } -Serialize::Data ModeLock::Serialize() const +void ModeLock::Serialize(Serialize::Data &data) const { - Serialize::Data data; - if (!this->ci) - return data; + return; const Anope::string* ChannelModeNameStrings = Flags<ChannelModeName>::GetFlagStrings(); - data["ci"].SetMax(64)/*XXX*/ << this->ci->name; - data["set"].SetMax(5) << this->set; - data["name"].SetMax(64) << ChannelModeNameStrings[this->name]; - data["param"].SetMax(512) << this->param; + data["ci"] << this->ci->name; + data["set"] << this->set; + data["name"] << ChannelModeNameStrings[this->name]; + data["param"] << this->param; data["setter"] << this->setter; - data["created"].SetType(Serialize::DT_INT) << this->created; - - return data; + data.SetType("created", Serialize::Data::DT_INT); data["created"] << this->created; } Serializable* ModeLock::Unserialize(Serializable *obj, Serialize::Data &data) { - ChannelInfo *ci = ChannelInfo::Find(data["ci"].astr()); + Anope::string sci, sname; + + data["ci"] >> sci; + data["name"] >> sname; + + ChannelInfo *ci = ChannelInfo::Find(sci); if (!ci) return NULL; @@ -154,7 +167,7 @@ Serializable* ModeLock::Unserialize(Serializable *obj, Serialize::Data &data) const Anope::string* ChannelModeNameStrings = Flags<ChannelModeName>::GetFlagStrings(); for (unsigned i = 0; !ChannelModeNameStrings[i].empty(); ++i) - if (ChannelModeNameStrings[i] == data["name"].astr()) + if (ChannelModeNameStrings[i] == sname) { name = static_cast<ChannelModeName>(i); break; @@ -182,7 +195,10 @@ Serializable* ModeLock::Unserialize(Serializable *obj, Serialize::Data &data) time_t created; data["created"] >> created; - ml = new ModeLock(ci, set, name, "", data["setter"].astr(), created); + Anope::string setter; + data["setter"] >> setter; + + ml = new ModeLock(ci, set, name, "", setter, created); data["param"] >> ml->param; ci->mode_locks->insert(std::make_pair(ml->name, ml)); @@ -190,12 +206,10 @@ Serializable* ModeLock::Unserialize(Serializable *obj, Serialize::Data &data) } } -Serialize::Data LogSetting::Serialize() const +void LogSetting::Serialize(Serialize::Data &data) const { - Serialize::Data data; - if (!ci) - return data; + return; data["ci"] << ci->name; data["service_name"] << service_name; @@ -204,14 +218,16 @@ Serialize::Data LogSetting::Serialize() const data["method"] << method; data["extra"] << extra; data["creator"] << creator; - data["created"].SetType(Serialize::DT_INT) << created; - - return data; + data.SetType("created", Serialize::Data::DT_INT); data["created"] << created; } Serializable* LogSetting::Unserialize(Serializable *obj, Serialize::Data &data) { - ChannelInfo *ci = ChannelInfo::Find(data["ci"].astr()); + Anope::string sci; + + data["ci"] >> sci; + + ChannelInfo *ci = ChannelInfo::Find(sci); if (ci == NULL) return NULL; @@ -376,22 +392,20 @@ ChannelInfo::~ChannelInfo() --this->founder->channelcount; } -Serialize::Data ChannelInfo::Serialize() const +void ChannelInfo::Serialize(Serialize::Data &data) const { - Serialize::Data data; - - data["name"].SetMax(255) << this->name; + data["name"] << this->name; if (this->founder) data["founder"] << this->founder->display; if (this->successor) data["successor"] << this->successor->display; data["description"] << this->desc; - data["time_registered"].SetType(Serialize::DT_INT) << this->time_registered; - data["last_used"].SetType(Serialize::DT_INT) << this->last_used; + data.SetType("time_registered", Serialize::Data::DT_INT); data["time_registered"] << this->time_registered; + data.SetType("last_used", Serialize::Data::DT_INT); data["last_used"] << this->last_used; data["last_topic"] << this->last_topic; data["last_topic_setter"] << this->last_topic_setter; - data["last_topic_time"].SetType(Serialize::DT_INT) << this->last_topic_time; - data["bantype"].SetType(Serialize::DT_INT) << this->bantype; + data.SetType("last_topic_time", Serialize::Data::DT_INT); data["last_topic_time"] << this->last_topic_time; + data.SetType("bantype", Serialize::Data::DT_INT); data["bantype"] << this->bantype; data["flags"] << this->ToString(); data["botflags"] << this->botflags.ToString(); { @@ -404,40 +418,44 @@ Serialize::Data ChannelInfo::Serialize() const data["bi"] << this->bi->nick; for (int i = 0; i < TTB_SIZE; ++i) data["ttb"] << this->ttb[i] << " "; - data["capsmin"].SetType(Serialize::DT_INT) << this->capsmin; - data["capspercent"].SetType(Serialize::DT_INT) << this->capspercent; - data["floodlines"].SetType(Serialize::DT_INT) << this->floodlines; - data["floodsecs"].SetType(Serialize::DT_INT) << this->floodsecs; - data["repeattimes"].SetType(Serialize::DT_INT) << this->repeattimes; + data.SetType("capsmin", Serialize::Data::DT_INT); data["capsmin"] << this->capsmin; + data.SetType("capspercent", Serialize::Data::DT_INT); data["capspercent"] << this->capspercent; + data.SetType("floodlines", Serialize::Data::DT_INT); data["floodlines"] << this->floodlines; + data.SetType("floodsecs", Serialize::Data::DT_INT); data["floodsecs"] << this->floodsecs; + data.SetType("repeattimes", Serialize::Data::DT_INT); data["repeattimes"] << this->repeattimes; data["memomax"] << this->memos.memomax; for (unsigned i = 0; i < this->memos.ignores.size(); ++i) data["memoignores"] << this->memos.ignores[i] << " "; - - return data; } Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data) { + Anope::string sname, sfounder, ssuccessor, sflags, sbotflags, slevels, sbi; + + data["name"] >> sname; + data["founder"] >> sfounder; + data["successor"] >> ssuccessor; + data["flags"] >> sflags; + data["botflags"] >> sbotflags; + data["levels"] >> slevels; + data["bi"] >> sbi; + ChannelInfo *ci; if (obj) ci = anope_dynamic_static_cast<ChannelInfo *>(obj); else - ci = new ChannelInfo(data["name"].astr()); + ci = new ChannelInfo(sname); - if (data.count("founder") > 0) - { - if (ci->founder) - --ci->founder->channelcount; - ci->founder = NickCore::Find(data["founder"].astr()); - if (ci->founder) - ++ci->founder->channelcount; - } - if (data.count("successor") > 0) - { - ci->successor = NickCore::Find(data["successor"].astr()); - if (ci->founder && *ci->founder == *ci->successor) - ci->successor = NULL; - } + if (ci->founder) + --ci->founder->channelcount; + ci->founder = NickCore::Find(sfounder); + if (ci->founder) + ++ci->founder->channelcount; + + ci->successor = NickCore::Find(ssuccessor); + if (ci->founder && *ci->founder == *ci->successor) + ci->successor = NULL; + data["description"] >> ci->desc; data["time_registered"] >> ci->time_registered; data["last_used"] >> ci->last_used; @@ -445,15 +463,15 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data) data["last_topic_setter"] >> ci->last_topic_setter; data["last_topic_time"] >> ci->last_topic_time; data["bantype"] >> ci->bantype; - ci->FromString(data["flags"].astr()); - ci->botflags.FromString(data["botflags"].astr()); + ci->FromString(sflags); + ci->botflags.FromString(sbotflags); { std::vector<Anope::string> v; - spacesepstream(data["levels"].astr()).GetTokens(v); + spacesepstream(slevels).GetTokens(v); for (unsigned i = 0; i + 1 < v.size(); i += 2) ci->levels[v[i]] = convertTo<int16_t>(v[i + 1]); } - BotInfo *bi = BotInfo::Find(data["bi"].astr()); + BotInfo *bi = BotInfo::Find(sbi); if (*ci->bi != bi) { if (ci->bi) diff --git a/src/serialize.cpp b/src/serialize.cpp index b6da2da..0f3e6c7 100644 --- a/src/serialize.cpp +++ b/src/serialize.cpp @@ -35,7 +35,7 @@ void Serialize::RegisterTypes() memo("Memo", Memo::Unserialize), xline("XLine", XLine::Unserialize); } -stringstream::stringstream() : std::stringstream(), type(Serialize::DT_TEXT), _max(0) +/*stringstream::stringstream() : std::stringstream(), type(Serialize::DT_TEXT), _max(0) { } @@ -84,14 +84,14 @@ stringstream &stringstream::SetMax(unsigned m) unsigned stringstream::GetMax() const { return this->_max; -} +}*/ -Serializable::Serializable() : last_commit_time(0), id(0) +Serializable::Serializable() : last_commit(NULL), last_commit_time(0), id(0) { throw CoreException("Default Serializable constructor?"); } -Serializable::Serializable(const Anope::string &serialize_type) : last_commit_time(0), id(0) +Serializable::Serializable(const Anope::string &serialize_type) : last_commit(NULL), last_commit_time(0), id(0) { if (SerializableItems == NULL) SerializableItems = new std::list<Serializable *>(); @@ -105,7 +105,7 @@ Serializable::Serializable(const Anope::string &serialize_type) : last_commit_ti FOREACH_MOD(I_OnSerializableConstruct, OnSerializableConstruct(this)); } -Serializable::Serializable(const Serializable &other) : last_commit_time(0), id(0) +Serializable::Serializable(const Serializable &other) : last_commit(NULL), last_commit_time(0), id(0) { SerializableItems->push_back(this); this->s_iter = SerializableItems->end(); @@ -119,6 +119,7 @@ Serializable::Serializable(const Serializable &other) : last_commit_time(0), id( Serializable::~Serializable() { SerializableItems->erase(this->s_iter); + delete last_commit; } Serializable &Serializable::operator=(const Serializable &) @@ -144,14 +145,15 @@ void Serializable::QueueUpdate() FOREACH_MOD(I_OnSerializableUpdate, OnSerializableUpdate(this)); } -bool Serializable::IsCached() +bool Serializable::IsCached(Serialize::Data *data) { - return this->last_commit == this->Serialize(); + return this->last_commit && this->last_commit->IsEqual(data); } -void Serializable::UpdateCache() +void Serializable::UpdateCache(Serialize::Data *data) { - this->last_commit = this->Serialize(); + delete this->last_commit; + this->last_commit = data; } bool Serializable::IsTSCached() @@ -164,11 +166,6 @@ void Serializable::UpdateTS() this->last_commit_time = Anope::CurTime; } -Type* Serializable::GetSerializableType() const -{ - return this->s_type; -} - const std::list<Serializable *> &Serializable::GetItems() { return *SerializableItems; @@ -188,11 +185,6 @@ Type::~Type() Types.erase(this->name); } -const Anope::string &Type::GetName() -{ - return this->name; -} - Serializable *Type::Unserialize(Serializable *obj, Serialize::Data &data) { return this->unserialize(obj, data); @@ -213,11 +205,6 @@ void Type::UpdateTimestamp() this->timestamp = Anope::CurTime; } -Module* Type::GetOwner() const -{ - return this->owner; -} - Type *Serialize::Type::Find(const Anope::string &name) { std::map<Anope::string, Type *>::iterator it = Types.find(name); diff --git a/src/socketengines/pipeengine_eventfd.cpp b/src/socketengines/pipeengine_eventfd.cpp deleted file mode 100644 index 61fddd0..0000000 --- a/src/socketengines/pipeengine_eventfd.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * - * (C) 2003-2012 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. - */ - -#include "services.h" -#include "sockets.h" - -#include <sys/eventfd.h> - -Pipe::Pipe() : Socket(eventfd(0, EFD_NONBLOCK)) -{ - if (this->sock < 0) - throw CoreException("Could not create pipe: " + Anope::LastError()); -} - -Pipe::~Pipe() -{ -} - -bool Pipe::ProcessRead() -{ - eventfd_t dummy; - eventfd_read(this->GetFD(), &dummy); - this->OnNotify(); - return true; -} - -void Pipe::Notify() -{ - eventfd_write(this->GetFD(), 1); -} - diff --git a/src/sockets.cpp b/src/sockets.cpp index 6aadb78..3dd3e67 100644 --- a/src/sockets.cpp +++ b/src/sockets.cpp @@ -419,7 +419,7 @@ Socket::Socket(int s, bool i, int type) this->sock = socket(this->ipv6 ? AF_INET6 : AF_INET, type, 0); else this->sock = s; - this->SetNonBlocking(); + this->SetBlocking(false); SocketEngine::Sockets[this->sock] = this; SocketEngine::Change(this, true, SF_READABLE); } @@ -443,16 +443,13 @@ bool Socket::IsIPv6() const return ipv6; } -bool Socket::SetBlocking() +bool Socket::SetBlocking(bool state) { int flags = fcntl(this->GetFD(), F_GETFL, 0); - return !fcntl(this->GetFD(), F_SETFL, flags & ~O_NONBLOCK); -} - -bool Socket::SetNonBlocking() -{ - int flags = fcntl(this->GetFD(), F_GETFL, 0); - return !fcntl(this->GetFD(), F_SETFL, flags | O_NONBLOCK); + if (state) + return !fcntl(this->GetFD(), F_SETFL, flags & ~O_NONBLOCK); + else + return !fcntl(this->GetFD(), F_SETFL, flags | O_NONBLOCK); } void Socket::Bind(const Anope::string &ip, int port) @@ -481,7 +478,7 @@ void Socket::ProcessError() ListenSocket::ListenSocket(const Anope::string &bindip, int port, bool i) { - this->SetNonBlocking(); + this->SetBlocking(false); const char op = 1; setsockopt(this->GetFD(), SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)); diff --git a/src/xline.cpp b/src/xline.cpp index 4ac6581..b2fd009 100644 --- a/src/xline.cpp +++ b/src/xline.cpp @@ -137,10 +137,8 @@ bool XLine::IsRegex() const return !this->mask.empty() && this->mask[0] == '/' && this->mask[this->mask.length() - 1] == '/'; } -Serialize::Data XLine::Serialize() const +void XLine::Serialize(Serialize::Data &data) const { - Serialize::Data data; - data["mask"] << this->mask; data["by"] << this->by; data["created"] << this->created; @@ -149,13 +147,15 @@ Serialize::Data XLine::Serialize() const data["uid"] << this->id; if (this->manager) data["manager"] << this->manager->name; - - return data; } Serializable* XLine::Unserialize(Serializable *obj, Serialize::Data &data) { - ServiceReference<XLineManager> xlm("XLineManager", data["manager"].astr()); + Anope::string smanager; + + data["manager"] >> smanager; + + ServiceReference<XLineManager> xlm("XLineManager", smanager); if (!xlm) return NULL; @@ -176,9 +176,16 @@ Serializable* XLine::Unserialize(Serializable *obj, Serialize::Data &data) } else { + Anope::string smask, sby, sreason, suid; time_t expires; + + data["mask"] >> smask; + data["by"] >> sby; + data["reason"] >> sreason; + data["uid"] >> suid; data["expires"] >> expires; - xl = new XLine(data["mask"].astr(), data["by"].astr(), expires, data["reason"].astr(), data["uid"].astr()); + + xl = new XLine(smask, sby, expires, sreason, suid); xlm->AddXLine(xl); } |