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:
19
Cargo.lock
generated
19
Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
40
src/utils.rs
40
src/utils.rs
@@ -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>>,
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user