From 84804836f5c1e782c77f1bbf676177151558e008 Mon Sep 17 00:00:00 2001 From: Jokler Date: Sat, 22 Feb 2020 22:46:06 +0100 Subject: Add tmtu mode as a front-end --- src/web_server.rs | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) (limited to 'src/web_server.rs') diff --git a/src/web_server.rs b/src/web_server.rs index 02c57e7..80c914c 100644 --- a/src/web_server.rs +++ b/src/web_server.rs @@ -1,17 +1,22 @@ use std::sync::Arc; +use std::time::Duration; use actix::{Actor, Addr, Handler, Message, SyncArbiter, SyncContext}; use actix_web::{ - get, middleware::Logger, web, App, HttpResponse, HttpServer, Responder, ResponseError, + get, http::header, middleware::Logger, post, web, App, Error, HttpResponse, HttpServer, + Responder, ResponseError, }; use askama::actix_web::TemplateIntoResponse; use askama::Template; use derive_more::Display; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use crate::bot::MasterBot; use crate::youtube_dl::AudioMetadata; +mod front_end_cookie; +use front_end_cookie::FrontEnd; + pub struct WebServerArgs { pub domain: String, pub bind_address: String, @@ -28,6 +33,8 @@ pub async fn start(args: WebServerArgs) -> std::io::Result<()> { .data(bot_addr.clone()) .wrap(Logger::default()) .service(index) + .service(tmtu_bot) + .service(post_front_end) .service(web::scope("/api").service(get_bot_list).service(get_bot)) .service(actix_files::Files::new("/static", "static/")) }) @@ -46,6 +53,34 @@ impl Actor for BotExecutor { type Context = SyncContext; } +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +struct FrontEndForm { + front_end: FrontEnd, +} + +#[post("/front-end")] +async fn post_front_end(form: web::Form) -> Result { + front_end_cookie::set_front_end(form.into_inner().front_end).await +} + +struct BotNameListRequest; + +impl Message for BotNameListRequest { + // A plain Vec does not work for some reason + type Result = Result, ()>; +} + +impl Handler for BotExecutor { + type Result = Result, ()>; + + fn handle(&mut self, _: BotNameListRequest, _: &mut Self::Context) -> Self::Result { + let bot = &self.0; + + Ok(bot.bot_names()) + } +} + struct BotDataListRequest; impl Message for BotDataListRequest { @@ -86,17 +121,32 @@ struct OverviewTemplate<'a> { bots: &'a [BotData], } +#[derive(Template)] +#[template(path = "tmtu/index.htm")] +struct TmtuTemplate { + bot_names: Vec, + bot: Option, +} + #[derive(Debug, Serialize)] pub struct BotData { pub name: String, pub state: crate::bot::State, pub volume: f64, + pub position: Option, pub currently_playing: Option, pub playlist: Vec, } #[get("/")] -async fn index(bot: web::Data>) -> impl Responder { +async fn index(bot: web::Data>, front: FrontEnd) -> Result { + match front { + FrontEnd::Lazy => lazy_index(bot).await, + FrontEnd::Tmtu => tmtu_index(bot).await, + } +} + +async fn lazy_index(bot: web::Data>) -> Result { let bot_datas = match bot.send(BotDataListRequest).await.unwrap() { Ok(data) => data, Err(_) => Vec::with_capacity(0), @@ -108,6 +158,38 @@ async fn index(bot: web::Data>) -> impl Responder { .into_response() } +async fn tmtu_index(bot: web::Data>) -> Result { + let bot_names = bot.send(BotNameListRequest).await.unwrap().unwrap(); + + TmtuTemplate { + bot_names, + bot: None, + } + .into_response() +} + +#[get("/tmtu/{name}")] +async fn tmtu_bot( + bot: web::Data>, + name: web::Path, + front: FrontEnd, +) -> Result { + if front != FrontEnd::Tmtu { + return Ok(HttpResponse::Found().header(header::LOCATION, "/").finish()); + } + + let bot_names = bot.send(BotNameListRequest).await.unwrap().unwrap(); + if let Some(bot) = bot.send(BotDataRequest(name.into_inner())).await.unwrap() { + TmtuTemplate { + bot_names, + bot: Some(bot), + } + .into_response() + } else { + Ok(HttpResponse::Found().header(header::LOCATION, "/").finish()) + } +} + #[get("/bots")] async fn get_bot_list(bot: web::Data>) -> impl Responder { let bot_datas = match bot.send(BotDataListRequest).await.unwrap() { @@ -149,3 +231,19 @@ async fn get_bot(bot: web::Data>, name: web::Path) -> Err(ApiErrorKind::NotFound) } } + +mod filters { + use std::time::Duration; + + pub fn fmt_duration(duration: &Option) -> Result { + if let Some(duration) = duration { + let secs = duration.as_secs(); + let mins = secs / 60; + let submin_secs = secs % 60; + + Ok(format!("{:02}:{:02}", mins, submin_secs)) + } else { + Ok(String::from("--:--")) + } + } +} -- cgit v1.2.3-70-g09d2