use crate::model::has_children::{HasChildren, HasProgress};
use crate::model::local_data_item::LocalDataItem;
use crate::model::transfer_state::TransferState;
use crate::services::transfer_manager::JobId;
use crate::settings::file_credentials::FileCredential;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalSelectedItem {
pub name: String,
pub path: String,
pub is_directory: bool,
pub destination_bucket: String,
pub destination_path: String,
pub s3_creds: FileCredential,
pub children: Option<Vec<LocalSelectedItem>>,
pub transfer_state: TransferState,
pub job_id: Option<JobId>,
}
impl LocalSelectedItem {
pub fn new(
name: String,
path: String,
is_directory: bool,
destination_bucket: String,
destination_path: String,
s3_creds: FileCredential,
children: Option<Vec<LocalSelectedItem>>,
) -> LocalSelectedItem {
LocalSelectedItem {
name,
path,
is_directory,
destination_bucket,
destination_path,
s3_creds,
children,
transfer_state: TransferState::default(),
job_id: None,
}
}
pub fn from_local_data_item(item: LocalDataItem, s3_creds: FileCredential) -> Self {
LocalSelectedItem {
name: item.name,
path: item.path,
is_directory: item.is_directory,
destination_bucket: String::new(),
destination_path: String::new(),
s3_creds,
children: None,
transfer_state: TransferState::default(),
job_id: None,
}
}
pub fn list_directory_items(item: &LocalSelectedItem) -> Vec<LocalSelectedItem> {
let path = Path::new(&item.path);
if item.is_directory {
let mut items = Vec::new();
if let Ok(entries) = fs::read_dir(path) {
for entry in entries.filter_map(Result::ok) {
let path = entry.path();
if path.is_dir() {
items.extend(Self::list_directory_items(&LocalSelectedItem {
name: path.file_name().unwrap().to_string_lossy().into_owned(),
path: path.to_string_lossy().into(),
is_directory: true,
destination_bucket: item.destination_bucket.clone(),
destination_path: PathBuf::from(&item.destination_path)
.join(path.file_name().unwrap().to_string_lossy().into_owned())
.to_string_lossy()
.into(),
s3_creds: item.s3_creds.clone(),
children: None,
transfer_state: TransferState::default(),
job_id: None,
}));
} else {
items.push(LocalSelectedItem {
name: path.file_name().unwrap().to_string_lossy().into_owned(),
path: path.to_string_lossy().into(),
is_directory: false,
destination_bucket: item.destination_bucket.clone(),
destination_path: PathBuf::from(&item.destination_path)
.join(path.file_name().unwrap().to_string_lossy().into_owned())
.to_string_lossy()
.into(),
s3_creds: item.s3_creds.clone(),
children: None,
transfer_state: TransferState::default(),
job_id: None,
});
}
}
}
items
} else {
vec![item.clone()]
}
}
pub fn is_transferred(&self) -> bool {
self.transfer_state.is_completed()
}
}
impl PartialEq for LocalSelectedItem {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.path == other.path
&& self.is_directory == other.is_directory
}
}
impl HasChildren for LocalSelectedItem {
fn children(&self) -> Option<&Vec<Self>> {
self.children.as_ref()
}
fn take_children(self) -> Vec<Self> {
self.children.unwrap_or_default()
}
}
impl HasProgress for LocalSelectedItem {
fn progress(&self) -> f64 {
self.transfer_state.progress()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_local_selected_item_correctly() {
let item = LocalSelectedItem {
destination_bucket: "test-bucket".into(),
destination_path: "".to_string(),
name: "file1.txt".into(),
path: "path/to/file1.txt".into(),
is_directory: false,
s3_creds: Default::default(),
children: None,
transfer_state: TransferState::default(),
job_id: None,
};
let res = LocalSelectedItem::new(
"file1.txt".into(),
"path/to/file1.txt".into(),
false,
"test-bucket".into(),
"".to_string(),
Default::default(),
None,
);
assert_eq!(item, res);
}
#[test]
fn test_transfer_state_helpers() {
let mut item = LocalSelectedItem {
name: "file1.txt".into(),
path: "/home/user/file1.txt".into(),
is_directory: false,
destination_bucket: "test-bucket".into(),
destination_path: "uploads/file1.txt".into(),
s3_creds: Default::default(),
children: None,
transfer_state: TransferState::default(),
job_id: None,
};
assert!(!item.is_transferred());
assert_eq!(item.transfer_state.progress(), 0.0);
assert!(item.transfer_state.error().is_none());
item.transfer_state = TransferState::InProgress(50.0);
assert!(!item.is_transferred());
assert_eq!(item.transfer_state.progress(), 50.0);
item.transfer_state = TransferState::Completed;
assert!(item.is_transferred());
assert_eq!(item.transfer_state.progress(), 100.0);
item.transfer_state = TransferState::Failed("Upload error".into());
assert!(!item.is_transferred());
assert_eq!(item.transfer_state.error(), Some("Upload error"));
}
}