Skip to content

Commit

Permalink
feat: Init polling controller updates
Browse files Browse the repository at this point in the history
  • Loading branch information
gambinish committed Oct 31, 2024
1 parent 955196c commit 3831038
Showing 1 changed file with 17 additions and 85 deletions.
102 changes: 17 additions & 85 deletions packages/assets-controllers/src/TokenListController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import type {
} from '@metamask/base-controller';
import { safelyExecute } from '@metamask/controller-utils';
import type {
NetworkClientId,
NetworkControllerStateChangeEvent,
NetworkState,
NetworkControllerGetNetworkClientByIdAction,
} from '@metamask/network-controller';
import { StaticIntervalPollingController } from '@metamask/polling-controller';
Expand Down Expand Up @@ -94,7 +92,7 @@ export const getDefaultTokenListState = (): TokenListState => {

/** The input to start polling for the {@link TokenListController} */
type TokenListPollingInput = {
networkClientId: NetworkClientId;
chainId: Hex;
};

/**
Expand All @@ -113,36 +111,26 @@ export class TokenListController extends StaticIntervalPollingController<TokenLi

private readonly cacheRefreshThreshold: number;

private chainId: Hex;

private abortController: AbortController;
private readonly abortController: AbortController;

/**
* Creates a TokenListController instance.
*
* @param options - The controller options.
* @param options.chainId - The chain ID of the current network.
* @param options.onNetworkStateChange - A function for registering an event handler for network state changes.
* @param options.interval - The polling interval, in milliseconds.
* @param options.cacheRefreshThreshold - The token cache expiry time, in milliseconds.
* @param options.messenger - A restricted controller messenger.
* @param options.state - Initial state to set on this controller.
* @param options.preventPollingOnNetworkRestart - Determines whether to prevent poilling on network restart in extension.
*/
constructor({
chainId,
preventPollingOnNetworkRestart = false,
onNetworkStateChange,
interval = DEFAULT_INTERVAL,
cacheRefreshThreshold = DEFAULT_THRESHOLD,
messenger,
state,
}: {
chainId: Hex;
preventPollingOnNetworkRestart?: boolean;
onNetworkStateChange?: (
listener: (networkState: NetworkState) => void,
) => void;
interval?: number;
cacheRefreshThreshold?: number;
messenger: TokenListControllerMessenger;
Expand All @@ -156,75 +144,26 @@ export class TokenListController extends StaticIntervalPollingController<TokenLi
});
this.intervalDelay = interval;
this.cacheRefreshThreshold = cacheRefreshThreshold;
this.chainId = chainId;
this.updatePreventPollingOnNetworkRestart(preventPollingOnNetworkRestart);
this.abortController = new AbortController();
if (onNetworkStateChange) {
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
// eslint-disable-next-line @typescript-eslint/no-misused-promises
onNetworkStateChange(async (networkControllerState) => {
await this.#onNetworkControllerStateChange(networkControllerState);
});
} else {
this.messagingSystem.subscribe(
'NetworkController:stateChange',
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
// eslint-disable-next-line @typescript-eslint/no-misused-promises
async (networkControllerState) => {
await this.#onNetworkControllerStateChange(networkControllerState);
},
);
}
}

/**
* Updates state and restarts polling on changes to the network controller
* state.
*
* @param networkControllerState - The updated network controller state.
*/
async #onNetworkControllerStateChange(networkControllerState: NetworkState) {
const selectedNetworkClient = this.messagingSystem.call(
'NetworkController:getNetworkClientById',
networkControllerState.selectedNetworkClientId,
);
const { chainId } = selectedNetworkClient.configuration;

if (this.chainId !== chainId) {
this.abortController.abort();
this.abortController = new AbortController();
this.chainId = chainId;
if (this.state.preventPollingOnNetworkRestart) {
this.clearingTokenListData();
} else {
// Ensure tokenList is referencing data from correct network
this.update(() => {
return {
...this.state,
tokenList: this.state.tokensChainsCache[this.chainId]?.data || {},
};
});
await this.restart();
}
}
}

/**
* Start polling for the token list.
*/
async start() {
if (!isTokenListSupportedForNetwork(this.chainId)) {
if (!isTokenListSupportedForNetwork(pollingInput.chainId)) {
return;
}
await this.#startPolling();
await this.#startPolling(pollingInput.chainId);
}

/**
* Restart polling for the token list.
*/
async restart() {
this.stopPolling();
await this.#startPolling();
await this.#startPolling(pollingInput.chainId);
}

/**
Expand All @@ -251,14 +190,16 @@ export class TokenListController extends StaticIntervalPollingController<TokenLi
}

/**
* Starts a new polling interval.
* Starts a new polling interval for a given chainId
* @param input - The input for the poll.
* @param input.chainId - The chainId of the chain to trigger the fetch.
*/
async #startPolling(): Promise<void> {
await safelyExecute(() => this.fetchTokenList());
async #startPolling({ chainId }: TokenListPollingInput): Promise<void> {
await safelyExecute(() => this._executePoll({ chainId }));
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
// eslint-disable-next-line @typescript-eslint/no-misused-promises
this.intervalId = setInterval(async () => {
await safelyExecute(() => this.fetchTokenList());
await safelyExecute(() => this._executePoll({ chainId }));
}, this.intervalDelay);
}

Expand All @@ -267,30 +208,21 @@ export class TokenListController extends StaticIntervalPollingController<TokenLi
*
* @private
* @param input - The input for the poll.
* @param input.networkClientId - The ID of the network client triggering the fetch.
* @param input.chainId - The chainId of the chain to trigger the fetch.
* @returns A promise that resolves when this operation completes.
*/
async _executePoll({
networkClientId,
}: TokenListPollingInput): Promise<void> {
return this.fetchTokenList(networkClientId);
async _executePoll({ chainId }: TokenListPollingInput): Promise<void> {
return this.fetchTokenList(chainId);
}

/**
* Fetching token list from the Token Service API.
*
* @param networkClientId - The ID of the network client triggering the fetch.
* @param chainId - The chainId of the network client triggering the fetch.
*/
async fetchTokenList(networkClientId?: NetworkClientId): Promise<void> {
async fetchTokenList(chainId: Hex): Promise<void> {
const releaseLock = await this.mutex.acquire();
let networkClient;
if (networkClientId) {
networkClient = this.messagingSystem.call(
'NetworkController:getNetworkClientById',
networkClientId,
);
}
const chainId = networkClient?.configuration.chainId ?? this.chainId;

try {
const { tokensChainsCache } = this.state;
let tokenList: TokenListMap = {};
Expand Down

0 comments on commit 3831038

Please sign in to comment.