feat: add assets for discord embedded messages
This commit is contained in:
parent
e225ffe997
commit
5183130427
6 changed files with 99 additions and 5 deletions
BIN
remote/cache-service/assets/closed.png
Normal file
BIN
remote/cache-service/assets/closed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
remote/cache-service/assets/offline.png
Normal file
BIN
remote/cache-service/assets/offline.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
remote/cache-service/assets/open.png
Normal file
BIN
remote/cache-service/assets/open.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -1,7 +1,8 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum::http::{HeaderMap, StatusCode};
|
use axum::http::{HeaderMap, StatusCode, header};
|
||||||
|
use axum::response::IntoResponse;
|
||||||
use axum::Json;
|
use axum::Json;
|
||||||
use noisebell_common::{validate_bearer, HistoryEntry, WebhookPayload};
|
use noisebell_common::{validate_bearer, HistoryEntry, WebhookPayload};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
@ -11,6 +12,10 @@ use crate::db;
|
||||||
use crate::types::{DoorStatus, WebhookTarget};
|
use crate::types::{DoorStatus, WebhookTarget};
|
||||||
use crate::webhook;
|
use crate::webhook;
|
||||||
|
|
||||||
|
static OPEN_PNG: &[u8] = include_bytes!("../assets/open.png");
|
||||||
|
static CLOSED_PNG: &[u8] = include_bytes!("../assets/closed.png");
|
||||||
|
static OFFLINE_PNG: &[u8] = include_bytes!("../assets/offline.png");
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub db: Arc<Mutex<rusqlite::Connection>>,
|
pub db: Arc<Mutex<rusqlite::Connection>>,
|
||||||
pub client: reqwest::Client,
|
pub client: reqwest::Client,
|
||||||
|
|
@ -126,3 +131,86 @@ pub async fn get_history(
|
||||||
|
|
||||||
Ok(Json(entries))
|
Ok(Json(entries))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_image_open() -> impl IntoResponse {
|
||||||
|
([(header::CONTENT_TYPE, "image/png"), (header::CACHE_CONTROL, "public, max-age=86400")], OPEN_PNG)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_image_closed() -> impl IntoResponse {
|
||||||
|
([(header::CONTENT_TYPE, "image/png"), (header::CACHE_CONTROL, "public, max-age=86400")], CLOSED_PNG)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_image_offline() -> impl IntoResponse {
|
||||||
|
([(header::CONTENT_TYPE, "image/png"), (header::CACHE_CONTROL, "public, max-age=86400")], OFFLINE_PNG)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_image(State(state): State<Arc<AppState>>) -> impl IntoResponse {
|
||||||
|
let db = state.db.clone();
|
||||||
|
let status = tokio::task::spawn_blocking(move || {
|
||||||
|
let conn = db.blocking_lock();
|
||||||
|
db::get_current_status_str(&conn)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("db task panicked")
|
||||||
|
.ok()
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
let image = match status.as_deref() {
|
||||||
|
Some("open") => OPEN_PNG,
|
||||||
|
Some("closed") => CLOSED_PNG,
|
||||||
|
_ => OFFLINE_PNG,
|
||||||
|
};
|
||||||
|
([(header::CONTENT_TYPE, "image/png"), (header::CACHE_CONTROL, "public, max-age=5")], image)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_badge(State(state): State<Arc<AppState>>) -> impl IntoResponse {
|
||||||
|
let db = state.db.clone();
|
||||||
|
let status = tokio::task::spawn_blocking(move || {
|
||||||
|
let conn = db.blocking_lock();
|
||||||
|
db::get_current_status_str(&conn)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("db task panicked")
|
||||||
|
.ok()
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
let (label, color) = match status.as_deref() {
|
||||||
|
Some("open") => ("open", "#57f287"),
|
||||||
|
Some("closed") => ("closed", "#ed4245"),
|
||||||
|
_ => ("offline", "#99aab5"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let label_width = 70u32;
|
||||||
|
let value_width = 10 + label.len() as u32 * 7;
|
||||||
|
let total_width = label_width + value_width;
|
||||||
|
let label_x = label_width as f32 / 2.0;
|
||||||
|
let value_x = label_width as f32 + value_width as f32 / 2.0;
|
||||||
|
|
||||||
|
let svg = format!(
|
||||||
|
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"{total_width}\" height=\"20\">\
|
||||||
|
<linearGradient id=\"s\" x2=\"0\" y2=\"100%\">\
|
||||||
|
<stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>\
|
||||||
|
<stop offset=\"1\" stop-opacity=\".1\"/>\
|
||||||
|
</linearGradient>\
|
||||||
|
<clipPath id=\"r\"><rect width=\"{total_width}\" height=\"20\" rx=\"3\" fill=\"#fff\"/></clipPath>\
|
||||||
|
<g clip-path=\"url(#r)\">\
|
||||||
|
<rect width=\"{label_width}\" height=\"20\" fill=\"#555\"/>\
|
||||||
|
<rect x=\"{label_width}\" width=\"{value_width}\" height=\"20\" fill=\"{color}\"/>\
|
||||||
|
<rect width=\"{total_width}\" height=\"20\" fill=\"url(#s)\"/>\
|
||||||
|
</g>\
|
||||||
|
<g fill=\"#fff\" text-anchor=\"middle\" font-family=\"Verdana,Geneva,sans-serif\" font-size=\"11\">\
|
||||||
|
<text x=\"{label_x}\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">noisebell</text>\
|
||||||
|
<text x=\"{label_x}\" y=\"14\">noisebell</text>\
|
||||||
|
<text x=\"{value_x}\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">{label}</text>\
|
||||||
|
<text x=\"{value_x}\" y=\"14\">{label}</text>\
|
||||||
|
</g></svg>"
|
||||||
|
);
|
||||||
|
|
||||||
|
(
|
||||||
|
[
|
||||||
|
(header::CONTENT_TYPE, "image/svg+xml"),
|
||||||
|
(header::CACHE_CONTROL, "no-cache, max-age=0"),
|
||||||
|
],
|
||||||
|
svg,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,11 @@ async fn main() -> Result<()> {
|
||||||
.route("/status", get(api::get_status))
|
.route("/status", get(api::get_status))
|
||||||
.route("/info", get(api::get_info))
|
.route("/info", get(api::get_info))
|
||||||
.route("/history", get(api::get_history))
|
.route("/history", get(api::get_history))
|
||||||
|
.route("/image", get(api::get_image))
|
||||||
|
.route("/image/open.png", get(api::get_image_open))
|
||||||
|
.route("/image/closed.png", get(api::get_image_closed))
|
||||||
|
.route("/image/offline.png", get(api::get_image_offline))
|
||||||
|
.route("/badge.svg", get(api::get_badge))
|
||||||
.layer(
|
.layer(
|
||||||
TraceLayer::new_for_http()
|
TraceLayer::new_for_http()
|
||||||
.make_span_with(tower_http::trace::DefaultMakeSpan::new().level(Level::INFO))
|
.make_span_with(tower_http::trace::DefaultMakeSpan::new().level(Level::INFO))
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,17 @@ struct AppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_embed(status: &str, timestamp: u64) -> CreateEmbed {
|
fn build_embed(status: &str, timestamp: u64) -> CreateEmbed {
|
||||||
let (colour, title, description) = match status {
|
let (colour, title, description, image_url) = match status {
|
||||||
"open" => (Colour::from_rgb(87, 242, 135), "Door is open", "The door at Noisebridge is open."),
|
"open" => (Colour::from_rgb(0, 255, 0), "Noisebridge is Open!", "It's time to start hacking.", "https://noisebell.extremist.software/image/open.png"),
|
||||||
"closed" => (Colour::from_rgb(237, 66, 69), "Door is closed", "The door at Noisebridge is closed."),
|
"closed" => (Colour::from_rgb(255, 0, 0), "Noisebridge is Closed!", "We'll see you again soon.", "https://noisebell.extremist.software/image/closed.png"),
|
||||||
_ => (Colour::from_rgb(153, 170, 181), "Pi is offline", "The Noisebridge Pi is offline."),
|
_ => (Colour::from_rgb(153, 170, 181), "Noisebridge is Offline", "The Noisebridge Pi is not responding.", "https://noisebell.extremist.software/image/offline.png"),
|
||||||
};
|
};
|
||||||
|
|
||||||
CreateEmbed::new()
|
CreateEmbed::new()
|
||||||
.title(title)
|
.title(title)
|
||||||
.description(description)
|
.description(description)
|
||||||
.colour(colour)
|
.colour(colour)
|
||||||
|
.thumbnail(image_url)
|
||||||
.timestamp(serenity::model::Timestamp::from_unix_timestamp(timestamp as i64).unwrap_or_else(|_| serenity::model::Timestamp::now()))
|
.timestamp(serenity::model::Timestamp::from_unix_timestamp(timestamp as i64).unwrap_or_else(|_| serenity::model::Timestamp::now()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue