d9a4ee6a0b
Jetzt tatsaechlich funktionsfaehig, nicht mehr nur Dummy: - Register-Fallback: erst CF_REGISTER_FLAG_NONE, bei "bereits registriert" automatisch mit UPDATE erneut versuchen. Klappt damit bei Erstaktivierung und bei Client-Neustart. - Hintergrund-Loop (cloud_files::sync_loop) pollt alle 30s /api/sync/changes, legt neue Placeholder an und ersetzt geaenderte. - Eigener Callback-Watcher (cloud_files::watcher::CallbackWatcher) hoert auf den Mount-Ordner und sendet lokale Aenderungen (Create/Modify) an den Loop, der sie via POST /api/files/upload hochlaedt. - Helper create_placeholder_at() vom Windows-Modul exportiert, damit der Loop neue Server-Dateien als Placeholder anlegen kann. - AppState erhaelt cloud_files_loop + cloud_files_watcher Felder; beim Disable wird der Loop sauber gestoppt und der Watcher gedroppt. Frontend (App.vue): - Neue Sektion "Cloud-Files (OneDrive-Style)" nur sichtbar wenn die Plattform es unterstuetzt (cloud_files_supported). - Ordner-Picker + Aktivieren/Deaktivieren-Button. - Fehlermeldungen + Sync-Log-Eintraege. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
120 lines
4.1 KiB
Rust
120 lines
4.1 KiB
Rust
//! 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;
|
|
pub mod sync_loop;
|
|
pub mod watcher;
|
|
|
|
/// 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())
|
|
}
|