修改同步逻辑

pull/1583/head
lyswhut 2023-08-28 13:39:23 +08:00
parent 71b84fb10d
commit c6f4bfa875
45 changed files with 604 additions and 482 deletions

View File

@ -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',
// ],
}

503
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -30,5 +30,5 @@
### 其他
- 更新 electron 到 v22.3.21
- 更新 electron 到 v22.3.22
- 重构同步服务端功能部分代码,使其更易扩展新功能

View File

@ -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

View File

@ -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

View File

@ -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>
}
}

34
src/common/types/list_sync.d.ts vendored Normal file
View File

@ -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'
}
}
}

View File

@ -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 }>
}
}

View File

@ -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
}>
}
}

View File

@ -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`)

View File

@ -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:

View File

@ -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>

View File

@ -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

View File

@ -8,3 +8,7 @@ export const callObj = Object.assign({}, list.handler)
export const modules = {
list,
}
export const featureVersion = {
list: 1,
} as const

View File

@ -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()
})
}

View File

@ -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)
})
}

View File

@ -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,
}
}
}

View File

@ -0,0 +1,8 @@
import * as handler from './handler'
import { callObj as _callObj } from '../modules'
export { modules } from '../modules'
export const callObj = {
...handler,
..._callObj,
}

View File

@ -1,4 +1,4 @@
import { File } from './constants'
import { File } from '../../../common/constants_sync'
import fs from 'node:fs'
import path from 'node:path'

View File

@ -10,3 +10,7 @@ export const modules = {
export { ListManage } from './list'
export const featureVersion = {
list: 1,
} as const

View File

@ -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()
}
}

View File

@ -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) {

View File

@ -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)
})
})
}

View File

@ -1,3 +1,3 @@
export * as handler from './handler'
export { default as sync } from './sync'
export { sync } from './sync'
export * from './localEvent'

View File

@ -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)
})

View File

@ -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
})

View File

@ -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>()

View File

@ -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)
})

View File

@ -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()
}
}

View File

@ -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
}
}
}

View File

@ -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,
}

View File

@ -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()
}

View File

@ -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
}

View File

@ -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) {

View File

@ -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 })
}

View File

@ -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'

View File

@ -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>
}

25
src/main/types/sync_common.d.ts vendored Normal file
View File

@ -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
}>
}
}

View File

@ -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/*"],

View File

@ -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) => {

View File

@ -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/*"],

View File

@ -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'

View File

@ -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',

View File

@ -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. */