Impl GhApiClient and use it in cargo-binstall to speedup resolution process (#832)

Fixed #776

 - Add new feature gh-api-client to binstalk-downloader
 - Impl new type `binstalk_downloader::remote::{RequestBuilder, Response}`
 - Impl `binstalk_downloader::gh_api_client::GhApiClient`, exposed if `cfg(feature = "gh-api-client")` and add e2e and unit tests for it
 - Use `binstalk_downloader::gh_api_client::GhApiClient` to speedup `cargo-binstall`
 - Add new option `--github-token` to supply the token for GitHub restful API, or read from env variable `GITHUB_TOKEN` if not present.

Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
Jiahao XU 2023-03-02 12:04:22 +11:00 committed by GitHub
parent 263c836757
commit 599bcaf333
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 960 additions and 192 deletions

View file

@ -0,0 +1,99 @@
use std::fmt;
use bytes::Bytes;
use futures_lite::stream::{Stream, StreamExt};
use reqwest::Method;
use super::{header, Client, Error, HttpError, StatusCode, Url};
#[derive(Debug)]
pub struct RequestBuilder {
pub(super) client: Client,
pub(super) inner: reqwest::RequestBuilder,
}
impl RequestBuilder {
pub fn bearer_auth(self, token: &dyn fmt::Display) -> RequestBuilder {
Self {
client: self.client,
inner: self.inner.bearer_auth(token),
}
}
pub fn header(self, key: &str, value: &str) -> RequestBuilder {
Self {
client: self.client,
inner: self.inner.header(key, value),
}
}
pub async fn send(self, error_for_status: bool) -> Result<Response, Error> {
let request = self.inner.build()?;
let method = request.method().clone();
Ok(Response {
inner: self.client.send_request(request, error_for_status).await?,
method,
})
}
}
#[derive(Debug)]
pub struct Response {
inner: reqwest::Response,
method: Method,
}
impl Response {
pub async fn bytes(self) -> Result<Bytes, Error> {
self.inner.bytes().await.map_err(Error::from)
}
pub fn bytes_stream(self) -> impl Stream<Item = Result<Bytes, Error>> {
let url = Box::new(self.inner.url().clone());
let method = self.method;
self.inner.bytes_stream().map(move |res| {
res.map_err(|err| {
Error::Http(Box::new(HttpError {
method: method.clone(),
url: Url::clone(&*url),
err,
}))
})
})
}
pub fn status(&self) -> StatusCode {
self.inner.status()
}
pub fn url(&self) -> &Url {
self.inner.url()
}
pub fn method(&self) -> &Method {
&self.method
}
pub fn error_for_status_ref(&self) -> Result<&Self, Error> {
match self.inner.error_for_status_ref() {
Ok(_) => Ok(self),
Err(err) => Err(Error::Http(Box::new(HttpError {
method: self.method().clone(),
url: self.url().clone(),
err,
}))),
}
}
pub fn error_for_status(self) -> Result<Self, Error> {
match self.error_for_status_ref() {
Ok(_) => Ok(self),
Err(err) => Err(err),
}
}
pub fn headers(&self) -> &header::HeaderMap {
self.inner.headers()
}
}