lx-music-desktop/src/main/modules/sync/server/user/data.ts
2023-08-30 14:30:47 +08:00

155 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import fs from 'node:fs'
import path from 'node:path'
import { randomBytes } from 'node:crypto'
import { throttle } from '@common/utils/common'
import { filterFileName, toMD5 } from '../utils'
import { File } from '@common/constants_sync'
interface ServerInfo {
serverId: string
version: number
}
interface DevicesInfo {
userName: string
clients: Record<string, LX.Sync.ServerKeyInfo>
}
const saveServerInfoThrottle = throttle(() => {
fs.writeFile(path.join(global.lxDataPath, File.serverDataPath, File.serverInfoJSON), JSON.stringify(serverInfo), (err) => {
if (err) console.error(err)
})
})
let serverInfo: ServerInfo
const exists = async(path: string) => fs.promises.stat(path).then(() => true).catch(() => false)
export const initServerInfo = async() => {
if (serverInfo != null) return
const serverInfoFilePath = path.join(global.lxDataPath, File.serverDataPath, File.serverInfoJSON)
if (await exists(serverInfoFilePath)) {
// eslint-disable-next-line require-atomic-updates
serverInfo = JSON.parse((await fs.promises.readFile(serverInfoFilePath)).toString())
} else {
// eslint-disable-next-line require-atomic-updates
serverInfo = {
serverId: randomBytes(4 * 4).toString('base64'),
version: 2,
}
const syncDataPath = path.join(global.lxDataPath, File.serverDataPath)
if (!await exists(syncDataPath)) {
await fs.promises.mkdir(syncDataPath, { recursive: true })
}
saveServerInfoThrottle()
}
}
export const getServerId = () => {
return serverInfo.serverId
}
export const getVersion = async() => {
await initServerInfo()
return serverInfo.version ?? 1
}
export const setVersion = async(version: number) => {
await initServerInfo()
serverInfo.version = version
saveServerInfoThrottle()
}
export const getUserDirname = (userName: string) => `${filterFileName(userName)}_${toMD5(userName).substring(0, 6)}`
export const getUserConfig = (userName: string) => {
return {
maxSnapshotNum: global.lx.appSetting['sync.server.maxSsnapshotNum'],
'list.addMusicLocationType': global.lx.appSetting['list.addMusicLocationType'],
}
}
// 读取所有用户目录下的devicesInfo信息建立clientId与用户的对应关系用于非首次连接
// let deviceUserMap: Map<string, string> = new Map<string, string>()
// const init
// for (const deviceInfo of fs.readdirSync(syncDataPath).map(dirname => {
// const devicesFilePath = path.join(syncDataPath, dirname, File.userDevicesJSON)
// if (fs.existsSync(devicesFilePath)) {
// const devicesInfo = JSON.parse(fs.readFileSync(devicesFilePath).toString()) as DevicesInfo
// if (getUserDirname(devicesInfo.userName) == dirname) return { userName: devicesInfo.userName, devices: devicesInfo.clients }
// }
// return { userName: '', devices: {} }
// })) {
// for (const device of Object.values(deviceInfo.devices)) {
// if (deviceInfo.userName) deviceUserMap.set(device.clientId, deviceInfo.userName)
// }
// }
// export const getUserName = (clientId: string): string | null => {
// if (!clientId) return null
// return deviceUserMap.get(clientId) ?? null
// }
// export const setUserName = (clientId: string, dir: string) => {
// deviceUserMap.set(clientId, dir)
// }
// export const deleteUserName = (clientId: string) => {
// deviceUserMap.delete(clientId)
// }
export const createClientKeyInfo = (deviceName: string, isMobile: boolean): LX.Sync.ServerKeyInfo => {
const keyInfo: LX.Sync.ServerKeyInfo = {
clientId: randomBytes(4 * 4).toString('base64'),
key: randomBytes(16).toString('base64'),
deviceName,
isMobile,
lastConnectDate: 0,
}
return keyInfo
}
export class UserDataManage {
userName: string
userDir: string
devicesFilePath: string
devicesInfo: DevicesInfo
private readonly saveDevicesInfoThrottle: () => void
getAllClientKeyInfo = () => {
return Object.values(this.devicesInfo.clients).sort((a, b) => (b.lastConnectDate ?? 0) - (a.lastConnectDate ?? 0))
}
saveClientKeyInfo = (keyInfo: LX.Sync.ServerKeyInfo) => {
if (this.devicesInfo.clients[keyInfo.clientId] == null && Object.keys(this.devicesInfo.clients).length > 101) throw new Error('max keys')
this.devicesInfo.clients[keyInfo.clientId] = keyInfo
this.saveDevicesInfoThrottle()
}
getClientKeyInfo = (clientId?: string | null): LX.Sync.ServerKeyInfo | null => {
if (!clientId) return null
return this.devicesInfo.clients[clientId] ?? null
}
removeClientKeyInfo = async(clientId: string) => {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this.devicesInfo.clients[clientId]
this.saveDevicesInfoThrottle()
}
isIncluedsClient = (clientId: string) => {
return Object.values(this.devicesInfo.clients).some(client => client.clientId == clientId)
}
constructor(userName: string) {
this.userName = userName
const syncDataPath = path.join(global.lxDataPath, File.serverDataPath)
this.userDir = syncDataPath
this.devicesFilePath = path.join(this.userDir, File.userDevicesJSON)
this.devicesInfo = fs.existsSync(this.devicesFilePath) ? JSON.parse(fs.readFileSync(this.devicesFilePath).toString()) : { userName, clients: {} }
this.saveDevicesInfoThrottle = throttle(() => {
fs.writeFile(this.devicesFilePath, JSON.stringify(this.devicesInfo), 'utf8', (err) => {
if (err) console.error(err)
})
})
}
}
// type UserDataManages = Map<string, UserDataManage>
// export const createUserDataManage = (user: LX.UserConfig) => {
// const manage = Object.create(userDataManage) as typeof userDataManage
// manage.userDir = user.dataPath
// }