-
Notifications
You must be signed in to change notification settings - Fork 124
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
Multiple clients via features #129
Conversation
dc86929
to
c596ede
Compare
…to multiple-clients
Sorry for missing your comment, I have fixed the |
5714834
to
9bdec0a
Compare
Ok so I've made a few discussion-related issues recently. The plan is to open some more issues in libraries that use rspotify like spotifyd, spotify-tui or ncspot, and both let them know about the rewrite and ask for their opinion. That should help us to take the decisions. I'll do that once this PR is merged. I won't be making any more commits from now on (other than suggestions you may come up with when reviewing the code). |
I have finished the code review, it's a huge PR, takes many time to review, and I have added a few suggestions, you could take time to have a look at them :) |
Sorry what suggestions? |
I have left some review comments, does you miss them? And I have merged a PR submitted by other contributor which seems to cause a conflict on file |
I'm afraid I can't find these comments. Can you provide a link? I'll fix the CHANGELOG.md issue. |
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.
There are all my review comments, I just forgot to submit my reviews and all comments are pending, sorry for that.
send_request: D, | ||
) -> ClientResult<String> | ||
where | ||
D: Fn(&mut Request) -> Response, |
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 does D: Fn(&mut Request)->Response
mean? I am a little bit confused about that?
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.
It's just a function to continue building the base Request
(with headers and such already) to pass its contents, like the one in src/http/reqwest.rs
. You can see its usage later on in this file.
In this case, calling something like send_json
with ureq
converts the Request into a Response (it's like the call
method in Reqwest implicitly), so that's the function signature needed. Using a closure makes it straightforward to choose between GET/POST/PUT/DELETE, and avoids the Content::Json
and Content::Form
enum I had previously, which was admittedly a mess.
params.insert("offset".to_owned(), offset.into().unwrap_or(0).to_string()); | ||
params.insert("q".to_owned(), q.to_owned()); | ||
params.insert("type".to_owned(), _type.as_str().to_owned()); | ||
if let Some(market) = market { |
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.
We could have a macro named map!
which does the same job as what json!
does, to reduce the boilerplate code.
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.
I did think about it. I initially wanted to use a serde_json::Value
type for GET requests (and thus json!
) because it makes its usage super easy and clean, but I ended up running into too many issues.
I also tried to make the query type a HashMap<&str, &str>
but failed because of ownership issues (this would avoid the to_owned
calls). All of the following conditional inserts failed because &str
is not owned and it goes out of scope:
if let Some(market) = market {
params.insert("market", market.as_str());
}
But I can give that a try again to see if it's possible to improve before being forced to use a macro (you can give it a try as well). Rather than creating one I'd use existing crates, like maplit.
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.
I would leave this for a different PR, though.
Is it ready to merge? :) |
I would say so! |
Merged :) |
This is a second attempt for fixing #112. The original idea at #120 was to have a
blocking
module that would call the async implementations with a blocking runtime in order to avoid code duplication. This turned up to be a bad idea, because it wasn't as easy and flexible as I thought. This new approach uses themaybe-async
crate, which makes it relatively easy to use multiple HTTP clients in the same crate with features. Instead of having ablocking
module, the user may configure what client is used like so:rspotify = { version = "...", default_features = false, features = "client-ureq" }
(client-reqwest
is still the default).Advantages of this approach:
ureq
instead ofreqwest
, which is much more minimal.macro_rules!
macro. These are quick and easy to implement, but supporting generic parameters and other compex stuff can get out of hands pretty quickly. This avoids any workarounds for that.derive_deref
dependency isn't necessary.Disadvantages of this approach:
maybe-async
. It's just a procedural macro so no performance impact whatsoever. This also requiresasync_trait
.Required changes and progress
reqwest
ureq
webapp
examplemaybe_async
about the parenthesis warnings when usingureq
: Parenthesis warnings with synchronous code fMeow/maybe-async-rs#1Read the CHANGELOG.md additions for more changes (most of them are from #127). I had to rewrite the
fetch_access_token
logic so that it can use the HTTP client inSpotify
, and I ended up improving lots of other stuff I saw. (this is still very WIP, along with the first two points of this section).I've left lots of
TODO
s that can be discussed after this is merged. I'd like to finish this ASAP so that other changes can be made without merge conflicts and without having to apply them for the blocking module as well.Also see the examples, some of them have been modified to show how the API works now.
derive_builder
to avoid repetition with the builder pattern #109from_env
#116