#![feature(box_syntax)] use crate::frontend::{pages::MyError, style::CSS_BUNDLE}; use database::Database; use frontend::pages::{home::page_home, node::page_library_node}; use jellyremuxer::{RemuxerContext, SendWriter}; use library::Library; use log::debug; use rocket::{get, http::ContentType, launch, response::stream::ByteStream, routes, State}; use std::{fs::read_to_string, sync::Arc}; use tokio::sync::mpsc; pub mod database; pub mod frontend; pub mod library; #[get("/assets/style.css")] async fn assets_style() -> (ContentType, String) { ( ContentType::CSS, if cfg!(debug_assertions) { read_to_string("server/src/frontend/style/layout.css").unwrap() } else { CSS_BUNDLE.to_string() }, ) } #[get("/stream?")] fn stream( selection: String, state: &State, ) -> Result<(ContentType, ByteStream![Vec]), MyError> { let (tx, mut rx) = mpsc::channel(16); let item = state.library.nested("mili-bento-box-bivouac")?.get_item()?; debug!("generating matroska"); let remuxer = state.remuxer.clone(); tokio::task::spawn_blocking(move || { remuxer .generate_into( SendWriter(tx), // SyncIoBridge() item.fs_path.parent().unwrap().to_path_buf(), item.data.clone(), selection.split(",").map(|e| e.parse().unwrap()).collect(), ) .unwrap(); }); debug!("starting stream"); Ok(( ContentType::WEBM, ByteStream! { while let Some(x) = rx.recv().await { debug!("yield {x:?}"); yield x } }, )) } pub struct AppState { pub database: Database, pub library: Library, pub remuxer: Arc, } #[launch] fn rocket() -> _ { env_logger::init_from_env("LOG"); let db_path = std::env::var("DB_PATH").unwrap_or("data/db".to_string()); let lib_path = std::env::var("LIB_PATH").unwrap_or("data/library".to_string()); let state = AppState { remuxer: RemuxerContext::new(), library: Library::open(&lib_path).unwrap(), database: Database::open(&db_path).unwrap(), }; rocket::build().manage(state).mount( "/", routes![page_home, page_library_node, assets_style, stream], ) }