Implement Week 1 foundation: workspace, core types, FUSE skeleton, LocalOrigin

- musicfs-core: OriginId, FileId, VirtualPath, ContentHash, AudioMeta,
  FileMeta, EventBus with FileAccessed event (5 tests)
- musicfs-fuse: FUSE skeleton with EROFS handlers for write ops
- musicfs-origins: Origin trait with watch(), LocalOrigin impl (6 tests)
- flake.nix: Nix dev shell with rust toolchain, clang, lld, fuse3

All 11 tests pass. Build produces no warnings.
This commit is contained in:
Alexander
2026-05-12 18:01:47 +02:00
parent e08988f7f3
commit 76856b893a
35 changed files with 1933 additions and 0 deletions
@@ -0,0 +1,55 @@
use async_trait::async_trait;
use musicfs_core::{DirEntry, FileStat, HealthStatus, OriginId, Result};
use std::path::{Path, PathBuf};
use tokio::io::AsyncRead;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OriginType {
Local,
Nfs,
Smb,
S3,
Sftp,
}
#[async_trait]
pub trait Origin: Send + Sync {
fn id(&self) -> &OriginId;
fn origin_type(&self) -> OriginType;
fn display_name(&self) -> &str;
async fn readdir(&self, path: &Path) -> Result<Vec<DirEntry>>;
async fn stat(&self, path: &Path) -> Result<FileStat>;
async fn read(&self, path: &Path, offset: u64, size: u32) -> Result<Vec<u8>>;
async fn exists(&self, path: &Path) -> Result<bool>;
async fn health(&self) -> HealthStatus;
async fn open_read(&self, path: &Path) -> Result<Box<dyn AsyncRead + Send + Unpin>>;
async fn watch(&self, path: &Path, callback: WatchCallback) -> Result<WatchHandle>;
}
pub type WatchCallback = Box<dyn Fn(WatchEvent) + Send + Sync>;
pub struct WatchHandle {
_cancel: tokio::sync::oneshot::Sender<()>,
}
impl WatchHandle {
pub fn new(cancel: tokio::sync::oneshot::Sender<()>) -> Self {
Self { _cancel: cancel }
}
}
#[derive(Debug, Clone)]
pub enum WatchEvent {
Created(PathBuf),
Modified(PathBuf),
Deleted(PathBuf),
}