2021-10-24 22:48:10 +00:00
|
|
|
use serde_json::json;
|
2021-10-25 00:51:26 +00:00
|
|
|
use std::net::IpAddr;
|
2021-10-24 22:48:10 +00:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
|
|
use warb::{hyper::StatusCode, Filter, Reply};
|
|
|
|
use warp as warb; // i think it's funny
|
|
|
|
|
|
|
|
mod events;
|
2022-02-15 23:15:06 +00:00
|
|
|
mod utils;
|
2021-10-25 00:51:26 +00:00
|
|
|
mod viewer_connection;
|
2021-10-24 22:48:10 +00:00
|
|
|
mod watch_session;
|
|
|
|
|
|
|
|
use serde::Deserialize;
|
|
|
|
|
|
|
|
use crate::{
|
2021-12-03 20:51:06 +00:00
|
|
|
viewer_connection::ws_subscribe,
|
|
|
|
watch_session::{get_session, SubtitleTrack, WatchSession, SESSIONS},
|
2021-10-24 22:48:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct StartSessionBody {
|
2021-10-25 01:59:52 +00:00
|
|
|
video_url: String,
|
2021-10-24 22:48:10 +00:00
|
|
|
#[serde(default = "Vec::new")]
|
2021-10-25 01:59:52 +00:00
|
|
|
subtitle_tracks: Vec<SubtitleTrack>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct SubscribeQuery {
|
|
|
|
nickname: String,
|
2022-01-18 11:42:55 +00:00
|
|
|
colour: String,
|
2021-10-24 22:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-02-15 23:15:06 +00:00
|
|
|
async fn get_emoji_list() -> Result<impl warb::Reply, warb::Rejection> {
|
|
|
|
use tokio_stream::{wrappers::ReadDirStream, StreamExt};
|
|
|
|
|
|
|
|
let dir = tokio::fs::read_dir("frontend/emojis")
|
|
|
|
.await
|
|
|
|
.expect("Couldn't read emojis directory!");
|
|
|
|
|
|
|
|
let files = ReadDirStream::new(dir)
|
|
|
|
.filter_map(|r| r.ok())
|
|
|
|
.map(|e| e.file_name().to_string_lossy().to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.await;
|
|
|
|
|
|
|
|
Ok(warb::reply::json(&files))
|
|
|
|
}
|
|
|
|
|
2021-10-24 22:48:10 +00:00
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
|
|
|
let start_session_route = warb::path!("start_session")
|
|
|
|
.and(warb::path::end())
|
|
|
|
.and(warb::post())
|
|
|
|
.and(warb::body::json())
|
|
|
|
.map(|body: StartSessionBody| {
|
|
|
|
let mut sessions = SESSIONS.lock().unwrap();
|
|
|
|
let session_uuid = Uuid::new_v4();
|
|
|
|
let session = WatchSession::new(body.video_url, body.subtitle_tracks);
|
|
|
|
let session_view = session.view();
|
|
|
|
sessions.insert(session_uuid, session);
|
|
|
|
|
|
|
|
warb::reply::json(&json!({ "id": session_uuid.to_string(), "session": session_view }))
|
|
|
|
});
|
|
|
|
|
2022-02-15 23:15:06 +00:00
|
|
|
let get_emoji_route = warb::path!("emojis").and_then(get_emoji_list);
|
|
|
|
|
2021-10-24 22:48:10 +00:00
|
|
|
enum RequestedSession {
|
|
|
|
Session(Uuid, WatchSession),
|
|
|
|
Error(warb::reply::WithStatus<warb::reply::Json>),
|
|
|
|
}
|
|
|
|
|
|
|
|
let get_running_session = warb::path::path("sess")
|
|
|
|
.and(warb::path::param::<String>())
|
|
|
|
.map(|session_id: String| {
|
|
|
|
if let Ok(uuid) = Uuid::parse_str(&session_id) {
|
2021-10-25 00:51:26 +00:00
|
|
|
get_session(uuid)
|
|
|
|
.map(|sess| RequestedSession::Session(uuid, sess))
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
RequestedSession::Error(warb::reply::with_status(
|
|
|
|
warb::reply::json(&json!({ "error": "session does not exist" })),
|
|
|
|
StatusCode::NOT_FOUND,
|
|
|
|
))
|
|
|
|
})
|
2021-10-24 22:48:10 +00:00
|
|
|
} else {
|
|
|
|
RequestedSession::Error(warb::reply::with_status(
|
|
|
|
warb::reply::json(&json!({ "error": "invalid session UUID" })),
|
|
|
|
StatusCode::BAD_REQUEST,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let get_status_route = get_running_session
|
|
|
|
.and(warb::path::end())
|
|
|
|
.map(|requested_session| match requested_session {
|
|
|
|
RequestedSession::Session(_, sess) => {
|
|
|
|
warb::reply::with_status(warb::reply::json(&sess.view()), StatusCode::OK)
|
|
|
|
}
|
|
|
|
RequestedSession::Error(e) => e,
|
|
|
|
});
|
|
|
|
|
|
|
|
let ws_subscribe_route = get_running_session
|
2021-10-25 01:59:52 +00:00
|
|
|
.and(warb::path!("subscribe"))
|
|
|
|
.and(warb::query())
|
|
|
|
.and(warb::ws())
|
2021-10-24 22:48:10 +00:00
|
|
|
.map(
|
2021-10-25 01:59:52 +00:00
|
|
|
|requested_session, query: SubscribeQuery, ws: warb::ws::Ws| match requested_session {
|
2021-10-24 22:48:10 +00:00
|
|
|
RequestedSession::Session(uuid, _) => ws
|
2022-01-18 11:42:55 +00:00
|
|
|
.on_upgrade(move |ws| ws_subscribe(uuid, query.nickname, query.colour, ws))
|
2021-10-24 22:48:10 +00:00
|
|
|
.into_response(),
|
|
|
|
RequestedSession::Error(error_response) => error_response.into_response(),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
let routes = start_session_route
|
|
|
|
.or(get_status_route)
|
|
|
|
.or(ws_subscribe_route)
|
2022-02-15 23:15:06 +00:00
|
|
|
.or(get_emoji_route)
|
2021-10-24 22:48:10 +00:00
|
|
|
.or(warb::path::end().and(warb::fs::file("frontend/index.html")))
|
|
|
|
.or(warb::fs::dir("frontend"));
|
|
|
|
|
2021-10-24 23:31:24 +00:00
|
|
|
let ip = std::env::var("IP")
|
2021-10-24 23:13:25 +00:00
|
|
|
.ok()
|
|
|
|
.and_then(|s| s.parse::<IpAddr>().ok())
|
|
|
|
.unwrap_or_else(|| [127, 0, 0, 1].into());
|
|
|
|
let port = std::env::var("PORT")
|
|
|
|
.ok()
|
|
|
|
.and_then(|s| s.parse::<u16>().ok())
|
|
|
|
.unwrap_or(3000);
|
2021-10-24 23:24:56 +00:00
|
|
|
|
2021-10-24 23:31:24 +00:00
|
|
|
println!("Listening at http://{}:{} ...", &ip, &port);
|
|
|
|
warb::serve(routes).run((ip, port)).await;
|
2021-10-24 22:48:10 +00:00
|
|
|
}
|