use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
use anyhow::Result;
use log::debug;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::mods::local::{LocalMod, ModWarning};
#[typeshare]
#[derive(Debug, Serialize, Deserialize, Hash)]
#[serde(rename_all = "camelCase")]
pub struct Alert {
pub enabled: bool,
pub severity: Option<String>,
pub message: Option<String>,
pub url: Option<String>,
pub url_label: Option<String>,
}
impl Alert {
pub fn compute_hash(&self) -> String {
let mut hasher = DefaultHasher::new();
self.hash(&mut hasher);
let num = hasher.finish();
format!("{num:x}")
}
}
pub async fn fetch_alert(url: &str) -> Result<Alert> {
debug!("Fetching Alert At: {url}");
let req = reqwest::get(url).await?.error_for_status();
if let Ok(alert) = req {
let alert = alert.json().await?;
Ok(alert)
} else {
Ok(Alert {
enabled: false,
severity: None,
message: None,
url: None,
url_label: None,
})
}
}
pub fn get_warnings<'a>(
mods: Vec<&'a LocalMod>,
ignore: Vec<&'a str>,
) -> Vec<(&'a str, &'a ModWarning)> {
mods.into_iter()
.filter_map(|m| {
if let Some(warning) = &m.manifest.warning {
let name = m.manifest.unique_name.to_string();
if ignore.contains(&name.as_str()) {
None
} else {
Some((m.manifest.unique_name.as_ref(), warning))
}
} else {
None
}
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::DEFAULT_ALERT_URL;
#[test]
pub fn test_get_alert() {
tokio_test::block_on(async {
let alert = fetch_alert(DEFAULT_ALERT_URL).await;
assert!(alert.is_ok());
});
}
#[test]
pub fn test_get_warnings() {
let mut mod1 = LocalMod::get_test(1);
mod1.manifest.warning = Some(ModWarning {
title: "Test".to_string(),
body: "Test".to_string(),
});
let mod2 = LocalMod::get_test(2);
let warnings = get_warnings(vec![&mod1, &mod2], vec![]);
assert_eq!(warnings.len(), 1);
let warnings = get_warnings(vec![&mod1, &mod2], vec![&mod1.manifest.unique_name]);
assert_eq!(warnings.len(), 0);
}
}