abstract out sessionstore
This commit is contained in:
@@ -10,7 +10,6 @@ import {
|
|||||||
} from 'react'
|
} from 'react'
|
||||||
import {type AtpSessionEvent, type BskyAgent} from '@atproto/api'
|
import {type AtpSessionEvent, type BskyAgent} from '@atproto/api'
|
||||||
|
|
||||||
import * as persisted from '#/state/persisted'
|
|
||||||
import {useCloseAllActiveElements} from '#/state/util'
|
import {useCloseAllActiveElements} from '#/state/util'
|
||||||
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
|
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
|
||||||
import {AnalyticsContext, useAnalyticsBase, utils} from '#/analytics'
|
import {AnalyticsContext, useAnalyticsBase, utils} from '#/analytics'
|
||||||
@@ -24,7 +23,7 @@ import {
|
|||||||
createAgentAndResume,
|
createAgentAndResume,
|
||||||
sessionAccountToSession,
|
sessionAccountToSession,
|
||||||
} from './agent'
|
} from './agent'
|
||||||
import {type Action, getInitialState, reducer, type State} from './reducer'
|
import {SessionStore} from './store'
|
||||||
export {isSignupQueued} from './util'
|
export {isSignupQueued} from './util'
|
||||||
import {addSessionDebugLog} from './logging'
|
import {addSessionDebugLog} from './logging'
|
||||||
export type {SessionAccount} from '#/state/session/types'
|
export type {SessionAccount} from '#/state/session/types'
|
||||||
@@ -61,47 +60,6 @@ const ApiContext = createContext<SessionApiContext>({
|
|||||||
})
|
})
|
||||||
ApiContext.displayName = '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<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
const ax = useAnalyticsBase()
|
const ax = useAnalyticsBase()
|
||||||
const cancelPendingTask = useOneTaskAtATime()
|
const cancelPendingTask = useOneTaskAtATime()
|
||||||
@@ -308,14 +266,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
[store, cancelPendingTask],
|
[store, cancelPendingTask],
|
||||||
)
|
)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return persisted.onUpdate('session', nextSession => {
|
return store.onUpdate(synced => {
|
||||||
const synced = nextSession
|
|
||||||
addSessionDebugLog({type: 'persisted:receive', data: synced})
|
|
||||||
store.dispatch({
|
|
||||||
type: 'synced-accounts',
|
|
||||||
syncedAccounts: synced.accounts,
|
|
||||||
syncedCurrentDid: synced.currentAccount?.did,
|
|
||||||
})
|
|
||||||
const syncedAccount = synced.accounts.find(
|
const syncedAccount = synced.accounts.find(
|
||||||
a => a.did === synced.currentAccount?.did,
|
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