:%s/daemon/service/g
This commit is contained in:
parent
c3f3770ea6
commit
f5d7d69578
25 changed files with 112 additions and 112 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
config_version = 1
|
config_version = 1
|
||||||
|
|
||||||
[daemon]
|
[service]
|
||||||
# Uncomment to customize paths
|
# Uncomment to customize paths
|
||||||
# socket_path = "/run/shepherdd/shepherdd.sock"
|
# socket_path = "/run/shepherdd/shepherdd.sock"
|
||||||
# log_dir = "/var/log/shepherdd"
|
# log_dir = "/var/log/shepherdd"
|
||||||
|
|
@ -15,24 +15,24 @@ default_max_run_seconds = 3600
|
||||||
|
|
||||||
# Global volume restrictions (optional)
|
# Global volume restrictions (optional)
|
||||||
# These apply when no entry-specific restrictions are defined
|
# These apply when no entry-specific restrictions are defined
|
||||||
[daemon.volume]
|
[service.volume]
|
||||||
max_volume = 80 # Maximum volume percentage (0-100)
|
max_volume = 80 # Maximum volume percentage (0-100)
|
||||||
# min_volume = 20 # Minimum volume percentage (0-100)
|
# min_volume = 20 # Minimum volume percentage (0-100)
|
||||||
allow_mute = true # Whether mute toggle is allowed
|
allow_mute = true # Whether mute toggle is allowed
|
||||||
allow_change = true # Whether volume changes are allowed at all
|
allow_change = true # Whether volume changes are allowed at all
|
||||||
|
|
||||||
# Default warning thresholds
|
# Default warning thresholds
|
||||||
[[daemon.default_warnings]]
|
[[service.default_warnings]]
|
||||||
seconds_before = 300
|
seconds_before = 300
|
||||||
severity = "info"
|
severity = "info"
|
||||||
message = "5 minutes remaining"
|
message = "5 minutes remaining"
|
||||||
|
|
||||||
[[daemon.default_warnings]]
|
[[service.default_warnings]]
|
||||||
seconds_before = 60
|
seconds_before = 60
|
||||||
severity = "warn"
|
severity = "warn"
|
||||||
message = "1 minute remaining!"
|
message = "1 minute remaining!"
|
||||||
|
|
||||||
[[daemon.default_warnings]]
|
[[service.default_warnings]]
|
||||||
seconds_before = 10
|
seconds_before = 10
|
||||||
severity = "critical"
|
severity = "critical"
|
||||||
message = "10 seconds remaining!"
|
message = "10 seconds remaining!"
|
||||||
|
|
@ -232,7 +232,7 @@ days = "weekends"
|
||||||
start = "10:00"
|
start = "10:00"
|
||||||
end = "20:00"
|
end = "20:00"
|
||||||
|
|
||||||
# No [entries.limits] section - uses daemon defaults
|
# No [entries.limits] section - uses service defaults
|
||||||
# Omitting limits entirely uses default_max_run_seconds
|
# Omitting limits entirely uses default_max_run_seconds
|
||||||
|
|
||||||
## === Media ===
|
## === Media ===
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ pub enum ErrorCode {
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "snake_case")]
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Get current daemon state
|
/// Get current service state
|
||||||
GetState,
|
GetState,
|
||||||
|
|
||||||
/// List available entries
|
/// List available entries
|
||||||
|
|
@ -160,7 +160,7 @@ pub enum Command {
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "snake_case")]
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
pub enum ResponsePayload {
|
pub enum ResponsePayload {
|
||||||
State(crate::DaemonStateSnapshot),
|
State(crate::ServiceStateSnapshot),
|
||||||
Entries(Vec<crate::EntryView>),
|
Entries(Vec<crate::EntryView>),
|
||||||
LaunchApproved {
|
LaunchApproved {
|
||||||
session_id: shepherd_util::SessionId,
|
session_id: shepherd_util::SessionId,
|
||||||
|
|
@ -234,7 +234,7 @@ mod tests {
|
||||||
fn response_serialization() {
|
fn response_serialization() {
|
||||||
let resp = Response::success(
|
let resp = Response::success(
|
||||||
1,
|
1,
|
||||||
ResponsePayload::State(crate::DaemonStateSnapshot {
|
ResponsePayload::State(crate::ServiceStateSnapshot {
|
||||||
api_version: API_VERSION,
|
api_version: API_VERSION,
|
||||||
policy_loaded: true,
|
policy_loaded: true,
|
||||||
current_session: None,
|
current_session: None,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use shepherd_util::{EntryId, SessionId};
|
use shepherd_util::{EntryId, SessionId};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::{DaemonStateSnapshot, SessionEndReason, WarningSeverity, API_VERSION};
|
use crate::{ServiceStateSnapshot, SessionEndReason, WarningSeverity, API_VERSION};
|
||||||
|
|
||||||
/// Event envelope
|
/// Event envelope
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
@ -25,12 +25,12 @@ impl Event {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All possible events from daemon to clients
|
/// All possible events from the service to clients
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "snake_case")]
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
pub enum EventPayload {
|
pub enum EventPayload {
|
||||||
/// Full state snapshot (sent on subscribe and major changes)
|
/// Full state snapshot (sent on subscribe and major changes)
|
||||||
StateChanged(DaemonStateSnapshot),
|
StateChanged(ServiceStateSnapshot),
|
||||||
|
|
||||||
/// Session has started
|
/// Session has started
|
||||||
SessionStarted {
|
SessionStarted {
|
||||||
|
|
@ -80,7 +80,7 @@ pub enum EventPayload {
|
||||||
muted: bool,
|
muted: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Daemon is shutting down
|
/// Service is shutting down
|
||||||
Shutdown,
|
Shutdown,
|
||||||
|
|
||||||
/// Audit event (for admin clients)
|
/// Audit event (for admin clients)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
//! Protocol types for shepherdd IPC
|
//! Protocol types for shepherdd IPC
|
||||||
//!
|
//!
|
||||||
//! This crate defines the stable API between the daemon and clients:
|
//! This crate defines the stable API between shepherdd and clients:
|
||||||
//! - Commands (requests from clients)
|
//! - Commands (requests from clients)
|
||||||
//! - Responses
|
//! - Responses
|
||||||
//! - Events (daemon -> clients)
|
//! - Events (service -> clients)
|
||||||
//! - Versioning
|
//! - Versioning
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,8 @@ pub enum SessionEndReason {
|
||||||
ProcessExited { exit_code: Option<i32> },
|
ProcessExited { exit_code: Option<i32> },
|
||||||
/// Policy change terminated session
|
/// Policy change terminated session
|
||||||
PolicyStop,
|
PolicyStop,
|
||||||
/// Daemon shutdown
|
/// Service shutdown
|
||||||
DaemonShutdown,
|
ServiceShutdown,
|
||||||
/// Launch failed
|
/// Launch failed
|
||||||
LaunchFailed { error: String },
|
LaunchFailed { error: String },
|
||||||
}
|
}
|
||||||
|
|
@ -187,9 +187,9 @@ pub struct SessionInfo {
|
||||||
pub warnings_issued: Vec<u64>,
|
pub warnings_issued: Vec<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Full daemon state snapshot
|
/// Full service state snapshot
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct DaemonStateSnapshot {
|
pub struct ServiceStateSnapshot {
|
||||||
pub api_version: u32,
|
pub api_version: u32,
|
||||||
pub policy_loaded: bool,
|
pub policy_loaded: bool,
|
||||||
pub current_session: Option<SessionInfo>,
|
pub current_session: Option<SessionInfo>,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Validated policy structures
|
//! Validated policy structures
|
||||||
|
|
||||||
use crate::schema::{RawConfig, RawDays, RawEntry, RawEntryKind, RawVolumeConfig, RawWarningThreshold};
|
use crate::schema::{RawConfig, RawDays, RawEntry, RawEntryKind, RawVolumeConfig, RawServiceConfig, RawWarningThreshold};
|
||||||
use crate::validation::{parse_days, parse_time};
|
use crate::validation::{parse_days, parse_time};
|
||||||
use shepherd_api::{EntryKind, WarningSeverity, WarningThreshold};
|
use shepherd_api::{EntryKind, WarningSeverity, WarningThreshold};
|
||||||
use shepherd_util::{DaysOfWeek, EntryId, TimeWindow, WallClock};
|
use shepherd_util::{DaysOfWeek, EntryId, TimeWindow, WallClock};
|
||||||
|
|
@ -11,8 +11,8 @@ use std::time::Duration;
|
||||||
/// Validated policy ready for use by the core engine
|
/// Validated policy ready for use by the core engine
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Policy {
|
pub struct Policy {
|
||||||
/// Daemon configuration
|
/// Service configuration
|
||||||
pub daemon: DaemonConfig,
|
pub service: ServiceConfig,
|
||||||
|
|
||||||
/// Validated entries
|
/// Validated entries
|
||||||
pub entries: Vec<Entry>,
|
pub entries: Vec<Entry>,
|
||||||
|
|
@ -31,7 +31,7 @@ impl Policy {
|
||||||
/// Convert from raw config (after validation)
|
/// Convert from raw config (after validation)
|
||||||
pub fn from_raw(raw: RawConfig) -> Self {
|
pub fn from_raw(raw: RawConfig) -> Self {
|
||||||
let default_warnings = raw
|
let default_warnings = raw
|
||||||
.daemon
|
.service
|
||||||
.default_warnings
|
.default_warnings
|
||||||
.clone()
|
.clone()
|
||||||
.map(|w| w.into_iter().map(convert_warning).collect())
|
.map(|w| w.into_iter().map(convert_warning).collect())
|
||||||
|
|
@ -39,13 +39,13 @@ impl Policy {
|
||||||
|
|
||||||
// 0 means unlimited, None means use 1 hour default
|
// 0 means unlimited, None means use 1 hour default
|
||||||
let default_max_run = raw
|
let default_max_run = raw
|
||||||
.daemon
|
.service
|
||||||
.default_max_run_seconds
|
.default_max_run_seconds
|
||||||
.map(seconds_to_duration_or_unlimited)
|
.map(seconds_to_duration_or_unlimited)
|
||||||
.unwrap_or(Some(Duration::from_secs(3600))); // 1 hour default
|
.unwrap_or(Some(Duration::from_secs(3600))); // 1 hour default
|
||||||
|
|
||||||
let global_volume = raw
|
let global_volume = raw
|
||||||
.daemon
|
.service
|
||||||
.volume
|
.volume
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(convert_volume_config)
|
.map(convert_volume_config)
|
||||||
|
|
@ -58,7 +58,7 @@ impl Policy {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
daemon: DaemonConfig::from_raw(raw.daemon),
|
service: ServiceConfig::from_raw(raw.service),
|
||||||
entries,
|
entries,
|
||||||
default_warnings,
|
default_warnings,
|
||||||
default_max_run,
|
default_max_run,
|
||||||
|
|
@ -72,16 +72,16 @@ impl Policy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Daemon configuration
|
/// Service configuration
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DaemonConfig {
|
pub struct ServiceConfig {
|
||||||
pub socket_path: PathBuf,
|
pub socket_path: PathBuf,
|
||||||
pub log_dir: PathBuf,
|
pub log_dir: PathBuf,
|
||||||
pub data_dir: PathBuf,
|
pub data_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DaemonConfig {
|
impl ServiceConfig {
|
||||||
fn from_raw(raw: crate::schema::RawDaemonConfig) -> Self {
|
fn from_raw(raw: RawServiceConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
socket_path: raw
|
socket_path: raw
|
||||||
.socket_path
|
.socket_path
|
||||||
|
|
@ -96,7 +96,7 @@ impl DaemonConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DaemonConfig {
|
impl Default for ServiceConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
socket_path: PathBuf::from("/run/shepherdd/shepherdd.sock"),
|
socket_path: PathBuf::from("/run/shepherdd/shepherdd.sock"),
|
||||||
|
|
@ -208,9 +208,9 @@ pub struct LimitsPolicy {
|
||||||
/// Volume control policy
|
/// Volume control policy
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct VolumePolicy {
|
pub struct VolumePolicy {
|
||||||
/// Maximum volume percentage allowed (enforced by daemon)
|
/// Maximum volume percentage allowed (enforced by the service)
|
||||||
pub max_volume: Option<u8>,
|
pub max_volume: Option<u8>,
|
||||||
/// Minimum volume percentage allowed (enforced by daemon)
|
/// Minimum volume percentage allowed (enforced by the service)
|
||||||
pub min_volume: Option<u8>,
|
pub min_volume: Option<u8>,
|
||||||
/// Whether mute toggle is allowed
|
/// Whether mute toggle is allowed
|
||||||
pub allow_mute: bool,
|
pub allow_mute: bool,
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,18 @@ pub struct RawConfig {
|
||||||
/// Config schema version
|
/// Config schema version
|
||||||
pub config_version: u32,
|
pub config_version: u32,
|
||||||
|
|
||||||
/// Global daemon settings
|
/// Global service settings
|
||||||
#[serde(default)]
|
#[serde(default, alias = "daemon")]
|
||||||
pub daemon: RawDaemonConfig,
|
pub service: RawServiceConfig,
|
||||||
|
|
||||||
/// List of allowed entries
|
/// List of allowed entries
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub entries: Vec<RawEntry>,
|
pub entries: Vec<RawEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Daemon-level settings
|
/// Service-level settings
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
pub struct RawDaemonConfig {
|
pub struct RawServiceConfig {
|
||||||
/// IPC socket path (default: /run/shepherdd/shepherdd.sock)
|
/// IPC socket path (default: /run/shepherdd/shepherdd.sock)
|
||||||
pub socket_path: Option<PathBuf>,
|
pub socket_path: Option<PathBuf>,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ fn validate_entry(entry: &RawEntry, config: &RawConfig) -> Vec<ValidationError>
|
||||||
.limits
|
.limits
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|l| l.max_run_seconds)
|
.and_then(|l| l.max_run_seconds)
|
||||||
.or(config.daemon.default_max_run_seconds);
|
.or(config.service.default_max_run_seconds);
|
||||||
|
|
||||||
// Only validate warnings if max_run is Some and not 0 (unlimited)
|
// Only validate warnings if max_run is Some and not 0 (unlimited)
|
||||||
if let (Some(warnings), Some(max_run)) = (&entry.warnings, max_run) {
|
if let (Some(warnings), Some(max_run)) = (&entry.warnings, max_run) {
|
||||||
|
|
@ -245,7 +245,7 @@ mod tests {
|
||||||
fn test_duplicate_id_detection() {
|
fn test_duplicate_id_detection() {
|
||||||
let config = RawConfig {
|
let config = RawConfig {
|
||||||
config_version: 1,
|
config_version: 1,
|
||||||
daemon: Default::default(),
|
service: Default::default(),
|
||||||
entries: vec![
|
entries: vec![
|
||||||
RawEntry {
|
RawEntry {
|
||||||
id: "game".into(),
|
id: "game".into(),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
use shepherd_api::{
|
use shepherd_api::{
|
||||||
DaemonStateSnapshot, EntryKindTag, EntryView, ReasonCode, SessionEndReason,
|
ServiceStateSnapshot, EntryKindTag, EntryView, ReasonCode, SessionEndReason,
|
||||||
WarningSeverity, API_VERSION,
|
WarningSeverity, API_VERSION,
|
||||||
};
|
};
|
||||||
use shepherd_config::{Entry, Policy};
|
use shepherd_config::{Entry, Policy};
|
||||||
|
|
@ -472,8 +472,8 @@ impl CoreEngine {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current daemon state snapshot
|
/// Get current service state snapshot
|
||||||
pub fn get_state(&self) -> DaemonStateSnapshot {
|
pub fn get_state(&self) -> ServiceStateSnapshot {
|
||||||
let current_session = self.current_session.as_ref().map(|s| {
|
let current_session = self.current_session.as_ref().map(|s| {
|
||||||
s.to_session_info(MonotonicInstant::now())
|
s.to_session_info(MonotonicInstant::now())
|
||||||
});
|
});
|
||||||
|
|
@ -481,7 +481,7 @@ impl CoreEngine {
|
||||||
// Build entry views for the snapshot
|
// Build entry views for the snapshot
|
||||||
let entries = self.list_entries(shepherd_util::now());
|
let entries = self.list_entries(shepherd_util::now());
|
||||||
|
|
||||||
DaemonStateSnapshot {
|
ServiceStateSnapshot {
|
||||||
api_version: API_VERSION,
|
api_version: API_VERSION,
|
||||||
policy_loaded: true,
|
policy_loaded: true,
|
||||||
current_session,
|
current_session,
|
||||||
|
|
@ -553,7 +553,7 @@ mod tests {
|
||||||
|
|
||||||
fn make_test_policy() -> Policy {
|
fn make_test_policy() -> Policy {
|
||||||
Policy {
|
Policy {
|
||||||
daemon: Default::default(),
|
service: Default::default(),
|
||||||
entries: vec![Entry {
|
entries: vec![Entry {
|
||||||
id: EntryId::new("test-game"),
|
id: EntryId::new("test-game"),
|
||||||
label: "Test Game".into(),
|
label: "Test Game".into(),
|
||||||
|
|
@ -661,7 +661,7 @@ mod tests {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
disabled_reason: None,
|
disabled_reason: None,
|
||||||
}],
|
}],
|
||||||
daemon: Default::default(),
|
service: Default::default(),
|
||||||
default_warnings: vec![],
|
default_warnings: vec![],
|
||||||
default_max_run: Some(Duration::from_secs(3600)),
|
default_max_run: Some(Duration::from_secs(3600)),
|
||||||
volume: Default::default(),
|
volume: Default::default(),
|
||||||
|
|
@ -722,7 +722,7 @@ mod tests {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
disabled_reason: None,
|
disabled_reason: None,
|
||||||
}],
|
}],
|
||||||
daemon: Default::default(),
|
service: Default::default(),
|
||||||
default_warnings: vec![],
|
default_warnings: vec![],
|
||||||
default_max_run: Some(Duration::from_secs(3600)),
|
default_max_run: Some(Duration::from_secs(3600)),
|
||||||
volume: Default::default(),
|
volume: Default::default(),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Host adapter trait interfaces for shepherdd
|
//! Host adapter trait interfaces for shepherdd
|
||||||
//!
|
//!
|
||||||
//! This crate defines the capability-based interface between the daemon core
|
//! This crate defines the capability-based interface between the shepherdd service
|
||||||
//! and platform-specific implementations. It contains no platform code itself.
|
//! and platform-specific implementations. It contains no platform code itself.
|
||||||
|
|
||||||
mod capabilities;
|
mod capabilities;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Volume control trait interfaces
|
//! Volume control trait interfaces
|
||||||
//!
|
//!
|
||||||
//! Defines the capability-based interface for volume control between
|
//! Defines the capability-based interface for volume control between
|
||||||
//! the daemon core and platform-specific implementations.
|
//! the shepherdd service and platform-specific implementations.
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -67,9 +67,9 @@ pub struct VolumeCapabilities {
|
||||||
/// Volume restrictions that can be enforced by policy
|
/// Volume restrictions that can be enforced by policy
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct VolumeRestrictions {
|
pub struct VolumeRestrictions {
|
||||||
/// Maximum volume percentage allowed (enforced by daemon)
|
/// Maximum volume percentage allowed (enforced by the service)
|
||||||
pub max_volume: Option<u8>,
|
pub max_volume: Option<u8>,
|
||||||
/// Minimum volume percentage allowed (enforced by daemon)
|
/// Minimum volume percentage allowed (enforced by the service)
|
||||||
pub min_volume: Option<u8>,
|
pub min_volume: Option<u8>,
|
||||||
/// Whether mute toggle is allowed
|
/// Whether mute toggle is allowed
|
||||||
pub allow_mute: bool,
|
pub allow_mute: bool,
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ impl LinuxHost {
|
||||||
info!(pid = pid, pgid = pgid, status = ?status, "Process exited - sending HostEvent::Exited");
|
info!(pid = pid, pgid = pgid, status = ?status, "Process exited - sending HostEvent::Exited");
|
||||||
|
|
||||||
// We don't have the session_id here, so we use a placeholder
|
// We don't have the session_id here, so we use a placeholder
|
||||||
// The daemon should track the mapping
|
// The service should track the mapping
|
||||||
let handle = HostSessionHandle::new(
|
let handle = HostSessionHandle::new(
|
||||||
SessionId::new(), // This will be matched by PID
|
SessionId::new(), // This will be matched by PID
|
||||||
HostHandlePayload::Linux { pid, pgid },
|
HostHandlePayload::Linux { pid, pgid },
|
||||||
|
|
|
||||||
|
|
@ -225,8 +225,8 @@ impl ManagedProcess {
|
||||||
|
|
||||||
// Special handling for WAYLAND_DISPLAY:
|
// Special handling for WAYLAND_DISPLAY:
|
||||||
// If SHEPHERD_WAYLAND_DISPLAY is set, use that instead of the inherited value.
|
// If SHEPHERD_WAYLAND_DISPLAY is set, use that instead of the inherited value.
|
||||||
// This allows apps to be launched on a nested compositor while the daemon
|
// This allows apps to be launched on a nested compositor while the service
|
||||||
// runs on the parent compositor. When the daemon runs inside the nested
|
// runs on the parent compositor. When the service runs inside the nested
|
||||||
// compositor, this is not needed as WAYLAND_DISPLAY is already correct.
|
// compositor, this is not needed as WAYLAND_DISPLAY is already correct.
|
||||||
if let Ok(shepherd_display) = std::env::var("SHEPHERD_WAYLAND_DISPLAY") {
|
if let Ok(shepherd_display) = std::env::var("SHEPHERD_WAYLAND_DISPLAY") {
|
||||||
debug!(display = %shepherd_display, "Using SHEPHERD_WAYLAND_DISPLAY override for child process");
|
debug!(display = %shepherd_display, "Using SHEPHERD_WAYLAND_DISPLAY override for child process");
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ fn build_hud_content(state: SharedState) -> gtk4::Box {
|
||||||
volume_slider.set_increments(5.0, 10.0);
|
volume_slider.set_increments(5.0, 10.0);
|
||||||
volume_slider.add_css_class("volume-slider");
|
volume_slider.add_css_class("volume-slider");
|
||||||
|
|
||||||
// Set initial value from daemon
|
// Set initial value from shepherdd
|
||||||
if let Some(info) = crate::volume::get_volume_status() {
|
if let Some(info) = crate::volume::get_volume_status() {
|
||||||
volume_slider.set_value(info.percent as f64);
|
volume_slider.set_value(info.percent as f64);
|
||||||
}
|
}
|
||||||
|
|
@ -333,7 +333,7 @@ fn build_hud_content(state: SharedState) -> gtk4::Box {
|
||||||
let session_state = state_for_close.session_state();
|
let session_state = state_for_close.session_state();
|
||||||
if let Some(session_id) = session_state.session_id() {
|
if let Some(session_id) = session_state.session_id() {
|
||||||
tracing::info!("Requesting end session for {}", session_id);
|
tracing::info!("Requesting end session for {}", session_id);
|
||||||
// Send StopCurrent command to daemon
|
// Send StopCurrent command to shepherdd
|
||||||
let socket_path = std::env::var("SHEPHERD_SOCKET")
|
let socket_path = std::env::var("SHEPHERD_SOCKET")
|
||||||
.unwrap_or_else(|_| "./dev-runtime/shepherd.sock".to_string());
|
.unwrap_or_else(|_| "./dev-runtime/shepherd.sock".to_string());
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
|
|
@ -349,7 +349,7 @@ fn build_hud_content(state: SharedState) -> gtk4::Box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Failed to connect to daemon: {}", e);
|
tracing::error!("Failed to connect to shepherdd: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Volume monitoring and control module
|
//! Volume monitoring and control module
|
||||||
//!
|
//!
|
||||||
//! Provides volume status and control via the shepherdd daemon.
|
//! Provides volume status and control via shepherdd.
|
||||||
//! The daemon handles actual volume control and enforces restrictions.
|
//! The service handles actual volume control and enforces restrictions.
|
||||||
|
|
||||||
use shepherd_api::{Command, ResponsePayload, VolumeInfo};
|
use shepherd_api::{Command, ResponsePayload, VolumeInfo};
|
||||||
use shepherd_ipc::IpcClient;
|
use shepherd_ipc::IpcClient;
|
||||||
|
|
@ -15,7 +15,7 @@ fn get_socket_path() -> PathBuf {
|
||||||
.unwrap_or_else(|_| PathBuf::from("./dev-runtime/shepherd.sock"))
|
.unwrap_or_else(|_| PathBuf::from("./dev-runtime/shepherd.sock"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current volume status from the daemon
|
/// Get current volume status from shepherdd
|
||||||
pub fn get_volume_status() -> Option<VolumeInfo> {
|
pub fn get_volume_status() -> Option<VolumeInfo> {
|
||||||
let socket_path = get_socket_path();
|
let socket_path = get_socket_path();
|
||||||
|
|
||||||
|
|
@ -45,14 +45,14 @@ pub fn get_volume_status() -> Option<VolumeInfo> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::debug!("Failed to connect to daemon for volume: {}", e);
|
tracing::debug!("Failed to connect to shepherdd for volume: {}", e);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toggle mute state via the daemon
|
/// Toggle mute state via shepherdd
|
||||||
pub fn toggle_mute() -> anyhow::Result<()> {
|
pub fn toggle_mute() -> anyhow::Result<()> {
|
||||||
let socket_path = get_socket_path();
|
let socket_path = get_socket_path();
|
||||||
|
|
||||||
|
|
@ -75,7 +75,7 @@ pub fn toggle_mute() -> anyhow::Result<()> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increase volume by a step via the daemon
|
/// Increase volume by a step via shepherdd
|
||||||
pub fn volume_up(step: u8) -> anyhow::Result<()> {
|
pub fn volume_up(step: u8) -> anyhow::Result<()> {
|
||||||
let socket_path = get_socket_path();
|
let socket_path = get_socket_path();
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@ pub fn volume_up(step: u8) -> anyhow::Result<()> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrease volume by a step via the daemon
|
/// Decrease volume by a step via shepherdd
|
||||||
pub fn volume_down(step: u8) -> anyhow::Result<()> {
|
pub fn volume_down(step: u8) -> anyhow::Result<()> {
|
||||||
let socket_path = get_socket_path();
|
let socket_path = get_socket_path();
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ pub fn volume_down(step: u8) -> anyhow::Result<()> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set volume to a specific percentage via the daemon
|
/// Set volume to a specific percentage via shepherdd
|
||||||
pub fn set_volume(percent: u8) -> anyhow::Result<()> {
|
pub fn set_volume(percent: u8) -> anyhow::Result<()> {
|
||||||
let socket_path = get_socket_path();
|
let socket_path = get_socket_path();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub struct IpcClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IpcClient {
|
impl IpcClient {
|
||||||
/// Connect to the daemon
|
/// Connect to shepherdd
|
||||||
pub async fn connect(socket_path: impl AsRef<Path>) -> IpcResult<Self> {
|
pub async fn connect(socket_path: impl AsRef<Path>) -> IpcResult<Self> {
|
||||||
let stream = UnixStream::connect(socket_path).await?;
|
let stream = UnixStream::connect(socket_path).await?;
|
||||||
let (read_half, write_half) = stream.into_split();
|
let (read_half, write_half) = stream.into_split();
|
||||||
|
|
@ -67,7 +67,7 @@ impl IpcClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stream of events from the daemon
|
/// Stream of events from shepherdd
|
||||||
pub struct EventStream {
|
pub struct EventStream {
|
||||||
reader: BufReader<tokio::net::unix::OwnedReadHalf>,
|
reader: BufReader<tokio::net::unix::OwnedReadHalf>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use tokio::runtime::Runtime;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::client::{ClientCommand, CommandClient, DaemonClient};
|
use crate::client::{ClientCommand, CommandClient, ServiceClient};
|
||||||
use crate::grid::LauncherGrid;
|
use crate::grid::LauncherGrid;
|
||||||
use crate::state::{LauncherState, SharedState};
|
use crate::state::{LauncherState, SharedState};
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ impl LauncherApp {
|
||||||
match client.launch(&entry_id).await {
|
match client.launch(&entry_id).await {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
debug!(response = ?response, "Launch response");
|
debug!(response = ?response, "Launch response");
|
||||||
// Handle error responses from daemon
|
// Handle error responses from shepherdd
|
||||||
match response.result {
|
match response.result {
|
||||||
shepherd_api::ResponseResult::Ok(payload) => {
|
shepherd_api::ResponseResult::Ok(payload) => {
|
||||||
// Check what kind of success response we got
|
// Check what kind of success response we got
|
||||||
|
|
@ -227,7 +227,7 @@ impl LauncherApp {
|
||||||
shepherd_api::ResponseResult::Err(err) => {
|
shepherd_api::ResponseResult::Err(err) => {
|
||||||
// Launch failed on server side - refresh state to recover
|
// Launch failed on server side - refresh state to recover
|
||||||
error!(error = %err.message, "Launch failed on server");
|
error!(error = %err.message, "Launch failed on server");
|
||||||
// Request fresh state from daemon to get back to correct state
|
// Request fresh state from shepherdd to get back to correct state
|
||||||
match client.get_state().await {
|
match client.get_state().await {
|
||||||
Ok(state_resp) => {
|
Ok(state_resp) => {
|
||||||
if let shepherd_api::ResponseResult::Ok(
|
if let shepherd_api::ResponseResult::Ok(
|
||||||
|
|
@ -293,14 +293,14 @@ impl LauncherApp {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start daemon client in background thread (separate from GTK main loop)
|
// Start shepherdd client in background thread (separate from GTK main loop)
|
||||||
// This ensures the tokio runtime is properly driven for event reception
|
// This ensures the tokio runtime is properly driven for event reception
|
||||||
let state_for_client = state.clone();
|
let state_for_client = state.clone();
|
||||||
let socket_for_client = socket_path.clone();
|
let socket_for_client = socket_path.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime for event loop");
|
let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime for event loop");
|
||||||
rt.block_on(async move {
|
rt.block_on(async move {
|
||||||
let client = DaemonClient::new(socket_for_client, state_for_client, command_rx);
|
let client = ServiceClient::new(socket_for_client, state_for_client, command_rx);
|
||||||
client.run().await;
|
client.run().await;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,13 @@ pub enum ClientCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Client connection manager
|
/// Client connection manager
|
||||||
pub struct DaemonClient {
|
pub struct ServiceClient {
|
||||||
socket_path: std::path::PathBuf,
|
socket_path: std::path::PathBuf,
|
||||||
state: SharedState,
|
state: SharedState,
|
||||||
command_rx: mpsc::UnboundedReceiver<ClientCommand>,
|
command_rx: mpsc::UnboundedReceiver<ClientCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DaemonClient {
|
impl ServiceClient {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
socket_path: impl AsRef<Path>,
|
socket_path: impl AsRef<Path>,
|
||||||
state: SharedState,
|
state: SharedState,
|
||||||
|
|
@ -67,13 +67,13 @@ impl DaemonClient {
|
||||||
async fn connect_and_run(&mut self) -> Result<()> {
|
async fn connect_and_run(&mut self) -> Result<()> {
|
||||||
self.state.set(LauncherState::Connecting);
|
self.state.set(LauncherState::Connecting);
|
||||||
|
|
||||||
info!(path = %self.socket_path.display(), "Connecting to daemon");
|
info!(path = %self.socket_path.display(), "Connecting to shepherdd");
|
||||||
|
|
||||||
let mut client = IpcClient::connect(&self.socket_path)
|
let mut client = IpcClient::connect(&self.socket_path)
|
||||||
.await
|
.await
|
||||||
.context("Failed to connect to daemon")?;
|
.context("Failed to connect to shepherdd")?;
|
||||||
|
|
||||||
info!("Connected to daemon");
|
info!("Connected to shepherdd");
|
||||||
|
|
||||||
// Get initial state (includes entries)
|
// Get initial state (includes entries)
|
||||||
info!("Sending GetState command");
|
info!("Sending GetState command");
|
||||||
|
|
@ -116,11 +116,11 @@ impl DaemonClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle events from daemon
|
// Handle events from shepherdd
|
||||||
event_result = events.next() => {
|
event_result = events.next() => {
|
||||||
match event_result {
|
match event_result {
|
||||||
Ok(event) => {
|
Ok(event) => {
|
||||||
info!(event = ?event, "Received event from daemon (client.rs)");
|
info!(event = ?event, "Received event from shepherdd (client.rs)");
|
||||||
self.state.handle_event(event);
|
self.state.handle_event(event);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Launcher application state management
|
//! Launcher application state management
|
||||||
|
|
||||||
use shepherd_api::{DaemonStateSnapshot, EntryView, Event, EventPayload};
|
use shepherd_api::{ServiceStateSnapshot, EntryView, Event, EventPayload};
|
||||||
use shepherd_util::SessionId;
|
use shepherd_util::SessionId;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
@ -9,7 +9,7 @@ use tokio::sync::watch;
|
||||||
/// Current state of the launcher UI
|
/// Current state of the launcher UI
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LauncherState {
|
pub enum LauncherState {
|
||||||
/// Not connected to daemon
|
/// Not connected to shepherdd
|
||||||
Disconnected,
|
Disconnected,
|
||||||
/// Connected, waiting for initial state
|
/// Connected, waiting for initial state
|
||||||
Connecting,
|
Connecting,
|
||||||
|
|
@ -58,9 +58,9 @@ impl SharedState {
|
||||||
self.receiver.clone()
|
self.receiver.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update state from daemon event
|
/// Update state from shepherdd event
|
||||||
pub fn handle_event(&self, event: Event) {
|
pub fn handle_event(&self, event: Event) {
|
||||||
tracing::info!(event = ?event.payload, "Received event from daemon");
|
tracing::info!(event = ?event.payload, "Received event from shepherdd");
|
||||||
match event.payload {
|
match event.payload {
|
||||||
EventPayload::StateChanged(snapshot) => {
|
EventPayload::StateChanged(snapshot) => {
|
||||||
tracing::info!(has_session = snapshot.current_session.is_some(), "Applying state snapshot");
|
tracing::info!(has_session = snapshot.current_session.is_some(), "Applying state snapshot");
|
||||||
|
|
@ -109,7 +109,7 @@ impl SharedState {
|
||||||
self.set(LauncherState::Connecting);
|
self.set(LauncherState::Connecting);
|
||||||
}
|
}
|
||||||
EventPayload::Shutdown => {
|
EventPayload::Shutdown => {
|
||||||
// Daemon is shutting down
|
// Service is shutting down
|
||||||
self.set(LauncherState::Disconnected);
|
self.set(LauncherState::Disconnected);
|
||||||
}
|
}
|
||||||
EventPayload::AuditEntry { .. } => {
|
EventPayload::AuditEntry { .. } => {
|
||||||
|
|
@ -121,7 +121,7 @@ impl SharedState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_snapshot(&self, snapshot: DaemonStateSnapshot) {
|
fn apply_snapshot(&self, snapshot: ServiceStateSnapshot) {
|
||||||
if let Some(session) = snapshot.current_session {
|
if let Some(session) = snapshot.current_session {
|
||||||
let now = shepherd_util::now();
|
let now = shepherd_util::now();
|
||||||
// For unlimited sessions (deadline=None), time_remaining is None
|
// For unlimited sessions (deadline=None), time_remaining is None
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ use std::time::Duration;
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "snake_case")]
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
pub enum AuditEventType {
|
pub enum AuditEventType {
|
||||||
/// Daemon started
|
/// Service started
|
||||||
DaemonStarted,
|
ServiceStarted,
|
||||||
|
|
||||||
/// Daemon stopped
|
/// Service stopped
|
||||||
DaemonStopped,
|
ServiceStopped,
|
||||||
|
|
||||||
/// Policy loaded/reloaded
|
/// Policy loaded/reloaded
|
||||||
PolicyLoaded { entry_count: usize },
|
PolicyLoaded { entry_count: usize },
|
||||||
|
|
|
||||||
|
|
@ -272,12 +272,12 @@ mod tests {
|
||||||
fn test_audit_log() {
|
fn test_audit_log() {
|
||||||
let store = SqliteStore::in_memory().unwrap();
|
let store = SqliteStore::in_memory().unwrap();
|
||||||
|
|
||||||
let event = AuditEvent::new(AuditEventType::DaemonStarted);
|
let event = AuditEvent::new(AuditEventType::ServiceStarted);
|
||||||
store.append_audit(event).unwrap();
|
store.append_audit(event).unwrap();
|
||||||
|
|
||||||
let events = store.get_recent_audits(10).unwrap();
|
let events = store.get_recent_audits(10).unwrap();
|
||||||
assert_eq!(events.len(), 1);
|
assert_eq!(events.len(), 1);
|
||||||
assert!(matches!(events[0].event, AuditEventType::DaemonStarted));
|
assert!(matches!(events[0].event, AuditEventType::ServiceStarted));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ name = "shepherdd"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description = "The shepherdd daemon: policy enforcement for child-focused computing"
|
description = "The shepherdd background service: policy enforcement for child-focused computing"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "shepherdd"
|
name = "shepherdd"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//! shepherdd - The shepherd daemon
|
//! shepherdd - The shepherd background service
|
||||||
//!
|
//!
|
||||||
//! This is the main entry point for the shepherdd service.
|
//! This is the main entry point for the shepherdd service.
|
||||||
//! It wires together all the components:
|
//! It wires together all the components:
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use shepherd_api::{
|
use shepherd_api::{
|
||||||
Command, DaemonStateSnapshot, ErrorCode, ErrorInfo, Event, EventPayload, HealthStatus,
|
Command, ServiceStateSnapshot, ErrorCode, ErrorInfo, Event, EventPayload, HealthStatus,
|
||||||
Response, ResponsePayload, SessionEndReason, StopMode, VolumeInfo, VolumeRestrictions,
|
Response, ResponsePayload, SessionEndReason, StopMode, VolumeInfo, VolumeRestrictions,
|
||||||
API_VERSION,
|
API_VERSION,
|
||||||
};
|
};
|
||||||
|
|
@ -30,10 +30,10 @@ use tokio::sync::Mutex;
|
||||||
use tracing::{debug, error, info, warn, Level};
|
use tracing::{debug, error, info, warn, Level};
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
/// shepherdd - Policy enforcement daemon for child-focused computing
|
/// shepherdd - Policy enforcement service for child-focused computing
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(name = "shepherdd")]
|
#[command(name = "shepherdd")]
|
||||||
#[command(about = "Policy enforcement daemon for child-focused computing", long_about = None)]
|
#[command(about = "Policy enforcement service for child-focused computing", long_about = None)]
|
||||||
struct Args {
|
struct Args {
|
||||||
/// Configuration file path
|
/// Configuration file path
|
||||||
#[arg(short, long, default_value = "/etc/shepherdd/config.toml")]
|
#[arg(short, long, default_value = "/etc/shepherdd/config.toml")]
|
||||||
|
|
@ -52,8 +52,8 @@ struct Args {
|
||||||
log_level: String,
|
log_level: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main daemon state
|
/// Main service state
|
||||||
struct Daemon {
|
struct Service {
|
||||||
engine: CoreEngine,
|
engine: CoreEngine,
|
||||||
host: Arc<LinuxHost>,
|
host: Arc<LinuxHost>,
|
||||||
volume: Arc<LinuxVolumeController>,
|
volume: Arc<LinuxVolumeController>,
|
||||||
|
|
@ -62,7 +62,7 @@ struct Daemon {
|
||||||
rate_limiter: RateLimiter,
|
rate_limiter: RateLimiter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Daemon {
|
impl Service {
|
||||||
async fn new(args: &Args) -> Result<Self> {
|
async fn new(args: &Args) -> Result<Self> {
|
||||||
// Load configuration
|
// Load configuration
|
||||||
let policy = load_config(&args.config)
|
let policy = load_config(&args.config)
|
||||||
|
|
@ -78,12 +78,12 @@ impl Daemon {
|
||||||
let socket_path = args
|
let socket_path = args
|
||||||
.socket
|
.socket
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| policy.daemon.socket_path.clone());
|
.unwrap_or_else(|| policy.service.socket_path.clone());
|
||||||
|
|
||||||
let data_dir = args
|
let data_dir = args
|
||||||
.data_dir
|
.data_dir
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| policy.daemon.data_dir.clone());
|
.unwrap_or_else(|| policy.service.data_dir.clone());
|
||||||
|
|
||||||
// Create data directory
|
// Create data directory
|
||||||
std::fs::create_dir_all(&data_dir)
|
std::fs::create_dir_all(&data_dir)
|
||||||
|
|
@ -98,8 +98,8 @@ impl Daemon {
|
||||||
|
|
||||||
info!(db_path = %db_path.display(), "Store initialized");
|
info!(db_path = %db_path.display(), "Store initialized");
|
||||||
|
|
||||||
// Log daemon start
|
// Log service start
|
||||||
store.append_audit(AuditEvent::new(AuditEventType::DaemonStarted))?;
|
store.append_audit(AuditEvent::new(AuditEventType::ServiceStarted))?;
|
||||||
|
|
||||||
// Initialize host adapter
|
// Initialize host adapter
|
||||||
let host = Arc::new(LinuxHost::new());
|
let host = Arc::new(LinuxHost::new());
|
||||||
|
|
@ -168,7 +168,7 @@ impl Daemon {
|
||||||
let tick_interval = Duration::from_millis(100);
|
let tick_interval = Duration::from_millis(100);
|
||||||
let mut tick_timer = tokio::time::interval(tick_interval);
|
let mut tick_timer = tokio::time::interval(tick_interval);
|
||||||
|
|
||||||
info!("Daemon running");
|
info!("Service running");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
|
@ -940,7 +940,7 @@ async fn main() -> Result<()> {
|
||||||
"shepherdd starting"
|
"shepherdd starting"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create and run daemon
|
// Create and run the service
|
||||||
let daemon = Daemon::new(&args).await?;
|
let service = Service::new(&args).await?;
|
||||||
daemon.run().await
|
service.run().await
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
//! Integration tests for shepherdd
|
//! Integration tests for shepherdd
|
||||||
//!
|
//!
|
||||||
//! These tests verify the end-to-end behavior of the daemon.
|
//! These tests verify the end-to-end behavior of shepherdd.
|
||||||
|
|
||||||
use shepherd_api::{EntryKind, WarningSeverity, WarningThreshold};
|
use shepherd_api::{EntryKind, WarningSeverity, WarningThreshold};
|
||||||
use shepherd_config::{AvailabilityPolicy, Entry, LimitsPolicy, Policy};
|
use shepherd_config::{AvailabilityPolicy, Entry, LimitsPolicy, Policy};
|
||||||
|
|
@ -14,7 +14,7 @@ use std::time::Duration;
|
||||||
|
|
||||||
fn make_test_policy() -> Policy {
|
fn make_test_policy() -> Policy {
|
||||||
Policy {
|
Policy {
|
||||||
daemon: Default::default(),
|
service: Default::default(),
|
||||||
entries: vec![
|
entries: vec![
|
||||||
Entry {
|
Entry {
|
||||||
id: EntryId::new("test-game"),
|
id: EntryId::new("test-game"),
|
||||||
|
|
|
||||||
|
|
@ -132,16 +132,16 @@ workspace 1 output *
|
||||||
|
|
||||||
### Application startup
|
### Application startup
|
||||||
|
|
||||||
# Start the daemon FIRST - it needs to create the socket before HUD/launcher connect
|
# Start shepherdd FIRST - it needs to create the socket before HUD/launcher connect
|
||||||
# Running inside sway ensures all spawned processes use the nested compositor
|
# Running inside sway ensures all spawned processes use the nested compositor
|
||||||
exec ./target/debug/shepherdd -c ./config.example.toml
|
exec ./target/debug/shepherdd -c ./config.example.toml
|
||||||
|
|
||||||
# Give the daemon a moment to initialize, then start UI components
|
# Give shepherdd a moment to initialize, then start UI components
|
||||||
# Start the shepherd-hud (time remaining overlay)
|
# Start the shepherd-hud (time remaining overlay)
|
||||||
exec sleep 1 && $hud
|
exec sleep 1 && $hud
|
||||||
|
|
||||||
# Start the shepherd-launcher on startup (the main "home" screen)
|
# Start the shepherd-launcher on startup (the main "home" screen)
|
||||||
# Small delay to ensure daemon is ready
|
# Small delay to ensure shepherdd is ready
|
||||||
exec_always sleep 1 && $launcher
|
exec_always sleep 1 && $launcher
|
||||||
|
|
||||||
### Disable workspace switching
|
### Disable workspace switching
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue