|
1 | 1 | //! This module implements functionality for interacting with GitHub.
|
2 | 2 |
|
3 |
| -use curl; |
4 |
| -use curl::easy::{Easy, List}; |
5 |
| - |
| 3 | +use reqwest::{self, header}; |
6 | 4 | use oauth2::*;
|
7 | 5 |
|
8 |
| -use serde::Deserialize; |
9 |
| -use serde_json; |
| 6 | +use serde::de::DeserializeOwned; |
10 | 7 |
|
11 | 8 | use std::str;
|
12 | 9 |
|
13 | 10 | use app::App;
|
14 |
| -use util::{human, internal, CargoResult, ChainError}; |
| 11 | +use util::{human, internal, CargoResult, CargoError, errors::NotFound}; |
15 | 12 |
|
16 | 13 | /// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
|
17 | 14 | /// because custom error-code handling may be desirable. Use
|
18 | 15 | /// `parse_github_response` to handle the "common" processing of responses.
|
19 |
| -pub fn github(app: &App, url: &str, auth: &Token) -> Result<(Easy, Vec<u8>), curl::Error> { |
| 16 | +pub fn github<T>(app: &App, url: &str, auth: &Token) -> CargoResult<T> |
| 17 | +where |
| 18 | + T: DeserializeOwned, |
| 19 | +{ |
20 | 20 | let url = format!("{}://api.github.com{}", app.config.api_protocol, url);
|
21 | 21 | info!("GITHUB HTTP: {}", url);
|
22 | 22 |
|
23 |
| - let mut headers = List::new(); |
24 |
| - headers |
25 |
| - .append("Accept: application/vnd.github.v3+json") |
26 |
| - .unwrap(); |
27 |
| - headers.append("User-Agent: hello!").unwrap(); |
28 |
| - headers |
29 |
| - .append(&format!("Authorization: token {}", auth.access_token)) |
30 |
| - .unwrap(); |
31 |
| - |
32 |
| - let mut handle = app.handle(); |
33 |
| - handle.url(&url).unwrap(); |
34 |
| - handle.get(true).unwrap(); |
35 |
| - handle.http_headers(headers).unwrap(); |
36 |
| - |
37 |
| - let mut data = Vec::new(); |
38 |
| - { |
39 |
| - let mut transfer = handle.transfer(); |
40 |
| - transfer |
41 |
| - .write_function(|buf| { |
42 |
| - data.extend_from_slice(buf); |
43 |
| - Ok(buf.len()) |
44 |
| - }).unwrap(); |
45 |
| - transfer.perform()?; |
46 |
| - } |
47 |
| - Ok((handle, data)) |
| 23 | + let client = app.http_client()?; |
| 24 | + client.get(&url) |
| 25 | + .header(header::ACCEPT, "application/vnd.github.v3+json") |
| 26 | + .header(header::AUTHORIZATION, format!("token {}", auth.access_token)) |
| 27 | + .send()? |
| 28 | + .error_for_status() |
| 29 | + .map_err(handle_error_response)? |
| 30 | + .json() |
| 31 | + .map_err(Into::into) |
48 | 32 | }
|
49 | 33 |
|
50 |
| -/// Checks for normal responses |
51 |
| -pub fn parse_github_response<'de, 'a: 'de, T: Deserialize<'de>>( |
52 |
| - mut resp: Easy, |
53 |
| - data: &'a [u8], |
54 |
| -) -> CargoResult<T> { |
55 |
| - match resp.response_code().unwrap() { |
56 |
| - // Ok! |
57 |
| - 200 => {} |
58 |
| - // Unauthorized or Forbidden |
59 |
| - 401 | 403 => { |
60 |
| - return Err(human( |
61 |
| - "It looks like you don't have permission \ |
62 |
| - to query a necessary property from Github \ |
63 |
| - to complete this request. \ |
64 |
| - You may need to re-authenticate on \ |
65 |
| - crates.io to grant permission to read \ |
66 |
| - github org memberships. Just go to \ |
67 |
| - https://crates.io/login", |
68 |
| - )); |
69 |
| - } |
70 |
| - // Something else |
71 |
| - n => { |
72 |
| - let resp = String::from_utf8_lossy(data); |
73 |
| - return Err(internal(&format_args!( |
74 |
| - "didn't get a 200 result from \ |
75 |
| - github, got {} with: {}", |
76 |
| - n, resp |
77 |
| - ))); |
| 34 | +fn handle_error_response(error: reqwest::Error) -> Box<dyn CargoError> { |
| 35 | + use reqwest::StatusCode as Status; |
| 36 | + |
| 37 | + match error.status() { |
| 38 | + Some(Status::UNAUTHORIZED) | Some(Status::FORBIDDEN) => human( |
| 39 | + "It looks like you don't have permission \ |
| 40 | + to query a necessary property from Github \ |
| 41 | + to complete this request. \ |
| 42 | + You may need to re-authenticate on \ |
| 43 | + crates.io to grant permission to read \ |
| 44 | + github org memberships. Just go to \ |
| 45 | + https://crates.io/login", |
| 46 | + ), |
| 47 | + Some(Status::NOT_FOUND) => Box::new(NotFound), |
| 48 | + _ => { |
| 49 | + internal(&format_args!( |
| 50 | + "didn't get a 200 result from github: {}", |
| 51 | + error |
| 52 | + )) |
78 | 53 | }
|
79 | 54 | }
|
80 |
| - |
81 |
| - let json = str::from_utf8(data) |
82 |
| - .ok() |
83 |
| - .chain_error(|| internal("github didn't send a utf8-response"))?; |
84 |
| - |
85 |
| - serde_json::from_str(json).chain_error(|| internal("github didn't send a valid json response")) |
86 | 55 | }
|
87 | 56 |
|
88 | 57 | /// Gets a token with the given string as the access token, but all
|
|
0 commit comments