websocket, polling rate, and component updates

This commit is contained in:
Nishad 2020-08-30 19:49:45 +08:00
parent c79765dd33
commit c5d8fef7d6
5 changed files with 108 additions and 61 deletions

View File

@ -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

View File

@ -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];
}

View File

@ -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);

View File

@ -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:

View File

@ -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(