完善同步

This commit is contained in:
lyswhut 2023-03-01 18:50:30 +08:00
parent 7c8a706ad3
commit 2169c9eb3b
10 changed files with 57 additions and 44 deletions

18
package-lock.json generated
View File

@ -1,17 +1,17 @@
{ {
"name": "lx-music-mobile", "name": "lx-music-mobile",
"version": "1.0.0-beta.4", "version": "1.0.0-beta.5",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "lx-music-mobile", "name": "lx-music-mobile",
"version": "1.0.0-beta.4", "version": "1.0.0-beta.5",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@craftzdog/react-native-buffer": "^6.0.5", "@craftzdog/react-native-buffer": "^6.0.5",
"@react-native-async-storage/async-storage": "^1.17.11", "@react-native-async-storage/async-storage": "^1.17.11",
"@react-native-clipboard/clipboard": "^1.11.1", "@react-native-clipboard/clipboard": "^1.11.2",
"@react-native-community/checkbox": "^0.5.14", "@react-native-community/checkbox": "^0.5.14",
"@react-native-community/slider": "^4.4.2", "@react-native-community/slider": "^4.4.2",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
@ -2123,9 +2123,9 @@
} }
}, },
"node_modules/@react-native-clipboard/clipboard": { "node_modules/@react-native-clipboard/clipboard": {
"version": "1.11.1", "version": "1.11.2",
"resolved": "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.11.1.tgz", "resolved": "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.11.2.tgz",
"integrity": "sha512-nvSIIHzybVWqYxcJE5hpT17ekxAAg383Ggzw5WrYHtkKX61N1AwaKSNmXs5xHV7pmKSOe/yWjtSwxIzfW51I5Q==", "integrity": "sha512-bHyZVW62TuleiZsXNHS1Pv16fWc0fh8O9WvBzl4h2fykqZRW9a+Pv/RGTH56E3X2PqzHP38K5go8zmCZUoIsoQ==",
"peerDependencies": { "peerDependencies": {
"react": ">=16.0", "react": ">=16.0",
"react-native": ">=0.57.0" "react-native": ">=0.57.0"
@ -13269,9 +13269,9 @@
} }
}, },
"@react-native-clipboard/clipboard": { "@react-native-clipboard/clipboard": {
"version": "1.11.1", "version": "1.11.2",
"resolved": "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.11.1.tgz", "resolved": "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.11.2.tgz",
"integrity": "sha512-nvSIIHzybVWqYxcJE5hpT17ekxAAg383Ggzw5WrYHtkKX61N1AwaKSNmXs5xHV7pmKSOe/yWjtSwxIzfW51I5Q==", "integrity": "sha512-bHyZVW62TuleiZsXNHS1Pv16fWc0fh8O9WvBzl4h2fykqZRW9a+Pv/RGTH56E3X2PqzHP38K5go8zmCZUoIsoQ==",
"requires": {} "requires": {}
}, },
"@react-native-community/checkbox": { "@react-native-community/checkbox": {

View File

@ -1,6 +1,6 @@
{ {
"name": "lx-music-mobile", "name": "lx-music-mobile",
"version": "1.0.0-beta.4", "version": "1.0.0-beta.5",
"versionCode": 53, "versionCode": 53,
"private": true, "private": true,
"scripts": { "scripts": {
@ -44,7 +44,7 @@
"dependencies": { "dependencies": {
"@craftzdog/react-native-buffer": "^6.0.5", "@craftzdog/react-native-buffer": "^6.0.5",
"@react-native-async-storage/async-storage": "^1.17.11", "@react-native-async-storage/async-storage": "^1.17.11",
"@react-native-clipboard/clipboard": "^1.11.1", "@react-native-clipboard/clipboard": "^1.11.2",
"@react-native-community/checkbox": "^0.5.14", "@react-native-community/checkbox": "^0.5.14",
"@react-native-community/slider": "^4.4.2", "@react-native-community/slider": "^4.4.2",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",

View File

@ -42,8 +42,6 @@ global.lx = {
// prevListPlayIndex: -1, // prevListPlayIndex: -1,
// syncKeyInfo: {}, // syncKeyInfo: {},
isSyncEnableing: false,
isEnableSyncLog: false, isEnableSyncLog: false,

View File

@ -33,6 +33,7 @@ const handleConnection = (socket: LX.Sync.Socket) => {
const heartbeatTools = { const heartbeatTools = {
failedNum: 0, failedNum: 0,
maxTryNum: 3,
pingTimeout: null as NodeJS.Timeout | null, pingTimeout: null as NodeJS.Timeout | null,
delayRetryTimeout: null as NodeJS.Timeout | null, delayRetryTimeout: null as NodeJS.Timeout | null,
handleOpen() { handleOpen() {
@ -59,16 +60,21 @@ const heartbeatTools = {
// client = null // client = null
if (!client) return 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 = setTimeout(() => {
this.delayRetryTimeout = null this.delayRetryTimeout = null
if (!client) return if (!client) return
console.log(dateFormat(new Date()), 'reconnnect...') console.log(dateFormat(new Date()), 'reconnnect...')
sendSyncStatus({
status: false,
message: `Try reconnnect... (${this.failedNum}/${this.maxTryNum})`,
})
connect(client.data.urlInfo, client.data.keyInfo) connect(client.data.urlInfo, client.data.keyInfo)
}, 2000) }, 2000)
this.failedNum++
}, },
clearTimeout() { clearTimeout() {
if (this.delayRetryTimeout) { if (this.delayRetryTimeout) {
@ -186,15 +192,25 @@ export const connect = (urlInfo: LX.Sync.UrlInfo, keyInfo: LX.Sync.KeyInfo) => {
} }
}) })
}) })
client.addEventListener('close', () => { client.addEventListener('close', ({ code }) => {
sendSyncStatus({
status: false,
message: '',
})
const err = new Error('closed') const err = new Error('closed')
for (const handler of closeEvents) void handler(err) for (const handler of closeEvents) void handler(err)
closeEvents = [] closeEvents = []
events = {} 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,
})
}) })
} }
@ -204,6 +220,7 @@ export const disconnect = async() => {
client.close(SYNC_CLOSE_CODE.normal) client.close(SYNC_CLOSE_CODE.normal)
client = null client = null
heartbeatTools.clearTimeout() heartbeatTools.clearTimeout()
heartbeatTools.failedNum = 0
} }
export const getStatus = (): LX.Sync.Status => status export const getStatus = (): LX.Sync.Status => status

View File

@ -5,13 +5,18 @@ import { SYNC_CODE } from '@/config/constant'
import log from '../log' import log from '../log'
import { parseUrl } from './utils' import { parseUrl } from './utils'
let connectId = 0
const handleConnect = async(host: string, authCode?: string) => { const handleConnect = async(host: string, authCode?: string) => {
// const hostInfo = await getSyncHost() // const hostInfo = await getSyncHost()
// console.log(hostInfo) // console.log(hostInfo)
// if (!hostInfo || !hostInfo.host || !hostInfo.port) throw new Error(SYNC_CODE.unknownServiceAddress) // if (!hostInfo || !hostInfo.host || !hostInfo.port) throw new Error(SYNC_CODE.unknownServiceAddress)
const id = connectId
const urlInfo = parseUrl(host) const urlInfo = parseUrl(host)
await disconnectServer(false) await disconnectServer(false)
if (id != connectId) return
const keyInfo = await handleAuth(urlInfo, authCode) const keyInfo = await handleAuth(urlInfo, authCode)
if (id != connectId) return
socketConnect(urlInfo, keyInfo) socketConnect(urlInfo, keyInfo)
} }
const handleDisconnect = async() => { const handleDisconnect = async() => {
@ -23,7 +28,9 @@ const connectServer = async(host: string, authCode?: string) => {
status: false, status: false,
message: SYNC_CODE.connecting, message: SYNC_CODE.connecting,
}) })
const id = connectId
return handleConnect(host, authCode).catch(async err => { return handleConnect(host, authCode).catch(async err => {
if (id != connectId) return
sendSyncStatus({ sendSyncStatus({
status: false, status: false,
message: err.message, message: err.message,
@ -44,6 +51,7 @@ const connectServer = async(host: string, authCode?: string) => {
const disconnectServer = async(isResetStatus = true) => handleDisconnect().then(() => { const disconnectServer = async(isResetStatus = true) => handleDisconnect().then(() => {
log.info('disconnect...') log.info('disconnect...')
if (isResetStatus) { if (isResetStatus) {
connectId++
sendSyncStatus({ sendSyncStatus({
status: false, status: false,
message: '', message: '',

View File

@ -121,9 +121,8 @@ const HistoryList = forwardRef<HistoryListType, HistoryListProps>(({ onSelect },
) )
}) })
export default memo(({ setHost, isWaiting }: { export default memo(({ setHost }: {
setHost: (host: string) => void setHost: (host: string) => void
isWaiting: boolean
}) => { }) => {
const t = useI18n() const t = useI18n()
const isEnableSync = useSettingValue('sync.enable') const isEnableSync = useSettingValue('sync.enable')
@ -141,7 +140,7 @@ export default memo(({ setHost, isWaiting }: {
return ( return (
<> <>
<View style={styles.btn}> <View style={styles.btn}>
<Button disabled={isWaiting || isEnableSync} onPress={showPopup}>{t('setting_sync_history')}</Button> <Button disabled={isEnableSync} onPress={showPopup}>{t('setting_sync_history')}</Button>
</View> </View>
<HistoryList ref={listRef} onSelect={handleSelect} /> <HistoryList ref={listRef} onSelect={handleSelect} />
</> </>

View File

@ -50,11 +50,9 @@ const HostInput = memo(({ setHost, host, disabled }: {
}) })
export default memo(({ host, setHost, isWaiting, setIsWaiting }: { export default memo(({ host, setHost }: {
host: string host: string
isWaiting: boolean
setHost: (host: string) => void setHost: (host: string) => void
setIsWaiting: (isWaiting: boolean) => void
}) => { }) => {
const t = useI18n() const t = useI18n()
const setIsEnableSync = useCallback((enable: boolean) => { const setIsEnableSync = useCallback((enable: boolean) => {
@ -104,13 +102,8 @@ export default memo(({ host, setHost, isWaiting, setIsWaiting }: {
if (enable) void addSyncHostHistory(host) if (enable) void addSyncHostHistory(host)
global.lx.isSyncEnableing = true void (enable ? connectServer(host) : disconnectServer())
setIsWaiting(true) }, [host, setIsEnableSync])
;(enable ? connectServer(host) : disconnectServer()).finally(() => {
global.lx.isSyncEnableing = false
setIsWaiting(false)
})
}, [host, setIsEnableSync, setIsWaiting])
const handleUpdateHost = useCallback((h: string) => { const handleUpdateHost = useCallback((h: string) => {
@ -155,12 +148,12 @@ export default memo(({ host, setHost, isWaiting, setIsWaiting }: {
return ( return (
<> <>
<View style={styles.infoContent}> <View style={styles.infoContent}>
<CheckBoxItem disabled={isWaiting || !host} check={isEnableSync} label={t('setting_sync_enbale')} onChange={handleSetEnableSync} /> <CheckBoxItem disabled={!host} check={isEnableSync} label={t('setting_sync_enbale')} onChange={handleSetEnableSync} />
<Text style={styles.textAddr} size={13}>{t('setting_sync_address', { address })}</Text> <Text style={styles.textAddr} size={13}>{t('setting_sync_address', { address })}</Text>
<Text style={styles.text} size={13}>{t('setting_sync_status', { status })}</Text> <Text style={styles.text} size={13}>{t('setting_sync_status', { status })}</Text>
</View> </View>
<View style={styles.inputContent} > <View style={styles.inputContent} >
<HostInput setHost={handleUpdateHost} host={host} disabled={isWaiting || isEnableSync} /> <HostInput setHost={handleUpdateHost} host={host} disabled={isEnableSync} />
</View> </View>
<ConfirmAlert <ConfirmAlert
onCancel={handleCancelSetCode} onCancel={handleCancelSetCode}

View File

@ -10,12 +10,11 @@ export default memo(() => {
const t = useI18n() const t = useI18n()
const [host, setHost] = useState('') const [host, setHost] = useState('')
const [isWaiting, setIsWaiting] = useState(global.lx.isSyncEnableing)
return ( return (
<Section title={t('setting_sync')}> <Section title={t('setting_sync')}>
<IsEnable host={host} setHost={setHost} isWaiting={isWaiting} setIsWaiting={setIsWaiting} /> <IsEnable host={host} setHost={setHost} />
<History setHost={setHost} isWaiting={isWaiting} /> <History setHost={setHost} />
</Section> </Section>
) )
}) })

1
src/types/app.d.ts vendored
View File

@ -28,7 +28,6 @@ interface Lx {
restorePlayInfo: LX.Player.SavedPlayInfo | null restorePlayInfo: LX.Player.SavedPlayInfo | null
isScreenKeepAwake: boolean isScreenKeepAwake: boolean
isPlayedStop: boolean isPlayedStop: boolean
isSyncEnableing: boolean
isEnableSyncLog: boolean isEnableSyncLog: boolean
playerTrackId: string playerTrackId: string

View File

@ -1179,10 +1179,10 @@
dependencies: dependencies:
"merge-options" "^3.0.4" "merge-options" "^3.0.4"
"@react-native-clipboard/clipboard@^1.11.1": "@react-native-clipboard/clipboard@^1.11.2":
"integrity" "sha512-nvSIIHzybVWqYxcJE5hpT17ekxAAg383Ggzw5WrYHtkKX61N1AwaKSNmXs5xHV7pmKSOe/yWjtSwxIzfW51I5Q==" "integrity" "sha512-bHyZVW62TuleiZsXNHS1Pv16fWc0fh8O9WvBzl4h2fykqZRW9a+Pv/RGTH56E3X2PqzHP38K5go8zmCZUoIsoQ=="
"resolved" "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.11.1.tgz" "resolved" "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.11.2.tgz"
"version" "1.11.1" "version" "1.11.2"
"@react-native-community/checkbox@^0.5.14": "@react-native-community/checkbox@^0.5.14":
"integrity" "sha512-UmGf3wBpoCXLmVRKIDZyzOG+QR1fOhm0FOw4KzxHTCXpsBvZgIn5wbJ+MWk4io5RohQdY8GSX2MYFmkPJeJpeA==" "integrity" "sha512-UmGf3wBpoCXLmVRKIDZyzOG+QR1fOhm0FOw4KzxHTCXpsBvZgIn5wbJ+MWk4io5RohQdY8GSX2MYFmkPJeJpeA=="