-
Notifications
You must be signed in to change notification settings - Fork 40
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
Custom backends support #405
base: master
Are you sure you want to change the base?
Conversation
The types in reqwest are re-exports of the types in http, so this should not break anything, and is needed to make reqwests an optional dependency.
Almost every module in client::requests defines their own Pending struct, wrapping a Boxed future, using copy+pasted code. This patch implements a templated Pending type in the client::requests module, and uses it in submodules. The patch also sets up a type alias called Pending in each of the submodules, to retain backwards compatibility.
Move the implementations of NextParams for SniffedNodes into the sender's corresponding files, since they fit better there. Remove (a)sync_next, since it couples the SniffedNodes object too tightly to the senders. Instead, senders can call `next_or_start_refresh` on the SniffedNodes object to get the address or a new `Refresher` struct indicating that a refresh is needed. The sender can then send out the request for the node list, and when the sender gets the results, it can feed them to the Refresher, consuming it. This makes the SniffedNodes object flexible with how senders receive their results.
The trait specifies the Request and Response types of the request, and specifies a function to convert the request builder to the Request type. All of the request builder types already had an `into_request` function, so this trait just codifies that behavior. Note that the raw request does not implement this (yet) since it does not do a standard conversion. This patch doesn't have any uses of the trait yet, but future patches will make use of it.
The request types can only be converted into one concrete type of Endpoint, but the existing From trait implementation can't convey that, making it impossible to write a bound for a type that can be converted into an endpoint with any body type. The new IntoEndpoint trait fixes this by making the body an associated type. The bound can be written as, for instance, `Req: for<'a> IntoEndpoint<'a>`
This adds and changes things to allow external implementations of `Sender` to exist, and to have a unified send function for results (currently implemented alongside of the existing send functionality, but will replace it). This patch adds TypedSender<T>, a companion trait for Sender that also lets the client handle deserialization, instead of having every request type implement deserialization for the two available senders.
Client code can now choose whether to include the sync sender or async sender via Cargo's features system. By default both are included. Make public some crate-private types, a) to avoid unused warnings, and b) other crates will likely need them for custom sender implementations. Had to downgrade the url crate to be compatible with reqwest's version.
Custom backends need access to the fields
Allows custom backends to create a client
The trait requires implementing on types that this crate exports, like SniffedNodes<TSender> and its parent NodeAddresses<TSender>, but that's not possible to do in external crates, due to rust's orphan rules. The return type, once again, is heavily dependent on the sender, since SniffedNodes needs to do a potentially asynchronous http request. So just cut out the middle man and fold the code into the Sender trait.
Backends in other crates will want to use that function.
It's not needed anymore, now that the Sender itself is responsible for querying for nodes.
FYI I haven't tested this too hardly yet, but I'm planning on working on a project that makes use of this crate on WASM, so that should exercise all the functionality. |
Wow! Thanks for the PR! This is pretty big. So does this allow implementing/creating your own I tried updating to futures 0.3 yesterday and it is a doozy... I wonder if this could help? Would it be crazy if we just remove sync sender now that |
Yes, you can implement your own sender in your own crate. Example for wasm using stdweb: https://gitlab.com/colonelthirtytwo/elastic-stdweb-rs IMO I'd rather keep syncsender around; tokio and the async stuff is a bit heavy and I would not be surprised if people would not want to include all that. |
Any chance you can rebase this onto master so we can run the tests? I assume they might need to be updated too? |
Could do. Just wanted a look-over of the code beforehand in case I had to change anything. |
One issue I've noticed is that since |
|
I am just now starting to look more at this and I have a few initial questions:
I'll add more to my review asap... |
|
|
Allows external crates to write their own
Sender
implementations and use them withClient
.This involved refactoring a decent amount of the crate, and probably has some backwards-incompatible changes. I didn't change any of the usual APIs though; most code that just does querying should still work.
The primary impetus of this change is getting this crate to work in WebAssembly. In that environment, requests must be made via the
XMLHttpRequest
API, and this crate must return JS promises. I have written such a backend, which serves as an example; code is here: https://gitlab.com/colonelthirtytwo/elastic-stdweb-rsMajor changes off the top of my head, see commits for more details:
TypedSender<TReqInner>
, a subtrait ofSender
that all backends should implement for allT: ReqInner
. This handles deserializing the response from the backend once it is available (ex. usingResult.map
forSyncSender
,Future::map
forAsyncSender
, andPromise::then
forStdwebSender
). The response type (an associated type of the trait) has to vary depending on the type being deserialized, hence why this is a separate trait fromSender
. Once Generic Associated Types are stabilized, the trait can be merged intoSender
.SyncSender
andAsyncSender
into one that uses theTypedSender
. Rust orphaning rules would forbid implementingRequest<MySender>
in external crates, so that approach would not scale.Sender
field fromSniffedNodes
and replace it with an API that was not responsible for fetching the request, since how to fetch the request would change based on backend.NextParams
trait and move its functionality toSender::next_params
.TypedSender
.SyncSender
,AsyncSender
, and related code are now behind cargo features, allowing this crate to be built without them (default is to include both, for backwards compatibility). WASM needs this, since the reqwest-based senders won't even build for that target.Fixes #281