refactor(admin): use warp instead
cargo devel CI / cargo CI (push) Successful in 1m59s Details

This commit is contained in:
Christoph J. Scherr 2024-09-07 18:03:29 +02:00
parent 8bd156b5fc
commit 1fe799e1c0
3 changed files with 78 additions and 48 deletions

View File

@ -16,10 +16,11 @@ anyhow = "1.0.86"
async-trait = "0.1.82"
clap = { version = "4.5.17", features = ["derive"] }
libpt = { version = "0.7.1", features = ["cli", "log"] }
minijinja = { version = "2.2.0", optional = true }
rand = "0.8.5"
serde = { version = "1.0.209", features = ["derive"] }
serde_json = "1.0.128"
tide = { version = "0.16.0", optional = true }
thiserror = "1.0.63"
tokio = { version = "1.40.0", features = [
"macros",
"net",
@ -28,7 +29,8 @@ tokio = { version = "1.40.0", features = [
"rt",
"sync",
] }
warp = { version = "0.3.7", optional = true }
[features]
default = ["admin-interface"]
admin-interface = ["dep:tide"]
admin-interface = ["dep:warp", "dep:minijinja"]

View File

@ -7,7 +7,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="author" content="{AUTHOR}">
<meta name="generator" content="Hugo 0.122.0">
<title>Starter Template · Bootstrap v5.3</title>
@ -21,19 +21,15 @@
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<!-- Favicons -->
<!-- <link rel="apple-touch-icon" href="/docs/5.3/assets/img/favicons/apple-touch-icon.png" sizes="180x180"> -->
<!-- <link rel="icon" href="/docs/5.3/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png"> -->
<!-- <link rel="icon" href="/docs/5.3/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png"> -->
<!-- <link rel="manifest" href="/docs/5.3/assets/img/favicons/manifest.json"> -->
<!-- <link rel="mask-icon" href="/docs/5.3/assets/img/favicons/safari-pinned-tab.svg" color="#712cf9"> -->
<!-- <link rel="icon" href="/docs/5.3/assets/img/favicons/favicon.ico"> -->
<!-- <meta name="theme-color" content="#712cf9"> -->
<link rel="icon" href="https://icons.getbootstrap.com/assets/icons/safe-fill.svg">
<meta name="theme-color" content="#712cf9">
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<!-- All the svgs we use later -->
<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
<symbol id="check2" viewBox="0 0 16 16">
<path
@ -52,8 +48,19 @@
<path
d="M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z" />
</symbol>
<symbol id="arrow-right-circle" viewBox="0 0 16 16">
<path
d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0zM4.5 7.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5H4.5z" />
</symbol>
<symbol id="vault" viewBox="0 0 16 16">
<title>Bootstrap</title>
<path d="M9.778 9.414A2 2 0 1 1 6.95 6.586a2 2 0 0 1 2.828 2.828" />
<path
d="M2.5 0A1.5 1.5 0 0 0 1 1.5V3H.5a.5.5 0 0 0 0 1H1v3.5H.5a.5.5 0 0 0 0 1H1V12H.5a.5.5 0 0 0 0 1H1v1.5A1.5 1.5 0 0 0 2.5 16h12a1.5 1.5 0 0 0 1.5-1.5v-13A1.5 1.5 0 0 0 14.5 0zm3.036 4.464 1.09 1.09a3 3 0 0 1 3.476 0l1.09-1.09a.5.5 0 1 1 .707.708l-1.09 1.09c.74 1.037.74 2.44 0 3.476l1.09 1.09a.5.5 0 1 1-.707.708l-1.09-1.09a3 3 0 0 1-3.476 0l-1.09 1.09a.5.5 0 1 1-.708-.708l1.09-1.09a3 3 0 0 1 0-3.476l-1.09-1.09a.5.5 0 1 1 .708-.708M14 6.5v3a.5.5 0 0 1-1 0v-3a.5.5 0 0 1 1 0" />
</symbol>
</svg>
<!-- theme switcher -->
<div class="dropdown position-fixed bottom-0 end-0 mb-3 me-3 bd-mode-toggle">
<button class="btn btn-bd-primary py-2 dropdown-toggle d-flex align-items-center" id="bd-theme" type="button"
aria-expanded="false" data-bs-toggle="dropdown" aria-label="Toggle theme (auto)">
@ -102,27 +109,14 @@
</ul>
</div>
<svg xmlns="http://www.w3.org/2000/svg" class="d-none">
<symbol id="arrow-right-circle" viewBox="0 0 16 16">
<path
d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0zM4.5 7.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5H4.5z" />
</symbol>
<symbol id="bootstrap" viewBox="0 0 118 94">
<title>Bootstrap</title>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M24.509 0c-6.733 0-11.715 5.893-11.492 12.284.214 6.14-.064 14.092-2.066 20.577C8.943 39.365 5.547 43.485 0 44.014v5.972c5.547.529 8.943 4.649 10.951 11.153 2.002 6.485 2.28 14.437 2.066 20.577C12.794 88.106 17.776 94 24.51 94H93.5c6.733 0 11.714-5.893 11.491-12.284-.214-6.14.064-14.092 2.066-20.577 2.009-6.504 5.396-10.624 10.943-11.153v-5.972c-5.547-.529-8.934-4.649-10.943-11.153-2.002-6.484-2.28-14.437-2.066-20.577C105.214 5.894 100.233 0 93.5 0H24.508zM80 57.863C80 66.663 73.436 72 62.543 72H44a2 2 0 01-2-2V24a2 2 0 012-2h18.437c9.083 0 15.044 4.92 15.044 12.474 0 5.302-4.01 10.049-9.119 10.88v.277C75.317 46.394 80 51.21 80 57.863zM60.521 28.34H49.948v14.934h8.905c6.884 0 10.68-2.772 10.68-7.727 0-4.643-3.264-7.207-9.012-7.207zM49.948 49.2v16.458H60.91c7.167 0 10.964-2.876 10.964-8.281 0-5.406-3.903-8.178-11.425-8.178H49.948z">
</path>
</symbol>
</svg>
<!-- basically everything but with some margin -->
<div class="col-lg-8 mx-auto p-4 py-md-5">
<header class="d-flex align-items-center pb-3 mb-5 border-bottom">
<a href="/" class="d-flex align-items-center text-body-emphasis text-decoration-none">
<svg class="bi me-2" width="40" height="32">
<use xlink:href="#bootstrap" />
<use xlink:href="#vault" />
</svg>
<span class="fs-4">Starter template</span>
<span class="fs-4">{TITLE}</span>
</a>
</header>

View File

@ -1,41 +1,75 @@
use std::fmt::Display;
use std::sync::Arc;
use anyhow::Result;
use libpt::log::warn;
use minijinja::context;
use minijinja::Environment;
use serde;
use tide::http::mime;
use tide::prelude::*;
use tide::Request;
use tide::Response;
use thiserror::Error;
use warp::reject;
use warp::reply::Reply;
use warp::reply::Response;
use warp::Filter;
use crate::config::Config;
use crate::vault::VaultRef;
#[derive(Clone)]
pub struct Interface {
pub struct Service<'tp> {
vault: VaultRef,
config: Config,
env: Environment<'tp>,
}
impl<'tp> Service<'tp> {
fn new(vault: VaultRef, config: Config, env: Environment<'tp>) -> Arc<Self> {
Self { vault, config, env }.into()
}
}
pub async fn serve(vault: VaultRef, config: Config) -> Result<()> {
let mut app = tide::with_state(Interface { vault, config });
app.at("/").get(overview);
app.at("/styles.css").get(styles);
app.listen("127.0.0.1:8000").await?;
let mut env = Environment::new();
env.add_template("index", include_str!("../../data/www/admin.html"))?;
let service = Service::new(vault, config, env);
let service2 = service.clone();
let routes = warp::path::end()
.map(move || service2.clone())
.and_then(overview);
warp::serve(routes)
.run(service.config.addr_admin.unwrap())
.await;
warn!("exited the admin interface");
Ok(())
}
async fn overview(req: Request<Interface>) -> tide::Result {
let r = Response::builder(200)
.content_type(mime::HTML)
.body(format!(
include_str!("../../data/www/admin.html"),
TITLE = "Wooly-Vault"
));
#[derive(Debug, Error)]
struct TemplateError(#[from] minijinja::Error);
Ok(r.into())
impl reject::Reject for TemplateError {}
impl Display for TemplateError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "something went wrong with producing this page")
}
}
async fn styles(_req: Request<Interface>) -> tide::Result {
let r = Response::builder(200)
.content_type(mime::CSS)
.body(include_str!("../../data/www/styles.css"));
Ok(r.into())
async fn overview(serv: Arc<Service<'_>>) -> Result<Box<dyn warp::Reply>, warp::Rejection> {
let r = Response::new(
serv.env
.get_template("index")
.map_err(TemplateError::from)?
.render(context!(TITLE => "Wooly-Vault", AUTHOR => env!("CARGO_PKG_AUTHORS")))
.map_err(TemplateError::from)?
.into(),
);
Ok(Box::new(r))
}
async fn styles() -> Result<Box<dyn warp::Reply>, warp::Rejection> {
let r = include_str!("../../data/www/styles.css").to_string();
Ok(Box::new(r))
}