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