Skip to content

Commit

Permalink
Merge pull request #4 from MathiasPius/sparse-index
Browse files Browse the repository at this point in the history
Use crates.io sparse index
  • Loading branch information
MathiasPius authored Sep 9, 2023
2 parents 4ab8e57 + e7a2ca3 commit 3b9bbe3
Show file tree
Hide file tree
Showing 10 changed files with 521 additions and 257 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Change Log

## 0.0.4

### Added
* Implemented CrateCache which can be used with either of the crates.io backends.
* Implemented crates.io sparse index backend and set it as the default.

### Fixed
* Left-over test code would create file CRATE_CACHE_DIR/test.

## 0.0.3

### Fixed
* Fix vulnerability in [rustls-webpki](https://github.com/briansmith/webpki/issues/69)
* Check crate versions immediately on open, instead of only on change.
83 changes: 42 additions & 41 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[package]
name = "crates-lsp"
version = "0.0.3"
version = "0.0.4"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
tokio = { version = "1.29.1", features = ["rt", "macros", "io-std"] }
tower-lsp = "0.19.0"
tower-lsp = "0.20.0"
async-trait = "0.1"

semver = { version = "1", features = ["serde"] }
hyper = { version = "0.14.27", features = ["client", "http1"] }
Expand Down
88 changes: 88 additions & 0 deletions src/crates/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use async_trait::async_trait;
use hyper::{client::HttpConnector, Body, Request};
use hyper_rustls::HttpsConnector;
use semver::Version;
use serde::Deserialize;

use super::{CrateError, CrateLookup};

type HyperClient = hyper::Client<HttpsConnector<HttpConnector>>;

#[derive(Debug, Clone)]
pub struct CrateApi {
client: HyperClient,
}

#[async_trait]
impl CrateLookup for CrateApi {
async fn get_latest_version(self, crate_name: String) -> Result<Version, CrateError> {
let response = self
.client
.request(
Request::builder()
.uri(&format!("https://crates.io/api/v1/crates/{crate_name}"))
.header(
"User-Agent",
"crates-lsp (github.com/MathiasPius/crates-lsp)",
)
.header("Accept", "application/json")
.body(Body::empty())
.map_err(CrateError::transport)?,
)
.await
.map_err(CrateError::transport)?;

let body = hyper::body::to_bytes(response.into_body())
.await
.map_err(CrateError::transport)?;

let stringified = String::from_utf8_lossy(&body);

#[derive(Deserialize)]
struct CrateInner {
pub max_stable_version: Version,
}

#[derive(Deserialize)]
struct Crate {
#[serde(rename = "crate")]
pub inner: CrateInner,
}

let details: Crate =
serde_json::from_str(&stringified).map_err(CrateError::Deserialization)?;

Ok(details.inner.max_stable_version)
}
}

impl Default for CrateApi {
fn default() -> Self {
let https = hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.https_only()
.enable_http1()
.build();
let client = hyper::Client::builder().build(https);

CrateApi { client }
}
}

#[cfg(test)]
mod tests {
use crate::crates::{api::CrateApi, cache::CrateCache, CrateLookup};

#[tokio::test]
async fn get_common_crates() {
let api = CrateApi::default();

let cache = CrateCache::default();

let versions = api
.fetch_versions(cache, &["serde", "log", "tracing", "crate-does-not-exist"])
.await;

println!("{versions:#?}");
}
}
Loading

0 comments on commit 3b9bbe3

Please sign in to comment.