| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /**
- * laser_cal Node.js 调用封装
- *
- * 支持三种调用模式:
- * 1. module 模式:通过 Python 解释器 + laser_wrapper.py 加载 .pyd/.so 共享库
- * 2. exe 模式:直接调用编译后的可执行程序(standalone 目录)
- * 3. onefile 模式:直接调用编译后的单文件可执行程序
- *
- * 使用示例:
- * const laser = require('./laser');
- *
- * // 自动检测模式
- * const result = await laser.callLaser('getpath');
- * const result = await laser.callLaser('loaddata', base64JsonData);
- */
- const { execFile } = require('child_process');
- const path = require('path');
- const fs = require('fs');
- // ============================================================
- // 配置区(根据实际部署路径修改)
- // ============================================================
- const PROJECT_NAME = 'laser_cal';
- const DIST_DIR = path.join(__dirname, '..', 'dist', 'program');
- const WRAPPER_SCRIPT = path.join(__dirname, 'laser_wrapper.py');
- // Python 路径(module 模式需要)
- // 可通过环境变量 PYTHON_PATH 覆盖
- const PYTHON_CMD = process.env.PYTHON_PATH
- || (process.platform === 'win32'
- ? path.join(__dirname, '..', 'myvenv', 'Scripts', 'python.exe')
- : 'python3');
- // ============================================================
- // 自动检测可用的调用模式
- // ============================================================
- function detectMode() {
- const exeName = process.platform === 'win32' ? `${PROJECT_NAME}.exe` : PROJECT_NAME;
- // 优先检测 onefile 模式(exe 在 dist/program/ 下)
- const onefilePath = path.join(DIST_DIR, exeName);
- if (fs.existsSync(onefilePath)) {
- return { mode: 'exe', execPath: onefilePath };
- }
- // 检测 standalone 模式(exe 在 dist/program/api_test.dist/ 下)
- const standalonePath = path.join(DIST_DIR, 'api_test.dist', exeName);
- if (fs.existsSync(standalonePath)) {
- return { mode: 'exe', execPath: standalonePath };
- }
- // 回退到 module 模式(使用 Python + wrapper)
- return { mode: 'module', execPath: null };
- }
- // ============================================================
- // 核心调用函数
- // ============================================================
- /**
- * 调用 laser_cal 后端
- * @param {string} apiName - API 名称: getpath | loaddata | historydata | deletedata
- * @param {string|null} b64Data - Base64 编码的 JSON 参数(loaddata/historydata/deletedata 需要)
- * @returns {Promise<object>} - 解析后的 JSON 结果
- */
- function callLaser(apiName, b64Data = null) {
- const detected = detectMode();
- if (detected.mode === 'exe') {
- return callExe(detected.execPath, apiName, b64Data);
- } else {
- return callModule(apiName, b64Data);
- }
- }
- /**
- * 直接调用可执行文件(exe/standalone 模式)
- */
- function callExe(exePath, apiName, b64Data = null) {
- return new Promise((resolve, reject) => {
- const args = [apiName];
- if (b64Data) {
- args.push(b64Data);
- }
- const options = {
- maxBuffer: 1024 * 1024 * 50,
- cwd: path.dirname(exePath) // 设置工作目录为 exe 所在目录(确保找到 license)
- };
- execFile(exePath, args, options, (error, stdout, stderr) => {
- if (error) {
- return reject(new Error(`Execution failed: ${error.message}\nStderr: ${stderr}`));
- }
- parseOutput(stdout, resolve, reject);
- });
- });
- }
- /**
- * 通过 Python 解释器调用(module 模式)
- */
- function callModule(apiName, b64Data = null) {
- return new Promise((resolve, reject) => {
- const args = [WRAPPER_SCRIPT, apiName];
- if (b64Data) {
- args.push(b64Data);
- }
- const options = {
- maxBuffer: 1024 * 1024 * 50
- };
- execFile(PYTHON_CMD, args, options, (error, stdout, stderr) => {
- if (error) {
- return reject(new Error(`Python execution failed: ${error.message}\nStderr: ${stderr}`));
- }
- parseOutput(stdout, resolve, reject);
- });
- });
- }
- /**
- * 解析 stdout JSON 输出
- */
- function parseOutput(stdout, resolve, reject) {
- try {
- const lines = stdout.trim().split('\n');
- const lastLine = lines[lines.length - 1];
- const result = JSON.parse(lastLine);
- if (result.error) {
- reject(new Error(result.error));
- } else {
- resolve(result);
- }
- } catch (e) {
- reject(new Error(`Failed to parse output: ${stdout}\nError: ${e.message}`));
- }
- }
- // ============================================================
- // 兼容旧接口
- // ============================================================
- /**
- * 兼容旧版 callPython 接口
- */
- function callPython(apiName, b64Data = null) {
- return callLaser(apiName, b64Data);
- }
- // ============================================================
- // 导出
- // ============================================================
- module.exports = {
- callLaser,
- callPython, // 向后兼容
- callExe,
- callModule,
- detectMode
- };
|