abstract out sessionstore
This commit is contained in:
@@ -10,7 +10,6 @@ import {
|
||||
} from 'react'
|
||||
import {type AtpSessionEvent, type BskyAgent} from '@atproto/api'
|
||||
|
||||
import * as persisted from '#/state/persisted'
|
||||
import {useCloseAllActiveElements} from '#/state/util'
|
||||
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
|
||||
import {AnalyticsContext, useAnalyticsBase, utils} from '#/analytics'
|
||||
@@ -24,7 +23,7 @@ import {
|
||||
createAgentAndResume,
|
||||
sessionAccountToSession,
|
||||
} from './agent'
|
||||
import {type Action, getInitialState, reducer, type State} from './reducer'
|
||||
import {SessionStore} from './store'
|
||||
export {isSignupQueued} from './util'
|
||||
import {addSessionDebugLog} from './logging'
|
||||
export type {SessionAccount} from '#/state/session/types'
|
||||
@@ -61,47 +60,6 @@ const ApiContext = createContext<SessionApiContext>({
|
||||
})
|
||||
ApiContext.displayName = 'SessionApiContext'
|
||||
|
||||
class SessionStore {
|
||||
private state: State
|
||||
private listeners = new Set<() => void>()
|
||||
|
||||
constructor() {
|
||||
// Careful: By the time this runs, `persisted` needs to already be filled.
|
||||
const initialState = getInitialState(persisted.get('session').accounts)
|
||||
addSessionDebugLog({type: 'reducer:init', state: initialState})
|
||||
this.state = initialState
|
||||
}
|
||||
|
||||
getState = (): State => {
|
||||
return this.state
|
||||
}
|
||||
|
||||
subscribe = (listener: () => void) => {
|
||||
this.listeners.add(listener)
|
||||
return () => {
|
||||
this.listeners.delete(listener)
|
||||
}
|
||||
}
|
||||
|
||||
dispatch = (action: Action) => {
|
||||
const nextState = reducer(this.state, action)
|
||||
this.state = nextState
|
||||
// Persist synchronously without waiting for the React render cycle.
|
||||
if (nextState.needsPersist) {
|
||||
nextState.needsPersist = false
|
||||
const persistedData = {
|
||||
accounts: nextState.accounts,
|
||||
currentAccount: nextState.accounts.find(
|
||||
a => a.did === nextState.currentAgentState.did,
|
||||
),
|
||||
}
|
||||
addSessionDebugLog({type: 'persisted:broadcast', data: persistedData})
|
||||
persisted.write('session', persistedData)
|
||||
}
|
||||
this.listeners.forEach(listener => listener())
|
||||
}
|
||||
}
|
||||
|
||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
const ax = useAnalyticsBase()
|
||||
const cancelPendingTask = useOneTaskAtATime()
|
||||
@@ -308,14 +266,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
[store, cancelPendingTask],
|
||||
)
|
||||
useEffect(() => {
|
||||
return persisted.onUpdate('session', nextSession => {
|
||||
const synced = nextSession
|
||||
addSessionDebugLog({type: 'persisted:receive', data: synced})
|
||||
store.dispatch({
|
||||
type: 'synced-accounts',
|
||||
syncedAccounts: synced.accounts,
|
||||
syncedCurrentDid: synced.currentAccount?.did,
|
||||
})
|
||||
return store.onUpdate(synced => {
|
||||
const syncedAccount = synced.accounts.find(
|
||||
a => a.did === synced.currentAccount?.did,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import * as persisted from '#/state/persisted'
|
||||
import {type Schema} from '#/state/persisted/schema'
|
||||
import {addSessionDebugLog} from './logging'
|
||||
import {type Action, getInitialState, reducer, type State} from './reducer'
|
||||
|
||||
export class SessionStore {
|
||||
private state: State
|
||||
private listeners = new Set<() => void>()
|
||||
|
||||
constructor() {
|
||||
// Careful: By the time this runs, `persisted` needs to already be filled.
|
||||
const initialState = getInitialState(persisted.get('session').accounts)
|
||||
addSessionDebugLog({type: 'reducer:init', state: initialState})
|
||||
this.state = initialState
|
||||
}
|
||||
|
||||
getState = (): State => {
|
||||
return this.state
|
||||
}
|
||||
|
||||
subscribe = (listener: () => void) => {
|
||||
this.listeners.add(listener)
|
||||
return () => {
|
||||
this.listeners.delete(listener)
|
||||
}
|
||||
}
|
||||
|
||||
dispatch = (action: Action) => {
|
||||
const nextState = reducer(this.state, action)
|
||||
this.state = nextState
|
||||
// Persist synchronously without waiting for the React render cycle.
|
||||
if (nextState.needsPersist) {
|
||||
nextState.needsPersist = false
|
||||
const persistedData = {
|
||||
accounts: nextState.accounts,
|
||||
currentAccount: nextState.accounts.find(
|
||||
a => a.did === nextState.currentAgentState.did,
|
||||
),
|
||||
}
|
||||
addSessionDebugLog({type: 'persisted:broadcast', data: persistedData})
|
||||
persisted.write('session', persistedData)
|
||||
}
|
||||
this.listeners.forEach(listener => listener())
|
||||
}
|
||||
|
||||
onUpdate = (callback: (synced: Schema['session']) => void): (() => void) => {
|
||||
return persisted.onUpdate('session', nextSession => {
|
||||
addSessionDebugLog({type: 'persisted:receive', data: nextSession})
|
||||
this.dispatch({
|
||||
type: 'synced-accounts',
|
||||
syncedAccounts: nextSession.accounts,
|
||||
syncedCurrentDid: nextSession.currentAccount?.did,
|
||||
})
|
||||
callback(nextSession)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user