chore: clean up and optimisation

This commit is contained in:
2026-08-07 16:06:01 +01:00
parent 5f152e9db7
commit 3287a0ed7c
6 changed files with 132 additions and 170 deletions
+69 -80
View File
@@ -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())
}