// electron/utils/readConfig.js const path = require('path'); const fs = require('fs'); const Log = require('ee-core/log'); const { spawn } = require('child_process'); const { EventEmitter } = require('events'); const { liveShow, liveHide, setParams, capture, getParams,CMD,captureLive,closeOtherWindow,minimizeSmartShooter } = require('../api/camera'); const { dialog } = require('electron'); // 引入 electron 的 dialog 模块 const CoreWindow = require("ee-core/electron/window"); const { readConfigFile, writeConfigFile } = require('../utils/config'); // 进程状态管理 let cameraProcess = null; // 子进程引用 let isProcessRunning = false; // 进程运行状态 const processEmitter = new EventEmitter(); // 进程事件发射器 // Smart Shooter 5 / 6 与 digiCamControl 并存。 // 5 和 6 共用同一套 External API(54543 事件 / 54544 请求),不能同时开,按 controlType 只启动其中一个。 const CONTROLLERS = { digiCamControl: { exe: "CameraControl.exe", pathKey: "digiCamControlPath", label: "digiCamControl", }, SmartShooter: { exe: "SmartShooter5.exe", pathKey: "SmartShooterPath", label: "Smart Shooter 5", }, SmartShooter6: { exe: "SmartShooter6.exe", pathKey: "SmartShooter6Path", label: "Smart Shooter 6", }, } // 历史配置 controlType 仍是 SmartShooter,保持原行为 function normalizeControlType(type) { return CONTROLLERS[type] ? type : "SmartShooter" } function isSmartShooterType(type) { return type === "SmartShooter" || type === "SmartShooter6" } function getController() { const config = readConfigFile() || {} const type = normalizeControlType(config.controlType) const spec = CONTROLLERS[type] return { type, ...spec, dir: config.controlPath || config[spec.pathKey] || "", } } function getExePath () { const controller = getController() const exePath = controller.dir ? path.join(controller.dir, controller.exe) : "" console.log('ex============ePath'); console.log(exePath); return exePath } // 用户手动选安装目录时,按目录里实际存在的 exe 识别,5 和 6 互不覆盖 function detectController(dir) { if (fs.existsSync(path.join(dir, CONTROLLERS.SmartShooter6.exe))) return "SmartShooter6" if (fs.existsSync(path.join(dir, CONTROLLERS.SmartShooter.exe))) return "SmartShooter" if (fs.existsSync(path.join(dir, CONTROLLERS.digiCamControl.exe))) return "digiCamControl" return "" } async function checkCameraControlCmdExists() { try { // 拼接 CameraControlCmd.exe 的完整路径 let exePath = getExePath() // 检查文件是否存在 const exists = await fs.promises.access(exePath, fs.constants.F_OK) .then(() => true) .catch(() => false); if (!exists) { // 弹出文件夹选择对话框 const { canceled, filePaths } = await dialog.showOpenDialog({ title: '选择 相机控制安装软件 文件夹', properties: ['openDirectory'] }); if (!canceled && filePaths.length > 0) { const selectedPath = filePaths[0]; const detected = detectController(selectedPath); if (!detected) { console.error('所选目录不是已知的相机控制软件'); return { status:-1, msg:"所选目录中未找到 SmartShooter6.exe、SmartShooter5.exe 或 CameraControl.exe", } } writeConfigFile("controlType", detected) writeConfigFile("controlPath", selectedPath) writeConfigFile(CONTROLLERS[detected].pathKey, selectedPath) } else { console.error('用户未选择文件夹'); return { status:-1, msg:"无法找到 SmartShooter6.exe、SmartShooter5.exe 或 CameraControl.exe", } } } const res = await openCameraControlCmd(); // Smart Shooter 5 / 6 启动后最小化窗口;digiCamControl 走自己的最小化命令 if(isSmartShooterType(getController().type)){ // 等待软件启动完成 setTimeout(async () => { try { await minimizeSmartShooter(); } catch (error) { console.log('最小化SmartShooter失败:', error); } }, 3000); // 等待3秒让软件完全启动 } return res; } catch (error) { Log.error('检查 第三方相机控制器 是否存在时出错:', error); throw error; } } async function openCameraControlCmd(digiCamControlPath) { return new Promise(async (resolve, reject) => { try { // 获取 digiCamControl 文件夹路径 // 拼接 CameraControlCmd.exe 的完整路径 let exePath = getExePath() // 检查文件是否存在 await fs.promises.access(exePath, fs.constants.F_OK); try { // 保存进程引用并标记为运行中 cameraProcess = spawn(exePath); isProcessRunning = true; console.log('[CAMERA-DEBUG] spawn PID:', cameraProcess.pid, '时间:', new Date().toISOString()); cameraProcess.stdout.on('data', (data) => { console.log('[CAMERA-DEBUG] stdout 收到数据:', data.toString().substring(0, 100)); resolve(true) }); // 监听进程关闭事件 cameraProcess.on('close', (code) => { console.log('[CAMERA-DEBUG] close 事件触发! PID:', cameraProcess?.pid, '退出码:', code, '时间:', new Date().toISOString()); isProcessRunning = false; cameraProcess = null; Log.info(`相机控制软件已关闭,退出码: ${code}`); processEmitter.emit('camera-process-closed'); }); cameraProcess.on('error', (err) => { console.log('[CAMERA-DEBUG] error 事件触发:', err.message); isProcessRunning = false; cameraProcess = null; Log.error('相机控制软件进程错误:', err); }); } catch (error) { Log.error('error 第三方相机控制器:', error); throw error; } } catch (error) { Log.error('无法找到或运行 第三方相机控制器:', error); throw error; } }) } async function closeCameraControlTips() { try { await closeOtherWindow() }catch (e) { console.log(e) } } module.exports = { checkCameraControlCmdExists, closeCameraControlTips, minimizeSmartShooter, CONTROLLERS, isSmartShooterType, getController, // 进程状态管理 isProcessRunning: () => isProcessRunning, onProcessClosed: (callback) => processEmitter.on('camera-process-closed', callback), removeProcessClosedListener: (callback) => processEmitter.removeListener('camera-process-closed', callback), };