treewide: better cross-device sync capabilities; in-database storage

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Id99798df6f7e4470caae8a193c2654aa6a6a6964
This commit is contained in:
raf 2026-02-05 08:28:50 +03:00
commit f34c78b238
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
41 changed files with 8806 additions and 138 deletions

View file

@ -104,6 +104,12 @@ pub struct Config {
pub analytics: AnalyticsConfig,
#[serde(default)]
pub photos: PhotoConfig,
#[serde(default)]
pub managed_storage: ManagedStorageConfig,
#[serde(default)]
pub sync: SyncConfig,
#[serde(default)]
pub sharing: SharingConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -560,6 +566,180 @@ impl Default for PhotoConfig {
}
}
// ===== Managed Storage Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManagedStorageConfig {
/// Enable managed storage for file uploads
#[serde(default)]
pub enabled: bool,
/// Directory where managed files are stored
#[serde(default = "default_managed_storage_dir")]
pub storage_dir: PathBuf,
/// Maximum upload size in bytes (default: 10GB)
#[serde(default = "default_max_upload_size")]
pub max_upload_size: u64,
/// Allowed MIME types for uploads (empty = allow all)
#[serde(default)]
pub allowed_mime_types: Vec<String>,
/// Automatically clean up orphaned blobs
#[serde(default = "default_true")]
pub auto_cleanup: bool,
/// Verify file integrity on read
#[serde(default)]
pub verify_on_read: bool,
}
fn default_managed_storage_dir() -> PathBuf {
Config::default_data_dir().join("managed")
}
fn default_max_upload_size() -> u64 {
10 * 1024 * 1024 * 1024 // 10GB
}
impl Default for ManagedStorageConfig {
fn default() -> Self {
Self {
enabled: false,
storage_dir: default_managed_storage_dir(),
max_upload_size: default_max_upload_size(),
allowed_mime_types: vec![],
auto_cleanup: true,
verify_on_read: false,
}
}
}
// ===== Sync Configuration =====
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ConflictResolution {
ServerWins,
ClientWins,
KeepBoth,
Manual,
}
impl Default for ConflictResolution {
fn default() -> Self {
Self::KeepBoth
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SyncConfig {
/// Enable cross-device sync functionality
#[serde(default)]
pub enabled: bool,
/// Default conflict resolution strategy
#[serde(default)]
pub default_conflict_resolution: ConflictResolution,
/// Maximum file size for sync in MB
#[serde(default = "default_max_sync_file_size")]
pub max_file_size_mb: u64,
/// Chunk size for chunked uploads in KB
#[serde(default = "default_chunk_size")]
pub chunk_size_kb: u64,
/// Upload session timeout in hours
#[serde(default = "default_upload_timeout")]
pub upload_timeout_hours: u64,
/// Maximum concurrent uploads per device
#[serde(default = "default_max_concurrent_uploads")]
pub max_concurrent_uploads: usize,
/// Sync log retention in days
#[serde(default = "default_sync_log_retention")]
pub sync_log_retention_days: u64,
}
fn default_max_sync_file_size() -> u64 {
4096 // 4GB
}
fn default_chunk_size() -> u64 {
4096 // 4MB
}
fn default_upload_timeout() -> u64 {
24 // 24 hours
}
fn default_max_concurrent_uploads() -> usize {
3
}
fn default_sync_log_retention() -> u64 {
90 // 90 days
}
impl Default for SyncConfig {
fn default() -> Self {
Self {
enabled: false,
default_conflict_resolution: ConflictResolution::default(),
max_file_size_mb: default_max_sync_file_size(),
chunk_size_kb: default_chunk_size(),
upload_timeout_hours: default_upload_timeout(),
max_concurrent_uploads: default_max_concurrent_uploads(),
sync_log_retention_days: default_sync_log_retention(),
}
}
}
// ===== Sharing Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SharingConfig {
/// Enable sharing functionality
#[serde(default = "default_true")]
pub enabled: bool,
/// Allow creating public share links
#[serde(default = "default_true")]
pub allow_public_links: bool,
/// Require password for public share links
#[serde(default)]
pub require_public_link_password: bool,
/// Maximum expiry time for public links in hours (0 = unlimited)
#[serde(default)]
pub max_public_link_expiry_hours: u64,
/// Allow users to reshare content shared with them
#[serde(default = "default_true")]
pub allow_reshare: bool,
/// Enable share notifications
#[serde(default = "default_true")]
pub notifications_enabled: bool,
/// Notification retention in days
#[serde(default = "default_notification_retention")]
pub notification_retention_days: u64,
/// Share activity log retention in days
#[serde(default = "default_activity_retention")]
pub activity_retention_days: u64,
}
fn default_notification_retention() -> u64 {
30
}
fn default_activity_retention() -> u64 {
90
}
impl Default for SharingConfig {
fn default() -> Self {
Self {
enabled: true,
allow_public_links: true,
require_public_link_password: false,
max_public_link_expiry_hours: 0,
allow_reshare: true,
notifications_enabled: true,
notification_retention_days: default_notification_retention(),
activity_retention_days: default_activity_retention(),
}
}
}
// ===== Storage Configuration =====
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -929,6 +1109,9 @@ impl Default for Config {
cloud: CloudConfig::default(),
analytics: AnalyticsConfig::default(),
photos: PhotoConfig::default(),
managed_storage: ManagedStorageConfig::default(),
sync: SyncConfig::default(),
sharing: SharingConfig::default(),
}
}
}