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

[base-controller] Implement utility function registerEventSubscriptions for batch registering all internal events of a messenger client class #4719

Open
MajorLift opened this issue Sep 19, 2024 · 0 comments
Assignees

Comments

@MajorLift
Copy link
Contributor

MajorLift commented Sep 19, 2024

Motivation

  • Currently, we manually enumerate each individual .subscribe() call in messenger client constructors. We should have a DRY-er way of doing this.
  • A "data as code" paradigm could be implemented by supplying the constructor with a map pairing each event type with an EventSubscriptionMap of its subscriptions (and associated handlers, selectors).
    • This would replace the hard-coded subscribe calls with flexible input data.
    • Consumers could be optionally allowed to override the default EventSubscriptionMap argument, thereby making the event handler and selector behavior programmable.
    • The presence of the default argument means that if alteration of behavior is unneeded, consumers can simply instantiate the class without any additional requirements.

Proof of Concept (WIP)

MessengerClient

export type EventsMap<
  AllowedEvents extends EventConstraint,
  Output = {
    [Event in AllowedEvents as Event['type']]: EventSubscriptionMap<Event>;
  },
> = Map<keyof Output & string, Output[keyof Output]>;

export class MessengerClient<
  WalletComponentName extends string,
  WalletComponentMessenger extends RestrictedControllerMessengerConstraint<WalletComponentName>,
> {
...
  constructor({
    name, 
    messenger, 
    eventSubscriptions = new Map() 
  }: {
      name: WalletComponentName;
      messenger: WalletComponentMessenger;
      eventSubscriptions: EventsMap<EventConstraint>;
    },
  ) {
    this.name = name;
    this.messagingSystem = messenger;
    this.#registerEventSubscriptions(eventSubscriptions);
  }
...
  #registerEventSubscriptions(subscriptionsMap: EventsMap<EventConstraint>) {
    for (const [eventType, subscriptions] of subscriptionsMap.entries()) {
      for (const [handler, selector] of subscriptions.entries()) {
        !selector
          ? this.messagingSystem.subscribe(eventType, handler)
          : this.messagingSystem.subscribe(eventType, handler, selector);
      }
    }
  }

Call Site: AssetsContractController

export class AssetsContractController extends MessengerClient<
  typeof name,
  AssetsContractControllerMessenger
> {

  ...

  constructor({
    messenger,
    chainId: initialChainId,
    eventSubscriptions = new Map([
      [
        `PreferencesController:stateChange` as const,
        new Map([
          (
            ...[
              { ipfsGateway },
              _,
            ]: ExtractEventPayload<PreferencesControllerStateChangeEvent>
          ) => {
            this.#ipfsGateway = ipfsGateway;
          },
          undefined,
        ]) as EventSubscriptionMap<PreferencesControllerStateChangeEvent>,
      ],
      [
        `NetworkController:networkDidChange` as const,
        new Map([
          (
            ...[
              { selectedNetworkClientId },
            ]: ExtractEventPayload<NetworkControllerNetworkDidChangeEvent>
          ) => {
            const chainId = this.#getCorrectChainId(selectedNetworkClientId);

            if (this.#chainId !== chainId) {
              this.#chainId = chainId;
              // @ts-expect-error TODO: remove this annotation once the `Eip1193Provider` class is released
              this.#provider = this.#getCorrectProvider();
            }
          },
          undefined,
        ]) as EventSubscriptionMap<NetworkControllerNetworkDidChangeEvent>,
      ],
    ]),
  }: {
    messenger: AssetsContractControllerMessenger;
    chainId: Hex;
    eventSubscriptions: EventsMap<AllowedEvents>;
  }) {
    super({
      name,
      messenger,
      eventSubscriptions,
    });
    this.#provider = undefined;
    this.#ipfsGateway = IPFS_DEFAULT_GATEWAY_URL;
    this.#chainId = initialChainId;
  }
  ...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant