websocket, polling rate, and component updates
This commit is contained in:
parent
c79765dd33
commit
c5d8fef7d6
|
@ -75,10 +75,10 @@ export default function TradeForm({ style, setChangeOrderRef }) {
|
|||
setChangeOrderRef && setChangeOrderRef(doChangeOrder);
|
||||
}, [setChangeOrderRef]);
|
||||
|
||||
useEffect(() => {
|
||||
sizeFraction && onSliderChange(sizeFraction);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [side, sizeFraction]);
|
||||
// useEffect(() => {
|
||||
// sizeFraction && onSliderChange(sizeFraction);
|
||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// }, [side, sizeFraction]);
|
||||
|
||||
const doChangeOrder = ({ size, price }) => {
|
||||
size && setSize(size);
|
||||
|
@ -203,12 +203,12 @@ export default function TradeForm({ style, setChangeOrderRef }) {
|
|||
step={market?.minOrderSize || 1}
|
||||
onChange={(e) => setSize(e.target.value)}
|
||||
/>
|
||||
<Slider
|
||||
value={sizeFraction}
|
||||
tipFormatter={(value) => `${value}%`}
|
||||
marks={sliderMarks}
|
||||
onChange={onSliderChange}
|
||||
/>
|
||||
{/*<Slider*/}
|
||||
{/* value={sizeFraction}*/}
|
||||
{/* tipFormatter={(value) => `${value}%`}*/}
|
||||
{/* marks={sliderMarks}*/}
|
||||
{/* onChange={onSliderChange}*/}
|
||||
{/*/>*/}
|
||||
<div style={{ paddingTop: 18 }}>
|
||||
{'POST '}
|
||||
<Switch
|
||||
|
|
|
@ -34,30 +34,30 @@ export function ConnectionProvider({ children }) {
|
|||
// The websocket library solana/web3.js uses closes its websocket connection when the subscription list
|
||||
// is empty after opening its first time, preventing subsequent subscriptions from receiving responses.
|
||||
// This is a hack to prevent the list from every getting empty
|
||||
useEffect(() => {
|
||||
const id = connection.onSignature(
|
||||
'do not worry, this is expected to yield warning logs',
|
||||
(result) => {
|
||||
console.log(
|
||||
'Received onSignature responses from does-not-exist',
|
||||
result,
|
||||
);
|
||||
},
|
||||
);
|
||||
return () => connection.removeSignatureListener(id);
|
||||
}, [connection]);
|
||||
useEffect(() => {
|
||||
const id = sendConnection.onSignature(
|
||||
'do not worry, this is expected to yield warning logs',
|
||||
(result) => {
|
||||
console.log(
|
||||
'Received onSignature responses from does-not-exist',
|
||||
result,
|
||||
);
|
||||
},
|
||||
);
|
||||
return () => sendConnection.removeSignatureListener(id);
|
||||
}, [sendConnection]);
|
||||
// useEffect(() => {
|
||||
// const id = connection.onSignature(
|
||||
// 'do not worry, this is expected to yield warning logs',
|
||||
// (result) => {
|
||||
// console.log(
|
||||
// 'Received onSignature responses from does-not-exist',
|
||||
// result,
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// return () => connection.removeSignatureListener(id);
|
||||
// }, [connection]);
|
||||
// useEffect(() => {
|
||||
// const id = sendConnection.onSignature(
|
||||
// 'do not worry, this is expected to yield warning logs',
|
||||
// (result) => {
|
||||
// console.log(
|
||||
// 'Received onSignature responses from does-not-exist',
|
||||
// result,
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
// return () => sendConnection.removeSignatureListener(id);
|
||||
// }, [sendConnection]);
|
||||
|
||||
return (
|
||||
<ConnectionContext.Provider
|
||||
|
@ -89,37 +89,52 @@ export function useAccountInfo(publicKey) {
|
|||
cacheKey,
|
||||
{ refreshInterval: 60000000 },
|
||||
);
|
||||
let id = publicKey?.toBase58();
|
||||
useEffect(() => {
|
||||
if (!publicKey) {
|
||||
return () => {};
|
||||
}
|
||||
if (accountListenerCount.has(cacheKey)) {
|
||||
let currentCount = accountListenerCount.get(cacheKey);
|
||||
accountListenerCount.set(cacheKey, currentCount + 1);
|
||||
return () => {};
|
||||
}
|
||||
let previousData = null;
|
||||
const id = connection.onAccountChange(publicKey, (e) => {
|
||||
if (e.data) {
|
||||
if (!previousData || !previousData.equals(e.data)) {
|
||||
setCache(cacheKey, e);
|
||||
let currentItem = accountListenerCount.get(cacheKey);
|
||||
console.log('Incrementing', id, currentItem.count + 1);
|
||||
accountListenerCount.set(cacheKey, {
|
||||
count: currentItem.count + 1,
|
||||
subscriptionId: currentItem.subscriptionId,
|
||||
});
|
||||
} else {
|
||||
let previousData = null;
|
||||
console.log('Subscribing to ', id);
|
||||
const subscriptionId = connection.onAccountChange(publicKey, (e) => {
|
||||
if (e.data) {
|
||||
if (!previousData || !previousData.equals(e.data)) {
|
||||
console.log('Passing along new data', id);
|
||||
setCache(cacheKey, e);
|
||||
} else {
|
||||
console.log('Skipping no-op update', id);
|
||||
}
|
||||
previousData = e.data;
|
||||
}
|
||||
previousData = e.data;
|
||||
}
|
||||
});
|
||||
accountListenerCount.set(cacheKey, 1);
|
||||
});
|
||||
console.log('Setting cache', id);
|
||||
accountListenerCount.set(cacheKey, { count: 1, subscriptionId });
|
||||
}
|
||||
return () => {
|
||||
let currentCount = accountListenerCount.get(cacheKey);
|
||||
if (currentCount === 1) {
|
||||
// last listener, safe to unsubscribe
|
||||
connection.removeAccountChangeListener(id);
|
||||
let currentItem = accountListenerCount.get(cacheKey);
|
||||
let nextCount = currentItem.count - 1;
|
||||
if (nextCount <= 0) {
|
||||
console.log('Removing cache', id);
|
||||
connection.removeAccountChangeListener(currentItem.subscriptionId);
|
||||
accountListenerCount.delete(cacheKey);
|
||||
} else {
|
||||
accountListenerCount.set(cacheKey, currentCount - 1);
|
||||
console.log('Decrementing', id, nextCount);
|
||||
accountListenerCount.set(cacheKey, {
|
||||
count: nextCount,
|
||||
subscriptionId: currentItem.subscriptionId,
|
||||
});
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [connection, publicKey?.toBase58(), cacheKey]);
|
||||
}, [cacheKey]);
|
||||
return [accountInfo, loaded];
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,11 @@ const pageLoadTime = new Date();
|
|||
const globalCache = new Map();
|
||||
|
||||
class FetchLoopListener {
|
||||
constructor(cacheKey, fn, refreshInterval, callback) {
|
||||
constructor(cacheKey, fn, refreshInterval, refreshIntervalOnError, callback) {
|
||||
this.cacheKey = cacheKey;
|
||||
this.fn = fn;
|
||||
this.refreshInterval = refreshInterval;
|
||||
this.refreshIntervalOnError = refreshIntervalOnError;
|
||||
this.callback = callback;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +31,14 @@ class FetchLoopInternal {
|
|||
);
|
||||
}
|
||||
|
||||
get refreshIntervalOnError() {
|
||||
return Math.min(
|
||||
...[...this.listeners]
|
||||
.map((listener) => listener.refreshIntervalOnError)
|
||||
.filter((x) => x),
|
||||
);
|
||||
}
|
||||
|
||||
get stopped() {
|
||||
return this.listeners.size === 0;
|
||||
}
|
||||
|
@ -65,6 +74,7 @@ class FetchLoopInternal {
|
|||
return;
|
||||
}
|
||||
|
||||
let errored = false;
|
||||
try {
|
||||
const data = await this.fn();
|
||||
globalCache.set(this.cacheKey, data);
|
||||
|
@ -74,9 +84,17 @@ class FetchLoopInternal {
|
|||
} catch (error) {
|
||||
++this.errors;
|
||||
console.warn(error);
|
||||
errored = true;
|
||||
} finally {
|
||||
if (!this.timeoutId && !this.stopped) {
|
||||
let waitTime = this.refreshInterval;
|
||||
if (
|
||||
errored &&
|
||||
this.refreshIntervalOnError &&
|
||||
this.refreshIntervalOnError > 0
|
||||
) {
|
||||
waitTime = this.refreshIntervalOnError;
|
||||
}
|
||||
|
||||
// Back off on errors.
|
||||
if (this.errors > 0) {
|
||||
|
@ -141,7 +159,7 @@ const globalLoops = new FetchLoops();
|
|||
export function useAsyncData(
|
||||
asyncFn,
|
||||
cacheKey,
|
||||
{ refreshInterval = 60000 } = {},
|
||||
{ refreshInterval = 60000, refreshIntervalOnError = null } = {},
|
||||
) {
|
||||
const [, rerender] = useReducer((i) => i + 1, 0);
|
||||
|
||||
|
@ -154,6 +172,7 @@ export function useAsyncData(
|
|||
cacheKey,
|
||||
asyncFn,
|
||||
refreshInterval,
|
||||
refreshIntervalOnError,
|
||||
rerender,
|
||||
);
|
||||
globalLoops.addListener(listener);
|
||||
|
|
|
@ -131,12 +131,12 @@ export function useAllMarkets() {
|
|||
const MarketContext = React.createContext(null);
|
||||
|
||||
// For things that don't really change
|
||||
const _SLOW_REFRESH_INTERVAL = 1000 * 1000;
|
||||
const _SLOW_REFRESH_INTERVAL = 5 * 1000;
|
||||
|
||||
// For things that change frequently
|
||||
const _FAST_REFRESH_INTERVAL = 5 * 1000;
|
||||
const _FAST_REFRESH_INTERVAL = 1000;
|
||||
|
||||
const _MEDIUM_REFRESH_INTERVAL = 5 * 1000;
|
||||
const _MEDIUM_REFRESH_INTERVAL = 3 * 1000;
|
||||
|
||||
export function MarketProvider({ children }) {
|
||||
const [marketName, setMarketName] = useLocalStorageState(
|
||||
|
@ -601,9 +601,12 @@ export function useBalances() {
|
|||
openOrdersAccount &&
|
||||
openOrdersAccount.quoteTokenTotal &&
|
||||
openOrdersAccount.quoteTokenFree;
|
||||
if (baseCurrency === 'UNKNOWN' || quoteCurrency === 'UNKNOWN') {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
key: baseCurrency,
|
||||
key: `${baseCurrency}${quoteCurrency}${baseCurrency}`,
|
||||
coin: baseCurrency,
|
||||
wallet: baseCurrencyBalances,
|
||||
orders:
|
||||
|
@ -620,7 +623,7 @@ export function useBalances() {
|
|||
: null,
|
||||
},
|
||||
{
|
||||
key: quoteCurrency,
|
||||
key: `${quoteCurrency}${baseCurrency}${quoteCurrency}`,
|
||||
coin: quoteCurrency,
|
||||
wallet: quoteCurrencyBalances,
|
||||
orders:
|
||||
|
|
|
@ -19,7 +19,17 @@ export async function settleFunds({
|
|||
!baseCurrencyAccount ||
|
||||
!quoteCurrencyAccount
|
||||
) {
|
||||
notify({ message: 'Not connected' });
|
||||
if (
|
||||
(baseCurrencyAccount && !quoteCurrencyAccount) ||
|
||||
(quoteCurrencyAccount && !baseCurrencyAccount)
|
||||
) {
|
||||
notify({
|
||||
message: 'Add token account',
|
||||
description: 'Add accounts for both currencies on sollet.io',
|
||||
});
|
||||
} else {
|
||||
notify({ message: 'Not connected' });
|
||||
}
|
||||
return;
|
||||
}
|
||||
const transaction = await market.makeSettleFundsTransaction(
|
||||
|
|
Loading…
Reference in New Issue