pinakes-server: eliminate unwraps from response builders
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I6d80e505963dfa4d117f6b33d69fc1516a6a6964
This commit is contained in:
parent
01fc2021c0
commit
1fe2c7998d
3 changed files with 67 additions and 64 deletions
|
|
@ -33,35 +33,35 @@ pub fn create_router_with_tls(
|
|||
.per_second(1)
|
||||
.burst_size(100)
|
||||
.finish()
|
||||
.unwrap(),
|
||||
.expect("valid global rate limit config"),
|
||||
);
|
||||
|
||||
// Strict rate limit for login: 5 requests/min per IP
|
||||
let login_governor = Arc::new(
|
||||
GovernorConfigBuilder::default()
|
||||
.per_second(12) // replenish one every 12 seconds
|
||||
.burst_size(5)
|
||||
.finish()
|
||||
.unwrap(),
|
||||
.per_second(12) // replenish one every 12 seconds
|
||||
.burst_size(5)
|
||||
.finish()
|
||||
.expect("valid login rate limit config"),
|
||||
);
|
||||
|
||||
// Rate limit for search: 10 requests/min per IP
|
||||
let search_governor = Arc::new(
|
||||
GovernorConfigBuilder::default()
|
||||
.per_second(6) // replenish one every 6 seconds (10/min)
|
||||
.burst_size(10)
|
||||
.finish()
|
||||
.unwrap(),
|
||||
.per_second(6) // replenish one every 6 seconds (10/min)
|
||||
.burst_size(10)
|
||||
.finish()
|
||||
.expect("valid search rate limit config"),
|
||||
);
|
||||
|
||||
// Rate limit for streaming: 5 requests per IP (very restrictive for
|
||||
// concurrent streams)
|
||||
let stream_governor = Arc::new(
|
||||
GovernorConfigBuilder::default()
|
||||
.per_second(60) // replenish slowly (one per minute)
|
||||
.burst_size(5) // max 5 concurrent connections
|
||||
.finish()
|
||||
.unwrap(),
|
||||
.per_second(60) // replenish slowly (one per minute)
|
||||
.burst_size(5) // max 5 concurrent connections
|
||||
.finish()
|
||||
.expect("valid stream rate limit config"),
|
||||
);
|
||||
|
||||
// Login route with strict rate limiting
|
||||
|
|
@ -501,9 +501,9 @@ pub fn create_router_with_tls(
|
|||
// CORS: allow same-origin by default, plus the desktop UI origin
|
||||
let cors = CorsLayer::new()
|
||||
.allow_origin([
|
||||
"http://localhost:3000".parse::<HeaderValue>().unwrap(),
|
||||
"http://127.0.0.1:3000".parse::<HeaderValue>().unwrap(),
|
||||
"tauri://localhost".parse::<HeaderValue>().unwrap(),
|
||||
HeaderValue::from_static("http://localhost:3000"),
|
||||
HeaderValue::from_static("http://127.0.0.1:3000"),
|
||||
HeaderValue::from_static("tauri://localhost"),
|
||||
])
|
||||
.allow_methods([
|
||||
Method::GET,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,36 @@ use uuid::Uuid;
|
|||
|
||||
use crate::{error::ApiError, state::AppState};
|
||||
|
||||
fn build_response(
|
||||
content_type: &str,
|
||||
body: impl Into<axum::body::Body>,
|
||||
) -> Result<axum::response::Response, ApiError> {
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", content_type)
|
||||
.body(body.into())
|
||||
.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("failed to build response: {e}"),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn build_response_with_status(
|
||||
status: StatusCode,
|
||||
headers: &[(&str, &str)],
|
||||
body: impl Into<axum::body::Body>,
|
||||
) -> Result<axum::response::Response, ApiError> {
|
||||
let mut builder = axum::response::Response::builder().status(status);
|
||||
for (name, value) in headers {
|
||||
builder = builder.header(*name, *value);
|
||||
}
|
||||
builder.body(body.into()).map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("failed to build response: {e}"),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn escape_xml(s: &str) -> String {
|
||||
s.replace('&', "&")
|
||||
.replace('<', "<")
|
||||
|
|
@ -42,12 +72,7 @@ pub async fn hls_master_playlist(
|
|||
));
|
||||
}
|
||||
|
||||
Ok(
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", "application/vnd.apple.mpegurl")
|
||||
.body(axum::body::Body::from(playlist))
|
||||
.unwrap(),
|
||||
)
|
||||
build_response("application/vnd.apple.mpegurl", playlist)
|
||||
}
|
||||
|
||||
pub async fn hls_variant_playlist(
|
||||
|
|
@ -84,12 +109,7 @@ pub async fn hls_variant_playlist(
|
|||
}
|
||||
playlist.push_str("#EXT-X-ENDLIST\n");
|
||||
|
||||
Ok(
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", "application/vnd.apple.mpegurl")
|
||||
.body(axum::body::Body::from(playlist))
|
||||
.unwrap(),
|
||||
)
|
||||
build_response("application/vnd.apple.mpegurl", playlist)
|
||||
}
|
||||
|
||||
pub async fn hls_segment(
|
||||
|
|
@ -127,21 +147,14 @@ pub async fn hls_segment(
|
|||
))
|
||||
})?;
|
||||
|
||||
return Ok(
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", "video/MP2T")
|
||||
.body(axum::body::Body::from(data))
|
||||
.unwrap(),
|
||||
);
|
||||
return build_response("video/MP2T", data);
|
||||
}
|
||||
|
||||
// Session exists but segment not ready yet
|
||||
return Ok(
|
||||
axum::response::Response::builder()
|
||||
.status(StatusCode::ACCEPTED)
|
||||
.header("Retry-After", "2")
|
||||
.body(axum::body::Body::from("segment not yet available"))
|
||||
.unwrap(),
|
||||
return build_response_with_status(
|
||||
StatusCode::ACCEPTED,
|
||||
&[("Retry-After", "2")],
|
||||
"segment not yet available",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -200,12 +213,7 @@ pub async fn dash_manifest(
|
|||
</MPD>"#
|
||||
);
|
||||
|
||||
Ok(
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", "application/dash+xml")
|
||||
.body(axum::body::Body::from(mpd))
|
||||
.unwrap(),
|
||||
)
|
||||
build_response("application/dash+xml", mpd)
|
||||
}
|
||||
|
||||
pub async fn dash_segment(
|
||||
|
|
@ -242,20 +250,13 @@ pub async fn dash_segment(
|
|||
))
|
||||
})?;
|
||||
|
||||
return Ok(
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", "video/mp4")
|
||||
.body(axum::body::Body::from(data))
|
||||
.unwrap(),
|
||||
);
|
||||
return build_response("video/mp4", data);
|
||||
}
|
||||
|
||||
return Ok(
|
||||
axum::response::Response::builder()
|
||||
.status(StatusCode::ACCEPTED)
|
||||
.header("Retry-After", "2")
|
||||
.body(axum::body::Body::from("segment not yet available"))
|
||||
.unwrap(),
|
||||
return build_response_with_status(
|
||||
StatusCode::ACCEPTED,
|
||||
&[("Retry-After", "2")],
|
||||
"segment not yet available",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,12 +97,14 @@ pub async fn get_subtitle_content(
|
|||
SubtitleFormat::Srt => "application/x-subrip",
|
||||
_ => "text/plain",
|
||||
};
|
||||
Ok(
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", content_type)
|
||||
.body(axum::body::Body::from(content))
|
||||
.unwrap(),
|
||||
)
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", content_type)
|
||||
.body(axum::body::Body::from(content))
|
||||
.map_err(|e| {
|
||||
ApiError(pinakes_core::error::PinakesError::InvalidOperation(
|
||||
format!("failed to build response: {e}"),
|
||||
))
|
||||
})
|
||||
} else {
|
||||
Err(ApiError(
|
||||
pinakes_core::error::PinakesError::InvalidOperation(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue