-
-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generalize polling abstraction #3636
Merged
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
5064689
PollingController: add option to poll by blockTracker
adonesky1 394fcdd
fix
adonesky1 242252b
adding tests
adonesky1 4a74704
another test + cleanup
adonesky1 6698ebd
add protection against multiple sources of polling interval
adonesky1 8906fb8
cleanup
adonesky1 8edcf25
small cleanups
adonesky1 f688425
move tests
adonesky1 f72c570
reorganize new tests
adonesky1 28a98fe
WIP
adonesky1 1c297c2
moving toward pure template pattern
adonesky1 9f0efe9
wip template pattern complete for BlockTrackerPollingController, now …
adonesky1 6404305
StaticIntervalPollingController wip
adonesky1 d4992ff
trying a different PollingTokenSetId type
adonesky1 4b52a02
change all instances over to new class
adonesky1 b932365
cleanup
adonesky1 76449d6
cleanup
adonesky1 5ccf0d3
break when pollingToken found whether or not its the last
adonesky1 997c806
add IPollingController type
adonesky1 ac31ea0
Merge branch 'main' into generalize-polling-abstraction
adonesky1 781c967
Merge branch 'main' into generalize-polling-abstraction
adonesky1 823aaa1
address feedback + cleanup
adonesky1 d7e9ba2
Merge branch 'main' into generalize-polling-abstraction
adonesky1 8a684fb
Merge branch 'main' into generalize-polling-abstraction
adonesky1 071f73b
use StaticIntervalPollingController for PendingUserOperationTracker
adonesky1 8d5ff1e
Merge branch 'main' into generalize-polling-abstraction
adonesky1 d4ce6ac
Merge branch 'main' into generalize-polling-abstraction
adonesky1 77f3d2e
update AccountTrackerController to use StaticIntervalPollingControllerV1
adonesky1 34234c6
Merge branch 'main' into generalize-polling-abstraction
adonesky1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
138 changes: 138 additions & 0 deletions
138
packages/polling-controller/src/AbstractPollingController.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import type { NetworkClientId } from '@metamask/network-controller'; | ||
import type { Json } from '@metamask/utils'; | ||
import stringify from 'fast-json-stable-stringify'; | ||
import { v4 as random } from 'uuid'; | ||
|
||
export type IPollingController = { | ||
startPollingByNetworkClientId( | ||
networkClientId: NetworkClientId, | ||
options: Json, | ||
): string; | ||
|
||
stopAllPolling(): void; | ||
|
||
stopPollingByPollingToken(pollingToken: string): void; | ||
|
||
onPollingCompleteByNetworkClientId( | ||
networkClientId: NetworkClientId, | ||
callback: (networkClientId: NetworkClientId) => void, | ||
options: Json, | ||
): void; | ||
|
||
_executePoll(networkClientId: NetworkClientId, options: Json): Promise<void>; | ||
_startPollingByNetworkClientId( | ||
networkClientId: NetworkClientId, | ||
options: Json, | ||
): void; | ||
_stopPollingByPollingTokenSetId(key: PollingTokenSetId): void; | ||
}; | ||
|
||
export const getKey = ( | ||
networkClientId: NetworkClientId, | ||
options: Json, | ||
): PollingTokenSetId => `${networkClientId}:${stringify(options)}`; | ||
|
||
export type PollingTokenSetId = `${NetworkClientId}:${string}`; | ||
|
||
type Constructor = new (...args: any[]) => object; | ||
|
||
/** | ||
* AbstractPollingControllerBaseMixin | ||
* | ||
* @param Base - The base class to mix onto. | ||
* @returns The composed class. | ||
*/ | ||
export function AbstractPollingControllerBaseMixin<TBase extends Constructor>( | ||
Base: TBase, | ||
) { | ||
abstract class AbstractPollingControllerBase | ||
extends Base | ||
implements IPollingController | ||
{ | ||
readonly #pollingTokenSets: Map<PollingTokenSetId, Set<string>> = new Map(); | ||
|
||
#callbacks: Map< | ||
PollingTokenSetId, | ||
Set<(PollingTokenSetId: PollingTokenSetId) => void> | ||
> = new Map(); | ||
|
||
abstract _executePoll( | ||
networkClientId: NetworkClientId, | ||
options: Json, | ||
): Promise<void>; | ||
|
||
abstract _startPollingByNetworkClientId( | ||
networkClientId: NetworkClientId, | ||
options: Json, | ||
): void; | ||
|
||
abstract _stopPollingByPollingTokenSetId(key: PollingTokenSetId): void; | ||
|
||
startPollingByNetworkClientId( | ||
networkClientId: NetworkClientId, | ||
options: Json = {}, | ||
): string { | ||
const pollToken = random(); | ||
const key = getKey(networkClientId, options); | ||
const pollingTokenSet = | ||
this.#pollingTokenSets.get(key) ?? new Set<string>(); | ||
pollingTokenSet.add(pollToken); | ||
this.#pollingTokenSets.set(key, pollingTokenSet); | ||
|
||
if (pollingTokenSet.size === 1) { | ||
this._startPollingByNetworkClientId(networkClientId, options); | ||
} | ||
|
||
return pollToken; | ||
} | ||
|
||
stopAllPolling() { | ||
this.#pollingTokenSets.forEach((tokenSet, _key) => { | ||
tokenSet.forEach((token) => { | ||
this.stopPollingByPollingToken(token); | ||
}); | ||
}); | ||
} | ||
|
||
stopPollingByPollingToken(pollingToken: string) { | ||
if (!pollingToken) { | ||
throw new Error('pollingToken required'); | ||
} | ||
|
||
let keyToDelete: PollingTokenSetId | null = null; | ||
for (const [key, tokenSet] of this.#pollingTokenSets) { | ||
if (tokenSet.delete(pollingToken)) { | ||
if (tokenSet.size === 0) { | ||
keyToDelete = key; | ||
} | ||
break; | ||
} | ||
} | ||
|
||
if (keyToDelete) { | ||
this._stopPollingByPollingTokenSetId(keyToDelete); | ||
this.#pollingTokenSets.delete(keyToDelete); | ||
const callbacks = this.#callbacks.get(keyToDelete); | ||
if (callbacks) { | ||
for (const callback of callbacks) { | ||
// eslint-disable-next-line n/callback-return | ||
callback(keyToDelete); | ||
} | ||
callbacks.clear(); | ||
} | ||
} | ||
} | ||
|
||
onPollingCompleteByNetworkClientId( | ||
networkClientId: NetworkClientId, | ||
callback: (networkClientId: NetworkClientId) => void, | ||
options: Json = {}, | ||
) { | ||
const key = getKey(networkClientId, options); | ||
const callbacks = this.#callbacks.get(key) ?? new Set<typeof callback>(); | ||
callbacks.add(callback); | ||
this.#callbacks.set(key, callbacks); | ||
} | ||
} | ||
return AbstractPollingControllerBase; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are your thoughts on making this
protected
? This way we don't have to prepend it with an underscore. Same goes for_stopPollingByPollingTokenSetId
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mixin pattern where we expose this class via function doesn't seem to like any private or protected methods in the exposed class...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like maybe there are ways to get around it but I'm not sure if we want to pursue them if its not recommended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, strange. Okay, no problem, then.