1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#![feature(box_syntax)]
use crate::frontend::{pages::MyError, style::CSS_BUNDLE};
use anyhow::anyhow;
use database::Database;
use frontend::pages::{home::page_home, node::page_library_node};
use jellyremuxer::{RemuxerContext, SendWriter};
use library::Library;
use log::{debug, warn};
use rocket::{
get,
http::ContentType,
launch,
response::stream::{ByteStream, ReaderStream},
routes, State,
};
use std::{fs::read_to_string, sync::Arc};
use tokio::{
io::{duplex, DuplexStream},
sync::mpsc,
};
use tokio_util::io::SyncIoBridge;
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?<selection>")]
fn stream(
selection: String,
state: &State<AppState>,
) -> Result<(ContentType, ReaderStream![DuplexStream]), MyError> {
let (a, b) = duplex(8196);
let item = state.library.nested("mili-bento-box-bivouac")?.get_item()?;
let remuxer = state.remuxer.clone();
let selection = selection
.split(",")
.map(|e| e.parse().map_err(|_| anyhow!("invalid number")))
.into_iter()
.collect::<Result<Vec<_>, _>>()?;
let b = SyncIoBridge::new(b);
tokio::task::spawn_blocking(move || {
if let Err(e) = remuxer.generate_into(
b,
item.fs_path.parent().unwrap().to_path_buf(),
item.data.clone(),
selection,
) {
warn!("stream stopped: {e}")
}
});
debug!("starting stream");
Ok((ContentType::WEBM, ReaderStream::one(a)))
}
pub struct AppState {
pub database: Database,
pub library: Library,
pub remuxer: Arc<RemuxerContext>,
}
#[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],
)
}
|