diff --git a/publish/changeLog.md b/publish/changeLog.md index 019309fc..f630f3f3 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -8,6 +8,7 @@ ### 新增 - 新增我的列表名右键菜单-排序歌曲-随机乱序功能,使用它可以对选中列表内歌曲进行随机重排(#1440) +- 新增数据同步服务端模式已认证设备列表管理,该功能位置:设置-数据同步-服务端模式-已认证设备列表 ### 优化 diff --git a/src/common/ipcNames.ts b/src/common/ipcNames.ts index abce60c2..a40a9819 100644 --- a/src/common/ipcNames.ts +++ b/src/common/ipcNames.ts @@ -127,6 +127,8 @@ const modules = { get_music_url_count: 'get_music_url_count', sync_action: 'sync_action', + sync_get_server_devices: 'sync_get_server_devices', + sync_remove_server_device: 'sync_remove_server_device', process_new_desktop_lyric_client: 'process_new_desktop_lyric_client', diff --git a/src/common/types/sync.d.ts b/src/common/types/sync.d.ts index 12247f64..981beb77 100644 --- a/src/common/types/sync.d.ts +++ b/src/common/types/sync.d.ts @@ -31,6 +31,8 @@ declare namespace LX { | SyncAction<'enable_server', EnableServer> | SyncAction<'enable_client', EnableClient> + type ServerDevices = ServerKeyInfo[] + interface ServerStatus { status: boolean message: string diff --git a/src/lang/en-us.json b/src/lang/en-us.json index 3a89b82b..1a5db3c2 100644 --- a/src/lang/en-us.json +++ b/src/lang/en-us.json @@ -522,10 +522,16 @@ "setting__sync_server_address": "Synchronization service address: {address}", "setting__sync_server_auth_code": "Connection code: {code}", "setting__sync_server_device": "Connected devices: {devices}", + "setting__sync_server_device_list_btn_remove": "Remove", + "setting__sync_server_device_list_noitem": "Nothing here ┗( ▔, ▔ )┛", + "setting__sync_server_device_list_time": "Last connection time: {time}", + "setting__sync_server_device_list_tips": "💡 After the device is removed, you need to re-enter the connection code when reconnecting", + "setting__sync_server_device_list_title": "Certified device", "setting__sync_server_mode": "Server mode (since the data is transmitted in clear text, please use it under a trusted network)", "setting__sync_server_port": "Sync port settings", "setting__sync_server_port_tip": "Please enter the synchronization service port number", "setting__sync_server_refresh_code": "Refresh the connection code", + "setting__sync_server_show_device_list": "List of certified devices", "setting__sync_tip": "For how to use it, please see the \"Sync function\" section of the FAQ", "setting__update": "Update", "setting__update_checking": "Checking for updates...", @@ -577,7 +583,7 @@ "sync__merge_tip_desc": "Merge the two lists together, the same song will be removed (the song of the merged person is removed), and different songs will be added.", "sync__other_label": "Other", "sync__other_tip": "Other: ", - "sync__other_tip_desc": "\"Cancel Sync\" will directly disconnect the two parties.", + "sync__other_tip_desc": "\"Cancel Sync\" will not use list sync.", "sync__overwrite": "Full coverage", "sync__overwrite_btn_cancel": "Cancel sync", "sync__overwrite_btn_local_remote": "Local list Overwrite remote list", diff --git a/src/lang/zh-cn.json b/src/lang/zh-cn.json index e36c9e26..316033f2 100644 --- a/src/lang/zh-cn.json +++ b/src/lang/zh-cn.json @@ -521,10 +521,16 @@ "setting__sync_server_address": "同步服务地址:{address}", "setting__sync_server_auth_code": "连接码:{code}", "setting__sync_server_device": "已连接的设备:{devices}", + "setting__sync_server_device_list_btn_remove": "移除", + "setting__sync_server_device_list_noitem": "这里啥也没有 ┗( ▔, ▔ )┛", + "setting__sync_server_device_list_time": "最后连接时间:{time}", + "setting__sync_server_device_list_tips": "💡 设备被移除后,再连接时需要重新输入连接码", + "setting__sync_server_device_list_title": "已认证设备", "setting__sync_server_mode": "服务端模式(由于数据是明文传输,请在受信任的网络下使用)", "setting__sync_server_port": "同步端口设置", "setting__sync_server_port_tip": "请输入同步服务端口号", "setting__sync_server_refresh_code": "刷新连接码", + "setting__sync_server_show_device_list": "已认证设备列表", "setting__sync_tip": "使用方式请看常见问题“同步功能”部分", "setting__update": "软件更新", "setting__update_checking": "检查更新中...", @@ -576,7 +582,7 @@ "sync__merge_tip_desc": "将两边的列表合并到一起,相同的歌曲将被去掉(去掉的是被合并者的歌曲),不同的歌曲将被添加。", "sync__other_label": "其他", "sync__other_tip": "其他:", - "sync__other_tip_desc": "“取消同步”将直接断开双方的连接。", + "sync__other_tip_desc": "“取消同步”将不使用列表同步功能。", "sync__overwrite": "完全覆盖", "sync__overwrite_btn_cancel": "取消同步", "sync__overwrite_btn_local_remote": "本机列表 覆盖 远程列表", diff --git a/src/lang/zh-tw.json b/src/lang/zh-tw.json index 0587da8e..09a9e186 100644 --- a/src/lang/zh-tw.json +++ b/src/lang/zh-tw.json @@ -522,10 +522,16 @@ "setting__sync_server_address": "同步服務地址:{address}", "setting__sync_server_auth_code": "連接碼:{code}", "setting__sync_server_device": "已連接的設備:{devices}", + "setting__sync_server_device_list_btn_remove": "移除", + "setting__sync_server_device_list_noitem": "這裡啥也沒有 ┗( ▔, ▔ )┛", + "setting__sync_server_device_list_time": "最後連接時間:{time}", + "setting__sync_server_device_list_tips": "💡 設備被移除後,再連接時需要重新輸入連接碼", + "setting__sync_server_device_list_title": "已認證設備", "setting__sync_server_mode": "服務端模式(由於數據是明文傳輸,請在受信任的網絡下使用)", "setting__sync_server_port": "同步端口設置", "setting__sync_server_port_tip": "請輸入同步服務端口號", "setting__sync_server_refresh_code": "刷新連接碼", + "setting__sync_server_show_device_list": "已認證設備列表", "setting__sync_tip": "使用方式請看常見問題“同步功能”部分", "setting__update": "軟件更新", "setting__update_checking": "檢查更新中...", @@ -576,7 +582,7 @@ "sync__merge_tip_desc": "將兩邊的列表合併到一起,相同的歌曲將被去掉(去掉的是被合併者的歌曲),不同的歌曲將被添加。", "sync__other_label": "其他", "sync__other_tip": "其他:", - "sync__other_tip_desc": "“取消同步”將直接斷開雙方的連接。", + "sync__other_tip_desc": "“取消同步”將不使用列表同步功能。", "sync__overwrite": "完全覆蓋", "sync__overwrite_btn_cancel": "取消同步", "sync__overwrite_btn_local_remote": "本機列表 覆蓋 遠程列表", diff --git a/src/main/modules/sync/index.ts b/src/main/modules/sync/index.ts index 86f23636..7ce3a5b9 100644 --- a/src/main/modules/sync/index.ts +++ b/src/main/modules/sync/index.ts @@ -9,6 +9,8 @@ export { stopServer, getStatus as getServerStatus, generateCode, + getDevices as getServerDevices, + removeDevice as removeServerDevice, } from './server' export { diff --git a/src/main/modules/sync/server/index.ts b/src/main/modules/sync/server/index.ts index a1d46046..789db369 100644 --- a/src/main/modules/sync/server/index.ts +++ b/src/main/modules/sync/server/index.ts @@ -1,14 +1,8 @@ -import { - startServer, - stopServer, - getStatus, - generateCode, -} from './server' - - export { startServer, stopServer, getStatus, generateCode, -} + getDevices, + removeDevice, +} from './server' diff --git a/src/main/modules/sync/server/modules/list/manage.ts b/src/main/modules/sync/server/modules/list/manage.ts index 8f0dd4a0..d1c4cc93 100644 --- a/src/main/modules/sync/server/modules/list/manage.ts +++ b/src/main/modules/sync/server/modules/list/manage.ts @@ -44,6 +44,10 @@ export class ListManage { await this.snapshotDataManage.updateDeviceSnapshotKey(clientId, key) } + removeDevice = async(clientId: string) => { + this.snapshotDataManage.removeSnapshotInfo(clientId) + } + getListData = async(): Promise => { return getLocalListData() } diff --git a/src/main/modules/sync/server/modules/list/snapshotDataManage.ts b/src/main/modules/sync/server/modules/list/snapshotDataManage.ts index 1240b850..c46134ae 100644 --- a/src/main/modules/sync/server/modules/list/snapshotDataManage.ts +++ b/src/main/modules/sync/server/modules/list/snapshotDataManage.ts @@ -68,6 +68,15 @@ export class SnapshotDataManage { this.saveSnapshotInfoThrottle() } + removeSnapshotInfo = (clientId: string) => { + let client = this.snapshotInfo.clients[clientId] + if (!client) return + if (client.snapshotKey) this.clientSnapshotKeys.splice(this.clientSnapshotKeys.indexOf(client.snapshotKey), 1) + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this.snapshotInfo.clients[clientId] + this.saveSnapshotInfoThrottle() + } + getSnapshot = async(name: string) => { const filePath = path.join(this.snapshotDir, `snapshot_${name}`) let listData: LX.Sync.List.ListData diff --git a/src/main/modules/sync/server/modules/list/sync/sync.ts b/src/main/modules/sync/server/modules/list/sync/sync.ts index 80ff5ab8..9f0d4f24 100644 --- a/src/main/modules/sync/server/modules/list/sync/sync.ts +++ b/src/main/modules/sync/server/modules/list/sync/sync.ts @@ -1,4 +1,5 @@ // import { SYNC_CLOSE_CODE } from '../../../../constants' +import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain' import { getUserSpace, getUserConfig } from '../../../user' import { getLocalListData, setLocalListData } from '@main/modules/sync/utils' // import { LIST_IDS } from '@common/constants' @@ -29,9 +30,26 @@ const getRemoteListMD5 = async(socket: LX.Sync.Server.Socket): Promise = // const getLocalListData = async(socket: LX.Sync.Server.Socket): Promise => { // return getUserSpace(socket.userInfo.name).listManage.getListData() // } -const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise => { - return socket.remoteQueueList.list_sync_get_sync_mode() -} +const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise => new Promise((resolve, reject) => { + const handleDisconnect = (err: Error) => { + sendCloseSelectMode() + removeSelectModeListener() + reject(err) + } + let removeEventClose = socket.onClose(handleDisconnect) + sendSelectMode(socket.keyInfo.deviceName, (mode) => { + if (mode == null) { + reject(new Error('cancel')) + return + } + resolve(mode) + removeSelectModeListener() + removeEventClose() + }) +}) +// const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise => { +// return socket.remoteQueueList.list_sync_get_sync_mode() +// } const finishedSync = async(socket: LX.Sync.Server.Socket) => { await socket.remoteQueueList.list_sync_finished() diff --git a/src/main/modules/sync/server/server/index.ts b/src/main/modules/sync/server/server/index.ts index a1d46046..789db369 100644 --- a/src/main/modules/sync/server/server/index.ts +++ b/src/main/modules/sync/server/server/index.ts @@ -1,14 +1,8 @@ -import { - startServer, - stopServer, - getStatus, - generateCode, -} from './server' - - export { startServer, stopServer, getStatus, generateCode, -} + getDevices, + removeDevice, +} from './server' diff --git a/src/main/modules/sync/server/server/server.ts b/src/main/modules/sync/server/server/server.ts index 7eda49ad..bd08b01a 100644 --- a/src/main/modules/sync/server/server/server.ts +++ b/src/main/modules/sync/server/server/server.ts @@ -385,3 +385,18 @@ export const generateCode = async() => { sendServerStatus(status) return status.code } + +export const getDevices = async() => { + const userSpace = getUserSpace() + return userSpace.getDecices() +} + +export const removeDevice = async(clientId: string) => { + if (wss) { + for (const client of wss.clients) { + if (client.keyInfo.clientId == clientId) client.close(SYNC_CLOSE_CODE.normal) + } + } + const userSpace = getUserSpace() + await userSpace.removeDevice(clientId) +} diff --git a/src/main/modules/sync/server/user/data.ts b/src/main/modules/sync/server/user/data.ts index a22351ef..4b7e80d4 100644 --- a/src/main/modules/sync/server/user/data.ts +++ b/src/main/modules/sync/server/user/data.ts @@ -3,7 +3,7 @@ import path from 'node:path' import { randomBytes } from 'node:crypto' import { throttle } from '@common/utils/common' import { filterFileName, toMD5 } from '../utils' -import { File } from '../../../../../common/constants_sync' +import { File } from '@common/constants_sync' interface ServerInfo { @@ -105,6 +105,10 @@ export class UserDataManage { devicesInfo: DevicesInfo private readonly saveDevicesInfoThrottle: () => void + getAllClientKeyInfo = () => { + return Object.values(this.devicesInfo.clients).sort((a, b) => (b.lastConnectDate ?? 0) - (a.lastConnectDate ?? 0)) + } + saveClientKeyInfo = (keyInfo: LX.Sync.ServerKeyInfo) => { if (this.devicesInfo.clients[keyInfo.clientId] == null && Object.keys(this.devicesInfo.clients).length > 101) throw new Error('max keys') this.devicesInfo.clients[keyInfo.clientId] = keyInfo @@ -116,6 +120,12 @@ export class UserDataManage { return this.devicesInfo.clients[clientId] ?? null } + removeClientKeyInfo = async(clientId: string) => { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete this.devicesInfo.clients[clientId] + this.saveDevicesInfoThrottle() + } + isIncluedsClient = (clientId: string) => { return Object.values(this.devicesInfo.clients).some(client => client.clientId == clientId) } diff --git a/src/main/modules/sync/server/user/index.ts b/src/main/modules/sync/server/user/index.ts index 9e881de6..d8f93b32 100644 --- a/src/main/modules/sync/server/user/index.ts +++ b/src/main/modules/sync/server/user/index.ts @@ -6,6 +6,8 @@ import { export interface UserSpace { dataManage: UserDataManage listManage: ListManage + getDecices: () => Promise + removeDevice: (clientId: string) => Promise } const users = new Map() @@ -31,9 +33,17 @@ export const getUserSpace = (userName = 'default') => { if (!user) { console.log('new user data manage:', userName) const dataManage = new UserDataManage(userName) + const listManage = new ListManage(dataManage) users.set(userName, user = { dataManage, - listManage: new ListManage(dataManage), + listManage, + async getDecices() { + return this.dataManage.getAllClientKeyInfo() + }, + async removeDevice(clientId) { + await listManage.removeDevice(clientId) + await dataManage.removeClientKeyInfo(clientId) + }, }) } return user diff --git a/src/main/modules/winMain/rendererEvent/sync.ts b/src/main/modules/winMain/rendererEvent/sync.ts index 65c4aae1..93bff17e 100644 --- a/src/main/modules/winMain/rendererEvent/sync.ts +++ b/src/main/modules/winMain/rendererEvent/sync.ts @@ -1,6 +1,16 @@ import { mainHandle } from '@common/mainIpc' import { WIN_MAIN_RENDERER_EVENT_NAME } from '@common/ipcNames' -import { startServer, stopServer, getServerStatus, generateCode, connectServer, disconnectServer, getClientStatus } from '@main/modules/sync' +import { + startServer, + stopServer, + getServerStatus, + generateCode, + connectServer, + disconnectServer, + getClientStatus, + getServerDevices, + removeServerDevice, +} from '@main/modules/sync' import { sendEvent } from '../main' let selectModeListenr: ((mode: LX.Sync.List.SyncMode | null) => void) | null = null @@ -27,6 +37,12 @@ export default () => { break } }) + mainHandle(WIN_MAIN_RENDERER_EVENT_NAME.sync_get_server_devices, async() => { + return getServerDevices() + }) + mainHandle(WIN_MAIN_RENDERER_EVENT_NAME.sync_remove_server_device, async({ params: clientId }) => { + await removeServerDevice(clientId) + }) } diff --git a/src/renderer/assets/svgs/phone.svg b/src/renderer/assets/svgs/phone.svg new file mode 100644 index 00000000..ffdf58d8 --- /dev/null +++ b/src/renderer/assets/svgs/phone.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/renderer/utils/ipc.ts b/src/renderer/utils/ipc.ts index b3503846..f1d794db 100644 --- a/src/renderer/utils/ipc.ts +++ b/src/renderer/utils/ipc.ts @@ -727,6 +727,23 @@ export const sendSyncAction = async(action: LX.Sync.SyncServiceActions) => { return rendererInvoke(WIN_MAIN_RENDERER_EVENT_NAME.sync_action, action) } +/** + * 获取同步服务端连接设备历史列表 + * @returns + */ +export const getSyncServerDevices = () => { + return rendererInvoke(WIN_MAIN_RENDERER_EVENT_NAME.sync_get_server_devices) +} + +/** + * 移除同步服务端连接设备 + * @returns + */ +export const removeSyncServerDevice = (clientId: string) => { + return rendererInvoke(WIN_MAIN_RENDERER_EVENT_NAME.sync_remove_server_device, clientId) +} + + // export const refreshSyncCode = async(): Promise => { // return rendererInvoke(WIN_MAIN_RENDERER_EVENT_NAME.sync_generate_code) // } diff --git a/src/renderer/views/Setting/components/SettingSync.vue b/src/renderer/views/Setting/components/SettingSync.vue deleted file mode 100644 index 65c7709a..00000000 --- a/src/renderer/views/Setting/components/SettingSync.vue +++ /dev/null @@ -1,130 +0,0 @@ - - - - - diff --git a/src/renderer/views/Setting/components/SettingSync/ServerDeviceListModal.vue b/src/renderer/views/Setting/components/SettingSync/ServerDeviceListModal.vue new file mode 100644 index 00000000..838c3d86 --- /dev/null +++ b/src/renderer/views/Setting/components/SettingSync/ServerDeviceListModal.vue @@ -0,0 +1,163 @@ + + + + + diff --git a/src/renderer/views/Setting/components/SettingSync/SyncClient.vue b/src/renderer/views/Setting/components/SettingSync/SyncClient.vue new file mode 100644 index 00000000..256d29fc --- /dev/null +++ b/src/renderer/views/Setting/components/SettingSync/SyncClient.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/src/renderer/views/Setting/components/SettingSync/SyncServer.vue b/src/renderer/views/Setting/components/SettingSync/SyncServer.vue new file mode 100644 index 00000000..e691d79c --- /dev/null +++ b/src/renderer/views/Setting/components/SettingSync/SyncServer.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/src/renderer/views/Setting/components/SettingSync/index.vue b/src/renderer/views/Setting/components/SettingSync/index.vue new file mode 100644 index 00000000..0d88a736 --- /dev/null +++ b/src/renderer/views/Setting/components/SettingSync/index.vue @@ -0,0 +1,44 @@ + + + diff --git a/src/renderer/views/Setting/index.vue b/src/renderer/views/Setting/index.vue index bd319dfc..d1e7cfa1 100644 --- a/src/renderer/views/Setting/index.vue +++ b/src/renderer/views/Setting/index.vue @@ -59,7 +59,7 @@ import SettingDesktopLyric from './components/SettingDesktopLyric.vue' import SettingSearch from './components/SettingSearch.vue' import SettingList from './components/SettingList.vue' import SettingDownload from './components/SettingDownload.vue' -import SettingSync from './components/SettingSync.vue' +import SettingSync from './components/SettingSync/index.vue' import SettingHotKey from './components/SettingHotKey.vue' import SettingNetwork from './components/SettingNetwork.vue' import SettingOdc from './components/SettingOdc.vue'