Skip to content
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

Add RateLimitController #698

Merged
merged 25 commits into from
Mar 4, 2022
Merged

Add RateLimitController #698

merged 25 commits into from
Mar 4, 2022

Conversation

FrederikBolding
Copy link
Member

@FrederikBolding FrederikBolding commented Feb 24, 2022

Added RateLimitController to dynamically and generically introduce rate limits to certain functions fx. called by Snaps.

Description

  • ADDED:
    • Added RateLimitController

Checklist

  • Tests are included if applicable
  • Any added code is fully documented

messenger,
state: { ...defaultState, ...state },
});
this.showNativeNotification = showNativeNotification;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could make this controller generic over the actions being rate limited, and pass them in as a mapping of type to implementation.

That would let us extend what is rate limited without altering the controller itself, and would decouple this controller from the things being rate limited.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@FrederikBolding FrederikBolding mentioned this pull request Feb 25, 2022
2 tasks
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
@FrederikBolding FrederikBolding marked this pull request as ready for review March 1, 2022 09:29
@FrederikBolding FrederikBolding requested a review from a team as a code owner March 1, 2022 09:29
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.test.ts Outdated Show resolved Hide resolved
Copy link
Member

@rekmarks rekmarks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring fixup.

src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
rateLimitCount?: number;
messenger: RateLimitMessenger<ApiType>;
state?: Partial<RateLimitState<ApiType>>;
implementations: Record<ApiType, (...args: unknown[]) => unknown>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem practical to use. In effect these implementations can't be used by the controller unless they happen to accept unknown or any as parameters. Try updating the unit tests to pass in a function with specific parameter types to see what I mean. Effectively this erases the types of the underlying method, so using would require lots of inconvenient casting and the loss of type safety.

When I suggested making this controller generic, what I had in mind was making it generic over the underlying implementation so their types would be preserved. We need to preserve the types for this to be practical.

I made an example of this here: https://github.com/MetaMask/controllers/tree/rate-limit-controller-types-example
Not sure if it works, and I didn't update the tests, so my apologies if it's broken. But that's generally what I was thinking originally.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gudahtt Hmm, this is a good idea, I think. I can explore this further tomorrow! Thanks!

Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions/questions.

src/ratelimit/RateLimitController.test.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.test.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Outdated Show resolved Hide resolved
src/ratelimit/RateLimitController.ts Show resolved Hide resolved
Copy link
Member

@rekmarks rekmarks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to @mcmire's outstanding feedback, RateLimitController.call() must itself be genericized in order to accurately type the parameters for each API type. With the current implementation, the ...args in call() will be a union of the parameters of all API types. I took a stab at this here: 7b29534

@FrederikBolding
Copy link
Member Author

In addition to @mcmire's outstanding feedback, RateLimitController.call() must itself be genericized in order to accurately type the parameters for each API type. With the current implementation, the ...args in call() will be a union of the parameters of all API types. I took a stab at this here: 7b29534

Fixed. I unfortunately don't see a way to have this type safety on messenger calls with the current implementation.

I talked to @Mrtenz and he has some ideas for how to restructure the messenger types to accommodate use-cases like this, but out of scope for this PR 😅

@FrederikBolding
Copy link
Member Author

cc @Gudahtt

@Gudahtt
Copy link
Member

Gudahtt commented Mar 3, 2022

Perhaps we could get around these type issues by... not calling the underlying method at all? Then we couldn't have to deal with those types at all. The call method could be replaced by a method that either returns that the method is rate limited, or increments the call count and returns that the method can be called.

Copy link
Member

@rekmarks rekmarks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@FrederikBolding FrederikBolding merged commit 9c5b75a into main Mar 4, 2022
@FrederikBolding FrederikBolding deleted the fb/rate-limiting-controller branch March 4, 2022 09:00
soralit pushed a commit to KeystoneHQ/controllers that referenced this pull request Mar 14, 2022
* Initial implementation of NotificationControllerV2

* Simplify implementation

* Fix small type issue

* Simplify and start using messaging system

* Adapt tests for controller messaging

* Simplify tests a bit

* Add action handler

* Fix types

* Fix tests

* Add some documentation and exports

* Pivot to RateLimitController

* Fix export

* Remove subject metadata type

* Make controller generic and allow caller to pass implementation mapping

* Fix PR comments

* Fix type name casing

* Fix controller docstrings

The docstrings contained references to "notifications" from this controller's infancy.

* Return potential result from implementation, Wrap in promise in case implementation is async

* Improve typing and API

* Fix type issue

* Fix PR comments

* Cast action handler

* Change use of useFakeTimers

* Throw error when API is rate-limited

* Small fixes

Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com>
MajorLift pushed a commit that referenced this pull request Oct 11, 2023
* Initial implementation of NotificationControllerV2

* Simplify implementation

* Fix small type issue

* Simplify and start using messaging system

* Adapt tests for controller messaging

* Simplify tests a bit

* Add action handler

* Fix types

* Fix tests

* Add some documentation and exports

* Pivot to RateLimitController

* Fix export

* Remove subject metadata type

* Make controller generic and allow caller to pass implementation mapping

* Fix PR comments

* Fix type name casing

* Fix controller docstrings

The docstrings contained references to "notifications" from this controller's infancy.

* Return potential result from implementation, Wrap in promise in case implementation is async

* Improve typing and API

* Fix type issue

* Fix PR comments

* Cast action handler

* Change use of useFakeTimers

* Throw error when API is rate-limited

* Small fixes

Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com>
MajorLift pushed a commit that referenced this pull request Oct 11, 2023
* Initial implementation of NotificationControllerV2

* Simplify implementation

* Fix small type issue

* Simplify and start using messaging system

* Adapt tests for controller messaging

* Simplify tests a bit

* Add action handler

* Fix types

* Fix tests

* Add some documentation and exports

* Pivot to RateLimitController

* Fix export

* Remove subject metadata type

* Make controller generic and allow caller to pass implementation mapping

* Fix PR comments

* Fix type name casing

* Fix controller docstrings

The docstrings contained references to "notifications" from this controller's infancy.

* Return potential result from implementation, Wrap in promise in case implementation is async

* Improve typing and API

* Fix type issue

* Fix PR comments

* Cast action handler

* Change use of useFakeTimers

* Throw error when API is rate-limited

* Small fixes

Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants