Kaynağa Gözat

feat(socket): 重构 socket 连接和消息处理

- 新增通用 socket 模块,用于处理与 pyapp 的通信
-优化 camera API,支持 digiCamControl 和 Smart Shooter 两种控制方式
- 修改前端检查相机连接逻辑,兼容两种控制方式
-调整直播预览功能,支持 Smart Shooter 预览- 重构后端 socket 控制器,使用新的 socket 模块
panqiuyao 5 ay önce
ebeveyn
işleme
cdbd0e5be9

+ 66 - 8
electron/api/camera.js

@@ -52,36 +52,76 @@ async function fetchExampleData(url) {
 }
 
 
+const socket = require('../utils/socket')
+const pySocket = new socket()
+const { readConfigFile } = require('../utils/config');
+
 
 module.exports = {
-  liveShow(){
-    return get({
-      url: '?CMD=LiveViewWnd_Show'
-    })
+  async liveShow(){
+    if(readConfigFile().type === 'digiCamContro'){
+      return get({
+        url: '?CMD=LiveViewWnd_Show'
+      })
+    }else{
+
+      await pySocket.sendMessage(JSON.stringify({
+        type: 'smart_shooter_enable_preview',
+        data:{
+          value:true
+        }
+      }))
+      return  new Promise(async (resolve, reject) => {
+        pySocket.onSocketMessage('smart_shooter_enable_preview',(message)=>{
+
+          resolve(message)
+        })
+      })
+    }
   },
-  liveHide(){
-    return get({
-      url: '?CMD=LiveViewWnd_Hide'
-    })
+  async liveHide(){
+    if(readConfigFile().type === 'digiCamContro'){
+      return get({
+        url: '?CMD=LiveViewWnd_Hide'
+      })
+    }else{
+
+      await pySocket.sendMessage(JSON.stringify({
+        type: 'smart_shooter_enable_preview',
+        data:{
+          value:false
+        }
+      }))
+      return  new Promise(async (resolve, reject) => {
+        pySocket.onSocketMessage('smart_shooter_enable_preview',(message)=>{
+
+          resolve(message)
+        })
+      })
+    }
   },
   captureLive(){
+    return  {}
     return get({
       url: '?CMD=LiveView_Capture'
     })
   },
   capture(){
+    return  {}
     return get({
       url: '?CMD=Capture'
     })
   },
 
   CMD(cmd){
+    return  {}
     return get({
       url: '?CMD='+cmd
     })
   },
 
   getParams(params){
+    return  {}
     return  fetchExampleData(`?slc=get&param1=${params}`)
   },
   setParams(params){
@@ -95,6 +135,24 @@ module.exports = {
       url: '/close_other_window',
     })
   },
+  async checkCamera(){
+    if(readConfigFile().type === 'digiCamContro'){
+      return  fetchExampleData(`?slc=get&param1=iso`)
+    }else {
+
+      await pySocket.sendMessage(JSON.stringify({
+        type: 'smart_shooter_getinfo',
+        data:{}
+      }))
+     return  new Promise(async (resolve, reject) => {
+        pySocket.onSocketMessage('smart_shooter_getinfo',(message)=>{
+          console.log('m===================essage')
+          console.log(message)
+          resolve(message)
+        })
+      })
+    }
+  }
 }
 
 

+ 2 - 1
electron/api/request.js

@@ -1,5 +1,6 @@
 const axios = require('axios')
-const { pyapp } = require('../config/app.config.json')
+const { readConfigFile } = require('../utils/config');
+const pyapp = readConfigFile().pyapp
 
 
 /* axios.defaults.withCredentials = true*/

+ 0 - 3
electron/config/app.config.json

@@ -1,3 +0,0 @@
-{
-  "pyapp": "127.0.0.1"
-}

+ 51 - 20
electron/controller/camera.js

@@ -1,7 +1,9 @@
 'use strict';
 const { Controller } = require('ee-core');
 const { checkCameraControlCmdExists, closeCameraControlTips} = require('../utils/camera');
-const { liveShow, liveHide, setParams, capture, getParams,CMD,captureLive,closeOtherWindow } = require('../api/camera');
+const {
+  checkCamera,
+  liveShow, liveHide, setParams, capture, getParams,CMD,captureLive,closeOtherWindow } = require('../api/camera');
 
 const { readConfigFile } = require('../utils/config');
 
@@ -13,28 +15,55 @@ class CameraController extends Controller {
 
   async connect() {
     try {
-      await getParams('iso').catch(e=>{
-        isOPen = false;
-      })
-      if(!isOPen){
-        await checkCameraControlCmdExists()
-        await  CMD('All_Minimize')
-        await closeCameraControlTips()
-        isOPen = true
-      }
 
-      const res = await getParams('iso')
-      if(res  === '未将对象引用设置到对象的实例。'){
+      if(readConfigFile().type === 'digiCamContro'){
+
+        await getParams('iso').catch(e=>{
+          isOPen = false;
+        })
+        if(!isOPen){
+          await checkCameraControlCmdExists(digiCamControlPath)
+          await  CMD('All_Minimize')
+          await closeCameraControlTips()
+          isOPen = true
+        }
+        const res = await getParams('iso')
+        if(res  === '未将对象引用设置到对象的实例。'){
+          return {
+            status:-1,
+            msg:"相机未连接,请链接相机。",
+          }
+        }
         return {
-          status:-1,
-          msg:"相机未连接,请链接相机。",
+          status:2,
+          msg:res,
         }
+
+
+      }else{
+
+        let res = await checkCamera().catch(e=>{
+          isOPen = false;
+        })
+        if(res?.device_status  === -1 ){
+          isOPen = false;
+          await checkCameraControlCmdExists()
+          isOPen = true
+
+          res = await checkCamera()
+        }
+
+        if(res?.device_status  === 2){
+          return  {
+            ...res,
+            status:2
+          };
+        }
+
+
       }
-      return {
-        status:2,
-        msg:res,
-      }
-      return true;
+
+
     } catch (error) {
 
       let msg = '请安装digiCamControl软件,并打开digiCamControl软件的web服务,端口为5513'
@@ -52,7 +81,9 @@ class CameraController extends Controller {
   async liveShow() {
     try {
       await liveShow();
-      await  CMD('All_Minimize')
+      if(readConfigFile().type === 'digiCamContro'){
+        await  CMD('All_Minimize')
+      }
       return true;
     } catch (error) {
       console.error('eeee启动直播失败:', error);

+ 7 - 91
electron/controller/socket.js

@@ -1,20 +1,10 @@
 'use strict';
 
 const { Controller } = require('ee-core');
-const Log = require('ee-core/log');
-const CoreWindow = require('ee-core/electron/window');
-const WebSocket = require('ws'); // 引入原生 ws 库
-let socket = null;
-const { pyapp } = require('../config/app.config.json')
+const socket = require('../utils/socket')
+const pySocket = new socket()
+
 
-const typeToMessage = {
-  run_mcu_single:['seeting','default'],
-  get_deviation_data:"developer",
-  set_deviation:"developer",
-  get_mcu_other_info:"developer",
-  set_mcu_other_info:"developer",
-  send_command:"developer"
-}
 class SocketController extends Controller {
   constructor(ctx) {
     super(ctx);
@@ -26,71 +16,7 @@ class SocketController extends Controller {
   async connect() {
 
      await new Promise(async (resolve,reject) => {
-
-       const win = CoreWindow.getMainWindow()
-       if(socket){
-         console.log('has socket ')
-         resolve(true);
-         win.webContents.send('controller.socket.connect_open', true);
-         return;
-       }
-
-      socket = new WebSocket('ws://'+pyapp+':7074/ws');
-
-      // 监听连接成功事件
-      socket.on('open', () => {
-        console.log('socket open')
-        resolve(true);
-        win.webContents.send('controller.socket.connect_open', true);
-      });
-
-      // 监听消息事件
-      socket.on('message', (data) => {
-        try {
-          let this_data = JSON.parse(data.toString());
-          console.log(this_data.msg_type);
-          console.log(this_data);
-          if(this_data.msg_type){
-            let channel = 'controller.socket.message_'+this_data.msg_type;
-            if(typeToMessage[this_data.msg_type]){
-              if(typeof typeToMessage[this_data.msg_type] === 'object'){
-
-                typeToMessage[this_data.msg_type].map(item=>{
-                  if(item === 'default'){
-                    win.webContents.send(channel, this_data);
-                  }else{
-                    if(this.app.electron[item]) this.app.electron[item].webContents.send(channel, this_data);
-                  }
-                })
-              }else{
-                if(this.app.electron[typeToMessage[this_data.msg_type]]) this.app.electron[typeToMessage[this_data.msg_type]].webContents.send(channel, this_data);
-              }
-            }else{
-              win.webContents.send(channel, this_data);
-            }
-          }
-        }catch (e){
-          console.log(e)
-        }
-      });
-
-      // 监听连接关闭事件
-      socket.on('close', () => {
-        console.log('socket close');
-        win.webContents.send('controller.socket.disconnect', null);
-        socket = null
-
-      });
-
-      // 监听错误事件
-      socket.on('error', (err) => {
-        console.log('socket error');
-        win.webContents.send('controller.socket.disconnect', null);
-        reject(true);
-
-      });
-
-      console.log('socket end')
+       pySocket.init()
 
     })
 
@@ -100,8 +26,7 @@ class SocketController extends Controller {
    * 发送 ping 消息
    */
   sendPing() {
-    const message = JSON.stringify({ data: 'node', type: 'ping' });
-    this.sendMessage(message);
+    pySocket.sendPing()
   }
 
   /**
@@ -109,23 +34,14 @@ class SocketController extends Controller {
    * @param {string} message - JSON 字符串
    */
   sendMessage(message) {
-    // 检查连接状态
-    console.log(message);
-    console.log(typeof socket);
-    if (socket?.readyState === WebSocket.OPEN) {
-      socket.send(message); // 使用 send() 发送
-    } else {
-    }
+    pySocket.sendMessage(message)
   }
 
   /**
    * 断开连接
    */
   disconnect() {
-    if (socket) {
-      socket.close(); // 使用 close() 方法
-      socket = null;
-    }
+    pySocket.disconnect()
   }
 }
 

+ 4 - 1
electron/controller/utils.js

@@ -7,7 +7,7 @@ const { dialog } = require('electron');
 const fs = require('fs');
 const path = require('path');
 const CoreWindow = require('ee-core/electron/window');
-const { BrowserWindow, Menu } = require('electron');
+const { BrowserWindow, Menu,app } = require('electron');
 
 const { readConfigFile } = require('../utils/config');
 const configDeault = readConfigFile();
@@ -159,6 +159,9 @@ class UtilsController extends Controller {
 
   }
 
+  getUserDir(){
+    return app.getPath('userData');
+  }
   async readFileImageForPath(filePath,maxWidth=1500){
 
     const getMimeType = (fileName)=>{

+ 1 - 1
electron/preload/bridge.js

@@ -7,4 +7,4 @@ const { contextBridge, ipcRenderer } = require('electron')
 
 contextBridge.exposeInMainWorld('electron', {
   ipcRenderer: ipcRenderer,
-})
+})

+ 2 - 1
electron/utils/config.default.json

@@ -4,5 +4,6 @@
   "controlType": "SmartShooter",
   "controlPath": "",
   "digiCamControlPath":"C:\\Program Files (x86)\\digiCamControl",
-  "SmartShooterPath":"C:\\Program Files\\Smart Shooter 5"
+  "SmartShooterPath":"C:\\Program Files\\Smart Shooter 5",
+  "pyapp": "127.0.0.1"
 }

+ 187 - 0
electron/utils/socket.js

@@ -0,0 +1,187 @@
+
+const Log = require('ee-core/log');
+const CoreWindow = require('ee-core/electron/window');
+const WebSocket = require('ws'); // 引入原生 ws 库
+const { readConfigFile } = require('./config');
+const pyapp = readConfigFile().pyapp
+const {  app} = require('electron');
+const path = require('path');
+const fs = require('fs');
+
+const typeToMessage = {
+  run_mcu_single:['seeting','default'],
+  get_deviation_data:"developer",
+  set_deviation:"developer",
+  get_mcu_other_info:"developer",
+  set_mcu_other_info:"developer",
+  send_command:"developer"
+}
+
+
+const previewPath = path.join(app.getPath("userData"),'preview','liveview.png');
+
+// 确保目录存在的函数
+function ensureDirectoryExistence(filePath) {
+  const dir = path.dirname(filePath);
+  if (fs.existsSync(dir)) {
+    return true;
+  }
+  ensureDirectoryExistence(path.dirname(dir));
+  fs.mkdirSync(dir);
+}
+
+function livePreview(data){
+  if(data.msg === '预览数据发送' && data.code === 1){
+
+    ensureDirectoryExistence(previewPath);
+    const tempFilePath = `${previewPath}.tmp`;
+
+    fs.writeFile(tempFilePath, data.data.smart_shooter_preview, 'base64', (err) => {
+      if (err) {
+        console.error('写入临时文件失败:', err);
+      } else {
+        fs.rename(tempFilePath, previewPath, (renameErr) => {
+          if (renameErr) {
+            console.error('重命名文件失败:', renameErr);
+          } else {
+            console.log(`文件已成功写入到 preview.png`);
+          }
+        });
+      }
+    });
+
+ }
+
+}
+
+const pySocket = function () {
+
+  this.init = async function () {
+    await new Promise(async (resolve,reject) => {
+
+      const win = CoreWindow.getMainWindow()
+      if(app.socket){
+        resolve(true);
+        win.webContents.send('controller.socket.connect_open', true);
+        return;
+      }
+
+      app.socket = new WebSocket('ws://'+pyapp+':7074/ws');
+
+      // 监听连接成功事件
+      app.socket.on('open', () => {
+        console.log('socket open')
+        resolve(true);
+        win.webContents.send('controller.socket.connect_open', true);
+      });
+
+      // 监听消息事件
+      app.socket.on('message', (data) => {
+        try {
+          console.log('socket.on.message11111111111111111111111');
+
+          let this_data = JSON.parse(data.toString());
+
+          if(this_data.msg_type){
+
+            switch (this_data.msg_type){
+              case 'smart_shooter_enable_preview':
+                livePreview(this_data);
+                break;
+            }
+            let channel = 'controller.socket.message_'+this_data.msg_type;
+            if(typeToMessage[this_data.msg_type]){
+              if(typeof typeToMessage[this_data.msg_type] === 'object'){
+
+                typeToMessage[this_data.msg_type].map(item=>{
+                  if(item === 'default'){
+                    win.webContents.send(channel, this_data);
+                  }else{
+                    if(this.app.electron[item]) this.app.electron[item].webContents.send(channel, this_data);
+                  }
+                })
+              }else{
+                if(this.app.electron[typeToMessage[this_data.msg_type]]) this.app.electron[typeToMessage[this_data.msg_type]].webContents.send(channel, this_data);
+              }
+            }else{
+              win.webContents.send(channel, this_data);
+            }
+          }
+        }catch (e){
+          console.log(e)
+        }
+      });
+
+      // 监听连接关闭事件
+      app.socket.on('close', () => {
+        console.log('socket close');
+        win.webContents.send('controller.socket.disconnect', null);
+        app.socket = null
+
+      });
+
+      // 监听错误事件
+      app.socket.on('error', (err) => {
+        console.log('socket error');
+        win.webContents.send('controller.socket.disconnect', null);
+        reject(true);
+
+      });
+
+
+    })
+
+  }
+  this.sendPing = function () {
+    const message = JSON.stringify({ data: 'node', type: 'ping' });
+    this.sendMessage(message);
+  }
+  this.sendMessage = async function (message) {
+    console.log('socket.=========================sendMessage');
+    console.log('socket.sendMessage');
+    console.log(message);
+    console.log(app.socket?.readyState);
+    if(!app.socket){
+      await  this.init()
+    }
+    // 检查连接状态
+    if (app.socket?.readyState === WebSocket.OPEN) {
+      console.log('send');
+      app.socket.send(message); // 使用 send() 发送
+    }
+  }
+
+  this.disconnect = function () {
+    if (app.socket) {
+      app.socket.close(); // 使用 close() 方法
+      app.socket = null;
+    }
+  }
+  this.onSocketMessage = async function (message_type,callback) {  // 监听消息事件
+    return new Promise(async (resolve,reject) => {
+      app.socket.on('message', onSocketMessage);
+      async function onSocketMessage(data){
+          try {
+            let this_data = JSON.parse(data.toString());
+
+            console.log('socket.on.message2222222222222222222222222');
+            console.log(this_data.msg_type);
+            console.log(message_type);
+            console.log(this_data);
+            if(this_data.msg_type === message_type){
+              app.socket.off('message', onSocketMessage);
+              callback(this_data)
+              resolve()
+            }
+          }catch (e){
+            Log.error(e)
+            reject(e)
+          }
+      }
+    })
+  }
+  return this;
+}
+
+
+module.exports = pySocket;

+ 0 - 6
frontend/src/stores/modules/check.ts

@@ -110,13 +110,7 @@ export const checkInfo = defineStore('checkInfo', () => {
 
               clientStore.ipc.removeAllListeners(icpList.camera.connect);
               clientStore.ipc.send(icpList.camera.connect,configInfoStore.digiCamControlPath);
-              clientStore.ipc.on(icpList.camera.digiCamControlPath, async (event, result) => {
-                clientStore.ipc.removeAllListeners(icpList.camera.digiCamControlPath);
-                if(result.code === 0 && result.data){
-                    configInfoStore.updateDigiCamControlPath(result.data)
-                }
 
-              })
               clientStore.ipc.on(icpList.camera.connect, async (event, result) => {
 
 

+ 15 - 1
frontend/src/stores/modules/config.ts

@@ -1,13 +1,26 @@
 import { defineStore } from 'pinia';
 import { ref, computed } from 'vue';
+import client from "./client";
+import icpList from "../../utils/ipc";
 
+const clientStore = client();
 
 export const configInfo = defineStore('config',()=>{
+  //作废了
   const digiCamControlPath = ref("C:\\Program Files (x86)\\digiCamControl")
   const updateDigiCamControlPath = (data:string)=>{
     digiCamControlPath.value = data
   }
 
+  const userDataPath = ref("")
+
+
+  clientStore.ipc.send(icpList.utils.getUserDir);
+  clientStore.ipc.on(icpList.utils.getUserDir, async (event, result) => {
+    userDataPath.value = result;
+
+  })
+
   //  1 为拍照并处理图像 2 为仅处理图像
   const appModel = ref(1)
   const updateAppModel = (data:number)=>{
@@ -17,7 +30,8 @@ export const configInfo = defineStore('config',()=>{
     digiCamControlPath,
     updateDigiCamControlPath,
     appModel,
-    updateAppModel
+    updateAppModel,
+    userDataPath,
   }
 },{
   persist:true,

+ 1 - 0
frontend/src/utils/ipc.ts

@@ -19,6 +19,7 @@ const icpList = {
         shellFun: 'controller.utils.shellFun',
         openDirectory:"controller.utils.openDirectory",
         openImage:"controller.utils.openImage",
+        getUserDir:"controller.utils.getUserDir",
         openFile:"controller.utils.openFile"
     },
     setting:{

+ 5 - 3
frontend/src/views/Photography/check.vue

@@ -120,7 +120,9 @@ import { digiCamControlWEB } from  '@/utils/appconfig'
 import { getFilePath } from '@/utils/appfun'
 import {ElMessage} from "element-plus";
 const previewKey = ref(0)
-const preview = ref(digiCamControlWEB+'liveview.jpg')
+//const preview = ref(digiCamControlWEB+'liveview.jpg')
+
+const preview = ref('C:\\Users\\Administrator\\AppData\\Roaming\\ZhiHuiYin\\preview\\liveview.png')
 
 const previewSrc = computed(()=>{
   let time = new Date().getTime()
@@ -159,7 +161,7 @@ function showVideo(){
       setTimeout(()=>{
         interval = setInterval(()=>{
           previewKey.value++;
-        },200)
+        },1000)
       },2000)
 
     })
@@ -251,7 +253,7 @@ clientStore.ipc.on(icpList.socket.message+'_run_mcu_single', async (event, resul
 
 })
 onMounted(()=>{
-  showVideo()
+ // showVideo()
 })
 
 /**