chore: clean up and optimisation
This commit is contained in:
+69
-80
@@ -4,6 +4,7 @@ use std::{
|
||||
Arc, LazyLock,
|
||||
atomic::{AtomicI32, Ordering},
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use axum_extra::extract::{CookieJar, cookie::Cookie};
|
||||
@@ -30,7 +31,7 @@ use axum::{
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use entity::{auth_session, stream_key, stream_session, users};
|
||||
use sea_orm::{DatabaseConnection, EntityTrait, IntoActiveModel, QueryFilter};
|
||||
use sea_orm::{DatabaseConnection, EntityTrait, IntoActiveModel};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sysinfo::System;
|
||||
use tokio::{
|
||||
@@ -80,7 +81,13 @@ impl HttpServer {
|
||||
];
|
||||
|
||||
let cors = CorsLayer::new()
|
||||
.allow_methods([Method::GET, Method::POST, Method::PATCH, Method::DELETE, Method::OPTIONS])
|
||||
.allow_methods([
|
||||
Method::GET,
|
||||
Method::POST,
|
||||
Method::PATCH,
|
||||
Method::DELETE,
|
||||
Method::OPTIONS,
|
||||
])
|
||||
.allow_headers([
|
||||
AUTHORIZATION,
|
||||
ACCEPT,
|
||||
@@ -103,9 +110,15 @@ impl HttpServer {
|
||||
// .route("/api/whip", post(handle_whip_injest))
|
||||
.route("/api/login", post(login_handler))
|
||||
.route("/api/stream/{slug}", post(stream_handler))
|
||||
.route("/stream", post(handle_whip_injest))
|
||||
.route("/stream/{slug}", delete(handle_whip_injest_delete).patch(handle_whip_injest_patch))
|
||||
.route("/api/whip/{slug}", delete(handle_whip_injest_delete).patch(handle_whip_injest_patch))
|
||||
.route("/api/whip", post(handle_whip_injest))
|
||||
.route(
|
||||
"/api/whip/{slug}",
|
||||
delete(handle_whip_injest_delete).patch(handle_whip_injest_patch),
|
||||
)
|
||||
// .route(
|
||||
// "/api/whip/{slug}",
|
||||
// delete(handle_whip_injest_delete).patch(handle_whip_injest_patch),
|
||||
// )
|
||||
.route("/api/meow", get(meow_handler))
|
||||
.route("/api/health", get(health_handler))
|
||||
.route("/api/uptime", get(uptime_handler))
|
||||
@@ -125,11 +138,6 @@ impl HttpServer {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct StreamCatalog {
|
||||
active_streams: Vec<StreamListing>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct StreamListing {
|
||||
label: String,
|
||||
@@ -181,39 +189,20 @@ async fn catalog_handler(
|
||||
) -> Result<impl IntoResponse, HttpError> {
|
||||
let streams = stream_session::Model::get_all_active_sessions(&state.db).await?;
|
||||
debug!("{:#?}", streams);
|
||||
let catalog: Vec<StreamListing> = futures::future::join_all(streams.iter().map(|listing| {
|
||||
let db = state.db.clone();
|
||||
let stream_key_id = listing.stream_key_id;
|
||||
let state2 = state.clone();
|
||||
async move {
|
||||
let key_info = stream_key::Entity::find_by_id(stream_key_id)
|
||||
.one(&db)
|
||||
.await?
|
||||
.ok_or(HttpError::NotFound)?;
|
||||
let user = users::Entity::find_by_id(key_info.user_id)
|
||||
.one(&db)
|
||||
.await?
|
||||
.ok_or(HttpError::NotFound)?;
|
||||
let meow = state2
|
||||
.appstate
|
||||
.clone()
|
||||
.lock()
|
||||
.await
|
||||
.stream_sessions
|
||||
.get(&key_info.id)
|
||||
.ok_or(HttpError::NotFound)?
|
||||
.started_at;
|
||||
Ok::<_, HttpError>(StreamListing {
|
||||
id: stream_key_id,
|
||||
label: key_info.label,
|
||||
user: user.username,
|
||||
started_at: meow,
|
||||
})
|
||||
}
|
||||
}))
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, HttpError>>()?;
|
||||
let catalog: Vec<StreamListing> = state
|
||||
.appstate
|
||||
.lock()
|
||||
.await
|
||||
.stream_sessions
|
||||
.iter()
|
||||
.map(|x| StreamListing {
|
||||
id: x.stream_key_id,
|
||||
label: x.stream_key_label.clone(),
|
||||
user: x.stream_key_user.clone(),
|
||||
started_at: x.started_at,
|
||||
})
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
Ok(Json(catalog))
|
||||
}
|
||||
|
||||
@@ -297,16 +286,6 @@ async fn create_stream_key_handler(
|
||||
Ok(StatusCode::CREATED)
|
||||
}
|
||||
|
||||
struct StreamKeys {
|
||||
keys: Vec<StreamKey>,
|
||||
}
|
||||
|
||||
struct StreamKey {
|
||||
id: i32,
|
||||
label: String,
|
||||
value: String,
|
||||
}
|
||||
|
||||
async fn get_all_stream_keys(
|
||||
State(state): State<Arc<HttpServer>>,
|
||||
auth: AuthUser,
|
||||
@@ -321,11 +300,6 @@ struct LoginForm {
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct LoginResponse {
|
||||
session_token: String,
|
||||
}
|
||||
|
||||
struct DevFlag(bool);
|
||||
|
||||
impl<S> FromRequestParts<S> for DevFlag
|
||||
@@ -457,7 +431,7 @@ async fn stream_handler(
|
||||
})?;
|
||||
|
||||
info!(request_id = request_id_clone, slug = %slug, stream_key_id, "WHEP offer received");
|
||||
let mut accept_rx = state.accept_rx.activate_cloned();
|
||||
let accept_rx = state.accept_rx.activate_cloned();
|
||||
// The webrtc worker owning the receiver died if this fails.
|
||||
state
|
||||
.offer_tx
|
||||
@@ -469,35 +443,50 @@ async fn stream_handler(
|
||||
"offer sent, waiting for answer"
|
||||
);
|
||||
|
||||
let reply_body = String::new();
|
||||
while let Ok(answer) = accept_rx.recv().await {
|
||||
debug!(request_id = request_id_clone, "received answer candidate");
|
||||
if let Some(reply) = answer.1 {
|
||||
if answer.0 == request_id_clone {
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::CREATED)
|
||||
.header("content-type", "application/sdp")
|
||||
.body(reply)
|
||||
.unwrap());
|
||||
} else {
|
||||
continue;
|
||||
// Bound the wait: a WebRTC setup failure (malformed SDP, codec mismatch)
|
||||
// would otherwise leave this HTTP request hanging forever.
|
||||
match tokio::time::timeout(Duration::from_secs(10), async {
|
||||
let mut accept_rx = accept_rx;
|
||||
loop {
|
||||
match accept_rx.recv().await {
|
||||
Ok(answer) if answer.0 == request_id_clone => return Some(answer.1),
|
||||
Ok(_) => continue,
|
||||
Err(_) => return None,
|
||||
}
|
||||
} else if answer.0 == request_id_clone {
|
||||
}
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(Some(Some(reply))) => {
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::CREATED)
|
||||
.header("content-type", "application/sdp")
|
||||
.body(reply)
|
||||
.unwrap());
|
||||
}
|
||||
Ok(Some(None)) => {
|
||||
return Ok(Response::builder()
|
||||
.status(StatusCode::UNSUPPORTED_MEDIA_TYPE)
|
||||
.body(String::new())
|
||||
.unwrap());
|
||||
}
|
||||
}
|
||||
info!(
|
||||
request_id = request_id_clone,
|
||||
"answer channel closed without a match"
|
||||
);
|
||||
Ok(None) => {
|
||||
info!(
|
||||
request_id = request_id_clone,
|
||||
"answer channel closed without a match"
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
warn!(
|
||||
request_id = request_id_clone,
|
||||
"timed out waiting for WHEP answer"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Response::builder()
|
||||
.status(StatusCode::CREATED)
|
||||
.header("content-type", "application/sdp")
|
||||
.body(reply_body)
|
||||
.status(StatusCode::GATEWAY_TIMEOUT)
|
||||
.body(String::new())
|
||||
.unwrap())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user