WIP Implement the video adapter to merge FS files and DB files.
This commit is contained in:
@@ -5,7 +5,7 @@ use std::io::{BufRead, BufReader};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use lumiere_domain::video::error::VideoError;
|
use lumiere_domain::video::error::VideoError;
|
||||||
use lumiere_domain::video::model::library_item::{LibraryItem, ReadLibraryItem};
|
use lumiere_domain::video::model::library_item::{LibraryItem, LibraryRawItem};
|
||||||
use lumiere_domain::video::port::VideoPort;
|
use lumiere_domain::video::port::VideoPort;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -21,7 +21,7 @@ impl VideoService {
|
|||||||
pub fn list_root_folder(self) -> Result<Vec<LibraryItem>, VideoError> {
|
pub fn list_root_folder(self) -> Result<Vec<LibraryItem>, VideoError> {
|
||||||
let read_items_with_possibly_no_id = self.video_port.list_root_folder()?;
|
let read_items_with_possibly_no_id = self.video_port.list_root_folder()?;
|
||||||
let items_with_id = read_items_with_possibly_no_id.iter()
|
let items_with_id = read_items_with_possibly_no_id.iter()
|
||||||
.map(ReadLibraryItem::map_to_library_item)
|
.map(LibraryRawItem::map_to_library_item)
|
||||||
.collect();
|
.collect();
|
||||||
self.video_port.save_all(items_with_id);
|
self.video_port.save_all(items_with_id);
|
||||||
Ok(items_with_id)
|
Ok(items_with_id)
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ pub struct LibraryItem {
|
|||||||
pub r#type: LibraryItemType,
|
pub r#type: LibraryItemType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReadLibraryItem {
|
pub struct LibraryRawItem {
|
||||||
pub id: Option<Uuid>,
|
pub id: Option<Uuid>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub r#type: LibraryItemType,
|
pub r#type: LibraryItemType,
|
||||||
}
|
}
|
||||||
impl ReadLibraryItem {
|
impl LibraryRawItem {
|
||||||
pub fn map_to_library_item(&self) -> LibraryItem {
|
pub fn map_to_library_item(&self) -> LibraryItem {
|
||||||
LibraryItem {
|
LibraryItem {
|
||||||
id: self.id.unwrap_or(Uuid::new_v4()),
|
id: self.id.unwrap_or(Uuid::new_v4()),
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use crate::video::error::VideoError;
|
use crate::video::error::VideoError;
|
||||||
use crate::video::model::library_item::{LibraryItem, ReadLibraryItem};
|
use crate::video::model::library_item::{LibraryItem, LibraryRawItem};
|
||||||
use crate::video::model::video::Video;
|
use crate::video::model::video::Video;
|
||||||
|
|
||||||
pub trait VideoPort: Send + Sync {
|
pub trait VideoPort: Send + Sync {
|
||||||
fn list_root_folder(&self) -> Result<Vec<ReadLibraryItem>, VideoError>;
|
fn list_root_folder(&self) -> Result<Vec<LibraryRawItem>, VideoError>;
|
||||||
fn list_folder(&self, folder_id: Uuid) -> Result<Vec<ReadLibraryItem>, VideoError>;
|
fn list_folder(&self, folder_id: Uuid) -> Result<Vec<LibraryRawItem>, VideoError>;
|
||||||
fn get_video_stream(&self, video_id: Uuid) -> Result<Video, VideoError>;
|
fn get_video_stream(&self, video_id: Uuid) -> Result<Video, VideoError>;
|
||||||
fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError>;
|
fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError>;
|
||||||
fn clone_box(&self) -> Box<dyn VideoPort>;
|
fn clone_box(&self) -> Box<dyn VideoPort>;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
use lumiere_domain::video::error::VideoError;
|
use lumiere_domain::video::error::VideoError;
|
||||||
use lumiere_domain::video::model::library_item::{LibraryItem, ReadLibraryItem};
|
use lumiere_domain::video::model::library_item::{LibraryItem, LibraryRawItem};
|
||||||
use lumiere_domain::video::model::video::Video;
|
use lumiere_domain::video::model::video::Video;
|
||||||
use lumiere_domain::video::port::VideoPort;
|
use lumiere_domain::video::port::VideoPort;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
pub struct VideoAdapter {
|
pub struct VideoAdapter {
|
||||||
|
|
||||||
@@ -13,21 +15,18 @@ impl VideoAdapter {
|
|||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_root_folder_read_library_items(&self) -> Result<Vec<ReadLibraryItem>, VideoError> {
|
fn get_root_folder_read_library_items(&self) -> Result<Vec<LibraryRawItem>, VideoError> {
|
||||||
use std::env;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// Get the root_folder path from environment variable
|
// Get the root_folder path from environment variable
|
||||||
let root_folder = env::var("ROOT_FOLDER").map_err(|_| VideoError::ConfigurationError("ROOT_FOLDER environment variable not set"))?;
|
let root_folder = env::var("ROOT_FOLDER").map_err(|_| VideoError::FolderBrowsingTechnicalIssue)?;
|
||||||
|
|
||||||
// List all elements inside this folder on the file system
|
// List all elements inside this folder on the file system
|
||||||
let entries = fs::read_dir(root_folder)
|
let entries = fs::read_dir(root_folder)
|
||||||
.map_err(|e| VideoError::FileSystemError(e.to_string()))?;
|
.map_err(|e| VideoError::FolderBrowsingTechnicalIssue)?;
|
||||||
|
|
||||||
// Map all those elements into ReadLibraryItem objects
|
// Map all those elements into ReadLibraryItem objects
|
||||||
let mut items: Vec<ReadLibraryItem> = Vec::new();
|
let mut items: Vec<LibraryRawItem> = Vec::new();
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
let entry = entry.map_err(|e| VideoError::FileSystemError(e.to_string()))?;
|
let entry = entry.map_err(|e| VideoError::FolderBrowsingTechnicalIssue)?;
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
|
||||||
// Determine if it's a file or directory
|
// Determine if it's a file or directory
|
||||||
@@ -39,7 +38,7 @@ impl VideoAdapter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create ReadLibraryItem with None for ID (will be generated later)
|
// Create ReadLibraryItem with None for ID (will be generated later)
|
||||||
let item = ReadLibraryItem {
|
let item = LibraryRawItem {
|
||||||
id: None,
|
id: None,
|
||||||
name: entry.file_name().to_string_lossy().into_owned(),
|
name: entry.file_name().to_string_lossy().into_owned(),
|
||||||
r#type: item_type,
|
r#type: item_type,
|
||||||
@@ -51,46 +50,45 @@ impl VideoAdapter {
|
|||||||
Ok(items)
|
Ok(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_all_library_items_from_db(&self) -> Result<Vec<ReadLibraryItem>, VideoError> {
|
pub fn get_all_library_items_from_db(&self) -> Result<Vec<LibraryRawItem>, VideoError> {
|
||||||
todo!()
|
Ok(vec!())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge_item_lists(file_system_items: Vec<LibraryRawItem>, db_items: Vec<LibraryRawItem>) -> Vec<LibraryRawItem> {
|
||||||
|
let mut all_items: Vec<LibraryRawItem> = Vec::new();
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
fn does_item_belong_to_db_items(database_items: &Vec<LibraryRawItem>, file_system_item: &LibraryRawItem) -> bool {
|
||||||
|
database_items.iter()
|
||||||
|
.any(|database_item| {
|
||||||
|
if let Some(item_id) = file_system_item.id {
|
||||||
|
database_item.id == Some(item_id)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VideoPort for VideoAdapter {
|
impl VideoPort for VideoAdapter {
|
||||||
fn list_root_folder(&self) -> Result<Vec<ReadLibraryItem>, VideoError> {
|
fn list_root_folder(&self) -> Result<Vec<LibraryRawItem>, VideoError> {
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
// In parallel: call both methods
|
|
||||||
let file_system_items = self.get_root_folder_read_library_items()?;
|
let file_system_items = self.get_root_folder_read_library_items()?;
|
||||||
let db_items = self.get_all_library_items_from_db()?;
|
let db_items = self.get_all_library_items_from_db()?;
|
||||||
|
|
||||||
// Merge the two lists. If an item from files has the same id as one from DB, use the DB version
|
let merged = Self::merge_item_lists(file_system_items, db_items);
|
||||||
let mut merged: Vec<ReadLibraryItem> = Vec::new();
|
|
||||||
|
|
||||||
// First add all DB items (they have IDs)
|
|
||||||
for db_item in db_items {
|
|
||||||
merged.push(db_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then add file system items only if they don't exist in DB
|
|
||||||
for fs_item in file_system_items {
|
|
||||||
let exists_in_db = merged.iter().any(|db_item| {
|
|
||||||
if let Some(fs_id) = fs_item.id {
|
|
||||||
db_item.id == Some(fs_id)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if !exists_in_db {
|
|
||||||
merged.push(fs_item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(merged)
|
Ok(merged)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_folder(&self, folder_id: Uuid) -> Result<Vec<ReadLibraryItem>, VideoError> {
|
fn list_folder(&self, folder_id: Uuid) -> Result<Vec<LibraryRawItem>, VideoError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user