discord-css-injector/src/panel.rs

108 lines
3.1 KiB
Rust

use std::{collections::HashMap, net::SocketAddr};
use futures::Future;
use include_dir::{include_dir, Dir};
use once_cell::sync::Lazy;
use warp::{
http::HeaderValue,
hyper::HeaderMap,
reply::{json, Response},
Filter, Rejection, Reply,
};
use crate::themes::{read_theme_from_dir, Theme};
static THEMES: Lazy<HashMap<String, Theme>> = Lazy::new(|| {
let mut themes = HashMap::new();
for entry in std::fs::read_dir("styles").unwrap() {
if entry.is_err() {
continue;
}
let path = entry.unwrap().path();
if path.is_dir() {
if let Some(theme) = read_theme_from_dir(path) {
themes.insert(theme.slug.clone(), theme);
}
}
}
themes
});
fn injector(theme_name: String, host: String) -> String {
if let Some(theme) = THEMES.get(&theme_name) {
// let current_addr = CURRENT_ADDRESS.get().expect("Couldn't get current address");
crate::injector::render_injector(host, theme)
} else {
"// Unknown theme, sorry!".to_string()
}
}
fn themes() -> impl Reply {
let themes: &HashMap<_, _> = &THEMES;
json(themes)
}
const PANEL_DIR: Dir = include_dir!("./src/panel");
async fn serve_panel_file(path: warp::path::Tail) -> Result<Response, Rejection> {
let mut file_name = path.as_str().to_string();
if ("/".to_string() + &file_name).ends_with("/") {
file_name.push_str("index.html");
}
if let Some(file) = PANEL_DIR.get_file(&file_name) {
let (mut head, body) = Response::new(file.contents().into()).into_parts();
let extension = file_name.rfind('.').map(|idx| &file_name[idx..]);
let content_type = match extension {
Some(".html") => "text/html; charset=utf-8",
Some(".css") => "text/css; charset=utf-8",
Some(".js") => "application/javascript; charset=utf-8",
Some(".txt") => "text/plain; charset=utf-8",
_ => "application/octet-stream",
};
head.headers
.insert("Content-Type", HeaderValue::from_str(content_type).unwrap());
return Ok(Response::from_parts(head, body));
}
Err(warp::reject::not_found())
}
pub fn serve_panel() -> (SocketAddr, impl Future<Output = ()>) {
let styles_route = {
let mut static_headers = HeaderMap::new();
for (h, v) in [
("Access-Control-Allow-Origin", "*"),
("Pragma", "no-cache"),
("Cache-Control", "no-cache"),
] {
static_headers.insert(h, HeaderValue::from_static(v));
}
warp::path("styles")
.and(warp::fs::dir("styles"))
.with(warp::reply::with::headers(static_headers))
};
let themes_list_route = warp::path("themes.json").map(themes);
let injector_route = warp::path!("theme" / String / "injector.js")
.and(warp::header("Host"))
.map(injector);
let panel_route = warp::get()
.and(warp::path::tail())
.and_then(serve_panel_file);
let routes = styles_route
.or(injector_route)
.or(themes_list_route)
.or(panel_route);
warp::serve(routes).bind_ephemeral(([127, 0, 0, 1], 0))
}