aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bot/master.rs1
-rw-r--r--src/web_server.rs185
-rw-r--r--src/web_server/api.rs48
-rw-r--r--src/web_server/bot_executor.rs63
-rw-r--r--src/web_server/default.rs24
-rw-r--r--src/web_server/front_end_cookie.rs8
-rw-r--r--src/web_server/tmtu.rs41
-rw-r--r--src/youtube_dl.rs11
-rw-r--r--templates/tmtu/index.htm4
9 files changed, 205 insertions, 180 deletions
diff --git a/src/bot/master.rs b/src/bot/master.rs
index 9b33744..755aaa1 100644
--- a/src/bot/master.rs
+++ b/src/bot/master.rs
@@ -215,7 +215,6 @@ impl MasterBot {
pub fn bot_data(&self, name: String) -> Option<crate::web_server::BotData> {
let music_bots = self.music_bots.read().unwrap();
-
let bot = music_bots.connected_bots.get(&name)?;
Some(crate::web_server::BotData {
diff --git a/src/web_server.rs b/src/web_server.rs
index 80c914c..0342a38 100644
--- a/src/web_server.rs
+++ b/src/web_server.rs
@@ -1,20 +1,21 @@
use std::sync::Arc;
use std::time::Duration;
-use actix::{Actor, Addr, Handler, Message, SyncArbiter, SyncContext};
+use actix::{Addr, SyncArbiter};
use actix_web::{
- get, http::header, middleware::Logger, post, web, App, Error, HttpResponse, HttpServer,
- Responder, ResponseError,
+ get, http::header, middleware::Logger, post, web, App, HttpResponse, HttpServer, Responder,
};
-use askama::actix_web::TemplateIntoResponse;
-use askama::Template;
-use derive_more::Display;
use serde::{Deserialize, Serialize};
use crate::bot::MasterBot;
use crate::youtube_dl::AudioMetadata;
+mod api;
+mod bot_executor;
+mod default;
mod front_end_cookie;
+mod tmtu;
+pub use bot_executor::*;
use front_end_cookie::FrontEnd;
pub struct WebServerArgs {
@@ -33,9 +34,13 @@ pub async fn start(args: WebServerArgs) -> std::io::Result<()> {
.data(bot_addr.clone())
.wrap(Logger::default())
.service(index)
- .service(tmtu_bot)
+ .service(get_bot)
.service(post_front_end)
- .service(web::scope("/api").service(get_bot_list).service(get_bot))
+ .service(
+ web::scope("/api")
+ .service(api::get_bot_list)
+ .service(api::get_bot),
+ )
.service(actix_files::Files::new("/static", "static/"))
})
.bind(args.bind_address)?
@@ -47,12 +52,6 @@ pub async fn start(args: WebServerArgs) -> std::io::Result<()> {
Ok(())
}
-pub struct BotExecutor(pub Arc<MasterBot>);
-
-impl Actor for BotExecutor {
- type Context = SyncContext<Self>;
-}
-
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
struct FrontEndForm {
@@ -60,74 +59,10 @@ struct FrontEndForm {
}
#[post("/front-end")]
-async fn post_front_end(form: web::Form<FrontEndForm>) -> Result<HttpResponse, Error> {
+async fn post_front_end(form: web::Form<FrontEndForm>) -> impl Responder {
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<Vec<String>, ()>;
-}
-
-impl Handler<BotNameListRequest> for BotExecutor {
- type Result = Result<Vec<String>, ()>;
-
- fn handle(&mut self, _: BotNameListRequest, _: &mut Self::Context) -> Self::Result {
- let bot = &self.0;
-
- Ok(bot.bot_names())
- }
-}
-
-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, _: BotDataListRequest, _: &mut Self::Context) -> Self::Result {
- let bot = &self.0;
-
- Ok(bot.bot_datas())
- }
-}
-
-struct BotDataRequest(String);
-
-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 OverviewTemplate<'a> {
- bots: &'a [BotData],
-}
-
-#[derive(Template)]
-#[template(path = "tmtu/index.htm")]
-struct TmtuTemplate {
- bot_names: Vec<String>,
- bot: Option<BotData>,
-}
-
#[derive(Debug, Serialize)]
pub struct BotData {
pub name: String,
@@ -139,96 +74,22 @@ pub struct BotData {
}
#[get("/")]
-async fn index(bot: web::Data<Addr<BotExecutor>>, front: FrontEnd) -> Result<HttpResponse, Error> {
+async fn index(bot: web::Data<Addr<BotExecutor>>, front: FrontEnd) -> impl Responder {
match front {
- FrontEnd::Lazy => lazy_index(bot).await,
- FrontEnd::Tmtu => tmtu_index(bot).await,
- }
-}
-
-async fn lazy_index(bot: web::Data<Addr<BotExecutor>>) -> Result<HttpResponse, Error> {
- let bot_datas = match bot.send(BotDataListRequest).await.unwrap() {
- Ok(data) => data,
- Err(_) => Vec::with_capacity(0),
- };
-
- OverviewTemplate {
- bots: &bot_datas[..],
- }
- .into_response()
-}
-
-async fn tmtu_index(bot: web::Data<Addr<BotExecutor>>) -> Result<HttpResponse, Error> {
- let bot_names = bot.send(BotNameListRequest).await.unwrap().unwrap();
-
- TmtuTemplate {
- bot_names,
- bot: None,
+ FrontEnd::Default => default::index(bot).await,
+ FrontEnd::Tmtu => tmtu::index(bot).await,
}
- .into_response()
}
-#[get("/tmtu/{name}")]
-async fn tmtu_bot(
+#[get("/bot/{name}")]
+async fn get_bot(
bot: web::Data<Addr<BotExecutor>>,
name: web::Path<String>,
front: FrontEnd,
-) -> Result<HttpResponse, Error> {
- 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<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)
+) -> impl Responder {
+ match front {
+ FrontEnd::Tmtu => tmtu::get_bot(bot, name.into_inner()).await,
+ FrontEnd::Default => Ok(HttpResponse::Found().header(header::LOCATION, "/").finish()),
}
}
diff --git a/src/web_server/api.rs b/src/web_server/api.rs
new file mode 100644
index 0000000..4deedad
--- /dev/null
+++ b/src/web_server/api.rs
@@ -0,0 +1,48 @@
+use actix::Addr;
+use actix_web::{get, web, HttpResponse, Responder, ResponseError};
+use derive_more::Display;
+use serde::Serialize;
+
+use crate::web_server::{BotDataListRequest, BotDataRequest, BotExecutor};
+
+#[get("/bots")]
+pub 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)
+}
+
+#[get("/bots/{name}")]
+pub 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)
+ }
+}
+
+#[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"),
+ }),
+ }
+ }
+}
diff --git a/src/web_server/bot_executor.rs b/src/web_server/bot_executor.rs
new file mode 100644
index 0000000..fde3c08
--- /dev/null
+++ b/src/web_server/bot_executor.rs
@@ -0,0 +1,63 @@
+use std::sync::Arc;
+
+use actix::{Actor, Handler, Message, SyncContext};
+
+use crate::bot::MasterBot;
+use crate::web_server::BotData;
+
+pub struct BotExecutor(pub Arc<MasterBot>);
+
+impl Actor for BotExecutor {
+ type Context = SyncContext<Self>;
+}
+
+pub struct BotNameListRequest;
+
+impl Message for BotNameListRequest {
+ // A plain Vec does not work for some reason
+ type Result = Result<Vec<String>, ()>;
+}
+
+impl Handler<BotNameListRequest> for BotExecutor {
+ type Result = Result<Vec<String>, ()>;
+
+ fn handle(&mut self, _: BotNameListRequest, _: &mut Self::Context) -> Self::Result {
+ let bot = &self.0;
+
+ Ok(bot.bot_names())
+ }
+}
+
+pub 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, _: BotDataListRequest, _: &mut Self::Context) -> Self::Result {
+ let bot = &self.0;
+
+ Ok(bot.bot_datas())
+ }
+}
+
+pub struct BotDataRequest(pub String);
+
+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)
+ }
+}
diff --git a/src/web_server/default.rs b/src/web_server/default.rs
new file mode 100644
index 0000000..b3c8291
--- /dev/null
+++ b/src/web_server/default.rs
@@ -0,0 +1,24 @@
+use actix::Addr;
+use actix_web::{web, Error, HttpResponse};
+use askama::actix_web::TemplateIntoResponse;
+use askama::Template;
+
+use crate::web_server::{filters, BotData, BotDataListRequest, BotExecutor};
+
+#[derive(Template)]
+#[template(path = "index.htm")]
+struct OverviewTemplate<'a> {
+ bots: &'a [BotData],
+}
+
+pub async fn index(bot: web::Data<Addr<BotExecutor>>) -> Result<HttpResponse, Error> {
+ let bot_datas = match bot.send(BotDataListRequest).await.unwrap() {
+ Ok(data) => data,
+ Err(_) => Vec::with_capacity(0),
+ };
+
+ OverviewTemplate {
+ bots: &bot_datas[..],
+ }
+ .into_response()
+}
diff --git a/src/web_server/front_end_cookie.rs b/src/web_server/front_end_cookie.rs
index 0207933..4812d0d 100644
--- a/src/web_server/front_end_cookie.rs
+++ b/src/web_server/front_end_cookie.rs
@@ -10,7 +10,7 @@ use serde::Deserialize;
#[derive(PartialEq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum FrontEnd {
- Lazy,
+ Default,
Tmtu,
}
@@ -19,7 +19,7 @@ impl FrontEnd {
fn cookie(&self) -> String {
let name = match self {
- FrontEnd::Lazy => "lazy",
+ FrontEnd::Default => "default",
FrontEnd::Tmtu => "tmtu",
};
@@ -39,7 +39,7 @@ impl FromRequest for FrontEnd {
let mut split = c.split('=');
if Some(Self::COOKIE_NAME) == split.next() {
match split.next() {
- Some("lazy") => return ok(FrontEnd::Lazy),
+ Some("default") => return ok(FrontEnd::Default),
Some("tmtu") => return ok(FrontEnd::Tmtu),
_ => (),
}
@@ -48,7 +48,7 @@ impl FromRequest for FrontEnd {
}
}
- ok(FrontEnd::Lazy)
+ ok(FrontEnd::Default)
}
}
diff --git a/src/web_server/tmtu.rs b/src/web_server/tmtu.rs
new file mode 100644
index 0000000..0645ee4
--- /dev/null
+++ b/src/web_server/tmtu.rs
@@ -0,0 +1,41 @@
+use actix::Addr;
+use actix_web::{http::header, web, Error, HttpResponse};
+use askama::actix_web::TemplateIntoResponse;
+use askama::Template;
+
+use crate::web_server::{filters, BotData, BotDataRequest, BotExecutor, BotNameListRequest};
+
+#[derive(Template)]
+#[template(path = "tmtu/index.htm")]
+struct TmtuTemplate {
+ bot_names: Vec<String>,
+ bot: Option<BotData>,
+}
+
+pub async fn index(bot: web::Data<Addr<BotExecutor>>) -> Result<HttpResponse, Error> {
+ let bot_names = bot.send(BotNameListRequest).await.unwrap().unwrap();
+
+ TmtuTemplate {
+ bot_names,
+ bot: None,
+ }
+ .into_response()
+}
+
+pub async fn get_bot(
+ bot: web::Data<Addr<BotExecutor>>,
+ name: String,
+) -> Result<HttpResponse, Error> {
+ let bot_names = bot.send(BotNameListRequest).await.unwrap().unwrap();
+
+ if let Some(bot) = bot.send(BotDataRequest(name)).await.unwrap() {
+ TmtuTemplate {
+ bot_names,
+ bot: Some(bot),
+ }
+ .into_response()
+ } else {
+ // TODO to 404 or not to 404
+ Ok(HttpResponse::Found().header(header::LOCATION, "/").finish())
+ }
+}
diff --git a/src/youtube_dl.rs b/src/youtube_dl.rs
index 99e50e7..89b1477 100644
--- a/src/youtube_dl.rs
+++ b/src/youtube_dl.rs
@@ -15,22 +15,11 @@ pub struct AudioMetadata {
pub title: String,
pub thumbnail: Option<String>,
#[serde(default, deserialize_with = "duration_deserialize")]
- #[serde(serialize_with = "duration_serialize")]
pub duration: Option<Duration>,
#[serde(skip)]
pub added_by: String,
}
-fn duration_serialize<S>(d: &Option<Duration>, s: S) -> Result<S::Ok, S::Error>
-where
- S: serde::Serializer,
-{
- match d {
- Some(d) => s.serialize_some(&d.as_secs_f64()),
- None => s.serialize_none(),
- }
-}
-
fn duration_deserialize<'de, D>(deserializer: D) -> Result<Option<Duration>, D::Error>
where
D: serde::Deserializer<'de>,
diff --git a/templates/tmtu/index.htm b/templates/tmtu/index.htm
index e7d1922..785e653 100644
--- a/templates/tmtu/index.htm
+++ b/templates/tmtu/index.htm
@@ -75,9 +75,9 @@
{% endmatch %}
{% for name in bot_names %}
{% if name.clone() == bot_name %}
- <li><a href="/tmtu/{{ name }}" class="botname selected">{{ name }}</a></li>
+ <li><a href="/bot/{{ name }}" class="botname selected">{{ name }}</a></li>
{% else %}
- <li><a href="/tmtu/{{ name }}" class="botname">{{ name }}</a></li>
+ <li><a href="/bot/{{ name }}" class="botname">{{ name }}</a></li>
{% endif %}
{% endfor %}
</ol>