From cef96884c6b22c6742590ea2cac830f26c33297e Mon Sep 17 00:00:00 2001 From: Florian THIERRY Date: Fri, 17 Jul 2026 23:20:44 +0200 Subject: [PATCH] Try to stream the file in handler. --- backend/domain/src/video/error.rs | 1 + backend/exposition/src/lib.rs | 3 ++- backend/exposition/src/video/handler.rs | 28 +++++++++++++-------- backend/infrastructure/src/video/adapter.rs | 2 +- backend/infrastructure/src/video/model.rs | 10 ++++---- frontend/src/app/app.html | 8 ++++++ 6 files changed, 35 insertions(+), 17 deletions(-) diff --git a/backend/domain/src/video/error.rs b/backend/domain/src/video/error.rs index 1ebd4a6..f2c40e9 100644 --- a/backend/domain/src/video/error.rs +++ b/backend/domain/src/video/error.rs @@ -1,3 +1,4 @@ +#[derive(Debug)] pub enum VideoError { VideoDoesNotExists, FolderDoesNotExists, diff --git a/backend/exposition/src/lib.rs b/backend/exposition/src/lib.rs index 09f5ac8..86249cb 100644 --- a/backend/exposition/src/lib.rs +++ b/backend/exposition/src/lib.rs @@ -2,7 +2,7 @@ extern crate core; use actix_web::web::ServiceConfig; use actix_web::{get, web, HttpResponse, Responder}; -use crate::video::handler::{download_file, get_root_folder_content}; +use crate::video::handler::{download_file, get_root_folder_content, get_video_stream}; pub mod user; pub mod video; @@ -14,6 +14,7 @@ async fn health() -> impl Responder { pub fn init(cfg: &mut ServiceConfig) { cfg.service(download_file) + .service(get_video_stream) .service(get_root_folder_content); cfg.default_service(web::to(not_found)); } diff --git a/backend/exposition/src/video/handler.rs b/backend/exposition/src/video/handler.rs index 6cb9ea1..24c94d8 100644 --- a/backend/exposition/src/video/handler.rs +++ b/backend/exposition/src/video/handler.rs @@ -28,22 +28,30 @@ pub async fn get_video_stream( ) -> impl Responder { let video_result = video_service.get_video_stream(video_id.into_inner()); + match video_result { Ok(video) => { - if let Some(tokioVideoFile) = video.file.as_any().downcast_ref::() { - HttpResponse::Ok() - .content_type("application/octet-stream") - .streaming(async_stream::stream! { - let mut stream = FramedRead::new(tokioVideoFile.file, BytesCodec::new()); - while let Some(chunk) = stream.next().await { - yield chunk.map(|bytes| bytes.freeze()); - } - }) + if let Some(tokio_video_file) = video.file.as_any().downcast_ref::() { + // Clone the file to extend its lifetime into the streaming closure + let cloned_file = tokio_video_file.file.try_clone(); + + match cloned_file { + Ok(file) => HttpResponse::Ok() + .content_type("application/octet-stream") + .streaming(async_stream::stream! { + let mut stream = FramedRead::new(file, BytesCodec::new()); + while let Some(chunk) = stream.next().await { + yield chunk.map(|bytes| bytes.freeze()); + } + }), + Err(_) => HttpResponse::InternalServerError().body("Failed to clone video file") + } + } else { HttpResponse::InternalServerError().body("Video file format is not handled.") } } - Err(error) => HttpResponse::InternalServerError().body("C P T") + Err(error) => HttpResponse::InternalServerError().body(format!("{:?}", error)) } } diff --git a/backend/infrastructure/src/video/adapter.rs b/backend/infrastructure/src/video/adapter.rs index ddaa7ef..d514826 100644 --- a/backend/infrastructure/src/video/adapter.rs +++ b/backend/infrastructure/src/video/adapter.rs @@ -123,7 +123,7 @@ impl VideoPort for LibraryItemAdapter { id: video.id, name: video.name, format: AVI, - file: Box::new(TokioVideoFile::new(&video_file_path).map_err(|_| VideoError::FileReadingTechnicalIssue)?) + file: Box::new(TokioVideoFile::new(&video_file_path)) }; Ok(result) diff --git a/backend/infrastructure/src/video/model.rs b/backend/infrastructure/src/video/model.rs index c00d8fe..284914d 100644 --- a/backend/infrastructure/src/video/model.rs +++ b/backend/infrastructure/src/video/model.rs @@ -1,6 +1,6 @@ use std::any::Any; +use std::fs::File; use std::io::{Error, ErrorKind}; -use tokio::fs::File; use uuid::Uuid; use lumiere_domain::video::model::library_item::{LibraryItem, LibraryItemType, LibraryRawItem}; use lumiere_domain::video::model::video::VideoFile; @@ -10,10 +10,10 @@ pub struct TokioVideoFile { } impl TokioVideoFile { - pub fn new(file_path: &String) -> Result { - let rt = tokio::runtime::Runtime::new()?; - let file = rt.block_on(async { File::open(file_path).await })?; - Ok(Self { file }) + pub fn new(file_path: &String) -> Self { + Self { + file: File::open(file_path).expect(format!("Failed to open file {file_path}").as_str()) + } } } diff --git a/frontend/src/app/app.html b/frontend/src/app/app.html index fbabc16..f99d6f9 100644 --- a/frontend/src/app/app.html +++ b/frontend/src/app/app.html @@ -9,4 +9,12 @@ } +
+ @if (firstVideo(); as firstVideo) { + + } +