1
0
Fork 0

Plugin reload <plugin_name> feature (#4942)

+ Add `reload <pluginname>`
* Fixes #365

Co-authored-by: Alexander Harkness <me@bearbin.net>
Co-authored-by: pwnOrbitals <c.de-claverie@pm.me>
Co-authored-by: Tiger Wang <ziwei.tiger@outlook.com>
This commit is contained in:
[IPSA] Chris de Claverie 2020-09-28 00:15:03 +02:00 committed by GitHub
parent 410d6c0045
commit 9a548b3b3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 89 additions and 28 deletions

View File

@ -37,10 +37,10 @@ lkolbly
LogicParrot
Luksor
M10360
maxluchterhand1
marmot21
Masy98
mathiascode
maxluchterhand1
MaxwellScroggs
mborland
mBornand
@ -53,6 +53,7 @@ nesco
NiLSPACE (formerly STR_Warrior)
p-mcgowan
pokechu22
pwnOrbitals
rs2k
SamJBarney
Schwertspize
@ -64,8 +65,8 @@ structinf (xdot)
sweetgiorni
Sxw1212
Taugeshtu
tigerw (Tiger Wang)
theophriene
tigerw (Tiger Wang)
tonibm19
TooAngel
UltraCoderRU

View File

@ -675,6 +675,17 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
Notes = "Queues the specified plugin to be unloaded. To avoid deadlocks, the unloading happens in the main tick thread asynchronously.",
},
ReloadPlugin =
{
Params =
{
{
Name = "PluginName",
Type = "string",
},
},
Notes = "Queues the specified plugin to be reloaded. To avoid deadlocks, the reloading happens in the main tick thread asynchronously.",
}
},
Constants =
{

View File

@ -45,7 +45,7 @@ void cPlugin::Unload(void)
AString cPlugin::GetLocalFolder(void) const
{
return std::string("Plugins/") + m_FolderName;
return "Plugins" + cFile::GetPathSeparator() + m_FolderName;
}

View File

@ -165,35 +165,54 @@ void cPluginManager::InsertDefaultPlugins(cSettingsRepositoryInterface & a_Setti
void cPluginManager::Tick(float a_Dt)
{
// Unload plugins that have been scheduled for unloading:
AStringVector PluginsToUnload;
decltype(m_PluginsNeedAction) PluginsNeedAction;
{
cCSLock Lock(m_CSPluginsToUnload);
std::swap(m_PluginsToUnload, PluginsToUnload);
cCSLock Lock(m_CSPluginsNeedAction);
std::swap(m_PluginsNeedAction, PluginsNeedAction);
}
for (auto & folder: PluginsToUnload)
// Process deferred actions:
for (auto & CurrentPlugin : PluginsNeedAction)
{
bool HasUnloaded = false;
bool HasFound = false;
for (auto & plugin: m_Plugins)
auto & Action = CurrentPlugin.first;
auto & Folder = CurrentPlugin.second;
bool WasLoaded = false;
bool WasFound = false;
for (auto & Plugin: m_Plugins)
{
if (plugin->GetFolderName() == folder)
if (Plugin->GetFolderName() == Folder)
{
HasFound = true;
if (plugin->IsLoaded())
WasFound = true;
if (Plugin->IsLoaded())
{
plugin->Unload();
HasUnloaded = true;
switch (Action)
{
case PluginAction::Reload :
{
// Reload plugins by unloading, then loading:
Plugin->Unload();
Plugin->Load();
break;
}
case PluginAction::Unload :
{
// Unload plugins that have been scheduled for unloading:
Plugin->Unload();
break;
}
}
WasLoaded = true;
}
}
}
if (!HasFound)
if (!WasFound)
{
LOG("Cannot unload plugin in folder \"%s\", there's no such plugin folder", folder.c_str());
LOG("Cannot act on plugin in folder \"%s\", there's no such plugin folder", Folder.c_str());
}
else if (!HasUnloaded)
else if (!WasLoaded)
{
LOG("Cannot unload plugin in folder \"%s\", it has not been loaded.", folder.c_str());
LOG("Cannot act on plugin in folder \"%s\", it has not been loaded.", Folder.c_str());
}
} // for plugin - m_Plugins[]
@ -1317,8 +1336,18 @@ void cPluginManager::UnloadPluginsNow()
void cPluginManager::UnloadPlugin(const AString & a_PluginFolder)
{
cCSLock Lock(m_CSPluginsToUnload);
m_PluginsToUnload.push_back(a_PluginFolder);
cCSLock Lock(m_CSPluginsNeedAction);
m_PluginsNeedAction.emplace_back(PluginAction::Unload, a_PluginFolder);
}
void cPluginManager::ReloadPlugin(const AString & a_PluginFolder)
{
cCSLock Lock(m_CSPluginsNeedAction);
m_PluginsNeedAction.emplace_back(PluginAction::Reload, a_PluginFolder);
}

View File

@ -162,6 +162,14 @@ public:
} ; // tolua_export
/** Defines the deferred actions needed for a plugin */
enum class PluginAction
{
Reload,
Unload
};
/** Used as a callback for enumerating bound commands */
class cCommandEnumCallback
{
@ -303,6 +311,10 @@ public:
Note that this function returns before the plugin is unloaded, to avoid deadlocks. */
void UnloadPlugin(const AString & a_PluginFolder); // tolua_export
/** Queues the specified plugin to be reloaded in the next call to Tick().
Note that this function returns before the plugin is unloaded, to avoid deadlocks. */
void ReloadPlugin(const AString & a_PluginFolder); // tolua_export
/** Loads the plugin from the specified plugin folder.
Returns true if the plugin was loaded successfully or was already loaded before, false otherwise. */
bool LoadPlugin(const AString & a_PluginFolder); // tolua_export
@ -408,13 +420,13 @@ private:
typedef std::map<AString, cCommandReg> CommandMap;
/** FolderNames of plugins that should be unloaded.
The plugins will be unloaded within the next call to Tick(), to avoid multithreading issues.
Protected against multithreaded access by m_CSPluginsToUnload. */
AStringVector m_PluginsToUnload;
/** FolderNames of plugins that need an action (unload, reload, ...).
The plugins will be acted upon within the next call to Tick(), to avoid multithreading issues.
Protected against multithreaded access by m_CSPluginsNeedAction. */
std::vector<std::pair<PluginAction, AString>> m_PluginsNeedAction;
/** Protects m_PluginsToUnload against multithreaded access. */
mutable cCriticalSection m_CSPluginsToUnload;
mutable cCriticalSection m_CSPluginsNeedAction;
/** All plugins that have been found in the Plugins folder. */
cPluginPtrs m_Plugins;

View File

@ -463,7 +463,15 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
}
else if (split[0] == "reload")
{
cPluginManager::Get()->ReloadPlugins();
if (split.size() > 1)
{
cPluginManager::Get()->ReloadPlugin(split[1]);
a_Output.Out("Plugin reload scheduled");
}
else
{
cPluginManager::Get()->ReloadPlugins();
}
a_Output.Finished();
return;
}