正在显示
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 | +} | |
\ No newline at end of file | ... | ... |
请
注册
或
登录
后发表评论