正在显示
1 个修改的文件
包含
283 行增加
和
0 行删除
src/server/python/dmppythonutils.cpp
0 → 100644
1 | +/************************************************************************** | ||
2 | +* file: dmppythonutils.cpp | ||
3 | + | ||
4 | +* Author: wanzhongping | ||
5 | +* Date: 2021-04-20 13:38:27 | ||
6 | +* Email: zhongpingw@chinadci.com | ||
7 | +* copyright: 广州城市信息研究所有限公司 | ||
8 | +***************************************************************************/ | ||
9 | + | ||
10 | + | ||
11 | +#include "dmppythonutils.h" | ||
12 | +#include "dmplogger.h" | ||
13 | +#include "dmpapplication.h" | ||
14 | +#include "../dmpserverinterface.h" | ||
15 | +#include <boost/format.hpp> | ||
16 | +#include <boost/algorithm/string.hpp> | ||
17 | +#include <boost/filesystem.hpp> | ||
18 | + | ||
19 | +namespace python = boost::python; | ||
20 | + | ||
21 | +#define INIT_MODULE PyInit_dmap_server | ||
22 | +extern "C" PyObject *INIT_MODULE(); | ||
23 | + | ||
24 | +DmpPythonUtils::DmpPythonUtils() | ||
25 | +{ | ||
26 | +} | ||
27 | + | ||
28 | +DmpPythonUtils::~DmpPythonUtils() | ||
29 | +{ | ||
30 | + ExitPython(); | ||
31 | +} | ||
32 | + | ||
33 | +void DmpPythonUtils::Init() | ||
34 | +{ | ||
35 | + if (PyImport_AppendInittab("dmap_server", INIT_MODULE) == -1) | ||
36 | + throw std::runtime_error("Failed to add dmap_server to the interpreter's " | ||
37 | + "builtin modules"); | ||
38 | + Py_Initialize(); | ||
39 | + python_enabled_ = true; | ||
40 | + main_module_ = python::import("__main__"); | ||
41 | + main_namespace_ = main_module_.attr("__dict__"); | ||
42 | +} | ||
43 | + | ||
44 | +bool DmpPythonUtils::CheckSystemImports() | ||
45 | +{ | ||
46 | + RunString("import sys"); | ||
47 | + RunString("import os"); | ||
48 | + | ||
49 | + std::string pluginpaths; | ||
50 | + std::vector<std::string> vec_paths = ExtraPluginsPaths(); | ||
51 | + std::vector<std::string>::iterator iter; | ||
52 | + std::string comma = ","; | ||
53 | + for (iter = vec_paths.begin(); iter != vec_paths.end(); iter++) | ||
54 | + { | ||
55 | + if (!boost::filesystem::exists(*iter)) | ||
56 | + { | ||
57 | + boost::format fmt = boost::format("The extra plugin path '%1' does not exist!") % *iter; | ||
58 | + LOGGER_WARN(fmt.str()); | ||
59 | + } | ||
60 | + | ||
61 | + if (!pluginpaths.empty()) | ||
62 | + { | ||
63 | + pluginpaths += comma; | ||
64 | + } | ||
65 | + pluginpaths += '"' + *iter + '"'; | ||
66 | + } | ||
67 | + if (!pluginpaths.empty()) | ||
68 | + { | ||
69 | + pluginpaths += comma; | ||
70 | + } | ||
71 | + pluginpaths += '"' + HomePluginsPath() + '"'; | ||
72 | + pluginpaths += comma + '"' + PluginsPath() + '"'; | ||
73 | + | ||
74 | + // expect that bindings are installed locally, so add the path to modules | ||
75 | + // also add path to plugins | ||
76 | + std::string newpaths; | ||
77 | + newpaths += '"' + PythonPath() + '"' + comma; | ||
78 | + newpaths += '"' + HomePythonPath() + '"' + comma; | ||
79 | + newpaths += pluginpaths; | ||
80 | + | ||
81 | + RunString("sys.path = [" + newpaths + "] + sys.path"); | ||
82 | + | ||
83 | + if (!RunString("import dmap.utils")) | ||
84 | + { | ||
85 | + return false; | ||
86 | + } | ||
87 | + | ||
88 | + boost::format fmt_plugin_paths = boost::format("dmap.utils.plugin_paths = [%1%]") % pluginpaths; | ||
89 | + RunString(fmt_plugin_paths.str()); | ||
90 | + boost::format fmt_sys_plugin_paths = boost::format("dmap.utils.sys_plugin_path = \"%1%\"") % PluginsPath(); | ||
91 | + RunString(fmt_sys_plugin_paths.str()); | ||
92 | + boost::format fmt_home_plugin_paths = boost::format("dmap.utils.home_plugin_path = \"%1%\"") % HomePluginsPath(); | ||
93 | + RunString(fmt_home_plugin_paths.str()); | ||
94 | + | ||
95 | + return true; | ||
96 | +} | ||
97 | + | ||
98 | +bool DmpPythonUtils::RunString(const std::string &command, bool single) | ||
99 | +{ | ||
100 | + try | ||
101 | + { | ||
102 | + std::cout << command << std::endl; | ||
103 | + if(single){ | ||
104 | + python::exec(command.c_str(), main_namespace_, main_namespace_); | ||
105 | + }else | ||
106 | + { | ||
107 | + python::exec_file(command.c_str(), main_namespace_, main_namespace_); | ||
108 | + } | ||
109 | + | ||
110 | + } | ||
111 | + catch (const python::error_already_set &) | ||
112 | + { | ||
113 | + std::cerr << ">>> Error! Uncaught exception:\n"; | ||
114 | + PyErr_Print(); | ||
115 | + return false; | ||
116 | + } | ||
117 | + return true; | ||
118 | +} | ||
119 | + | ||
120 | +bool DmpPythonUtils::EvalString(const std::string &command, std::string &result ) | ||
121 | +{ | ||
122 | + try | ||
123 | + { | ||
124 | + std::cout << command << std::endl; | ||
125 | + python::object res = python::eval(command.c_str(), main_namespace_, main_namespace_); | ||
126 | + result = python::extract<std::string>(res); | ||
127 | + } | ||
128 | + catch (const python::error_already_set &) | ||
129 | + { | ||
130 | + std::cerr << ">>> Error! Uncaught exception:\n"; | ||
131 | + PyErr_Print(); | ||
132 | + return false; | ||
133 | + } | ||
134 | + return true; | ||
135 | +} | ||
136 | + | ||
137 | + | ||
138 | +void DmpPythonUtils::InitServerPython(DmpServerInterface *interface) | ||
139 | +{ | ||
140 | + Init(); | ||
141 | + if (!CheckSystemImports()) | ||
142 | + { | ||
143 | + ExitPython(); | ||
144 | + return; | ||
145 | + } | ||
146 | + | ||
147 | + try | ||
148 | + { | ||
149 | + python::import("dmap_server"); | ||
150 | + main_namespace_["serverIface_"] = boost::python::ptr(interface); | ||
151 | + RunString("dmap.utils.initServerInterface(serverIface_)"); | ||
152 | + } | ||
153 | + catch (python::error_already_set &e) | ||
154 | + { | ||
155 | + PyErr_PrintEx(0); | ||
156 | + } | ||
157 | + //Finish(); | ||
158 | +} | ||
159 | + | ||
160 | +bool DmpPythonUtils::StartServerPlugin(std::string packageName) | ||
161 | +{ | ||
162 | + boost::format fmt = boost::format("dmap.utils.startServerPlugin('%1%')") % packageName; | ||
163 | + try | ||
164 | + { | ||
165 | + std::cout << fmt.str() << std::endl; | ||
166 | + python::object res = python::eval(fmt.str().c_str(), main_namespace_, main_namespace_); | ||
167 | + return python::extract<bool>(res); | ||
168 | + } | ||
169 | + catch (const python::error_already_set &) | ||
170 | + { | ||
171 | + std::cerr << ">>> Error! Uncaught exception:\n"; | ||
172 | + PyErr_Print(); | ||
173 | + } | ||
174 | + return false; | ||
175 | +} | ||
176 | + | ||
177 | +void DmpPythonUtils::Finish() | ||
178 | +{ | ||
179 | + // release GIL! | ||
180 | + // Later on, we acquire GIL just before doing some Python calls and | ||
181 | + // release GIL again when the work with Python API is done. | ||
182 | + // (i.e. there must be PyGILState_Ensure + PyGILState_Release pair | ||
183 | + // around any calls to Python API, otherwise we may segfault!) | ||
184 | + //main_state_ = PyEval_SaveThread(); | ||
185 | +} | ||
186 | + | ||
187 | +std::vector<std::string> DmpPythonUtils::ExtraPluginsPaths() const | ||
188 | +{ | ||
189 | + std::vector<std::string> vec_paths; | ||
190 | + const char *paths = getenv("DMAP_PLUGINPATH"); | ||
191 | + if (paths) | ||
192 | + { | ||
193 | + if (boost::icontains(paths, ";")) | ||
194 | + { | ||
195 | + boost::split(vec_paths, paths, boost::is_any_of(";"), boost::token_compress_on); | ||
196 | + } | ||
197 | + else | ||
198 | + { | ||
199 | + vec_paths.push_back(paths); | ||
200 | + } | ||
201 | + } | ||
202 | + return vec_paths; | ||
203 | +} | ||
204 | + | ||
205 | +std::string DmpPythonUtils::PythonPath() const | ||
206 | +{ | ||
207 | + if (DmpApplication::IsRunningFromBuildDir()) | ||
208 | + return DmpApplication::build_output_path() + "/python"; | ||
209 | + else | ||
210 | + return DmpApplication::pkg_data_path() + "/python"; | ||
211 | +} | ||
212 | + | ||
213 | +std::string DmpPythonUtils::PluginsPath() const | ||
214 | +{ | ||
215 | + return PythonPath() + "/plugins"; | ||
216 | +} | ||
217 | + | ||
218 | +std::string DmpPythonUtils::HomePythonPath() const | ||
219 | +{ | ||
220 | + std::string settingsDir = DmpApplication::DMapSettingsDirPath(); | ||
221 | + boost::format fmt = boost::format("%1%/python") % settingsDir; | ||
222 | + return fmt.str(); | ||
223 | +} | ||
224 | + | ||
225 | +std::string DmpPythonUtils::HomePluginsPath() const | ||
226 | +{ | ||
227 | + return HomePythonPath() + "/plugins"; | ||
228 | +} | ||
229 | + | ||
230 | +bool DmpPythonUtils::IsEnabled() | ||
231 | +{ | ||
232 | + return python_enabled_; | ||
233 | +} | ||
234 | + | ||
235 | +bool DmpPythonUtils::LoadPlugin(const std::string &packageName) | ||
236 | +{ | ||
237 | + boost::format fmt = boost::format("dmap.utils.loadPlugin('%1%')") % packageName; | ||
238 | + try | ||
239 | + { std::cout << fmt.str() << std::endl; | ||
240 | + python::object res = python::eval(fmt.str().c_str(), main_namespace_, main_namespace_); | ||
241 | + return python::extract<bool>(res); | ||
242 | + } | ||
243 | + catch (const python::error_already_set &) | ||
244 | + { | ||
245 | + std::cerr << ">>> Error! Uncaught exception:\n"; | ||
246 | + PyErr_Print(); | ||
247 | + } | ||
248 | + return false; | ||
249 | +} | ||
250 | + | ||
251 | +void DmpPythonUtils::UninstallErrorHook() | ||
252 | +{ | ||
253 | + RunString("qgis.utils.uninstallErrorHook()"); | ||
254 | +} | ||
255 | +std::string DmpPythonUtils::GetPluginMetadata(const std::string &pluginName, const std::string &function) | ||
256 | +{ | ||
257 | + std::string res; | ||
258 | + boost::format fmt = boost::format("dmap.utils.pluginMetadata('%1%', '%2%')") % pluginName % function; | ||
259 | + EvalString(fmt.str(), res); | ||
260 | + LOGGER_DEBUG("metadata " + pluginName + " - '" + function + "' = " + res); | ||
261 | + return res; | ||
262 | +} | ||
263 | +std::vector<std::string> DmpPythonUtils::PluginList() | ||
264 | +{ | ||
265 | + RunString("dmap.utils.updateAvailablePlugins()"); | ||
266 | + | ||
267 | + std::string output; | ||
268 | + EvalString("'\\n'.join(dmap.utils.available_plugins)", output); | ||
269 | + | ||
270 | + std::vector<std::string> vec_plugins; | ||
271 | + boost::split(vec_plugins, output, boost::is_any_of("\n"), boost::token_compress_on); | ||
272 | + return vec_plugins; | ||
273 | +} | ||
274 | +void DmpPythonUtils::ExitPython() | ||
275 | +{ | ||
276 | + if (error_hook_installed_) | ||
277 | + UninstallErrorHook(); | ||
278 | + // causes segfault! | ||
279 | + //Py_Finalize(); | ||
280 | + // main_module_ = nullptr; | ||
281 | + // main_dict_ = nullptr; | ||
282 | + python_enabled_ = false; | ||
283 | +} |
请
注册
或
登录
后发表评论