Otclient  14/8/2020
module.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 #include "module.h"
24 #include "modulemanager.h"
25 #include "resourcemanager.h"
26 
27 #include <framework/otml/otml.h>
29 
30 Module::Module(const std::string& name)
31 {
32  m_name = name;
33  m_sandboxEnv = g_lua.newSandboxEnv();
34 }
35 
37 {
38  if(m_loaded)
39  return true;
40 
41  try {
42  // add to package.loaded
43  g_lua.getGlobalField("package", "loaded");
44  g_lua.getRef(m_sandboxEnv);
45  g_lua.setField(m_name);
46  g_lua.pop();
47 
48  for(const std::string& depName : m_dependencies) {
49  if(depName == m_name)
50  stdext::throw_exception("cannot depend on itself");
51 
52  ModulePtr dep = g_modules.getModule(depName);
53  if(!dep)
54  stdext::throw_exception(stdext::format("dependency '%s' was not found", depName));
55 
56  if(dep->hasDependency(m_name, true))
57  stdext::throw_exception(stdext::format("dependency '%s' is recursively depending on itself", depName));
58 
59  if(!dep->isLoaded() && !dep->load())
60  stdext::throw_exception(stdext::format("dependency '%s' has failed to load", depName));
61  }
62 
63  if(m_sandboxed)
64  g_lua.setGlobalEnvironment(m_sandboxEnv);
65 
66  for(const std::string& script : m_scripts) {
67  g_lua.loadScript(script);
68  g_lua.safeCall(0, 0);
69  }
70 
71  const std::string& onLoadBuffer = std::get<0>(m_onLoadFunc);
72  const std::string& onLoadSource = std::get<1>(m_onLoadFunc);
73  if(!onLoadBuffer.empty()) {
74  g_lua.loadBuffer(onLoadBuffer, onLoadSource);
75  if(m_sandboxed) {
76  g_lua.getRef(m_sandboxEnv);
77  g_lua.setEnv();
78  }
79  g_lua.safeCall(0, 0);
80  }
81 
82  if(m_sandboxed)
84 
85  m_loaded = true;
86  g_logger.debug(stdext::format("Loaded module '%s'", m_name));
87  } catch(stdext::exception& e) {
88  // remove from package.loaded
89  g_lua.getGlobalField("package", "loaded");
90  g_lua.pushNil();
91  g_lua.setField(m_name);
92  g_lua.pop();
93 
94  if(m_sandboxed)
96  g_logger.error(stdext::format("Unable to load module '%s': %s", m_name, e.what()));
97  return false;
98  }
99 
101 
102  for(const std::string& modName : m_loadLaterModules) {
103  ModulePtr dep = g_modules.getModule(modName);
104  if(!dep)
105  g_logger.error(stdext::format("Unable to find module '%s' required by '%s'", modName, m_name));
106  else if(!dep->isLoaded())
107  dep->load();
108  }
109 
110  return true;
111 }
112 
114 {
115  if(m_loaded) {
116  try {
117  if(m_sandboxed)
118  g_lua.setGlobalEnvironment(m_sandboxEnv);
119 
120  const std::string& onUnloadBuffer = std::get<0>(m_onUnloadFunc);
121  const std::string& onUnloadSource = std::get<1>(m_onUnloadFunc);
122  if(!onUnloadBuffer.empty()) {
123  g_lua.loadBuffer(onUnloadBuffer, onUnloadSource);
124  g_lua.safeCall(0, 0);
125  }
126 
127  if(m_sandboxed)
129  } catch(stdext::exception& e) {
130  if(m_sandboxed)
132  g_logger.error(stdext::format("Unable to unload module '%s': %s", m_name, e.what()));
133  }
134 
135  // clear all env references
136  g_lua.getRef(m_sandboxEnv);
137  g_lua.clearTable();
138  g_lua.pop();
139 
140  // remove from package.loaded
141  g_lua.getGlobalField("package", "loaded");
142  g_lua.pushNil();
143  g_lua.setField(m_name);
144  g_lua.pop();
145 
146  m_loaded = false;
147  //g_logger.info(stdext::format("Unloaded module '%s'", m_name));
149  }
150 }
151 
153 {
154  unload();
155  return load();
156 }
157 
159 {
160  for(const ModulePtr& module : g_modules.getModules()) {
161  if(module->isLoaded() && module->hasDependency(m_name))
162  return true;
163  }
164  return false;
165 }
166 
167 bool Module::hasDependency(const std::string& name, bool recursive)
168 {
169  if(std::find(m_dependencies.begin(), m_dependencies.end(), name) != m_dependencies.end())
170  return true;
171 
172  if(recursive) {
173  for(const std::string& depName : m_dependencies) {
174  ModulePtr dep = g_modules.getModule(depName);
175  if(dep && dep->hasDependency(name, true))
176  return true;
177  }
178  }
179 
180  return false;
181 }
182 
184 {
185  lua->getRef(m_sandboxEnv);
186  return 1;
187 }
188 
189 void Module::discover(const OTMLNodePtr& moduleNode)
190 {
191  const static std::string none = "none";
192  m_description = moduleNode->valueAt("description", none);
193  m_author = moduleNode->valueAt("author", none);
194  m_website = moduleNode->valueAt("website", none);
195  m_version = moduleNode->valueAt("version", none);
196  m_autoLoad = moduleNode->valueAt<bool>("autoload", false);
197  m_reloadable = moduleNode->valueAt<bool>("reloadable", true);
198  m_sandboxed = moduleNode->valueAt<bool>("sandboxed", false);
199  m_autoLoadPriority = moduleNode->valueAt<int>("autoload-priority", 9999);
200 
201  if(OTMLNodePtr node = moduleNode->get("dependencies")) {
202  for(const OTMLNodePtr& tmp : node->children())
203  m_dependencies.push_back(tmp->value());
204  }
205 
206  if(OTMLNodePtr node = moduleNode->get("scripts")) {
207  for(const OTMLNodePtr& tmp : node->children())
208  m_scripts.push_back(stdext::resolve_path(tmp->value(), node->source()));
209  }
210 
211  if(OTMLNodePtr node = moduleNode->get("load-later")) {
212  for(const OTMLNodePtr& tmp : node->children())
213  m_loadLaterModules.push_back(tmp->value());
214  }
215 
216  if(OTMLNodePtr node = moduleNode->get("@onLoad"))
217  m_onLoadFunc = std::make_tuple(node->value(), "@" + node->source() + ":[" + node->tag() + "]");
218 
219  if(OTMLNodePtr node = moduleNode->get("@onUnload"))
220  m_onUnloadFunc = std::make_tuple(node->value(), "@" + node->source() + ":[" + node->tag() + "]");
221 }
Module::asModule
ModulePtr asModule()
Definition: module.h:59
Module::unload
void unload()
Definition: module.cpp:113
otml.h
ModuleManager::getModule
ModulePtr getModule(const std::string &moduleName)
Definition: modulemanager.cpp:125
Module::load
bool load()
Definition: module.cpp:36
ModuleManager::getModules
std::deque< ModulePtr > getModules()
Definition: modulemanager.h:42
module.h
resourcemanager.h
luainterface.h
Logger::error
void error(const std::string &what)
Definition: logger.h:54
OTMLNode::children
OTMLNodeList children()
Definition: otmlnode.cpp:170
LuaInterface::setGlobalEnvironment
void setGlobalEnvironment(int env)
Definition: luainterface.cpp:859
LuaInterface::loadScript
void loadScript(const std::string &fileName)
Definition: luainterface.cpp:324
stdext::format
std::string format()
Definition: format.h:82
LuaInterface::clearTable
void clearTable(int index=-1)
Definition: luainterface.cpp:918
Module::hasDependency
bool hasDependency(const std::string &name, bool recursive=false)
Definition: module.cpp:167
stdext::resolve_path
std::string resolve_path(const std::string &filePath, std::string sourcePath)
Resolve a file path by combining sourcePath with filePath.
Definition: string.cpp:35
OTMLNode::valueAt
T valueAt(const std::string &childTag)
Definition: otmlnode.h:130
g_logger
Logger g_logger
Definition: logger.cpp:35
LuaInterface::newSandboxEnv
int newSandboxEnv()
Creates a new environment table The new environment table is redirected to the global environment (ak...
Definition: luainterface.cpp:536
g_lua
LuaInterface g_lua
Definition: luainterface.cpp:31
LuaInterface::setEnv
void setEnv(int index=-2)
Definition: luainterface.cpp:900
ModuleManager::updateModuleLoadOrder
void updateModuleLoadOrder(ModulePtr module)
Definition: modulemanager.cpp:133
Module::getSandbox
int getSandbox(LuaInterface *lua)
Definition: module.cpp:183
LuaInterface::getGlobalField
void getGlobalField(const std::string &globalKey, const std::string &fieldKey)
Definition: luainterface.cpp:944
LuaInterface
Class that manages LUA stuff.
Definition: luainterface.h:32
LuaInterface::loadBuffer
void loadBuffer(const std::string &buffer, const std::string &source)
Definition: luainterface.cpp:730
OTMLNode::get
OTMLNodePtr get(const std::string &childTag)
Definition: otmlnode.cpp:54
stdext::throw_exception
void throw_exception(const std::string &what)
Throws a generic exception.
Definition: exception.h:43
LuaInterface::resetGlobalEnvironment
void resetGlobalEnvironment()
Definition: luainterface.h:250
stdext::exception::what
virtual const char * what() const
Definition: exception.h:37
Logger::debug
void debug(const std::string &what)
Definition: logger.h:51
LuaInterface::pop
void pop(int n=1)
Definition: luainterface.cpp:999
stdext::shared_object_ptr
Definition: shared_object.h:39
LuaInterface::setField
void setField(const char *key, int index=-2)
Definition: luainterface.cpp:887
modulemanager.h
LuaInterface::pushNil
void pushNil()
Definition: luainterface.cpp:1060
LuaInterface::getRef
void getRef(int ref)
Definition: luainterface.cpp:846
Module::isDependent
bool isDependent()
Definition: module.cpp:158
Module::discover
void discover(const OTMLNodePtr &moduleNode)
Definition: module.cpp:189
Module::Module
Module(const std::string &name)
Definition: module.cpp:30
LuaInterface::safeCall
int safeCall(int numArgs=0, int numRets=-1)
Calls a function The function and arguments must be on top of the stack in order, results are pushed ...
Definition: luainterface.cpp:432
g_modules
ModuleManager g_modules
Definition: modulemanager.cpp:29
Module::reload
bool reload()
Definition: module.cpp:152
stdext::exception
Definition: exception.h:31