完善同步
parent
e75ab3a7d7
commit
3399333360
|
@ -523,14 +523,14 @@
|
|||
"sync__merge_tip_desc": "Merge the two lists together, the same song will be removed (the song of the merged person is removed), and different songs will be added.",
|
||||
"sync__other_label": "Other",
|
||||
"sync__other_tip": "Other: ",
|
||||
"sync__other_tip_desc": "\"Only use real-time synchronization function\" will not modify the lists of both parties, only real-time synchronization operations; \"Cancel synchronization\" will directly disconnect the two parties.",
|
||||
"sync__other_tip_desc": "\"Cancel Sync\" will directly disconnect the two parties.",
|
||||
"sync__overwrite": "Full coverage",
|
||||
"sync__overwrite_btn_cancel": "Cancel sync",
|
||||
"sync__overwrite_btn_local_remote": "Local list Overwrite remote list",
|
||||
"sync__overwrite_btn_none": "Only use real-time synchronization",
|
||||
"sync__overwrite_btn_remote_local": "Remote list Overwrite local list",
|
||||
"sync__overwrite_label": "Cover",
|
||||
"sync__overwrite_tip": "Cover: ",
|
||||
"sync__overwrite_tip": "Over: ",
|
||||
"sync__overwrite_tip_desc": "The list with the same ID of the covered person and the covered list will be deleted and replaced with the list of the covered person (lists with different list IDs will be merged together). If you check Complete coverage, all lists of the covered person will be moved. \nDivide, and then replace with a list of overriders.",
|
||||
"sync__title": "Choose how to synchronize the list with {name}",
|
||||
"sync_status_disabled": "not connected",
|
||||
|
|
|
@ -526,7 +526,7 @@
|
|||
"sync__merge_tip_desc": "将两边的列表合并到一起,相同的歌曲将被去掉(去掉的是被合并者的歌曲),不同的歌曲将被添加。",
|
||||
"sync__other_label": "其他",
|
||||
"sync__other_tip": "其他:",
|
||||
"sync__other_tip_desc": "“仅使用实时同步功能”将不修改双方的列表,仅实时同步操作;“取消同步”将直接断开双方的连接。",
|
||||
"sync__other_tip_desc": "“取消同步”将直接断开双方的连接。",
|
||||
"sync__overwrite": "完全覆盖",
|
||||
"sync__overwrite_btn_cancel": "取消同步",
|
||||
"sync__overwrite_btn_local_remote": "本机列表 覆盖 远程列表",
|
||||
|
|
|
@ -523,7 +523,7 @@
|
|||
"sync__merge_tip_desc": "將兩邊的列表合併到一起,相同的歌曲將被去掉(去掉的是被合併者的歌曲),不同的歌曲將被添加。",
|
||||
"sync__other_label": "其他",
|
||||
"sync__other_tip": "其他:",
|
||||
"sync__other_tip_desc": "“僅使用實時同步功能”將不修改雙方的列表,僅實時同步操作;“取消同步”將直接斷開雙方的連接。",
|
||||
"sync__other_tip_desc": "“取消同步”將直接斷開雙方的連接。",
|
||||
"sync__overwrite": "完全覆蓋",
|
||||
"sync__overwrite_btn_cancel": "取消同步",
|
||||
"sync__overwrite_btn_local_remote": "本機列表 覆蓋 遠程列表",
|
||||
|
|
|
@ -38,6 +38,7 @@ const handleConnection = (socket: LX.Sync.Client.Socket) => {
|
|||
|
||||
const heartbeatTools = {
|
||||
failedNum: 0,
|
||||
maxTryNum: 3,
|
||||
pingTimeout: null as NodeJS.Timeout | null,
|
||||
delayRetryTimeout: null as NodeJS.Timeout | null,
|
||||
handleOpen() {
|
||||
|
@ -64,16 +65,21 @@ const heartbeatTools = {
|
|||
// client = null
|
||||
if (!client) return
|
||||
|
||||
if (this.failedNum > 3) throw new Error('connect error')
|
||||
if (++this.failedNum > this.maxTryNum) {
|
||||
this.failedNum = 0
|
||||
throw new Error('connect error')
|
||||
}
|
||||
|
||||
this.delayRetryTimeout = setTimeout(() => {
|
||||
this.delayRetryTimeout = null
|
||||
if (!client) return
|
||||
console.log(dateFormat(new Date()), 'reconnnect...')
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: `Try reconnnect... (${this.failedNum}/${this.maxTryNum})`,
|
||||
})
|
||||
connect(client.data.urlInfo, client.data.keyInfo)
|
||||
}, 2000)
|
||||
|
||||
this.failedNum++
|
||||
},
|
||||
clearTimeout() {
|
||||
if (this.delayRetryTimeout) {
|
||||
|
@ -176,23 +182,40 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
|||
message: '',
|
||||
})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
log.r_error(err.stack)
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: err.message,
|
||||
})
|
||||
if (err.message == 'closed') {
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: '',
|
||||
})
|
||||
} else {
|
||||
console.log(err)
|
||||
log.r_error(err.stack)
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: err.message,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
client.addEventListener('close', () => {
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: '',
|
||||
})
|
||||
client.addEventListener('close', ({ code }) => {
|
||||
const err = new Error('closed')
|
||||
for (const handler of closeEvents) void handler(err)
|
||||
closeEvents = []
|
||||
events = {}
|
||||
switch (code) {
|
||||
case SYNC_CLOSE_CODE.normal:
|
||||
// case SYNC_CLOSE_CODE.failed:
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: '',
|
||||
})
|
||||
}
|
||||
})
|
||||
client.addEventListener('error', ({ message }) => {
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -202,6 +225,7 @@ export const disconnect = async() => {
|
|||
client.close(SYNC_CLOSE_CODE.normal)
|
||||
client = null
|
||||
heartbeatTools.clearTimeout()
|
||||
heartbeatTools.failedNum = 0
|
||||
}
|
||||
|
||||
export const getStatus = (): LX.Sync.ClientStatus => status
|
||||
|
|
|
@ -5,13 +5,18 @@ import { SYNC_CODE } from '@common/constants'
|
|||
import log from '../log'
|
||||
import { parseUrl } from './utils'
|
||||
|
||||
let connectId = 0
|
||||
|
||||
const handleConnect = async(host: string, authCode?: string) => {
|
||||
// const hostInfo = await getSyncHost()
|
||||
// console.log(hostInfo)
|
||||
// if (!hostInfo || !hostInfo.host || !hostInfo.port) throw new Error(SYNC_CODE.unknownServiceAddress)
|
||||
const id = connectId
|
||||
const urlInfo = parseUrl(host)
|
||||
await disconnectServer(false)
|
||||
if (id != connectId) return
|
||||
const keyInfo = await handleAuth(urlInfo, authCode)
|
||||
if (id != connectId) return
|
||||
socketConnect(urlInfo, keyInfo)
|
||||
}
|
||||
const handleDisconnect = async() => {
|
||||
|
@ -23,12 +28,9 @@ const connectServer = async(host: string, authCode?: string) => {
|
|||
status: false,
|
||||
message: SYNC_CODE.connecting,
|
||||
})
|
||||
return handleConnect(host, authCode).then(() => {
|
||||
sendSyncStatus({
|
||||
status: true,
|
||||
message: '',
|
||||
})
|
||||
}).catch(async err => {
|
||||
const id = connectId
|
||||
return handleConnect(host, authCode).catch(async err => {
|
||||
if (id != connectId) return
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: err.message,
|
||||
|
@ -49,6 +51,7 @@ const connectServer = async(host: string, authCode?: string) => {
|
|||
const disconnectServer = async(isResetStatus = true) => handleDisconnect().then(() => {
|
||||
log.info('disconnect...')
|
||||
if (isResetStatus) {
|
||||
connectId++
|
||||
sendSyncStatus({
|
||||
status: false,
|
||||
message: '',
|
||||
|
|
|
@ -9,15 +9,15 @@ import log from './log'
|
|||
|
||||
export const getSyncAuthKey = async(serverId: string) => {
|
||||
const store = getStore(STORE_NAMES.SYNC)
|
||||
const keys = store.get('syncAuthKey') as Record<string, LX.Sync.ClientKeyInfo> | null
|
||||
const keys = store.get('syncAuthKey_v3') as Record<string, LX.Sync.ClientKeyInfo> | null
|
||||
if (!keys) return null
|
||||
return keys[serverId] ?? null
|
||||
}
|
||||
export const setSyncAuthKey = async(serverId: string, info: LX.Sync.ClientKeyInfo) => {
|
||||
const store = getStore(STORE_NAMES.SYNC)
|
||||
let keys: Record<string, LX.Sync.ClientKeyInfo> = (store.get('syncAuthKey') as Record<string, LX.Sync.ClientKeyInfo> | null) ?? {}
|
||||
let keys: Record<string, LX.Sync.ClientKeyInfo> = (store.get('syncAuthKey_v3') as Record<string, LX.Sync.ClientKeyInfo> | null) ?? {}
|
||||
keys[serverId] = info
|
||||
store.set('syncAuthKey', keys)
|
||||
store.set('syncAuthKey_v3', keys)
|
||||
}
|
||||
|
||||
let syncHost: string
|
||||
|
@ -73,7 +73,7 @@ const devicesInfo: DevicesInfo = { serverId: '', clients: {}, snapshotInfo: { la
|
|||
let deviceKeys: string[] = []
|
||||
const saveDevicesInfoThrottle = throttle(() => {
|
||||
const store = getStore(STORE_NAMES.SYNC)
|
||||
store.set('keys', devicesInfo.clients)
|
||||
store.set('clients', devicesInfo.clients)
|
||||
})
|
||||
|
||||
const initDeviceInfo = () => {
|
||||
|
@ -82,7 +82,8 @@ const initDeviceInfo = () => {
|
|||
if (serverId) devicesInfo.serverId = serverId
|
||||
else {
|
||||
devicesInfo.serverId = randomBytes(4 * 4).toString('base64')
|
||||
saveDevicesInfoThrottle()
|
||||
const store = getStore(STORE_NAMES.SYNC)
|
||||
store.set('serverId', devicesInfo.serverId)
|
||||
}
|
||||
const devices = store.get('clients') as DevicesInfo['clients'] | undefined
|
||||
if (devices) devicesInfo.clients = devices
|
||||
|
@ -155,6 +156,7 @@ export const saveSnapshotInfo = (info: SnapshotInfo) => {
|
|||
}
|
||||
|
||||
export const getSnapshot = async(name: string) => {
|
||||
console.log('getSnapshot', name)
|
||||
const filePath = path.join(global.lxDataPath, `snapshot_${name}`)
|
||||
let listData: LX.Sync.ListData
|
||||
try {
|
||||
|
@ -166,6 +168,7 @@ export const getSnapshot = async(name: string) => {
|
|||
return listData
|
||||
}
|
||||
export const saveSnapshot = async(name: string, data: string) => {
|
||||
console.log('saveSnapshot', name)
|
||||
const filePath = path.join(global.lxDataPath, `snapshot_${name}`)
|
||||
return fs.promises.writeFile(filePath, data).catch((err) => {
|
||||
log.error(err)
|
||||
|
@ -173,6 +176,7 @@ export const saveSnapshot = async(name: string, data: string) => {
|
|||
})
|
||||
}
|
||||
export const removeSnapshot = async(name: string) => {
|
||||
console.log('removeSnapshot', name)
|
||||
const filePath = path.join(global.lxDataPath, `snapshot_${name}`)
|
||||
return fs.promises.unlink(filePath).catch((err) => {
|
||||
log.error(err)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// import { sendSyncActionList } from '@main/modules/winMain'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants'
|
||||
import { updateDeviceSnapshotKey } from '../../data'
|
||||
import { handleRemoteListAction } from '../../utils'
|
||||
import { createSnapshot, encryptMsg } from '../utils'
|
||||
import { handleRemoteListAction, registerListActionEvent } from '../../utils'
|
||||
import { createSnapshot, encryptMsg, getCurrentListInfoKey } from '../utils'
|
||||
|
||||
let wss: LX.Sync.Server.SocketServer | null
|
||||
let removeListener: (() => void) | null
|
||||
|
@ -29,16 +29,16 @@ const broadcast = async(key: string, data: any, excludeIds: string[] = []) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const sendListAction = async(action: LX.Sync.ActionList) => {
|
||||
const sendListAction = async(action: LX.Sync.ActionList) => {
|
||||
console.log('sendListAction', action.action)
|
||||
// io.sockets
|
||||
await broadcast('list:sync:action', action)
|
||||
await broadcast(await getCurrentListInfoKey(), action)
|
||||
}
|
||||
|
||||
export const registerListHandler = (_wss: LX.Sync.Server.SocketServer, socket: LX.Sync.Server.Socket) => {
|
||||
if (!wss) {
|
||||
wss = _wss
|
||||
// removeListener = registerListActionEvent()
|
||||
removeListener = registerListActionEvent(sendListAction)
|
||||
}
|
||||
|
||||
socket.onRemoteEvent('list:sync:action', (action) => {
|
||||
|
|
|
@ -19,6 +19,7 @@ let status: LX.Sync.ServerStatus = {
|
|||
code: '',
|
||||
devices: [],
|
||||
}
|
||||
let stopingServer = false
|
||||
|
||||
const codeTools: {
|
||||
timeout: NodeJS.Timer | null
|
||||
|
@ -148,6 +149,7 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
// const events = new Map<keyof ActionsType, Array<(err: Error | null, data: LX.Sync.ActionSyncType[keyof LX.Sync.ActionSyncType]) => void>>()
|
||||
// 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>)> = []
|
||||
socket.addEventListener('message', ({ data }) => {
|
||||
if (typeof data === 'string') {
|
||||
let syncData: LX.Sync.ActionSync
|
||||
|
@ -167,11 +169,9 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
})
|
||||
socket.addEventListener('close', () => {
|
||||
const err = new Error('closed')
|
||||
for (const handler of Object.values(events).flat()) {
|
||||
// @ts-expect-error
|
||||
handler(err, null)
|
||||
}
|
||||
for (const handler of closeEvents) void handler(err)
|
||||
events = {}
|
||||
closeEvents = []
|
||||
if (!status.devices.length) handleUnconnection()
|
||||
log.info('deconnection', socket.keyInfo.deviceName)
|
||||
})
|
||||
|
@ -186,6 +186,12 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
eventArr!.splice(eventArr!.indexOf(handler), 1)
|
||||
}
|
||||
}
|
||||
socket.onClose = function(handler: typeof closeEvents[number]) {
|
||||
closeEvents.push(handler)
|
||||
return () => {
|
||||
closeEvents.splice(closeEvents.indexOf(handler), 1)
|
||||
}
|
||||
}
|
||||
socket.sendData = function(eventName, data, callback) {
|
||||
socket.send(encryptMsg(socket.keyInfo, JSON.stringify({ action: eventName, data })), callback)
|
||||
}
|
||||
|
@ -248,6 +254,7 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
|
||||
const handleStopServer = async() => new Promise<void>((resolve, reject) => {
|
||||
if (!wss) return
|
||||
for (const client of wss.clients) client.close(SYNC_CLOSE_CODE.normal)
|
||||
wss.close()
|
||||
wss = null
|
||||
httpServer.close((err) => {
|
||||
|
@ -271,6 +278,9 @@ export const stopServer = async() => {
|
|||
return
|
||||
}
|
||||
console.log('stoping sync server...')
|
||||
status.message = 'stoping...'
|
||||
sendServerStatus(status)
|
||||
stopingServer = true
|
||||
await handleStopServer().then(() => {
|
||||
console.log('sync server stoped')
|
||||
status.status = false
|
||||
|
@ -281,12 +291,14 @@ export const stopServer = async() => {
|
|||
console.log(err)
|
||||
status.message = err.message
|
||||
}).finally(() => {
|
||||
stopingServer = false
|
||||
sendServerStatus(status)
|
||||
})
|
||||
}
|
||||
|
||||
export const startServer = async(port: number) => {
|
||||
console.log('status.status', status.status)
|
||||
if (stopingServer) return
|
||||
if (status.status) await handleStopServer()
|
||||
|
||||
log.info('starting sync server')
|
||||
|
|
|
@ -52,11 +52,6 @@ export const createSnapshot = async() => {
|
|||
|
||||
|
||||
export const getCurrentListInfoKey = async() => {
|
||||
if (!snapshotInfo) snapshotInfo = getSnapshotInfo()
|
||||
if (snapshotInfo.latest) {
|
||||
return snapshotInfo.latest
|
||||
}
|
||||
snapshotInfo.latest = toMD5(JSON.stringify(await getLocalListData()))
|
||||
saveSnapshotInfo(snapshotInfo)
|
||||
return snapshotInfo.latest
|
||||
// if (!snapshotInfo) snapshotInfo = getSnapshotInfo()
|
||||
return createSnapshot()
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ export default (name: string, isIgnoredError = true, isShowErrorAlert = true): S
|
|||
|
||||
|
||||
const backPath = join(global.lxDataPath, name + '.json.bak')
|
||||
fs.copyFileSync(join(global.lxDataPath, name + '.json'), backPath)
|
||||
fs.renameSync(join(global.lxDataPath, name + '.json'), backPath)
|
||||
if (isShowErrorAlert) {
|
||||
dialog.showMessageBoxSync({
|
||||
type: 'error',
|
||||
|
|
|
@ -35,6 +35,7 @@ export default {
|
|||
const handleSubmit = () => {
|
||||
let code = verify()
|
||||
if (code == '') return
|
||||
authCode.value = ''
|
||||
handleClose()
|
||||
sendSyncAction({
|
||||
action: 'enable_client',
|
||||
|
|
|
@ -6,7 +6,7 @@ import { SYNC_CODE } from '@common/constants'
|
|||
|
||||
export default () => {
|
||||
const handleSyncList = (event: LX.Sync.SyncMainWindowActions) => {
|
||||
console.log(event)
|
||||
// console.log(event)
|
||||
switch (event.action) {
|
||||
case 'select_mode':
|
||||
sync.deviceName = event.data
|
||||
|
|
|
@ -21,7 +21,7 @@ export const mergeSetting = (newSetting: Partial<LX.AppSetting>) => {
|
|||
}
|
||||
|
||||
export const updateSetting = window.lxData.updateSetting = (setting: Partial<LX.AppSetting>) => {
|
||||
console.warn(setting)
|
||||
// console.warn(setting)
|
||||
void saveSetting(setting)
|
||||
}
|
||||
|
||||
|
|
|
@ -140,10 +140,10 @@ export default {
|
|||
scrollIndex = _scrollIndex
|
||||
isAnimation = _isAnimation
|
||||
if (isAnimation) restoreScroll(scrollIndex, isAnimation)
|
||||
console.log('handleRestoreScroll', scrollIndex, isAnimation)
|
||||
// console.log('handleRestoreScroll', scrollIndex, isAnimation)
|
||||
}
|
||||
const onLoadedList = () => {
|
||||
console.log('restoreScroll', scrollIndex, isAnimation)
|
||||
// console.log('restoreScroll', scrollIndex, isAnimation)
|
||||
restoreScroll(scrollIndex, isAnimation)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue