Files
FreeCADWasmDev/freecad-source/src/WebAssembly/FreeCADCoreProbe/HelpRuntimeProbe.cpp
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

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;}
}