From 10ade1e23da96dee972be77d7cd3fe6d0f107a4d Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Sun, 5 Sep 2010 12:43:13 -0400 Subject: Break channel database read/write out of m_chanregister --- src/modules/m_sql_channels.cpp | 192 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 src/modules/m_sql_channels.cpp (limited to 'src/modules/m_sql_channels.cpp') diff --git a/src/modules/m_sql_channels.cpp b/src/modules/m_sql_channels.cpp new file mode 100644 index 000000000..e00e6c53b --- /dev/null +++ b/src/modules/m_sql_channels.cpp @@ -0,0 +1,192 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2010 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + + +#include "inspircd.h" +#include "sql.h" + +/* $ModDesc: Provides channel mode +r for channel registration */ + +static bool reading = false; + +class DatabaseReadQuery : public SQLQuery +{ + public: + LocalIntExt& InDB; + DatabaseReadQuery(Module* me, LocalIntExt& indb) : SQLQuery(me), InDB(indb) + { + } + + void OnResult(SQLResult& res) + { + SQLEntries row; + reading = true; + while (res.GetRow(row)) + { + std::string channame = row[0]; + Channel* chan = ServerInstance->FindChan(channame); + if (!chan) + { + time_t ts = atol(row[1].value.c_str()); + if (!ts) + ts = ServerInstance->Time(); + chan = new Channel(channame, ts); + } + InDB.set(chan, 1); + if (!row[2].nul) + { + irc::spacesepstream modes(row[2]); + std::string mode; + irc::modestacker ms; + while (modes.GetToken(mode)) + { + std::string::size_type eq = mode.find('='); + std::string name = mode.substr(0, eq); + std::string value; + if (eq != std::string::npos) + value = mode.substr(eq + 1); + ModeHandler *mh = ServerInstance->Modes->FindMode(name); + if (!mh) + continue; + ms.push(irc::modechange(mh->id, value, true)); + } + ServerInstance->Modes->Process(ServerInstance->FakeClient, chan, ms); + } + if (!row[3].nul) + { + chan->topic = row[3]; + chan->setby = row[4]; + chan->topicset = atol(row[5].value.c_str()); + } + } + reading = false; + } +}; +class DiscardQuery : public SQLQuery +{ + public: + DiscardQuery(Module* me) : SQLQuery(me) {} + void OnResult(SQLResult& res) {} + void OnError(SQLerror& e) + { + ServerInstance->Logs->Log("m_chanregister", DEFAULT, "SQL update returned error: %s", e.str.c_str()); + } +}; + +class ChanSQLDB : public Module +{ + private: + std::string tablename; + dynamic_reference sqldb; + LocalIntExt InDB; + + public: + ChanSQLDB() : sqldb("SQL"), InDB("in_sql_chans", this) + { + } + Version GetVersion() + { + return Version("Provides channel state updates to an SQL databse", VF_VENDOR); + } + void init() + { + Implementation eventlist[] = { + I_OnMode, I_OnPostTopicChange + }; + + ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); + + ParamL n; + n.push_back(tablename); + // just dump the entire thing back to us, please + sqldb->submit(new DatabaseReadQuery(this, InDB), + "SELECT (name, ts, modes, topic, topicset, topicts) FROM ?", n); + } + void ReadConfig(ConfigReadStatus& status) + { + ConfigTag *tag = ServerInstance->Config->GetTag ("chandb"); + + tablename = tag->getString("sqltable"); + std::string dbid = tag->getString("dbid"); + if (dbid.empty()) + sqldb.SetProvider("SQL"); + else + sqldb.SetProvider("SQL/" + dbid); + if (!sqldb) + status.ReportError(tag, "SQL database not found!"); + } + void OnPostTopicChange (User *user, Channel *chan, const std::string &topic) + { + if (reading || !InDB.get(chan)) + return; + ParamL n; + n.push_back(tablename); + n.push_back(chan->topic); + n.push_back(chan->setby); + n.push_back(ConvToStr(chan->topicset)); + n.push_back(chan->name); + sqldb->submit(new DiscardQuery(this), + "UPDATE ? SET (topic, topicset, topicts) = ('?', '?', '?') WHERE name = '?'", n); + } + + void OnMode (User *user, Extensible *target, const irc::modestacker &modes) + { + Channel *chan = IS_CHANNEL(target); + if (reading || !chan) + return; + if (!InDB.get(chan)) + { + AddToDB(chan); + return; + } + irc::modestacker ms; + chan->ChanModes(ms, MODELIST_FULL); + ParamL n; + n.push_back(tablename); + n.push_back(ms.popModeLine(FORMAT_PERSIST, INT_MAX, INT_MAX)); + n.push_back(chan->name); + sqldb->submit(new DiscardQuery(this), + "UPDATE ? SET modes = '?' WHERE name = '?'", n); + } + + void AddToDB(Channel* chan) + { + irc::modestacker ms; + chan->ChanModes(ms, MODELIST_FULL); + ParamL n; + n.push_back(tablename); + n.push_back(chan->name); + n.push_back(ConvToStr(chan->age)); + n.push_back(ms.popModeLine(FORMAT_PERSIST, INT_MAX, INT_MAX)); + if (chan->topic.empty()) + { + sqldb->submit(new DiscardQuery(this), + "INSERT INTO ? (name, ts, modes) VALUES ('?', '?', '?')", n); + } + else + { + n.push_back(chan->topic); + n.push_back(chan->setby); + n.push_back(ConvToStr(chan->topicset)); + sqldb->submit(new DiscardQuery(this), + "INSERT INTO ? (name, ts, modes, topic, topicset, topicts) VALUES ('?', '?', '?', '?', '?', '?')", n); + } + } + + void Prioritize() + { + // database reading may depend on channel modes being loaded + ServerInstance->Modules->SetPriority(this, I_ModuleInit, PRIORITY_LAST); + } +}; +MODULE_INIT(ChanSQLDB) -- cgit v1.3.1-10-gc9f91