128 lines
3.4 KiB
Rust
128 lines
3.4 KiB
Rust
use std::{path::Path, time::SystemTime};
|
|
|
|
use chrono::{DateTime, Utc};
|
|
use julid::Julid;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::error::LocalSendError;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct FileMetadata {
|
|
pub id: String,
|
|
pub file_name: String,
|
|
pub size: u64,
|
|
pub file_type: String, // mime type
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub sha256: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub preview: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub metadata: Option<FileMetadataExt>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct FileMetadataExt {
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub modified: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub accessed: Option<String>,
|
|
}
|
|
|
|
impl FileMetadata {
|
|
pub fn from_path(path: &Path) -> crate::error::Result<Self> {
|
|
let metadata = path.metadata()?;
|
|
if !metadata.is_file() {
|
|
return Err(LocalSendError::NotAFile);
|
|
}
|
|
|
|
let id = path.to_str().unwrap().to_string();
|
|
let file_name = path.file_name().unwrap().to_str().unwrap().to_string();
|
|
let size = metadata.len();
|
|
|
|
let file_type = mime_guess::from_path(path)
|
|
.first()
|
|
.map(|mime| mime.to_string())
|
|
.unwrap_or_else(|| "application/octet-stream".to_string()); // Default type if none found
|
|
|
|
let sha256 = Some(sha256::try_digest(path)?);
|
|
|
|
let metadata = Some(FileMetadataExt {
|
|
modified: metadata.modified().ok().map(format_datetime),
|
|
accessed: metadata.accessed().ok().map(format_datetime),
|
|
});
|
|
|
|
Ok(FileMetadata {
|
|
id,
|
|
file_name,
|
|
size,
|
|
file_type,
|
|
sha256,
|
|
preview: None,
|
|
metadata,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum DeviceType {
|
|
Mobile,
|
|
Desktop,
|
|
Web,
|
|
Headless,
|
|
Server,
|
|
Unknown,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Device {
|
|
pub alias: String,
|
|
pub version: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub device_model: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub device_type: Option<DeviceType>,
|
|
pub fingerprint: String,
|
|
pub port: u16,
|
|
pub protocol: String,
|
|
#[serde(default)]
|
|
pub download: bool,
|
|
#[serde(default)]
|
|
pub announce: Option<bool>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum Protocol {
|
|
Http,
|
|
Https,
|
|
}
|
|
|
|
impl Default for Device {
|
|
fn default() -> Self {
|
|
Self {
|
|
alias: "Joecalsend".to_string(),
|
|
version: "2.1".to_string(),
|
|
device_model: None,
|
|
device_type: Some(DeviceType::Headless),
|
|
fingerprint: Julid::new().to_string(),
|
|
port: 53317,
|
|
protocol: "http".to_string(),
|
|
download: false,
|
|
announce: Some(true),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Device {
|
|
pub fn to_json(&self) -> crate::error::Result<String> {
|
|
Ok(serde_json::to_string(self)?)
|
|
}
|
|
}
|
|
|
|
fn format_datetime(system_time: SystemTime) -> String {
|
|
let datetime: DateTime<Utc> = system_time.into();
|
|
datetime.to_rfc3339()
|
|
}
|