154 lines
4.4 KiB
Markdown
154 lines
4.4 KiB
Markdown
# shepherd-api
|
|
|
|
Protocol types for Shepherd IPC communication.
|
|
|
|
## Overview
|
|
|
|
This crate defines the stable API between the Shepherd service (`shepherdd`) and its clients (launcher UI, HUD overlay, admin tools). It contains:
|
|
|
|
- **Commands** - Requests from clients to the service
|
|
- **Responses** - Service replies to commands
|
|
- **Events** - Asynchronous notifications from service to clients
|
|
- **Shared types** - Entry views, session info, reason codes, etc.
|
|
|
|
## Purpose
|
|
|
|
`shepherd-api` establishes the contract between components, ensuring:
|
|
|
|
1. **Stability** - Versioned protocol with backward compatibility
|
|
2. **Type safety** - Strongly typed messages prevent protocol errors
|
|
3. **Decoupling** - Clients and service can evolve independently
|
|
|
|
## API Version
|
|
|
|
```rust
|
|
use shepherd_api::API_VERSION;
|
|
|
|
// Current API version
|
|
assert_eq!(API_VERSION, 1);
|
|
```
|
|
|
|
## Key Types
|
|
|
|
### Commands
|
|
|
|
Commands are requests sent by clients to the service:
|
|
|
|
```rust
|
|
use shepherd_api::Command;
|
|
|
|
// Request available entries
|
|
let cmd = Command::ListEntries;
|
|
|
|
// Request to launch an entry
|
|
let cmd = Command::Launch {
|
|
entry_id: "minecraft".into()
|
|
};
|
|
|
|
// Request to stop current session
|
|
let cmd = Command::StopCurrent {
|
|
mode: StopMode::Graceful
|
|
};
|
|
|
|
// Subscribe to real-time events
|
|
let cmd = Command::SubscribeEvents;
|
|
```
|
|
|
|
Available commands:
|
|
- `GetState` - Get full service state snapshot
|
|
- `ListEntries` - List all entries with availability
|
|
- `Launch { entry_id }` - Launch an entry
|
|
- `StopCurrent { mode }` - Stop the current session
|
|
- `ReloadConfig` - Reload configuration (admin only)
|
|
- `SubscribeEvents` - Subscribe to event stream
|
|
- `GetHealth` - Get service health status
|
|
- `SetVolume { level }` - Set system volume
|
|
- `GetVolume` - Get current volume
|
|
|
|
### Events
|
|
|
|
Events are pushed from the service to subscribed clients:
|
|
|
|
```rust
|
|
use shepherd_api::{Event, EventPayload};
|
|
|
|
// Events received by clients
|
|
match event.payload {
|
|
EventPayload::StateChanged(snapshot) => { /* Update UI */ }
|
|
EventPayload::SessionStarted(info) => { /* Show HUD */ }
|
|
EventPayload::WarningIssued { threshold, remaining, severity, message } => { /* Alert user */ }
|
|
EventPayload::SessionExpired { session_id } => { /* Time's up */ }
|
|
EventPayload::SessionEnded { session_id, reason } => { /* Return to launcher */ }
|
|
EventPayload::PolicyReloaded { entry_count } => { /* Refresh entry list */ }
|
|
EventPayload::VolumeChanged(info) => { /* Update volume display */ }
|
|
}
|
|
```
|
|
|
|
### Entry Views
|
|
|
|
Entries as presented to UIs:
|
|
|
|
```rust
|
|
use shepherd_api::EntryView;
|
|
|
|
let view: EntryView = /* from service */;
|
|
|
|
if view.enabled {
|
|
// Entry can be launched
|
|
println!("Max run time: {:?}", view.max_run_if_started_now);
|
|
} else {
|
|
// Entry unavailable, show reasons
|
|
for reason in &view.reasons {
|
|
match reason {
|
|
ReasonCode::OutsideTimeWindow { next_window_start } => { /* ... */ }
|
|
ReasonCode::QuotaExhausted { used, quota } => { /* ... */ }
|
|
ReasonCode::CooldownActive { available_at } => { /* ... */ }
|
|
ReasonCode::SessionActive { entry_id, remaining } => { /* ... */ }
|
|
ReasonCode::InternetUnavailable { check } => { /* ... */ }
|
|
// ...
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Session Info
|
|
|
|
Information about active sessions:
|
|
|
|
```rust
|
|
use shepherd_api::{SessionInfo, SessionState};
|
|
|
|
let session: SessionInfo = /* from snapshot */;
|
|
|
|
match session.state {
|
|
SessionState::Launching => { /* Show spinner */ }
|
|
SessionState::Running => { /* Show countdown */ }
|
|
SessionState::Warned => { /* Highlight urgency */ }
|
|
SessionState::Expiring => { /* Terminating... */ }
|
|
SessionState::Ended => { /* Session over */ }
|
|
}
|
|
```
|
|
|
|
### Reason Codes
|
|
|
|
Structured explanations for unavailability:
|
|
|
|
- `OutsideTimeWindow` - Not within allowed time window
|
|
- `QuotaExhausted` - Daily time limit reached
|
|
- `CooldownActive` - Must wait after previous session
|
|
- `SessionActive` - Another session is running
|
|
- `UnsupportedKind` - Host doesn't support this entry type
|
|
- `Disabled` - Entry explicitly disabled in config
|
|
|
|
## Design Philosophy
|
|
|
|
- **Service is authoritative** - Clients display state, service enforces policy
|
|
- **Structured reasons** - UIs can explain "why is this unavailable?"
|
|
- **Event-driven** - Clients subscribe and react to changes
|
|
- **Serializable** - All types derive `Serialize`/`Deserialize` for JSON transport
|
|
|
|
## Dependencies
|
|
|
|
- `serde` - Serialization/deserialization
|
|
- `chrono` - Timestamp types
|
|
- `shepherd-util` - ID types
|