70 lines
3.6 KiB
C++
70 lines
3.6 KiB
C++
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
#include <App/Application.h>
|
|
#include <Base/Exception.h>
|
|
#include <Python.h>
|
|
#include <emscripten/emscripten.h>
|
|
|
|
#include <fstream>
|
|
#include <iterator>
|
|
#include <string>
|
|
|
|
namespace {
|
|
std::string error;
|
|
std::string underscoreResult;
|
|
std::string uriResult;
|
|
int initialized = 0;
|
|
|
|
std::string pythonError(const char* fallback)
|
|
{
|
|
PyObject* type=nullptr; PyObject* value=nullptr; PyObject* trace=nullptr;
|
|
PyErr_Fetch(&type,&value,&trace); PyErr_NormalizeException(&type,&value,&trace);
|
|
std::string message=fallback; if(value){PyObject* text=PyObject_Str(value);if(text){message += ": ";message += PyUnicode_AsUTF8(text);Py_DECREF(text);}}
|
|
Py_XDECREF(type);Py_XDECREF(value);Py_XDECREF(trace);return message;
|
|
}
|
|
|
|
bool setup()
|
|
{
|
|
if (initialized) return true;
|
|
App::Application::initWebCore();
|
|
const char* code=
|
|
"import sys, types\n"
|
|
"sys.path.insert(0, '/freecad-mod/Help')\n"
|
|
"sys.path.insert(0, '/freecad-python')\n"
|
|
"_urllib=types.ModuleType('urllib'); _request=types.ModuleType('urllib.request'); _error=types.ModuleType('urllib.error')\n"
|
|
"_urllib.request=_request; _urllib.error=_error\n"
|
|
"sys.modules['urllib']=_urllib; sys.modules['urllib.request']=_request; sys.modules['urllib.error']=_error\n";
|
|
PyObject* globals=PyDict_New(); PyDict_SetItemString(globals,"__builtins__",PyEval_GetBuiltins());
|
|
PyObject* result=PyRun_String(code,Py_file_input,globals,globals);Py_DECREF(globals);
|
|
if(!result){error=pythonError("Help headless setup failed");return false;}Py_DECREF(result);
|
|
PyObject* module=PyImport_ImportModule("Help");
|
|
if(!module){error=pythonError("official Help.py import failed");return false;}Py_DECREF(module);initialized=1;return true;
|
|
}
|
|
|
|
bool callString(PyObject* module,const char* name,const char* argument,std::string& output)
|
|
{
|
|
PyObject* function=PyObject_GetAttrString(module,name);if(!function||!PyCallable_Check(function)){Py_XDECREF(function);error=std::string("Help callable unavailable: ")+name;return false;}
|
|
PyObject* value=PyObject_CallFunction(function,"s",argument);Py_DECREF(function);
|
|
if(!value){error=pythonError(name);return false;}PyObject* text=PyObject_Str(value);Py_DECREF(value);if(!text){error=pythonError(name);return false;}output=PyUnicode_AsUTF8(text);Py_DECREF(text);return true;
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
EMSCRIPTEN_KEEPALIVE int fc_web_help_source_inventory()
|
|
{
|
|
error.clear();std::ifstream file("/freecad-mod/Help/Help.py");if(!file){error="embedded Help.py is missing";return 0;}
|
|
const std::string text((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>());
|
|
if(text.find("def underscore_page") == std::string::npos || text.find("def get_uri") == std::string::npos){error="Help source inventory mismatch";return 0;}
|
|
return setup()?1:0;
|
|
}
|
|
EMSCRIPTEN_KEEPALIVE int fc_web_help_python_api()
|
|
{
|
|
error.clear();underscoreResult.clear();uriResult.clear();if(!setup())return 0;PyObject* module=PyImport_ImportModule("Help");if(!module){error=pythonError("Help import failed");return 0;}
|
|
const bool ok=callString(module,"underscore_page","Part Design/Additive Box",underscoreResult)&&callString(module,"get_uri","/tmp/help/page.md",uriResult);Py_DECREF(module);return ok&&underscoreResult=="Part Design/Additive_Box"&&uriResult=="file:///tmp/help/"?1:0;
|
|
}
|
|
EMSCRIPTEN_KEEPALIVE const char* fc_web_help_error(){return error.c_str();}
|
|
EMSCRIPTEN_KEEPALIVE const char* fc_web_help_underscore_result(){return underscoreResult.c_str();}
|
|
EMSCRIPTEN_KEEPALIVE const char* fc_web_help_uri_result(){return uriResult.c_str();}
|
|
EMSCRIPTEN_KEEPALIVE int fc_web_help_initialized(){return initialized;}
|
|
}
|