fix: filemanager state handling (#232)
* fix: filemanager state handling * refactor: fm provider and fm page * fix: detect bee warmup and wait more for syncing * refactor: optimize bee provider to avoid rerenders --------- Co-authored-by: Roland Seres <roland.seres90@gmail.com>
This commit is contained in:
+112
-113
@@ -29,7 +29,7 @@ import { useLatestBeeRelease } from '../hooks/apiHooks'
|
||||
|
||||
import { Context as SettingsContext } from './Settings'
|
||||
|
||||
const LAUNCH_GRACE_PERIOD = 15_000
|
||||
const LAUNCH_GRACE_PERIOD = 35_000
|
||||
const REFRESH_WHEN_OK = 30_000
|
||||
const REFRESH_WHEN_ERROR = 5_000
|
||||
const TIMEOUT = 3_000
|
||||
@@ -116,15 +116,22 @@ interface Props {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
function getStatus(
|
||||
nodeInfo: NodeInfo | null,
|
||||
apiHealth: boolean,
|
||||
topology: Topology | null,
|
||||
chequebookAddress: ChequebookAddressResponse | null,
|
||||
chequebookBalance: ChequebookBalanceResponse | null,
|
||||
error: Error | null,
|
||||
startedAt: number,
|
||||
): Status {
|
||||
interface StatusProps {
|
||||
nodeInfo: NodeInfo | null
|
||||
apiHealth: boolean
|
||||
topology: Topology | null
|
||||
isWarmingUp: boolean
|
||||
chequebookAddress: ChequebookAddressResponse | null
|
||||
chequebookBalance: ChequebookBalanceResponse | null
|
||||
error: Error | null
|
||||
startedAt: number
|
||||
}
|
||||
|
||||
function getStatus(props: StatusProps): Status {
|
||||
const { nodeInfo, apiHealth, topology, isWarmingUp, chequebookAddress, chequebookBalance, error, startedAt } = {
|
||||
...props,
|
||||
}
|
||||
|
||||
const status: Status = { ...initialValues.status }
|
||||
|
||||
// API connection check
|
||||
@@ -143,15 +150,17 @@ function getStatus(
|
||||
|
||||
if (chequebookAddress?.chequebookAddress && chequebookBalance !== null) {
|
||||
status.chequebook.checkState = CheckState.OK
|
||||
} else status.chequebook.checkState = CheckState.OK
|
||||
} else {
|
||||
status.chequebook.checkState = CheckState.WARNING
|
||||
}
|
||||
}
|
||||
|
||||
status.all = determineOverallStatus(status, startedAt)
|
||||
status.all = determineOverallStatus(status, isWarmingUp, startedAt)
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
function determineOverallStatus(status: Status, startedAt: number): CheckState {
|
||||
function determineOverallStatus(status: Status, isWarmingUp: boolean, startedAt: number): CheckState {
|
||||
const hasErrors = Object.values(status).some(
|
||||
({ isEnabled, checkState }) => isEnabled && checkState === CheckState.ERROR,
|
||||
)
|
||||
@@ -160,15 +169,23 @@ function determineOverallStatus(status: Status, startedAt: number): CheckState {
|
||||
)
|
||||
const isInGracePeriod = Date.now() - startedAt < LAUNCH_GRACE_PERIOD
|
||||
|
||||
if (hasErrors && isInGracePeriod) {
|
||||
if (isWarmingUp || isInGracePeriod) {
|
||||
return CheckState.CONNECTING
|
||||
} else if (hasErrors) {
|
||||
return CheckState.ERROR
|
||||
} else if (hasWarnings) {
|
||||
return CheckState.WARNING
|
||||
} else {
|
||||
return CheckState.OK
|
||||
}
|
||||
|
||||
if (hasErrors) {
|
||||
return CheckState.ERROR
|
||||
}
|
||||
|
||||
if (hasWarnings) {
|
||||
return CheckState.WARNING
|
||||
}
|
||||
|
||||
return CheckState.OK
|
||||
}
|
||||
|
||||
function getFulfilledValue<T>(result: PromiseSettledResult<T>): T | null {
|
||||
return result.status === 'fulfilled' ? result.value : null
|
||||
}
|
||||
|
||||
// This does not need to be exposed and works much better as variable than state variable which may trigger some unnecessary re-renders
|
||||
@@ -179,6 +196,7 @@ export function Provider({ children }: Props): ReactElement {
|
||||
|
||||
const [beeVersion, setBeeVersion] = useState<string | null>(null)
|
||||
const [apiHealth, setApiHealth] = useState<boolean>(false)
|
||||
const [isWarmingUp, setIsWarmingUp] = useState<boolean>(true)
|
||||
const [nodeAddresses, setNodeAddresses] = useState<NodeAddresses | null>(null)
|
||||
const [nodeInfo, setNodeInfo] = useState<NodeInfo | null>(null)
|
||||
const [topology, setNodeTopology] = useState<Topology | null>(null)
|
||||
@@ -191,7 +209,7 @@ export function Provider({ children }: Props): ReactElement {
|
||||
const [settlements, setSettlements] = useState<AllSettlements | null>(null)
|
||||
const [chainState, setChainState] = useState<ChainState | null>(null)
|
||||
const [walletBalance, setWalletBalance] = useState<WalletBalance | null>(null)
|
||||
const [startedAt] = useState(() => Date.now())
|
||||
const [startedAt, setStartedAt] = useState(() => Date.now())
|
||||
|
||||
const { latestBeeRelease } = useLatestBeeRelease()
|
||||
|
||||
@@ -202,6 +220,15 @@ export function Provider({ children }: Props): ReactElement {
|
||||
|
||||
const frequencyRef = useRef<number | null>(frequency)
|
||||
|
||||
useEffect(() => {
|
||||
if (isWarmingUp) return
|
||||
|
||||
setStartedAt(Date.now())
|
||||
const timer = setTimeout(() => setStartedAt(0), LAUNCH_GRACE_PERIOD)
|
||||
|
||||
return () => clearTimeout(timer)
|
||||
}, [isWarmingUp])
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
// Don't want to refresh when already refreshing
|
||||
if (isRefreshing) {
|
||||
@@ -215,101 +242,63 @@ export function Provider({ children }: Props): ReactElement {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
isRefreshing = true
|
||||
setError(null)
|
||||
isRefreshing = true
|
||||
|
||||
const promises = [
|
||||
// API health
|
||||
beeApi
|
||||
.getHealth({ timeout: TIMEOUT })
|
||||
.then(response => setBeeVersion(response.version))
|
||||
.then(() => setApiHealth(true))
|
||||
.catch(() => {
|
||||
setBeeVersion(null)
|
||||
setApiHealth(false)
|
||||
}),
|
||||
const [
|
||||
healthResult,
|
||||
statusResult,
|
||||
nodeAddressesResult,
|
||||
nodeInfoResult,
|
||||
topologyResult,
|
||||
peersResult,
|
||||
chequebookAddressResult,
|
||||
peerChequesResult,
|
||||
chainStateResult,
|
||||
walletResult,
|
||||
chequebookBalanceResult,
|
||||
stakeResult,
|
||||
peerBalancesResult,
|
||||
settlementsResult,
|
||||
] = await Promise.allSettled([
|
||||
beeApi.getHealth({ timeout: TIMEOUT }),
|
||||
beeApi.getStatus({ timeout: TIMEOUT }),
|
||||
beeApi.getNodeAddresses({ timeout: TIMEOUT }),
|
||||
beeApi.getNodeInfo({ timeout: TIMEOUT }),
|
||||
beeApi.getTopology({ timeout: TIMEOUT }),
|
||||
beeApi.getPeers({ timeout: TIMEOUT }),
|
||||
beeApi.getChequebookAddress({ timeout: TIMEOUT }),
|
||||
beeApi.getLastCheques({ timeout: TIMEOUT }),
|
||||
beeApi.getChainState({ timeout: TIMEOUT }),
|
||||
beeApi.getWalletBalance({ timeout: TIMEOUT }),
|
||||
beeApi.getChequebookBalance({ timeout: TIMEOUT }),
|
||||
beeApi.getStake({ timeout: TIMEOUT }),
|
||||
beeApi.getAllBalances({ timeout: TIMEOUT }),
|
||||
beeApi.getAllSettlements(),
|
||||
])
|
||||
|
||||
// Node Addresses
|
||||
beeApi
|
||||
.getNodeAddresses({ timeout: TIMEOUT })
|
||||
.then(setNodeAddresses)
|
||||
.catch(() => setNodeAddresses(null)),
|
||||
|
||||
// NodeInfo
|
||||
beeApi
|
||||
.getNodeInfo({ timeout: TIMEOUT })
|
||||
.then(setNodeInfo)
|
||||
.catch(() => setNodeInfo(null)),
|
||||
|
||||
// Network Topology
|
||||
beeApi
|
||||
.getTopology({ timeout: TIMEOUT })
|
||||
.then(setNodeTopology)
|
||||
.catch(() => setNodeTopology(null)),
|
||||
|
||||
// Peers
|
||||
beeApi
|
||||
.getPeers({ timeout: TIMEOUT })
|
||||
.then(setPeers)
|
||||
.catch(() => setPeers(null)),
|
||||
|
||||
// Chequebook address
|
||||
beeApi
|
||||
.getChequebookAddress({ timeout: TIMEOUT })
|
||||
.then(setChequebookAddress)
|
||||
.catch(() => setChequebookAddress(null)),
|
||||
|
||||
// Cheques
|
||||
beeApi
|
||||
.getLastCheques({ timeout: TIMEOUT })
|
||||
.then(setPeerCheques)
|
||||
.catch(() => setPeerCheques(null)),
|
||||
|
||||
// Chain state
|
||||
beeApi
|
||||
.getChainState({ timeout: TIMEOUT })
|
||||
.then(setChainState)
|
||||
.catch(() => setChainState(null)),
|
||||
|
||||
// Wallet
|
||||
beeApi
|
||||
.getWalletBalance({ timeout: TIMEOUT })
|
||||
.then(setWalletBalance)
|
||||
.catch(() => setWalletBalance(null)),
|
||||
|
||||
// Chequebook balance
|
||||
beeApi
|
||||
.getChequebookBalance({ timeout: TIMEOUT })
|
||||
.then(setChequebookBalance)
|
||||
.catch(() => setChequebookBalance(null)),
|
||||
|
||||
beeApi
|
||||
.getStake({ timeout: TIMEOUT })
|
||||
.then(stake => setStake(stake))
|
||||
.catch(() => setStake(null)),
|
||||
|
||||
// Peer balances
|
||||
beeApi
|
||||
.getAllBalances({ timeout: TIMEOUT })
|
||||
.then(x => setPeerBalances(x.balances))
|
||||
.catch(() => setPeerBalances(null)),
|
||||
|
||||
// Settlements
|
||||
beeApi
|
||||
.getAllSettlements()
|
||||
.then(setSettlements)
|
||||
.catch(() => setSettlements(null)),
|
||||
]
|
||||
|
||||
await Promise.allSettled(promises)
|
||||
} catch (e) {
|
||||
setError(e as Error)
|
||||
}
|
||||
// All setters called synchronously — React 18 batches them into one render.
|
||||
const health = getFulfilledValue(healthResult)
|
||||
setBeeVersion(health?.version ?? null)
|
||||
setApiHealth(Boolean(health))
|
||||
|
||||
setIsWarmingUp(getFulfilledValue(statusResult)?.isWarmingUp ?? false)
|
||||
setNodeAddresses(getFulfilledValue(nodeAddressesResult))
|
||||
setNodeInfo(getFulfilledValue(nodeInfoResult))
|
||||
setNodeTopology(getFulfilledValue(topologyResult))
|
||||
setPeers(getFulfilledValue(peersResult))
|
||||
setChequebookAddress(getFulfilledValue(chequebookAddressResult))
|
||||
setPeerCheques(getFulfilledValue(peerChequesResult))
|
||||
setChainState(getFulfilledValue(chainStateResult))
|
||||
setWalletBalance(getFulfilledValue(walletResult))
|
||||
setChequebookBalance(getFulfilledValue(chequebookBalanceResult))
|
||||
setStake(getFulfilledValue(stakeResult))
|
||||
setPeerBalances(getFulfilledValue(peerBalancesResult)?.balances ?? null)
|
||||
setSettlements(getFulfilledValue(settlementsResult))
|
||||
setError(null)
|
||||
setIsLoading(false)
|
||||
isRefreshing = false
|
||||
setLastUpdate(Date.now())
|
||||
|
||||
isRefreshing = false
|
||||
}, [beeApi])
|
||||
|
||||
const start = useCallback(
|
||||
@@ -322,8 +311,18 @@ export function Provider({ children }: Props): ReactElement {
|
||||
const stop = useCallback(() => setFrequency(null), [])
|
||||
|
||||
const status = useMemo(
|
||||
() => getStatus(nodeInfo, apiHealth, topology, chequebookAddress, chequebookBalance, error, startedAt),
|
||||
[nodeInfo, apiHealth, topology, chequebookAddress, chequebookBalance, error, startedAt],
|
||||
() =>
|
||||
getStatus({
|
||||
nodeInfo,
|
||||
apiHealth,
|
||||
topology,
|
||||
isWarmingUp,
|
||||
chequebookAddress,
|
||||
chequebookBalance,
|
||||
error,
|
||||
startedAt,
|
||||
}),
|
||||
[nodeInfo, apiHealth, topology, chequebookAddress, chequebookBalance, error, startedAt, isWarmingUp],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
+147
-84
@@ -7,10 +7,12 @@ import { FILE_MANAGER_EVENTS } from '../modules/filemanager/constants/common'
|
||||
import { getUsableStamps } from '../modules/filemanager/utils/bee'
|
||||
import { getSignerPk } from '../modules/filemanager/utils/common'
|
||||
|
||||
import { CheckState, Context as BeeContext } from './Bee'
|
||||
import { Context as SettingsContext } from './Settings'
|
||||
|
||||
interface ContextInterface {
|
||||
fm: FileManagerBase | null
|
||||
initDone: boolean
|
||||
files: FileInfo[]
|
||||
currentDrive?: DriveInfo
|
||||
currentStamp?: PostageBatch
|
||||
@@ -24,6 +26,7 @@ interface ContextInterface {
|
||||
setCurrentStamp: (s: PostageBatch | undefined) => void
|
||||
resync: () => Promise<void>
|
||||
init: () => Promise<FileManagerBase | null>
|
||||
notifyPkSaved: () => void
|
||||
setShowError: (show: boolean) => void
|
||||
syncDrives: () => Promise<void>
|
||||
refreshStamp: (batchId: string) => Promise<PostageBatch | undefined>
|
||||
@@ -31,6 +34,7 @@ interface ContextInterface {
|
||||
|
||||
const initialValues: ContextInterface = {
|
||||
fm: null,
|
||||
initDone: false,
|
||||
files: [],
|
||||
currentDrive: undefined,
|
||||
currentStamp: undefined,
|
||||
@@ -45,6 +49,7 @@ const initialValues: ContextInterface = {
|
||||
resync: async () => {},
|
||||
// eslint-disable-next-line require-await
|
||||
init: async () => null,
|
||||
notifyPkSaved: () => {},
|
||||
setShowError: () => {},
|
||||
syncDrives: async () => {},
|
||||
// eslint-disable-next-line require-await
|
||||
@@ -85,12 +90,18 @@ const findDrives = (
|
||||
}
|
||||
|
||||
export function Provider({ children }: Props) {
|
||||
const initInProgressRef = useRef(false)
|
||||
const beeInstanceRef = useRef<Bee | null>(null)
|
||||
const initInProgressRef = useRef<boolean>(false)
|
||||
const isBeeApiInitialized = useRef<boolean>(false)
|
||||
|
||||
const { status } = useContext(BeeContext)
|
||||
const { apiUrl } = useContext(SettingsContext)
|
||||
|
||||
const apiUrlRef = useRef<string>(apiUrl)
|
||||
|
||||
const [pkSaved, setPkSaved] = useState<boolean>(false)
|
||||
const [beeInstance, setBeeInstance] = useState<Bee | null>(null)
|
||||
const [fm, setFm] = useState<FileManagerBase | null>(null)
|
||||
const [initDone, setInitDone] = useState<boolean>(false)
|
||||
const [shallReset, setShallReset] = useState<boolean>(false)
|
||||
const [files, setFiles] = useState<FileInfo[]>([])
|
||||
const [drives, setDrives] = useState<DriveInfo[]>([])
|
||||
@@ -102,6 +113,8 @@ export function Provider({ children }: Props) {
|
||||
const [initializationError, setInitializationError] = useState<boolean>(false)
|
||||
const [showError, setShowError] = useState<boolean>(false)
|
||||
|
||||
const notifyPkSaved = useCallback(() => setPkSaved(v => !v), [])
|
||||
|
||||
const syncFiles = useCallback((manager: FileManagerBase, fi?: FileInfo, remove?: boolean): void => {
|
||||
if (fi) {
|
||||
if (remove) {
|
||||
@@ -129,70 +142,73 @@ export function Provider({ children }: Props) {
|
||||
setFiles([...manager.fileInfoList])
|
||||
}, [])
|
||||
|
||||
const syncDrives = useCallback(async (manager: FileManagerBase, di?: DriveInfo, remove?: boolean): Promise<void> => {
|
||||
if (!beeInstanceRef.current) {
|
||||
return
|
||||
}
|
||||
const syncDrives = useCallback(
|
||||
async (manager: FileManagerBase, di?: DriveInfo, remove?: boolean): Promise<void> => {
|
||||
if (!beeInstance) {
|
||||
return
|
||||
}
|
||||
|
||||
const usableStamps = await getUsableStamps(beeInstanceRef.current)
|
||||
const usableStamps = await getUsableStamps(beeInstance)
|
||||
|
||||
if (di) {
|
||||
const isNotExpired = usableStamps.some(s => s.batchID.toString() === di.batchId.toString())
|
||||
if (di) {
|
||||
const isNotExpired = usableStamps.some(s => s.batchID.toString() === di.batchId.toString())
|
||||
|
||||
if (isNotExpired) {
|
||||
if (remove) {
|
||||
setDrives(prev => prev.filter(d => d.id.toString() !== di.id.toString()))
|
||||
if (isNotExpired) {
|
||||
if (remove) {
|
||||
setDrives(prev => prev.filter(d => d.id.toString() !== di.id.toString()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (di.isAdmin) {
|
||||
setAdminDrive(di)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
setDrives(prev => {
|
||||
const existingIndex = prev.findIndex(d => d.id.toString() === di.id.toString())
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
const updated = [...prev]
|
||||
updated[existingIndex] = di
|
||||
|
||||
return updated
|
||||
return
|
||||
}
|
||||
|
||||
return [...prev, di]
|
||||
})
|
||||
if (di.isAdmin) {
|
||||
setAdminDrive(di)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
setDrives(prev => {
|
||||
const existingIndex = prev.findIndex(d => d.id.toString() === di.id.toString())
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
const updated = [...prev]
|
||||
updated[existingIndex] = di
|
||||
|
||||
return updated
|
||||
}
|
||||
|
||||
return [...prev, di]
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
setExpiredDrives(prev => prev.filter(d => d.id.toString() !== di.id.toString()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (!di.isAdmin) {
|
||||
setExpiredDrives(prev => {
|
||||
const exists = prev.some(d => d.id.toString() === di.id.toString())
|
||||
|
||||
return exists ? prev : [...prev, di]
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: handle admin drive expiration!
|
||||
return
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
setExpiredDrives(prev => prev.filter(d => d.id.toString() !== di.id.toString()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (!di.isAdmin) {
|
||||
setExpiredDrives(prev => {
|
||||
const exists = prev.some(d => d.id.toString() === di.id.toString())
|
||||
|
||||
return exists ? prev : [...prev, di]
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: handle admin drive expiration!
|
||||
return
|
||||
}
|
||||
|
||||
const { adminDrive: tmpAdminDrive, userDrives, expiredDrives } = findDrives(manager.driveList, usableStamps)
|
||||
setAdminDrive(tmpAdminDrive)
|
||||
setDrives(userDrives)
|
||||
setExpiredDrives(expiredDrives)
|
||||
}, [])
|
||||
const { adminDrive: tmpAdminDrive, userDrives, expiredDrives } = findDrives(manager.driveList, usableStamps)
|
||||
setAdminDrive(tmpAdminDrive)
|
||||
setDrives(userDrives)
|
||||
setExpiredDrives(expiredDrives)
|
||||
},
|
||||
[beeInstance],
|
||||
)
|
||||
|
||||
const syncDrivesPublic = useCallback(async () => {
|
||||
if (fm) {
|
||||
@@ -200,55 +216,56 @@ export function Provider({ children }: Props) {
|
||||
}
|
||||
}, [fm, syncDrives])
|
||||
|
||||
const refreshStamp = useCallback(async (batchId: string): Promise<PostageBatch | undefined> => {
|
||||
if (!beeInstanceRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
const usableStamps = await getUsableStamps(beeInstanceRef.current)
|
||||
const refreshedStamp = usableStamps.find(s => s.batchID.toString() === batchId)
|
||||
|
||||
setCurrentStamp(prev => {
|
||||
if (prev && prev.batchID.toString() === batchId && refreshedStamp) {
|
||||
return refreshedStamp
|
||||
const refreshStamp = useCallback(
|
||||
async (batchId: string): Promise<PostageBatch | undefined> => {
|
||||
if (!beeInstance) {
|
||||
return
|
||||
}
|
||||
|
||||
return prev
|
||||
})
|
||||
const usableStamps = await getUsableStamps(beeInstance)
|
||||
const refreshedStamp = usableStamps.find(s => s.batchID.toString() === batchId)
|
||||
|
||||
return refreshedStamp
|
||||
}, [])
|
||||
setCurrentStamp(prev => {
|
||||
if (prev && prev.batchID.toString() === batchId && refreshedStamp) {
|
||||
return refreshedStamp
|
||||
}
|
||||
|
||||
return prev
|
||||
})
|
||||
|
||||
return refreshedStamp
|
||||
},
|
||||
[beeInstance],
|
||||
)
|
||||
|
||||
const init = useCallback(async (): Promise<FileManagerBase | null> => {
|
||||
const pk = getSignerPk()
|
||||
|
||||
if (!apiUrl || !pk || initInProgressRef.current) return null
|
||||
if (!beeInstance || !pk || initInProgressRef.current) return null
|
||||
|
||||
initInProgressRef.current = true
|
||||
|
||||
setFm(null)
|
||||
setInitDone(false)
|
||||
setFiles([])
|
||||
setDrives([])
|
||||
setAdminDrive(null)
|
||||
setInitializationError(false)
|
||||
setCurrentDrive(undefined)
|
||||
setCurrentStamp(undefined)
|
||||
setShallReset(false)
|
||||
|
||||
if (!beeInstanceRef.current) {
|
||||
beeInstanceRef.current = new Bee(apiUrl, { signer: pk })
|
||||
}
|
||||
|
||||
const manager = new FileManagerBase(beeInstanceRef.current)
|
||||
const manager = new FileManagerBase(beeInstance)
|
||||
|
||||
const handleInitialized = (success: boolean) => {
|
||||
setInitializationError(!success)
|
||||
setInitDone(true)
|
||||
|
||||
if (success) {
|
||||
if (manager.adminStamp && !manager.adminStamp.usable) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Admin stamp exists but is not usable')
|
||||
setShallReset(true)
|
||||
setInitializationError(true)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -310,11 +327,13 @@ export function Provider({ children }: Props) {
|
||||
|
||||
return manager
|
||||
} catch {
|
||||
setInitDone(true)
|
||||
|
||||
return null
|
||||
} finally {
|
||||
initInProgressRef.current = false
|
||||
}
|
||||
}, [apiUrl, syncDrives, syncFiles])
|
||||
}, [beeInstance, syncDrives, syncFiles])
|
||||
|
||||
const resync = useCallback(async (): Promise<void> => {
|
||||
const prevDriveId = currentDrive?.id.toString()
|
||||
@@ -322,19 +341,59 @@ export function Provider({ children }: Props) {
|
||||
|
||||
const manager = await init()
|
||||
|
||||
if (prevDriveId && manager && beeInstanceRef.current) {
|
||||
if (prevDriveId && manager && beeInstance) {
|
||||
const refreshedDrive = manager.driveList.find(d => d.id.toString() === prevDriveId)
|
||||
setCurrentDrive(refreshedDrive)
|
||||
|
||||
const uStamps: PostageBatch[] = await getUsableStamps(beeInstanceRef.current)
|
||||
const uStamps: PostageBatch[] = await getUsableStamps(beeInstance)
|
||||
const isValidCurrentStamp = uStamps.find(s => s.batchID.toString() === prevStamp?.batchID.toString())
|
||||
|
||||
setCurrentStamp(isValidCurrentStamp)
|
||||
}
|
||||
}, [currentDrive?.id, currentStamp, init])
|
||||
}, [beeInstance, currentDrive?.id, currentStamp, init])
|
||||
|
||||
useEffect(() => {
|
||||
if (!apiUrl || initInProgressRef.current) {
|
||||
apiUrlRef.current = apiUrl
|
||||
}, [apiUrl])
|
||||
|
||||
useEffect(() => {
|
||||
const isConnecting = status.all === CheckState.CONNECTING
|
||||
const isApiOk = status.apiConnection.isEnabled && status.apiConnection.checkState === CheckState.OK
|
||||
const currentApiUrl = apiUrlRef.current
|
||||
const pk = getSignerPk()
|
||||
|
||||
if (!currentApiUrl || !pk) {
|
||||
isBeeApiInitialized.current = false
|
||||
setBeeInstance(null)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (isConnecting) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isBeeApiInitialized.current) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isApiOk) {
|
||||
return
|
||||
}
|
||||
|
||||
isBeeApiInitialized.current = true
|
||||
setBeeInstance(new Bee(currentApiUrl, { signer: pk }))
|
||||
}, [status.all, status.apiConnection, pkSaved])
|
||||
|
||||
useEffect(() => {
|
||||
isBeeApiInitialized.current = false
|
||||
setBeeInstance(null)
|
||||
setInitDone(false)
|
||||
initInProgressRef.current = false
|
||||
}, [apiUrl])
|
||||
|
||||
useEffect(() => {
|
||||
if (!beeInstance || initInProgressRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -343,7 +402,7 @@ export function Provider({ children }: Props) {
|
||||
}
|
||||
|
||||
initFromLocalState()
|
||||
}, [apiUrl, init])
|
||||
}, [beeInstance, init])
|
||||
|
||||
useEffect(() => {
|
||||
if (fm && drives.length === 0 && !adminDrive) {
|
||||
@@ -354,6 +413,7 @@ export function Provider({ children }: Props) {
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
fm,
|
||||
initDone,
|
||||
files,
|
||||
currentDrive,
|
||||
currentStamp,
|
||||
@@ -367,12 +427,14 @@ export function Provider({ children }: Props) {
|
||||
setCurrentStamp,
|
||||
resync,
|
||||
init,
|
||||
notifyPkSaved,
|
||||
setShowError,
|
||||
syncDrives: syncDrivesPublic,
|
||||
refreshStamp,
|
||||
}),
|
||||
[
|
||||
fm,
|
||||
initDone,
|
||||
files,
|
||||
currentDrive,
|
||||
currentStamp,
|
||||
@@ -386,6 +448,7 @@ export function Provider({ children }: Props) {
|
||||
setCurrentStamp,
|
||||
resync,
|
||||
init,
|
||||
notifyPkSaved,
|
||||
setShowError,
|
||||
syncDrivesPublic,
|
||||
refreshStamp,
|
||||
|
||||
Reference in New Issue
Block a user