Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions shared/constants/config/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ export interface State extends Store {
setLoginError: (error?: RPCError) => void
logoutAndTryToLogInAs: (username: string) => void
onEngineConnected: () => void
onEngineDisonnected: () => void
onEngineIncoming: (action: EngineGen.Actions) => void
osNetworkStatusChanged: (online: boolean, type: T.Config.ConnectionType, isInit?: boolean) => void
openUnlockFolders: (devices: ReadonlyArray<T.RPCGen.Device>) => void
Expand All @@ -183,6 +182,7 @@ export interface State extends Store {
remoteWindowNeedsProps: (component: string, params: string) => void
resetRevokedSelf: () => void
revoke: (deviceName: string, wasCurrentDevice: boolean) => void
refreshAccounts: () => Promise<void>
setAccounts: (a: Store['configuredAccounts']) => void
setAndroidShare: (s: Store['androidShare']) => void
setBadgeState: (b: State['badgeState']) => void
Expand Down Expand Up @@ -488,8 +488,6 @@ export const useConfigState = Z.createZustand<State>((set, get) => {
ignorePromise(f())
},
onEngineConnected: () => {
storeRegistry.getState('daemon').dispatch.startHandshake()

// The startReachability RPC call both starts and returns the current
// reachability state. Then we'll get updates of changes from this state via reachabilityChanged.
// This should be run on app start and service re-connect in case the service somehow crashed or was restarted manually.
Expand Down Expand Up @@ -517,13 +515,6 @@ export const useConfigState = Z.createZustand<State>((set, get) => {
get().dispatch.dynamic.onEngineConnectedDesktop?.()
get().dispatch.loadOnStart('initialStartupAsEarlyAsPossible')
},
onEngineDisonnected: () => {
const f = async () => {
await logger.dump()
}
ignorePromise(f())
storeRegistry.getState('daemon').dispatch.setError(new Error('Disconnected'))
},
onEngineIncoming: action => {
switch (action.type) {
case EngineGen.keybase1GregorUIPushState: {
Expand Down Expand Up @@ -612,6 +603,30 @@ export const useConfigState = Z.createZustand<State>((set, get) => {
}
ignorePromise(f())
},
refreshAccounts: async () => {
const defaultUsername = get().defaultUsername
const configuredAccounts = (await T.RPCGen.loginGetConfiguredAccountsRpcPromise()) ?? []
const {setAccounts, setDefaultUsername} = get().dispatch

let existingDefaultFound = false as boolean
let currentName = ''
const nextConfiguredAccounts: Array<T.Config.ConfiguredAccount> = []

configuredAccounts.forEach(account => {
const {username, isCurrent, fullname, hasStoredSecret} = account
if (username === defaultUsername) {
existingDefaultFound = true
}
if (isCurrent) {
currentName = account.username
}
nextConfiguredAccounts.push({fullname, hasStoredSecret, username})
})
if (!existingDefaultFound) {
setDefaultUsername(currentName)
}
setAccounts(nextConfiguredAccounts)
},
remoteWindowNeedsProps: (component, params) => {
set(s => {
const map = s.remoteWindowNeedsProps.get(component) ?? new Map<string, number>()
Expand Down Expand Up @@ -650,7 +665,6 @@ export const useConfigState = Z.createZustand<State>((set, get) => {
s.justRevokedSelf = name
s.revokedTrigger++
})
storeRegistry.getState('daemon').dispatch.loadDaemonAccounts()
}
},
setAccounts: a => {
Expand Down
84 changes: 14 additions & 70 deletions shared/constants/daemon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,25 @@ import logger from '@/logger'
import {ignorePromise} from '../utils'
import * as T from '../types'
import * as Z from '@/util/zustand'
import {storeRegistry} from '../store-registry'
import {useCurrentUserState} from '../current-user'
import {useDarkModeState} from '../darkmode'
import {maxHandshakeTries} from '../values'

// Load accounts, this call can be slow so we attempt to continue w/o waiting if we determine we're logged in
// normally this wouldn't be worth it but this is startup
const getAccountsWaitKey = 'config.getAccounts'

type Store = T.Immutable<{
bootstrapStatus?: T.RPCGen.BootstrapStatus
error?: Error
handshakeState: T.Config.DaemonHandshakeState
handshakeFailedReason: string
handshakeRetriesLeft: number
handshakeState: T.Config.DaemonHandshakeState
handshakeVersion: number
handshakeWaiters: Map<string, number>
// if we ever restart handshake up this so we can ignore any waiters for old things
handshakeVersion: number
}>

const initialStore: Store = {
bootstrapStatus: undefined,
handshakeFailedReason: '',
handshakeRetriesLeft: maxHandshakeTries,
handshakeState: 'starting',
Expand All @@ -31,9 +30,8 @@ const initialStore: Store = {

export interface State extends Store {
dispatch: {
loadDaemonAccounts: () => void
loadDaemonAccounts: (configuredAccountsLength: number, loggedIn: boolean, refreshAccounts: () => Promise<void>) => void
loadDaemonBootstrapStatus: () => Promise<void>
refreshAccounts: () => Promise<void>
resetState: () => void
setError: (e?: Error) => void
setFailed: (r: string) => void
Expand Down Expand Up @@ -93,7 +91,6 @@ export const useDaemonState = Z.createZustand<State>((set, get) => {

// When there are no more waiters, we can show the actual app

let _emitStartupOnLoadDaemonConnectedOnce = false
const dispatch: State['dispatch'] = {
daemonHandshake: version => {
get().dispatch.setState('waitingForWaiters')
Expand All @@ -111,22 +108,19 @@ export const useDaemonState = Z.createZustand<State>((set, get) => {
wait(name, version, true)
try {
await get().dispatch.loadDaemonBootstrapStatus()
useDarkModeState.getState().dispatch.loadDarkPrefs()
storeRegistry.getState('chat').dispatch.loadStaticConfig()
} finally {
wait(name, version, false)
}
}
ignorePromise(f())
get().dispatch.loadDaemonAccounts()
},
daemonHandshakeDone: () => {
get().dispatch.setState('done')
},
loadDaemonAccounts: () => {
loadDaemonAccounts: (configuredAccountsLength: number, loggedIn: boolean, refreshAccounts: () => Promise<void>) => {
const f = async () => {
const version = get().handshakeVersion
if (storeRegistry.getState('config').configuredAccounts.length) {
if (configuredAccountsLength) {
// bail on already loaded
return
}
Expand All @@ -135,7 +129,7 @@ export const useDaemonState = Z.createZustand<State>((set, get) => {
const handshakeVersion = version

// did we beat getBootstrapStatus?
if (!storeRegistry.getState('config').loggedIn) {
if (!loggedIn) {
handshakeWait = true
}

Expand All @@ -145,7 +139,7 @@ export const useDaemonState = Z.createZustand<State>((set, get) => {
wait(getAccountsWaitKey, handshakeVersion, true)
}

await get().dispatch.refreshAccounts()
await refreshAccounts()

if (handshakeWait) {
// someone dismissed this already?
Expand All @@ -172,32 +166,22 @@ export const useDaemonState = Z.createZustand<State>((set, get) => {
const {wait} = get().dispatch

const f = async () => {
const {setBootstrap} = useCurrentUserState.getState().dispatch
const {setDefaultUsername} = storeRegistry.getState('config').dispatch
const s = await T.RPCGen.configGetBootstrapStatusRpcPromise()
const {userReacjis, deviceName, deviceID, uid, loggedIn, username} = s
setBootstrap({deviceID, deviceName, uid, username})
if (username) {
setDefaultUsername(username)
}
if (loggedIn) {
storeRegistry.getState('config').dispatch.setUserSwitching(false)
}
set(state => {
state.bootstrapStatus = T.castDraft(s)
})

logger.info(`[Bootstrap] loggedIn: ${loggedIn ? 1 : 0}`)
storeRegistry.getState('config').dispatch.setLoggedIn(loggedIn, false)
storeRegistry.getState('chat').dispatch.updateUserReacjis(userReacjis)
logger.info(`[Bootstrap] loggedIn: ${s.loggedIn ? 1 : 0}`)

// set HTTP srv info
if (s.httpSrvInfo) {
logger.info(`[Bootstrap] http server: addr: ${s.httpSrvInfo.address} token: ${s.httpSrvInfo.token}`)
storeRegistry.getState('config').dispatch.setHTTPSrvInfo(s.httpSrvInfo.address, s.httpSrvInfo.token)
} else {
logger.info(`[Bootstrap] http server: no info given`)
}

// if we're logged in act like getAccounts is done already
if (loggedIn) {
if (s.loggedIn) {
const {handshakeWaiters} = get()
if (handshakeWaiters.get(getAccountsWaitKey)) {
wait(getAccountsWaitKey, version, false)
Expand All @@ -207,39 +191,6 @@ export const useDaemonState = Z.createZustand<State>((set, get) => {
return await f()
},
onRestartHandshakeNative: _onRestartHandshakeNative,
refreshAccounts: async () => {
const configuredAccounts = (await T.RPCGen.loginGetConfiguredAccountsRpcPromise()) ?? []
// already have one?
const {defaultUsername} = storeRegistry.getState('config')
const {setAccounts, setDefaultUsername} = storeRegistry.getState('config').dispatch

let existingDefaultFound = false as boolean
let currentName = ''
const nextConfiguredAccounts: Array<T.Config.ConfiguredAccount> = []
const usernameToFullname: {[username: string]: string} = {}

configuredAccounts.forEach(account => {
const {username, isCurrent, fullname, hasStoredSecret} = account
if (username === defaultUsername) {
existingDefaultFound = true
}
if (isCurrent) {
currentName = account.username
}
nextConfiguredAccounts.push({hasStoredSecret, username})
usernameToFullname[username] = fullname
})
if (!existingDefaultFound) {
setDefaultUsername(currentName)
}
setAccounts(nextConfiguredAccounts)
storeRegistry.getState('users').dispatch.updates(
Object.keys(usernameToFullname).map(name => ({
info: {fullname: usernameToFullname[name]},
name,
}))
)
},
resetState: () => {
set(s => ({
...s,
Expand Down Expand Up @@ -270,13 +221,6 @@ export const useDaemonState = Z.createZustand<State>((set, get) => {
set(s => {
s.handshakeState = ds
})

if (ds !== 'done') return

if (!_emitStartupOnLoadDaemonConnectedOnce) {
_emitStartupOnLoadDaemonConnectedOnce = true
storeRegistry.getState('config').dispatch.loadOnStart('connectedToDaemonForFirstTime')
}
},
startHandshake: () => {
get().dispatch.setError()
Expand Down
9 changes: 8 additions & 1 deletion shared/constants/engine/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import * as PeopleUtil from '../people/util'
import * as PinentryUtil from '../pinentry/util'
import {onEngineIncoming as onEngineIncomingShared} from '../platform-specific/shared'
import {storeRegistry} from '../store-registry'
import {ignorePromise} from '../utils'
import * as TrackerUtil from '../tracker2/util'
import * as UnlockFoldersUtil from '../unlock-folders/util'
import logger from '@/logger'

type Store = object
const initialStore: Store = {}
Expand All @@ -27,14 +29,19 @@ export const useEngineState = Z.createZustand<State>(set => {
onEngineConnected: () => {
ChatUtil.onEngineConnected()
storeRegistry.getState('config').dispatch.onEngineConnected()
storeRegistry.getState('daemon').dispatch.startHandshake()
NotifUtil.onEngineConnected()
PeopleUtil.onEngineConnected()
PinentryUtil.onEngineConnected()
TrackerUtil.onEngineConnected()
UnlockFoldersUtil.onEngineConnected()
},
onEngineDisconnected: () => {
storeRegistry.getState('config').dispatch.onEngineDisonnected()
const f = async () => {
await logger.dump()
}
ignorePromise(f())
storeRegistry.getState('daemon').dispatch.setError(new Error('Disconnected'))
},
onEngineIncoming: action => {
// defer a frame so its more like before
Expand Down
65 changes: 63 additions & 2 deletions shared/constants/platform-specific/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {useChatState} from '../chat2'
import * as ChatUtil from '../chat2/util'
import {useConfigState} from '../config'
import {useCurrentUserState} from '../current-user'
import {useDaemonState} from '../daemon'
import {useDarkModeState} from '../darkmode'
import * as DeepLinksUtil from '../deeplinks/util'
import * as DevicesUtil from '../devices/util'
import * as FollowerUtil from '../followers/util'
Expand All @@ -29,6 +31,8 @@ import * as TrackerUtil from '../tracker2/util'
import * as UnlockFoldersUtil from '../unlock-folders/util'
import * as UsersUtil from '../users/util'

let _emitStartupOnLoadDaemonConnectedOnce = false

export const initSharedSubscriptions = () => {
useConfigState.subscribe((s, old) => {
if (s.loadOnStartPhase !== old.loadOnStartPhase) {
Expand Down Expand Up @@ -106,9 +110,9 @@ export const initSharedSubscriptions = () => {
ignorePromise(storeRegistry.getState('daemon').dispatch.loadDaemonBootstrapStatus())
storeRegistry.getState('fs').dispatch.checkKbfsDaemonRpcStatus()
}
storeRegistry.getState('daemon').dispatch.loadDaemonAccounts()
storeRegistry.getState('daemon').dispatch.loadDaemonAccounts(s.configuredAccounts.length, s.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts)
if (!s.loggedInCausedbyStartup) {
ignorePromise(storeRegistry.getState('daemon').dispatch.refreshAccounts())
ignorePromise(storeRegistry.getState('config').dispatch.refreshAccounts())
}
}

Expand All @@ -117,6 +121,63 @@ export const initSharedSubscriptions = () => {
storeRegistry.getState('chat').dispatch.toggleInboxSearch(false)
}
}

if (s.revokedTrigger !== old.revokedTrigger) {
storeRegistry.getState('daemon').dispatch.loadDaemonAccounts(s.configuredAccounts.length, s.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts)
}
})

useDaemonState.subscribe((s, old) => {
if (s.handshakeVersion !== old.handshakeVersion) {
useDarkModeState.getState().dispatch.loadDarkPrefs()
storeRegistry.getState('chat').dispatch.loadStaticConfig()
const configState = storeRegistry.getState('config')
s.dispatch.loadDaemonAccounts(configState.configuredAccounts.length, configState.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts)
}

if (s.bootstrapStatus !== old.bootstrapStatus) {
const bootstrap = s.bootstrapStatus
if (bootstrap) {
const {deviceID, deviceName, loggedIn, uid, username, userReacjis} = bootstrap
useCurrentUserState.getState().dispatch.setBootstrap({deviceID, deviceName, uid, username})

const configDispatch = storeRegistry.getState('config').dispatch
if (username) {
configDispatch.setDefaultUsername(username)
}
if (loggedIn) {
configDispatch.setUserSwitching(false)
}
configDispatch.setLoggedIn(loggedIn, false)

if (bootstrap.httpSrvInfo) {
configDispatch.setHTTPSrvInfo(bootstrap.httpSrvInfo.address, bootstrap.httpSrvInfo.token)
}

storeRegistry.getState('chat').dispatch.updateUserReacjis(userReacjis)
}
}

if (s.handshakeState !== old.handshakeState) {
if (s.handshakeState === 'done') {
if (!_emitStartupOnLoadDaemonConnectedOnce) {
_emitStartupOnLoadDaemonConnectedOnce = true
storeRegistry.getState('config').dispatch.loadOnStart('connectedToDaemonForFirstTime')
}
}
}
})

useConfigState.subscribe((s, old) => {
if (s.configuredAccounts !== old.configuredAccounts) {
const updates = s.configuredAccounts.map(account => ({
info: {fullname: account.fullname ?? ''},
name: account.username,
}))
if (updates.length > 0) {
storeRegistry.getState('users').dispatch.updates(updates)
}
}
})
}

Expand Down
1 change: 1 addition & 0 deletions shared/constants/types/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type OutOfDate = {
}
export type DaemonHandshakeState = 'starting' | 'waitingForWaiters' | 'done'
export type ConfiguredAccount = {
fullname?: string
hasStoredSecret: boolean
username: string
}
Expand Down