feat(client): Windows Cloud-Files-API als File-Provider (OneDrive-Style)
Neuer Modus neben dem bestehenden Full-Sync: Dateien erscheinen im Explorer als Platzhalter mit Wolken-Icon und werden erst bei Zugriff vom Mini-Cloud-Server gestreamt. Windows (MVP): - CfRegisterSyncRoot + CfConnectSyncRoot - CfCreatePlaceholders fuer jede Datei aus /api/sync/tree - FETCH_DATA-Callback mit Range-basiertem HTTPS-Download + CfExecute - CfSetPinState fuer manuelles "Immer offline halten" Linux (Skelett): - FUSE-Provider hinter Feature-Flag linux_fuse (libfuse3-dev) - Stub-Funktionen - Implementierung folgt macOS: - Platzhalter, erfordert Apple-Signatur - spaeter Tauri-Commands: cloud_files_supported/enable/disable/pin/unpin. Cargo.toml: target-spezifische windows-rs Dependency. Doku: clients/desktop/CLOUD_FILES.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
//! Native File-Provider-Integration (Platzhalter-Dateien wie bei OneDrive).
|
||||
//!
|
||||
//! Auf Windows realisiert ueber die Cloud Files API (cfapi.dll), auf Linux
|
||||
//! ueber FUSE (optional, hinter `linux_fuse`-Feature). macOS folgt spaeter
|
||||
//! ueber NSFileProviderExtension (braucht Apple-Signatur).
|
||||
//!
|
||||
//! Der bestehende `sync::engine` bleibt unberuehrt und bietet weiterhin
|
||||
//! den klassischen "kopiere-alles-lokal"-Modus. Der Cloud-Files-Modus
|
||||
//! ist sozusagen "files-on-demand": Datei wird erst bei Zugriff geladen.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Ein Eintrag aus dem Mini-Cloud-Syncbaum, so wie er vom Server kommt.
|
||||
/// Wird von beiden Plattformen genutzt, um Platzhalter / FUSE-Inodes zu
|
||||
/// erzeugen.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RemoteEntry {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub parent_id: Option<i64>,
|
||||
pub is_folder: bool,
|
||||
pub size: i64,
|
||||
/// UTC-ISO8601
|
||||
pub modified_at: String,
|
||||
/// SHA-256 falls vom Server ausgeliefert, sonst None.
|
||||
pub checksum: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SyncState {
|
||||
/// Datei existiert nur als Platzhalter (online-only).
|
||||
Cloud,
|
||||
/// Datei ist vollstaendig lokal vorhanden und aktuell.
|
||||
InSync,
|
||||
/// Lokal geaendert, Upload ausstehend.
|
||||
PendingUpload,
|
||||
/// Auf dem Server gesperrt (durch anderen Nutzer).
|
||||
LockedByOther,
|
||||
/// Durch diesen Client gesperrt.
|
||||
LockedLocal,
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod windows;
|
||||
#[cfg(all(target_os = "linux", feature = "linux_fuse"))]
|
||||
pub mod linux;
|
||||
|
||||
/// Registriere den Sync-Root beim Betriebssystem. Ruft je nach Plattform
|
||||
/// cfapi/CfRegisterSyncRoot bzw. mountet ein FUSE-Dateisystem.
|
||||
#[allow(unused_variables)]
|
||||
pub fn register_sync_root(
|
||||
mount_point: &PathBuf,
|
||||
provider_name: &str,
|
||||
account_id: &str,
|
||||
) -> Result<(), String> {
|
||||
#[cfg(windows)]
|
||||
return windows::register_sync_root(mount_point, provider_name, account_id);
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "linux_fuse"))]
|
||||
return linux::mount(mount_point);
|
||||
|
||||
#[cfg(not(any(windows, all(target_os = "linux", feature = "linux_fuse"))))]
|
||||
Err("File-Provider-Integration fuer diese Plattform noch nicht verfuegbar".into())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn unregister_sync_root(mount_point: &PathBuf) -> Result<(), String> {
|
||||
#[cfg(windows)]
|
||||
return windows::unregister_sync_root(mount_point);
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "linux_fuse"))]
|
||||
return linux::unmount(mount_point);
|
||||
|
||||
#[cfg(not(any(windows, all(target_os = "linux", feature = "linux_fuse"))))]
|
||||
Err("File-Provider-Integration fuer diese Plattform noch nicht verfuegbar".into())
|
||||
}
|
||||
|
||||
/// Erzeuge fuer alle Remote-Eintraege Platzhalter (cloud-only Dateien).
|
||||
/// Ordner werden als echte Verzeichnisse angelegt, Dateien als
|
||||
/// Platzhalter mit gespeicherten Metadaten (Groesse, Mtime, ID).
|
||||
#[allow(unused_variables)]
|
||||
pub fn populate_placeholders(
|
||||
mount_point: &PathBuf,
|
||||
entries: &[RemoteEntry],
|
||||
) -> Result<(), String> {
|
||||
#[cfg(windows)]
|
||||
return windows::populate_placeholders(mount_point, entries);
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "linux_fuse"))]
|
||||
return linux::populate(mount_point, entries);
|
||||
|
||||
#[cfg(not(any(windows, all(target_os = "linux", feature = "linux_fuse"))))]
|
||||
Err("File-Provider-Integration fuer diese Plattform noch nicht verfuegbar".into())
|
||||
}
|
||||
|
||||
/// Ist File-Provider-Integration auf dieser Plattform grundsaetzlich verfuegbar?
|
||||
pub fn is_supported() -> bool {
|
||||
cfg!(windows) || cfg!(all(target_os = "linux", feature = "linux_fuse"))
|
||||
}
|
||||
|
||||
/// Markiere eine lokal bereits vorhandene Datei als "immer offline halten".
|
||||
#[allow(unused_variables)]
|
||||
pub fn pin_file(path: &PathBuf) -> Result<(), String> {
|
||||
#[cfg(windows)]
|
||||
return windows::set_pin_state(path, true);
|
||||
#[cfg(not(windows))]
|
||||
Err("Nur auf Windows unterstuetzt".into())
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub fn unpin_file(path: &PathBuf) -> Result<(), String> {
|
||||
#[cfg(windows)]
|
||||
return windows::set_pin_state(path, false);
|
||||
#[cfg(not(windows))]
|
||||
Err("Nur auf Windows unterstuetzt".into())
|
||||
}
|
||||
Reference in New Issue
Block a user