feat: support media account unbind requests
This commit is contained in:
@@ -150,6 +150,7 @@ type MonitorExecutionPhase =
|
||||
const heartbeatIntervalMs = 15_000
|
||||
const pullIntervalMs = 60_000
|
||||
const publishPullIntervalMs = 30_000
|
||||
const accountSyncIntervalMs = 30_000
|
||||
const pumpWatchdogIntervalMs = 30_000
|
||||
const leaseExtendIntervalMs = 60_000
|
||||
const defaultPublishTaskTimeoutMs = 5 * 60_000
|
||||
@@ -258,11 +259,13 @@ interface RuntimeState {
|
||||
publishFallbackBackoffUntil: number
|
||||
heartbeatTimer: ReturnType<typeof setInterval> | null
|
||||
pullTimer: ReturnType<typeof setInterval> | null
|
||||
accountSyncTimer: ReturnType<typeof setInterval> | null
|
||||
pumpWatchdogTimer: ReturnType<typeof setInterval> | null
|
||||
accountHealthReportTimer: ReturnType<typeof setTimeout> | null
|
||||
accountHealthReportQueue: Map<string, DesktopAccountHealthReport>
|
||||
accountHealthReportBadAccounts: Set<string>
|
||||
accountRemoteHealth: Map<string, DesktopAccountInfo['health']>
|
||||
accountSyncRunning: boolean
|
||||
dispatchWsClient: DispatchWsClient | null
|
||||
dispatchWsConnected: boolean
|
||||
lastHeartbeatAt: number
|
||||
@@ -289,11 +292,13 @@ const state: RuntimeState = {
|
||||
publishFallbackBackoffUntil: 0,
|
||||
heartbeatTimer: null,
|
||||
pullTimer: null,
|
||||
accountSyncTimer: null,
|
||||
pumpWatchdogTimer: null,
|
||||
accountHealthReportTimer: null,
|
||||
accountHealthReportQueue: new Map<string, DesktopAccountHealthReport>(),
|
||||
accountHealthReportBadAccounts: new Set<string>(),
|
||||
accountRemoteHealth: new Map<string, DesktopAccountInfo['health']>(),
|
||||
accountSyncRunning: false,
|
||||
dispatchWsClient: null,
|
||||
dispatchWsConnected: false,
|
||||
lastHeartbeatAt: 0,
|
||||
@@ -712,6 +717,7 @@ function startRuntime(): void {
|
||||
connectDispatchWs()
|
||||
scheduleHeartbeatLoop()
|
||||
schedulePullLoop()
|
||||
scheduleAccountSyncLoop()
|
||||
schedulePumpWatchdogLoop()
|
||||
|
||||
void sendHeartbeat('startup')
|
||||
@@ -753,6 +759,10 @@ function stopRuntime(): void {
|
||||
clearInterval(state.pullTimer)
|
||||
state.pullTimer = null
|
||||
}
|
||||
if (state.accountSyncTimer) {
|
||||
clearInterval(state.accountSyncTimer)
|
||||
state.accountSyncTimer = null
|
||||
}
|
||||
if (state.pumpWatchdogTimer) {
|
||||
clearInterval(state.pumpWatchdogTimer)
|
||||
state.pumpWatchdogTimer = null
|
||||
@@ -824,6 +834,16 @@ function schedulePullLoop(): void {
|
||||
}, publishPullIntervalMs)
|
||||
}
|
||||
|
||||
function scheduleAccountSyncLoop(): void {
|
||||
if (state.accountSyncTimer) {
|
||||
clearInterval(state.accountSyncTimer)
|
||||
}
|
||||
|
||||
state.accountSyncTimer = setInterval(() => {
|
||||
void syncAccounts('timer')
|
||||
}, accountSyncIntervalMs)
|
||||
}
|
||||
|
||||
function schedulePumpWatchdogLoop(): void {
|
||||
if (state.pumpWatchdogTimer) {
|
||||
clearInterval(state.pumpWatchdogTimer)
|
||||
@@ -1180,13 +1200,17 @@ async function sendHeartbeat(source: 'startup' | 'timer'): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function syncAccounts(source: 'startup' | 'manual'): Promise<void> {
|
||||
async function syncAccounts(source: 'startup' | 'manual' | 'timer'): Promise<void> {
|
||||
if (!canRunLive(state.session)) {
|
||||
return
|
||||
}
|
||||
if (state.accountSyncRunning) {
|
||||
return
|
||||
}
|
||||
|
||||
state.accountSyncRunning = true
|
||||
try {
|
||||
const accounts = await listDesktopAccounts()
|
||||
const accounts = await consumeDeleteRequestedAccounts(await listDesktopAccounts())
|
||||
state.lastAccountsSyncAt = Date.now()
|
||||
state.lastError = null
|
||||
|
||||
@@ -1298,9 +1322,47 @@ async function syncAccounts(source: 'startup' | 'manual'): Promise<void> {
|
||||
setSchedulerError(message)
|
||||
|
||||
recordActivity('warn', '账号同步失败', message)
|
||||
} finally {
|
||||
state.accountSyncRunning = false
|
||||
}
|
||||
}
|
||||
|
||||
async function consumeDeleteRequestedAccounts(
|
||||
accounts: DesktopAccountInfo[],
|
||||
): Promise<DesktopAccountInfo[]> {
|
||||
const remainingAccounts: DesktopAccountInfo[] = []
|
||||
|
||||
for (const account of accounts) {
|
||||
if (!account.delete_requested_at) {
|
||||
remainingAccounts.push(account)
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
await deleteDesktopAccount(account.id, account.sync_version)
|
||||
await clearSessionHandle(account.id)
|
||||
forgetTrackedAccountHealth(account.id)
|
||||
state.accountProfiles.delete(account.id)
|
||||
recordActivity(
|
||||
'info',
|
||||
'账号已自动解绑',
|
||||
`${account.display_name} 已按服务端解绑申请移除,并清理了当前机器上的本地会话缓存。`,
|
||||
)
|
||||
} catch (error) {
|
||||
remainingAccounts.push(account)
|
||||
console.warn('[desktop-runtime] requested desktop account cleanup failed', {
|
||||
accountId: account.id,
|
||||
platform: account.platform,
|
||||
platformUid: account.platform_uid,
|
||||
message: errorMessage(error),
|
||||
})
|
||||
recordActivity('warn', '账号自动解绑失败', `${account.display_name}:${errorMessage(error)}`)
|
||||
}
|
||||
}
|
||||
|
||||
return remainingAccounts
|
||||
}
|
||||
|
||||
async function cleanupDuplicateDesktopAccounts(accounts: DesktopAccountInfo[]): Promise<void> {
|
||||
for (const account of accounts) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user