aboutsummaryrefslogtreecommitdiffstats
path: root/src/web_server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/web_server.rs')
-rw-r--r--src/web_server.rs90
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)
+ }
+}