syntax = "proto3"; package musicfs; // MusicFs service exposes a server-side music library to a remote musicfs // FUSE mount. service MusicFs { // Hash-based reconciliation. Client sends the (inode, hash) pairs it // currently has; server responds with the subset that changed (new or // hash-different) plus the inodes the client has but the server no longer // has. Cheap on the wire — no file metadata crosses until the client asks. rpc Reconcile(ReconcileRequest) returns (ReconcileResponse); // Fetch full metadata for a specific set of inodes. Called after Reconcile // returns a non-empty `changed` list, for just those inodes. rpc GetMetadata(GetMetadataRequest) returns (stream ManifestEntry); // Stream every file entry in the library. Convenience RPC for first-run // bootstrapping or full-refresh. The diff-based Reconcile path is the // normal case. rpc GetManifest(GetManifestRequest) returns (stream ManifestEntry); // Stream the bytes of one file. If `start` and `length` are both zero the // server streams the entire file; otherwise just the requested range. The // first chunk carries `total_size` and `offset`; subsequent chunks continue // from there. rpc GetFile(GetFileRequest) returns (stream FileChunk); // Long-lived stream of filesystem change events. The client uses these as // wake-ups to refetch the manifest; correctness always rests on the hash // diff, never on the event payload. rpc SubscribeEvents(SubscribeEventsRequest) returns (stream ChangeEvent); } message ReconcileRequest { repeated InodeHash entries = 1; } message ReconcileResponse { repeated InodeHash changed = 1; repeated uint64 deleted = 2; } message InodeHash { uint64 inode = 1; uint64 hash = 2; } message GetMetadataRequest { repeated uint64 inodes = 1; } message GetManifestRequest {} message GetFileRequest { uint64 id = 1; // When both are zero the server streams the entire file. uint64 start = 2; uint64 length = 3; } message SubscribeEventsRequest {} message ManifestEntry { uint64 id = 1; string rel_path = 2; uint64 size = 3; uint64 mtime = 4; uint64 ctime = 5; uint64 crtime = 6; MusicMetadata music_metadata = 7; } message MusicMetadata { repeated string artist = 1; optional string album_artist = 2; string album = 3; int32 track_number = 4; string track_title = 5; repeated string other_tags = 6; bytes header = 7; repeated bytes picture_block_headers = 8; repeated PictureDataRange picture_data_ranges = 9; uint64 real_audio_start = 10; uint64 vorbis_comment_offset = 11; uint64 vorbis_comment_length = 12; } message PictureDataRange { uint64 offset = 1; uint64 length = 2; } message FileChunk { bytes data = 1; uint64 offset = 2; uint64 total_size = 3; } message ChangeEvent { // "create", "modify", or "remove". string kind = 1; }