From beb0134dfc6f903fe9f36be4cd9a0b7623626f1a Mon Sep 17 00:00:00 2001 From: Florian THIERRY Date: Tue, 14 Jul 2026 21:35:55 +0200 Subject: [PATCH] Implement the video adapter to retrieve the root folder content. --- backend/application/src/video/service.rs | 4 +-- .../domain/src/video/model/library_item.rs | 5 +++- backend/domain/src/video/port.rs | 1 + backend/exposition/src/lib.rs | 5 ++-- backend/exposition/src/video/handler.rs | 22 ++++++++++++++- backend/exposition/src/video/mod.rs | 1 + backend/exposition/src/video/model.rs | 27 +++++++++++++++++++ .../video/video_format_content_type_mapper.rs | 22 +++++++-------- backend/infrastructure/src/video/adapter.rs | 23 ++++++++-------- backend/launcher/src/application_context.rs | 7 +++++ backend/launcher/src/main.rs | 2 +- 11 files changed, 90 insertions(+), 29 deletions(-) create mode 100644 backend/exposition/src/video/model.rs diff --git a/backend/application/src/video/service.rs b/backend/application/src/video/service.rs index 10c8536..c0dc932 100644 --- a/backend/application/src/video/service.rs +++ b/backend/application/src/video/service.rs @@ -18,12 +18,12 @@ impl VideoService { Self { video_port } } - pub fn list_root_folder(self) -> Result, VideoError> { + pub fn list_root_folder(&self) -> Result, VideoError> { let read_items_with_possibly_no_id = self.video_port.list_root_folder()?; let items_with_id = read_items_with_possibly_no_id.iter() .map(LibraryRawItem::map_to_library_item) .collect(); - self.video_port.save_all(items_with_id); + self.video_port.save_all(&items_with_id)?; Ok(items_with_id) } } diff --git a/backend/domain/src/video/model/library_item.rs b/backend/domain/src/video/model/library_item.rs index d66dda7..4082cab 100644 --- a/backend/domain/src/video/model/library_item.rs +++ b/backend/domain/src/video/model/library_item.rs @@ -1,17 +1,20 @@ use std::io::Read; use uuid::Uuid; +#[derive(Clone, Copy)] pub enum LibraryItemType { VIDEO, FOLDER } +#[derive(Clone)] pub struct LibraryItem { pub id: Uuid, pub name: String, pub r#type: LibraryItemType, } +#[derive(Clone)] pub struct LibraryRawItem { pub id: Option, pub name: String, @@ -21,7 +24,7 @@ impl LibraryRawItem { pub fn map_to_library_item(&self) -> LibraryItem { LibraryItem { id: self.id.unwrap_or(Uuid::new_v4()), - name: self.name, + name: self.name.clone(), r#type: self.r#type, } } diff --git a/backend/domain/src/video/port.rs b/backend/domain/src/video/port.rs index 9aab745..1a3f98a 100644 --- a/backend/domain/src/video/port.rs +++ b/backend/domain/src/video/port.rs @@ -8,6 +8,7 @@ pub trait VideoPort: Send + Sync { fn list_folder(&self, folder_id: Uuid) -> Result, VideoError>; fn get_video_stream(&self, video_id: Uuid) -> Result; fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError>; + fn save_all(&self, library_items: &Vec) -> Result<(), VideoError>; fn clone_box(&self) -> Box; } diff --git a/backend/exposition/src/lib.rs b/backend/exposition/src/lib.rs index 16d77be..09f5ac8 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; +use crate::video::handler::{download_file, get_root_folder_content}; pub mod user; pub mod video; @@ -13,7 +13,8 @@ async fn health() -> impl Responder { } pub fn init(cfg: &mut ServiceConfig) { - cfg.service(download_file); + cfg.service(download_file) + .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 f3c74ca..0b3b1c0 100644 --- a/backend/exposition/src/video/handler.rs +++ b/backend/exposition/src/video/handler.rs @@ -1,7 +1,12 @@ -use actix_web::{get, HttpResponse, Responder}; +use std::sync::Arc; +use actix_web::{get, web, HttpResponse, Responder}; use tokio::fs::File; use tokio_util::codec::{BytesCodec, FramedRead}; use futures_util::stream::StreamExt; +use lumiere_application::video::service::VideoService; +use lumiere_domain::video::error::VideoError; +use lumiere_domain::video::model::library_item::LibraryItem; +use crate::video::model::LibraryItemDto; #[get("/download")] pub async fn download_file() -> impl Responder { @@ -14,4 +19,19 @@ pub async fn download_file() -> impl Responder { yield chunk.map(|bytes| bytes.freeze()); } }) +} + +#[get("/library")] +pub async fn get_root_folder_content( + video_service: web::Data> +) -> impl Responder { + match video_service.list_root_folder() { + Ok(library_items) => { + let result: Vec = library_items.iter() + .map(LibraryItemDto::new) + .collect(); + HttpResponse::Ok().json(result) + } + Err(_) => HttpResponse::InternalServerError().finish() + } } \ No newline at end of file diff --git a/backend/exposition/src/video/mod.rs b/backend/exposition/src/video/mod.rs index 6ed9738..78d7477 100644 --- a/backend/exposition/src/video/mod.rs +++ b/backend/exposition/src/video/mod.rs @@ -1,2 +1,3 @@ pub mod handler; +pub mod model; pub mod video_format_content_type_mapper; \ No newline at end of file diff --git a/backend/exposition/src/video/model.rs b/backend/exposition/src/video/model.rs new file mode 100644 index 0000000..d8d4657 --- /dev/null +++ b/backend/exposition/src/video/model.rs @@ -0,0 +1,27 @@ +use lumiere_domain::video::model::library_item::{LibraryItem, LibraryItemType}; +use serde::Serialize; +use uuid::Uuid; + +#[derive(Serialize)] +pub struct LibraryItemDto { + pub id: Uuid, + pub name: String, + pub r#type: String +} + +impl LibraryItemDto { + pub fn new(library_item: &LibraryItem) -> Self { + Self { + id: library_item.id.clone(), + name: library_item.name.clone(), + r#type: Self::map_type_to_string(library_item.r#type) + } + } + + fn map_type_to_string(r#type: LibraryItemType) -> String { + match r#type { + LibraryItemType::VIDEO => String::from("VIDEO"), + LibraryItemType::FOLDER => String::from("FOLDER") + } + } +} \ No newline at end of file diff --git a/backend/exposition/src/video/video_format_content_type_mapper.rs b/backend/exposition/src/video/video_format_content_type_mapper.rs index 386aff1..67c5dc8 100644 --- a/backend/exposition/src/video/video_format_content_type_mapper.rs +++ b/backend/exposition/src/video/video_format_content_type_mapper.rs @@ -1,11 +1,11 @@ -use lumiere_domain::video::library_item::VideoFormat; - -pub fn map_to_content_type(video_format: &VideoFormat) -> &'static str { - match video_format { - VideoFormat::AVI => "video/x-msvideo", - VideoFormat::MKV => "video/x-matroska", - VideoFormat::MP4 => "video/mp4", - VideoFormat::WEBM => "video/webm", - VideoFormat::UNKNOWN => "application/octet-stream" - } -} \ No newline at end of file +// use lumiere_domain::video::library_item::VideoFormat; +// +// pub fn map_to_content_type(video_format: &VideoFormat) -> &'static str { +// match video_format { +// VideoFormat::AVI => "video/x-msvideo", +// VideoFormat::MKV => "video/x-matroska", +// VideoFormat::MP4 => "video/mp4", +// VideoFormat::WEBM => "video/webm", +// VideoFormat::UNKNOWN => "application/octet-stream" +// } +// } \ No newline at end of file diff --git a/backend/infrastructure/src/video/adapter.rs b/backend/infrastructure/src/video/adapter.rs index 845e8a0..bf24200 100644 --- a/backend/infrastructure/src/video/adapter.rs +++ b/backend/infrastructure/src/video/adapter.rs @@ -6,6 +6,7 @@ use uuid::Uuid; use std::env; use std::fs; +#[derive(Clone)] pub struct VideoAdapter { } @@ -50,20 +51,16 @@ impl VideoAdapter { Ok(items) } - pub fn get_all_library_items_from_db(&self) -> Result, VideoError> { + fn get_all_library_items_from_db(&self) -> Result, VideoError> { Ok(vec!()) } fn merge_item_lists(file_system_items: Vec, db_items: Vec) -> Vec { - let mut all_items: Vec = Vec::new(); + let file_system_items_which_are_not_in_database: Vec = file_system_items.into_iter() + .filter(|file_system_item| !Self::does_item_belong_to_db_items(&db_items, &file_system_item)) + .collect(); - db_items.iter().for_each(|item| all_items.push(*item)); - - file_system_items.iter() - .filter(|file_system_item| Self::does_item_belong_to_db_items(&db_items, file_system_item)) - .for_each(|file_system_item| all_items.push(*file_system_item)); - - all_items + db_items.into_iter().chain(file_system_items_which_are_not_in_database).collect() } fn does_item_belong_to_db_items(database_items: &Vec, file_system_item: &LibraryRawItem) -> bool { @@ -90,11 +87,15 @@ impl VideoPort for VideoAdapter { todo!() } - fn save(&self, library_item: LibraryItem) -> Result<(), VideoError> { + fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError> { todo!() } + fn save_all(&self, library_items: &Vec) -> Result<(), VideoError> { + Ok(()) + } + fn clone_box(&self) -> Box { - todo!() + Box::new(self.clone()) } } \ No newline at end of file diff --git a/backend/launcher/src/application_context.rs b/backend/launcher/src/application_context.rs index 1f02b3b..c3ecb86 100644 --- a/backend/launcher/src/application_context.rs +++ b/backend/launcher/src/application_context.rs @@ -8,6 +8,7 @@ use std::io::{Error, ErrorKind}; use std::sync::{Arc, Mutex}; use lumiere_application::configuration::service::ConfigurationService; use lumiere_application::user::service::UserService; +use lumiere_application::video::service::VideoService; use lumiere_infrastructure::common::database_connection::DatabaseConnection; use lumiere_infrastructure::common::database_initialisation::initialise_database_tables; use lumiere_infrastructure::configuration::adapter::ConfigurationSqliteAdapter; @@ -16,11 +17,13 @@ use lumiere_infrastructure::user::adapter::UserSqliteAdapter; use lumiere_infrastructure::user::diesel_adapter::UserDieselAdapter; use lumiere_infrastructure::user::diesel_repository::UserDieselRepository; use lumiere_infrastructure::user::repository::UserSqliteRepository; +use lumiere_infrastructure::video::adapter::VideoAdapter; pub struct ApplicationContext { pub database_connection: Arc>, pub configuration_service: ConfigurationService, pub user_service: UserService, + pub video_service: VideoService, } impl ApplicationContext { @@ -56,11 +59,15 @@ impl ApplicationContext { // let user_repository = UserSqliteRepository::new(arc_mutex_connection.clone()); // let user_adapter = Box::new(UserSqliteAdapter::new(user_repository.clone())); let user_service = UserService::new(configuration_service.clone(), user_adapter.clone()); + + let video_adapter = Box::new(VideoAdapter::new()); + let video_service = VideoService::new(video_adapter.clone()); Self { database_connection: arc_mutex_connection.clone(), configuration_service, user_service, + video_service, } } diff --git a/backend/launcher/src/main.rs b/backend/launcher/src/main.rs index 3ecd12f..e73f5a3 100644 --- a/backend/launcher/src/main.rs +++ b/backend/launcher/src/main.rs @@ -12,7 +12,6 @@ use std::io::{BufReader, Error}; use std::path::Path; use std::sync::Arc; use lumiere_exposition::init; -use lumiere_exposition::video::video_format_content_type_mapper::map_to_content_type; use lumiere_infrastructure::video::video_format_detector::get_content_type; use tokio_cron_scheduler::{Job, JobScheduler}; @@ -35,6 +34,7 @@ async fn main() -> std::io::Result<()> { let server = HttpServer::new( move || App::new().configure(init) .app_data(web::Data::new(Arc::new(application_context.user_service.clone()))) + .app_data(web::Data::new(Arc::new(application_context.video_service.clone()))) ) .bind("0.0.0.0:19000") // .bind_rustls_0_23(("0.0.0.0", 19000), tls_config)