[Session] Align state and global agent switchpoints (#3845)

* Adopt synced accounts unconditionally

* Remove try/catch around resuming session

* Move to login form on resume failure

* Restructure code flow for easier reading

---------

Co-authored-by: Eric Bailey <git@esb.lol>
zio/stable
dan 2024-05-03 17:57:09 +01:00 committed by GitHub
parent 85b34418ef
commit 4a2d4253e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 70 deletions

View File

@ -15,7 +15,7 @@ export function useAccountSwitcher() {
const [pendingDid, setPendingDid] = useState<string | null>(null) const [pendingDid, setPendingDid] = useState<string | null>(null)
const {_} = useLingui() const {_} = useLingui()
const {track} = useAnalytics() const {track} = useAnalytics()
const {initSession, clearCurrentAccount} = useSessionApi() const {initSession} = useSessionApi()
const {requestSwitchToAccount} = useLoggedOutViewControls() const {requestSwitchToAccount} = useLoggedOutViewControls()
const onPressSwitchAccount = useCallback( const onPressSwitchAccount = useCallback(
@ -53,19 +53,11 @@ export function useAccountSwitcher() {
logger.error(`switch account: selectAccount failed`, { logger.error(`switch account: selectAccount failed`, {
message: e.message, message: e.message,
}) })
clearCurrentAccount() // back user out to login
} finally { } finally {
setPendingDid(null) setPendingDid(null)
} }
}, },
[ [_, track, initSession, requestSwitchToAccount, pendingDid],
_,
track,
clearCurrentAccount,
initSession,
requestSwitchToAccount,
pendingDid,
],
) )
return {onPressSwitchAccount, pendingDid} return {onPressSwitchAccount, pendingDid}

View File

@ -39,31 +39,33 @@ export const ChooseAccountForm = ({
// The session API isn't resilient to race conditions so let's just ignore this. // The session API isn't resilient to race conditions so let's just ignore this.
return return
} }
if (account.accessJwt) { if (!account.accessJwt) {
if (account.did === currentAccount?.did) { // Move to login form.
setShowLoggedOut(false)
Toast.show(_(msg`Already signed in as @${account.handle}`))
} else {
try {
setPendingDid(account.did)
await initSession(account)
logEvent('account:loggedIn', {
logContext: 'ChooseAccountForm',
withPassword: false,
})
track('Sign In', {resumedSession: true})
Toast.show(_(msg`Signed in as @${account.handle}`))
} catch (e: any) {
logger.error('choose account: initSession failed', {
message: e.message,
})
onSelectAccount(account)
} finally {
setPendingDid(null)
}
}
} else {
onSelectAccount(account) onSelectAccount(account)
return
}
if (account.did === currentAccount?.did) {
setShowLoggedOut(false)
Toast.show(_(msg`Already signed in as @${account.handle}`))
return
}
try {
setPendingDid(account.did)
await initSession(account)
logEvent('account:loggedIn', {
logContext: 'ChooseAccountForm',
withPassword: false,
})
track('Sign In', {resumedSession: true})
Toast.show(_(msg`Signed in as @${account.handle}`))
} catch (e: any) {
logger.error('choose account: initSession failed', {
message: e.message,
})
// Move to login form.
onSelectAccount(account)
} finally {
setPendingDid(null)
} }
}, },
[ [

View File

@ -337,35 +337,22 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
if (isSessionExpired(account)) { if (isSessionExpired(account)) {
logger.debug(`session: attempting to resume using previous session`) logger.debug(`session: attempting to resume using previous session`)
try { const freshAccount = await resumeSessionWithFreshAccount()
const freshAccount = await resumeSessionWithFreshAccount() __globalAgent = agent
__globalAgent = agent await fetchingGates
await fetchingGates setState(s => {
setState(s => { return {
return { accounts: [
accounts: [ freshAccount,
freshAccount, ...s.accounts.filter(a => a.did !== freshAccount.did),
...s.accounts.filter(a => a.did !== freshAccount.did), ],
], currentAgentState: {
currentAgentState: { did: freshAccount.did,
did: freshAccount.did, agent: agent,
agent: agent, },
}, needsPersist: true,
needsPersist: true, }
} })
})
} catch (e) {
/*
* Note: `agent.persistSession` is also called when this fails, and
* we handle that failure via `createPersistSessionHandler`
*/
logger.info(`session: resumeSessionWithFreshAccount failed`, {
message: e,
})
__globalAgent = PUBLIC_BSKY_AGENT
// TODO: This needs a setState.
}
} else { } else {
logger.debug(`session: attempting to reuse previous session`) logger.debug(`session: attempting to reuse previous session`)
@ -480,6 +467,11 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
const persistedSession = persisted.get('session') const persistedSession = persisted.get('session')
logger.debug(`session: persisted onUpdate`, {}) logger.debug(`session: persisted onUpdate`, {})
setState(s => ({
accounts: persistedSession.accounts,
currentAgentState: s.currentAgentState,
needsPersist: false, // Synced from another tab. Don't persist to avoid cycles.
}))
const selectedAccount = persistedSession.accounts.find( const selectedAccount = persistedSession.accounts.find(
a => a.did === persistedSession.currentAccount?.did, a => a.did === persistedSession.currentAccount?.did,
@ -531,15 +523,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
did: undefined, did: undefined,
agent: PUBLIC_BSKY_AGENT, agent: PUBLIC_BSKY_AGENT,
}, },
needsPersist: true, // TODO: This seems bad in this codepath. Existing behavior. needsPersist: false, // Synced from another tab. Don't persist to avoid cycles.
})) }))
} }
setState(s => ({
accounts: persistedSession.accounts,
currentAgentState: s.currentAgentState,
needsPersist: false, // Synced from another tab. Don't persist to avoid cycles.
}))
}) })
}, [state, setState, initSession]) }, [state, setState, initSession])