|
@@ -0,0 +1,181 @@
|
|
|
|
+// src/stores/websocket.ts
|
|
|
|
+import { defineStore } from 'pinia'
|
|
|
|
+import { ref } from 'vue'
|
|
|
|
+import { $root as protobuf } from '@/common/proto/proto'
|
|
|
|
+import * as Constant from '@/common/constant/Constant'
|
|
|
|
+
|
|
|
|
+// MessageType = $root.lookupType("protocol.Message");
|
|
|
|
+
|
|
|
|
+export const useWebSocketStore = defineStore('webSocketStore', () => {
|
|
|
|
+ const socket = ref(null) // 创建WebSocket对象
|
|
|
|
+ const peer = ref(null) // 创建RTCPeerConnection对象
|
|
|
|
+ const lockConnection = ref(false)
|
|
|
|
+ const reconnectAttempts = ref(0)
|
|
|
|
+ const maxReconnectAttempts = 5
|
|
|
|
+ const reconnectInterval = 3000
|
|
|
|
+
|
|
|
|
+ // 心跳检测
|
|
|
|
+ const heartCheck = {
|
|
|
|
+ timeout: 10000,
|
|
|
|
+ timeoutObj: null,
|
|
|
|
+ serverTimeoutObj: null,
|
|
|
|
+ num: 3,
|
|
|
|
+ start: function () {
|
|
|
|
+ const self = this
|
|
|
|
+ const _num = this.num
|
|
|
|
+
|
|
|
|
+ this.timeoutObj && clearTimeout(this.timeoutObj)
|
|
|
|
+ this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj)
|
|
|
|
+
|
|
|
|
+ this.timeoutObj = setTimeout(() => {
|
|
|
|
+ if (socket.value?.readyState === 1) {
|
|
|
|
+ const data = {
|
|
|
|
+ type: "heatbeat",
|
|
|
|
+ content: "ping",
|
|
|
|
+ }
|
|
|
|
+ const message = protobuf.lookup("protocol.Message")
|
|
|
|
+ const messagePB = message.create(data)
|
|
|
|
+ socket.value.send(message.encode(messagePB).finish())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.serverTimeoutObj = setTimeout(() => {
|
|
|
|
+ _num--
|
|
|
|
+ if (_num <= 0) {
|
|
|
|
+ console.log("the ping num is more then 3, close socket!")
|
|
|
|
+ socket.value?.close()
|
|
|
|
+ }
|
|
|
|
+ }, self.timeout)
|
|
|
|
+ }, this.timeout)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 连接WebSocket
|
|
|
|
+ const connect = (userUuid) => {
|
|
|
|
+ console.log("开始连接...")
|
|
|
|
+ peer.value = new RTCPeerConnection()
|
|
|
|
+ socket.value = new WebSocket(`ws://192.168.0.59:8888/api/v1/socket.io?user=${userUuid}`)
|
|
|
|
+
|
|
|
|
+ socket.value.onopen = () => {
|
|
|
|
+ heartCheck.start()
|
|
|
|
+ console.log("链接")
|
|
|
|
+ webrtcConnection()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ socket.value.onmessage = (event) => {
|
|
|
|
+ heartCheck.start()
|
|
|
|
+ handleMessage(event.data)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ socket.value.onclose = () => {
|
|
|
|
+ console.log("关闭并重新连接-->--->")
|
|
|
|
+ reconnect()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ socket.value.onerror = () => {
|
|
|
|
+ console.log("error----->>>>")
|
|
|
|
+ reconnect()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 处理接收到的消息
|
|
|
|
+ const handleMessage = (data) => {
|
|
|
|
+ const messageProto = protobuf.lookupType("protocol.Message")
|
|
|
|
+ const reader = new FileReader()
|
|
|
|
+
|
|
|
|
+ reader.readAsArrayBuffer(data)
|
|
|
|
+ reader.onload = (event) => {
|
|
|
|
+ const messagePB = messageProto.decode(new Uint8Array(event.target?.result))
|
|
|
|
+ // 单独解码
|
|
|
|
+ console.log(messagePB)
|
|
|
|
+
|
|
|
|
+ if (messagePB.type === "heatbeat") return
|
|
|
|
+
|
|
|
|
+ if (messagePB.type === Constant.MESSAGE_TRANS_TYPE) {
|
|
|
|
+ dealWebRtcMessage(messagePB)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 其他消息处理...
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // WebRTC 连接
|
|
|
|
+ const webrtcConnection = () => {
|
|
|
|
+ if (!peer.value) return
|
|
|
|
+
|
|
|
|
+ peer.value.onicecandidate = (e) => {
|
|
|
|
+ if (e.candidate && socket.value) {
|
|
|
|
+ const candidate = {
|
|
|
|
+ type: 'answer_ice',
|
|
|
|
+ iceCandidate: e.candidate
|
|
|
|
+ }
|
|
|
|
+ const message = {
|
|
|
|
+ content: JSON.stringify(candidate),
|
|
|
|
+ type: Constant.MESSAGE_TRANS_TYPE,
|
|
|
|
+ }
|
|
|
|
+ sendMessage(message)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ peer.value.ontrack = (e) => {
|
|
|
|
+ if (e && e.streams) {
|
|
|
|
+ const remoteVideo = document.getElementById("remoteVideoReceiver")
|
|
|
|
+ const remoteAudio = document.getElementById("audioPhone")
|
|
|
|
+
|
|
|
|
+ if (remoteVideo) remoteVideo.srcObject = e.streams[0]
|
|
|
|
+ if (remoteAudio) remoteAudio.srcObject = e.streams[0]
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 处理WebRTC消息
|
|
|
|
+ const dealWebRtcMessage = (messagePB) => {
|
|
|
|
+ // 实现与React版本相同的逻辑
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 重新连接
|
|
|
|
+ const reconnect = () => {
|
|
|
|
+ if (lockConnection.value) return
|
|
|
|
+ lockConnection.value = true
|
|
|
|
+
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ if (socket.value?.readyState !== 1) {
|
|
|
|
+ connect(localStorage.uuid)
|
|
|
|
+ }
|
|
|
|
+ lockConnection.value = false
|
|
|
|
+ }, 10000)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 发送消息
|
|
|
|
+ const sendMessage = (messageData) => {
|
|
|
|
+ if (!socket.value) return
|
|
|
|
+
|
|
|
|
+ const data = {
|
|
|
|
+ ...messageData,
|
|
|
|
+ fromUsername: localStorage.username,
|
|
|
|
+ from: localStorage.uuid,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const message = protobuf.lookup("protocol.Message")
|
|
|
|
+ const messagePB = message.create(data)
|
|
|
|
+ socket.value.send(message.encode(messagePB).finish())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 关闭连接
|
|
|
|
+ const close = () => {
|
|
|
|
+ socket.value?.close()
|
|
|
|
+ peer.value?.close()
|
|
|
|
+ socket.value = null
|
|
|
|
+ peer.value = null
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ socket,
|
|
|
|
+ peer,
|
|
|
|
+ connect,
|
|
|
|
+ sendMessage,
|
|
|
|
+ close,
|
|
|
|
+ dealWebRtcMessage,
|
|
|
|
+ webrtcConnection
|
|
|
|
+ }
|
|
|
|
+})
|