修改同步逻辑
parent
71b84fb10d
commit
c6f4bfa875
|
@ -8,6 +8,7 @@ module.exports = {
|
|||
'vue',
|
||||
'@types/ws',
|
||||
// 'eslint-config-standard-with-typescript',
|
||||
'typescript', // https://github.com/microsoft/TypeScript/pull/54567
|
||||
],
|
||||
|
||||
// target: 'newest',
|
||||
|
@ -24,10 +25,6 @@ module.exports = {
|
|||
|
||||
// target: 'minor',
|
||||
// filter: [
|
||||
// 'eslint-plugin-n',
|
||||
// 'electron',
|
||||
// 'eslint-config-standard-with-typescript',
|
||||
// '@typescript-eslint/eslint-plugin',
|
||||
// '@typescript-eslint/parser',
|
||||
// ],
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "2.4.0-beta.9",
|
||||
"version": "2.4.0-beta.10",
|
||||
"description": "一个免费的音乐查找助手",
|
||||
"main": "./dist/main.js",
|
||||
"productName": "lx-music-desktop",
|
||||
|
@ -205,14 +205,14 @@
|
|||
},
|
||||
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
"@babel/eslint-parser": "^7.22.10",
|
||||
"@babel/core": "^7.22.11",
|
||||
"@babel/eslint-parser": "^7.22.11",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-modules-umd": "^7.22.5",
|
||||
"@babel/plugin-transform-runtime": "^7.22.10",
|
||||
"@babel/preset-env": "^7.22.10",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@babel/preset-typescript": "^7.22.11",
|
||||
"@tsconfig/recommended": "^1.0.2",
|
||||
"@types/better-sqlite3": "^7.6.4",
|
||||
"@types/needle": "^3.2.0",
|
||||
|
@ -230,15 +230,15 @@
|
|||
"css-loader": "^6.8.1",
|
||||
"css-minimizer-webpack-plugin": "^5.0.1",
|
||||
"del": "^6.1.1",
|
||||
"electron": "^22.3.21",
|
||||
"electron-builder": "^24.6.3",
|
||||
"electron": "^22.3.22",
|
||||
"electron-builder": "^24.6.4",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-to-chromium": "^1.4.496",
|
||||
"electron-to-chromium": "^1.4.503",
|
||||
"electron-updater": "^6.1.4",
|
||||
"eslint": "^8.47.0",
|
||||
"eslint": "^8.48.0",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-config-standard-with-typescript": "^38.1.0",
|
||||
"eslint-config-standard-with-typescript": "^39.0.0",
|
||||
"eslint-formatter-friendly": "github:lyswhut/eslint-friendly-formatter#2170d1320e2fad13615a9dcf229669f0bb473a53",
|
||||
"eslint-plugin-html": "^7.1.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
|
@ -274,19 +274,19 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@simonwep/pickr": "^1.8.2",
|
||||
"better-sqlite3": "^8.5.1",
|
||||
"better-sqlite3": "^8.5.2",
|
||||
"bufferutil": "^4.0.7",
|
||||
"comlink": "~4.3.1",
|
||||
"crypto-js": "^4.1.1",
|
||||
"electron-font-manager": "github:lyswhut/electron-font-manager#6d2f5ecf850c4fe34812b9394913680462ee0dae",
|
||||
"electron-log": "^5.0.0-beta.25",
|
||||
"electron-log": "^5.0.0-beta.28",
|
||||
"electron-store": "^8.1.0",
|
||||
"font-list": "^1.5.0",
|
||||
"font-list": "^1.5.1",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"image-size": "^1.0.2",
|
||||
"jschardet": "^3.0.0",
|
||||
"long": "^5.2.3",
|
||||
"message2call": "^0.1.0",
|
||||
"message2call": "^0.1.2",
|
||||
"music-metadata": "^8.1.4",
|
||||
"needle": "github:lyswhut/needle#93299ac841b7e9a9f82ca7279b88aaaeda404060",
|
||||
"node-id3": "^0.2.6",
|
||||
|
|
|
@ -30,5 +30,5 @@
|
|||
|
||||
### 其他
|
||||
|
||||
- 更新 electron 到 v22.3.21
|
||||
- 更新 electron 到 v22.3.22
|
||||
- 重构同步服务端功能部分代码,使其更易扩展新功能
|
||||
|
|
|
@ -76,24 +76,3 @@ export const DOWNLOAD_STATUS = {
|
|||
} as const
|
||||
|
||||
export const QUALITYS = ['flac24bit', 'flac', 'wav', 'ape', '320k', '192k', '128k'] as const
|
||||
|
||||
export const SYNC_CODE = {
|
||||
helloMsg: 'Hello~::^-^::~v4~',
|
||||
idPrefix: 'OjppZDo6',
|
||||
authMsg: 'lx-music auth::',
|
||||
authFailed: 'Auth failed',
|
||||
missingAuthCode: 'Missing auth code',
|
||||
getServiceIdFailed: 'Get service id failed',
|
||||
connectServiceFailed: 'Connect service failed',
|
||||
connecting: 'Connecting...',
|
||||
unknownServiceAddress: 'Unknown service address',
|
||||
msgBlockedIp: 'Blocked IP',
|
||||
msgConnect: 'lx-music connect',
|
||||
msgAuthFailed: 'Auth failed',
|
||||
} as const
|
||||
|
||||
export const SYNC_CLOSE_CODE = {
|
||||
normal: 1000,
|
||||
failed: 4100,
|
||||
} as const
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ export const SYNC_CLOSE_CODE = {
|
|||
failed: 4100,
|
||||
} as const
|
||||
|
||||
export const TRANS_MODE: Readonly<Record<LX.Sync.ListSyncMode, LX.Sync.ListSyncMode>> = {
|
||||
export const TRANS_MODE: Readonly<Record<LX.Sync.List.SyncMode, LX.Sync.List.SyncMode>> = {
|
||||
merge_local_remote: 'merge_remote_local',
|
||||
merge_remote_local: 'merge_local_remote',
|
||||
overwrite_local_remote: 'overwrite_remote_local',
|
||||
|
@ -64,3 +64,7 @@ export const File = {
|
|||
|
||||
syncAuthKeysJSON: 'syncAuthKey.json',
|
||||
} as const
|
||||
|
||||
export const FeaturesList = [
|
||||
'list',
|
||||
] as const
|
|
@ -139,19 +139,5 @@ declare namespace LX {
|
|||
userList: UserListInfoFull[]
|
||||
tempList: LX.Music.MusicInfo[]
|
||||
}
|
||||
|
||||
type ActionList = SyncAction<'list_data_overwrite', LX.List.ListActionDataOverwrite>
|
||||
| SyncAction<'list_create', LX.List.ListActionAdd>
|
||||
| SyncAction<'list_remove', LX.List.ListActionRemove>
|
||||
| SyncAction<'list_update', LX.List.ListActionUpdate>
|
||||
| SyncAction<'list_update_position', LX.List.ListActionUpdatePosition>
|
||||
| SyncAction<'list_music_add', LX.List.ListActionMusicAdd>
|
||||
| SyncAction<'list_music_move', LX.List.ListActionMusicMove>
|
||||
| SyncAction<'list_music_remove', LX.List.ListActionMusicRemove>
|
||||
| SyncAction<'list_music_update', LX.List.ListActionMusicUpdate>
|
||||
| SyncAction<'list_music_update_position', LX.List.ListActionMusicUpdatePosition>
|
||||
| SyncAction<'list_music_overwrite', LX.List.ListActionMusicOverwrite>
|
||||
| SyncAction<'list_music_clear', LX.List.ListActionMusicClear>
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
declare namespace LX {
|
||||
|
||||
namespace Sync {
|
||||
namespace List {
|
||||
interface ListInfo {
|
||||
lastSyncDate?: number
|
||||
snapshotKey: string
|
||||
}
|
||||
|
||||
type ActionList = LX.Sync.SyncAction<'list_data_overwrite', LX.List.ListActionDataOverwrite>
|
||||
| SyncAction<'list_create', LX.List.ListActionAdd>
|
||||
| SyncAction<'list_remove', LX.List.ListActionRemove>
|
||||
| SyncAction<'list_update', LX.List.ListActionUpdate>
|
||||
| SyncAction<'list_update_position', LX.List.ListActionUpdatePosition>
|
||||
| SyncAction<'list_music_add', LX.List.ListActionMusicAdd>
|
||||
| SyncAction<'list_music_move', LX.List.ListActionMusicMove>
|
||||
| SyncAction<'list_music_remove', LX.List.ListActionMusicRemove>
|
||||
| SyncAction<'list_music_update', LX.List.ListActionMusicUpdate>
|
||||
| SyncAction<'list_music_update_position', LX.List.ListActionMusicUpdatePosition>
|
||||
| SyncAction<'list_music_overwrite', LX.List.ListActionMusicOverwrite>
|
||||
| SyncAction<'list_music_clear', LX.List.ListActionMusicClear>
|
||||
|
||||
type ListData = Omit<LX.List.ListDataFull, 'tempList'>
|
||||
type SyncMode = 'merge_local_remote'
|
||||
| 'merge_remote_local'
|
||||
| 'overwrite_local_remote'
|
||||
| 'overwrite_remote_local'
|
||||
| 'overwrite_local_remote_full'
|
||||
| 'overwrite_remote_local_full'
|
||||
// | 'none'
|
||||
| 'cancel'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,48 +24,13 @@ declare namespace LX {
|
|||
| SyncAction<'client_status', ClientStatus>
|
||||
| SyncAction<'server_status', ServerStatus>
|
||||
|
||||
type SyncServiceActions = SyncAction<'select_mode', ListSyncMode>
|
||||
type SyncServiceActions = SyncAction<'select_mode', LX.Sync.List.SyncMode>
|
||||
| SyncAction<'get_server_status'>
|
||||
| SyncAction<'get_client_status'>
|
||||
| SyncAction<'generate_code'>
|
||||
| SyncAction<'enable_server', EnableServer>
|
||||
| SyncAction<'enable_client', EnableClient>
|
||||
|
||||
type ActionList = SyncAction<'list_data_overwrite', LX.List.ListActionDataOverwrite>
|
||||
| SyncAction<'list_create', LX.List.ListActionAdd>
|
||||
| SyncAction<'list_remove', LX.List.ListActionRemove>
|
||||
| SyncAction<'list_update', LX.List.ListActionUpdate>
|
||||
| SyncAction<'list_update_position', LX.List.ListActionUpdatePosition>
|
||||
| SyncAction<'list_music_add', LX.List.ListActionMusicAdd>
|
||||
| SyncAction<'list_music_move', LX.List.ListActionMusicMove>
|
||||
| SyncAction<'list_music_remove', LX.List.ListActionMusicRemove>
|
||||
| SyncAction<'list_music_update', LX.List.ListActionMusicUpdate>
|
||||
| SyncAction<'list_music_update_position', LX.List.ListActionMusicUpdatePosition>
|
||||
| SyncAction<'list_music_overwrite', LX.List.ListActionMusicOverwrite>
|
||||
| SyncAction<'list_music_clear', LX.List.ListActionMusicClear>
|
||||
|
||||
type ActionSync = SyncAction<'list:sync:list_sync_get_md5', string>
|
||||
| SyncAction<'list:sync:list_sync_get_list_data', ListData>
|
||||
| SyncAction<'list:sync:list_sync_get_sync_mode', Mode>
|
||||
| SyncAction<'list:sync:action', ActionList>
|
||||
// | SyncAction<'finished'>
|
||||
|
||||
type ActionSyncType = Actions<ActionSync>
|
||||
|
||||
type ActionSyncSend = SyncAction<'list:sync:list_sync_get_md5'>
|
||||
| SyncAction<'list:sync:list_sync_get_list_data'>
|
||||
| SyncAction<'list:sync:list_sync_get_sync_mode'>
|
||||
| SyncAction<'list:sync:list_sync_set_data', LX.Sync.ListData>
|
||||
| SyncAction<'list:sync:action', ActionList>
|
||||
| SyncAction<'list:sync:finished'>
|
||||
|
||||
type ActionSyncSendType = Actions<ActionSyncSend>
|
||||
|
||||
interface List {
|
||||
action: string
|
||||
data: any
|
||||
}
|
||||
|
||||
interface ServerStatus {
|
||||
status: boolean
|
||||
message: string
|
||||
|
@ -94,20 +59,10 @@ declare namespace LX {
|
|||
isMobile: boolean
|
||||
}
|
||||
|
||||
interface ListInfo {
|
||||
lastSyncDate?: number
|
||||
snapshotKey: string
|
||||
type ServerType = 'desktop-app' | 'server'
|
||||
interface EnabledFeatures {
|
||||
list: boolean
|
||||
}
|
||||
type ListData = Omit<LX.List.ListDataFull, 'tempList'>
|
||||
|
||||
type ListSyncMode = 'merge_local_remote'
|
||||
| 'merge_remote_local'
|
||||
| 'overwrite_local_remote'
|
||||
| 'overwrite_remote_local'
|
||||
| 'overwrite_local_remote_full'
|
||||
| 'overwrite_remote_local_full'
|
||||
// | 'none'
|
||||
| 'cancel'
|
||||
|
||||
type SupportedFeatures = Partial<{ [k in keyof EnabledFeatures]: number }>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
declare namespace LX {
|
||||
namespace Sync {
|
||||
type ServerActions = WarpPromiseRecord<{
|
||||
onListSyncAction: (action: LX.List.ActionList) => void
|
||||
}>
|
||||
|
||||
type ClientActions = WarpPromiseRecord<{
|
||||
onListSyncAction: (action: LX.List.ActionList) => void
|
||||
list_sync_get_md5: () => string
|
||||
list_sync_get_sync_mode: () => ListSyncMode
|
||||
list_sync_get_list_data: () => ListData
|
||||
list_sync_set_list_data: (data: ListData) => void
|
||||
list_sync_finished: () => void
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import { request, generateRsaKey } from './utils'
|
||||
import { getSyncAuthKey, setSyncAuthKey } from './data'
|
||||
import { SYNC_CODE } from '@common/constants'
|
||||
import log from '../log'
|
||||
import { aesDecrypt, aesEncrypt, getComputerName, rsaDecrypt } from '../utils'
|
||||
import { toMD5 } from '@common/utils/nodejs'
|
||||
import { SYNC_CODE } from '@common/constants_sync'
|
||||
|
||||
|
||||
const hello = async(urlInfo: LX.Sync.Client.UrlInfo) => request(`${urlInfo.httpProtocol}//${urlInfo.hostPath}/hello`)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import WebSocket from 'ws'
|
||||
import { encryptMsg, decryptMsg } from './utils'
|
||||
import { modules, callObj } from './modules'
|
||||
import { callObj } from './sync'
|
||||
// import { action as commonAction } from '@root/store/modules/common'
|
||||
// import { getStore } from '@root/store'
|
||||
// import registerSyncListHandler from './syncList'
|
||||
import log from '../log'
|
||||
import { SYNC_CLOSE_CODE, SYNC_CODE } from '@common/constants'
|
||||
import { dateFormat } from '@common/utils/common'
|
||||
import { aesEncrypt, getAddress } from '../utils'
|
||||
import { sendClientStatus } from '@main/modules/winMain'
|
||||
import { createMsg2call } from 'message2call'
|
||||
import { SYNC_CLOSE_CODE, SYNC_CODE } from '@common/constants_sync'
|
||||
|
||||
let status: LX.Sync.ClientStatus = {
|
||||
status: false,
|
||||
|
@ -31,18 +31,6 @@ export const sendSyncMessage = (message: string) => {
|
|||
sendClientStatus(status)
|
||||
}
|
||||
|
||||
const handleConnection = (socket: LX.Sync.Client.Socket) => {
|
||||
for (const { registerEvent } of Object.values(modules)) {
|
||||
registerEvent(socket)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDisconnection = () => {
|
||||
for (const { unregisterEvent } of Object.values(modules)) {
|
||||
unregisterEvent()
|
||||
}
|
||||
}
|
||||
|
||||
const heartbeatTools = {
|
||||
failedNum: 0,
|
||||
maxTryNum: 100000,
|
||||
|
@ -139,14 +127,14 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
|||
heartbeatTools.connect(client)
|
||||
|
||||
let closeEvents: Array<(err: Error) => (void | Promise<void>)> = []
|
||||
let disconnected = true
|
||||
|
||||
const message2read = createMsg2call({
|
||||
const message2read = createMsg2call<LX.Sync.ServerSyncActions>({
|
||||
funcsObj: {
|
||||
...callObj,
|
||||
list_sync_finished() {
|
||||
finished() {
|
||||
log.info('sync list success')
|
||||
client!.isReady = true
|
||||
handleConnection(client as LX.Sync.Client.Socket)
|
||||
sendSyncStatus({
|
||||
status: true,
|
||||
message: '',
|
||||
|
@ -156,6 +144,7 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
|||
},
|
||||
timeout: 120 * 1000,
|
||||
sendMessage(data) {
|
||||
if (disconnected) throw new Error('disconnected')
|
||||
void encryptMsg(keyInfo, JSON.stringify(data)).then((data) => {
|
||||
client?.send(data)
|
||||
}).catch((err) => {
|
||||
|
@ -178,13 +167,14 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
|||
},
|
||||
})
|
||||
|
||||
client.remoteSyncList = message2read.createSyncRemote('list')
|
||||
client.remote = message2read.remote
|
||||
client.remoteQueueList = message2read.createQueueRemote('list')
|
||||
|
||||
client.addEventListener('message', ({ data }) => {
|
||||
if (data == 'ping') return
|
||||
if (typeof data === 'string') {
|
||||
void decryptMsg(keyInfo, data).then((data) => {
|
||||
let syncData: LX.Sync.ServerActions
|
||||
let syncData: LX.Sync.ServerSyncActions
|
||||
try {
|
||||
syncData = JSON.parse(data)
|
||||
} catch (err) {
|
||||
|
@ -212,6 +202,10 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
|||
// const store = getStore()
|
||||
// global.lx.syncKeyInfo = keyInfo
|
||||
client!.isReady = false
|
||||
client!.moduleReadys = {
|
||||
list: false,
|
||||
}
|
||||
disconnected = false
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: initMessage,
|
||||
|
@ -225,7 +219,7 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
|||
log.error(err?.message)
|
||||
}
|
||||
closeEvents = []
|
||||
handleDisconnection()
|
||||
disconnected = true
|
||||
message2read.onDestroy()
|
||||
switch (code) {
|
||||
case SYNC_CLOSE_CODE.normal:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { File } from '../constants'
|
||||
import { File } from '../../../../common/constants_sync'
|
||||
|
||||
|
||||
let syncAuthKeys: Record<string, LX.Sync.ClientKeyInfo>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import handleAuth from './auth'
|
||||
import { connect as socketConnect, disconnect as socketDisconnect, sendSyncStatus, sendSyncMessage } from './client'
|
||||
// import { getSyncHost } from '@root/utils/data'
|
||||
import { SYNC_CODE } from '@common/constants'
|
||||
import log from '../log'
|
||||
import { parseUrl } from './utils'
|
||||
import migrateData from '../migrate'
|
||||
import { SYNC_CODE } from '@common/constants_sync'
|
||||
|
||||
let connectId = 0
|
||||
|
||||
|
|
|
@ -8,3 +8,7 @@ export const callObj = Object.assign({}, list.handler)
|
|||
export const modules = {
|
||||
list,
|
||||
}
|
||||
|
||||
export const featureVersion = {
|
||||
list: 1,
|
||||
} as const
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// 这个文件导出的方法将暴露给服务端调用,第一个参数固定为当前 socket 对象
|
||||
import { handleRemoteListAction } from '@main/modules/sync/utils'
|
||||
import { getLocalListData, setLocalListData } from '../../../utils'
|
||||
import { toMD5 } from '@common/utils/nodejs'
|
||||
import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain'
|
||||
import log from '@main/modules/sync/log'
|
||||
import { registerEvent, unregisterEvent } from './localEvent'
|
||||
|
||||
const logInfo = (eventName: string, success = false) => {
|
||||
log.info(`[${eventName}]${eventName.replace('list:sync:list_sync_', '').replaceAll('_', ' ')}${success ? ' success' : ''}`)
|
||||
|
@ -11,8 +13,8 @@ const logInfo = (eventName: string, success = false) => {
|
|||
// log.error(`[${eventName}]${eventName.replace('list:sync:list_sync_', '').replaceAll('_', ' ')} error: ${err.message}`)
|
||||
// }
|
||||
|
||||
export const onListSyncAction = async(socket: LX.Sync.Client.Socket, action: LX.Sync.ActionList) => {
|
||||
if (!socket.isReady) return
|
||||
export const onListSyncAction = async(socket: LX.Sync.Client.Socket, action: LX.Sync.List.ActionList) => {
|
||||
if (!socket.moduleReadys?.list) return
|
||||
await handleRemoteListAction(action)
|
||||
}
|
||||
|
||||
|
@ -21,7 +23,7 @@ export const list_sync_get_md5 = async(socket: LX.Sync.Client.Socket) => {
|
|||
return toMD5(JSON.stringify(await getLocalListData()))
|
||||
}
|
||||
|
||||
const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.ListSyncMode> => new Promise((resolve, reject) => {
|
||||
const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.List.SyncMode> => new Promise((resolve, reject) => {
|
||||
const handleDisconnect = (err: Error) => {
|
||||
sendCloseSelectMode()
|
||||
removeSelectModeListener()
|
||||
|
@ -47,7 +49,17 @@ export const list_sync_get_list_data = async(socket: LX.Sync.Client.Socket) => {
|
|||
return getLocalListData()
|
||||
}
|
||||
|
||||
export const list_sync_set_list_data = async(socket: LX.Sync.Client.Socket, data: LX.Sync.ListData) => {
|
||||
export const list_sync_set_list_data = async(socket: LX.Sync.Client.Socket, data: LX.Sync.List.ListData) => {
|
||||
logInfo('list:sync:list_sync_set_list_data')
|
||||
await setLocalListData(data)
|
||||
}
|
||||
|
||||
export const list_sync_finished = async(socket: LX.Sync.Client.Socket) => {
|
||||
logInfo('list:sync:finished')
|
||||
socket.moduleReadys.list = true
|
||||
registerEvent(socket)
|
||||
socket.onClose(() => {
|
||||
unregisterEvent()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@ export const registerEvent = (socket: LX.Sync.Client.Socket) => {
|
|||
// unregisterLocalListAction?.()
|
||||
// unregisterLocalListAction = null
|
||||
// })
|
||||
unregisterEvent()
|
||||
unregisterLocalListAction = registerListActionEvent((action) => {
|
||||
if (!socket?.isReady) return
|
||||
void socket.remoteSyncList.onListSyncAction(action)
|
||||
if (!socket.moduleReadys?.list) return
|
||||
void socket.remoteQueueList.onListSyncAction(action)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// 这个文件导出的方法将暴露给服务端调用,第一个参数固定为当前 socket 对象
|
||||
|
||||
// import { getUserSpace } from '@/user'
|
||||
// import { modules } from '../modules'
|
||||
|
||||
import { featureVersion } from '../modules'
|
||||
|
||||
|
||||
export const getEnabledFeatures = async(socket: LX.Sync.Client.Socket, serverType: LX.Sync.ServerType, supportedFeatures: LX.Sync.SupportedFeatures): Promise<LX.Sync.EnabledFeatures> => {
|
||||
// const userSpace = getUserSpace(socket.userInfo.name)
|
||||
switch (serverType) {
|
||||
case 'server':
|
||||
return {
|
||||
list: featureVersion.list == supportedFeatures.list,
|
||||
}
|
||||
case 'desktop-app':
|
||||
default:
|
||||
return {
|
||||
list: featureVersion.list == supportedFeatures.list,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import * as handler from './handler'
|
||||
import { callObj as _callObj } from '../modules'
|
||||
export { modules } from '../modules'
|
||||
|
||||
export const callObj = {
|
||||
...handler,
|
||||
..._callObj,
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { File } from './constants'
|
||||
import { File } from '../../../common/constants_sync'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
|
|
|
@ -10,3 +10,7 @@ export const modules = {
|
|||
|
||||
|
||||
export { ListManage } from './list'
|
||||
|
||||
export const featureVersion = {
|
||||
list: 1,
|
||||
} as const
|
||||
|
|
|
@ -44,7 +44,7 @@ export class ListManage {
|
|||
await this.snapshotDataManage.updateDeviceSnapshotKey(clientId, key)
|
||||
}
|
||||
|
||||
getListData = async(): Promise<LX.Sync.ListData> => {
|
||||
getListData = async(): Promise<LX.Sync.List.ListData> => {
|
||||
return getLocalListData()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import fs from 'node:fs'
|
|||
import path from 'node:path'
|
||||
import syncLog from '../../../log'
|
||||
import { getUserConfig, type UserDataManage } from '../../user/data'
|
||||
import { File } from '../../../constants'
|
||||
import { File } from '../../../../../../common/constants_sync'
|
||||
import { checkAndCreateDirSync } from '../../utils'
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ interface SnapshotInfo {
|
|||
latest: string | null
|
||||
time: number
|
||||
list: string[]
|
||||
clients: Record<string, LX.Sync.ListInfo>
|
||||
clients: Record<string, LX.Sync.List.ListInfo>
|
||||
}
|
||||
export class SnapshotDataManage {
|
||||
userDataManage: UserDataManage
|
||||
|
@ -70,7 +70,7 @@ export class SnapshotDataManage {
|
|||
|
||||
getSnapshot = async(name: string) => {
|
||||
const filePath = path.join(this.snapshotDir, `snapshot_${name}`)
|
||||
let listData: LX.Sync.ListData
|
||||
let listData: LX.Sync.List.ListData
|
||||
try {
|
||||
listData = JSON.parse((await fs.promises.readFile(filePath)).toString('utf-8'))
|
||||
} catch (err) {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// 这个文件导出的方法将暴露给客户端调用,第一个参数固定为当前 socket 对象
|
||||
// import { throttle } from '@common/utils/common'
|
||||
// import { sendSyncActionList } from '@main/modules/winMain'
|
||||
// import { SYNC_CLOSE_CODE } from '@/constants'
|
||||
import { SYNC_CLOSE_CODE } from '@main/modules/sync/constants'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { getUserSpace } from '@main/modules/sync/server/user'
|
||||
import { handleRemoteListAction } from '@main/modules/sync/utils'
|
||||
// import { encryptMsg } from '@/utils/tools'
|
||||
|
@ -108,7 +109,7 @@ import { handleRemoteListAction } from '@main/modules/sync/utils'
|
|||
// }
|
||||
// }
|
||||
|
||||
// export const sendListAction = async(action: LX.Sync.ActionList) => {
|
||||
// export const sendListAction = async(action: LX.Sync.List.ActionList) => {
|
||||
// console.log('sendListAction', action.action)
|
||||
// // io.sockets
|
||||
// await broadcast('list:sync:action', action)
|
||||
|
@ -144,7 +145,8 @@ import { handleRemoteListAction } from '@main/modules/sync/utils'
|
|||
// // }
|
||||
// }
|
||||
|
||||
export const onListSyncAction = async(socket: LX.Sync.Server.Socket, action: LX.Sync.ActionList) => {
|
||||
export const onListSyncAction = async(socket: LX.Sync.Server.Socket, action: LX.Sync.List.ActionList) => {
|
||||
if (!socket.moduleReadys.list) return
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
await handleRemoteListAction(action).then(async updated => {
|
||||
if (!updated) {
|
||||
|
@ -156,8 +158,8 @@ export const onListSyncAction = async(socket: LX.Sync.Server.Socket, action: LX.
|
|||
const currentUserName = socket.userInfo.name
|
||||
const currentId = socket.keyInfo.clientId
|
||||
socket.broadcast((client) => {
|
||||
if (client.keyInfo.clientId == currentId || !client.isReady || client.userInfo.name != currentUserName) return
|
||||
void client.remoteSyncList.onListSyncAction(action)
|
||||
if (client.keyInfo.clientId == currentId || !client.moduleReadys?.list || client.userInfo.name != currentUserName) return
|
||||
void client.remoteQueueList.onListSyncAction(action)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export * as handler from './handler'
|
||||
export { default as sync } from './sync'
|
||||
export { sync } from './sync'
|
||||
export * from './localEvent'
|
||||
|
|
|
@ -5,13 +5,13 @@ import { getUserSpace } from '../../../user'
|
|||
let unregisterLocalListAction: (() => void) | null
|
||||
|
||||
|
||||
const sendListAction = async(wss: LX.Sync.Server.SocketServer, action: LX.Sync.ActionList) => {
|
||||
const sendListAction = async(wss: LX.Sync.Server.SocketServer, action: LX.Sync.List.ActionList) => {
|
||||
// console.log('sendListAction', action.action)
|
||||
const userSpace = getUserSpace()
|
||||
const key = await userSpace.listManage.createSnapshot()
|
||||
for (const client of wss.clients) {
|
||||
if (!client.isReady) return
|
||||
void client.remoteSyncList.onListSyncAction(action).then(() => {
|
||||
if (!client.moduleReadys?.list) continue
|
||||
void client.remoteQueueList.onListSyncAction(action).then(() => {
|
||||
void userSpace.listManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
})
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ export const registerEvent = (wss: LX.Sync.Server.SocketServer) => {
|
|||
// unregisterLocalListAction?.()
|
||||
// unregisterLocalListAction = null
|
||||
// })
|
||||
unregisterEvent()
|
||||
unregisterLocalListAction = registerListActionEvent((action) => {
|
||||
void sendListAction(wss, action)
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { SYNC_CLOSE_CODE } from '../../../../constants'
|
||||
// import { SYNC_CLOSE_CODE } from '../../../../constants'
|
||||
import { getUserSpace, getUserConfig } from '../../../user'
|
||||
import { getLocalListData, setLocalListData } from '@main/modules/sync/utils'
|
||||
// import { LIST_IDS } from '@common/constants'
|
||||
|
@ -9,7 +9,7 @@ import { getLocalListData, setLocalListData } from '@main/modules/sync/utils'
|
|||
let syncingId: string | null = null
|
||||
const wait = async(time = 1000) => await new Promise((resolve, reject) => setTimeout(resolve, time))
|
||||
|
||||
const patchListData = (listData: Partial<LX.Sync.ListData>): LX.Sync.ListData => {
|
||||
const patchListData = (listData: Partial<LX.Sync.List.ListData>): LX.Sync.List.ListData => {
|
||||
return Object.assign({
|
||||
defaultList: [],
|
||||
loveList: [],
|
||||
|
@ -17,39 +17,39 @@ const patchListData = (listData: Partial<LX.Sync.ListData>): LX.Sync.ListData =>
|
|||
}, listData)
|
||||
}
|
||||
|
||||
const getRemoteListData = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.ListData> => {
|
||||
const getRemoteListData = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.List.ListData> => {
|
||||
console.log('getRemoteListData')
|
||||
return patchListData(await socket.remoteSyncList.list_sync_get_list_data())
|
||||
return patchListData(await socket.remoteQueueList.list_sync_get_list_data())
|
||||
}
|
||||
|
||||
const getRemoteListMD5 = async(socket: LX.Sync.Server.Socket): Promise<string> => {
|
||||
return socket.remoteSyncList.list_sync_get_md5()
|
||||
return socket.remoteQueueList.list_sync_get_md5()
|
||||
}
|
||||
|
||||
// const getLocalListData = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.ListData> => {
|
||||
// const getLocalListData = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.List.ListData> => {
|
||||
// return getUserSpace(socket.userInfo.name).listManage.getListData()
|
||||
// }
|
||||
const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.ListSyncMode> => {
|
||||
return socket.remoteSyncList.list_sync_get_sync_mode()
|
||||
const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.List.SyncMode> => {
|
||||
return socket.remoteQueueList.list_sync_get_sync_mode()
|
||||
}
|
||||
|
||||
const finishedSync = async(socket: LX.Sync.Server.Socket) => {
|
||||
await socket.remoteSyncList.list_sync_finished()
|
||||
await socket.remoteQueueList.list_sync_finished()
|
||||
}
|
||||
|
||||
|
||||
const setLocalList = async(socket: LX.Sync.Server.Socket, listData: LX.Sync.ListData) => {
|
||||
const setLocalList = async(socket: LX.Sync.Server.Socket, listData: LX.Sync.List.ListData) => {
|
||||
await setLocalListData(listData)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
return userSpace.listManage.createSnapshot()
|
||||
}
|
||||
|
||||
const overwriteRemoteListData = async(socket: LX.Sync.Server.Socket, listData: LX.Sync.ListData, key: string, excludeIds: string[] = []) => {
|
||||
const overwriteRemoteListData = async(socket: LX.Sync.Server.Socket, listData: LX.Sync.List.ListData, key: string, excludeIds: string[] = []) => {
|
||||
const action = { action: 'list_data_overwrite', data: listData } as const
|
||||
const tasks: Array<Promise<void>> = []
|
||||
socket.broadcast((client) => {
|
||||
if (excludeIds.includes(client.keyInfo.clientId) || client.userInfo.name != socket.userInfo.name || !client.isReady) return
|
||||
tasks.push(client.remoteSyncList.onListSyncAction(action).then(async() => {
|
||||
if (excludeIds.includes(client.keyInfo.clientId) || client.userInfo.name != socket.userInfo.name || !client.moduleReadys?.list) return
|
||||
tasks.push(client.remoteQueueList.onListSyncAction(action).then(async() => {
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
return userSpace.listManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
|
@ -59,14 +59,14 @@ const overwriteRemoteListData = async(socket: LX.Sync.Server.Socket, listData: L
|
|||
if (!tasks.length) return
|
||||
await Promise.all(tasks)
|
||||
}
|
||||
const setRemotelList = async(socket: LX.Sync.Server.Socket, listData: LX.Sync.ListData, key: string): Promise<void> => {
|
||||
await socket.remoteSyncList.list_sync_set_list_data(listData)
|
||||
const setRemotelList = async(socket: LX.Sync.Server.Socket, listData: LX.Sync.List.ListData, key: string): Promise<void> => {
|
||||
await socket.remoteQueueList.list_sync_set_list_data(listData)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
await userSpace.listManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
}
|
||||
|
||||
type UserDataObj = Map<string, LX.List.UserListInfoFull>
|
||||
const createUserListDataObj = (listData: LX.Sync.ListData): UserDataObj => {
|
||||
const createUserListDataObj = (listData: LX.Sync.List.ListData): UserDataObj => {
|
||||
const userListDataObj: UserDataObj = new Map()
|
||||
for (const list of listData.userList) userListDataObj.set(list.id, list)
|
||||
return userListDataObj
|
||||
|
@ -111,9 +111,9 @@ const handleMergeList = (
|
|||
}
|
||||
return ids.map(id => map.get(id)) as LX.Music.MusicInfo[]
|
||||
}
|
||||
const mergeList = (socket: LX.Sync.Server.Socket, sourceListData: LX.Sync.ListData, targetListData: LX.Sync.ListData): LX.Sync.ListData => {
|
||||
const mergeList = (socket: LX.Sync.Server.Socket, sourceListData: LX.Sync.List.ListData, targetListData: LX.Sync.List.ListData): LX.Sync.List.ListData => {
|
||||
const addMusicLocationType = getUserConfig(socket.userInfo.name)['list.addMusicLocationType']
|
||||
const newListData: LX.Sync.ListData = {
|
||||
const newListData: LX.Sync.List.ListData = {
|
||||
defaultList: [],
|
||||
loveList: [],
|
||||
userList: [],
|
||||
|
@ -147,8 +147,8 @@ const mergeList = (socket: LX.Sync.Server.Socket, sourceListData: LX.Sync.ListDa
|
|||
|
||||
return newListData
|
||||
}
|
||||
const overwriteList = (sourceListData: LX.Sync.ListData, targetListData: LX.Sync.ListData): LX.Sync.ListData => {
|
||||
const newListData: LX.Sync.ListData = {
|
||||
const overwriteList = (sourceListData: LX.Sync.List.ListData, targetListData: LX.Sync.List.ListData): LX.Sync.List.ListData => {
|
||||
const newListData: LX.Sync.List.ListData = {
|
||||
defaultList: [],
|
||||
loveList: [],
|
||||
userList: [],
|
||||
|
@ -171,16 +171,13 @@ const overwriteList = (sourceListData: LX.Sync.ListData, targetListData: LX.Sync
|
|||
return newListData
|
||||
}
|
||||
|
||||
const handleMergeListData = async(socket: LX.Sync.Server.Socket): Promise<[LX.Sync.ListData, boolean, boolean]> => {
|
||||
const mode: LX.Sync.ListSyncMode = await getSyncMode(socket)
|
||||
const handleMergeListData = async(socket: LX.Sync.Server.Socket): Promise<[LX.Sync.List.ListData, boolean, boolean]> => {
|
||||
const mode: LX.Sync.List.SyncMode = await getSyncMode(socket)
|
||||
|
||||
if (mode == 'cancel') {
|
||||
socket.close(SYNC_CLOSE_CODE.normal)
|
||||
throw new Error('cancel')
|
||||
}
|
||||
if (mode == 'cancel') throw new Error('cancel')
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalListData()])
|
||||
console.log('handleMergeListData', 'remoteListData, localListData')
|
||||
let listData: LX.Sync.ListData
|
||||
let listData: LX.Sync.List.ListData
|
||||
let requiredUpdateLocalListData = true
|
||||
let requiredUpdateRemoteListData = true
|
||||
switch (mode) {
|
||||
|
@ -206,9 +203,7 @@ const handleMergeListData = async(socket: LX.Sync.Server.Socket): Promise<[LX.Sy
|
|||
break
|
||||
// case 'none': return null
|
||||
// case 'cancel':
|
||||
default:
|
||||
socket.close(SYNC_CLOSE_CODE.normal)
|
||||
throw new Error('cancel')
|
||||
default: throw new Error('cancel')
|
||||
}
|
||||
return [listData, requiredUpdateLocalListData, requiredUpdateRemoteListData]
|
||||
}
|
||||
|
@ -299,12 +294,12 @@ const checkListLatest = async(socket: LX.Sync.Server.Socket) => {
|
|||
if (latest && userCurrentListInfoKey != currentListInfoKey) await userSpace.listManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, currentListInfoKey)
|
||||
return latest
|
||||
}
|
||||
const handleMergeListDataFromSnapshot = async(socket: LX.Sync.Server.Socket, snapshot: LX.Sync.ListData) => {
|
||||
const handleMergeListDataFromSnapshot = async(socket: LX.Sync.Server.Socket, snapshot: LX.Sync.List.ListData) => {
|
||||
if (await checkListLatest(socket)) return
|
||||
|
||||
const addMusicLocationType = getUserConfig(socket.userInfo.name)['list.addMusicLocationType']
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalListData()])
|
||||
const newListData: LX.Sync.ListData = {
|
||||
const newListData: LX.Sync.List.ListData = {
|
||||
defaultList: [],
|
||||
loveList: [],
|
||||
userList: [],
|
||||
|
@ -413,7 +408,7 @@ const syncList = async(socket: LX.Sync.Server.Socket) => {
|
|||
// await fsPromises.unlink(filePath)
|
||||
// }
|
||||
|
||||
export default async(socket: LX.Sync.Server.Socket) => {
|
||||
export const sync = async(socket: LX.Sync.Server.Socket) => {
|
||||
let disconnected = false
|
||||
socket.onClose(() => {
|
||||
disconnected = true
|
||||
|
@ -428,7 +423,8 @@ export default async(socket: LX.Sync.Server.Socket) => {
|
|||
|
||||
syncingId = socket.keyInfo.clientId
|
||||
await syncList(socket).then(async() => {
|
||||
return finishedSync(socket)
|
||||
await finishedSync(socket)
|
||||
socket.moduleReadys.list = true
|
||||
}).finally(() => {
|
||||
syncingId = null
|
||||
})
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import type http from 'http'
|
||||
import { SYNC_CODE } from '@common/constants'
|
||||
import {
|
||||
aesEncrypt,
|
||||
aesDecrypt,
|
||||
|
@ -10,6 +9,7 @@ import querystring from 'node:querystring'
|
|||
import { getUserSpace, createClientKeyInfo } from '../user'
|
||||
import { toMD5 } from '../utils'
|
||||
import { getComputerName } from '../../utils'
|
||||
import { SYNC_CODE } from '@common/constants_sync'
|
||||
|
||||
const requestIps = new Map<string, number>()
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import http, { type IncomingMessage } from 'node:http'
|
||||
import url from 'node:url'
|
||||
import { WebSocketServer } from 'ws'
|
||||
import { modules, callObj } from '../modules'
|
||||
import { registerLocalSyncEvent, callObj, sync, unregisterLocalSyncEvent } from './sync'
|
||||
import { authCode, authConnect } from './auth'
|
||||
import { getAddress } from '../../utils'
|
||||
import { SYNC_CLOSE_CODE, SYNC_CODE } from '../../constants'
|
||||
import { SYNC_CLOSE_CODE, SYNC_CODE } from '@common/constants_sync'
|
||||
import { getUserSpace, releaseUserSpace, getServerId, initServerInfo } from '../user'
|
||||
import { createMsg2call } from 'message2call'
|
||||
import log from '../../log'
|
||||
|
@ -23,6 +22,8 @@ let status: LX.Sync.ServerStatus = {
|
|||
|
||||
let stopingServer = false
|
||||
|
||||
let host = 'http://localhost'
|
||||
|
||||
const codeTools: {
|
||||
timeout: NodeJS.Timer | null
|
||||
start: () => void
|
||||
|
@ -42,46 +43,25 @@ const codeTools: {
|
|||
},
|
||||
}
|
||||
|
||||
const syncData = async(socket: LX.Sync.Server.Socket) => {
|
||||
let disconnected = false
|
||||
socket.onClose(() => {
|
||||
disconnected = true
|
||||
})
|
||||
for (const module of Object.values(modules)) {
|
||||
await module.sync(socket)
|
||||
if (disconnected) throw new Error('disconnected')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const registerLocalSyncEvent = async(wss: LX.Sync.Server.SocketServer) => {
|
||||
for (const module of Object.values(modules)) {
|
||||
module.registerEvent(wss)
|
||||
}
|
||||
}
|
||||
|
||||
const unregisterLocalSyncEvent = () => {
|
||||
for (const module of Object.values(modules)) {
|
||||
module.unregisterEvent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const checkDuplicateClient = (newSocket: LX.Sync.Server.Socket) => {
|
||||
for (const client of [...wss!.clients]) {
|
||||
if (client === newSocket || client.keyInfo.clientId != newSocket.keyInfo.clientId) continue
|
||||
log.info('duplicate client', client.userInfo.name, client.keyInfo.deviceName)
|
||||
client.isReady = false
|
||||
for (const name of Object.keys(client.moduleReadys) as Array<keyof LX.Sync.Server.Socket['moduleReadys']>) {
|
||||
client.moduleReadys[name] = false
|
||||
}
|
||||
client.close(SYNC_CLOSE_CODE.normal)
|
||||
}
|
||||
}
|
||||
|
||||
const handleConnection = async(socket: LX.Sync.Server.Socket, request: IncomingMessage) => {
|
||||
const queryData = url.parse(request.url as string, true).query as Record<string, string>
|
||||
const queryData = new URL(request.url as string, host).searchParams
|
||||
const clientId = queryData.get('i')
|
||||
|
||||
// // if (typeof socket.handshake.query.i != 'string') return socket.disconnect(true)
|
||||
const userSpace = getUserSpace()
|
||||
const keyInfo = userSpace.dataManage.getClientKeyInfo(queryData.i)
|
||||
const keyInfo = userSpace.dataManage.getClientKeyInfo(clientId)
|
||||
if (!keyInfo) {
|
||||
socket.close(SYNC_CLOSE_CODE.failed)
|
||||
return
|
||||
|
@ -95,7 +75,7 @@ const handleConnection = async(socket: LX.Sync.Server.Socket, request: IncomingM
|
|||
checkDuplicateClient(socket)
|
||||
|
||||
try {
|
||||
await syncData(socket)
|
||||
await sync(socket)
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
log.warn(err)
|
||||
|
@ -174,6 +154,12 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
|
||||
wss.on('connection', function(socket, request) {
|
||||
socket.isReady = false
|
||||
socket.moduleReadys = {
|
||||
list: false,
|
||||
}
|
||||
socket.feature = {
|
||||
list: false,
|
||||
}
|
||||
socket.on('pong', () => {
|
||||
socket.isAlive = true
|
||||
})
|
||||
|
@ -182,10 +168,12 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
// const events = new Map<keyof LX.Sync.ActionSyncType, Array<(err: Error | null, data: LX.Sync.ActionSyncType[keyof LX.Sync.ActionSyncType]) => void>>()
|
||||
// let events: Partial<{ [K in keyof LX.Sync.ActionSyncType]: Array<(data: LX.Sync.ActionSyncType[K]) => void> }> = {}
|
||||
let closeEvents: Array<(err: Error) => (void | Promise<void>)> = []
|
||||
const msg2call = createMsg2call<LX.Sync.ClientActions>({
|
||||
let disconnected = false
|
||||
const msg2call = createMsg2call<LX.Sync.ClientSyncActions>({
|
||||
funcsObj: callObj,
|
||||
timeout: 120 * 1000,
|
||||
sendMessage(data) {
|
||||
if (disconnected) throw new Error('disconnected')
|
||||
void encryptMsg(socket.keyInfo, JSON.stringify(data)).then((data) => {
|
||||
// console.log('sendData', eventName)
|
||||
socket.send(data)
|
||||
|
@ -200,13 +188,14 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
},
|
||||
onError(error, path, groupName) {
|
||||
const name = groupName ?? ''
|
||||
log.error(`sync call ${name} ${path.join('.')} error:`, error)
|
||||
const deviceName = socket.keyInfo?.deviceName ?? ''
|
||||
log.error(`sync call ${deviceName} ${name} ${path.join('.')} error:`, error)
|
||||
if (groupName == null) return
|
||||
socket.close(SYNC_CLOSE_CODE.failed)
|
||||
},
|
||||
})
|
||||
socket.remote = msg2call.remote
|
||||
socket.remoteSyncList = msg2call.createSyncRemote('list')
|
||||
socket.remoteQueueList = msg2call.createQueueRemote('list')
|
||||
socket.addEventListener('message', ({ data }) => {
|
||||
if (typeof data != 'string') return
|
||||
void decryptMsg(socket.keyInfo, data).then((data) => {
|
||||
|
@ -233,14 +222,15 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
log.error(err?.message)
|
||||
}
|
||||
closeEvents = []
|
||||
disconnected = true
|
||||
msg2call.onDestroy()
|
||||
if (socket.isReady) {
|
||||
log.info('deconnection', socket.userInfo.name, socket.keyInfo.deviceName)
|
||||
// events = {}
|
||||
if (!status.devices.length) handleUnconnection()
|
||||
} else {
|
||||
const queryData = url.parse(request.url as string, true).query as Record<string, string>
|
||||
log.info('deconnection', queryData.i)
|
||||
const queryData = new URL(request.url as string, host).searchParams
|
||||
log.info('deconnection', queryData.get('i'))
|
||||
}
|
||||
})
|
||||
socket.onClose = function(handler: typeof closeEvents[number]) {
|
||||
|
@ -311,6 +301,7 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
void registerLocalSyncEvent(wss as LX.Sync.Server.SocketServer)
|
||||
})
|
||||
|
||||
host = `http://${ip}:${port}`
|
||||
httpServer.listen(port, ip)
|
||||
})
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { modules } from '../../modules'
|
||||
|
||||
export const registerLocalSyncEvent = async(wss: LX.Sync.Server.SocketServer) => {
|
||||
unregisterLocalSyncEvent()
|
||||
for (const module of Object.values(modules)) {
|
||||
module.registerEvent(wss)
|
||||
}
|
||||
}
|
||||
|
||||
export const unregisterLocalSyncEvent = () => {
|
||||
for (const module of Object.values(modules)) {
|
||||
module.unregisterEvent()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// 这个文件导出的方法将暴露给客户端调用,第一个参数固定为当前 socket 对象
|
||||
// import { getUserSpace } from '@/user'
|
||||
import { FeaturesList } from '../../../../../../common/constants_sync'
|
||||
import { modules } from '../../modules'
|
||||
|
||||
|
||||
export const onFeatureChanged = async(socket: LX.Sync.Server.Socket, feature: LX.Sync.EnabledFeatures) => {
|
||||
// const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const beforeFeature = socket.feature
|
||||
|
||||
for (const name of FeaturesList) {
|
||||
if (feature[name] == beforeFeature[name]) continue
|
||||
if (feature[name]) {
|
||||
await modules[name].sync(socket).then(() => {
|
||||
beforeFeature[name] = true
|
||||
}).catch(_ => _)
|
||||
} else {
|
||||
socket.moduleReadys[name] = false
|
||||
beforeFeature[name] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import * as handler from './handler'
|
||||
import { callObj as _callObj } from '../../modules'
|
||||
export { sync } from './sync'
|
||||
export { modules } from '../../modules'
|
||||
export * from './event'
|
||||
|
||||
export const callObj = {
|
||||
...handler,
|
||||
..._callObj,
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { FeaturesList } from '../../../../../../common/constants_sync'
|
||||
import { featureVersion, modules } from '../../modules'
|
||||
|
||||
|
||||
export const sync = async(socket: LX.Sync.Server.Socket) => {
|
||||
let disconnected = false
|
||||
socket.onClose(() => {
|
||||
disconnected = true
|
||||
})
|
||||
const enabledFeatures = await socket.remote.getEnabledFeatures('desktop-app', featureVersion)
|
||||
|
||||
if (disconnected) throw new Error('disconnected')
|
||||
for (const moduleName of FeaturesList) {
|
||||
if (enabledFeatures[moduleName]) {
|
||||
await modules[moduleName].sync(socket).then(() => {
|
||||
socket.feature[moduleName] = true
|
||||
}).catch(_ => _)
|
||||
}
|
||||
if (disconnected) throw new Error('disconnected')
|
||||
}
|
||||
await socket.remote.finished()
|
||||
}
|
|
@ -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 '../../constants'
|
||||
import { File } from '../../../../../common/constants_sync'
|
||||
|
||||
|
||||
interface ServerInfo {
|
||||
|
@ -111,7 +111,7 @@ export class UserDataManage {
|
|||
this.saveDevicesInfoThrottle()
|
||||
}
|
||||
|
||||
getClientKeyInfo = (clientId?: string): LX.Sync.ServerKeyInfo | null => {
|
||||
getClientKeyInfo = (clientId?: string | null): LX.Sync.ServerKeyInfo | null => {
|
||||
if (!clientId) return null
|
||||
return this.devicesInfo.clients[clientId] ?? null
|
||||
}
|
||||
|
|
|
@ -90,8 +90,8 @@ export const rsaDecrypt = (buffer: Buffer, key: string): Buffer => {
|
|||
return privateDecrypt({ key, padding: constants.RSA_PKCS1_OAEP_PADDING }, buffer)
|
||||
}
|
||||
|
||||
export const getLocalListData = async(): Promise<LX.Sync.ListData> => {
|
||||
const lists: LX.Sync.ListData = {
|
||||
export const getLocalListData = async(): Promise<LX.Sync.List.ListData> => {
|
||||
const lists: LX.Sync.List.ListData = {
|
||||
defaultList: await global.lx.worker.dbService.getListMusics(LIST_IDS.DEFAULT),
|
||||
loveList: await global.lx.worker.dbService.getListMusics(LIST_IDS.LOVE),
|
||||
userList: [],
|
||||
|
@ -106,12 +106,12 @@ export const getLocalListData = async(): Promise<LX.Sync.ListData> => {
|
|||
return lists
|
||||
}
|
||||
|
||||
export const setLocalListData = async(listData: LX.Sync.ListData) => {
|
||||
export const setLocalListData = async(listData: LX.Sync.List.ListData) => {
|
||||
await global.lx.event_list.list_data_overwrite(listData, true)
|
||||
}
|
||||
|
||||
|
||||
export const registerListActionEvent = (sendListAction: (action: LX.Sync.ActionList) => (void | Promise<void>)) => {
|
||||
export const registerListActionEvent = (sendListAction: (action: LX.Sync.List.ActionList) => (void | Promise<void>)) => {
|
||||
const list_data_overwrite = async(listData: MakeOptional<LX.List.ListDataFull, 'tempList'>, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_data_overwrite', data: listData })
|
||||
|
@ -188,7 +188,7 @@ export const registerListActionEvent = (sendListAction: (action: LX.Sync.ActionL
|
|||
}
|
||||
}
|
||||
|
||||
export const handleRemoteListAction = async({ action, data }: LX.Sync.ActionList) => {
|
||||
export const handleRemoteListAction = async({ action, data }: LX.Sync.List.ActionList) => {
|
||||
// console.log('handleRemoteListAction', action)
|
||||
|
||||
switch (action) {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { WIN_MAIN_RENDERER_EVENT_NAME } from '@common/ipcNames'
|
|||
import { startServer, stopServer, getServerStatus, generateCode, connectServer, disconnectServer, getClientStatus } from '@main/modules/sync'
|
||||
import { sendEvent } from '../main'
|
||||
|
||||
let selectModeListenr: ((mode: LX.Sync.ListSyncMode | null) => void) | null = null
|
||||
let selectModeListenr: ((mode: LX.Sync.List.SyncMode | null) => void) | null = null
|
||||
|
||||
export default () => {
|
||||
mainHandle<LX.Sync.SyncServiceActions, any>(WIN_MAIN_RENDERER_EVENT_NAME.sync_action, async({ params: data }) => {
|
||||
|
@ -46,7 +46,7 @@ export const sendServerStatus = (status: LX.Sync.ServerStatus) => {
|
|||
data: status,
|
||||
})
|
||||
}
|
||||
export const sendSelectMode = (deviceName: string, listener: (mode: LX.Sync.ListSyncMode | null) => void) => {
|
||||
export const sendSelectMode = (deviceName: string, listener: (mode: LX.Sync.List.SyncMode | null) => void) => {
|
||||
selectModeListenr = listener
|
||||
sendSyncAction({ action: 'select_mode', data: deviceName })
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ import '@common/types/app_setting'
|
|||
import '@common/types/common'
|
||||
import '@common/types/user_api'
|
||||
import '@common/types/sync'
|
||||
import '@common/types/sync_common'
|
||||
import '@common/types/list'
|
||||
import '@common/types/list_sync'
|
||||
import '@common/types/download_list'
|
||||
import '@common/types/music'
|
||||
import '@common/types/player'
|
||||
|
|
|
@ -13,9 +13,13 @@ declare global {
|
|||
keyInfo: ClientKeyInfo
|
||||
urlInfo: UrlInfo
|
||||
}
|
||||
moduleReadys: {
|
||||
list: boolean
|
||||
}
|
||||
|
||||
onClose: (handler: (err: Error) => (void | Promise<void>)) => () => void
|
||||
remoteSyncList: LX.Sync.ServerActions
|
||||
remote: LX.Sync.ServerSyncActions
|
||||
remoteQueueList: LX.Sync.ServerSyncListActions
|
||||
}
|
||||
|
||||
interface UrlInfo {
|
||||
|
@ -31,11 +35,16 @@ declare global {
|
|||
isReady: boolean
|
||||
userInfo: { name: 'default' }
|
||||
keyInfo: ServerKeyInfo
|
||||
feature: LX.Sync.EnabledFeatures
|
||||
moduleReadys: {
|
||||
list: boolean
|
||||
}
|
||||
|
||||
onClose: (handler: (err: Error) => (void | Promise<void>)) => () => void
|
||||
broadcast: (handler: (client: Socket) => void) => void
|
||||
|
||||
remote: LX.Sync.ClientActions
|
||||
remoteSyncList: LX.Sync.ClientActions
|
||||
remote: LX.Sync.ClientSyncActions
|
||||
remoteQueueList: LX.Sync.ClientSyncListActions
|
||||
}
|
||||
type SocketServer = WS.Server<Socket>
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
declare namespace LX {
|
||||
namespace Sync {
|
||||
type ServerSyncActions = WarpPromiseRecord<{
|
||||
onFeatureChanged: (feature: EnabledFeatures) => void
|
||||
}>
|
||||
type ServerSyncListActions = WarpPromiseRecord<{
|
||||
onListSyncAction: (action: LX.Sync.List.ActionList) => void
|
||||
}>
|
||||
|
||||
type ClientSyncActions = WarpPromiseRecord<{
|
||||
getEnabledFeatures: (serverType: ServerType, supportedFeatures: SupportedFeatures) => EnabledFeatures
|
||||
finished: () => void
|
||||
}>
|
||||
type ClientSyncListActions = WarpPromiseRecord<{
|
||||
onListSyncAction: (action: LX.Sync.List.ActionList) => void
|
||||
list_sync_get_md5: () => string
|
||||
list_sync_get_sync_mode: () => LX.Sync.List.SyncMode
|
||||
list_sync_get_list_data: () => LX.Sync.List.ListData
|
||||
list_sync_set_list_data: (data: LX.Sync.List.ListData) => void
|
||||
list_sync_finished: () => void
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"isolatedModules": true,
|
||||
"moduleResolution": "nodenext",
|
||||
"paths": { /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
"@common/*": ["common/*"],
|
||||
// "@renderer/*": ["renderer/*"],
|
||||
|
|
|
@ -2,7 +2,7 @@ import { markRaw, onBeforeUnmount } from '@common/utils/vueTools'
|
|||
import { onSyncAction, sendSyncAction } from '@renderer/utils/ipc'
|
||||
import { sync } from '@renderer/store'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { SYNC_CODE } from '@common/constants'
|
||||
import { SYNC_CODE } from '@common/constants_sync'
|
||||
|
||||
export default () => {
|
||||
const handleSyncList = (event: LX.Sync.SyncMainWindowActions) => {
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"isolatedModules": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "nodenext",
|
||||
"resolveJsonModule": true,
|
||||
"paths": { /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
"@common/*": ["common/*"],
|
||||
"@renderer/*": ["renderer/*"],
|
||||
|
|
|
@ -2,6 +2,7 @@ import '@common/types/app_setting'
|
|||
import '@common/types/common'
|
||||
import '@common/types/user_api'
|
||||
import '@common/types/sync'
|
||||
import '@common/types/list_sync'
|
||||
import '@common/types/music'
|
||||
import '@common/types/list'
|
||||
import '@common/types/download_list'
|
||||
|
|
|
@ -46,7 +46,7 @@ import { openUrl } from '@common/utils/electron'
|
|||
import { useI18n } from '@renderer/plugins/i18n'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import { debounce } from '@common/utils/common'
|
||||
import { SYNC_CODE } from '@common/constants'
|
||||
import { SYNC_CODE } from '@common/constants_sync'
|
||||
|
||||
export default {
|
||||
name: 'SettingSync',
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
"target": "ESNext",
|
||||
"allowJs": true,
|
||||
"module": "esnext",
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "nodenext",
|
||||
"resolveJsonModule": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./src", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": { /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
|
|
Loading…
Reference in New Issue