mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2025-12-11 20:15:30 +01:00
457 lines
12 KiB
Plaintext
457 lines
12 KiB
Plaintext
---
|
|
title: Unified Addressing
|
|
sidebarTitle: Addressing
|
|
---
|
|
|
|
Spacedrive uses a unified addressing scheme that works seamlessly across local devices, cloud storage, and content-addressed files. Every file has a single, intuitive URI that tells you exactly where it lives - whether it's on your laptop, in S3, or stored by content hash.
|
|
|
|
**Local devices:**
|
|
|
|
```
|
|
local://jamies-macbook/Users/james/Documents/report.pdf
|
|
```
|
|
|
|
**Cloud storage:**
|
|
|
|
```
|
|
s3://my-bucket/photos/2024/vacation.jpg
|
|
```
|
|
|
|
**Content addressed:**
|
|
|
|
```
|
|
content://550e8400-e29b-41d4-a716-446655440000
|
|
```
|
|
|
|
The same URI format works across all storage types, matching industry-standard cloud tools like AWS CLI and gsutil. Copy a path from Spacedrive and paste it directly into your terminal.
|
|
|
|
## URI Formats
|
|
|
|
### Cloud Storage - Service-Native URIs
|
|
|
|
Cloud files use the same URI format as their native tools:
|
|
|
|
```
|
|
s3://my-bucket/photos/2024/vacation/IMG_0123.jpg
|
|
gdrive://My Drive/Documents/Contract 2024.pdf
|
|
onedrive://Documents/Budget Spreadsheet.xlsx
|
|
dropbox://Apps/Spacedrive/backup-2024-10.zip
|
|
azblob://container/data/export-2024.csv
|
|
gcs://my-bucket/logs/application-2024-10-15.log
|
|
```
|
|
|
|
**Pattern**: `{service}://{identifier}/{path}`
|
|
|
|
Where:
|
|
|
|
- `{service}`: Cloud service type (s3, gdrive, onedrive, dropbox, azblob, gcs, b2, wasabi, spaces)
|
|
- `{identifier}`: Service-specific root (bucket name, folder, container)
|
|
- `{path}`: Path within the service
|
|
|
|
<Tip>
|
|
These URIs match AWS CLI, gsutil, and other cloud tools exactly. Copy a path
|
|
from Spacedrive and paste it into `aws s3 cp` without modification.
|
|
</Tip>
|
|
|
|
### Local Files - Device-Aware URIs
|
|
|
|
Local files include the device name for multi-device clarity:
|
|
|
|
```
|
|
local://jamies-macbook/Users/james/Documents/report.pdf
|
|
local://home-server/mnt/storage/media/movies/Inception.mkv
|
|
local://work-desktop/C:/Projects/spacedrive/README.md
|
|
```
|
|
|
|
**Pattern**: `local://{device-slug}/{path}`
|
|
|
|
Where:
|
|
|
|
- `{device-slug}`: URL-safe device identifier (generated from device name)
|
|
- `{path}`: Absolute path on that device
|
|
|
|
<Note>
|
|
Device slugs are generated automatically from your device name by converting
|
|
to lowercase and replacing non-alphanumeric characters with hyphens. "Jamie's
|
|
MacBook Pro" becomes `jamies-macbook-pro`.
|
|
</Note>
|
|
|
|
### Content-Addressed Files
|
|
|
|
Content URIs reference files by their content hash, independent of location:
|
|
|
|
```
|
|
content://550e8400-e29b-41d4-a716-446655440000
|
|
```
|
|
|
|
**Pattern**: `content://{uuid}`
|
|
|
|
This enables location-independent operations. The same photo stored on multiple devices and in cloud storage shares one content URI. Spacedrive resolves it to the most efficient available location.
|
|
|
|
## Device Slug System
|
|
|
|
Spacedrive generates URL-safe slugs from device names to create stable, human-readable URIs.
|
|
|
|
### Slug Generation
|
|
|
|
```rust
|
|
// Convert device name to slug
|
|
let name = "Jamie's MacBook Pro";
|
|
let slug = name.to_lowercase()
|
|
.chars()
|
|
.map(|c| if c.is_alphanumeric() { c } else { '-' })
|
|
.collect::<String>()
|
|
.trim_matches('-');
|
|
// Result: "jamies-macbook-pro"
|
|
```
|
|
|
|
Examples:
|
|
|
|
- "Jamie's MacBook" → `jamies-macbook`
|
|
- "Home Server 2024" → `home-server-2024`
|
|
- "DESKTOP-ABC123" → `desktop-abc123`
|
|
|
|
### Slug Uniqueness
|
|
|
|
Each device's slug must be unique within your Spacedrive network. The database enforces this with a unique constraint on the `slug` column. If you try to add a device with a duplicate name, you'll need to rename one device.
|
|
|
|
<Warning>
|
|
If two devices have the same name (e.g., both "MacBook Pro"), you must give
|
|
them distinct names before they can sync. Spacedrive will warn you during
|
|
pairing.
|
|
</Warning>
|
|
|
|
### Resolution
|
|
|
|
When parsing a `local://` URI, Spacedrive looks up the device by slug:
|
|
|
|
```rust
|
|
// Parse: local://jamies-macbook/Users/james/file.txt
|
|
let device_id = device_manager.resolve_by_slug("jamies-macbook")?;
|
|
let path = PathBuf::from("/Users/james/file.txt");
|
|
```
|
|
|
|
Currently, slug resolution only works for the current device. Remote device paths use UUIDs internally but display with slugs for user-facing operations.
|
|
|
|
## How It Works
|
|
|
|
Spacedrive maintains user-friendly URIs in the display layer while using efficient internal identifiers for operations.
|
|
|
|
### User-Facing Display
|
|
|
|
```rust
|
|
// Display path to user
|
|
let display_uri = sd_path.display_with_context(&context).await;
|
|
println!("{}", display_uri);
|
|
// Output: "s3://media-bucket/videos/demo.mp4"
|
|
```
|
|
|
|
### Internal Representation
|
|
|
|
```rust
|
|
pub enum SdPath {
|
|
Physical {
|
|
device_slug: String, // URL-safe device identifier
|
|
path: PathBuf,
|
|
},
|
|
Cloud {
|
|
service: CloudServiceType, // Cloud service type (S3, GoogleDrive, etc.)
|
|
identifier: String, // Service identifier (bucket, drive name, etc.)
|
|
path: String, // Path within the service
|
|
},
|
|
Content {
|
|
content_id: Uuid,
|
|
},
|
|
}
|
|
```
|
|
|
|
### Resolution Flow
|
|
|
|
```
|
|
User Input: s3://my-bucket/file.jpg
|
|
↓
|
|
Parse Scheme: "s3" → CloudServiceType::S3
|
|
↓
|
|
Parse Identity: identifier = "my-bucket"
|
|
path = "file.jpg"
|
|
↓
|
|
Create SdPath: SdPath::Cloud { service: S3, identifier: "my-bucket", path: "file.jpg" }
|
|
↓
|
|
Find Volume: VolumeManager::find_cloud_volume(S3, "my-bucket")
|
|
↓
|
|
Mount Cache: "s3://my-bucket" → VolumeFingerprint (O(1) lookup)
|
|
↓
|
|
Operations: Use volume backend for I/O operations
|
|
```
|
|
|
|
The service and identifier are stored directly in the `SdPath`, making cloud paths self-contained. The VolumeManager maintains a mount point cache for fast volume lookups.
|
|
|
|
## Cloud Service Schemes
|
|
|
|
Spacedrive supports these cloud URI schemes:
|
|
|
|
| Service | Scheme | Example |
|
|
| -------------------- | ------------- | -------------------------------------- |
|
|
| Amazon S3 | `s3://` | `s3://my-bucket/path/file.jpg` |
|
|
| Google Drive | `gdrive://` | `gdrive://My Drive/Documents/file.pdf` |
|
|
| OneDrive | `onedrive://` | `onedrive://Documents/file.xlsx` |
|
|
| Dropbox | `dropbox://` | `dropbox://Apps/Spacedrive/file.zip` |
|
|
| Azure Blob | `azblob://` | `azblob://container/data/file.csv` |
|
|
| Google Cloud Storage | `gcs://` | `gcs://bucket/logs/file.log` |
|
|
| Backblaze B2 | `b2://` | `b2://bucket/backups/file.tar` |
|
|
| Wasabi | `wasabi://` | `wasabi://bucket/archive/file.zip` |
|
|
| DigitalOcean Spaces | `spaces://` | `spaces://space/assets/file.png` |
|
|
|
|
S3-compatible services (MinIO, Cloudflare R2, Wasabi, etc.) use the `s3://` scheme with custom endpoints.
|
|
|
|
## Parsing URIs
|
|
|
|
### From User Input
|
|
|
|
```rust
|
|
use sd_core::domain::addressing::SdPath;
|
|
|
|
// Parse cloud URI
|
|
let path = SdPath::from_uri_with_context(
|
|
"s3://my-bucket/photos/vacation.jpg",
|
|
&context
|
|
).await?;
|
|
|
|
// Parse local URI
|
|
let path = SdPath::from_uri_with_context(
|
|
"local://jamies-macbook/Users/james/file.txt",
|
|
&context
|
|
).await?;
|
|
|
|
// Parse content URI
|
|
let path = SdPath::from_uri_with_context(
|
|
"content://550e8400-e29b-41d4-a716-446655440000",
|
|
&context
|
|
).await?;
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
```rust
|
|
match SdPath::from_uri_with_context(uri, &context).await {
|
|
Ok(path) => { /* Use path */ }
|
|
Err(SdPathParseError::UnknownScheme) => {
|
|
// Invalid URI scheme
|
|
}
|
|
Err(SdPathParseError::VolumeNotFound) => {
|
|
// Cloud volume doesn't exist or isn't added
|
|
}
|
|
Err(SdPathParseError::DeviceNotFound) => {
|
|
// Device slug not found
|
|
}
|
|
Err(_) => {
|
|
// Other parse errors
|
|
}
|
|
}
|
|
```
|
|
|
|
## CLI Usage
|
|
|
|
The unified addressing scheme makes CLI operations intuitive:
|
|
|
|
```bash
|
|
# Copy from Google Drive to S3
|
|
sd cp gdrive://Work/report.pdf s3://backup/documents/
|
|
|
|
# List files on remote device
|
|
sd ls local://home-server/mnt/media/movies/
|
|
|
|
# Search across all storage
|
|
sd search "*.mp4"
|
|
# Results show unified URIs:
|
|
# gdrive://Videos/vacation.mp4
|
|
# s3://media/clips/demo.mp4
|
|
# local://macbook/Users/james/Downloads/tutorial.mp4
|
|
|
|
# Sync local to cloud
|
|
sd sync local://macbook/Photos/ s3://backup/photos/
|
|
```
|
|
|
|
## Code Examples
|
|
|
|
### File Operations
|
|
|
|
```rust
|
|
// Copy from cloud to local
|
|
let src = SdPath::from_uri_with_context(
|
|
"gdrive://Work/presentation.pptx",
|
|
&context
|
|
).await?;
|
|
|
|
let dst = SdPath::from_uri_with_context(
|
|
"local://macbook/Desktop/",
|
|
&context
|
|
).await?;
|
|
|
|
copy_action.execute(src, dst).await?;
|
|
```
|
|
|
|
### Display Paths
|
|
|
|
```rust
|
|
// Get user-friendly URI for display
|
|
let uri = sd_path.display_with_context(&context).await;
|
|
println!("File location: {}", uri);
|
|
|
|
// Examples:
|
|
// "s3://media-bucket/videos/demo.mp4"
|
|
// "local://jamies-macbook/Users/james/file.txt"
|
|
// "content://550e8400-e29b-41d4-a716-446655440000"
|
|
```
|
|
|
|
### Building Paths
|
|
|
|
```rust
|
|
// Create cloud path
|
|
let path = SdPath::Cloud {
|
|
service: CloudServiceType::S3,
|
|
identifier: "my-bucket".to_string(),
|
|
path: "photos/vacation.jpg".to_string(),
|
|
};
|
|
|
|
// Create local path
|
|
let path = SdPath::Physical {
|
|
device_slug: "jamies-macbook".to_string(),
|
|
path: PathBuf::from("/Users/james/file.txt"),
|
|
};
|
|
|
|
// Create content path
|
|
let path = SdPath::Content {
|
|
content_id: Uuid::new_v4(),
|
|
};
|
|
```
|
|
|
|
## Industry Standard Alignment
|
|
|
|
Spacedrive's addressing matches industry tools:
|
|
|
|
**AWS CLI**:
|
|
|
|
```bash
|
|
aws s3 cp s3://bucket/file.jpg local-file.jpg
|
|
sd cp s3://bucket/file.jpg local://macbook/Desktop/file.jpg
|
|
```
|
|
|
|
**gsutil**:
|
|
|
|
```bash
|
|
gsutil cp gs://bucket/file.jpg local-file.jpg
|
|
sd cp gcs://bucket/file.jpg local://macbook/Desktop/file.jpg
|
|
```
|
|
|
|
**Azure CLI**:
|
|
|
|
```bash
|
|
az storage blob download --container container --name file.csv
|
|
sd cp azblob://container/file.csv local://macbook/Desktop/file.csv
|
|
```
|
|
|
|
The alignment eliminates context switching between tools. URIs copy-paste directly between Spacedrive and native cloud tools.
|
|
|
|
## Benefits
|
|
|
|
### Self-Documenting
|
|
|
|
URIs clearly show where files live:
|
|
|
|
```
|
|
s3://media-bucket/photos/vacation.jpg
|
|
↑ ↑
|
|
Service Bucket
|
|
```
|
|
|
|
No need to remember which cloud provider or check internal IDs.
|
|
|
|
### Cross-Storage Operations
|
|
|
|
Operations work identically across storage types:
|
|
|
|
```rust
|
|
// Same API for all storage backends
|
|
copy(src, dst).await?;
|
|
|
|
// Works for any combination:
|
|
// - local → local
|
|
// - local → cloud
|
|
// - cloud → cloud
|
|
// - cloud → local
|
|
```
|
|
|
|
### Location Independence
|
|
|
|
Content URIs enable operations without knowing physical location:
|
|
|
|
```rust
|
|
// Reference by content, not location
|
|
let file = SdPath::Content { content_id };
|
|
|
|
// Spacedrive finds the best location:
|
|
// - Fastest device (SSD vs HDD)
|
|
// - Lowest cost (local vs cloud egress)
|
|
// - Highest availability
|
|
```
|
|
|
|
## Limitations
|
|
|
|
### Device Slug Resolution
|
|
|
|
Device slug resolution works for all devices in the library through an in-memory cache. When a library opens, all device slugs are loaded into the DeviceManager's cache, enabling instant O(1) resolution for any device whether online or offline.
|
|
|
|
The cache updates automatically when:
|
|
|
|
- A library is opened (loads all devices from database)
|
|
- New devices pair and sync
|
|
- The library closes (cache is cleared)
|
|
|
|
This means `local://` URIs can reference any device in the library, not just the current device.
|
|
|
|
### Cloud Volume Lookup
|
|
|
|
Cloud volumes use an O(1) mount point cache for fast lookups. The cache maps mount point strings (e.g., `"s3://my-bucket"`) to volume fingerprints. For volumes added before the cache was implemented, a linear scan serves as a fallback.
|
|
|
|
### Slug Collisions
|
|
|
|
If two devices would generate the same slug, the second device must be renamed. There's no automatic disambiguation.
|
|
|
|
## Best Practices
|
|
|
|
### URI Display
|
|
|
|
Use `display()` to convert SdPath to a user-facing URI string. The method generates the appropriate format automatically based on the path type.
|
|
|
|
### URI Parsing
|
|
|
|
Use `from_uri()` when parsing user input. The method parses service-native URIs and validates the format.
|
|
|
|
### Device Naming
|
|
|
|
Choose distinct device names to avoid slug collisions. Include location or purpose in names:
|
|
|
|
- "jamies-macbook-home"
|
|
- "jamies-macbook-work"
|
|
- "home-server-basement"
|
|
- "backup-nas-office"
|
|
|
|
### Cloud Mount Points
|
|
|
|
Spacedrive ensures cloud mount points are unique by appending `-2`, `-3` if collisions occur:
|
|
|
|
```
|
|
s3://my-bucket ← First S3 volume with this bucket
|
|
s3://my-bucket-2 ← Second volume (different credentials or endpoint)
|
|
```
|
|
|
|
This enables multiple configurations for the same cloud resource.
|
|
|
|
## Related Documentation
|
|
|
|
- [Devices](/docs/core/devices) - Device management and pairing
|
|
- [Volumes](/docs/core/volumes) - Volume system and cloud integration
|
|
- [Cloud Integration](/docs/core/cloud-integration) - Cloud storage details
|
|
- [Data Model](/docs/core/data-model) - SdPath internal representation
|