Skip to content
Open
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
20 changes: 9 additions & 11 deletions shared/app/global-errors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,8 @@ const GlobalError = () => {
const {daemonError, error, onDismiss, onFeedback} = d
const {cachedDetails, cachedSummary, size, onExpandClick} = d

if (size === 'Closed') {
return null
}

if (!daemonError && !error) {
return null
}

// daemonError first: size only tracks globalError, so checking it before this
// branch would hide the disconnect overlay
if (daemonError) {
if (isMobile) {
return null
Expand All @@ -131,19 +125,23 @@ const GlobalError = () => {

const message = daemonError.message || 'Keybase is currently unreachable. Trying to reconnect you…'
return (
<Kb.Box2 direction="vertical" style={styles.containerOverlay}>
<Kb.Box2 direction="horizontal" centerChildren={true} style={styles.overlayRow}>
<Kb.Box2 direction="vertical" fullWidth={true} fullHeight={true} style={styles.containerOverlay}>
<Kb.Box2 direction="horizontal" fullWidth={true} centerChildren={true} style={styles.overlayRow}>
<Kb.Text center={true} type="BodySmallSemibold" style={styles.message}>
{message}
</Kb.Text>
</Kb.Box2>
<Kb.Box2 direction="vertical" flex={1} centerChildren={true} style={styles.overlayFill}>
<Kb.Box2 direction="vertical" fullWidth={true} flex={1} centerChildren={true} style={styles.overlayFill}>
<Kb.Animation animationType="disconnected" height={175} width={600} />
</Kb.Box2>
</Kb.Box2>
)
}

if (size === 'Closed') {
return null
}

if (isMobile) {
return (
<Kb.Box2
Expand Down
2 changes: 0 additions & 2 deletions shared/app/index.native.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/// <reference types="webpack-env" />
import * as C from '@/constants'
import {useConfigState} from '@/stores/config'
import {useShellState} from '@/stores/shell'
import * as Kb from '@/common-adapters'
import * as React from 'react'
Expand Down Expand Up @@ -143,7 +142,6 @@ const useInit = () => {
}, onEngineIncoming)
initPlatformListener()
eng.listenersAreReady()
useConfigState.getState().dispatch.installerRan()
}, [])
}

Expand Down
1 change: 0 additions & 1 deletion shared/constants/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export const invalidPasswordErrorString = 'Bad password: Invalid password. Serve
export const defaultKBFSPath = runMode === 'prod' ? '/keybase' : `/keybase.${runMode}`
export const defaultPrivatePrefix = '/private/'
export const defaultPublicPrefix = '/public/'
export const noKBFSFailReason = "Can't connect to KBFS"
const defaultTeamPrefix = '/team/'

export const privateFolderWithUsers = (users: ReadonlyArray<string>) =>
Expand Down
86 changes: 31 additions & 55 deletions shared/constants/init/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as Chat from '@/constants/chat'
import {ignorePromise, neverThrowPromiseFunc} from '@/constants/utils'
import {useConfigState} from '@/stores/config'
import {useDaemonState} from '@/stores/daemon'
import {FatalHandshakeError, useDaemonState} from '@/stores/daemon'
import {useRouterState} from '@/stores/router'
import {useShellState, type ConnectionType} from '@/stores/shell'
import {useSettingsContactsState} from '@/stores/settings-contacts'
Expand All @@ -16,7 +16,6 @@ import {afterKbfsDaemonRpcStatusChanged} from '@/fs/common/lifecycle'
import {logState, setThreadInputCommandStatus} from '@/constants/router'
import {initSharedSubscriptions, _onEngineIncoming, onEngineConnected as onSharedEngineConnected} from './shared'
import {noConversationIDKey} from '../types/chat/common'
import {noKBFSFailReason} from '@/constants/config'
import {dumpLogs, persistRoute} from '@/util/storeless-actions'

// ─── Desktop-only imports (runtime-guarded) ──────────────────────────────────
Expand Down Expand Up @@ -190,15 +189,13 @@ const loadStartupDetails = async () => {
const {guiConfig, Linking} = _getNative()
const {getStartupDetailsFromInitialPush} = await import('./push-listener.native')

const [routeState, initialUrl, push] = await Promise.all([
neverThrowPromiseFunc(async () => {
try {
const config = JSON.parse(guiConfig) as {ui?: {routeState2?: string}} | undefined
return Promise.resolve(config?.ui?.routeState2 ?? '')
} catch {
return Promise.resolve('')
}
}),
let routeState = ''
try {
const config = JSON.parse(guiConfig) as {ui?: {routeState2?: string}} | undefined
routeState = config?.ui?.routeState2 ?? ''
} catch {}

const [initialUrl, push] = await Promise.all([
neverThrowPromiseFunc(async () => {
const linkingStart = Date.now()
logger.info('[Startup] loadStartupDetails: calling Linking.getInitialURL')
Expand Down Expand Up @@ -450,16 +447,6 @@ const _initNativePlatformListener = () => {
}
}

useDaemonState.subscribe((s, old) => {
const versionChanged = s.handshakeVersion !== old.handshakeVersion
const stateChanged = s.handshakeState !== old.handshakeState
const justBecameReady = stateChanged && s.handshakeState === 'done' && old.handshakeState !== 'done'

if (versionChanged || justBecameReady) {
configureAndroidCacheDir()
}
})

useConfigState.subscribe((s, old) => {
if (s.loggedIn === old.loggedIn) return
const f = async () => {
Expand Down Expand Up @@ -554,14 +541,23 @@ const _initNativePlatformListener = () => {
ignorePromise(setupAudioMode(false))

if (isAndroid) {
const daemonState = useDaemonState.getState()
if (daemonState.handshakeState === 'done' || daemonState.handshakeVersion > 0) {
// HMR re-init after the handshake already finished: the bootstrap step won't run again
if (useDaemonState.getState().handshakeState === 'done') {
configureAndroidCacheDir()
}
afterKbfsDaemonRpcStatusChanged()
}

initSharedSubscriptions()
initSharedSubscriptions(
isAndroid
? [
async () => {
configureAndroidCacheDir()
return Promise.resolve()
},
]
: []
)
}

const _initDesktopPlatformListener = () => {
Expand Down Expand Up @@ -660,30 +656,6 @@ const _initDesktopPlatformListener = () => {
}

_platformUnsubs.push(useDaemonState.subscribe((s, old) => {
if (s.handshakeVersion !== old.handshakeVersion) {
if (!isWindows) return

const f = async () => {
const waitKey = 'pipeCheckFail'
const version = s.handshakeVersion
const {wait} = s.dispatch
wait(waitKey, version, true)
try {
logger.info('Checking RPC ownership')
if (KB2.functions.winCheckRPCOwnership) {
await KB2.functions.winCheckRPCOwnership()
}
wait(waitKey, version, false)
} catch (error_) {
// error will be logged in bootstrap check
getEngine().reset()
const error = error_ as {message?: string}
wait(waitKey, version, false, error.message || 'windows pipe owner fail', true)
}
}
ignorePromise(f())
}

if (s.handshakeState !== old.handshakeState && s.handshakeState === 'done') {
useConfigState.getState().dispatch.setStartupDetails({
conversation: Chat.noConversationIDKey,
Expand All @@ -694,20 +666,24 @@ const _initDesktopPlatformListener = () => {
}
}))

useDaemonState.setState(s => {
s.dispatch.onRestartHandshakeNative = () => {
const {handshakeFailedReason} = useDaemonState.getState()
if (isWindows && handshakeFailedReason === noKBFSFailReason) {
KB2.functions.requestWindowsStartService?.()
const winPipeCheckStep = async () => {
try {
logger.info('Checking RPC ownership')
if (KB2.functions.winCheckRPCOwnership) {
await KB2.functions.winCheckRPCOwnership()
}
} catch (error_) {
getEngine().reset()
const error = error_ as {message?: string}
throw new FatalHandshakeError(error.message || 'windows pipe owner fail')
}
})
}

if (!isLinux) {
afterKbfsDaemonRpcStatusChanged()
}

initSharedSubscriptions()
initSharedSubscriptions(isWindows ? [winPipeCheckStep] : [])
}

export {onEngineConnected, onEngineDisconnected} from './shared'
12 changes: 3 additions & 9 deletions shared/constants/init/push-listener.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ import {
getNativeEmitter,
getInitialNotification,
removeAllPendingNotificationRequests,
shareListenersRegistered,
} from 'react-native-kb'
import {useConfigState} from '@/stores/config'
import {useCurrentUserState} from '@/stores/current-user'
import {useLogoutState} from '@/stores/logout'
import {usePushState} from '@/stores/push'
import {useShellState} from '@/stores/shell'

Expand Down Expand Up @@ -240,12 +238,6 @@ export const initPushListener = () => {
.catch(() => {})
})

// Token handling
useLogoutState.subscribe((s, old) => {
if (s.version === old.version) return
usePushState.getState().dispatch.deleteToken(s.version)
})

let lastCount = -1
useConfigState.subscribe((s, old) => {
if (s.badgeState === old.badgeState) return
Expand Down Expand Up @@ -351,7 +343,9 @@ export const initPushListener = () => {
}
emitDeepLink('keybase://incoming-share')
})
shareListenersRegistered()
// shareListenersRegistered() is deliberately NOT called here: it makes native flush
// pending share intents, and emitDeepLink has no queue. The init/index.tsx router
// subscriber calls it once we're logged in with the router mounted.
}
} catch (e) {
logger.error('[Push] failed to set up listeners: ', e)
Expand Down
Loading