From 5d3b77f1cd30598ec27cbdf774c261faa8a0dfbc Mon Sep 17 00:00:00 2001 From: jude Date: Sun, 29 Oct 2023 18:00:45 +0000 Subject: [PATCH 1/6] Add metrics Change dashboards to load an index.html file compiled otherwise --- .gitignore | 2 ++ Cargo.lock | 30 +++++++++++++++++++++ web/Cargo.toml | 1 + web/src/lib.rs | 16 +++++++++--- web/src/metrics.rs | 43 +++++++++++++++++++++++++++++++ web/src/routes/dashboard/guild.rs | 1 - web/src/routes/dashboard/mod.rs | 30 +++++++++++++-------- web/src/routes/metrics.rs | 18 +++++++++++++ web/src/routes/mod.rs | 1 + web/static/css/style.css | 4 +++ 10 files changed, 130 insertions(+), 16 deletions(-) create mode 100644 web/src/metrics.rs delete mode 100644 web/src/routes/dashboard/guild.rs create mode 100644 web/src/routes/metrics.rs diff --git a/.gitignore b/.gitignore index 1b9cd34..7c89042 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ /venv .cargo /.idea +web/static/index.html +web/static/assets diff --git a/Cargo.lock b/Cargo.lock index c617b30..00d0846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2051,6 +2051,27 @@ dependencies = [ "yansi", ] +[[package]] +name = "prometheus" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +dependencies = [ + "cfg-if", + "fnv", + "lazy_static", + "memchr", + "parking_lot", + "protobuf", + "thiserror", +] + +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" + [[package]] name = "quote" version = "1.0.33" @@ -2174,7 +2195,11 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reminder-rs" +<<<<<<< HEAD version = "1.6.50" +======= +version = "1.6.48" +>>>>>>> 97f186d (Add metrics) dependencies = [ "base64 0.21.5", "chrono", @@ -2202,7 +2227,11 @@ dependencies = [ [[package]] name = "reminder_web" +<<<<<<< HEAD version = "0.1.4" +======= +version = "0.1.3" +>>>>>>> 97f186d (Add metrics) dependencies = [ "base64 0.13.1", "chrono", @@ -2211,6 +2240,7 @@ dependencies = [ "lazy_static", "log", "oauth2", + "prometheus", "rand", "reqwest", "rocket", diff --git a/web/Cargo.toml b/web/Cargo.toml index a274d4b..e10e8ef 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -19,3 +19,4 @@ lazy_static = "1.4.0" rand = "0.8" base64 = "0.13" csv = "1.2" +prometheus = "0.13.3" diff --git a/web/src/lib.rs b/web/src/lib.rs index 7e02265..b340464 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -6,6 +6,7 @@ mod consts; mod macros; mod catchers; mod guards; +mod metrics; mod routes; use std::{env, path::Path}; @@ -25,7 +26,10 @@ use serenity::{ }; use sqlx::{MySql, Pool}; -use crate::consts::{CNC_GUILD, DISCORD_OAUTH_AUTHORIZE, DISCORD_OAUTH_TOKEN, SUBSCRIPTION_ROLES}; +use crate::{ + consts::{CNC_GUILD, DISCORD_OAUTH_AUTHORIZE, DISCORD_OAUTH_TOKEN, SUBSCRIPTION_ROLES}, + metrics::{init_metrics, MetricProducer}, +}; type Database = MySql; @@ -64,7 +68,10 @@ pub async fn initialize( let static_path = if Path::new("web/static").exists() { "web/static" } else { "/lib/reminder-rs/static" }; + init_metrics(); + rocket::build() + .attach(MetricProducer) .attach(Template::fairing()) .register( "/", @@ -85,12 +92,13 @@ pub async fn initialize( .mount( "/", routes![ - routes::index, routes::cookies, + routes::index, + routes::metrics::metrics, routes::privacy, - routes::terms, - routes::return_to_same_site, routes::report::report_error, + routes::return_to_same_site, + routes::terms, ], ) .mount( diff --git a/web/src/metrics.rs b/web/src/metrics.rs new file mode 100644 index 0000000..13754ae --- /dev/null +++ b/web/src/metrics.rs @@ -0,0 +1,43 @@ +use lazy_static::lazy_static; +use prometheus::{IntCounterVec, Opts, Registry}; +use rocket::{ + fairing::{Fairing, Info, Kind}, + Data, Request, Response, +}; + +lazy_static! { + pub static ref REGISTRY: Registry = Registry::new(); + static ref REQUEST_COUNTER: IntCounterVec = + IntCounterVec::new(Opts::new("requests", "Requests"), &["method", "route"]).unwrap(); + static ref RESPONSE_COUNTER: IntCounterVec = + IntCounterVec::new(Opts::new("responses", "Responses"), &["status", "route"]).unwrap(); +} + +pub fn init_metrics() { + REGISTRY.register(Box::new(REQUEST_COUNTER.clone())).unwrap(); +} + +pub struct MetricProducer; + +#[rocket::async_trait] +impl Fairing for MetricProducer { + fn info(&self) -> Info { + Info { name: "Metrics fairing", kind: Kind::Request } + } + + async fn on_request(&self, req: &mut Request<'_>, _data: &mut Data<'_>) { + if let Some(route) = req.route() { + REQUEST_COUNTER + .with_label_values(&[req.method().as_str(), &route.uri.to_string()]) + .inc(); + } + } + + async fn on_response<'r>(&self, req: &'r Request<'_>, resp: &mut Response<'r>) { + if let Some(route) = req.route() { + RESPONSE_COUNTER + .with_label_values(&[&resp.status().code.to_string(), &route.uri.to_string()]) + .inc(); + } + } +} diff --git a/web/src/routes/dashboard/guild.rs b/web/src/routes/dashboard/guild.rs deleted file mode 100644 index 8b13789..0000000 --- a/web/src/routes/dashboard/guild.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/src/routes/dashboard/mod.rs b/web/src/routes/dashboard/mod.rs index 06bd35d..2a51e01 100644 --- a/web/src/routes/dashboard/mod.rs +++ b/web/src/routes/dashboard/mod.rs @@ -1,8 +1,13 @@ -use std::collections::HashMap; +use std::path::Path; use chrono::{naive::NaiveDateTime, Utc}; use rand::{rngs::OsRng, seq::IteratorRandom}; -use rocket::{http::CookieJar, response::Redirect, serde::json::json}; +use rocket::{ + fs::{relative, NamedFile}, + http::CookieJar, + response::Redirect, + serde::json::json, +}; use rocket_dyn_templates::Template; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serenity::{ @@ -27,7 +32,6 @@ use crate::{ pub mod api; pub mod export; -pub mod guild; type Unset = Option; @@ -655,22 +659,26 @@ async fn create_database_channel( } #[get("/")] -pub async fn dashboard_home(cookies: &CookieJar<'_>) -> Result { +pub async fn dashboard_home(cookies: &CookieJar<'_>) -> Result { if cookies.get_private("userid").is_some() { - let mut map = HashMap::new(); - map.insert("version", env!("CARGO_PKG_VERSION")); - Ok(Template::render("dashboard", &map)) + NamedFile::open(Path::new(relative!("static/index.html"))).await.map_err(|e| { + warn!("Couldn't render dashboard: {:?}", e); + + Redirect::to("/login/discord") + }) } else { Err(Redirect::to("/login/discord")) } } #[get("/<_..>")] -pub async fn dashboard(cookies: &CookieJar<'_>) -> Result { +pub async fn dashboard(cookies: &CookieJar<'_>) -> Result { if cookies.get_private("userid").is_some() { - let mut map = HashMap::new(); - map.insert("version", env!("CARGO_PKG_VERSION")); - Ok(Template::render("dashboard", &map)) + NamedFile::open(Path::new(relative!("static/index.html"))).await.map_err(|e| { + warn!("Couldn't render dashboard: {:?}", e); + + Redirect::to("/login/discord") + }) } else { Err(Redirect::to("/login/discord")) } diff --git a/web/src/routes/metrics.rs b/web/src/routes/metrics.rs new file mode 100644 index 0000000..0421264 --- /dev/null +++ b/web/src/routes/metrics.rs @@ -0,0 +1,18 @@ +use prometheus; + +use crate::metrics::REGISTRY; + +#[get("/metrics")] +pub async fn metrics() -> String { + let encoder = prometheus::TextEncoder::new(); + let res_custom = encoder.encode_to_string(®ISTRY.gather()); + + match res_custom { + Ok(s) => s, + Err(e) => { + warn!("Error encoding metrics: {:?}", e); + + String::new() + } + } +} diff --git a/web/src/routes/mod.rs b/web/src/routes/mod.rs index b9c871e..568f5f3 100644 --- a/web/src/routes/mod.rs +++ b/web/src/routes/mod.rs @@ -1,6 +1,7 @@ pub mod admin; pub mod dashboard; pub mod login; +pub mod metrics; pub mod report; use std::collections::HashMap; diff --git a/web/static/css/style.css b/web/static/css/style.css index 4fffab7..deb519d 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -633,6 +633,10 @@ li.highlight { display: flex; } +.button-row-edit > button { + margin-right: 4px; +} + .button-row .button-row-reminder { flex-grow: 0; padding: 2px; From 14a54471f782766edfb8893d516f619ad8c288a0 Mon Sep 17 00:00:00 2001 From: jude Date: Sun, 29 Oct 2023 18:27:55 +0000 Subject: [PATCH 2/6] Build dashboard --- .gitmodules | 3 +++ Cargo.toml | 1 + reminder-dashboard | 1 + 3 files changed, 5 insertions(+) create mode 100644 .gitmodules create mode 160000 reminder-dashboard diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..61a269d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "reminder-dashboard"] + path = reminder-dashboard + url = gitea@gitea.jellypro.xyz:jude/reminder-dashboard diff --git a/Cargo.toml b/Cargo.toml index 87e77ac..7197ea0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ assets = [ ["conf/default.env", "etc/reminder-rs/config.env", "600"], ["conf/Rocket.toml", "etc/reminder-rs/Rocket.toml", "600"], ["web/static/**/*", "lib/reminder-rs/static", "644"], + ["reminder-dashboard/dist/static/**/*", "lib/reminder-rs/static", "644"], ["web/templates/**/*", "lib/reminder-rs/templates", "644"], ["healthcheck", "lib/reminder-rs/healthcheck", "755"], ["cron.d/reminder_health", "etc/cron.d/reminder_health", "644"], diff --git a/reminder-dashboard b/reminder-dashboard new file mode 160000 index 0000000..d5f1a2e --- /dev/null +++ b/reminder-dashboard @@ -0,0 +1 @@ +Subproject commit d5f1a2e3a1a226743e17bcf5ad42fc46d232e41f From 7a6372ed02f4d218bfc1f81b5ec17f2a9a869f4b Mon Sep 17 00:00:00 2001 From: jude Date: Mon, 6 Nov 2023 16:53:04 +0000 Subject: [PATCH 3/6] Update styles for notification flash --- reminder-dashboard | 2 +- web/static/css/style.css | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/reminder-dashboard b/reminder-dashboard index d5f1a2e..8ba7a39 160000 --- a/reminder-dashboard +++ b/reminder-dashboard @@ -1 +1 @@ -Subproject commit d5f1a2e3a1a226743e17bcf5ad42fc46d232e41f +Subproject commit 8ba7a39ce532907b845c54dd3b54bf2a4c7a04e9 diff --git a/web/static/css/style.css b/web/static/css/style.css index deb519d..ecaacfc 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -218,17 +218,16 @@ div.inset-content { margin-right: 10%; } -div.flash-message { +div.flash-container { position: fixed; + width: 100%; + bottom: 0; +} + +div.flash-message { width: calc(100% - 32px); margin: 16px !important; z-index: 99; - bottom: 0; - display: none; -} - -div.flash-message.is-active { - display: block; } body { From 59982df827a9932c80be5c5163a8b6555253379b Mon Sep 17 00:00:00 2001 From: jude Date: Sun, 12 Nov 2023 10:15:29 +0000 Subject: [PATCH 4/6] Correct merge errors --- Cargo.lock | 8 -------- web/src/routes/dashboard/mod.rs | 1 - 2 files changed, 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00d0846..aac4a83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2195,11 +2195,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reminder-rs" -<<<<<<< HEAD version = "1.6.50" -======= -version = "1.6.48" ->>>>>>> 97f186d (Add metrics) dependencies = [ "base64 0.21.5", "chrono", @@ -2227,11 +2223,7 @@ dependencies = [ [[package]] name = "reminder_web" -<<<<<<< HEAD version = "0.1.4" -======= -version = "0.1.3" ->>>>>>> 97f186d (Add metrics) dependencies = [ "base64 0.13.1", "chrono", diff --git a/web/src/routes/dashboard/mod.rs b/web/src/routes/dashboard/mod.rs index 2a51e01..7bc9243 100644 --- a/web/src/routes/dashboard/mod.rs +++ b/web/src/routes/dashboard/mod.rs @@ -8,7 +8,6 @@ use rocket::{ response::Redirect, serde::json::json, }; -use rocket_dyn_templates::Template; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serenity::{ client::Context, From a2d442bc54343322955251c222f0b9ff64782bf8 Mon Sep 17 00:00:00 2001 From: jude Date: Sun, 12 Nov 2023 17:17:22 +0000 Subject: [PATCH 5/6] Reset intervals correctly --- reminder-dashboard | 2 +- web/src/routes/dashboard/api/guild/reminders.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/reminder-dashboard b/reminder-dashboard index 8ba7a39..d068782 160000 --- a/reminder-dashboard +++ b/reminder-dashboard @@ -1 +1 @@ -Subproject commit 8ba7a39ce532907b845c54dd3b54bf2a4c7a04e9 +Subproject commit d068782596bb85d883a594633e9b516c1bc428fc diff --git a/web/src/routes/dashboard/api/guild/reminders.rs b/web/src/routes/dashboard/api/guild/reminders.rs index 1cb67d2..9b7c6e2 100644 --- a/web/src/routes/dashboard/api/guild/reminders.rs +++ b/web/src/routes/dashboard/api/guild/reminders.rs @@ -235,6 +235,21 @@ pub async fn edit_reminder( ]); } } + } else { + sqlx::query!( + " + UPDATE reminders + SET interval_seconds = NULL, interval_days = NULL, interval_months = NULL + WHERE uid = ? + ", + reminder.uid + ) + .execute(transaction.executor()) + .await + .map_err(|e| { + warn!("Error updating reminder interval: {:?}", e); + json!({ "reminder": Option::::None, "errors": vec!["Unknown error"] }) + })?; } if reminder.channel > 0 { From 7aae24638886690bfe57fd845ed15c4b10c24ded Mon Sep 17 00:00:00 2001 From: jude Date: Thu, 21 Dec 2023 16:37:21 +0000 Subject: [PATCH 6/6] Remove submodule --- .gitmodules | 3 --- reminder-dashboard | 1 - 2 files changed, 4 deletions(-) delete mode 100644 .gitmodules delete mode 160000 reminder-dashboard diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 61a269d..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "reminder-dashboard"] - path = reminder-dashboard - url = gitea@gitea.jellypro.xyz:jude/reminder-dashboard diff --git a/reminder-dashboard b/reminder-dashboard deleted file mode 160000 index d068782..0000000 --- a/reminder-dashboard +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d068782596bb85d883a594633e9b516c1bc428fc