PluginManager.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "adchpp.h"
00020
00021 #include "PluginManager.h"
00022
00023 #include "SimpleXML.h"
00024 #include "LogManager.h"
00025 #include "SocketManager.h"
00026 #include "version.h"
00027 #include "File.h"
00028 #include "Text.h"
00029
00030 #ifdef _WIN32
00031
00032 #define PLUGIN_EXT _T(".dll")
00033
00034 #define PM_LOAD_LIBRARY(filename) ::LoadLibrary(filename)
00035 #define PM_UNLOAD_LIBRARY(lib) ::FreeLibrary(lib)
00036 #define PM_GET_ADDRESS(lib, name) ::GetProcAddress(lib, name)
00037 #define PM_GET_ERROR_STRING() Util::translateError(GetLastError())
00038
00039 #else
00040
00041 #include "dlfcn.h"
00042
00043 #define PLUGIN_EXT ".so"
00044
00045 #define PM_LOAD_LIBRARY(filename) ::dlopen(filename, RTLD_LAZY | RTLD_GLOBAL)
00046 #define PM_UNLOAD_LIBRARY(lib) ::dlclose(lib)
00047 #define PM_GET_ADDRESS(lib, name) ::dlsym(lib, name)
00048 #define PM_GET_ERROR_STRING() ::dlerror()
00049
00050 #endif
00051
00052 namespace adchpp {
00053
00054 using namespace std;
00055 using std::placeholders::_1;
00056
00057 PluginManager* PluginManager::instance = 0;
00058 const string PluginManager::className = "PluginManager";
00059
00060 PluginManager::PluginManager() throw() {
00061
00062 }
00063
00064 PluginManager::~PluginManager() throw() {
00065
00066 }
00067
00068 void PluginManager::attention(const function<void()>& f) {
00069 SocketManager::getInstance()->addJob(f);
00070 }
00071
00072 void PluginManager::load() {
00073 for(StringIter i = plugins.begin(); i != plugins.end(); ++i) {
00074 loadPlugin(*i + PLUGIN_EXT);
00075 }
00076 }
00077
00078 bool PluginManager::loadPlugin(const string& file) {
00079 if(file.length() < 3) {
00080 return false;
00081 }
00082 plugin_t h;
00083
00084 #ifndef _WIN32
00085 if(!File::isAbsolutePath(file)) {
00086 h = PM_LOAD_LIBRARY((pluginPath + file).c_str());
00087 } else {
00088 h = PM_LOAD_LIBRARY(file.c_str());
00089 }
00090 #else
00091 if(!File::isAbsolutePath(file)) {
00092 h = LoadLibraryEx((pluginPath + file).c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES);
00093 } else {
00094 h = LoadLibraryEx(file.c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES);
00095 }
00096 #endif
00097
00098 if(h == NULL) {
00099 LOG(className, "Failed to load " + Text::utf8ToAcp(file) + ": " + PM_GET_ERROR_STRING());
00100 return false;
00101 }
00102
00103 PLUGIN_GET_VERSION v = (PLUGIN_GET_VERSION)PM_GET_ADDRESS(h, "pluginGetVersion");
00104 if(v != NULL) {
00105 double ver = v();
00106 if(ver == PLUGINVERSION) {
00107 #ifdef _WIN32
00108
00109 FreeLibrary(h);
00110 if(!File::isAbsolutePath(file)) {
00111 h = PM_LOAD_LIBRARY((pluginPath + file).c_str());
00112 } else {
00113 h = PM_LOAD_LIBRARY(file.c_str());
00114 }
00115 if(h == NULL) {
00116 LOG(className, "Failed to load " + Text::utf8ToAcp(file) + ": " + PM_GET_ERROR_STRING());
00117 return false;
00118 }
00119 #endif
00120 PLUGIN_LOAD l = (PLUGIN_LOAD)PM_GET_ADDRESS(h, "pluginLoad");
00121 PLUGIN_UNLOAD u = (PLUGIN_UNLOAD)PM_GET_ADDRESS(h, "pluginUnload");
00122
00123 if(l != NULL && u != NULL) {
00124 int i = l();
00125 if(i != 0) {
00126 LOG(className, "Failed to load plugin " + Text::utf8ToAcp(file) + " (Error " + Util::toString(i) + ")");
00127 } else {
00128
00129 active.push_back(PluginInfo(h, v, l, u));
00130 LOG(className, Text::utf8ToAcp(file) + " loaded");
00131 return true;
00132 }
00133 } else {
00134 LOG(className, Text::utf8ToAcp(file) + " is not a valid ADCH++ plugin");
00135 }
00136 } else {
00137 LOG(className, Text::utf8ToAcp(file) + " is for another version of ADCH++ (" + Util::toString(ver) + "), please get the correct one from the author");
00138 }
00139 } else {
00140 LOG(className, Text::utf8ToAcp(file) + " is not a valid ADCH++ plugin");
00141 }
00142
00143 PM_UNLOAD_LIBRARY(h);
00144 return false;
00145 }
00146
00147 void PluginManager::shutdown() {
00148 for(PluginList::reverse_iterator i = active.rbegin(); i != active.rend(); ++i)
00149 i->pluginUnload();
00150 #ifndef HAVE_BROKEN_MTALLOC
00151 for(PluginList::reverse_iterator i = active.rbegin(); i != active.rend(); ++i)
00152 PM_UNLOAD_LIBRARY(i->handle);
00153 #endif
00154
00155 registry.clear();
00156 active.clear();
00157 }
00158
00159 PluginManager::CommandDispatch::CommandDispatch(const std::string& name_, const PluginManager::CommandSlot& f_) :
00160 name('+' + name_),
00161 f(f_)
00162 {
00163 }
00164
00165 void PluginManager::CommandDispatch::operator()(Entity& e, AdcCommand& cmd, bool& ok) {
00166 if(e.getState() != Entity::STATE_NORMAL) {
00167 return;
00168 }
00169
00170 if(cmd.getCommand() != AdcCommand::CMD_MSG) {
00171 return;
00172 }
00173
00174 if(cmd.getParameters().size() < 1) {
00175 return;
00176 }
00177
00178 StringList l;
00179 Util::tokenize(l, cmd.getParameters()[0], ' ');
00180 if(l[0] != name) {
00181 return;
00182 }
00183 l[0] = name.substr(1);
00184
00185 if(!PluginManager::getInstance()->handleCommand(e, l)) {
00186 return;
00187 }
00188
00189 cmd.setPriority(AdcCommand::PRIORITY_IGNORE);
00190 f(e, l, ok);
00191 }
00192
00193 ClientManager::SignalReceive::Connection PluginManager::onCommand(const std::string& commandName, const CommandSlot& f) {
00194 return ClientManager::getInstance()->signalReceive().connect(CommandDispatch(commandName, f));
00195 }
00196
00197 PluginManager::CommandSignal& PluginManager::getCommandSignal(const std::string& commandName) {
00198 CommandHandlers::iterator i = commandHandlers.find(commandName);
00199 if(i == commandHandlers.end())
00200 return commandHandlers.insert(make_pair(commandName, CommandSignal())).first->second;
00201
00202 return i->second;
00203 }
00204
00205 bool PluginManager::handleCommand(Entity& e, const StringList& l) {
00206 CommandHandlers::iterator i = commandHandlers.find(l[0]);
00207 if(i == commandHandlers.end())
00208 return true;
00209
00210 bool ok = true;
00211 i->second(e, l, ok);
00212 return ok;
00213 }
00214
00215 }