Caner 2 years ago
parent
commit
b6b620b8fe
3 changed files with 166 additions and 131 deletions
  1. 36 2
      electron/main.js
  2. 1 0
      package.json
  3. 129 129
      src/App.vue

+ 36 - 2
electron/main.js

@@ -2,8 +2,11 @@ const { app, BrowserWindow, Menu, ipcMain, globalShortcut, dialog, screen, Tray
 const { join } = require('path');
 const { join } = require('path');
 const { fork } = require('child_process');
 const { fork } = require('child_process');
 const { platform } = require('process');
 const { platform } = require('process');
+const mqtt = require('mqtt')
+const client = mqtt.connect('mqtt://127.0.0.1:49800', { manualConnect: true })
 const sleep = (ms) => new Promise(res => setTimeout(res, ms));
 const sleep = (ms) => new Promise(res => setTimeout(res, ms));
 class MainSerivce {
 class MainSerivce {
+  #mqttChannel = ''
   constructor() {
   constructor() {
     Menu.setApplicationMenu(null) // 去掉菜单栏
     Menu.setApplicationMenu(null) // 去掉菜单栏
     app.commandLine.appendSwitch('wm-window-animations-disabled') // 拖动闪屏
     app.commandLine.appendSwitch('wm-window-animations-disabled') // 拖动闪屏
@@ -114,10 +117,11 @@ class MainSerivce {
       if (evt === 'close-loading') {
       if (evt === 'close-loading') {
         if (this.loadingWin) this.loadingWin.close()
         if (this.loadingWin) this.loadingWin.close()
         this.mainWin.show()
         this.mainWin.show()
-        if (this.mainWin.isVisible()) this.connectLogi()
+        // if (this.mainWin.isVisible()) this.connectLogi()
       } else if (evt === 'minWin') {
       } else if (evt === 'minWin') {
         this.mainWin.minimize()
         this.mainWin.minimize()
       } else if (evt === 'closeWin') {
       } else if (evt === 'closeWin') {
+        client.end()
         this.mainWin.close()
         this.mainWin.close()
       } else if (evt === 'maxWin') {
       } else if (evt === 'maxWin') {
         const { width, height } = screen.getPrimaryDisplay().size
         const { width, height } = screen.getPrimaryDisplay().size
@@ -125,8 +129,38 @@ class MainSerivce {
           this.mainWin.setBounds({ width: 1300, height: 760 })
           this.mainWin.setBounds({ width: 1300, height: 760 })
           this.mainWin.center()
           this.mainWin.center()
         }
         }
+      } else if (evt === 'loginMqtt') {
+        client.options.username = data.room
+        client.options.password = data.name
+        client.connect()
+      } else if (evt === 'closeMqtt') {
+        client.end()
+      } else if (evt === 'sendMqtt') {
+        try {
+          const db = JSON.stringify(data)
+          if (client.connected && this.#mqttChannel) client.publish(this.#mqttChannel, db)
+        } catch (error) {
+          console.log(error);
+        }
       }
       }
     })
     })
+
+    // 监听
+    client.on('connect', () => this.mainWin.webContents.send('message', { type: 'connect' }))
+    client.on('message', (_, msg, __) => {
+      try {
+        const db = JSON.parse(msg.toString())
+        if (db.type === 'join') this.#mqttChannel = db.channel
+        this.mainWin.webContents.send('message', db)
+      } catch (error) {
+        console.log(error);
+      }
+    })
+    client.on('error', (e) => {
+      this.#mqttChannel = ''
+      this.mainWin.webContents.send('message', { type: 'disconnect' })
+      client.end(true)
+    })
   }
   }
 
 
   connectLogi() {
   connectLogi() {
@@ -143,7 +177,7 @@ class MainSerivce {
           }
           }
         })
         })
       } else {
       } else {
-        if (this.mainWin && !this.mainWin.isDestroyed() && this.contrlEvent) this.mainWin?.webContents.send('contrlData', msg.data)
+        if (this.mainWin && !this.mainWin.isDestroyed() && this.contrlEvent) this.mainWin?.webContents.send('message', { type: 'contrl', content: msg.data })
       }
       }
     })
     })
   }
   }

+ 1 - 0
package.json

@@ -10,6 +10,7 @@
     "build": "vue-tsc --noEmit ; vite build ; electron-builder build"
     "build": "vue-tsc --noEmit ; vite build ; electron-builder build"
   },
   },
   "dependencies": {
   "dependencies": {
+    "mqtt": "^5.0.2",
     "node-hid": "^2.1.2"
     "node-hid": "^2.1.2"
   },
   },
   "devDependencies": {
   "devDependencies": {

+ 129 - 129
src/App.vue

@@ -1,8 +1,5 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import { Socket, io } from 'socket.io-client'
-import {
-  onMounted, onUnmounted, ref, watch
-} from 'vue'
+import { onUnmounted, ref, watch } from 'vue'
 import Login from '@/components/login.vue'
 import Login from '@/components/login.vue'
 import Gauge from '@/components/gauge.vue'
 import Gauge from '@/components/gauge.vue'
 import Record from '@/components/record.vue'
 import Record from '@/components/record.vue'
@@ -10,7 +7,6 @@ import Battery from '@/components/battery.vue'
 import Loading from '@/components/loading.vue'
 import Loading from '@/components/loading.vue'
 
 
 const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms))
 const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms))
-const HOST = 'wss://car.caner.top'
 const iceServers = [
 const iceServers = [
   {
   {
     urls: [ 'stun:caner.top:3478' ]
     urls: [ 'stun:caner.top:3478' ]
@@ -21,7 +17,6 @@ const iceServers = [
     credential: '123456'
     credential: '123456'
   }
   }
 ]
 ]
-const socket = ref(null as null | Socket)
 const Peer = ref(null as null | RTCPeerConnection | undefined)
 const Peer = ref(null as null | RTCPeerConnection | undefined)
 const isLogin = ref(false)
 const isLogin = ref(false)
 const remoteVideo = ref()
 const remoteVideo = ref()
@@ -44,159 +39,166 @@ const SpeedValue = ref(0)
 // 方向盘数据
 // 方向盘数据
 function onContrlData() {
 function onContrlData() {
   if (showLoading.value) return
   if (showLoading.value) return
-  socket.value?.emit('msg', { type: 'conctrl', conctrl: { ...conctrlData.value } })
+  window.$electron.send('sendMqtt', { type: 'conctrl', conctrl: { ...conctrlData.value } })
   conctrlAnimation.value = requestAnimationFrame(onContrlData)
   conctrlAnimation.value = requestAnimationFrame(onContrlData)
 }
 }
 
 
-// 档位计算
-function countContrlData(v: number) {
-  // 转10进制
-  const num = parseInt(v.toString(), 10)
-  if (conctrlNum.value % 2) {
-    // 倒档
-    return Math.floor(num / 2)
-  }
-  // 前进
-  return Math.floor(((128 - (num / 2)) + 128))
-}
-
 // 关闭
 // 关闭
 function close(err?: string) {
 function close(err?: string) {
   if (Peer.value) Peer.value?.close()
   if (Peer.value) Peer.value?.close()
   if (remoteVideo.value) remoteVideo.value.srcObject = null
   if (remoteVideo.value) remoteVideo.value.srcObject = null
-  if (socket.value) socket.value.disconnect()
   isLogin.value = false
   isLogin.value = false
   showLoading.value = false
   showLoading.value = false
   error.value = err || ''
   error.value = err || ''
-  socket.value = null
   Peer.value = null
   Peer.value = null
   audioStateNum.value = 0
   audioStateNum.value = 0
   quantity.value = 0
   quantity.value = 0
   cancelAnimationFrame(conctrlAnimation.value)
   cancelAnimationFrame(conctrlAnimation.value)
+  console.log('退出')
 }
 }
 
 
-// init socket
-function intSoketRtc(host: string) {
-  showLoading.value = true
-  // int socket
-  socket.value = io(host, {
-    autoConnect: false,
-    transports: [ 'websocket' ]
-  })
+// 初始化rtc
+function initRTC() {
+  try {
+    Peer.value = new RTCPeerConnection({
+      iceServers,
+      bundlePolicy: 'max-bundle'
+    })
 
 
-  // socket
-  socket.value.on('connect', () => {
-    try {
-      isLogin.value = true
-      // init webrtc
-      Peer.value = new RTCPeerConnection({
-        iceServers,
-        bundlePolicy: 'max-bundle'
-      })
-
-      // listen state
-      Peer.value.onicegatheringstatechange = () => {
-        console.log('GatheringState: ', Peer.value?.iceGatheringState)
-        if (Peer.value?.iceGatheringState === 'complete') {
-          const answer = Peer.value.localDescription
-          socket.value?.emit('msg', answer)
-        }
-      }
-
-      // listen track
-      Peer.value.ontrack = async (evt) => {
-        console.log('track', evt)
-        remoteVideo.value.srcObject = evt.streams[0]
+    // listen state
+    Peer.value.onicegatheringstatechange = () => {
+      console.log('GatheringState: ', Peer.value?.iceGatheringState)
+      if (Peer.value?.iceGatheringState === 'complete') {
+        const answer = Peer.value.localDescription
+        window.$electron.send('sendMqtt', answer)
       }
       }
+    }
 
 
-      // listen changestate·
-      Peer.value.oniceconnectionstatechange = async () => {
-        const state = Peer.value?.iceConnectionState
-        console.log('ICE状态', state)
-        if (
-          state === 'failed'
-          || state === 'disconnected'
-          || state === 'closed'
-        ) {
-          close('P2P通信失败')
-        }
+    // listen track
+    Peer.value.ontrack = async (evt) => {
+      console.log('track', evt)
+      remoteVideo.value.srcObject = evt.streams[0]
+    }
 
 
-        // ICE连接成功
-        if (state === 'connected') {
-          await sleep(3000)
-          showLoading.value = false
-          onContrlData()
-        }
+    // listen changestate·
+    Peer.value.oniceconnectionstatechange = async () => {
+      const state = Peer.value?.iceConnectionState
+      console.log('ICE状态', state)
+      if (
+        state === 'failed'
+        || state === 'disconnected'
+        || state === 'closed'
+      ) {
+        close('P2P通信失败')
       }
       }
-    } catch (error) {
-      close('webrtc初始化失败')
-    }
-  })
 
 
-  socket.value.on('msg', async (data) => {
-    const key = data.type
-    if (key === 'offer') {
-      await Peer.value?.setRemoteDescription(data)
-      const answer = await Peer.value?.createAnswer()
-      await Peer.value?.setLocalDescription(answer)
-    } else if (key === 'power') {
-      quantity.value = data.power
-    } else if (key === 'speed') {
-      const d = Math.floor(data.data)
-      SpeedValue.value = d
+      // ICE连接成功
+      if (state === 'connected') {
+        await sleep(3000)
+        showLoading.value = false
+        onContrlData()
+      }
     }
     }
-  })
+    console.log('rtc 初始化成功')
+  } catch (error) {
+    close('webrtc初始化失败')
+  }
+}
 
 
-  socket.value.on('joined', async () => socket.value?.emit('msg', { type: 'startRTC' }))
+// 登录
+async function login(data: { name: string, roomID: string }) {
+  window.$electron.send('loginMqtt', { room: data.roomID, name: data.name })
+}
 
 
-  socket.value.on('leaved', () => close('车端断开'))
+// 档位计算
+function countContrlData(v: number) {
+  // 转10进制
+  const num = parseInt(v.toString(), 10)
+  if (conctrlNum.value % 2) {
+    // 倒档
+    return Math.floor(num / 2)
+  }
+  // 前进
+  return Math.floor(((128 - (num / 2)) + 128))
+}
 
 
-  socket.value.on('connect_error', () => close('服务器连接失败'))
+// 发送语音
+function sendAudio(blob: Blob) {
+  window.$electron.send('sendMqtt', { type: 'Meadia', Meadia: blob })
 }
 }
 
 
-// 遥控数据
-window.$electron?.on('contrlData', (db: Uint8Array) => {
-  // 倒档 | 前进 =>右拨片
-  conctrlGrears.value = db[6] === 2
-  // 鸣笛 =>回车
-  warnAudio.value = !!db[54]
-  // 录音 =>左拨片
-  micState.value = db[6] === 1
-  // 静音 =>L3
-  audioState.value = db[6] === 64
-  // 控制
-  conctrlData.value = {
-    v0: 128,
-    v1: 128,
-    v2: parseInt(db[44].toString(), 10), // 方向盘
-    v3: countContrlData(db[46]) // 油门
+// mqtt
+window.$electron.on('message', async (msg: any) => {
+  switch (msg.type) {
+    case 'connect':
+      console.log('连接成功')
+      isLogin.value = true
+      showLoading.value = true
+      break
+    case 'disconnect':
+      close('服务器连接失败')
+      break
+    case 'join':
+      window.$electron.send('sendMqtt', { type: 'startRTC' })
+      console.log('开始rtc')
+
+      initRTC()
+      break
+    case 'leave':
+      close('对方断开连接')
+
+      break
+    case 'offer':
+      {
+        await Peer.value?.setRemoteDescription(msg)
+        const answerd = await Peer.value?.createAnswer()
+        await Peer.value?.setLocalDescription(answerd)
+      }
+      break
+    case 'power':
+      quantity.value = msg.power
+      console.log('电量')
+
+      break
+    case 'speed':
+      SpeedValue.value = Math.floor(msg.data)
+      console.log('速度')
+
+      break
+    case 'contrl':
+      {
+        const db = msg.content
+        // 倒档 | 前进 =>右拨片
+        conctrlGrears.value = db[6] === 2
+        // 鸣笛 =>回车
+        warnAudio.value = !!db[54]
+        // 录音 =>左拨片
+        micState.value = db[6] === 1
+        // 静音 =>L3
+        audioState.value = db[6] === 64
+        // 控制
+        conctrlData.value = {
+          v0: 128,
+          v1: 128,
+          v2: parseInt(db[44].toString(), 10), // 方向盘
+          v3: countContrlData(db[46]) // 油门
+        }
+      }
+      console.log('遥控数据', conctrlData.value)
+      break
+    default:
+      break
   }
   }
-  console.log(6, conctrlData.value)
 })
 })
 
 
 // 窗口事件
 // 窗口事件
 function titleEvent(type: string) {
 function titleEvent(type: string) {
   if (type === 'maxWin') winMaxOrMin.value = !winMaxOrMin.value
   if (type === 'maxWin') winMaxOrMin.value = !winMaxOrMin.value
-  if (type === 'loginOut') { close(); return }
-  window.$electron?.send(type, winMaxOrMin.value)
-}
-
-// 发送语音
-function sendAudio(blob: Blob) {
-  socket.value?.emit('msg', {
-    type: 'Meadia',
-    Meadia: blob
-  })
-}
-
-// 登录
-async function login(data: { name: string, roomID: string }) {
-  if (!socket.value) intSoketRtc(HOST)
-  socket.value!.auth = {
-    roomID: data.roomID,
-    name: data.name
+  if (type === 'loginOut') {
+    close()
+  } else {
+    window.$electron?.send(type, winMaxOrMin.value)
   }
   }
-  socket.value?.connect()
 }
 }
 
 
 // 监听按钮状态
 // 监听按钮状态
@@ -204,21 +206,19 @@ watch([ audioState, warnAudio, conctrlGrears ], () => {
   if (showLoading.value) return
   if (showLoading.value) return
   if (audioState.value) {
   if (audioState.value) {
     audioStateNum.value++
     audioStateNum.value++
-    socket.value?.emit('msg', { type: 'contrlAudio', contrlAudio: !!(audioStateNum.value % 2) })
+    window.$electron.send('sendMqtt', { type: 'contrlAudio', contrlAudio: !!(audioStateNum.value % 2) })
   }
   }
   if (conctrlGrears.value) {
   if (conctrlGrears.value) {
     conctrlNum.value++
     conctrlNum.value++
   }
   }
-  if (warnAudio.value) socket.value?.emit('msg', { type: 'warnAudio' })
+  if (warnAudio.value) window.$electron.send('sendMqtt', { type: 'warnAudio', contrlAudio: !!(audioStateNum.value % 2) })
 })
 })
 
 
-// 初始化
-onMounted(() => intSoketRtc(HOST))
 onUnmounted(() => close())
 onUnmounted(() => close())
 
 
 // 关闭loadingwin
 // 关闭loadingwin
 window.$electron.send('close-loading')
 window.$electron.send('close-loading')
-</script>·
+</script>
 <template>
 <template>
   <template v-if="isLogin">
   <template v-if="isLogin">
     <video
     <video