新增同步功能对“不喜欢歌曲”列表的同步
This commit is contained in:
+2
-1
@@ -6,7 +6,7 @@ import { getTheme, initHotKey, initSetting, parseEnvParams } from './utils'
|
||||
import { navigationUrlWhiteList } from '@common/config'
|
||||
import defaultSetting from '@common/defaultSetting'
|
||||
import { closeWindow, isExistWindow as isExistMainWindow, showWindow as showMainWindow } from './modules/winMain'
|
||||
import { createAppEvent, createListEvent } from '@main/event'
|
||||
import { createAppEvent, createDislikeEvent, createListEvent } from '@main/event'
|
||||
import { isMac, log } from '@common/utils'
|
||||
import createWorkers from './worker'
|
||||
import { migrateDBData } from './utils/migrate'
|
||||
@@ -212,6 +212,7 @@ export const initAppSetting = async() => {
|
||||
// mainWindowClosed: true,
|
||||
event_app: createAppEvent(),
|
||||
event_list: createListEvent(),
|
||||
event_dislike: createDislikeEvent(),
|
||||
appSetting: defaultSetting,
|
||||
worker: createWorkers(),
|
||||
hotKey: {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { EventEmitter } from 'events'
|
||||
|
||||
|
||||
export class Event extends EventEmitter {
|
||||
dislike_changed() {
|
||||
this.emit('dislike_changed')
|
||||
}
|
||||
|
||||
/**
|
||||
* 覆盖整个列表数据
|
||||
* @param dislikeData 列表数据
|
||||
* @param isRemote 是否属于远程操作
|
||||
*/
|
||||
async dislike_data_overwrite(dislikeData: LX.Dislike.DislikeRules, isRemote: boolean = false) {
|
||||
await global.lx.worker.dbService.dislikeInfoOverwrite(dislikeData)
|
||||
this.emit('dislike_data_overwrite', dislikeData, isRemote)
|
||||
this.dislike_changed()
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加歌曲到列表
|
||||
* @param dislikeId 列表id
|
||||
* @param musicInfos 添加的歌曲信息
|
||||
* @param addMusicLocationType 添加在到列表的位置
|
||||
* @param isRemote 是否属于远程操作
|
||||
*/
|
||||
async dislike_music_add(musicInfo: LX.Dislike.DislikeMusicInfo[], isRemote: boolean = false) {
|
||||
// const changedIds =
|
||||
await global.lx.worker.dbService.dislikeInfoAdd(musicInfo)
|
||||
// await checkUpdateDislike(changedIds)
|
||||
this.emit('dislike_music_add', musicInfo, isRemote)
|
||||
this.dislike_changed()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空列表内的歌曲
|
||||
* @param ids 列表Id
|
||||
* @param isRemote 是否属于远程操作
|
||||
*/
|
||||
async dislike_music_clear(isRemote: boolean = false) {
|
||||
// const changedIds =
|
||||
await global.lx.worker.dbService.dislikeInfoOverwrite('')
|
||||
// await checkUpdateDislike(changedIds)
|
||||
this.emit('dislike_music_clear', isRemote)
|
||||
this.dislike_changed()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type EventMethods = Omit<EventType, keyof EventEmitter>
|
||||
declare class EventType extends Event {
|
||||
on<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): this
|
||||
once<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): this
|
||||
off<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): this
|
||||
}
|
||||
export type Type = Omit<EventType, keyof Omit<EventEmitter, 'on' | 'off' | 'once'>>
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Event as App, type Type as AppType } from './AppEvent'
|
||||
import { Event as List, type Type as ListType } from './ListEvent'
|
||||
import { Event as Dislike, type Type as DislikeType } from './DislikeEvent'
|
||||
|
||||
export type {
|
||||
AppType,
|
||||
ListType,
|
||||
DislikeType,
|
||||
}
|
||||
|
||||
export const createAppEvent = (): AppType => {
|
||||
@@ -14,3 +16,7 @@ export const createListEvent = (): ListType => {
|
||||
return new List()
|
||||
}
|
||||
|
||||
export const createDislikeEvent = (): DislikeType => {
|
||||
return new Dislike()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export { registerRendererEvents } from './winRendererEvent'
|
||||
|
||||
export { default } from './rendererEvent'
|
||||
@@ -0,0 +1,18 @@
|
||||
import { mainHandle } from '@common/mainIpc'
|
||||
import { DISLIKE_EVENT_NAME } from '@common/ipcNames'
|
||||
|
||||
// 列表操作事件(公共,只注册一次)
|
||||
export default () => {
|
||||
mainHandle<LX.Dislike.DislikeInfo>(DISLIKE_EVENT_NAME.get_dislike_music_infos, async() => {
|
||||
return global.lx.worker.dbService.getDislikeListInfo()
|
||||
})
|
||||
mainHandle<LX.Dislike.DislikeMusicInfo[]>(DISLIKE_EVENT_NAME.add_dislike_music_infos, async({ params: listData }) => {
|
||||
await global.lx.event_dislike.dislike_music_add(listData, false)
|
||||
})
|
||||
mainHandle<LX.Dislike.DislikeRules>(DISLIKE_EVENT_NAME.overwrite_dislike_music_infos, async({ params: rules }) => {
|
||||
await global.lx.event_dislike.dislike_data_overwrite(rules, false)
|
||||
})
|
||||
mainHandle(DISLIKE_EVENT_NAME.clear_dislike_music_infos, async() => {
|
||||
await global.lx.event_dislike.dislike_music_clear(false)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { DISLIKE_EVENT_NAME } from '@common/ipcNames'
|
||||
|
||||
// 发送列表操作事件到渲染进程的注册方法
|
||||
// 哪个渲染进程需要接收则引入此方法注册
|
||||
export const registerRendererEvents = (sendEvent: <T = any>(name: string, params?: T | undefined) => void) => {
|
||||
const dislike_music_add = async(listData: LX.Dislike.DislikeMusicInfo[]) => {
|
||||
sendEvent<LX.Dislike.DislikeMusicInfo[]>(DISLIKE_EVENT_NAME.add_dislike_music_infos, listData)
|
||||
}
|
||||
const dislike_data_overwrite = async(rules: LX.Dislike.DislikeRules) => {
|
||||
sendEvent<LX.Dislike.DislikeRules>(DISLIKE_EVENT_NAME.overwrite_dislike_music_infos, rules)
|
||||
}
|
||||
const dislike_music_clear = async() => {
|
||||
sendEvent(DISLIKE_EVENT_NAME.clear_dislike_music_infos)
|
||||
}
|
||||
global.lx.event_dislike.on('dislike_music_add', dislike_music_add)
|
||||
global.lx.event_dislike.on('dislike_data_overwrite', dislike_data_overwrite)
|
||||
global.lx.event_dislike.on('dislike_music_clear', dislike_music_clear)
|
||||
|
||||
return () => {
|
||||
global.lx.event_dislike.off('dislike_music_add', dislike_music_add)
|
||||
global.lx.event_dislike.off('dislike_data_overwrite', dislike_data_overwrite)
|
||||
global.lx.event_dislike.off('dislike_music_clear', dislike_music_clear)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import common from './common'
|
||||
import list from './list'
|
||||
import dislike from './dislike'
|
||||
|
||||
export default () => {
|
||||
common()
|
||||
list()
|
||||
dislike()
|
||||
}
|
||||
|
||||
@@ -200,6 +200,7 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
||||
|
||||
client.remote = message2read.remote
|
||||
client.remoteQueueList = message2read.createQueueRemote('list')
|
||||
client.remoteQueueDislike = message2read.createQueueRemote('dislike')
|
||||
|
||||
client.addEventListener('message', ({ data }) => {
|
||||
if (data == 'ping') return
|
||||
@@ -235,6 +236,7 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
||||
client!.isReady = false
|
||||
client!.moduleReadys = {
|
||||
list: false,
|
||||
dislike: false,
|
||||
}
|
||||
disconnected = false
|
||||
sendSyncStatus({
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// 这个文件导出的方法将暴露给服务端调用,第一个参数固定为当前 socket 对象
|
||||
import { handleRemoteDislikeAction, getLocalDislikeData, setLocalDislikeData } from '@main/modules/sync/dislikeEvent'
|
||||
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('dislike:sync:dislike_sync_', '').replaceAll('_', ' ')}${success ? ' success' : ''}`)
|
||||
}
|
||||
// const logError = (eventName: string, err: Error) => {
|
||||
// log.error(`[${eventName}]${eventName.replace('dislike:sync:dislike_sync_', '').replaceAll('_', ' ')} error: ${err.message}`)
|
||||
// }
|
||||
const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.Dislike.SyncMode> => new Promise((resolve, reject) => {
|
||||
const handleDisconnect = (err: Error) => {
|
||||
sendCloseSelectMode()
|
||||
removeSelectModeListener()
|
||||
reject(err)
|
||||
}
|
||||
let removeEventClose = socket.onClose(handleDisconnect)
|
||||
sendSelectMode(socket.data.keyInfo.serverName, 'dislike', (mode) => {
|
||||
if (mode == null) {
|
||||
reject(new Error('cancel'))
|
||||
return
|
||||
}
|
||||
resolve(mode)
|
||||
removeSelectModeListener()
|
||||
removeEventClose()
|
||||
})
|
||||
})
|
||||
const handler: LX.Sync.ClientSyncHandlerDislikeActions<LX.Sync.Client.Socket> = {
|
||||
async onDislikeSyncAction(socket, action) {
|
||||
if (!socket.moduleReadys?.dislike) return
|
||||
await handleRemoteDislikeAction(action)
|
||||
},
|
||||
|
||||
async dislike_sync_get_md5(socket) {
|
||||
logInfo('dislike:sync:dislike_sync_get_md5')
|
||||
return toMD5((await getLocalDislikeData()).trim())
|
||||
},
|
||||
|
||||
|
||||
async dislike_sync_get_sync_mode(socket) {
|
||||
return getSyncMode(socket)
|
||||
},
|
||||
|
||||
async dislike_sync_get_list_data(socket) {
|
||||
logInfo('dislike:sync:dislike_sync_get_list_data')
|
||||
return getLocalDislikeData()
|
||||
},
|
||||
|
||||
async dislike_sync_set_list_data(socket, data) {
|
||||
logInfo('dislike:sync:dislike_sync_set_list_data')
|
||||
await setLocalDislikeData(data)
|
||||
},
|
||||
|
||||
async dislike_sync_finished(socket) {
|
||||
logInfo('dislike:sync:finished')
|
||||
socket.moduleReadys.dislike = true
|
||||
registerEvent(socket)
|
||||
socket.onClose(() => {
|
||||
unregisterEvent()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
export { default as handler } from './handler'
|
||||
|
||||
export * from './localEvent'
|
||||
@@ -0,0 +1,21 @@
|
||||
import { registerDislikeActionEvent } from '@main/modules/sync/dislikeEvent'
|
||||
|
||||
let unregisterLocalListAction: (() => void) | null
|
||||
|
||||
export const registerEvent = (socket: LX.Sync.Client.Socket) => {
|
||||
// socket = _socket
|
||||
// socket.onClose(() => {
|
||||
// unregisterLocalListAction?.()
|
||||
// unregisterLocalListAction = null
|
||||
// })
|
||||
unregisterEvent()
|
||||
unregisterLocalListAction = registerDislikeActionEvent((action) => {
|
||||
if (!socket.moduleReadys?.dislike) return
|
||||
void socket.remoteQueueDislike.onDislikeSyncAction(action)
|
||||
})
|
||||
}
|
||||
|
||||
export const unregisterEvent = () => {
|
||||
unregisterLocalListAction?.()
|
||||
unregisterLocalListAction = null
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
import * as list from './list'
|
||||
import * as dislike from './dislike'
|
||||
// export * as theme from './theme'
|
||||
|
||||
|
||||
export const callObj = Object.assign({}, list.handler)
|
||||
export const callObj = Object.assign({},
|
||||
list.handler,
|
||||
dislike.handler,
|
||||
)
|
||||
|
||||
|
||||
export const modules = {
|
||||
list,
|
||||
dislike,
|
||||
}
|
||||
|
||||
export const featureVersion = {
|
||||
list: 1,
|
||||
dislike: 1,
|
||||
} as const
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// 这个文件导出的方法将暴露给服务端调用,第一个参数固定为当前 socket 对象
|
||||
import { handleRemoteListAction } from '@main/modules/sync/utils'
|
||||
import { getLocalListData, setLocalListData } from '../../../utils'
|
||||
import {
|
||||
handleRemoteListAction,
|
||||
getLocalListData,
|
||||
setLocalListData,
|
||||
} from '@main/modules/sync/listEvent'
|
||||
import { toMD5 } from '@common/utils/nodejs'
|
||||
import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain'
|
||||
import log from '@main/modules/sync/log'
|
||||
@@ -12,17 +15,6 @@ const logInfo = (eventName: string, success = false) => {
|
||||
// const logError = (eventName: string, err: Error) => {
|
||||
// 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.List.ActionList) => {
|
||||
if (!socket.moduleReadys?.list) return
|
||||
await handleRemoteListAction(action)
|
||||
}
|
||||
|
||||
export const list_sync_get_md5 = async(socket: LX.Sync.Client.Socket) => {
|
||||
logInfo('list:sync:list_sync_get_md5')
|
||||
return toMD5(JSON.stringify(await getLocalListData()))
|
||||
}
|
||||
|
||||
const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.List.SyncMode> => new Promise((resolve, reject) => {
|
||||
const handleDisconnect = (err: Error) => {
|
||||
sendCloseSelectMode()
|
||||
@@ -30,7 +22,7 @@ const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.List.S
|
||||
reject(err)
|
||||
}
|
||||
let removeEventClose = socket.onClose(handleDisconnect)
|
||||
sendSelectMode(socket.data.keyInfo.serverName, (mode) => {
|
||||
sendSelectMode(socket.data.keyInfo.serverName, 'list', (mode) => {
|
||||
if (mode == null) {
|
||||
reject(new Error('cancel'))
|
||||
return
|
||||
@@ -40,26 +32,41 @@ const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.List.S
|
||||
removeEventClose()
|
||||
})
|
||||
})
|
||||
export const list_sync_get_sync_mode = async(socket: LX.Sync.Client.Socket) => {
|
||||
return getSyncMode(socket)
|
||||
}
|
||||
|
||||
export const list_sync_get_list_data = async(socket: LX.Sync.Client.Socket) => {
|
||||
logInfo('list:sync:list_sync_get_list_data')
|
||||
return getLocalListData()
|
||||
}
|
||||
const handler: LX.Sync.ClientSyncHandlerListActions<LX.Sync.Client.Socket> = {
|
||||
async onListSyncAction(socket, action) {
|
||||
if (!socket.moduleReadys?.list) return
|
||||
await handleRemoteListAction(action)
|
||||
},
|
||||
|
||||
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)
|
||||
}
|
||||
async list_sync_get_md5(socket) {
|
||||
logInfo('list:sync:list_sync_get_md5')
|
||||
return toMD5(JSON.stringify(await getLocalListData()))
|
||||
},
|
||||
|
||||
export const list_sync_finished = async(socket: LX.Sync.Client.Socket) => {
|
||||
logInfo('list:sync:finished')
|
||||
socket.moduleReadys.list = true
|
||||
registerEvent(socket)
|
||||
socket.onClose(() => {
|
||||
unregisterEvent()
|
||||
})
|
||||
|
||||
async list_sync_get_sync_mode(socket) {
|
||||
return getSyncMode(socket)
|
||||
},
|
||||
|
||||
async list_sync_get_list_data(socket) {
|
||||
logInfo('list:sync:list_sync_get_list_data')
|
||||
return getLocalListData()
|
||||
},
|
||||
|
||||
async list_sync_set_list_data(socket, data) {
|
||||
logInfo('list:sync:list_sync_set_list_data')
|
||||
await setLocalListData(data)
|
||||
},
|
||||
|
||||
async list_sync_finished(socket) {
|
||||
logInfo('list:sync:finished')
|
||||
socket.moduleReadys.list = true
|
||||
registerEvent(socket)
|
||||
socket.onClose(() => {
|
||||
unregisterEvent()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
export * as handler from './handler'
|
||||
export { default as handler } from './handler'
|
||||
|
||||
export * from './localEvent'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { registerListActionEvent } from '@main/modules/sync/utils'
|
||||
import { registerListActionEvent } from '@main/modules/sync/listEvent'
|
||||
|
||||
let unregisterLocalListAction: (() => void) | null
|
||||
|
||||
|
||||
@@ -12,11 +12,13 @@ export const getEnabledFeatures = async(socket: LX.Sync.Client.Socket, serverTyp
|
||||
case 'server':
|
||||
return {
|
||||
list: featureVersion.list == supportedFeatures.list,
|
||||
dislike: featureVersion.dislike == supportedFeatures.dislike,
|
||||
}
|
||||
case 'desktop-app':
|
||||
default:
|
||||
return {
|
||||
list: featureVersion.list == supportedFeatures.list,
|
||||
dislike: featureVersion.dislike == supportedFeatures.dislike,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
export const getLocalDislikeData = async(): Promise<LX.Dislike.DislikeRules> => {
|
||||
return (await global.lx.worker.dbService.getDislikeListInfo()).rules
|
||||
}
|
||||
|
||||
export const setLocalDislikeData = async(listData: LX.Dislike.DislikeRules) => {
|
||||
await global.lx.event_dislike.dislike_data_overwrite(listData, true)
|
||||
}
|
||||
|
||||
export const registerDislikeActionEvent = (sendDislikeAction: (action: LX.Sync.Dislike.ActionList) => (void | Promise<void>)) => {
|
||||
const dislike_music_add = async(listData: LX.Dislike.DislikeMusicInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendDislikeAction({ action: 'dislike_music_add', data: listData })
|
||||
}
|
||||
const dislike_data_overwrite = async(listInfos: LX.Dislike.DislikeRules, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendDislikeAction({ action: 'dislike_data_overwrite', data: listInfos })
|
||||
}
|
||||
const dislike_music_clear = async(isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendDislikeAction({ action: 'dislike_music_clear' })
|
||||
}
|
||||
|
||||
global.lx.event_dislike.on('dislike_music_add', dislike_music_add)
|
||||
global.lx.event_dislike.on('dislike_data_overwrite', dislike_data_overwrite)
|
||||
global.lx.event_dislike.on('dislike_music_clear', dislike_music_clear)
|
||||
return () => {
|
||||
global.lx.event_dislike.off('dislike_music_add', dislike_music_add)
|
||||
global.lx.event_dislike.off('dislike_data_overwrite', dislike_data_overwrite)
|
||||
global.lx.event_dislike.off('dislike_music_clear', dislike_music_clear)
|
||||
}
|
||||
}
|
||||
|
||||
export const handleRemoteDislikeAction = async(event: LX.Sync.Dislike.ActionList) => {
|
||||
// console.log('handleRemoteDislikeAction', event)
|
||||
|
||||
switch (event.action) {
|
||||
case 'dislike_music_add':
|
||||
await global.lx.event_dislike.dislike_music_add(event.data, true)
|
||||
break
|
||||
case 'dislike_data_overwrite':
|
||||
await global.lx.event_dislike.dislike_data_overwrite(event.data, true)
|
||||
break
|
||||
case 'dislike_music_clear':
|
||||
await global.lx.event_dislike.dislike_music_clear(true)
|
||||
break
|
||||
default:
|
||||
throw new Error('unknown list sync action')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
import { LIST_IDS } from '@common/constants'
|
||||
|
||||
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: [],
|
||||
}
|
||||
|
||||
const userListInfos = await global.lx.worker.dbService.getAllUserList()
|
||||
for await (const list of userListInfos) {
|
||||
lists.userList.push(await global.lx.worker.dbService.getListMusics(list.id)
|
||||
.then(musics => ({ ...list, list: musics })))
|
||||
}
|
||||
|
||||
return lists
|
||||
}
|
||||
|
||||
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.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 })
|
||||
}
|
||||
const list_create = async(position: number, listInfos: LX.List.UserListInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_create', data: { position, listInfos } })
|
||||
}
|
||||
const list_remove = async(ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_remove', data: ids })
|
||||
}
|
||||
const list_update = async(lists: LX.List.UserListInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_update', data: lists })
|
||||
}
|
||||
const list_update_position = async(position: number, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_update_position', data: { position, ids } })
|
||||
}
|
||||
const list_music_overwrite = async(listId: string, musicInfos: LX.Music.MusicInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_overwrite', data: { listId, musicInfos } })
|
||||
}
|
||||
const list_music_add = async(id: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_add', data: { id, musicInfos, addMusicLocationType } })
|
||||
}
|
||||
const list_music_move = async(fromId: string, toId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_move', data: { fromId, toId, musicInfos, addMusicLocationType } })
|
||||
}
|
||||
const list_music_remove = async(listId: string, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_remove', data: { listId, ids } })
|
||||
}
|
||||
const list_music_update = async(musicInfos: LX.List.ListActionMusicUpdate, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_update', data: musicInfos })
|
||||
}
|
||||
const list_music_clear = async(ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_clear', data: ids })
|
||||
}
|
||||
const list_music_update_position = async(listId: string, position: number, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_update_position', data: { listId, position, ids } })
|
||||
}
|
||||
global.lx.event_list.on('list_data_overwrite', list_data_overwrite)
|
||||
global.lx.event_list.on('list_create', list_create)
|
||||
global.lx.event_list.on('list_remove', list_remove)
|
||||
global.lx.event_list.on('list_update', list_update)
|
||||
global.lx.event_list.on('list_update_position', list_update_position)
|
||||
global.lx.event_list.on('list_music_overwrite', list_music_overwrite)
|
||||
global.lx.event_list.on('list_music_add', list_music_add)
|
||||
global.lx.event_list.on('list_music_move', list_music_move)
|
||||
global.lx.event_list.on('list_music_remove', list_music_remove)
|
||||
global.lx.event_list.on('list_music_update', list_music_update)
|
||||
global.lx.event_list.on('list_music_clear', list_music_clear)
|
||||
global.lx.event_list.on('list_music_update_position', list_music_update_position)
|
||||
return () => {
|
||||
global.lx.event_list.off('list_data_overwrite', list_data_overwrite)
|
||||
global.lx.event_list.off('list_create', list_create)
|
||||
global.lx.event_list.off('list_remove', list_remove)
|
||||
global.lx.event_list.off('list_update', list_update)
|
||||
global.lx.event_list.off('list_update_position', list_update_position)
|
||||
global.lx.event_list.off('list_music_overwrite', list_music_overwrite)
|
||||
global.lx.event_list.off('list_music_add', list_music_add)
|
||||
global.lx.event_list.off('list_music_move', list_music_move)
|
||||
global.lx.event_list.off('list_music_remove', list_music_remove)
|
||||
global.lx.event_list.off('list_music_update', list_music_update)
|
||||
global.lx.event_list.off('list_music_clear', list_music_clear)
|
||||
global.lx.event_list.off('list_music_update_position', list_music_update_position)
|
||||
}
|
||||
}
|
||||
|
||||
export const handleRemoteListAction = async({ action, data }: LX.Sync.List.ActionList) => {
|
||||
// console.log('handleRemoteListAction', action)
|
||||
|
||||
switch (action) {
|
||||
case 'list_data_overwrite':
|
||||
await global.lx.event_list.list_data_overwrite(data, true)
|
||||
break
|
||||
case 'list_create':
|
||||
await global.lx.event_list.list_create(data.position, data.listInfos, true)
|
||||
break
|
||||
case 'list_remove':
|
||||
await global.lx.event_list.list_remove(data, true)
|
||||
break
|
||||
case 'list_update':
|
||||
await global.lx.event_list.list_update(data, true)
|
||||
break
|
||||
case 'list_update_position':
|
||||
await global.lx.event_list.list_update_position(data.position, data.ids, true)
|
||||
break
|
||||
case 'list_music_add':
|
||||
await global.lx.event_list.list_music_add(data.id, data.musicInfos, data.addMusicLocationType, true)
|
||||
break
|
||||
case 'list_music_move':
|
||||
await global.lx.event_list.list_music_move(data.fromId, data.toId, data.musicInfos, data.addMusicLocationType, true)
|
||||
break
|
||||
case 'list_music_remove':
|
||||
await global.lx.event_list.list_music_remove(data.listId, data.ids, true)
|
||||
break
|
||||
case 'list_music_update':
|
||||
await global.lx.event_list.list_music_update(data, true)
|
||||
break
|
||||
case 'list_music_update_position':
|
||||
await global.lx.event_list.list_music_update_position(data.listId, data.position, data.ids, true)
|
||||
break
|
||||
case 'list_music_overwrite':
|
||||
await global.lx.event_list.list_music_overwrite(data.listId, data.musicInfos, true)
|
||||
break
|
||||
case 'list_music_clear':
|
||||
await global.lx.event_list.list_music_clear(data, true)
|
||||
break
|
||||
default:
|
||||
throw new Error('unknown list sync action')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * as sync from './sync'
|
||||
export { DislikeManage } from './manage'
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { type UserDataManage } from '../../user'
|
||||
import { SnapshotDataManage } from './snapshotDataManage'
|
||||
import { toMD5 } from '../../utils'
|
||||
import { getLocalDislikeData } from '@main/modules/sync/dislikeEvent'
|
||||
|
||||
export class DislikeManage {
|
||||
snapshotDataManage: SnapshotDataManage
|
||||
|
||||
constructor(userDataManage: UserDataManage) {
|
||||
this.snapshotDataManage = new SnapshotDataManage(userDataManage)
|
||||
}
|
||||
|
||||
createSnapshot = async() => {
|
||||
const listData = await this.getDislikeRules()
|
||||
const md5 = toMD5(listData.trim())
|
||||
const snapshotInfo = await this.snapshotDataManage.getSnapshotInfo()
|
||||
console.log(md5, snapshotInfo.latest)
|
||||
if (snapshotInfo.latest == md5) return md5
|
||||
if (snapshotInfo.list.includes(md5)) {
|
||||
snapshotInfo.list.splice(snapshotInfo.list.indexOf(md5), 1)
|
||||
} else await this.snapshotDataManage.saveSnapshot(md5, listData)
|
||||
if (snapshotInfo.latest) snapshotInfo.list.unshift(snapshotInfo.latest)
|
||||
snapshotInfo.latest = md5
|
||||
snapshotInfo.time = Date.now()
|
||||
this.snapshotDataManage.saveSnapshotInfo(snapshotInfo)
|
||||
return md5
|
||||
}
|
||||
|
||||
getCurrentListInfoKey = async() => {
|
||||
const snapshotInfo = await this.snapshotDataManage.getSnapshotInfo()
|
||||
if (snapshotInfo.latest) {
|
||||
return snapshotInfo.latest
|
||||
}
|
||||
snapshotInfo.latest = toMD5((await this.getDislikeRules()).trim())
|
||||
this.snapshotDataManage.saveSnapshotInfo(snapshotInfo)
|
||||
return snapshotInfo.latest
|
||||
}
|
||||
|
||||
getDeviceCurrentSnapshotKey = async(clientId: string) => {
|
||||
return this.snapshotDataManage.getDeviceCurrentSnapshotKey(clientId)
|
||||
}
|
||||
|
||||
updateDeviceSnapshotKey = async(clientId: string, key: string) => {
|
||||
await this.snapshotDataManage.updateDeviceSnapshotKey(clientId, key)
|
||||
}
|
||||
|
||||
removeDevice = async(clientId: string) => {
|
||||
this.snapshotDataManage.removeSnapshotInfo(clientId)
|
||||
}
|
||||
|
||||
getDislikeRules = async() => {
|
||||
return getLocalDislikeData()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
import { throttle } from '@common/utils/common'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import syncLog from '../../../log'
|
||||
import { getUserConfig, type UserDataManage } from '../../user/data'
|
||||
import { File } from '../../../../../../common/constants_sync'
|
||||
import { checkAndCreateDirSync } from '../../utils'
|
||||
|
||||
|
||||
interface SnapshotInfo {
|
||||
latest: string | null
|
||||
time: number
|
||||
list: string[]
|
||||
clients: Record<string, LX.Sync.Dislike.ListInfo>
|
||||
}
|
||||
export class SnapshotDataManage {
|
||||
userDataManage: UserDataManage
|
||||
dislikeDir: string
|
||||
snapshotDir: string
|
||||
snapshotInfoFilePath: string
|
||||
snapshotInfo: SnapshotInfo
|
||||
clientSnapshotKeys: string[]
|
||||
private readonly saveSnapshotInfoThrottle: () => void
|
||||
|
||||
isIncluedsDevice = (key: string) => {
|
||||
return this.clientSnapshotKeys.includes(key)
|
||||
}
|
||||
|
||||
clearOldSnapshot = async() => {
|
||||
if (!this.snapshotInfo) return
|
||||
const snapshotList = this.snapshotInfo.list.filter(key => !this.isIncluedsDevice(key))
|
||||
// console.log(snapshotList.length, lx.config.maxSnapshotNum)
|
||||
const userMaxSnapshotNum = getUserConfig(this.userDataManage.userName).maxSnapshotNum
|
||||
let requiredSave = snapshotList.length > userMaxSnapshotNum
|
||||
while (snapshotList.length > userMaxSnapshotNum) {
|
||||
const name = snapshotList.pop()
|
||||
if (name) {
|
||||
await this.removeSnapshot(name)
|
||||
this.snapshotInfo.list.splice(this.snapshotInfo.list.indexOf(name), 1)
|
||||
} else break
|
||||
}
|
||||
if (requiredSave) this.saveSnapshotInfo(this.snapshotInfo)
|
||||
}
|
||||
|
||||
updateDeviceSnapshotKey = async(clientId: string, key: string) => {
|
||||
// console.log('updateDeviceSnapshotKey', key)
|
||||
let client = this.snapshotInfo.clients[clientId]
|
||||
if (!client) client = this.snapshotInfo.clients[clientId] = { snapshotKey: '', lastSyncDate: 0 }
|
||||
if (client.snapshotKey) this.clientSnapshotKeys.splice(this.clientSnapshotKeys.indexOf(client.snapshotKey), 1)
|
||||
client.snapshotKey = key
|
||||
client.lastSyncDate = Date.now()
|
||||
this.clientSnapshotKeys.push(key)
|
||||
this.saveSnapshotInfoThrottle()
|
||||
}
|
||||
|
||||
getDeviceCurrentSnapshotKey = async(clientId: string) => {
|
||||
// console.log('updateDeviceSnapshotKey', key)
|
||||
const client = this.snapshotInfo.clients[clientId]
|
||||
return client?.snapshotKey
|
||||
}
|
||||
|
||||
getSnapshotInfo = async(): Promise<SnapshotInfo> => {
|
||||
return this.snapshotInfo
|
||||
}
|
||||
|
||||
saveSnapshotInfo = (info: SnapshotInfo) => {
|
||||
this.snapshotInfo = info
|
||||
this.saveSnapshotInfoThrottle()
|
||||
}
|
||||
|
||||
removeSnapshotInfo = (clientId: string) => {
|
||||
let client = this.snapshotInfo.clients[clientId]
|
||||
if (!client) return
|
||||
if (client.snapshotKey) this.clientSnapshotKeys.splice(this.clientSnapshotKeys.indexOf(client.snapshotKey), 1)
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete this.snapshotInfo.clients[clientId]
|
||||
this.saveSnapshotInfoThrottle()
|
||||
}
|
||||
|
||||
getSnapshot = async(name: string) => {
|
||||
const filePath = path.join(this.snapshotDir, `snapshot_${name}`)
|
||||
let listData: LX.Dislike.DislikeRules
|
||||
try {
|
||||
listData = (await fs.promises.readFile(filePath)).toString('utf-8')
|
||||
} catch (err) {
|
||||
syncLog.warn(err)
|
||||
return null
|
||||
}
|
||||
return listData
|
||||
}
|
||||
|
||||
saveSnapshot = async(name: string, data: string) => {
|
||||
syncLog.info('saveSnapshot', this.userDataManage.userName, name)
|
||||
const filePath = path.join(this.snapshotDir, `snapshot_${name}`)
|
||||
try {
|
||||
fs.writeFileSync(filePath, data)
|
||||
} catch (err) {
|
||||
syncLog.error(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
removeSnapshot = async(name: string) => {
|
||||
syncLog.info('removeSnapshot', this.userDataManage.userName, name)
|
||||
const filePath = path.join(this.snapshotDir, `snapshot_${name}`)
|
||||
try {
|
||||
fs.unlinkSync(filePath)
|
||||
} catch (err) {
|
||||
syncLog.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
constructor(userDataManage: UserDataManage) {
|
||||
this.userDataManage = userDataManage
|
||||
|
||||
this.dislikeDir = path.join(userDataManage.userDir, File.dislikeDir)
|
||||
checkAndCreateDirSync(this.dislikeDir)
|
||||
|
||||
this.snapshotDir = path.join(this.dislikeDir, File.dislikeSnapshotDir)
|
||||
checkAndCreateDirSync(this.snapshotDir)
|
||||
|
||||
this.snapshotInfoFilePath = path.join(this.dislikeDir, File.dislikeSnapshotInfoJSON)
|
||||
this.snapshotInfo = fs.existsSync(this.snapshotInfoFilePath)
|
||||
? JSON.parse(fs.readFileSync(this.snapshotInfoFilePath).toString())
|
||||
: { latest: null, time: 0, list: [], clients: {} }
|
||||
|
||||
this.saveSnapshotInfoThrottle = throttle(() => {
|
||||
fs.writeFile(this.snapshotInfoFilePath, JSON.stringify(this.snapshotInfo), 'utf8', (err) => {
|
||||
if (err) console.error(err)
|
||||
void this.clearOldSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
this.clientSnapshotKeys = Object.values(this.snapshotInfo.clients).map(device => device.snapshotKey).filter(k => k)
|
||||
}
|
||||
}
|
||||
// type UserDataManages = Map<string, UserDataManage>
|
||||
|
||||
// export const createUserDataManage = (user: LX.UserConfig) => {
|
||||
// const manage = Object.create(userDataManage) as typeof userDataManage
|
||||
// manage.userDir = user.dataPath
|
||||
// }
|
||||
@@ -0,0 +1,35 @@
|
||||
// 这个文件导出的方法将暴露给客户端调用,第一个参数固定为当前 socket 对象
|
||||
// import { throttle } from '@common/utils/common'
|
||||
// import { sendSyncActionList } from '@main/modules/winMain'
|
||||
// import { SYNC_CLOSE_CODE } from '@/constants'
|
||||
// import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { getUserSpace } from '@main/modules/sync/server/user'
|
||||
import { handleRemoteDislikeAction } from '@main/modules/sync/dislikeEvent'
|
||||
// import { encryptMsg } from '@/utils/tools'
|
||||
|
||||
|
||||
const handler: LX.Sync.ServerSyncHandlerDislikeActions<LX.Sync.Server.Socket> = {
|
||||
async onDislikeSyncAction(socket, action) {
|
||||
if (!socket.moduleReadys.dislike) return
|
||||
await handleRemoteDislikeAction(action)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const key = await userSpace.dislikeManage.createSnapshot()
|
||||
userSpace.dislikeManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
const currentUserName = socket.userInfo.name
|
||||
const currentId = socket.keyInfo.clientId
|
||||
socket.broadcast((client) => {
|
||||
if (client.keyInfo.clientId == currentId || !client.moduleReadys?.dislike || client.userInfo.name != currentUserName) return
|
||||
void client.remoteQueueDislike.onDislikeSyncAction(action).then(async() => {
|
||||
return userSpace.dislikeManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.dislike = false
|
||||
console.log(err.message)
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default handler
|
||||
@@ -0,0 +1,3 @@
|
||||
export { default as handler } from './handler'
|
||||
export { sync } from './sync'
|
||||
export * from './localEvent'
|
||||
@@ -0,0 +1,43 @@
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { registerDislikeActionEvent } from '../../../../dislikeEvent'
|
||||
import { getUserSpace } from '../../../user'
|
||||
|
||||
// let socket: LX.Sync.Server.Socket | null
|
||||
let unregisterLocalListAction: (() => void) | null
|
||||
|
||||
|
||||
const sendListAction = async(wss: LX.Sync.Server.SocketServer, action: LX.Sync.Dislike.ActionList) => {
|
||||
// console.log('sendListAction', action.action)
|
||||
const userSpace = getUserSpace()
|
||||
let key = ''
|
||||
for (const client of wss.clients) {
|
||||
if (!client.moduleReadys?.dislike) continue
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
if (!key) key = await userSpace.dislikeManage.createSnapshot()
|
||||
void client.remoteQueueDislike.onDislikeSyncAction(action).then(async() => {
|
||||
return userSpace.dislikeManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.dislike = false
|
||||
console.log(err.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const registerEvent = (wss: LX.Sync.Server.SocketServer) => {
|
||||
// socket = _socket
|
||||
// socket.onClose(() => {
|
||||
// unregisterLocalListAction?.()
|
||||
// unregisterLocalListAction = null
|
||||
// })
|
||||
unregisterEvent()
|
||||
unregisterLocalListAction = registerDislikeActionEvent((action) => {
|
||||
void sendListAction(wss, action)
|
||||
})
|
||||
}
|
||||
|
||||
export const unregisterEvent = () => {
|
||||
unregisterLocalListAction?.()
|
||||
unregisterLocalListAction = null
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
// import { SYNC_CLOSE_CODE } from '../../../../constants'
|
||||
import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain'
|
||||
import { getUserSpace } from '../../../user'
|
||||
import { getLocalDislikeData, setLocalDislikeData } from '@main/modules/sync/dislikeEvent'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { filterRules } from '../utils'
|
||||
// import { LIST_IDS } from '@common/constants'
|
||||
|
||||
// type ListInfoType = LX.Dislike.UserListInfoFull | LX.Dislike.MyDefaultListInfoFull | LX.Dislike.MyLoveListInfoFull
|
||||
|
||||
// let wss: LX.Sync.Server.SocketServer | null
|
||||
let syncingId: string | null = null
|
||||
const wait = async(time = 1000) => await new Promise((resolve, reject) => setTimeout(resolve, time))
|
||||
|
||||
|
||||
const getRemoteListData = async(socket: LX.Sync.Server.Socket): Promise<LX.Dislike.DislikeRules> => {
|
||||
console.log('getRemoteListData')
|
||||
return (await socket.remoteQueueDislike.dislike_sync_get_list_data()) ?? ''
|
||||
}
|
||||
|
||||
const getRemoteDataMD5 = async(socket: LX.Sync.Server.Socket): Promise<string> => {
|
||||
return socket.remoteQueueDislike.dislike_sync_get_md5()
|
||||
}
|
||||
|
||||
// const getLocalDislikeData async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.Dislike.ListData> => {
|
||||
// return getUserSpace(socket.userInfo.name).listManage.getListData()
|
||||
// }
|
||||
const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.Dislike.SyncMode> => new Promise((resolve, reject) => {
|
||||
const handleDisconnect = (err: Error) => {
|
||||
sendCloseSelectMode()
|
||||
removeSelectModeListener()
|
||||
reject(err)
|
||||
}
|
||||
let removeEventClose = socket.onClose(handleDisconnect)
|
||||
sendSelectMode(socket.keyInfo.deviceName, 'dislike', (mode) => {
|
||||
if (mode == null) {
|
||||
reject(new Error('cancel'))
|
||||
return
|
||||
}
|
||||
resolve(mode)
|
||||
removeSelectModeListener()
|
||||
removeEventClose()
|
||||
})
|
||||
})
|
||||
// const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.Dislike.SyncMode> => {
|
||||
// return socket.remoteQueueDislike.list_sync_get_sync_mode()
|
||||
// }
|
||||
|
||||
const finishedSync = async(socket: LX.Sync.Server.Socket) => {
|
||||
await socket.remoteQueueDislike.dislike_sync_finished()
|
||||
}
|
||||
|
||||
|
||||
const setLocalList = async(socket: LX.Sync.Server.Socket, listData: LX.Dislike.DislikeRules) => {
|
||||
await setLocalDislikeData(listData)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
return userSpace.listManage.createSnapshot()
|
||||
}
|
||||
|
||||
const overwriteRemoteListData = async(socket: LX.Sync.Server.Socket, listData: LX.Dislike.DislikeRules, key: string, excludeIds: string[] = []) => {
|
||||
const action = { action: 'dislike_data_overwrite', data: listData } as const
|
||||
const tasks: Array<Promise<void>> = []
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
socket.broadcast((client) => {
|
||||
if (excludeIds.includes(client.keyInfo.clientId) || client.userInfo?.name != socket.userInfo.name || !client.moduleReadys?.dislike) return
|
||||
tasks.push(client.remoteQueueDislike.onDislikeSyncAction(action).then(async() => {
|
||||
return userSpace.dislikeManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.list = false
|
||||
console.log(err.message)
|
||||
}))
|
||||
})
|
||||
if (!tasks.length) return
|
||||
await Promise.all(tasks)
|
||||
}
|
||||
const setRemotelList = async(socket: LX.Sync.Server.Socket, listData: LX.Dislike.DislikeRules, key: string): Promise<void> => {
|
||||
await socket.remoteQueueDislike.dislike_sync_set_list_data(listData)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
await userSpace.dislikeManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
}
|
||||
|
||||
|
||||
const mergeList = (socket: LX.Sync.Server.Socket, sourceListData: LX.Dislike.DislikeRules, targetListData: LX.Dislike.DislikeRules): LX.Dislike.DislikeRules => {
|
||||
return Array.from(filterRules(sourceListData + '\n' + targetListData)).join('\n')
|
||||
}
|
||||
|
||||
const handleMergeListData = async(socket: LX.Sync.Server.Socket): Promise<[LX.Dislike.DislikeRules, boolean, boolean]> => {
|
||||
const mode: LX.Sync.Dislike.SyncMode = await getSyncMode(socket)
|
||||
|
||||
if (mode == 'cancel') throw new Error('cancel')
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalDislikeData()])
|
||||
console.log('handleMergeListData', 'remoteListData, localListData')
|
||||
let listData: LX.Dislike.DislikeRules
|
||||
let requiredUpdateLocalListData = true
|
||||
let requiredUpdateRemoteListData = true
|
||||
switch (mode) {
|
||||
case 'merge_local_remote':
|
||||
listData = mergeList(socket, localListData, remoteListData)
|
||||
break
|
||||
case 'merge_remote_local':
|
||||
listData = mergeList(socket, remoteListData, localListData)
|
||||
break
|
||||
case 'overwrite_local_remote':
|
||||
listData = localListData
|
||||
requiredUpdateLocalListData = false
|
||||
break
|
||||
case 'overwrite_remote_local':
|
||||
listData = remoteListData
|
||||
requiredUpdateRemoteListData = false
|
||||
break
|
||||
// case 'none': return null
|
||||
// case 'cancel':
|
||||
default: throw new Error('cancel')
|
||||
}
|
||||
return [listData, requiredUpdateLocalListData, requiredUpdateRemoteListData]
|
||||
}
|
||||
|
||||
const handleSyncList = async(socket: LX.Sync.Server.Socket) => {
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalDislikeData()])
|
||||
console.log('handleSyncList', 'remoteListData, localListData')
|
||||
console.log('localListData', localListData.length)
|
||||
console.log('remoteListData', remoteListData.length)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const clientId = socket.keyInfo.clientId
|
||||
if (localListData.length) {
|
||||
if (remoteListData.length) {
|
||||
const [mergedList, requiredUpdateLocalListData, requiredUpdateRemoteListData] = await handleMergeListData(socket)
|
||||
console.log('handleMergeListData', 'mergedList', requiredUpdateLocalListData, requiredUpdateRemoteListData)
|
||||
let key
|
||||
if (requiredUpdateLocalListData) {
|
||||
key = await setLocalList(socket, mergedList)
|
||||
await overwriteRemoteListData(socket, mergedList, key, [clientId])
|
||||
if (!requiredUpdateRemoteListData) await userSpace.dislikeManage.updateDeviceSnapshotKey(clientId, key)
|
||||
}
|
||||
if (requiredUpdateRemoteListData) {
|
||||
if (!key) key = await userSpace.dislikeManage.getCurrentListInfoKey()
|
||||
await setRemotelList(socket, mergedList, key)
|
||||
}
|
||||
} else {
|
||||
await setRemotelList(socket, localListData, await userSpace.dislikeManage.getCurrentListInfoKey())
|
||||
}
|
||||
} else {
|
||||
let key: string
|
||||
if (remoteListData.length) {
|
||||
key = await setLocalList(socket, remoteListData)
|
||||
await overwriteRemoteListData(socket, remoteListData, key, [clientId])
|
||||
}
|
||||
key ??= await userSpace.dislikeManage.getCurrentListInfoKey()
|
||||
await userSpace.dislikeManage.updateDeviceSnapshotKey(clientId, key)
|
||||
}
|
||||
}
|
||||
|
||||
const mergeDataFromSnapshot = (
|
||||
sourceList: LX.Dislike.DislikeRules,
|
||||
targetList: LX.Dislike.DislikeRules,
|
||||
snapshotList: LX.Dislike.DislikeRules,
|
||||
): LX.Dislike.DislikeRules => {
|
||||
const removedRules = new Set<string>()
|
||||
const sourceRules = filterRules(sourceList)
|
||||
const targetRules = filterRules(targetList)
|
||||
|
||||
if (snapshotList) {
|
||||
const snapshotRules = filterRules(snapshotList)
|
||||
for (const m of snapshotRules.values()) {
|
||||
if (!sourceRules.has(m) || !targetRules.has(m)) removedRules.add(m)
|
||||
}
|
||||
}
|
||||
return Array.from(new Set(Array.from([...sourceRules, ...targetRules]).filter((rule) => {
|
||||
return !removedRules.has(rule)
|
||||
}))).join('\n')
|
||||
}
|
||||
const checkListLatest = async(socket: LX.Sync.Server.Socket) => {
|
||||
const remoteListMD5 = await getRemoteDataMD5(socket)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const userCurrentListInfoKey = await userSpace.dislikeManage.getDeviceCurrentSnapshotKey(socket.keyInfo.clientId)
|
||||
const currentListInfoKey = await userSpace.dislikeManage.getCurrentListInfoKey()
|
||||
const latest = remoteListMD5 == currentListInfoKey
|
||||
if (latest && userCurrentListInfoKey != currentListInfoKey) await userSpace.dislikeManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, currentListInfoKey)
|
||||
return latest
|
||||
}
|
||||
|
||||
const handleMergeListDataFromSnapshot = async(socket: LX.Sync.Server.Socket, snapshot: LX.Dislike.DislikeRules) => {
|
||||
if (await checkListLatest(socket)) return
|
||||
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalDislikeData()])
|
||||
const newDislikeData = mergeDataFromSnapshot(localListData, remoteListData, snapshot)
|
||||
|
||||
const key = await setLocalList(socket, newDislikeData)
|
||||
const err = await setRemotelList(socket, newDislikeData, key).catch(err => err)
|
||||
await overwriteRemoteListData(socket, newDislikeData, key, [socket.keyInfo.clientId])
|
||||
if (err) throw err
|
||||
}
|
||||
|
||||
const syncDislike = async(socket: LX.Sync.Server.Socket) => {
|
||||
// socket.data.snapshotFilePath = getSnapshotFilePath(socket.keyInfo)
|
||||
// console.log(socket.keyInfo)
|
||||
const user = getUserSpace(socket.userInfo.name)
|
||||
const userCurrentDislikeInfoKey = await user.dislikeManage.getDeviceCurrentSnapshotKey(socket.keyInfo.clientId)
|
||||
if (userCurrentDislikeInfoKey) {
|
||||
const listData = await user.dislikeManage.snapshotDataManage.getSnapshot(userCurrentDislikeInfoKey)
|
||||
if (listData) {
|
||||
console.log('handleMergeDislikeDataFromSnapshot')
|
||||
await handleMergeListDataFromSnapshot(socket, listData)
|
||||
return
|
||||
}
|
||||
}
|
||||
await handleSyncList(socket)
|
||||
}
|
||||
|
||||
export const sync = async(socket: LX.Sync.Server.Socket) => {
|
||||
let disconnected = false
|
||||
socket.onClose(() => {
|
||||
disconnected = true
|
||||
if (syncingId == socket.keyInfo.clientId) syncingId = null
|
||||
})
|
||||
|
||||
while (true) {
|
||||
if (disconnected) throw new Error('disconnected')
|
||||
if (!syncingId) break
|
||||
await wait()
|
||||
}
|
||||
|
||||
syncingId = socket.keyInfo.clientId
|
||||
await syncDislike(socket).then(async() => {
|
||||
await finishedSync(socket)
|
||||
socket.moduleReadys.dislike = true
|
||||
}).finally(() => {
|
||||
syncingId = null
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { SPLIT_CHAR } from '@common/constants'
|
||||
|
||||
|
||||
export const filterRules = (rules: string) => {
|
||||
const list: string[] = []
|
||||
for (const item of rules.split('\n')) {
|
||||
if (!item) continue
|
||||
let [name, singer] = item.split(SPLIT_CHAR.DISLIKE_NAME)
|
||||
if (name) {
|
||||
name = name.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
|
||||
if (singer) {
|
||||
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
|
||||
list.push(`${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
|
||||
} else {
|
||||
list.push(name)
|
||||
}
|
||||
} else if (singer) {
|
||||
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
|
||||
list.push(`${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
|
||||
}
|
||||
}
|
||||
return new Set(list)
|
||||
}
|
||||
@@ -1,16 +1,22 @@
|
||||
import { sync } from './list'
|
||||
import { sync as listSync } from './list'
|
||||
import { sync as dislikeSync } from './dislike'
|
||||
|
||||
export const callObj = Object.assign({},
|
||||
sync.handler,
|
||||
listSync.handler,
|
||||
dislikeSync.handler,
|
||||
)
|
||||
|
||||
export const modules = {
|
||||
list: sync,
|
||||
list: listSync,
|
||||
dislike: dislikeSync,
|
||||
}
|
||||
|
||||
|
||||
export { ListManage } from './list'
|
||||
|
||||
export { DislikeManage } from './dislike'
|
||||
|
||||
export const featureVersion = {
|
||||
list: 1,
|
||||
dislike: 1,
|
||||
} as const
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type UserDataManage } from '../../user'
|
||||
import { SnapshotDataManage } from './snapshotDataManage'
|
||||
import { toMD5 } from '../../utils'
|
||||
import { getLocalListData } from '@main/modules/sync/utils'
|
||||
import { getLocalListData } from '@main/modules/sync/listEvent'
|
||||
|
||||
export class ListManage {
|
||||
snapshotDataManage: SnapshotDataManage
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { getUserSpace } from '@main/modules/sync/server/user'
|
||||
import { handleRemoteListAction } from '@main/modules/sync/utils'
|
||||
import { handleRemoteListAction } from '@main/modules/sync/listEvent'
|
||||
// import { encryptMsg } from '@/utils/tools'
|
||||
|
||||
// let wss: LX.SocketServer | null
|
||||
@@ -146,23 +146,27 @@ import { handleRemoteListAction } from '@main/modules/sync/utils'
|
||||
// // }
|
||||
// }
|
||||
|
||||
export const onListSyncAction = async(socket: LX.Sync.Server.Socket, action: LX.Sync.List.ActionList) => {
|
||||
if (!socket.moduleReadys.list) return
|
||||
await handleRemoteListAction(action)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const key = await userSpace.listManage.createSnapshot()
|
||||
userSpace.listManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
const currentUserName = socket.userInfo.name
|
||||
const currentId = socket.keyInfo.clientId
|
||||
socket.broadcast((client) => {
|
||||
if (client.keyInfo.clientId == currentId || !client.moduleReadys?.list || client.userInfo.name != currentUserName) return
|
||||
void client.remoteQueueList.onListSyncAction(action).then(async() => {
|
||||
return userSpace.listManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.list = false
|
||||
console.log(err.message)
|
||||
const handler: LX.Sync.ServerSyncHandlerListActions<LX.Sync.Server.Socket> = {
|
||||
async onListSyncAction(socket, action) {
|
||||
if (!socket.moduleReadys.list) return
|
||||
await handleRemoteListAction(action)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const key = await userSpace.listManage.createSnapshot()
|
||||
userSpace.listManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
const currentUserName = socket.userInfo.name
|
||||
const currentId = socket.keyInfo.clientId
|
||||
socket.broadcast((client) => {
|
||||
if (client.keyInfo.clientId == currentId || !client.moduleReadys?.list || client.userInfo.name != currentUserName) return
|
||||
void client.remoteQueueList.onListSyncAction(action).then(async() => {
|
||||
return userSpace.listManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.list = false
|
||||
console.log(err.message)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * as handler from './handler'
|
||||
export { default as handler } from './handler'
|
||||
export { sync } from './sync'
|
||||
export * from './localEvent'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { registerListActionEvent } from '../../../../utils'
|
||||
import { registerListActionEvent } from '../../../../listEvent'
|
||||
import { getUserSpace } from '../../../user'
|
||||
|
||||
// let socket: LX.Sync.Server.Socket | null
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// import { SYNC_CLOSE_CODE } from '../../../../constants'
|
||||
import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain'
|
||||
import { getUserSpace, getUserConfig } from '../../../user'
|
||||
import { getLocalListData, setLocalListData } from '@main/modules/sync/utils'
|
||||
import { getLocalListData, setLocalListData } from '@main/modules/sync/listEvent'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
// import { LIST_IDS } from '@common/constants'
|
||||
|
||||
@@ -38,7 +38,7 @@ const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.List.S
|
||||
reject(err)
|
||||
}
|
||||
let removeEventClose = socket.onClose(handleDisconnect)
|
||||
sendSelectMode(socket.keyInfo.deviceName, (mode) => {
|
||||
sendSelectMode(socket.keyInfo.deviceName, 'list', (mode) => {
|
||||
if (mode == null) {
|
||||
reject(new Error('cancel'))
|
||||
return
|
||||
|
||||
@@ -156,9 +156,11 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
||||
socket.isReady = false
|
||||
socket.moduleReadys = {
|
||||
list: false,
|
||||
dislike: false,
|
||||
}
|
||||
socket.feature = {
|
||||
list: false,
|
||||
dislike: false,
|
||||
}
|
||||
socket.on('pong', () => {
|
||||
socket.isAlive = true
|
||||
@@ -196,6 +198,7 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
||||
})
|
||||
socket.remote = msg2call.remote
|
||||
socket.remoteQueueList = msg2call.createQueueRemote('list')
|
||||
socket.remoteQueueDislike = msg2call.createQueueRemote('dislike')
|
||||
socket.addEventListener('message', ({ data }) => {
|
||||
if (typeof data != 'string') return
|
||||
void decryptMsg(socket.keyInfo, data).then((data) => {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { UserDataManage } from './data'
|
||||
import {
|
||||
ListManage,
|
||||
DislikeManage,
|
||||
} from '../modules'
|
||||
|
||||
export interface UserSpace {
|
||||
dataManage: UserDataManage
|
||||
listManage: ListManage
|
||||
dislikeManage: DislikeManage
|
||||
getDecices: () => Promise<LX.Sync.ServerKeyInfo[]>
|
||||
removeDevice: (clientId: string) => Promise<void>
|
||||
}
|
||||
@@ -34,9 +36,11 @@ export const getUserSpace = (userName = 'default') => {
|
||||
console.log('new user data manage:', userName)
|
||||
const dataManage = new UserDataManage(userName)
|
||||
const listManage = new ListManage(dataManage)
|
||||
const dislikeManage = new DislikeManage(dataManage)
|
||||
users.set(userName, user = {
|
||||
dataManage,
|
||||
listManage,
|
||||
dislikeManage,
|
||||
async getDecices() {
|
||||
return this.dataManage.getAllClientKeyInfo()
|
||||
},
|
||||
|
||||
@@ -2,7 +2,6 @@ import { createCipheriv, createDecipheriv, publicEncrypt, privateDecrypt, consta
|
||||
import os, { networkInterfaces } from 'node:os'
|
||||
import zlib from 'node:zlib'
|
||||
import cp from 'node:child_process'
|
||||
import { LIST_IDS } from '@common/constants'
|
||||
|
||||
|
||||
export const getAddress = (): string[] => {
|
||||
@@ -89,146 +88,3 @@ export const rsaEncrypt = (buffer: Buffer, key: string): string => {
|
||||
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.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: [],
|
||||
}
|
||||
|
||||
const userListInfos = await global.lx.worker.dbService.getAllUserList()
|
||||
for await (const list of userListInfos) {
|
||||
lists.userList.push(await global.lx.worker.dbService.getListMusics(list.id)
|
||||
.then(musics => ({ ...list, list: musics })))
|
||||
}
|
||||
|
||||
return lists
|
||||
}
|
||||
|
||||
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.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 })
|
||||
}
|
||||
const list_create = async(position: number, listInfos: LX.List.UserListInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_create', data: { position, listInfos } })
|
||||
}
|
||||
const list_remove = async(ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_remove', data: ids })
|
||||
}
|
||||
const list_update = async(lists: LX.List.UserListInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_update', data: lists })
|
||||
}
|
||||
const list_update_position = async(position: number, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_update_position', data: { position, ids } })
|
||||
}
|
||||
const list_music_overwrite = async(listId: string, musicInfos: LX.Music.MusicInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_overwrite', data: { listId, musicInfos } })
|
||||
}
|
||||
const list_music_add = async(id: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_add', data: { id, musicInfos, addMusicLocationType } })
|
||||
}
|
||||
const list_music_move = async(fromId: string, toId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_move', data: { fromId, toId, musicInfos, addMusicLocationType } })
|
||||
}
|
||||
const list_music_remove = async(listId: string, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_remove', data: { listId, ids } })
|
||||
}
|
||||
const list_music_update = async(musicInfos: LX.List.ListActionMusicUpdate, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_update', data: musicInfos })
|
||||
}
|
||||
const list_music_clear = async(ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_clear', data: ids })
|
||||
}
|
||||
const list_music_update_position = async(listId: string, position: number, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_update_position', data: { listId, position, ids } })
|
||||
}
|
||||
global.lx.event_list.on('list_data_overwrite', list_data_overwrite)
|
||||
global.lx.event_list.on('list_create', list_create)
|
||||
global.lx.event_list.on('list_remove', list_remove)
|
||||
global.lx.event_list.on('list_update', list_update)
|
||||
global.lx.event_list.on('list_update_position', list_update_position)
|
||||
global.lx.event_list.on('list_music_overwrite', list_music_overwrite)
|
||||
global.lx.event_list.on('list_music_add', list_music_add)
|
||||
global.lx.event_list.on('list_music_move', list_music_move)
|
||||
global.lx.event_list.on('list_music_remove', list_music_remove)
|
||||
global.lx.event_list.on('list_music_update', list_music_update)
|
||||
global.lx.event_list.on('list_music_clear', list_music_clear)
|
||||
global.lx.event_list.on('list_music_update_position', list_music_update_position)
|
||||
return () => {
|
||||
global.lx.event_list.off('list_data_overwrite', list_data_overwrite)
|
||||
global.lx.event_list.off('list_create', list_create)
|
||||
global.lx.event_list.off('list_remove', list_remove)
|
||||
global.lx.event_list.off('list_update', list_update)
|
||||
global.lx.event_list.off('list_update_position', list_update_position)
|
||||
global.lx.event_list.off('list_music_overwrite', list_music_overwrite)
|
||||
global.lx.event_list.off('list_music_add', list_music_add)
|
||||
global.lx.event_list.off('list_music_move', list_music_move)
|
||||
global.lx.event_list.off('list_music_remove', list_music_remove)
|
||||
global.lx.event_list.off('list_music_update', list_music_update)
|
||||
global.lx.event_list.off('list_music_clear', list_music_clear)
|
||||
global.lx.event_list.off('list_music_update_position', list_music_update_position)
|
||||
}
|
||||
}
|
||||
|
||||
export const handleRemoteListAction = async({ action, data }: LX.Sync.List.ActionList) => {
|
||||
// console.log('handleRemoteListAction', action)
|
||||
|
||||
switch (action) {
|
||||
case 'list_data_overwrite':
|
||||
await global.lx.event_list.list_data_overwrite(data, true)
|
||||
break
|
||||
case 'list_create':
|
||||
await global.lx.event_list.list_create(data.position, data.listInfos, true)
|
||||
break
|
||||
case 'list_remove':
|
||||
await global.lx.event_list.list_remove(data, true)
|
||||
break
|
||||
case 'list_update':
|
||||
await global.lx.event_list.list_update(data, true)
|
||||
break
|
||||
case 'list_update_position':
|
||||
await global.lx.event_list.list_update_position(data.position, data.ids, true)
|
||||
break
|
||||
case 'list_music_add':
|
||||
await global.lx.event_list.list_music_add(data.id, data.musicInfos, data.addMusicLocationType, true)
|
||||
break
|
||||
case 'list_music_move':
|
||||
await global.lx.event_list.list_music_move(data.fromId, data.toId, data.musicInfos, data.addMusicLocationType, true)
|
||||
break
|
||||
case 'list_music_remove':
|
||||
await global.lx.event_list.list_music_remove(data.listId, data.ids, true)
|
||||
break
|
||||
case 'list_music_update':
|
||||
await global.lx.event_list.list_music_update(data, true)
|
||||
break
|
||||
case 'list_music_update_position':
|
||||
await global.lx.event_list.list_music_update_position(data.listId, data.position, data.ids, true)
|
||||
break
|
||||
case 'list_music_overwrite':
|
||||
await global.lx.event_list.list_music_overwrite(data.listId, data.musicInfos, true)
|
||||
break
|
||||
case 'list_music_clear':
|
||||
await global.lx.event_list.list_music_clear(data, true)
|
||||
break
|
||||
default:
|
||||
throw new Error('unknown list sync action')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { registerRendererEvents as common } from '@main/modules/commonRenderers/common'
|
||||
import { registerRendererEvents as list } from '@main/modules/commonRenderers/list'
|
||||
import { registerRendererEvents as dislike } from '@main/modules/commonRenderers/dislike'
|
||||
import app, { sendConfigChange } from './app'
|
||||
import hotKey from './hotKey'
|
||||
import kw_decodeLyric from './kw_decodeLyric'
|
||||
@@ -25,6 +26,7 @@ export default () => {
|
||||
|
||||
common(sendEvent)
|
||||
list(sendEvent)
|
||||
dislike(sendEvent)
|
||||
app()
|
||||
hotKey()
|
||||
kw_decodeLyric()
|
||||
|
||||
@@ -70,16 +70,6 @@ export default () => {
|
||||
return global.lx.worker.dbService.musicInfoOtherSourceCount()
|
||||
})
|
||||
|
||||
// =========================不喜欢的歌曲=========================
|
||||
mainHandle<LX.Dislike.DislikeInfo>(WIN_MAIN_RENDERER_EVENT_NAME.get_dislike_music_infos, async() => {
|
||||
return global.lx.worker.dbService.getDislikeListInfo()
|
||||
})
|
||||
mainHandle<LX.Dislike.DislikeMusicInfo[]>(WIN_MAIN_RENDERER_EVENT_NAME.add_dislike_music_infos, async({ params: infos }) => {
|
||||
await global.lx.worker.dbService.dislikeInfoAdd(infos)
|
||||
})
|
||||
mainHandle<string>(WIN_MAIN_RENDERER_EVENT_NAME.overwrite_dislike_music_infos, async({ params: rules }) => {
|
||||
await global.lx.worker.dbService.dislikeInfoOverwrite(rules)
|
||||
})
|
||||
// mainHandle<string[]>(WIN_MAIN_RENDERER_EVENT_NAME.remove_dislike_music_infos, async({ params: ids }) => {
|
||||
// await global.lx.worker.dbService.dislikeInfoRemove(ids)
|
||||
// })
|
||||
|
||||
@@ -13,7 +13,8 @@ import {
|
||||
} from '@main/modules/sync'
|
||||
import { sendEvent } from '../main'
|
||||
|
||||
let selectModeListenr: ((mode: LX.Sync.List.SyncMode | null) => void) | null = null
|
||||
|
||||
let selectModeListenr: ((mode: LX.Sync.ModeTypes[keyof LX.Sync.ModeTypes] | null) => void) | null = null
|
||||
|
||||
export default () => {
|
||||
mainHandle<LX.Sync.SyncServiceActions, any>(WIN_MAIN_RENDERER_EVENT_NAME.sync_action, async({ params: data }) => {
|
||||
@@ -29,7 +30,7 @@ export default () => {
|
||||
case 'generate_code': return generateCode()
|
||||
case 'select_mode':
|
||||
if (selectModeListenr) {
|
||||
selectModeListenr(data.data)
|
||||
selectModeListenr(data.data.mode)
|
||||
selectModeListenr = null
|
||||
}
|
||||
break
|
||||
@@ -62,9 +63,9 @@ export const sendServerStatus = (status: LX.Sync.ServerStatus) => {
|
||||
data: status,
|
||||
})
|
||||
}
|
||||
export const sendSelectMode = (deviceName: string, listener: (mode: LX.Sync.List.SyncMode | null) => void) => {
|
||||
selectModeListenr = listener
|
||||
sendSyncAction({ action: 'select_mode', data: deviceName })
|
||||
export const sendSelectMode = <T extends keyof LX.Sync.ModeTypes>(deviceName: string, type: T, listener: (mode: LX.Sync.ModeTypes[T] | null) => void) => {
|
||||
selectModeListenr = listener as typeof selectModeListenr
|
||||
sendSyncAction({ action: 'select_mode', data: { deviceName, type } })
|
||||
}
|
||||
export const removeSelectModeListener = () => {
|
||||
if (selectModeListenr) selectModeListenr(null)
|
||||
|
||||
Vendored
+2
-1
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-var */
|
||||
// import { Event as WinMainEvent } from '@main/modules/winMain/event'
|
||||
// import { Event as WinLyricEvent } from '@main/modules/winLyric/event'
|
||||
import { type AppType, type ListType } from '@main/event'
|
||||
import { type DislikeType, type AppType, type ListType } from '@main/event'
|
||||
import { type DBSeriveTypes } from '@main/worker/utils'
|
||||
|
||||
interface Lx {
|
||||
@@ -25,6 +25,7 @@ interface Lx {
|
||||
// mainWindowClosed: boolean
|
||||
event_app: AppType
|
||||
event_list: ListType
|
||||
event_dislike: DislikeType
|
||||
worker: {
|
||||
dbService: DBSeriveTypes
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -13,3 +13,4 @@ import '@common/types/theme'
|
||||
import '@common/types/ipc_main'
|
||||
import '@common/types/sound_effect'
|
||||
import '@common/types/dislike_list'
|
||||
import '@common/types/dislike_list_sync'
|
||||
|
||||
Vendored
+4
@@ -15,11 +15,13 @@ declare global {
|
||||
}
|
||||
moduleReadys: {
|
||||
list: boolean
|
||||
dislike: boolean
|
||||
}
|
||||
|
||||
onClose: (handler: (err: Error) => (void | Promise<void>)) => () => void
|
||||
remote: LX.Sync.ServerSyncActions
|
||||
remoteQueueList: LX.Sync.ServerSyncListActions
|
||||
remoteQueueDislike: LX.Sync.ServerSyncDislikeActions
|
||||
}
|
||||
|
||||
interface UrlInfo {
|
||||
@@ -38,6 +40,7 @@ declare global {
|
||||
feature: LX.Sync.EnabledFeatures
|
||||
moduleReadys: {
|
||||
list: boolean
|
||||
dislike: boolean
|
||||
}
|
||||
|
||||
onClose: (handler: (err: Error) => (void | Promise<void>)) => () => void
|
||||
@@ -45,6 +48,7 @@ declare global {
|
||||
|
||||
remote: LX.Sync.ClientSyncActions
|
||||
remoteQueueList: LX.Sync.ClientSyncListActions
|
||||
remoteQueueDislike: LX.Sync.ClientSyncDislikeActions
|
||||
}
|
||||
type SocketServer = WS.Server<Socket>
|
||||
}
|
||||
|
||||
Vendored
+25
@@ -1,16 +1,30 @@
|
||||
type WarpSyncHandlerActions<Socket, Actions> = {
|
||||
[K in keyof Actions]: (...args: [Socket, ...Parameters<Actions[K]>]) => ReturnType<Actions[K]>
|
||||
}
|
||||
|
||||
declare namespace LX {
|
||||
namespace Sync {
|
||||
type ServerSyncActions = WarpPromiseRecord<{
|
||||
onFeatureChanged: (feature: EnabledFeatures) => void
|
||||
}>
|
||||
type ServerSyncHandlerActions<Socket> = WarpSyncHandlerActions<Socket, ServerSyncActions>
|
||||
|
||||
type ServerSyncListActions = WarpPromiseRecord<{
|
||||
onListSyncAction: (action: LX.Sync.List.ActionList) => void
|
||||
}>
|
||||
type ServerSyncHandlerListActions<Socket> = WarpSyncHandlerActions<Socket, ServerSyncListActions>
|
||||
|
||||
type ServerSyncDislikeActions = WarpPromiseRecord<{
|
||||
onDislikeSyncAction: (action: LX.Sync.Dislike.ActionList) => void
|
||||
}>
|
||||
type ServerSyncHandlerDislikeActions<Socket> = WarpSyncHandlerActions<Socket, ServerSyncDislikeActions>
|
||||
|
||||
type ClientSyncActions = WarpPromiseRecord<{
|
||||
getEnabledFeatures: (serverType: ServerType, supportedFeatures: SupportedFeatures) => EnabledFeatures
|
||||
finished: () => void
|
||||
}>
|
||||
type ClientSyncHandlerActions<Socket> = WarpSyncHandlerActions<Socket, ClientSyncActions>
|
||||
|
||||
type ClientSyncListActions = WarpPromiseRecord<{
|
||||
onListSyncAction: (action: LX.Sync.List.ActionList) => void
|
||||
list_sync_get_md5: () => string
|
||||
@@ -19,6 +33,17 @@ declare namespace LX {
|
||||
list_sync_set_list_data: (data: LX.Sync.List.ListData) => void
|
||||
list_sync_finished: () => void
|
||||
}>
|
||||
type ClientSyncHandlerListActions<Socket> = WarpSyncHandlerActions<Socket, ClientSyncListActions>
|
||||
|
||||
type ClientSyncDislikeActions = WarpPromiseRecord<{
|
||||
onDislikeSyncAction: (action: LX.Sync.Dislike.ActionList) => void
|
||||
dislike_sync_get_md5: () => string
|
||||
dislike_sync_get_sync_mode: () => LX.Sync.Dislike.SyncMode
|
||||
dislike_sync_get_list_data: () => LX.Dislike.DislikeRules
|
||||
dislike_sync_set_list_data: (data: LX.Dislike.DislikeRules) => void
|
||||
dislike_sync_finished: () => void
|
||||
}>
|
||||
type ClientSyncHandlerDislikeActions<Socket> = WarpSyncHandlerActions<Socket, ClientSyncDislikeActions>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ const initDislikeList = () => {
|
||||
}
|
||||
}
|
||||
|
||||
dislikeInfo.rules = Array.from(new Set(list)).join('\n') + '\n'
|
||||
dislikeInfo.rules = Array.from(new Set(list)).join('\n')
|
||||
|
||||
return dislikeInfo
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user