XuqmGroup-RNSDK/src/sdk.ts

118 行
2.9 KiB
TypeScript

import { _clearToken, setUserId as setCommonUserId, getUserId as getCommonUserId, XuqmSDK as CommonXuqmSDK } from '@xuqm/rn-common'
import { ImSDK } from '@xuqm/rn-im'
import { PushSDK } from '@xuqm/rn-push'
import type { UserProfile } from '@xuqm/rn-im'
export interface UnifiedLoginRefreshResult {
userSig: string
expiresAt?: number
}
export interface UnifiedLoginOptions {
userId: string
userSig: string
profile?: Pick<UserProfile, 'nickname' | 'avatar' | 'gender'>
expiresAt?: number
refreshUserSig?: () => Promise<UnifiedLoginRefreshResult>
}
type SessionState = UnifiedLoginOptions
const REFRESH_GRACE_MS = 5 * 60 * 1000
const REFRESH_RETRY_MS = 30 * 1000
let currentSession: SessionState | null = null
let refreshTimer: ReturnType<typeof setTimeout> | null = null
let refreshInFlight = false
function clearRefreshTimer(): void {
if (refreshTimer) {
clearTimeout(refreshTimer)
refreshTimer = null
}
}
async function applyLoginSession(session: SessionState): Promise<void> {
clearRefreshTimer()
setCommonUserId(session.userId)
try {
await ImSDK.loginWithUserSig(session.userId, session.userSig)
} catch (error) {
setCommonUserId(null)
currentSession = null
throw error
}
currentSession = session
try {
await PushSDK.initialize(session.userId)
} catch (error) {
void error
}
scheduleRefresh()
}
async function refreshSession(): Promise<void> {
const session = currentSession
if (refreshInFlight || !session?.refreshUserSig) return
refreshInFlight = true
try {
const refreshed = await session.refreshUserSig()
if (currentSession !== session) return
await applyLoginSession({
...session,
userSig: refreshed.userSig,
expiresAt: refreshed.expiresAt ?? session.expiresAt,
})
} catch (error) {
clearRefreshTimer()
refreshTimer = setTimeout(() => {
void refreshSession()
}, REFRESH_RETRY_MS)
if (CommonXuqmSDK.getUserId() && process.env.NODE_ENV !== 'production') {
console.warn('[XuqmSDK] userSig refresh failed, will retry', error)
}
} finally {
refreshInFlight = false
}
}
function scheduleRefresh(): void {
clearRefreshTimer()
const session = currentSession
if (!session?.refreshUserSig || !session.expiresAt) return
const delayMs = Math.max(session.expiresAt - Date.now() - REFRESH_GRACE_MS, 0)
refreshTimer = setTimeout(() => {
void refreshSession()
}, delayMs)
}
async function login(options: UnifiedLoginOptions): Promise<void> {
if (currentSession) {
await logout()
}
await applyLoginSession(options)
}
async function logout(): Promise<void> {
clearRefreshTimer()
const userId = currentSession?.userId ?? getCommonUserId()
currentSession = null
refreshInFlight = false
setCommonUserId(null)
if (userId) {
try {
await PushSDK.logout(userId)
} catch (error) {
void error
}
}
ImSDK.disconnect()
await _clearToken()
}
export const XuqmSDK = {
...CommonXuqmSDK,
login,
logout,
}