X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fcoremods%2Fcore_reloadmodule.cpp;h=ea5d40abdc72d8c6841c06f90db9af98cd71b597;hb=c02b30b96e48fb4b01c275c1b8b49d69ad2ebd4a;hp=68db9e25a1d8ad7efee461cb0bc02589f61b8c4e;hpb=c0aba5b728b0a921d95ec120aa638dab1520b42f;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/coremods/core_reloadmodule.cpp b/src/coremods/core_reloadmodule.cpp index 68db9e25a..ea5d40abd 100644 --- a/src/coremods/core_reloadmodule.cpp +++ b/src/coremods/core_reloadmodule.cpp @@ -24,18 +24,42 @@ #include "modules/reload.h" static Events::ModuleEventProvider* reloadevprov; +static ClientProtocol::Serializer* dummyserializer; + +class DummySerializer : public ClientProtocol::Serializer +{ + bool Parse(LocalUser* user, const std::string& line, ClientProtocol::ParseOutput& parseoutput) CXX11_OVERRIDE + { + return false; + } + + ClientProtocol::SerializedMessage Serialize(const ClientProtocol::Message& msg, const ClientProtocol::TagSelection& tagwl) const CXX11_OVERRIDE + { + return ClientProtocol::SerializedMessage(); + } + + public: + DummySerializer(Module* mod) + : ClientProtocol::Serializer(mod, "dummy") + { + } +}; class CommandReloadmodule : public Command { Events::ModuleEventProvider evprov; + DummySerializer dummyser; + public: /** Constructor for reloadmodule. */ CommandReloadmodule(Module* parent) : Command(parent, "RELOADMODULE", 1) , evprov(parent, "event/reloadmodule") + , dummyser(parent) { reloadevprov = &evprov; + dummyserializer = &dummyser; flags_needed = 'o'; syntax = ""; } @@ -45,7 +69,7 @@ class CommandReloadmodule : public Command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ - CmdResult Handle(const std::vector& parameters, User *user); + CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; namespace ReloadModule @@ -62,6 +86,7 @@ class DataKeeper { ModeHandler* mh; ExtensionItem* extitem; + ClientProtocol::Serializer* serializer; }; ProviderInfo(ModeHandler* mode) @@ -75,6 +100,12 @@ class DataKeeper , extitem(ei) { } + + ProviderInfo(ClientProtocol::Serializer* ser) + : itemname(ser->name) + , serializer(ser) + { + } }; struct InstanceData @@ -143,7 +174,17 @@ class DataKeeper }; // Data saved for each user - typedef OwnedModesExts UserData; + struct UserData : public OwnedModesExts + { + static const size_t UNUSED_INDEX = (size_t)-1; + size_t serializerindex; + + UserData(User* user, size_t serializeridx) + : OwnedModesExts(user->uuid) + , serializerindex(serializeridx) + { + } + }; /** Module being reloaded */ @@ -157,6 +198,10 @@ class DataKeeper */ std::vector handledexts; + /** Stores all serializers provided by the module + */ + std::vector handledserializers; + /** Stores all of the module data related to users */ std::vector userdatalist; @@ -172,6 +217,14 @@ class DataKeeper void SaveExtensions(Extensible* extensible, std::vector& extdatalist); void SaveMemberData(Channel* chan, std::vector& memberdatalist); static void SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata); + size_t SaveSerializer(User* user); + + /** Get the index of a ProviderInfo representing the serializer in the handledserializers list. + * If the serializer is not already in the list it is added. + * @param serializer Serializer to get an index to. + * @return Index of the ProviderInfo representing the serializer. + */ + size_t GetSerializerIndex(ClientProtocol::Serializer* serializer); void CreateModeList(ModeType modetype); void DoSaveUsers(); @@ -186,6 +239,10 @@ class DataKeeper */ void LinkModes(ModeType modetype); + /** Link previously saved serializer names to currently available Serializers + */ + void LinkSerializers(); + void DoRestoreUsers(); void DoRestoreChans(); void DoRestoreModules(); @@ -213,6 +270,15 @@ class DataKeeper */ void RestoreModes(const std::vector& list, ModeType modetype, Modes::ChangeList& modechange); + /** Restore previously saved serializer on a User. + * Quit the user if the serializer cannot be restored. + * @param serializerindex Saved serializer index to restore. + * @param user User whose serializer to restore. If not local then calling this method is a no-op. + * @return True if the serializer didn't need restoring or was restored successfully. + * False if the serializer should have been restored but the required serializer is unavailable and the user was quit. + */ + bool RestoreSerializer(size_t serializerindex, User* user); + /** Restore all modes and extensions of all members on a channel * @param chan Channel whose members are being restored * @param memberdata Data to restore @@ -262,16 +328,44 @@ void DataKeeper::DoSaveUsers() // Serialize all extensions attached to the User SaveExtensions(user, currdata.extlist); + // Save serializer name if applicable and get an index to it + size_t serializerindex = SaveSerializer(user); + // Add to list if the user has any modes or extensions set that we are interested in, otherwise we don't // have to do anything with this user when restoring - if (!currdata.empty()) + if ((!currdata.empty()) || (serializerindex != UserData::UNUSED_INDEX)) { - userdatalist.push_back(UserData(user->uuid)); + userdatalist.push_back(UserData(user, serializerindex)); userdatalist.back().swap(currdata); } } } +size_t DataKeeper::GetSerializerIndex(ClientProtocol::Serializer* serializer) +{ + for (size_t i = 0; i < handledserializers.size(); i++) + { + if (handledserializers[i].serializer == serializer) + return i; + } + + handledserializers.push_back(ProviderInfo(serializer)); + return handledserializers.size()-1; +} + +size_t DataKeeper::SaveSerializer(User* user) +{ + LocalUser* const localuser = IS_LOCAL(user); + if ((!localuser) || (!localuser->serializer)) + return UserData::UNUSED_INDEX; + if (localuser->serializer->creator != mod) + return UserData::UNUSED_INDEX; + + const size_t serializerindex = GetSerializerIndex(localuser->serializer); + localuser->serializer = dummyserializer; + return serializerindex; +} + void DataKeeper::SaveExtensions(Extensible* extensible, std::vector& extdata) { const Extensible::ExtensibleStore& setexts = extensible->GetExtList(); @@ -456,6 +550,16 @@ void DataKeeper::LinkExtensions() } } +void DataKeeper::LinkSerializers() +{ + for (std::vector::iterator i = handledserializers.begin(); i != handledserializers.end(); ++i) + { + ProviderInfo& item = *i; + item.serializer = ServerInstance->Modules.FindDataService(item.itemname); + VerifyServiceProvider(item.serializer, "Serializer"); + } +} + void DataKeeper::Restore(Module* newmod) { this->mod = newmod; @@ -464,6 +568,7 @@ void DataKeeper::Restore(Module* newmod) LinkExtensions(); LinkModes(MODETYPE_USER); LinkModes(MODETYPE_CHANNEL); + LinkSerializers(); // Restore DoRestoreUsers(); @@ -505,6 +610,30 @@ void DataKeeper::RestoreModes(const std::vector& list, ModeType mo } } +bool DataKeeper::RestoreSerializer(size_t serializerindex, User* user) +{ + if (serializerindex == UserData::UNUSED_INDEX) + return true; + + // The following checks are redundant + LocalUser* const localuser = IS_LOCAL(user); + if (!localuser) + return true; + if (localuser->serializer != dummyserializer) + return true; + + const ProviderInfo& provinfo = handledserializers[serializerindex]; + if (!provinfo.serializer) + { + // Users cannot exist without a serializer + ServerInstance->Users.QuitUser(user, "Serializer lost in reload"); + return false; + } + + localuser->serializer = provinfo.serializer; + return true; +} + void DataKeeper::DoRestoreUsers() { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring user data"); @@ -520,6 +649,10 @@ void DataKeeper::DoRestoreUsers() continue; } + // Attempt to restore serializer first, if it fails it's a fatal error and RestoreSerializer() quits them + if (!RestoreSerializer(userdata.serializerindex, user)) + continue; + RestoreObj(userdata, user, MODETYPE_USER, modechange); ServerInstance->Modes.Process(ServerInstance->FakeClient, NULL, user, modechange, ModeParser::MODE_LOCALONLY); modechange.clear(); @@ -565,7 +698,7 @@ void DataKeeper::DoRestoreModules() } // namespace ReloadModule -class ReloadAction : public HandlerBase0 +class ReloadAction : public ActionBase { Module* const mod; const std::string uuid; @@ -579,7 +712,7 @@ class ReloadAction : public HandlerBase0 { } - void Call() + void Call() CXX11_OVERRIDE { ReloadModule::DataKeeper datakeeper; datakeeper.Save(mod); @@ -608,12 +741,12 @@ class ReloadAction : public HandlerBase0 } }; -CmdResult CommandReloadmodule::Handle (const std::vector& parameters, User *user) +CmdResult CommandReloadmodule::Handle(User* user, const Params& parameters) { Module* m = ServerInstance->Modules->Find(parameters[0]); if (m == creator) { - user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "You cannot reload core_reloadmodule.so (unload and load it)"); + user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "You cannot reload core_reloadmodule (unload and load it)"); return CMD_FAILURE; } @@ -632,4 +765,21 @@ CmdResult CommandReloadmodule::Handle (const std::vector& parameter } } -COMMAND_INIT(CommandReloadmodule) +class CoreModReloadmodule : public Module +{ + private: + CommandReloadmodule cmd; + + public: + CoreModReloadmodule() + : cmd(this) + { + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Provides the RELOADMODULE command", VF_CORE | VF_VENDOR); + } +}; + +MODULE_INIT(CoreModReloadmodule)