hpk/src/repository/mod.rs

103 lines
3.1 KiB
Rust

use {
crate::Package,
hpk_package::ron,
rayon::prelude::*,
serde::{Deserialize, Serialize},
std::{
collections::HashMap,
error::Error,
io::Read,
sync::{mpsc::Sender, Mutex, PoisonError},
time::Duration,
},
url::Url,
};
#[derive(Clone, Debug, Deserialize, Serialize)]
/// A struct representing all of the packages available in a remote repository
pub struct Repository {
/// The unique name for this repository
pub name: String,
/// The base url for this repository
pub base_url: Url,
/// a `HashMap` representing all available packages on this server, with the
/// keys being the unique name of each package
pub packages: HashMap<String, Package>,
}
#[derive(Clone, Debug)]
/// Messages sent to the caller thread when fetching an update for a repository
pub enum Message {
ContentLength(usize),
BytesRead(usize),
Failure(String),
Success(usize),
}
impl Repository {
pub fn build(name: &str, url: &Url, sender: Sender<Message>) -> Result<Self, Box<dyn Error>> {
let url = url.join("packages.ron.zstd")?;
let resp = ureq::get(&url.to_string())
.timeout(Duration::from_secs(10))
.call()?;
if let Some(val) = resp.header("Content-Length") {
if let Ok(num) = val.parse::<usize>() {
sender.send(Message::ContentLength(num))?;
}
}
let reader = resp.into_reader();
let mut reader = zstd::Decoder::new(reader)?;
let mut buf = vec![];
loop {
let bytes = reader.read(&mut buf)?;
if bytes == 0 {
break;
}
sender.send(Message::BytesRead(bytes))?;
}
let packages = ron::de::from_bytes(&buf)?;
Ok(Self {
name: name.to_string(),
base_url: url.clone(),
packages,
})
}
pub fn search_names(&self, query: &str) -> Result<Vec<&Package>, PoisonError<Vec<&Package>>> {
let mut results = vec![];
if let Some(p) = self.packages.get(query) {
results.push(p);
}
let results = Mutex::new(results);
self.packages.par_iter().for_each(|(k, v)| {
if k.contains(query) {
if let Ok(mut r) = results.lock() {
r.push(v);
}
}
});
let results = results.into_inner()?;
Ok(results)
}
pub fn search_all(&self, query: &str) -> Result<Vec<&Package>, PoisonError<Vec<&Package>>> {
let mut results = vec![];
if let Some(p) = self.packages.get(query) {
results.push(p);
}
let results = Mutex::new(results);
self.packages.par_iter().for_each(|(k, v)| {
if k.contains(query)
|| v.description.contains(query)
|| v.long_description.contains(query)
{
if let Ok(mut r) = results.lock() {
r.push(v);
}
}
});
let results = results.into_inner()?;
Ok(results)
}
}