m/cup
1
0
mirror of https://github.com/sergi0g/cup.git synced 2025-11-15 08:33:49 -05:00

Switch back to json

This commit is contained in:
Sergio
2024-07-17 15:28:32 +03:00
parent d1cb62304d
commit 1cf4cf2394
7 changed files with 47 additions and 72 deletions

19
Cargo.lock generated
View File

@@ -355,15 +355,13 @@ dependencies = [
"bollard", "bollard",
"chrono", "chrono",
"clap", "clap",
"home",
"http-auth", "http-auth",
"indicatif", "indicatif",
"json",
"liquid", "liquid",
"once_cell", "once_cell",
"rayon", "rayon",
"regex", "regex",
"serde",
"serde_json",
"termsize", "termsize",
"tokio", "tokio",
"ureq", "ureq",
@@ -557,15 +555,6 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "http" name = "http"
version = "1.1.0" version = "1.1.0"
@@ -803,6 +792,12 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "json"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
[[package]] [[package]]
name = "kstring" name = "kstring"
version = "2.0.0" version = "2.0.0"

View File

@@ -8,7 +8,6 @@ clap = { version = "4.5.7", features = ["derive"] }
indicatif = { version = "0.17.8", optional = true } indicatif = { version = "0.17.8", optional = true }
tokio = {version = "1.38.0", features = ["rt", "rt-multi-thread", "macros"]} tokio = {version = "1.38.0", features = ["rt", "rt-multi-thread", "macros"]}
ureq = { version = "2.9.7", features = ["tls"] } ureq = { version = "2.9.7", features = ["tls"] }
serde_json = "1.0"
rayon = "1.10.0" rayon = "1.10.0"
xitca-web = { version = "0.5.0", optional = true, features = ["logger"] } xitca-web = { version = "0.5.0", optional = true, features = ["logger"] }
liquid = { version = "0.26.6", optional = true } liquid = { version = "0.26.6", optional = true }
@@ -17,13 +16,12 @@ once_cell = "1.19.0"
http-auth = { version = "0.1.9", features = [] } http-auth = { version = "0.1.9", features = [] }
termsize = { version = "0.1.8", optional = true } termsize = { version = "0.1.8", optional = true }
regex = "1.10.5" regex = "1.10.5"
chrono = { version = "0.4.38", default-features = false, features = ["std", "alloc", "clock"] } chrono = { version = "0.4.38", default-features = false, features = ["std", "alloc", "clock"], optional = true }
home = "0.5.9" json = "0.12.4"
serde = "1.0.204"
[features] [features]
default = ["server", "cli"] default = ["server", "cli"]
server = ["dep:xitca-web", "dep:liquid"] server = ["dep:xitca-web", "dep:liquid", "dep:chrono"]
cli = ["dep:indicatif", "dep:termsize"] cli = ["dep:indicatif", "dep:termsize"]
[profile.release] [profile.release]

View File

@@ -1,7 +1,7 @@
use std::time::Duration; use std::time::Duration;
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use serde_json::json; use json::object;
use crate::utils::{sort_update_vec, to_json}; use crate::utils::{sort_update_vec, to_json};
@@ -40,7 +40,7 @@ pub fn print_updates(updates: &[(String, Option<bool>)], icons: &bool) {
} }
pub fn print_raw_updates(updates: &[(String, Option<bool>)]) { pub fn print_raw_updates(updates: &[(String, Option<bool>)]) {
println!("{}", serde_json::to_string(&to_json(updates)).unwrap()); println!("{}", json::stringify(to_json(updates)));
} }
pub fn print_update(name: &str, has_update: &Option<bool>) { pub fn print_update(name: &str, has_update: &Option<bool>) {
@@ -58,7 +58,7 @@ pub fn print_update(name: &str, has_update: &Option<bool>) {
} }
pub fn print_raw_update(name: &str, has_update: &Option<bool>) { pub fn print_raw_update(name: &str, has_update: &Option<bool>) {
let result = json!({"images": {name: has_update}}); let result = object! {images: {[name]: *has_update}} ;
println!("{}", result); println!("{}", result);
} }

View File

@@ -1,8 +1,8 @@
use check::{get_all_updates, get_update};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
#[cfg(feature = "cli")] #[cfg(feature = "cli")]
use formatting::{print_raw_update, print_raw_updates, print_update, print_updates, Spinner}; use formatting::{print_raw_update, print_raw_updates, print_update, print_updates, Spinner};
#[cfg(feature = "cli")] #[cfg(feature = "cli")]
use check::{get_all_updates, get_update};
#[cfg(feature = "server")] #[cfg(feature = "server")]
use server::serve; use server::serve;
use std::path::PathBuf; use std::path::PathBuf;
@@ -10,13 +10,13 @@ use utils::load_config;
pub mod check; pub mod check;
pub mod docker; pub mod docker;
#[cfg(feature = "cli")]
pub mod formatting;
pub mod image; pub mod image;
pub mod registry; pub mod registry;
pub mod utils;
#[cfg(feature = "cli")]
pub mod formatting;
#[cfg(feature = "server")] #[cfg(feature = "server")]
pub mod server; pub mod server;
pub mod utils;
#[derive(Parser)] #[derive(Parser)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]

View File

@@ -1,7 +1,7 @@
use std::sync::Mutex; use std::sync::Mutex;
use json::JsonValue;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use serde_json::Value;
use ureq::Error; use ureq::Error;
use http_auth::parse_challenges; use http_auth::parse_challenges;
@@ -95,18 +95,13 @@ pub fn get_token(images: Vec<&Image>, auth_url: &str) -> String {
error!("Token request failed!\n{}", e) error!("Token request failed!\n{}", e)
} }
}; };
let parsed_token_response: Value = match serde_json::from_str(&raw_response) { let parsed_token_response: JsonValue = match json::parse(&raw_response) {
Ok(parsed) => parsed, Ok(parsed) => parsed,
Err(e) => { Err(e) => {
error!("Failed to parse server response\n{}", e) error!("Failed to parse server response\n{}", e)
} }
}; };
parsed_token_response parsed_token_response["token"].to_string()
.get("token")
.unwrap()
.as_str()
.unwrap()
.to_string()
} }
fn parse_www_authenticate(www_auth: &str) -> String { fn parse_www_authenticate(www_auth: &str) -> String {

View File

@@ -1,6 +1,7 @@
use std::{collections::HashMap, sync::Arc}; use std::sync::Arc;
use chrono::Local; use chrono::Local;
use json::JsonValue;
use liquid::{object, Object}; use liquid::{object, Object};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use xitca_web::{ use xitca_web::{
@@ -15,7 +16,7 @@ use xitca_web::{
use crate::{ use crate::{
check::get_all_updates, check::get_all_updates,
error, error,
utils::{sort_update_vec, to_json, Config, JsonData}, utils::{sort_update_vec, to_json},
}; };
const RAW_TEMPLATE: &str = include_str!("static/template.liquid"); const RAW_TEMPLATE: &str = include_str!("static/template.liquid");
@@ -24,7 +25,7 @@ const FAVICON_ICO: &[u8] = include_bytes!("static/favicon.ico");
const FAVICON_SVG: &[u8] = include_bytes!("static/favicon.svg"); const FAVICON_SVG: &[u8] = include_bytes!("static/favicon.svg");
const APPLE_TOUCH_ICON: &[u8] = include_bytes!("static/apple-touch-icon.png"); const APPLE_TOUCH_ICON: &[u8] = include_bytes!("static/apple-touch-icon.png");
pub async fn serve(port: &u16, socket: Option<String>, config: Config) -> std::io::Result<()> { pub async fn serve(port: &u16, socket: Option<String>, config: JsonValue) -> std::io::Result<()> {
let mut data = ServerData::new(socket, config).await; let mut data = ServerData::new(socket, config).await;
data.refresh().await; data.refresh().await;
App::new() App::new()
@@ -48,7 +49,7 @@ async fn home(data: StateRef<'_, Arc<Mutex<ServerData>>>) -> WebResponse {
async fn json(data: StateRef<'_, Arc<Mutex<ServerData>>>) -> WebResponse { async fn json(data: StateRef<'_, Arc<Mutex<ServerData>>>) -> WebResponse {
WebResponse::new(ResponseBody::from( WebResponse::new(ResponseBody::from(
serde_json::to_string(&data.lock().await.json).unwrap(), json::stringify(data.lock().await.json.clone())
)) ))
} }
@@ -72,19 +73,19 @@ async fn apple_touch_icon() -> WebResponse {
struct ServerData { struct ServerData {
template: String, template: String,
raw_updates: Vec<(String, Option<bool>)>, raw_updates: Vec<(String, Option<bool>)>,
json: JsonData, json: JsonValue,
socket: Option<String>, socket: Option<String>,
config: Config, config: JsonValue,
} }
impl ServerData { impl ServerData {
async fn new(socket: Option<String>, config: Config) -> Self { async fn new(socket: Option<String>, config: JsonValue) -> Self {
let mut s = Self { let mut s = Self {
socket, socket,
template: String::new(), template: String::new(),
json: JsonData { json: json::object! {
metrics: HashMap::new(), metrics: json::object! {},
images: HashMap::new(), images: json::object! {},
}, },
raw_updates: Vec::new(), raw_updates: Vec::new(),
config, config,
@@ -110,8 +111,8 @@ impl ServerData {
.collect::<Vec<Object>>(); .collect::<Vec<Object>>();
self.json = to_json(&self.raw_updates); self.json = to_json(&self.raw_updates);
let last_updated = Local::now().format("%Y-%m-%d %H:%M:%S"); let last_updated = Local::now().format("%Y-%m-%d %H:%M:%S");
let theme = match &self.config.theme { let theme = match &self.config["theme"].as_str() {
Some(t) => match t.as_str() { Some(t) => match *t {
"default" => "neutral", "default" => "neutral",
"blue" => "gray", "blue" => "gray",
_ => error!( _ => error!(
@@ -122,7 +123,7 @@ impl ServerData {
None => "neutral", None => "neutral",
}; };
let globals = object!({ let globals = object!({
"metrics": [{"name": "Monitored images", "value": self.json.metrics.get("monitored_images")}, {"name": "Up to date", "value": self.json.metrics.get("up_to_date")}, {"name": "Updates available", "value": self.json.metrics.get("update_available")}, {"name": "Unknown", "value": self.json.metrics.get("unknown")}], "metrics": [{"name": "Monitored images", "value": self.json["metrics"]["monitored_images"].as_usize()}, {"name": "Up to date", "value": self.json["metrics"]["up_to_date"].as_usize()}, {"name": "Updates available", "value": self.json["metrics"]["update_available"].as_usize()}, {"name": "Unknown", "value": self.json["metrics"]["unknown"].as_usize()}],
"images": images, "images": images,
"style": STYLE, "style": STYLE,
"last_updated": last_updated.to_string(), "last_updated": last_updated.to_string(),

View File

@@ -1,8 +1,8 @@
use std::{collections::HashMap, path::PathBuf}; use std::path::PathBuf;
use json::{object, JsonValue};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use serde::{Deserialize, Serialize};
/// This macro is an alternative to panic. It prints the message you give it and exits the process with code 1, without printing a stack trace. Useful for when the program has to exit due to a user error or something unexpected which is unrelated to the program (e.g. a failed web request) /// This macro is an alternative to panic. It prints the message you give it and exits the process with code 1, without printing a stack trace. Useful for when the program has to exit due to a user error or something unexpected which is unrelated to the program (e.g. a failed web request)
#[macro_export] #[macro_export]
@@ -87,7 +87,7 @@ pub fn sort_update_vec(updates: &[(String, Option<bool>)]) -> Vec<(String, Optio
} }
/// Tries to load the config from the path provided and perform basic validation /// Tries to load the config from the path provided and perform basic validation
pub fn load_config(config_path: Option<PathBuf>) -> Config { pub fn load_config(config_path: Option<PathBuf>) -> JsonValue {
let raw_config = match &config_path { let raw_config = match &config_path {
Some(path) => std::fs::read_to_string(path), Some(path) => std::fs::read_to_string(path),
None => Ok(String::from("{\"theme\":\"default\"}")), None => Ok(String::from("{\"theme\":\"default\"}")),
@@ -98,25 +98,19 @@ pub fn load_config(config_path: Option<PathBuf>) -> Config {
&config_path.unwrap().to_str().unwrap() &config_path.unwrap().to_str().unwrap()
) )
}; };
match serde_json::from_str(&raw_config.unwrap()) { match json::parse(&raw_config.unwrap()) {
Ok(v) => v, Ok(v) => v,
Err(e) => panic!("Failed to parse config!\n{}", e), Err(e) => panic!("Failed to parse config!\n{}", e),
} }
} }
#[derive(Deserialize)] pub fn to_json(updates: &[(String, Option<bool>)]) -> JsonValue {
pub struct Config { let mut json_data: JsonValue = object! {
pub authentication: Option<HashMap<String, String>>, metrics: object! {},
pub theme: Option<String>, images: object! {}
}
pub fn to_json(updates: &[(String, Option<bool>)]) -> JsonData {
let mut json_data: JsonData = JsonData {
metrics: HashMap::new(),
images: HashMap::new(),
}; };
updates.iter().for_each(|(image, has_update)| { updates.iter().for_each(|(image, has_update)| {
let _ = json_data.images.insert(image.clone(), *has_update); let _ = json_data["images"].insert(image, *has_update);
}); });
let up_to_date = updates let up_to_date = updates
.iter() .iter()
@@ -133,17 +127,9 @@ pub fn to_json(updates: &[(String, Option<bool>)]) -> JsonData {
.filter(|&(_, value)| value.is_none()) .filter(|&(_, value)| value.is_none())
.collect::<Vec<&(String, Option<bool>)>>() .collect::<Vec<&(String, Option<bool>)>>()
.len(); .len();
let _ = json_data.metrics.insert("monitored_images", updates.len()); let _ = json_data["metrics"].insert("monitored_images", updates.len());
let _ = json_data.metrics.insert("up_to_date", up_to_date); let _ = json_data["metrics"].insert("up_to_date", up_to_date);
let _ = json_data let _ = json_data["metrics"].insert("update_available", update_available);
.metrics let _ = json_data["metrics"].insert("unknown", unknown);
.insert("update_available", update_available);
let _ = json_data.metrics.insert("unknown", unknown);
json_data json_data
} }
#[derive(Serialize)]
pub struct JsonData {
pub metrics: HashMap<&'static str, usize>,
pub images: HashMap<String, Option<bool>>,
}