pinakes-server: eliminate unwraps from response builders

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I6d80e505963dfa4d117f6b33d69fc1516a6a6964
This commit is contained in:
raf 2026-03-07 16:55:43 +03:00
commit 1fe2c7998d
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
3 changed files with 67 additions and 64 deletions

View file

@ -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('&', "&amp;")
.replace('<', "&lt;")
@ -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",
);
}

View file

@ -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(