diff options
Diffstat (limited to 'src/web_server.rs')
| -rw-r--r-- | src/web_server.rs | 90 |
1 files changed, 76 insertions, 14 deletions
diff --git a/src/web_server.rs b/src/web_server.rs index 94f043a..02c57e7 100644 --- a/src/web_server.rs +++ b/src/web_server.rs @@ -1,9 +1,13 @@ use std::sync::Arc; use actix::{Actor, Addr, Handler, Message, SyncArbiter, SyncContext}; -use actix_web::{get, middleware::Logger, web, App, HttpServer, Responder}; +use actix_web::{ + get, middleware::Logger, web, App, HttpResponse, HttpServer, Responder, ResponseError, +}; use askama::actix_web::TemplateIntoResponse; use askama::Template; +use derive_more::Display; +use serde::Serialize; use crate::bot::MasterBot; use crate::youtube_dl::AudioMetadata; @@ -24,6 +28,7 @@ pub async fn start(args: WebServerArgs) -> std::io::Result<()> { .data(bot_addr.clone()) .wrap(Logger::default()) .service(index) + .service(web::scope("/api").service(get_bot_list).service(get_bot)) .service(actix_files::Files::new("/static", "static/")) }) .bind(args.bind_address)? @@ -41,29 +46,47 @@ impl Actor for BotExecutor { type Context = SyncContext<Self>; } -impl Handler<PlaylistRequest> for BotExecutor { +struct BotDataListRequest; + +impl Message for BotDataListRequest { + // A plain Vec does not work for some reason + type Result = Result<Vec<BotData>, ()>; +} + +impl Handler<BotDataListRequest> for BotExecutor { type Result = Result<Vec<BotData>, ()>; - fn handle(&mut self, _: PlaylistRequest, _: &mut Self::Context) -> Self::Result { + fn handle(&mut self, _: BotDataListRequest, _: &mut Self::Context) -> Self::Result { let bot = &self.0; Ok(bot.bot_datas()) } } -struct PlaylistRequest; +struct BotDataRequest(String); -impl Message for PlaylistRequest { - type Result = Result<Vec<BotData>, ()>; +impl Message for BotDataRequest { + type Result = Option<BotData>; +} + +impl Handler<BotDataRequest> for BotExecutor { + type Result = Option<BotData>; + + fn handle(&mut self, r: BotDataRequest, _: &mut Self::Context) -> Self::Result { + let name = r.0; + let bot = &self.0; + + bot.bot_data(name) + } } #[derive(Template)] #[template(path = "index.htm")] -struct PlaylistTemplate<'a> { +struct OverviewTemplate<'a> { bots: &'a [BotData], } -#[derive(Debug)] +#[derive(Debug, Serialize)] pub struct BotData { pub name: String, pub state: crate::bot::State, @@ -74,16 +97,55 @@ pub struct BotData { #[get("/")] async fn index(bot: web::Data<Addr<BotExecutor>>) -> impl Responder { - let bot_datas = match bot.send(PlaylistRequest).await.unwrap() { + let bot_datas = match bot.send(BotDataListRequest).await.unwrap() { Ok(data) => data, - Err(_) => { - //error!("Playlist error: {}", e); - Vec::with_capacity(0) - } + Err(_) => Vec::with_capacity(0), }; - PlaylistTemplate { + OverviewTemplate { bots: &bot_datas[..], } .into_response() } + +#[get("/bots")] +async fn get_bot_list(bot: web::Data<Addr<BotExecutor>>) -> impl Responder { + let bot_datas = match bot.send(BotDataListRequest).await.unwrap() { + Ok(data) => data, + Err(_) => Vec::with_capacity(0), + }; + + web::Json(bot_datas) +} + +#[derive(Serialize)] +struct ApiError { + error: String, + description: String, +} + +#[derive(Debug, Display)] +enum ApiErrorKind { + #[display(fmt = "Not Found")] + NotFound, +} + +impl ResponseError for ApiErrorKind { + fn error_response(&self) -> HttpResponse { + match *self { + ApiErrorKind::NotFound => HttpResponse::NotFound().json(ApiError { + error: self.to_string(), + description: String::from("The requested resource was not found"), + }), + } + } +} + +#[get("/bots/{name}")] +async fn get_bot(bot: web::Data<Addr<BotExecutor>>, name: web::Path<String>) -> impl Responder { + if let Some(bot_data) = bot.send(BotDataRequest(name.into_inner())).await.unwrap() { + Ok(web::Json(bot_data)) + } else { + Err(ApiErrorKind::NotFound) + } +} |
