feat: merge api (#658)

This commit is contained in:
Cafe137
2024-06-03 15:07:01 -07:00
committed by GitHub
parent b3f521ca20
commit 8cbd812a2c
43 changed files with 218 additions and 717 deletions
+28 -128
View File
@@ -2,7 +2,6 @@ import {
BeeModes,
ChainState,
ChequebookAddressResponse,
Health,
LastChequesResponse,
NodeAddresses,
NodeInfo,
@@ -10,8 +9,6 @@ import {
Topology,
} from '@ethersphere/bee-js'
import { ReactChild, ReactElement, createContext, useContext, useEffect, useState } from 'react'
import semver from 'semver'
import PackageJson from '../../package.json'
import { useLatestBeeRelease } from '../hooks/apiHooks'
import { BzzToken } from '../models/BzzToken'
import { Token } from '../models/Token'
@@ -38,9 +35,6 @@ interface StatusItem {
interface Status {
all: CheckState
version: StatusItem
blockchainConnection: StatusItem
debugApiConnection: StatusItem
apiConnection: StatusItem
topology: StatusItem
chequebook: StatusItem
@@ -48,15 +42,8 @@ interface Status {
interface ContextInterface {
status: Status
latestPublishedVersion?: string
latestUserVersion?: string
latestUserVersionExact?: string
isLatestBeeVersion: boolean
latestBeeVersionUrl: string
error: Error | null
apiHealth: boolean
debugApiHealth: Health | null
debugApiReadiness: boolean
nodeAddresses: NodeAddresses | null
nodeInfo: NodeInfo | null
topology: Topology | null
@@ -80,22 +67,12 @@ interface ContextInterface {
const initialValues: ContextInterface = {
status: {
all: CheckState.ERROR,
version: { isEnabled: false, checkState: CheckState.ERROR },
blockchainConnection: { isEnabled: false, checkState: CheckState.ERROR },
debugApiConnection: { isEnabled: false, checkState: CheckState.ERROR },
apiConnection: { isEnabled: false, checkState: CheckState.ERROR },
topology: { isEnabled: false, checkState: CheckState.ERROR },
chequebook: { isEnabled: false, checkState: CheckState.ERROR },
},
latestPublishedVersion: undefined,
latestUserVersion: undefined,
latestUserVersionExact: undefined,
isLatestBeeVersion: false,
latestBeeVersionUrl: 'https://github.com/ethersphere/bee/releases/latest',
error: null,
apiHealth: false,
debugApiHealth: null,
debugApiReadiness: false,
nodeAddresses: null,
nodeInfo: null,
topology: null,
@@ -124,40 +101,16 @@ interface Props {
}
function getStatus(
debugApiHealth: Health | null,
debugApiReadiness: boolean,
nodeInfo: NodeInfo | null,
apiHealth: boolean,
topology: Topology | null,
chequebookAddress: ChequebookAddressResponse | null,
chequebookBalance: ChequebookBalance | null,
error: Error | null,
isDesktop: boolean,
startedAt: number,
latestPublishedVersion: string | undefined,
latestUserVersion: string | undefined,
): Status {
const status: Status = { ...initialValues.status }
// Version check
status.version.isEnabled = !isDesktop
status.version.checkState =
latestPublishedVersion &&
latestUserVersion &&
semver.satisfies(latestPublishedVersion, latestUserVersion, {
includePrerelease: true,
})
? CheckState.OK
: CheckState.WARNING
// Blockchain connection check
status.blockchainConnection.isEnabled = true
status.blockchainConnection.checkState = Boolean(debugApiHealth?.status === 'ok') ? CheckState.OK : CheckState.ERROR
// Debug API connection check
status.debugApiConnection.isEnabled = true
status.debugApiConnection.checkState = Boolean(debugApiHealth?.status === 'ok') ? CheckState.OK : CheckState.ERROR
// API connection check
status.apiConnection.isEnabled = true
status.apiConnection.checkState = apiHealth ? CheckState.OK : CheckState.ERROR
@@ -177,17 +130,12 @@ function getStatus(
} else status.chequebook.checkState = CheckState.OK
}
status.all = determineOverallStatus(debugApiHealth, debugApiReadiness, status, startedAt)
status.all = determineOverallStatus(status, startedAt)
return status
}
function determineOverallStatus(
debugApiHealth: Health | null,
debugApiReadiness: boolean,
status: Status,
startedAt: number,
): CheckState {
function determineOverallStatus(status: Status, startedAt: number): CheckState {
const hasErrors = Object.values(status).some(
({ isEnabled, checkState }) => isEnabled && checkState === CheckState.ERROR,
)
@@ -196,9 +144,7 @@ function determineOverallStatus(
)
const isInGracePeriod = Date.now() - startedAt < LAUNCH_GRACE_PERIOD
if (debugApiHealth?.status === 'ok' && !debugApiReadiness) {
return CheckState.STARTING
} else if (hasErrors && isInGracePeriod) {
if (hasErrors && isInGracePeriod) {
return CheckState.CONNECTING
} else if (hasErrors) {
return CheckState.ERROR
@@ -212,19 +158,13 @@ function determineOverallStatus(
// This does not need to be exposed and works much better as variable than state variable which may trigger some unnecessary re-renders
let isRefreshing = false
interface InitialSettings {
isDesktop?: boolean
}
interface Props extends InitialSettings {
interface Props {
children: ReactChild
}
export function Provider({ children, isDesktop }: Props): ReactElement {
const { beeApi, beeDebugApi } = useContext(SettingsContext)
export function Provider({ children }: Props): ReactElement {
const { beeApi } = useContext(SettingsContext)
const [apiHealth, setApiHealth] = useState<boolean>(false)
const [debugApiHealth, setDebugApiHealth] = useState<Health | null>(null)
const [debugApiReadiness, setDebugApiReadiness] = useState(false)
const [nodeAddresses, setNodeAddresses] = useState<NodeAddresses | null>(null)
const [nodeInfo, setNodeInfo] = useState<NodeInfo | null>(null)
const [topology, setNodeTopology] = useState<Topology | null>(null)
@@ -246,10 +186,6 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
const [lastUpdate, setLastUpdate] = useState<number | null>(initialValues.lastUpdate)
const [frequency, setFrequency] = useState<number | null>(30000)
const latestPublishedVersion = semver.coerce(latestBeeRelease?.name)?.version
const latestUserVersion = semver.coerce(debugApiHealth?.version)?.version
const latestUserVersionExact = debugApiHealth?.version
useEffect(() => {
setIsLoading(true)
@@ -260,8 +196,6 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
useEffect(() => {
setIsLoading(true)
setDebugApiHealth(null)
setNodeAddresses(null)
setNodeTopology(null)
setNodeInfo(null)
@@ -273,15 +207,19 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
setSettlements(null)
setChainState(null)
if (beeDebugApi !== null) refresh()
}, [beeDebugApi]) // eslint-disable-line react-hooks/exhaustive-deps
if (beeApi !== null) {
refresh()
}
}, [beeApi]) // eslint-disable-line react-hooks/exhaustive-deps
const refresh = async () => {
// Don't want to refresh when already refreshing
if (isRefreshing) return
if (isRefreshing) {
return
}
// Not a valid bee api
if (!beeApi || !beeDebugApi) {
if (!beeApi) {
setIsLoading(false)
return
@@ -293,7 +231,7 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
// Wrap the chequebook balance call to return BZZ values as Token object
const chequeBalanceWrapper = async () => {
const { totalBalance, availableBalance } = await beeDebugApi.getChequebookBalance({ timeout: TIMEOUT })
const { totalBalance, availableBalance } = await beeApi.getChequebookBalance({ timeout: TIMEOUT })
return {
totalBalance: new Token(totalBalance),
@@ -303,14 +241,14 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
// Wrap the balances call to return BZZ values as Token object
const peerBalanceWrapper = async () => {
const { balances } = await beeDebugApi.getAllBalances({ timeout: TIMEOUT })
const { balances } = await beeApi.getAllBalances({ timeout: TIMEOUT })
return balances.map(({ peer, balance }) => ({ peer, balance: new Token(balance) }))
}
// Wrap the settlements call to return BZZ values as Token object
const settlementsWrapper = async () => {
const { totalReceived, settlements, totalSent } = await beeDebugApi.getAllSettlements({ timeout: TIMEOUT })
const { totalReceived, settlements, totalSent } = await beeApi.getAllSettlements({ timeout: TIMEOUT })
return {
totalReceived: new Token(totalReceived),
@@ -330,62 +268,50 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
.then(setApiHealth)
.catch(() => setApiHealth(false)),
// Debug API health
beeDebugApi
.getHealth({ timeout: TIMEOUT })
.then(setDebugApiHealth)
.catch(() => setDebugApiHealth(null)),
// Debug API readiness
beeDebugApi
.getReadiness({ timeout: TIMEOUT })
.then(setDebugApiReadiness)
.catch(() => setDebugApiReadiness(false)),
// Node Addresses
beeDebugApi
beeApi
.getNodeAddresses({ timeout: TIMEOUT })
.then(setNodeAddresses)
.catch(() => setNodeAddresses(null)),
// NodeInfo
beeDebugApi
beeApi
.getNodeInfo({ timeout: TIMEOUT })
.then(setNodeInfo)
.catch(() => setNodeInfo(null)),
// Network Topology
beeDebugApi
beeApi
.getTopology({ timeout: TIMEOUT })
.then(setNodeTopology)
.catch(() => setNodeTopology(null)),
// Peers
beeDebugApi
beeApi
.getPeers({ timeout: TIMEOUT })
.then(setPeers)
.catch(() => setPeers(null)),
// Chequebook address
beeDebugApi
beeApi
.getChequebookAddress({ timeout: TIMEOUT })
.then(setChequebookAddress)
.catch(() => setChequebookAddress(null)),
// Cheques
beeDebugApi
beeApi
.getLastCheques({ timeout: TIMEOUT })
.then(setPeerCheques)
.catch(() => setPeerCheques(null)),
// Chain state
beeDebugApi
beeApi
.getChainState({ timeout: TIMEOUT })
.then(setChainState)
.catch(() => setChainState(null)),
// Wallet
beeDebugApi
beeApi
.getWalletBalance({ timeout: TIMEOUT })
.then(({ chainID }) => setChainId(chainID))
.catch(() => setChainId(null)),
@@ -395,7 +321,7 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
.then(setChequebookBalance)
.catch(() => setChequebookBalance(null)),
beeDebugApi
beeApi
.getStake({ timeout: TIMEOUT })
.then(stake => setStake(new BzzToken(stake)))
.catch(() => setStake(null)),
@@ -427,20 +353,7 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
}
const stop = () => setFrequency(null)
const status = getStatus(
debugApiHealth,
debugApiReadiness,
nodeInfo,
apiHealth,
topology,
chequebookAddress,
chequebookBalance,
error,
Boolean(isDesktop),
startedAt,
latestPublishedVersion,
latestUserVersion,
)
const status = getStatus(nodeInfo, apiHealth, topology, chequebookAddress, chequebookBalance, error, startedAt)
useEffect(() => {
let newFrequency = REFRESH_WHEN_OK
@@ -458,27 +371,14 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
return () => clearInterval(interval)
}
}, [frequency, beeDebugApi, beeApi]) // eslint-disable-line react-hooks/exhaustive-deps
}, [frequency, beeApi]) // eslint-disable-line react-hooks/exhaustive-deps
return (
<Context.Provider
value={{
status,
latestUserVersion,
latestUserVersionExact,
latestPublishedVersion,
isLatestBeeVersion: Boolean(
latestPublishedVersion &&
latestUserVersion &&
semver.satisfies(latestPublishedVersion, latestUserVersion, {
includePrerelease: true,
}),
),
latestBeeVersionUrl: latestBeeRelease?.html_url || 'https://github.com/ethersphere/bee/releases/latest',
error,
apiHealth,
debugApiHealth,
debugApiReadiness,
nodeAddresses,
nodeInfo,
topology,
+2 -29
View File
@@ -1,7 +1,7 @@
import { Bee, BeeDebug } from '@ethersphere/bee-js'
import { Bee } from '@ethersphere/bee-js'
import { providers } from 'ethers'
import { ReactElement, ReactNode, createContext, useEffect, useState } from 'react'
import { DEFAULT_BEE_API_HOST, DEFAULT_BEE_DEBUG_API_HOST, DEFAULT_RPC_URL } from '../constants'
import { DEFAULT_BEE_API_HOST, DEFAULT_RPC_URL } from '../constants'
import { useGetBeeConfig } from '../hooks/apiHooks'
const LocalStorageKeys = {
@@ -10,9 +10,7 @@ const LocalStorageKeys = {
interface ContextInterface {
apiUrl: string
apiDebugUrl: string
beeApi: Bee | null
beeDebugApi: BeeDebug | null
lockedApiSettings: boolean
desktopApiKey: string
isDesktop: boolean
@@ -23,7 +21,6 @@ interface ContextInterface {
dataDir: string | null
ensResolver: string | null
setApiUrl: (url: string) => void
setDebugApiUrl: (url: string) => void
setAndPersistJsonRpcProvider: (url: string) => void
isLoading: boolean
error: Error | null
@@ -31,11 +28,8 @@ interface ContextInterface {
const initialValues: ContextInterface = {
beeApi: null,
beeDebugApi: null,
apiUrl: DEFAULT_BEE_API_HOST,
apiDebugUrl: DEFAULT_BEE_DEBUG_API_HOST,
setApiUrl: () => {}, // eslint-disable-line
setDebugApiUrl: () => {}, // eslint-disable-line
lockedApiSettings: false,
isDesktop: false,
desktopApiKey: '',
@@ -55,7 +49,6 @@ export const Consumer = Context.Consumer
interface InitialSettings {
beeApiUrl?: string
beeDebugApiUrl?: string
lockedApiSettings?: boolean
isDesktop?: boolean
desktopUrl?: string
@@ -73,9 +66,7 @@ export function Provider({ children, ...propsSettings }: Props): ReactElement {
localStorage.getItem(LocalStorageKeys.providerUrl) || propsSettings.defaultRpcUrl || DEFAULT_RPC_URL
const [apiUrl, setApiUrl] = useState<string>(initialValues.apiUrl)
const [apiDebugUrl, setDebugApiUrl] = useState<string>(initialValues.apiDebugUrl)
const [beeApi, setBeeApi] = useState<Bee | null>(null)
const [beeDebugApi, setBeeDebugApi] = useState<BeeDebug | null>(null)
const [desktopApiKey, setDesktopApiKey] = useState<string>(initialValues.desktopApiKey)
const [rpcProviderUrl, setRpcProviderUrl] = useState(propsProviderUrl)
const [rpcProvider, setRpcProvider] = useState(new providers.JsonRpcProvider(propsProviderUrl))
@@ -84,12 +75,6 @@ export function Provider({ children, ...propsSettings }: Props): ReactElement {
const url = makeHttpUrl(
config?.['api-addr'] ?? sessionStorage.getItem('api_host') ?? propsSettings.beeApiUrl ?? apiUrl,
)
const debugUrl = makeHttpUrl(
config?.['debug-api-addr'] ??
sessionStorage.getItem('debug_api_host') ??
propsSettings.beeDebugApiUrl ??
apiDebugUrl,
)
useEffect(() => {
const urlSearchParams = new URLSearchParams(window.location.search)
@@ -111,24 +96,12 @@ export function Provider({ children, ...propsSettings }: Props): ReactElement {
}
}, [url])
useEffect(() => {
try {
setBeeDebugApi(new BeeDebug(debugUrl))
sessionStorage.setItem('debug_api_host', debugUrl)
} catch (e) {
setBeeDebugApi(null)
}
}, [debugUrl])
return (
<Context.Provider
value={{
apiUrl: url,
apiDebugUrl: debugUrl,
beeApi,
beeDebugApi,
setApiUrl,
setDebugApiUrl,
lockedApiSettings: Boolean(propsSettings.lockedApiSettings),
desktopApiKey,
isDesktop,
+8 -5
View File
@@ -48,7 +48,7 @@ export function enrichStamp(postageBatch: PostageBatch): EnrichedPostageBatch {
}
export function Provider({ children }: Props): ReactElement {
const { beeDebugApi } = useContext(SettingsContext)
const { beeApi } = useContext(SettingsContext)
const [stamps, setStamps] = useState<EnrichedPostageBatch[] | null>(initialValues.stamps)
const [error, setError] = useState<Error | null>(initialValues.error)
const [isLoading, setIsLoading] = useState<boolean>(initialValues.isLoading)
@@ -56,14 +56,17 @@ export function Provider({ children }: Props): ReactElement {
const [frequency, setFrequency] = useState<number | null>(null)
const refresh = async () => {
// Don't want to refresh when already refreshing
if (isLoading) return
if (isLoading) {
return
}
if (!beeDebugApi) return
if (!beeApi) {
return
}
try {
setIsLoading(true)
const stamps = await beeDebugApi.getAllPostageBatch()
const stamps = await beeApi.getAllPostageBatch()
setStamps(stamps.filter(x => x.exists).map(enrichStamp))
setLastUpdate(Date.now())