Compare commits
9 Commits
develop
...
fix/5759-i
Author | SHA1 | Date | |
---|---|---|---|
|
002738af70 | ||
|
b0bbae4c2e | ||
|
635445f23b | ||
|
10e30b9f70 | ||
|
46c6e27aec | ||
|
4bd73bfc0f | ||
|
15aad9db62 | ||
|
46308b381f | ||
|
938ad08a60 |
@ -1,63 +1,126 @@
|
|||||||
import type { InMemoryCacheConfig } from '@apollo/client';
|
import type { InMemoryCacheConfig } from '@apollo/client';
|
||||||
import {
|
import {
|
||||||
AppFailure,
|
|
||||||
AppLoader,
|
AppLoader,
|
||||||
NetworkLoader,
|
NetworkLoader,
|
||||||
NodeFailure,
|
|
||||||
NodeGuard,
|
|
||||||
useEnvironment,
|
useEnvironment,
|
||||||
|
useNodeSwitcherStore,
|
||||||
} from '@vegaprotocol/environment';
|
} from '@vegaprotocol/environment';
|
||||||
import { type ReactNode } from 'react';
|
import { useEffect, type ReactNode, useState } from 'react';
|
||||||
import { Web3Provider } from './web3-provider';
|
import { Web3Provider } from './web3-provider';
|
||||||
import { useT } from '../../lib/use-t';
|
import { useT } from '../../lib/use-t';
|
||||||
import { DataLoader } from './data-loader';
|
import { DataLoader } from './data-loader';
|
||||||
import { WalletProvider } from '@vegaprotocol/wallet-react';
|
import { WalletProvider } from '@vegaprotocol/wallet-react';
|
||||||
import { useVegaWalletConfig } from '../../lib/hooks/use-vega-wallet-config';
|
import { useVegaWalletConfig } from '../../lib/hooks/use-vega-wallet-config';
|
||||||
|
import { Trans } from 'react-i18next';
|
||||||
|
import { Button, Loader, Splash, VLogo } from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
|
const Failure = ({ reason }: { reason?: ReactNode }) => {
|
||||||
|
const t = useT();
|
||||||
|
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
|
||||||
|
return (
|
||||||
|
<Splash>
|
||||||
|
<div className="border border-vega-red m-10 mx-auto w-4/5 max-w-3xl rounded-lg overflow-hidden animate-shake">
|
||||||
|
<div className="bg-vega-red text-white px-2 py-2 flex gap-1 items-center font-alpha calt uppercase">
|
||||||
|
<VLogo className="h-4" />
|
||||||
|
<span className="text-lg">{t('Failed to initialize the app')}</span>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 text-left text-sm">
|
||||||
|
<p className="mb-4">{reason}</p>
|
||||||
|
<div className="text-center">
|
||||||
|
<Button className="border-2" onClick={() => setNodeSwitcher(true)}>
|
||||||
|
{t('Change node')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Splash>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loading = () => {
|
||||||
|
const [showSlowNotification, setShowSlowNotification] = useState(false);
|
||||||
|
const t = useT();
|
||||||
|
const setNodeSwitcher = useNodeSwitcherStore((store) => store.setDialogOpen);
|
||||||
|
useEffect(() => {
|
||||||
|
const to = setTimeout(() => {
|
||||||
|
if (!showSlowNotification) setShowSlowNotification(true);
|
||||||
|
}, 5000);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(to);
|
||||||
|
};
|
||||||
|
}, [showSlowNotification]);
|
||||||
|
return (
|
||||||
|
<Splash>
|
||||||
|
<div className="border border-transparent m-10 mx-auto w-4/5 max-w-3xl rounded-lg overflow-hidden">
|
||||||
|
<div className="mt-11 p-4 text-left text-sm">
|
||||||
|
<Loader />
|
||||||
|
{showSlowNotification && (
|
||||||
|
<>
|
||||||
|
<p className="mt-4 text-center">
|
||||||
|
{t(
|
||||||
|
"It looks like you're connection is slow, try switching to another node."
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<div className="mt-4 text-center">
|
||||||
|
<Button
|
||||||
|
className="border-2"
|
||||||
|
onClick={() => setNodeSwitcher(true)}
|
||||||
|
>
|
||||||
|
{t('Change node')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Splash>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
export const Bootstrapper = ({ children }: { children: ReactNode }) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const { error, VEGA_URL } = useEnvironment();
|
|
||||||
|
const { error, VEGA_URL } = useEnvironment((state) => ({
|
||||||
|
error: state.error,
|
||||||
|
VEGA_URL: state.VEGA_URL,
|
||||||
|
}));
|
||||||
const config = useVegaWalletConfig();
|
const config = useVegaWalletConfig();
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return <AppLoader />;
|
return <AppLoader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ERR_DATA_LOADER = (
|
||||||
|
<Trans
|
||||||
|
i18nKey="It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
|
||||||
|
components={[
|
||||||
|
<span key="vega" className="text-muted">
|
||||||
|
{VEGA_URL}
|
||||||
|
</span>,
|
||||||
|
]}
|
||||||
|
values={{
|
||||||
|
VEGA_URL,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NetworkLoader
|
<NetworkLoader
|
||||||
cache={cacheConfig}
|
cache={cacheConfig}
|
||||||
skeleton={<AppLoader />}
|
skeleton={<Loading />}
|
||||||
failure={
|
failure={<Failure reason={error} />}
|
||||||
<AppFailure title={t('Could not initialize app')} error={error} />
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<NodeGuard
|
<DataLoader
|
||||||
skeleton={<AppLoader />}
|
skeleton={<Loading />}
|
||||||
failure={
|
failure={<Failure reason={ERR_DATA_LOADER} />}
|
||||||
<NodeFailure
|
|
||||||
title={t('Node: {{VEGA_URL}} is unsuitable', { VEGA_URL })}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<DataLoader
|
<Web3Provider
|
||||||
skeleton={<AppLoader />}
|
skeleton={<Loading />}
|
||||||
failure={
|
failure={<Failure reason={t('Could not configure web3 provider')} />}
|
||||||
<AppFailure
|
|
||||||
title={t('Could not load market data or asset data')}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Web3Provider
|
<WalletProvider config={config}>{children}</WalletProvider>
|
||||||
skeleton={<AppLoader />}
|
</Web3Provider>
|
||||||
failure={
|
</DataLoader>
|
||||||
<AppFailure title={t('Could not configure web3 provider')} />
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<WalletProvider config={config}>{children}</WalletProvider>
|
|
||||||
</Web3Provider>
|
|
||||||
</DataLoader>
|
|
||||||
</NodeGuard>
|
|
||||||
</NetworkLoader>
|
</NetworkLoader>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import { Splash } from '@vegaprotocol/ui-toolkit';
|
|
||||||
|
|
||||||
export const AppFailure = ({
|
|
||||||
title,
|
|
||||||
error,
|
|
||||||
}: {
|
|
||||||
title: string;
|
|
||||||
error?: string | null;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Splash>
|
|
||||||
<p className="mb-4 text-xl">{title}</p>
|
|
||||||
{error && <p className="mb-8 text-sm">{error}</p>}
|
|
||||||
</Splash>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
export * from './app-failure';
|
|
@ -1,4 +1,3 @@
|
|||||||
export * from './app-failure';
|
|
||||||
export * from './app-loader';
|
export * from './app-loader';
|
||||||
export * from './network-loader';
|
export * from './network-loader';
|
||||||
export * from './network-switcher';
|
export * from './network-switcher';
|
||||||
|
@ -40,6 +40,16 @@ const mockStatsQuery = (
|
|||||||
vegaTime: new Date().toISOString(),
|
vegaTime: new Date().toISOString(),
|
||||||
chainId: 'test-chain-id',
|
chainId: 'test-chain-id',
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'a',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -335,6 +345,16 @@ describe('RowData', () => {
|
|||||||
vegaTime: new Date().toISOString(),
|
vegaTime: new Date().toISOString(),
|
||||||
chainId: 'test-chain-id',
|
chainId: 'test-chain-id',
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'a',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import { TradingRadio } from '@vegaprotocol/ui-toolkit';
|
import {
|
||||||
|
CopyWithTooltip,
|
||||||
|
TradingRadio,
|
||||||
|
VegaIcon,
|
||||||
|
VegaIconNames,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { CUSTOM_NODE_KEY } from '../../types';
|
import { CUSTOM_NODE_KEY } from '../../types';
|
||||||
import {
|
import {
|
||||||
@ -127,8 +132,17 @@ export const RowData = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{id !== CUSTOM_NODE_KEY && (
|
{id !== CUSTOM_NODE_KEY && (
|
||||||
<div className="break-all" data-testid="node">
|
<div className="break-all flex gap-2" data-testid="node">
|
||||||
<TradingRadio id={`node-url-${id}`} value={url} label={url} />
|
<TradingRadio id={`node-url-${id}`} value={url} label={url} />
|
||||||
|
{url.length > 0 && url !== 'custom' && (
|
||||||
|
<span className="text-muted">
|
||||||
|
<CopyWithTooltip text={url}>
|
||||||
|
<button>
|
||||||
|
<VegaIcon name={VegaIconNames.COPY} />
|
||||||
|
</button>
|
||||||
|
</CopyWithTooltip>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<LayoutCell
|
<LayoutCell
|
||||||
|
@ -39,6 +39,19 @@ export const getMockStatisticsResult = (
|
|||||||
blockHeight: '11',
|
blockHeight: '11',
|
||||||
vegaTime: new Date().toISOString(),
|
vegaTime: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
__typename: 'NetworkParametersConnection',
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'NetworkParameterEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'NetworkParameter',
|
||||||
|
key: 'a',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getMockQueryResult = (env: Networks): NodeCheckQuery => ({
|
export const getMockQueryResult = (env: Networks): NodeCheckQuery => ({
|
||||||
@ -48,6 +61,19 @@ export const getMockQueryResult = (env: Networks): NodeCheckQuery => ({
|
|||||||
blockHeight: '11',
|
blockHeight: '11',
|
||||||
vegaTime: new Date().toISOString(),
|
vegaTime: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
__typename: 'NetworkParametersConnection',
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'NetworkParameterEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'NetworkParameter',
|
||||||
|
key: 'a',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function getHandler<T>(
|
function getHandler<T>(
|
||||||
|
@ -34,6 +34,16 @@ const createDefaultMockClient = () => {
|
|||||||
blockHeight: '100',
|
blockHeight: '100',
|
||||||
vegaTime: new Date().toISOString(),
|
vegaTime: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'something',
|
||||||
|
value: 123,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
subscribe: () => ({
|
subscribe: () => ({
|
||||||
@ -183,6 +193,16 @@ describe('useEnvironment', () => {
|
|||||||
blockHeight: '100',
|
blockHeight: '100',
|
||||||
vegaTime: new Date(1).toISOString(),
|
vegaTime: new Date(1).toISOString(),
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'something',
|
||||||
|
value: 123,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, wait);
|
}, wait);
|
||||||
@ -244,6 +264,16 @@ describe('useEnvironment', () => {
|
|||||||
blockHeight: '100',
|
blockHeight: '100',
|
||||||
vegaTime: new Date().toISOString(),
|
vegaTime: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'something',
|
||||||
|
value: 123,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
subscribe: () => ({
|
subscribe: () => ({
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { parse as tomlParse } from 'toml';
|
import { parse as tomlParse } from 'toml';
|
||||||
import { isValidUrl, LocalStorage } from '@vegaprotocol/utils';
|
import { LocalStorage, isValidUrl } from '@vegaprotocol/utils';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { createClient } from '@vegaprotocol/apollo-client';
|
import { createClient } from '@vegaprotocol/apollo-client';
|
||||||
@ -22,6 +22,7 @@ import uniq from 'lodash/uniq';
|
|||||||
import orderBy from 'lodash/orderBy';
|
import orderBy from 'lodash/orderBy';
|
||||||
import first from 'lodash/first';
|
import first from 'lodash/first';
|
||||||
import { canMeasureResponseTime, measureResponseTime } from '../utils/time';
|
import { canMeasureResponseTime, measureResponseTime } from '../utils/time';
|
||||||
|
import compact from 'lodash/compact';
|
||||||
|
|
||||||
type Client = ReturnType<typeof createClient>;
|
type Client = ReturnType<typeof createClient>;
|
||||||
type ClientCollection = {
|
type ClientCollection = {
|
||||||
@ -70,10 +71,19 @@ const fetchConfig = async (url?: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a suitable node by running a test query and test
|
* Find a suitable nodes by running a test query and test
|
||||||
* subscription, against a list of clients, first to resolve wins
|
* subscription, against a list of clients, first to resolve wins
|
||||||
*/
|
*/
|
||||||
const findNode = async (clients: ClientCollection): Promise<string | null> => {
|
const findHealthyNodes = async (nodes: string[]) => {
|
||||||
|
const clients: ClientCollection = {};
|
||||||
|
nodes.forEach((url) => {
|
||||||
|
clients[url] = createClient({
|
||||||
|
url,
|
||||||
|
cacheConfig: undefined,
|
||||||
|
retry: false,
|
||||||
|
connectToDevTools: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
const tests = Object.entries(clients).map((args) => testNode(...args));
|
const tests = Object.entries(clients).map((args) => testNode(...args));
|
||||||
try {
|
try {
|
||||||
const nodes = await Promise.all(tests);
|
const nodes = await Promise.all(tests);
|
||||||
@ -93,11 +103,10 @@ const findNode = async (clients: ClientCollection): Promise<string | null> => {
|
|||||||
['desc', 'desc', 'asc']
|
['desc', 'desc', 'asc']
|
||||||
);
|
);
|
||||||
|
|
||||||
const best = first(ordered);
|
return ordered;
|
||||||
return best ? best.url : null;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// All tests rejected, no suitable node found
|
// All tests rejected, no suitable node found
|
||||||
return null;
|
return [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -142,6 +151,15 @@ const testQuery = (
|
|||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result && !result.error) {
|
if (result && !result.error) {
|
||||||
|
const netParams = compact(
|
||||||
|
result.data.networkParametersConnection.edges?.map((n) => n?.node)
|
||||||
|
);
|
||||||
|
if (netParams.length === 0) {
|
||||||
|
// any node that doesn't return the network parameters is considered
|
||||||
|
// failed
|
||||||
|
resolve(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const res = {
|
const res = {
|
||||||
blockHeight: Number(result.data.statistics.blockHeight),
|
blockHeight: Number(result.data.statistics.blockHeight),
|
||||||
vegaTime: new Date(result.data.statistics.vegaTime),
|
vegaTime: new Date(result.data.statistics.vegaTime),
|
||||||
@ -600,32 +618,34 @@ export const useEnvironment = create<EnvStore>()((set, get) => ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const state = get();
|
const state = get();
|
||||||
const storedUrl = LocalStorage.getItem(STORAGE_KEY);
|
|
||||||
|
let storedUrl = LocalStorage.getItem(STORAGE_KEY);
|
||||||
|
if (!isValidUrl(storedUrl)) {
|
||||||
|
// remove invalid data from local storage
|
||||||
|
LocalStorage.removeItem(STORAGE_KEY);
|
||||||
|
storedUrl = null;
|
||||||
|
}
|
||||||
|
|
||||||
let nodes: string[] | undefined;
|
let nodes: string[] | undefined;
|
||||||
try {
|
try {
|
||||||
nodes = await fetchConfig(state.VEGA_CONFIG_URL);
|
nodes = uniq(
|
||||||
const enrichedNodes = uniq(
|
compact([
|
||||||
[...nodes, state.VEGA_URL, storedUrl].filter(Boolean) as string[]
|
// url from local storage
|
||||||
|
storedUrl,
|
||||||
|
// url from state (if set via env var)
|
||||||
|
state.VEGA_URL,
|
||||||
|
// urls from network configuration
|
||||||
|
...(await fetchConfig(state.VEGA_CONFIG_URL)),
|
||||||
|
])
|
||||||
);
|
);
|
||||||
set({ nodes: enrichedNodes });
|
set({ nodes });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn(`Could not fetch node config from ${state.VEGA_CONFIG_URL}`);
|
console.warn(`Could not fetch node config from ${state.VEGA_CONFIG_URL}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node url found in localStorage, if its valid attempt to connect
|
// skip picking up the best node if VEGA_URL env variable is set
|
||||||
if (storedUrl) {
|
if (state.VEGA_URL && isValidUrl(state.VEGA_URL)) {
|
||||||
if (isValidUrl(storedUrl)) {
|
state.setUrl(state.VEGA_URL);
|
||||||
set({ VEGA_URL: storedUrl, status: 'success' });
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
LocalStorage.removeItem(STORAGE_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VEGA_URL env var is set and is a valid url no need to proceed
|
|
||||||
if (state.VEGA_URL) {
|
|
||||||
set({ status: 'success' });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,37 +659,35 @@ export const useEnvironment = create<EnvStore>()((set, get) => ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a map of node urls to client instances
|
const healthyNodes = await findHealthyNodes(nodes);
|
||||||
const clients: ClientCollection = {};
|
|
||||||
nodes.forEach((url) => {
|
// A requested node is a node to which the app was previously connected
|
||||||
clients[url] = createClient({
|
// or the one set via env variable.
|
||||||
url,
|
const requestedNodeUrl = storedUrl || state.VEGA_URL;
|
||||||
cacheConfig: undefined,
|
|
||||||
retry: false,
|
const bestNode = first(healthyNodes);
|
||||||
connectToDevTools: false,
|
const requestedNode = healthyNodes.find(
|
||||||
});
|
(n) => requestedNodeUrl && n.url === requestedNodeUrl
|
||||||
|
);
|
||||||
|
if (!requestedNode) {
|
||||||
|
// remove unhealthy node url from local storage
|
||||||
|
LocalStorage.removeItem(STORAGE_KEY);
|
||||||
|
}
|
||||||
|
// A node's url (VEGA_URL) is either the requested node (previously
|
||||||
|
// connected or taken form env variable) or the currently best available
|
||||||
|
// node.
|
||||||
|
const url = requestedNode?.url || bestNode?.url;
|
||||||
|
|
||||||
|
if (url != null) {
|
||||||
|
state.setUrl(url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set({
|
||||||
|
status: 'failed',
|
||||||
|
error: 'No suitable node found',
|
||||||
});
|
});
|
||||||
|
console.warn('No suitable node was found');
|
||||||
// Find a suitable node to connect to by attempting a query and a
|
|
||||||
// subscription, first to fulfill both will be the resulting url.
|
|
||||||
const url = await findNode(clients);
|
|
||||||
|
|
||||||
if (url !== null) {
|
|
||||||
set({
|
|
||||||
status: 'success',
|
|
||||||
VEGA_URL: url,
|
|
||||||
});
|
|
||||||
LocalStorage.setItem(STORAGE_KEY, url);
|
|
||||||
}
|
|
||||||
// Every node failed either to make a query or retrieve data from
|
|
||||||
// a subscription
|
|
||||||
else {
|
|
||||||
set({
|
|
||||||
status: 'failed',
|
|
||||||
error: 'No node found',
|
|
||||||
});
|
|
||||||
console.warn('No suitable vega node was found');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -28,6 +28,16 @@ const createStatsMock = (
|
|||||||
blockHeight: blockHeight.toString(),
|
blockHeight: blockHeight.toString(),
|
||||||
vegaTime: '12345',
|
vegaTime: '12345',
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
key: 'a',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
query NodeCheck {
|
query NodeCheck {
|
||||||
|
# statistics needed to get the most recent node in terms of block height
|
||||||
statistics {
|
statistics {
|
||||||
chainId
|
chainId
|
||||||
blockHeight
|
blockHeight
|
||||||
vegaTime
|
vegaTime
|
||||||
}
|
}
|
||||||
|
# net params needed to filter out the nodes that are not suitable
|
||||||
|
networkParametersConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subscription NodeCheckTimeUpdate {
|
subscription NodeCheckTimeUpdate {
|
||||||
|
@ -6,7 +6,7 @@ const defaultOptions = {} as const;
|
|||||||
export type NodeCheckQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
export type NodeCheckQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type NodeCheckQuery = { __typename?: 'Query', statistics: { __typename?: 'Statistics', chainId: string, blockHeight: string, vegaTime: any } };
|
export type NodeCheckQuery = { __typename?: 'Query', statistics: { __typename?: 'Statistics', chainId: string, blockHeight: string, vegaTime: any }, networkParametersConnection: { __typename?: 'NetworkParametersConnection', edges?: Array<{ __typename?: 'NetworkParameterEdge', node: { __typename?: 'NetworkParameter', key: string, value: string } } | null> | null } };
|
||||||
|
|
||||||
export type NodeCheckTimeUpdateSubscriptionVariables = Types.Exact<{ [key: string]: never; }>;
|
export type NodeCheckTimeUpdateSubscriptionVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@ -21,6 +21,14 @@ export const NodeCheckDocument = gql`
|
|||||||
blockHeight
|
blockHeight
|
||||||
vegaTime
|
vegaTime
|
||||||
}
|
}
|
||||||
|
networkParametersConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -12,6 +12,19 @@ export const statisticsQuery = (
|
|||||||
blockHeight: '11',
|
blockHeight: '11',
|
||||||
vegaTime: new Date().toISOString(),
|
vegaTime: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
|
networkParametersConnection: {
|
||||||
|
__typename: 'NetworkParametersConnection',
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'NetworkParameterEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'NetworkParameter',
|
||||||
|
key: 'a',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return merge(defaultResult, override);
|
return merge(defaultResult, override);
|
||||||
|
@ -485,5 +485,7 @@
|
|||||||
"See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.": "See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.",
|
"See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.": "See all the live games on the cards below. Every on-chain game is community funded and designed. <0>Find out how to create one</0>.",
|
||||||
"Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.": "Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.",
|
"Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.": "Teams can earn rewards if they meet the goals set in the on-chain trading competitions. Track your earned rewards here, and see which teams are top of the leaderboard this month.",
|
||||||
"Currently no active games on the network.": "Currently no active games on the network.",
|
"Currently no active games on the network.": "Currently no active games on the network.",
|
||||||
"Currently no active teams on the network.": "Currently no active teams on the network."
|
"Currently no active teams on the network.": "Currently no active teams on the network.",
|
||||||
|
"It looks like you're connection is slow, try switching to another node.": "It looks like you're connection is slow, try switching to another node.",
|
||||||
|
"It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node.": "It appears that the connection to the node <0>{{VEGA_URL}}</0> does not return necessary data, try switching to another node."
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export const isValidUrl = (url?: string) => {
|
export const isValidUrl = (url?: string | null) => {
|
||||||
if (!url) return false;
|
if (!url) return false;
|
||||||
try {
|
try {
|
||||||
new URL(url);
|
new URL(url);
|
||||||
|
Loading…
Reference in New Issue
Block a user