diff --git a/main.js b/main.js index bfb93c9..aae070a 100644 --- a/main.js +++ b/main.js @@ -14,6 +14,7 @@ const path = require('node:path') const fs = require('fs'); const Registry = require('winreg'); const { autoUpdater, CancellationToken } = require('electron-updater'); +const signalR = require('@microsoft/signalr'); const cancellationToken = new CancellationToken() app.allowRendererProcessReuse = false; let mainWindow = null; @@ -21,6 +22,7 @@ let childWindow = {} let isMaximized = false; let env; let regKey; +let connection = null; class AppWindow extends BrowserWindow { constructor(config) { @@ -142,6 +144,218 @@ app.on('ready', () => { isMaximized = true; } }); + // socket + ipcMain.handle('startSignalr', (event, user) => { + startSignalr(user) + }); + ipcMain.handle('offSignalr', (event) => { + if (connection) { + connection.off('ReceiveMessage'); + connection.off('Operation'); + connection.off('ForceExitRoom'); + connection.off('AllLeave'); + connection.off('ShowUser'); + connection.off('RefreshView'); + connection.off('UserJoined'); + connection.off('UserLeave'); + connection.off('OperAllMicr'); + connection.off('OperMicr'); + connection.off('OperCamera'); + connection.off('ManagerRefresh'); + connection.off('ApplyToSpeak'); + connection.off('Watch'); + connection.off('DriverList'); + connection.off('SetDriver'); + connection.off('ShowDriverList'); + } + }); + ipcMain.handle('onStop', (event) => { + if (connection) { + storage.setItem('isSignalr', false) + connection.off('Invitation'); + connection.off('ForceLogout'); + connection.stop() + connection = "" + } + }); + ipcMain.handle('onInvoke', async (event, str, data) => { + switch (str) { + case 'sendChannelMsg': + await connection.invoke(str, data.roomNum, data.msg) + break; + case 'sendOper': + // 4:屏幕共享 + await connection.invoke(str, data.roomNum, data.type) + break; + case 'getDrivers': + // 获取某个人的设备列表 + await connection.invoke(str, data.uid) + break; + case 'sendDrivers': + // 发送设备列表给某个人 + await connection.invoke(str, data.uid, data.driversJsonString) + break; + case 'setDrivers': + // 设置某个人的设备列表 + await connection.invoke(str, data.uid, data.driversJsonString) + break; + case 'joinChannel': + // 设置某个人的设备列表 + await connection.invoke(str, data.roomNum, data.enableMicr, data.enableCamera) + break; + case 'levelChannel': + // 设置某个人的设备列表 + await connection.invoke(str, data.roomNum) + break; + } + }); + ipcMain.handle('onOtherSignalr', (event) => { + if (connection) { + // 邀请 + connection.on("Invitation", (roomNum, roomName, InviterName) => { + mainWindow.webContents.send('onOtherSignalr', { + key: 'Invitation', + roomNum, roomName, InviterName + }); + }); + // 退出 + connection.on("ForceLogout", (msg) => { + mainWindow.webContents.send('onOtherSignalr', { + key: 'ForceLogout', + msg + }); + }); + } + }); + ipcMain.handle('onSignalr', (event) => { + if (connection) { + // 聊天 + connection.on("ReceiveMessage", (uid, userName, message, timestamp) => { + mainWindow.webContents.send('onSignalr', { + key: 'ReceiveMessage', + uid, message, userName, timestamp + }) + }); + // 扩展操作 + connection.on("Operation", (type) => { + mainWindow.webContents.send('onSignalr', { + key: 'Operation', + type + }) + }); + // 移出会议 + connection.on("ForceExitRoom", () => { + mainWindow.webContents.send('onSignalr', { + key: 'ForceExitRoom', + }) + }); + // 全员离开房间 + connection.on("AllLeave", () => { + mainWindow.webContents.send('onSignalr', { + key: 'AllLeave', + }) + }); + // 全员看他 + connection.on("ShowUser", (uid, uname, operUid, operUserName) => { + mainWindow.webContents.send('onSignalr', { + key: 'ShowUser', + uid, + uname, + operUid, + operUserName, + }) + }); + // 更新视图模式 + connection.on("RefreshView", (type) => { + mainWindow.webContents.send('onSignalr', { + key: 'RefreshView', + type + }) + }); + // 用户加入频道回调 + connection.on("UserJoined", (user) => { + mainWindow.webContents.send('onSignalr', { + key: 'UserJoined', + user, + }) + }); + // 用户退出频道回调 + connection.on("UserLeave", (uid,) => { + mainWindow.webContents.send('onSignalr', { + key: 'UserLeave', + uid, + }) + }); + // 所有用户开闭麦 + connection.on("OperAllMicr", (enableMicr, uid) => { + mainWindow.webContents.send('onSignalr', { + key: 'OperAllMicr', + enableMicr, + uid + }) + }); + // 用户关闭开启麦克风 + connection.on("OperMicr", (user, operUid) => { + mainWindow.webContents.send('onSignalr', { + key: 'OperMicr', + user, + operUid + }) + }); + // 用户开启关闭摄像头 + connection.on("OperCamera", (user, operUid) => { + mainWindow.webContents.send('onSignalr', { + key: 'OperCamera', + user, + operUid + }) + }); + // 发言人用户信息刷新 + connection.on("ManagerRefresh", (user, uid) => { + mainWindow.webContents.send('onSignalr', { + key: 'ManagerRefresh', + user, + uid + }) + }); + // 申请发言 + connection.on("ApplyToSpeak", (uid, uname) => { + mainWindow.webContents.send('onSignalr', { + key: 'ApplyToSpeak', + uid, + uname + }) + }); + // 管理员查看随机用户 + connection.on("Watch", (watchUids) => { + mainWindow.webContents.send('onSignalr', { + key: 'Watch', + watchUids + }) + }); + // 设备列表 + connection.on("DriverList", (callerUid) => { + mainWindow.webContents.send('onSignalr', { + key: 'DriverList', + callerUid + }) + }); + // 设置设备 + connection.on("SaveDriver", (driver) => { + mainWindow.webContents.send('onSignalr', { + key: 'SaveDriver', + driver + }) + }); + // 显示设备列表 + connection.on("ShowDriverList", (driversJsonString) => { + mainWindow.webContents.send('onSignalr', { + key: 'ShowDriverList', + driversJsonString + }) + }); + } + }); // 放大缩小退出窗口 ipcMain.handle('setViewStatus', async (event, status) => { switch (status) { @@ -493,4 +707,40 @@ function mainWindowCenter() { // 主窗口隐藏 function mainWindowHide() { mainWindow.setPosition(-999999, -999999); +} + +const startSignalr = async (user) => { + connection = new signalR.HubConnectionBuilder().withAutomaticReconnect() + .withUrl(`${env === 'development' ? 'http://192.168.2.9:5192' : 'https://meeting-api.23544.com/pc'}/session-manage`, { + skipNegotiation: true, + transport: signalR.HttpTransportType.WebSockets, + accessTokenFactory: () => user.token + }) + .build(); + onStart() + mainWindow.webContents.send('changeLocalStorage', { + isSignalr: true, + reconnect: true, + }); + connection.onreconnected(async () => { + mainWindow.webContents.send('changeLocalStorage', { + reconnect: true, + }); + }); + connection.onreconnecting(async () => { + onStart() + mainWindow.webContents.send('changeLocalStorage', { + reconnect: false, + }); + }); +} + +const onStart = async () => { + if (connection) { + if (connection.state !== signalR.HubConnectionState.Connected) { + connection.start(); + } else { + setTimeout(onStart, 3000); + } + } } \ No newline at end of file diff --git a/preload.js b/preload.js index 3ebbaa3..b9eda4d 100644 --- a/preload.js +++ b/preload.js @@ -1,6 +1,28 @@ // // 在 preload 脚本中。 const { ipcRenderer } = require('electron') window.electron = { + // socket + startSignalr: (user) => { + ipcRenderer.invoke('startSignalr', user) + }, + offSignalr: () => { + ipcRenderer.invoke('offSignalr') + }, + onStop: () => { + ipcRenderer.invoke('onStop') + }, + onInvoke: (str, data) => { + ipcRenderer.invoke('onInvoke', str, data) + }, + changeLocalStorage: (callback) => { + ipcRenderer.on('changeLocalStorage', callback) + }, + onOtherSignalr: (callback) => { + ipcRenderer.on('onOtherSignalr', callback) + }, + onSignalr: (callback) => { + ipcRenderer.on('onSignalr', callback) + }, // 设置窗口大小 setMainWindowSize: (config) => { ipcRenderer.invoke('setMainWindowSize', { ...config }) diff --git a/src/App.tsx b/src/App.tsx index de62109..0791fa7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,7 +9,6 @@ import Meeting from '@/page/Meeting/index' import NotFound from '@/page/NotFound/index' import { storage } from '@/utils' import { message, Spin } from "antd"; -import { onOtherSignalr, onStop, startSignalr } from "@/utils/package/signalr"; import JoinMeetingModal from "@/components/JoinMeetingModal"; import UpdateModal from "@/components/UpdateModal"; import * as CryptoJS from 'crypto-js'; @@ -54,7 +53,7 @@ const App: React.FC = () => { storage.setItem('user', JSON.stringify(res.data)) storage.setItem('userLogin', true) toSrc('/home') - await startSignalr() + await window.electron.startSignalr(res.data) } else { toSrc('/login') } @@ -121,6 +120,11 @@ const App: React.FC = () => { } } }) + window.electron.changeLocalStorage(async (_e: any, data: any) => { + for (const key in data) { + storage.setItem(key, data[key]) + } + }) }, []) useEffect(() => { window.electron.onUpdate((_e: any, data: any) => { @@ -196,7 +200,7 @@ const App: React.FC = () => { }, [state]) useEffect(() => { if (location.href.indexOf('/login') !== -1) { - onStop() + window.electron.onStop() } }, [navigate]) } @@ -219,7 +223,7 @@ const App: React.FC = () => { }; const onEventSignalr = (): void => { - onOtherSignalr(async (item: any) => { + window.electron.onOtherSignalr(async (_e: any, item: any) => { switch (item.key) { case 'Invitation': window.electron.joinNotification({ diff --git a/src/components/EquipmentManagement/index.tsx b/src/components/EquipmentManagement/index.tsx index 2872586..4f740ee 100644 --- a/src/components/EquipmentManagement/index.tsx +++ b/src/components/EquipmentManagement/index.tsx @@ -1,6 +1,5 @@ import styles from '@/components/EquipmentManagement/index.module.scss' import { getKeyOpenChildWindow } from '@/utils/package/public'; -import { onInvoke } from '@/utils/package/signalr'; import { Button, Modal, Select, Slider, message } from 'antd'; import { useState, useImperativeHandle, forwardRef } from "react"; const EquipmentManagement = forwardRef((props: any, ref: any) => { @@ -12,7 +11,7 @@ const EquipmentManagement = forwardRef((props: any, ref: any) => { if (isOpen) { props.getDriver?.(uid) } else { - await onInvoke('getDrivers', { + await window.electron.onInvoke('getDrivers', { uid }) } @@ -99,7 +98,7 @@ const EquipmentManagement = forwardRef((props: any, ref: any) => { driversJsonString: JSON.stringify(deviceInfo) }) } else { - await onInvoke('setDrivers', { + await window.electron.onInvoke('setDrivers', { uid: callerUid, driversJsonString: JSON.stringify(deviceInfo) }) diff --git a/src/page/Login/index.tsx b/src/page/Login/index.tsx index 20d88fb..6ac5ca2 100644 --- a/src/page/Login/index.tsx +++ b/src/page/Login/index.tsx @@ -7,7 +7,6 @@ import { storage } from '@/utils' import { GetCheckUser, PostAnonLogin, PostLogin } from '@/api/Login' import * as CryptoJS from 'crypto-js'; import ImageUrl from '@/utils/package/imageUrl' -import { startSignalr } from '@/utils/package/signalr'; import { v4 as uuidv4 } from 'uuid'; import { GetCheckoutRoomNum, GetRoomInfo, GetRoomRtcToken } from '@/api/Home/Index'; const Login: React.FC = () => { @@ -164,7 +163,7 @@ const Login: React.FC = () => { height: Math.ceil(res.height / 1.3), }) }) - startSignalr() + window.electron.startSignalr(res.data) navigate('/home') } }) @@ -321,7 +320,7 @@ const Login: React.FC = () => { if (res.code == 200) { storage.setItem('user', JSON.stringify(res.data)) storage.setItem('userLogin', true) - await startSignalr() + await window.electron.startSignalr(res.data) getRoomRtcToken(anonInfo.roomNum, (options: any) => { if (options) { GetRoomInfo(anonInfo.roomNum).then(async (res) => { diff --git a/src/page/Meeting/index.tsx b/src/page/Meeting/index.tsx index 2308c89..64af072 100644 --- a/src/page/Meeting/index.tsx +++ b/src/page/Meeting/index.tsx @@ -11,7 +11,6 @@ import { storage } from '@/utils'; import { GetRoomUser, PostOpenMicr, PostOpenCamera, GetLeaveAll, PostRoomManager, DeleteRoomManager, GetRoomKickout, GetShowUser, PostShowUser, PostMuteAll, GetRoomUserItem, GetApplySpeak } from '@/api/Meeting'; import ImageUrl from '@/utils/package/imageUrl' import { agora } from '@/utils/package/agora' -import { onInvoke, onSignalr, offSignalr } from '@/utils/package/signalr'; import dayjs from 'dayjs'; import durationPlugin from 'dayjs/plugin/duration'; import { AudioVolumeInfo, ConnectionChangedReasonType, ConnectionStateType, LocalVideoStreamReason, LocalVideoStreamState, QualityType, RtcConnection, RtcStats, UserOfflineReasonType, VideoSourceType, VideoStreamType } from 'agora-electron-sdk'; @@ -276,12 +275,12 @@ const Meeting: React.FC = () => { }) break; case 'userListWindowEquipmentManagement': - await onInvoke('getDrivers', { + await window.electron.onInvoke('getDrivers', { uid: userListWindowEquipmentManagement.uid, }) break; case 'userListWindowSetEquipmentManagement': - await onInvoke('setDrivers', { + await window.electron.onInvoke('setDrivers', { uid: userListWindowSetEquipmentManagement.uid, driversJsonString: userListWindowSetEquipmentManagement.driversJsonString }) @@ -534,7 +533,7 @@ const Meeting: React.FC = () => { }, [currentVideoId, isShare]); useEffect(() => { - onSignalr(async (item: any) => { + window.electron.onSignalr(async (item: any) => { const setting = JSON.parse(storage.getItem('setting') as string) switch (item.key) { // 聊天 @@ -789,7 +788,7 @@ const Meeting: React.FC = () => { playBackDeviceId: res[1].ecordingList.find((row: any) => row.deviceId === setting.playBackDeviceId) ? setting.playBackDeviceId : res[1].playBackList.length ? res[1].playBackList[0].deviceId : null, ecordingVolume: res[1].ecordingVolume } - onInvoke('sendDrivers', { + window.electron.onInvoke('sendDrivers', { uid: item.callerUid, driversJsonString: JSON.stringify(data) }) @@ -825,7 +824,7 @@ const Meeting: React.FC = () => { } }) return () => { - offSignalr() + window.electron.offSignalr() } }, []) @@ -1715,7 +1714,7 @@ const Meeting: React.FC = () => { break; case 'reconnect': if (e.value == true) { - await onInvoke('joinChannel', { + await window.electron.onInvoke('joinChannel', { roomNum: state.channelId, enableMicr: !footerList[0][0].active, enableCamera: !footerList[0][1].active @@ -1747,7 +1746,7 @@ const Meeting: React.FC = () => { const sendMsg = (text?: string): void => { let msg = text ? text : textMsg; if (msg) { - onInvoke('sendChannelMsg', { + window.electron.onInvoke('sendChannelMsg', { roomNum: state.channelId, msg: msg, }) @@ -1991,7 +1990,7 @@ const Meeting: React.FC = () => { // enableMicr, // enableCamera // }) - await onInvoke('joinChannel', { + await window.electron.onInvoke('joinChannel', { roomNum: state.channelId, enableMicr, enableCamera @@ -2003,7 +2002,7 @@ const Meeting: React.FC = () => { // await GetLeave({ // roomNum: state.channelId, // }) - await onInvoke('levelChannel', { + await window.electron.onInvoke('levelChannel', { roomNum: state.channelId }) } @@ -2792,7 +2791,7 @@ const Meeting: React.FC = () => { open={isSharePopConfirm} onConfirm={async () => { setIsSharePopConfirm(false) - await onInvoke('sendOper', { + await window.electron.onInvoke('sendOper', { roomNum: state.channelId, type: 4, }) diff --git a/src/render.d.ts b/src/render.d.ts index b4982bc..aa4f3ef 100644 --- a/src/render.d.ts +++ b/src/render.d.ts @@ -1,5 +1,12 @@ // electron-env.d.ts export interface IElectronAPI { + startSignalr: (user: any) => Promise; + offSignalr: () => Promise; + onStop: () => Promise; + onInvoke: (str: string, data: any) => Promise; + changeLocalStorage: (callBack: Function) => void; + onOtherSignalr: (callBack: Function) => void; + onSignalr: (callBack: Function) => void; setMainWindowSize: (config: any) => void; getWindowSize: () => any; setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize' | 'hide' | 'show') => void; diff --git a/src/utils/package/signalr.ts b/src/utils/package/signalr.ts deleted file mode 100644 index 0d0652b..0000000 --- a/src/utils/package/signalr.ts +++ /dev/null @@ -1,242 +0,0 @@ -import * as signalR from '@microsoft/signalr'; -import storage from './storage'; -let connection = '' as any; -export const startSignalr = async () => { - const user = await JSON.parse(storage.getItem('user') as string); - connection = new signalR.HubConnectionBuilder().withAutomaticReconnect() - .withUrl(`${import.meta.env.VITE_BASE_URL_API}/session-manage`, { - skipNegotiation: true, - transport: signalR.HttpTransportType.WebSockets, - accessTokenFactory: () => user.token - }) - .build(); - onStart() - storage.setItem('isSignalr', true) - storage.setItem('reconnect', true) - connection.onreconnected(async () => { - storage.setItem('reconnect', true) - }); - connection.onreconnecting(async () => { - onStart() - storage.setItem('reconnect', false) - }); -} - -export const onStart = async () => { - if (connection) { - if (connection.state !== signalR.HubConnectionState.Connected) { - connection.start(); - } else { - setTimeout(onStart, 3000); - } - } -} -export const onOtherSignalr = (callBack: Function) => { - if (connection) { - // 邀请 - connection.on("Invitation", (roomNum: string, roomName: string, InviterName: string) => { - callBack({ - key: 'Invitation', - roomNum, roomName, InviterName - }) - }); - // 退出 - connection.on("ForceLogout", (msg: string) => { - callBack({ - key: 'ForceLogout', - msg - }) - }); - } -} -export const onSignalr = (callBack: Function) => { - if (connection) { - // 聊天 - connection.on("ReceiveMessage", (uid: string, userName: string, message: string, timestamp: string) => { - callBack({ - key: 'ReceiveMessage', - uid, message, userName, timestamp - }) - }); - // 扩展操作 - connection.on("Operation", (type: number) => { - callBack({ - key: 'Operation', - type - }) - }); - // 移出会议 - connection.on("ForceExitRoom", () => { - callBack({ - key: 'ForceExitRoom', - }) - }); - // 全员离开房间 - connection.on("AllLeave", () => { - callBack({ - key: 'AllLeave', - }) - }); - // 全员看他 - connection.on("ShowUser", (uid: string, uname: string, operUid: string, operUserName: string) => { - callBack({ - key: 'ShowUser', - uid, - uname, - operUid, - operUserName, - }) - }); - // 更新视图模式 - connection.on("RefreshView", (type: string) => { - callBack({ - key: 'RefreshView', - type - }) - }); - // 用户加入频道回调 - connection.on("UserJoined", (user: any) => { - callBack({ - key: 'UserJoined', - user, - }) - }); - // 用户退出频道回调 - connection.on("UserLeave", (uid: string,) => { - callBack({ - key: 'UserLeave', - uid, - }) - }); - // 所有用户开闭麦 - connection.on("OperAllMicr", (enableMicr: boolean, uid: string) => { - callBack({ - key: 'OperAllMicr', - enableMicr, - uid - }) - }); - // 用户关闭开启麦克风 - connection.on("OperMicr", (user: any, operUid: string) => { - callBack({ - key: 'OperMicr', - user, - operUid - }) - }); - // 用户开启关闭摄像头 - connection.on("OperCamera", (user: any, operUid: string) => { - callBack({ - key: 'OperCamera', - user, - operUid - }) - }); - // 发言人用户信息刷新 - connection.on("ManagerRefresh", (user: any, uid: string) => { - callBack({ - key: 'ManagerRefresh', - user, - uid - }) - }); - // 申请发言 - connection.on("ApplyToSpeak", (uid: string, uname: string) => { - callBack({ - key: 'ApplyToSpeak', - uid, - uname - }) - }); - // 管理员查看随机用户 - connection.on("Watch", (watchUids: string[]) => { - callBack({ - key: 'Watch', - watchUids - }) - }); - // 设备列表 - connection.on("DriverList", (callerUid: string) => { - callBack({ - key: 'DriverList', - callerUid - }) - }); - // 设置设备 - connection.on("SaveDriver", (driver: string) => { - callBack({ - key: 'SaveDriver', - driver - }) - }); - // 显示设备列表 - connection.on("ShowDriverList", (driversJsonString: string) => { - callBack({ - key: 'ShowDriverList', - driversJsonString - }) - }); - } -} -export const offSignalr = () => { - if (connection) { - connection.off('ReceiveMessage'); - connection.off('Operation'); - connection.off('ForceExitRoom'); - connection.off('AllLeave'); - connection.off('ShowUser'); - connection.off('RefreshView'); - connection.off('UserJoined'); - connection.off('UserLeave'); - connection.off('OperAllMicr'); - connection.off('OperMicr'); - connection.off('OperCamera'); - connection.off('ManagerRefresh'); - connection.off('ApplyToSpeak'); - connection.off('Watch'); - connection.off('DriverList'); - connection.off('SetDriver'); - connection.off('ShowDriverList'); - } -} -export const onInvoke = async (str: string, data: any) => { - switch (str) { - case 'sendChannelMsg': - await connection.invoke(str, data.roomNum, data.msg) - break; - case 'sendOper': - // 4:屏幕共享 - await connection.invoke(str, data.roomNum, data.type) - break; - case 'getDrivers': - // 获取某个人的设备列表 - await connection.invoke(str, data.uid) - break; - case 'sendDrivers': - // 发送设备列表给某个人 - await connection.invoke(str, data.uid, data.driversJsonString) - break; - case 'setDrivers': - // 设置某个人的设备列表 - await connection.invoke(str, data.uid, data.driversJsonString) - break; - case 'joinChannel': - // 设置某个人的设备列表 - await connection.invoke(str, data.roomNum, data.enableMicr, data.enableCamera) - break; - case 'levelChannel': - // 设置某个人的设备列表 - await connection.invoke(str, data.roomNum) - break; - } -} -export const onStop = async () => { - if (connection) { - storage.setItem('isSignalr', false) - connection.off('Invitation'); - connection.off('ForceLogout'); - connection.stop() - connection = "" - } -} -