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

Turn api.foo(auth, …) into fully featured ApiConnection(auth).foo(…). #4659

Open
4 tasks
chrisbobbe opened this issue Apr 14, 2021 · 4 comments
Open
4 tasks

Comments

@chrisbobbe
Copy link
Contributor

chrisbobbe commented Apr 14, 2021

This implementation plan is on the path to #4170. It will expose methods to cancel in-progress fetches, and for #4170 we'd just have to call those methods in the right places.

I've put together this plan from discussion with Greg in chat (@gnprice, please edit this plan liberally as needed! 🙂):

  • Just like fetch itself, [something like api.sendMessage] can take as an optional argument (or really, as an optional property in an optional argument which is an options-object) a signal: AbortSignal.
  • If so, then before we start the fetch request, we'll listen on that AbortSignal, with a handler which will in turn abort the AbortController whose signal we're going to pass to the actual fetch request.

IOW we can make api.sendMessage and its friends behave in the same way that APIs in the web platform itself are supposed to behave:
https://dom.spec.whatwg.org/#abortcontroller-api-integration
(which includes details […] like if the signal you're passed is already aborted, then reject immediately.)

This is an area where I expect we'll be able to fruitfully write solid tests; see #4193 for examples of testing with Jest's fake timers.

We've never used React Native's AbortController polyfill (from facebook/react-native#24419, released in v0.60) before. There may be surprising differences from its standard, documented behavior. Anyway:

  • Make the pure refactor to replace api.foo(auth, …) with ApiConnection(auth).foo(…).

  • Have ApiConnection implement a cache, keyed by the email and realm (i.e. the identity, as in identityOfAuth: Auth => Identity) from auth. We want ApiConnection to return the same object for the same identity, and a different object for a different identity.

  • Allow canceling all in-progress fetches at once:

    • When ApiConnection(auth) is called, have it create an empty array or set called something like abortControllers. abortControllers will be maintained so that it always comprises one item per in-progress request.
    • When it's time to do a fetch, create a new AbortController object and pass its AbortSignal in the fetch call (note fetch's signal param). Add the AbortController object to abortControllers.
    • Listen for that fetch's success or failure; when either happens, remove its AbortController object from abortControllers because only in-progress fetches should be there.
    • Have the result of ApiConnection(auth) grow an .abortAll method. That method should call .abort() on all items in abortControllers. That'll cancel all in-progress fetches.
  • Allow canceling individual fetches:

    • Have ApiConnection(auth).foo take an optional signal: AbortSignal, probably in a params object with its other params.
    • If signal is passed, call signal.addEventListener('abort', …), with a handler that calls .abort() on this request's AbortController in abortControllers. (This is less direct than just passing the supplied signal to the fetch, but that'd make it tricky to also have .abortAll (see above) because a single fetch call takes just one signal and so can't directly listen to multiple AbortController.abort()s at once.)
@chrisbobbe chrisbobbe changed the title Turn api.foo(auth, …) into fully featured makeApi(auth).foo(…). Turn api.foo(auth, …) into fully featured ApiConnection(auth).foo(…). Apr 14, 2021
@gnprice
Copy link
Member

gnprice commented Apr 14, 2021

See also chat discussion.

@chrisbobbe
Copy link
Contributor Author

See also chat discussion.

Greg says:

Anyway. I think figuring out a way for this ApiConnection to work -- including how to write the types so that we don't have to duplicate the specific argument and return types and try to keep them in sync -- may be a good task for me to do. (Or at least to prototype it with a handful of routes.)

Then perhaps hand over the baton for figuring out how to do the AbortSignal part of things.

@chrisbobbe
Copy link
Contributor Author

chrisbobbe commented Jul 30, 2021

What do we think about letting an ApiConnection instance hold the server feature level, not just the auth? I've been looking at #4203 and I think that might be a good place for it to be held. Then it's easy to do feature-level conditionals right where we put together a request, without making the caller pass the feature level to the specific binding (like api.getMessages in current code) as a special favor.

@gnprice
Copy link
Member

gnprice commented Sep 8, 2021

What do we think about letting an ApiConnection instance hold the server feature level, not just the auth? I've been looking at #4203 and I think that might be a good place for it to be held. Then it's easy to do feature-level conditionals right where we put together a request, without making the caller pass the feature level to the specific binding (like api.getMessages in current code) as a special favor.

Yeah, I agree.

chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this issue Jun 13, 2022
See discussion:
  https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/Maintaining.20.60edit_history.60.20on.20message-update.20events/near/1391009

Much of the plumbing added here can be removed with our plan to
encapsulate the feature level in a new ApiConnection class; see
  zulip#4659 (comment)
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this issue Jun 14, 2022
We'll use this for a feature-level condition on FL 118 for
edit_history.

Most of this can be removed with our plan to encapsulate the feature
level in a new ApiConnection class; see
  zulip#4659 (comment)
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this issue Jun 14, 2022
See discussion:
  https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/Maintaining.20.60edit_history.60.20on.20message-update.20events/near/1391009

Much of the plumbing added here can be removed with our plan to
encapsulate the feature level in a new ApiConnection class; see
  zulip#4659 (comment)
gnprice pushed a commit to chrisbobbe/zulip-mobile that referenced this issue Jun 14, 2022
We'll use this for a feature-level condition on FL 118 for
edit_history.

Most of this can be removed with our plan to encapsulate the feature
level in a new ApiConnection class; see
  zulip#4659 (comment)
gnprice pushed a commit to chrisbobbe/zulip-mobile that referenced this issue Jun 14, 2022
See discussion:
  https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/Maintaining.20.60edit_history.60.20on.20message-update.20events/near/1391009

Much of the plumbing added here can be removed with our plan to
encapsulate the feature level in a new ApiConnection class; see
  zulip#4659 (comment)
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

No branches or pull requests

2 participants