232 lines
5.8 KiB
Markdown
232 lines
5.8 KiB
Markdown
# shepherd-config
|
|
|
|
Configuration parsing and validation for Shepherd.
|
|
|
|
## Overview
|
|
|
|
This crate handles loading, parsing, and validating the TOML configuration that defines what entries are available, when they're available, and for how long. It provides:
|
|
|
|
- **Schema definitions** - Raw configuration structure as parsed from TOML
|
|
- **Policy objects** - Validated, ready-to-use policy structures
|
|
- **Validation** - Detailed error messages for misconfiguration
|
|
- **Hot reload support** - Configuration can be reloaded at runtime
|
|
|
|
## Configuration Format
|
|
|
|
Shepherd uses TOML for configuration. Here's a complete example:
|
|
|
|
```toml
|
|
config_version = 1
|
|
|
|
[service]
|
|
socket_path = "/run/shepherdd/shepherdd.sock"
|
|
data_dir = "/var/lib/shepherdd"
|
|
default_max_run_seconds = 1800 # 30 minutes default
|
|
|
|
# Internet connectivity check (optional)
|
|
[service.internet]
|
|
check = "https://connectivitycheck.gstatic.com/generate_204"
|
|
interval_seconds = 10
|
|
timeout_ms = 1500
|
|
|
|
# Global volume restrictions
|
|
[service.volume]
|
|
max_volume = 80
|
|
allow_unmute = true
|
|
|
|
# Default warning thresholds (seconds before expiry)
|
|
[[service.default_warnings]]
|
|
seconds_before = 300 # 5 minutes
|
|
severity = "info"
|
|
|
|
[[service.default_warnings]]
|
|
seconds_before = 60 # 1 minute
|
|
severity = "warn"
|
|
|
|
[[service.default_warnings]]
|
|
seconds_before = 10
|
|
severity = "critical"
|
|
message_template = "Closing in {remaining} seconds!"
|
|
|
|
# Entry definitions
|
|
[[entries]]
|
|
id = "minecraft"
|
|
label = "Minecraft"
|
|
icon = "minecraft"
|
|
kind = { type = "snap", snap_name = "mc-installer" }
|
|
|
|
[entries.internet]
|
|
required = true
|
|
|
|
[entries.availability]
|
|
[[entries.availability.windows]]
|
|
days = "weekdays"
|
|
start = "15:00"
|
|
end = "18:00"
|
|
|
|
[[entries.availability.windows]]
|
|
days = "weekends"
|
|
start = "10:00"
|
|
end = "20:00"
|
|
|
|
[entries.limits]
|
|
max_run_seconds = 1800 # 30 minutes per session
|
|
daily_quota_seconds = 7200 # 2 hours per day
|
|
cooldown_seconds = 600 # 10 minutes between sessions
|
|
|
|
[[entries]]
|
|
id = "educational-game"
|
|
label = "GCompris"
|
|
icon = "gcompris-qt"
|
|
kind = { type = "process", command = "gcompris-qt" }
|
|
|
|
[entries.availability]
|
|
always = true # Always available
|
|
|
|
[entries.limits]
|
|
max_run_seconds = 3600 # 1 hour
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Loading Configuration
|
|
|
|
```rust
|
|
use shepherd_config::{load_config, parse_config, Policy};
|
|
use std::path::Path;
|
|
|
|
// Load from file (typically ~/.config/shepherd/config.toml)
|
|
let policy = load_config("config.toml")?;
|
|
|
|
// Parse from string
|
|
let toml_content = std::fs::read_to_string("config.toml")?;
|
|
let policy = parse_config(&toml_content)?;
|
|
|
|
// Access entries
|
|
for entry in &policy.entries {
|
|
println!("{}: {:?}", entry.label, entry.kind);
|
|
}
|
|
```
|
|
|
|
### Entry Kinds
|
|
|
|
Entries can be of several types:
|
|
|
|
```toml
|
|
# Regular process
|
|
kind = { type = "process", command = "/usr/bin/game", args = ["--fullscreen"] }
|
|
|
|
# Snap application
|
|
kind = { type = "snap", snap_name = "mc-installer" }
|
|
|
|
# Steam game (via Steam snap)
|
|
kind = { type = "steam", app_id = 504230 }
|
|
|
|
# Virtual machine (future)
|
|
kind = { type = "vm", driver = "qemu", args = { disk = "game.qcow2" } }
|
|
|
|
# Media playback (future)
|
|
kind = { type = "media", library_id = "movies" }
|
|
|
|
# Custom type
|
|
kind = { type = "custom", type_name = "my-launcher", payload = { ... } }
|
|
```
|
|
|
|
### Time Windows
|
|
|
|
Time windows control when entries are available:
|
|
|
|
```toml
|
|
[entries.availability]
|
|
[[entries.availability.windows]]
|
|
days = "weekdays" # or "weekends", "all"
|
|
start = "15:00"
|
|
end = "18:00"
|
|
|
|
[[entries.availability.windows]]
|
|
days = ["sat", "sun"] # Specific days
|
|
start = "09:00"
|
|
end = "21:00"
|
|
```
|
|
|
|
### Limits
|
|
|
|
Control session duration and frequency:
|
|
|
|
```toml
|
|
[entries.limits]
|
|
max_run_seconds = 1800 # Max duration per session
|
|
daily_quota_seconds = 7200 # Total daily limit
|
|
cooldown_seconds = 600 # Wait time between sessions
|
|
```
|
|
|
|
### Internet Requirements
|
|
|
|
Entries can require internet connectivity. When the device is offline, those entries are hidden.
|
|
|
|
```toml
|
|
[service.internet]
|
|
check = "https://connectivitycheck.gstatic.com/generate_204"
|
|
interval_seconds = 300
|
|
timeout_ms = 1500
|
|
|
|
[entries.internet]
|
|
required = true
|
|
# Optional per-entry override:
|
|
# check = "tcp://1.1.1.1:53"
|
|
```
|
|
|
|
## Validation
|
|
|
|
The configuration is validated at load time. Validation catches:
|
|
|
|
- **Duplicate entry IDs** - Each entry must have a unique ID
|
|
- **Empty commands** - Process entries must specify a command
|
|
- **Invalid time windows** - Start time must be before end time
|
|
- **Invalid thresholds** - Warning thresholds must be less than max run time
|
|
- **Negative durations** - All durations must be positive
|
|
- **Unknown kinds** - Entry types must be recognized (unless Custom)
|
|
|
|
```rust
|
|
use shepherd_config::{parse_config, ConfigError};
|
|
|
|
let result = parse_config(toml_str);
|
|
match result {
|
|
Ok(policy) => { /* Use policy */ }
|
|
Err(ConfigError::ValidationFailed { errors }) => {
|
|
for error in errors {
|
|
eprintln!("Config error: {}", error);
|
|
}
|
|
}
|
|
Err(e) => eprintln!("Failed to load config: {}", e),
|
|
}
|
|
```
|
|
|
|
## Hot Reload
|
|
|
|
Configuration can be reloaded at runtime via the service's `ReloadConfig` command or by sending `SIGHUP` to the service process. Reload is atomic: either the new configuration is fully applied or the old one remains.
|
|
|
|
Active sessions continue with their original time limits when configuration is reloaded.
|
|
|
|
## Key Types
|
|
|
|
- `Policy` - Validated policy ready for the core engine
|
|
- `Entry` - A launchable entry definition
|
|
- `AvailabilityPolicy` - Time window rules
|
|
- `LimitsPolicy` - Duration and quota limits
|
|
- `WarningPolicy` - Warning threshold configuration
|
|
- `VolumePolicy` - Volume restrictions
|
|
|
|
## Design Philosophy
|
|
|
|
- **Human-readable** - TOML is easy to read and write
|
|
- **Strict validation** - Catch errors at load time, not runtime
|
|
- **Versioned schema** - `config_version` enables future migrations
|
|
- **Sensible defaults** - Minimal config is valid
|
|
|
|
## Dependencies
|
|
|
|
- `toml` - TOML parsing
|
|
- `serde` - Deserialization
|
|
- `chrono` - Time types
|
|
- `thiserror` - Error types
|