diff --git a/.changeset/early-bobcats-fry.md b/.changeset/early-bobcats-fry.md new file mode 100644 index 000000000..cb22d6d8c --- /dev/null +++ b/.changeset/early-bobcats-fry.md @@ -0,0 +1,6 @@ +--- +'renterd': patch +'@siafoundation/renterd-react': patch +--- + +Fixed a bug optimistically updating last scan information when initiating a host scan. diff --git a/.changeset/eighty-eagles-taste.md b/.changeset/eighty-eagles-taste.md new file mode 100644 index 000000000..2a0dc068a --- /dev/null +++ b/.changeset/eighty-eagles-taste.md @@ -0,0 +1,5 @@ +--- +'renterd': minor +--- + +The hosts explorer now uses the new combined hosts API. diff --git a/.changeset/fair-carrots-reflect.md b/.changeset/fair-carrots-reflect.md new file mode 100644 index 000000000..3051f542a --- /dev/null +++ b/.changeset/fair-carrots-reflect.md @@ -0,0 +1,7 @@ +--- +'@siafoundation/renterd-js': minor +'@siafoundation/renterd-react': minor +'@siafoundation/renterd-types': minor +--- + +Added the bus list autopilots API. diff --git a/.changeset/late-onions-hammer.md b/.changeset/late-onions-hammer.md new file mode 100644 index 000000000..5beb0933e --- /dev/null +++ b/.changeset/late-onions-hammer.md @@ -0,0 +1,7 @@ +--- +'@siafoundation/renterd-js': minor +'@siafoundation/renterd-react': minor +'@siafoundation/renterd-types': minor +--- + +Added new combined hosts API. diff --git a/.changeset/tiny-mails-guess.md b/.changeset/tiny-mails-guess.md new file mode 100644 index 000000000..ff80ebbc1 --- /dev/null +++ b/.changeset/tiny-mails-guess.md @@ -0,0 +1,7 @@ +--- +'@siafoundation/renterd-js': minor +'@siafoundation/renterd-react': minor +'@siafoundation/renterd-types': minor +--- + +Removed deprecated search hosts and autopilot hosts APIs. diff --git a/apps/renterd/contexts/app/useAutopilot.tsx b/apps/renterd/contexts/app/useAutopilot.tsx index d2cb73ab4..59ee63fbd 100644 --- a/apps/renterd/contexts/app/useAutopilot.tsx +++ b/apps/renterd/contexts/app/useAutopilot.tsx @@ -1,8 +1,17 @@ import { secondsInMilliseconds } from '@siafoundation/units' -import { useAutopilotState } from '@siafoundation/renterd-react' +import { useAutopilotState, useAutopilots } from '@siafoundation/renterd-react' import { useEffect, useState } from 'react' export function useAutopilot() { + // Assume there is only one autopilot. + const autopilots = useAutopilots({ + config: { + swr: { + revalidateOnFocus: false, + }, + }, + }) + const id = autopilots.data?.[0]?.id const state = useAutopilotState({ config: { swr: { @@ -31,6 +40,7 @@ export function useAutopilot() { }, [state]) return { + id: id || 'autopilot', status, state, } diff --git a/apps/renterd/contexts/hosts/columns.tsx b/apps/renterd/contexts/hosts/columns.tsx index 84e5342ff..4a1b0be0f 100644 --- a/apps/renterd/contexts/hosts/columns.tsx +++ b/apps/renterd/contexts/hosts/columns.tsx @@ -21,7 +21,8 @@ import { format, formatDistance, formatRelative } from 'date-fns' import { HostContextMenu } from '../../components/Hosts/HostContextMenu' import { useWorkflows } from '@siafoundation/react-core' import { - AutopilotHost, + HostPriceTable, + HostSettings, RhpScanPayload, workerRhpScanRoute, } from '@siafoundation/renterd-types' @@ -135,15 +136,15 @@ export const columns: HostsTableColumn[] = ( return (
- {data.usable ? ( + {data.isUsable ? ( ) : ( @@ -198,7 +199,7 @@ export const columns: HostsTableColumn[] = (
- {Object.entries(data.gougingBreakdown) + {Object.entries(data.gouging) .filter(([_, reason]) => reason && typeof reason === 'string') .map(([key, reason]) => ( @@ -451,29 +452,30 @@ export const columns: HostsTableColumn[] = ( /> ), }, - { - id: 'ap_scoreOverall', - label: 'overall score', - category: 'autopilot', - contentClassName: 'w-[120px] justify-end', - render: ({ data, context }) => { - if (!context.isAutopilotConfigured) { - return ( - - - - - ) - } - return ( - v.toPrecision(2)} - /> - ) - }, - }, + // TODO? + // { + // id: 'ap_scoreOverall', + // label: 'overall score', + // category: 'autopilot', + // contentClassName: 'w-[120px] justify-end', + // render: ({ data, context }) => { + // if (!context.isAutopilotConfigured) { + // return ( + // + // - + // + // ) + // } + // return ( + // v.toPrecision(2)} + // /> + // ) + // }, + // }, { id: 'ap_scoreAge', label: 'age score', @@ -490,7 +492,7 @@ export const columns: HostsTableColumn[] = ( return ( v.toPrecision(2)} /> @@ -513,7 +515,7 @@ export const columns: HostsTableColumn[] = ( return ( v.toPrecision(2)} /> @@ -536,7 +538,7 @@ export const columns: HostsTableColumn[] = ( return ( v.toPrecision(2)} /> @@ -559,7 +561,7 @@ export const columns: HostsTableColumn[] = ( return ( v.toPrecision(2)} /> @@ -582,7 +584,7 @@ export const columns: HostsTableColumn[] = ( return ( v.toPrecision(2)} /> @@ -605,7 +607,7 @@ export const columns: HostsTableColumn[] = ( return ( v.toPrecision(2)} /> @@ -628,7 +630,7 @@ export const columns: HostsTableColumn[] = ( return ( context.isAutopilotConfigured ? '-' : v.toPrecision(2) @@ -1078,9 +1080,7 @@ function getFullLabelAndTip(col: HostsTableColumn): { } } -type Key = - | keyof AutopilotHost['host']['priceTable'] - | keyof AutopilotHost['host']['settings'] +type Key = keyof HostPriceTable | keyof HostSettings function makeRenderSc(section: 'priceTable' | 'settings', name: Key) { return memo(function RenderPriceTableNumber({ data }: { data: HostData }) { diff --git a/apps/renterd/contexts/hosts/dataset.ts b/apps/renterd/contexts/hosts/dataset.ts index be8dcc346..98fc6f059 100644 --- a/apps/renterd/contexts/hosts/dataset.ts +++ b/apps/renterd/contexts/hosts/dataset.ts @@ -1,31 +1,28 @@ import { useMemo } from 'react' import BigNumber from 'bignumber.js' import { HostData } from './types' -import { Host } from '@siafoundation/renterd-types' +import { Host, HostAutopilotChecks } from '@siafoundation/renterd-types' import { - useAutopilotHostsSearch, useHostsAllowlist, useHostsBlocklist, - useHostsSearch, + useHosts, } from '@siafoundation/renterd-react' import { ContractData } from '../contracts/types' -import { useApp } from '../app' import { SiaCentralHost } from '@siafoundation/sia-central-types' +import { objectEntries } from '@siafoundation/design-system' export function useDataset({ - autopilotStatus, - regularResponse, - autopilotResponse, + response, allContracts, + autopilotID, allowlist, blocklist, isAllowlistActive, geoHosts, onHostSelect, }: { - autopilotStatus: ReturnType['autopilot']['status'] - regularResponse: ReturnType - autopilotResponse: ReturnType + response: ReturnType + autopilotID: string allContracts: ContractData[] allowlist: ReturnType blocklist: ReturnType @@ -34,51 +31,28 @@ export function useDataset({ onHostSelect: (publicKey: string, location?: [number, number]) => void }) { return useMemo(() => { - if (autopilotStatus === 'off') { - return ( - regularResponse.data?.map((host) => { - const sch = geoHosts.find((gh) => gh.public_key === host.publicKey) - return { - onClick: () => onHostSelect(host.publicKey, sch?.location), - ...getHostFields(host, allContracts), - ...getAllowedFields({ - host, - allowlist: allowlist.data, - blocklist: blocklist.data, - isAllowlistActive, - }), - ...getAutopilotFields(), - location: sch?.location, - countryCode: sch?.country_code, - } - }) || null - ) - } else if (autopilotStatus === 'on') { - return ( - autopilotResponse.data?.map((ah) => { - const sch = geoHosts.find((gh) => gh.public_key === ah.host.publicKey) - return { - onClick: () => onHostSelect(ah.host.publicKey, sch?.location), - ...getHostFields(ah.host, allContracts), - ...getAllowedFields({ - host: ah.host, - allowlist: allowlist.data, - blocklist: blocklist.data, - isAllowlistActive, - }), - ...getAutopilotFields(ah.checks), - location: sch?.location, - countryCode: sch?.country_code, - } - }) || null - ) - } - return null + return ( + response.data?.map((host) => { + const sch = geoHosts.find((gh) => gh.public_key === host.publicKey) + return { + onClick: () => onHostSelect(host.publicKey, sch?.location), + ...getHostFields(host, allContracts), + ...getAllowedFields({ + host, + allowlist: allowlist.data, + blocklist: blocklist.data, + isAllowlistActive, + }), + ...getAutopilotFields(host.checks?.[autopilotID]), + location: sch?.location, + countryCode: sch?.country_code, + } + }) || null + ) }, [ onHostSelect, - autopilotStatus, - regularResponse.data, - autopilotResponse.data, + autopilotID, + response.data, allContracts, allowlist.data, blocklist.data, @@ -159,42 +133,85 @@ function getAllowedFields({ } function getAutopilotFields(ahc?: { - score: number - gougingBreakdown: { - contractErr?: string - downloadErr?: string - gougingErr?: string - uploadErr?: string - } - gouging: boolean - scoreBreakdown: { + score: { age: number collateral: number interactions: number - prices: number storageRemaining: number + prices: number uptime: number version: number } - unusableReasons: string[] - usable: boolean + gouging: { + contractErr?: string + downloadErr?: string + gougingErr?: string + uploadErr?: string + pruneErr?: string + } + usability: { + blocked: boolean + gouging: boolean + lowScore: boolean + notAcceptingContracts: boolean + notAnnounced: boolean + notCompletingScan: boolean + offline: boolean + redundantIP: boolean + } }) { return { - score: new BigNumber(ahc?.score || 0), - scoreBreakdown: { - age: new BigNumber(ahc?.scoreBreakdown.age || 0), - collateral: new BigNumber(ahc?.scoreBreakdown.collateral || 0), - interactions: new BigNumber(ahc?.scoreBreakdown.interactions || 0), - prices: new BigNumber(ahc?.scoreBreakdown.prices || 0), - storageRemaining: new BigNumber( - ahc?.scoreBreakdown.storageRemaining || 0 - ), - uptime: new BigNumber(ahc?.scoreBreakdown.uptime || 0), - version: new BigNumber(ahc?.scoreBreakdown.version || 0), - }, - gougingBreakdown: ahc?.gougingBreakdown || {}, + score: ahc + ? { + age: new BigNumber(ahc?.score.age || 0), + collateral: new BigNumber(ahc?.score.collateral || 0), + interactions: new BigNumber(ahc?.score.interactions || 0), + prices: new BigNumber(ahc?.score.prices || 0), + storageRemaining: new BigNumber(ahc?.score.storageRemaining || 0), + uptime: new BigNumber(ahc?.score.uptime || 0), + version: new BigNumber(ahc?.score.version || 0), + } + : undefined, + isGouging: ahc + ? Object.values(ahc.gouging || {}).some((v) => v) + : undefined, + isUsable: ahc + ? Object.values(ahc.usability || {}).every((v) => !v) + : undefined, gouging: ahc?.gouging, - unusableReasons: ahc?.unusableReasons || [], - usable: ahc?.usable, + usability: ahc?.usability, + unusableReasons: ahc + ? objectEntries(ahc.usability).reduce((acc, [key, value]) => { + if (value) { + return acc.concat(getUnusableReasonLabel(key)) + } + return acc + }, []) + : [], + } +} + +function getUnusableReasonLabel( + key: keyof HostAutopilotChecks['usability'] +): string { + switch (key) { + case 'blocked': + return 'Host is blocked' + case 'gouging': + return 'Host is gouging' + case 'lowScore': + return 'Host has low score' + case 'notAcceptingContracts': + return 'Host is not accepting contracts' + case 'notAnnounced': + return 'Host is not announced' + case 'notCompletingScan': + return 'Host is not completing scan' + case 'offline': + return 'Host is offline' + case 'redundantIP': + return 'Host has redundant IP' + default: + return 'Unknown' } } diff --git a/apps/renterd/contexts/hosts/index.tsx b/apps/renterd/contexts/hosts/index.tsx index 7d7e9a6e1..14f86f722 100644 --- a/apps/renterd/contexts/hosts/index.tsx +++ b/apps/renterd/contexts/hosts/index.tsx @@ -6,14 +6,13 @@ import { truncate, } from '@siafoundation/design-system' import { - HostsSearchFilterMode, + HostsFilterMode, HostsUsabilityMode, } from '@siafoundation/renterd-types' import { - useAutopilotHostsSearch, useHostsAllowlist, useHostsBlocklist, - useHostsSearch, + useHosts as useHostsSearch, } from '@siafoundation/renterd-react' import { createContext, @@ -66,43 +65,18 @@ function useHostsMain() { return keyIn.length ? keyIn : undefined }, [filters, allContracts]) - const autopilotResponse = useAutopilotHostsSearch({ - disabled: - // prevents an extra fetch when allContracts is null - (filters.find((f) => f.id === 'hasActiveContracts') && !allContracts) || - autopilot.status !== 'on', + const response = useHostsSearch({ payload: { + autopilotID: autopilot.id, limit, offset, usabilityMode: (filters.find((f) => f.id === 'usabilityMode')?.value || 'all') as HostsUsabilityMode, filterMode: (filters.find((f) => f.id === 'filterMode')?.value || - 'all') as HostsSearchFilterMode, + 'all') as HostsFilterMode, addressContains: filters.find((f) => f.id === 'addressContains')?.value, keyIn, }, - config: { - swr: { - // before autopilot is configured this will repeatedly 500 - errorRetryInterval: 20_000, - refreshInterval: defaultDatasetRefreshInterval, - }, - }, - }) - - const regularResponse = useHostsSearch({ - disabled: autopilot.status !== 'off', - payload: { - limit, - offset, - filterMode: (filters.find((f) => f.id === 'filterMode')?.value || - 'all') as HostsSearchFilterMode, - addressContains: filters.find((f) => f.id === 'addressContains')?.value, - keyIn: - filters.find((f) => f.id === 'hasActiveContracts') && allContracts - ? allContracts.map((c) => c.hostKey) - : undefined, - }, config: { swr: { refreshInterval: defaultDatasetRefreshInterval, @@ -197,10 +171,9 @@ function useHostsMain() { ) const dataset = useDataset({ - autopilotStatus: autopilot.status, - autopilotResponse, - regularResponse, + response, allContracts, + autopilotID: autopilot.id, allowlist, blocklist, isAllowlistActive, @@ -236,12 +209,8 @@ function useHostsMain() { [enabledColumns] ) - const isValidating = - autopilot.status === 'on' - ? autopilotResponse.isValidating - : regularResponse.isValidating - const error = - autopilot.status === 'on' ? autopilotResponse.error : regularResponse.error + const isValidating = response.isValidating + const error = response.error const dataState = useDatasetEmptyState(dataset, isValidating, error, filters) const siascanUrl = useSiascanUrl() diff --git a/apps/renterd/contexts/hosts/status.ts b/apps/renterd/contexts/hosts/status.ts index 75d72d34e..0fe4583d8 100644 --- a/apps/renterd/contexts/hosts/status.ts +++ b/apps/renterd/contexts/hosts/status.ts @@ -18,7 +18,7 @@ export const hostColors = { export function getHostStatus(h: HostData) { // active and unusable - if (h.activeContractsCount.gt(0) && !h.usable) { + if (h.activeContractsCount.gt(0) && !h.isUsable) { return { status: 'activeAndUnusable', ...hostColors.activeAndUnusable, diff --git a/apps/renterd/contexts/hosts/types.tsx b/apps/renterd/contexts/hosts/types.tsx index 32b514d78..8374cdbd3 100644 --- a/apps/renterd/contexts/hosts/types.tsx +++ b/apps/renterd/contexts/hosts/types.tsx @@ -1,4 +1,4 @@ -import { AutopilotHost } from '@siafoundation/renterd-types' +import { HostPriceTable, HostSettings } from '@siafoundation/renterd-types' import BigNumber from 'bignumber.js' import { ContractData } from '../contracts/types' @@ -22,8 +22,7 @@ export type HostData = { totalInteractions: BigNumber totalScans: BigNumber // autopilot - score: BigNumber - scoreBreakdown: { + score?: { age: BigNumber collateral: BigNumber interactions: BigNumber @@ -32,17 +31,28 @@ export type HostData = { uptime: BigNumber version: BigNumber } - unusableReasons: string[] - gougingBreakdown: { + gouging?: { contractErr?: string downloadErr?: string gougingErr?: string uploadErr?: string + pruneErr?: string } - priceTable?: AutopilotHost['host']['priceTable'] - settings?: AutopilotHost['host']['settings'] - gouging: boolean - usable: boolean + usability?: { + blocked: boolean + gouging: boolean + lowScore: boolean + notAcceptingContracts: boolean + notAnnounced: boolean + notCompletingScan: boolean + offline: boolean + redundantIP: boolean + } + isGouging?: boolean + isUsable?: boolean + priceTable?: HostPriceTable + unusableReasons?: string[] + settings?: HostSettings activeContractsCount: BigNumber activeContracts: ContractData[] // merged in from sia central API diff --git a/libs/renterd-js/src/autopilot.ts b/libs/renterd-js/src/autopilot.ts index bde26e561..49f4077d9 100644 --- a/libs/renterd-js/src/autopilot.ts +++ b/libs/renterd-js/src/autopilot.ts @@ -8,9 +8,6 @@ import { AutopilotConfigUpdateParams, AutopilotConfigUpdatePayload, AutopilotConfigUpdateResponse, - AutopilotHostsSearchParams, - AutopilotHostsSearchPayload, - AutopilotHostsSearchResponse, AutopilotStateParams, AutopilotStatePayload, AutopilotStateResponse, @@ -18,7 +15,6 @@ import { AutopilotTriggerPayload, AutopilotTriggerResponse, autopilotConfigRoute, - autopilotHostsRoute, autopilotStateRoute, autopilotTriggerRoute, } from '@siafoundation/renterd-types' @@ -54,11 +50,6 @@ export function Autopilot({ AutopilotConfigEvaluatePayload, AutopilotConfigEvaluateResponse >(axios, 'post', autopilotConfigRoute), - hostsSearch: buildRequestHandler< - AutopilotHostsSearchParams, - AutopilotHostsSearchPayload, - AutopilotHostsSearchResponse - >(axios, 'post', autopilotHostsRoute), trigger: buildRequestHandler< AutopilotTriggerParams, AutopilotTriggerPayload, diff --git a/libs/renterd-js/src/bus.ts b/libs/renterd-js/src/bus.ts index 25d3bdbcd..c24950727 100644 --- a/libs/renterd-js/src/bus.ts +++ b/libs/renterd-js/src/bus.ts @@ -94,9 +94,9 @@ import { HostsBlocklistUpdateParams, HostsBlocklistUpdatePayload, HostsBlocklistUpdateResponse, - HostsSearchParams, - HostsSearchPayload, - HostsSearchResponse, + HostsParams, + HostsPayload, + HostsResponse, MultipartUploadAbortParams, MultipartUploadAbortPayload, MultipartUploadAbortResponse, @@ -247,7 +247,7 @@ import { busObjectsKeyRoute, busObjectsListRoute, busObjectsRenameRoute, - busSearchHostsRoute, + busHostsRoute, busSearchObjectsRoute, busSettingKeyRoute, busSettingsRoute, @@ -271,6 +271,10 @@ import { busWalletSendRoute, busWalletSignRoute, busWalletTransactionsRoute, + busAutopilotsRoute, + AutopilotsParams, + AutopilotsPayload, + AutopilotsResponse, } from '@siafoundation/renterd-types' import { buildRequestHandler, initAxios } from '@siafoundation/request' import { AxiosRequestConfig } from 'axios' @@ -284,6 +288,11 @@ export function Bus({ api, password }: { api: string; password?: string }) { BusStatePayload, BusStateResponse >(axios, 'get', busStateRoute), + autopilots: buildRequestHandler< + AutopilotsParams, + AutopilotsPayload, + AutopilotsResponse + >(axios, 'get', busAutopilotsRoute), consensusState: buildRequestHandler< ConsensusStateParams, ConsensusStatePayload, @@ -384,11 +393,11 @@ export function Bus({ api, password }: { api: string; password?: string }) { WalletPendingPayload, WalletPendingResponse >(axios, 'get', busWalletPendingRoute), - hostsSearch: buildRequestHandler< - HostsSearchParams, - HostsSearchPayload, - HostsSearchResponse - >(axios, 'post', busSearchHostsRoute), + hosts: buildRequestHandler( + axios, + 'post', + busHostsRoute + ), host: buildRequestHandler( axios, 'get', diff --git a/libs/renterd-react/src/autopilot.ts b/libs/renterd-react/src/autopilot.ts index d2957e215..fed9bd0fb 100644 --- a/libs/renterd-react/src/autopilot.ts +++ b/libs/renterd-react/src/autopilot.ts @@ -17,16 +17,12 @@ import { AutopilotConfigEvaluateParams, AutopilotConfigEvaluatePayload, AutopilotConfigEvaluateResponse, - AutopilotHostsSearchParams, - AutopilotHostsSearchPayload, - AutopilotHostsSearchResponse, AutopilotStateParams, AutopilotStateResponse, AutopilotTriggerParams, AutopilotTriggerPayload, AutopilotTriggerResponse, autopilotConfigRoute, - autopilotHostsRoute, autopilotStateRoute, autopilotTriggerRoute, } from '@siafoundation/renterd-types' @@ -81,19 +77,6 @@ export function useAutopilotConfigEvaluate( return usePostSwr({ ...args, route: autopilotConfigRoute }) } -export function useAutopilotHostsSearch( - args?: HookArgsWithPayloadSwr< - AutopilotHostsSearchParams, - AutopilotHostsSearchPayload, - AutopilotHostsSearchResponse - > -) { - return usePostSwr({ - ...args, - route: autopilotHostsRoute, - }) -} - export function useAutopilotTrigger( args?: HookArgsCallback< AutopilotTriggerParams, diff --git a/libs/renterd-react/src/bus.ts b/libs/renterd-react/src/bus.ts index d43f7886b..c57a399f3 100644 --- a/libs/renterd-react/src/bus.ts +++ b/libs/renterd-react/src/bus.ts @@ -88,9 +88,9 @@ import { HostsBlocklistUpdateParams, HostsBlocklistUpdatePayload, HostsBlocklistUpdateResponse, - HostsSearchParams, - HostsSearchPayload, - HostsSearchResponse, + HostsParams, + HostsPayload, + HostsResponse, MultipartUploadAbortParams, MultipartUploadAbortPayload, MultipartUploadAbortResponse, @@ -206,7 +206,7 @@ import { busObjectsKeyRoute, busObjectsListRoute, busObjectsRenameRoute, - busSearchHostsRoute, + busHostsRoute, busSearchObjectsRoute, busSettingKeyRoute, busSettingsRoute, @@ -259,6 +259,9 @@ import { WalletSendPayload, WalletSendResponse, busWalletSendRoute, + busAutopilotsRoute, + AutopilotsParams, + AutopilotsResponse, } from '@siafoundation/renterd-types' // state @@ -272,6 +275,17 @@ export function useBusState( }) } +// autopilots + +export function useAutopilots( + args?: HookArgsSwr +) { + return useGetSwr({ + ...args, + route: busAutopilotsRoute, + }) +} + // consensus export function useConsensusState( @@ -501,16 +515,12 @@ export function useWalletPending( return useGetSwr({ ...args, route: busWalletPendingRoute }) } -export function useHostsSearch( - args: HookArgsWithPayloadSwr< - HostsSearchParams, - HostsSearchPayload, - HostsSearchResponse - > +export function useHosts( + args: HookArgsWithPayloadSwr ) { return usePostSwr({ ...args, - route: busSearchHostsRoute, + route: busHostsRoute, }) } @@ -555,7 +565,7 @@ export function useHostsAllowlistUpdate( async (mutate) => { mutate((key) => { const matches = [ - busSearchHostsRoute, + busHostsRoute, busHostsAllowlistRoute, busContractsRoute, ] @@ -577,7 +587,7 @@ export function useHostsBlocklistUpdate( async (mutate) => { mutate((key) => { const matches = [ - busSearchHostsRoute, + busHostsRoute, busHostsBlocklistRoute, busContractsRoute, ] diff --git a/libs/renterd-react/src/worker.ts b/libs/renterd-react/src/worker.ts index b28831498..aba185c07 100644 --- a/libs/renterd-react/src/worker.ts +++ b/libs/renterd-react/src/worker.ts @@ -11,8 +11,6 @@ import { AccountResetDriftParams, AccountResetDriftPayload, AccountResetDriftResponse, - AutopilotHost, - Host, MultipartUploadPartParams, MultipartUploadPartPayload, MultipartUploadPartResponse, @@ -27,9 +25,8 @@ import { RhpScanResponse, WorkerStateParams, WorkerStateResponse, - autopilotHostsRoute, busObjectsRoute, - busSearchHostsRoute, + busHostsRoute, workerAccountIdResetdriftRoute, workerMultipartKeyRoute, workerObjectsKeyRoute, @@ -121,52 +118,31 @@ export function useRhpScan( // is debounced so if the user rescans multiple hosts in quick // succession the list is optimistically updated n times followed // by a single network revalidate. - mutate( - (key) => key.startsWith(autopilotHostsRoute), + mutate( + (key) => key.startsWith(busHostsRoute), (data) => - data?.map((aph) => { - if (aph.host.publicKey === hostKey) { + data?.map((h) => { + if (h.publicKey === hostKey) { return { - ...aph, + ...h, host: { - ...aph.host, + ...h, interactions: { - ...aph.host.interactions, - LastScan: new Date().toISOString(), - LastScanSuccess: !response.data.scanError, + ...h.interactions, + lastScan: new Date().toISOString(), + lastScanSuccess: !response.data.scanError, }, settings: response.data.settings, }, } } - return aph - }), - false - ) - mutate( - (key) => key.startsWith(busSearchHostsRoute), - (data) => - data?.map((host) => { - if (host.publicKey === hostKey) { - return { - ...host, - interactions: { - ...host.interactions, - LastScan: new Date().toISOString(), - LastScanSuccess: !response.data.scanError, - }, - settings: response.data.settings, - } - } - return host + return h }), false ) debouncedListRevalidate(() => { mutate( - (key) => - key.startsWith(autopilotHostsRoute) || - key.startsWith(busSearchHostsRoute), + (key) => key.startsWith(busHostsRoute), (d) => d, true ) diff --git a/libs/renterd-types/src/autopilot.ts b/libs/renterd-types/src/autopilot.ts index de2c1d5b6..fa82d960a 100644 --- a/libs/renterd-types/src/autopilot.ts +++ b/libs/renterd-types/src/autopilot.ts @@ -1,14 +1,8 @@ -import { - AutopilotConfig, - GougingSettings, - Host, - RedundancySettings, -} from './types' -import { HostsSearchPayload, BusStateResponse } from './bus' +import { AutopilotConfig, GougingSettings, RedundancySettings } from './types' +import { BusStateResponse } from './bus' export const autopilotStateRoute = '/autopilot/state' export const autopilotConfigRoute = '/autopilot/config' -export const autopilotHostsRoute = '/autopilot/hosts' export const autopilotTriggerRoute = '/autopilot/trigger' type AutopilotStatus = { @@ -63,35 +57,6 @@ export type AutopilotConfigEvaluateResponse = { recommendation?: ConfigRecommendation } -export type AutopilotHost = { - host: Host - checks?: { - score: number - scoreBreakdown: { - age: number - collateral: number - interactions: number - storageRemaining: number - prices: number - uptime: number - version: number - } - unusableReasons: string[] - gougingBreakdown: { - contractErr?: string - downloadErr?: string - gougingErr?: string - uploadErr?: string - } - gouging: boolean - usable: boolean - } -} - -export type AutopilotHostsSearchParams = void -export type AutopilotHostsSearchPayload = HostsSearchPayload -export type AutopilotHostsSearchResponse = AutopilotHost[] - export type AutopilotTriggerParams = void export type AutopilotTriggerPayload = { forceScan: boolean } export type AutopilotTriggerResponse = { triggered: boolean } diff --git a/libs/renterd-types/src/bus.ts b/libs/renterd-types/src/bus.ts index 2c5628317..0b899475f 100644 --- a/libs/renterd-types/src/bus.ts +++ b/libs/renterd-types/src/bus.ts @@ -10,6 +10,7 @@ import { TransactionID, } from '@siafoundation/types' import { + Autopilot, ConsensusState, Contract, ContractRevision, @@ -23,6 +24,7 @@ import { } from './types' export const busStateRoute = '/bus/state' +export const busAutopilotsRoute = '/bus/autopilots' export const busConsensusStateRoute = '/bus/consensus/state' export const busConsensusAcceptblockRoute = '/bus/consensus/acceptblock' export const busSyncerPeersRoute = '/bus/syncer/peers' @@ -43,7 +45,7 @@ export const busWalletDiscardRoute = '/bus/wallet/discard' export const busWalletPrepareFormRoute = '/bus/wallet/prepare/form' export const busWalletPrepareRenewRoute = '/bus/wallet/prepare/renew' export const busWalletPendingRoute = '/bus/wallet/pending' -export const busSearchHostsRoute = '/bus/search/hosts' +export const busHostsRoute = '/bus/hosts' export const busHostHostKeyRoute = '/bus/host/:hostKey' export const busHostsHostKeyRoute = '/bus/hosts/:hostKey' export const busHostsBlocklistRoute = '/bus/hosts/blocklist' @@ -105,6 +107,12 @@ export type BusStateResponse = BuildState & { startTime: number } +// autopilots + +export type AutopilotsParams = void +export type AutopilotsPayload = void +export type AutopilotsResponse = Autopilot[] + // consensus export type ConsensusStateParams = void @@ -242,18 +250,19 @@ export type WalletPendingResponse = Transaction[] // hosts -export type HostsSearchParams = void -export type HostsSearchFilterMode = 'all' | 'allowed' | 'blocked' +export type HostsParams = void +export type HostsFilterMode = 'all' | 'allowed' | 'blocked' export type HostsUsabilityMode = 'all' | 'usable' | 'unusable' -export type HostsSearchPayload = { - filterMode: HostsSearchFilterMode +export type HostsPayload = { + autopilotID: string + filterMode: HostsFilterMode usabilityMode?: HostsUsabilityMode addressContains?: string keyIn?: string[] offset?: number limit?: number } -export type HostsSearchResponse = Host[] +export type HostsResponse = Host[] export type HostParams = { hostKey: string } export type HostPayload = Host diff --git a/libs/renterd-types/src/types.ts b/libs/renterd-types/src/types.ts index 559049860..d796724f6 100644 --- a/libs/renterd-types/src/types.ts +++ b/libs/renterd-types/src/types.ts @@ -241,6 +241,40 @@ export type Host = { scanned: boolean priceTable?: HostPriceTable settings?: HostSettings + blocked: boolean + storedData: number + resolvedAddresses?: string[] + subnets?: string[] + checks?: Record +} + +export type HostAutopilotChecks = { + score: { + age: number + collateral: number + interactions: number + storageRemaining: number + prices: number + uptime: number + version: number + } + gouging: { + contractErr?: string + downloadErr?: string + gougingErr?: string + uploadErr?: string + pruneErr?: string + } + usability: { + blocked: boolean + gouging: boolean + lowScore: boolean + notAcceptingContracts: boolean + notAnnounced: boolean + notCompletingScan: boolean + offline: boolean + redundantIP: boolean + } } export type SiacoinElement = { @@ -275,6 +309,12 @@ export type AutopilotConfig = { contracts: AutopilotContractsConfig } +export type Autopilot = { + id: string + config: AutopilotConfig + currentPeriod: number +} + export type WalletTransaction = { raw: Transaction index: ChainIndex