:%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
|
||||
|
||||
[daemon]
|
||||
[service]
|
||||
# Uncomment to customize paths
|
||||
# socket_path = "/run/shepherdd/shepherdd.sock"
|
||||
# log_dir = "/var/log/shepherdd"
|
||||
|
|
@ -15,24 +15,24 @@ default_max_run_seconds = 3600
|
|||
|
||||
# Global volume restrictions (optional)
|
||||
# These apply when no entry-specific restrictions are defined
|
||||
[daemon.volume]
|
||||
[service.volume]
|
||||
max_volume = 80 # Maximum volume percentage (0-100)
|
||||
# min_volume = 20 # Minimum volume percentage (0-100)
|
||||
allow_mute = true # Whether mute toggle is allowed
|
||||
allow_change = true # Whether volume changes are allowed at all
|
||||
|
||||
# Default warning thresholds
|
||||
[[daemon.default_warnings]]
|
||||
[[service.default_warnings]]
|
||||
seconds_before = 300
|
||||
severity = "info"
|
||||
message = "5 minutes remaining"
|
||||
|
||||
[[daemon.default_warnings]]
|
||||
[[service.default_warnings]]
|
||||
seconds_before = 60
|
||||
severity = "warn"
|
||||
message = "1 minute remaining!"
|
||||
|
||||
[[daemon.default_warnings]]
|
||||
[[service.default_warnings]]
|
||||
seconds_before = 10
|
||||
severity = "critical"
|
||||
message = "10 seconds remaining!"
|
||||
|
|
@ -232,7 +232,7 @@ days = "weekends"
|
|||
start = "10: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
|
||||
|
||||
## === Media ===
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ pub enum ErrorCode {
|
|||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum Command {
|
||||
/// Get current daemon state
|
||||
/// Get current service state
|
||||
GetState,
|
||||
|
||||
/// List available entries
|
||||
|
|
@ -160,7 +160,7 @@ pub enum Command {
|
|||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum ResponsePayload {
|
||||
State(crate::DaemonStateSnapshot),
|
||||
State(crate::ServiceStateSnapshot),
|
||||
Entries(Vec<crate::EntryView>),
|
||||
LaunchApproved {
|
||||
session_id: shepherd_util::SessionId,
|
||||
|
|
@ -234,7 +234,7 @@ mod tests {
|
|||
fn response_serialization() {
|
||||
let resp = Response::success(
|
||||
1,
|
||||
ResponsePayload::State(crate::DaemonStateSnapshot {
|
||||
ResponsePayload::State(crate::ServiceStateSnapshot {
|
||||
api_version: API_VERSION,
|
||||
policy_loaded: true,
|
||||
current_session: None,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||
use shepherd_util::{EntryId, SessionId};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{DaemonStateSnapshot, SessionEndReason, WarningSeverity, API_VERSION};
|
||||
use crate::{ServiceStateSnapshot, SessionEndReason, WarningSeverity, API_VERSION};
|
||||
|
||||
/// Event envelope
|
||||
#[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)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum EventPayload {
|
||||
/// Full state snapshot (sent on subscribe and major changes)
|
||||
StateChanged(DaemonStateSnapshot),
|
||||
StateChanged(ServiceStateSnapshot),
|
||||
|
||||
/// Session has started
|
||||
SessionStarted {
|
||||
|
|
@ -80,7 +80,7 @@ pub enum EventPayload {
|
|||
muted: bool,
|
||||
},
|
||||
|
||||
/// Daemon is shutting down
|
||||
/// Service is shutting down
|
||||
Shutdown,
|
||||
|
||||
/// Audit event (for admin clients)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! 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)
|
||||
//! - Responses
|
||||
//! - Events (daemon -> clients)
|
||||
//! - Events (service -> clients)
|
||||
//! - Versioning
|
||||
|
||||
mod commands;
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ pub enum SessionEndReason {
|
|||
ProcessExited { exit_code: Option<i32> },
|
||||
/// Policy change terminated session
|
||||
PolicyStop,
|
||||
/// Daemon shutdown
|
||||
DaemonShutdown,
|
||||
/// Service shutdown
|
||||
ServiceShutdown,
|
||||
/// Launch failed
|
||||
LaunchFailed { error: String },
|
||||
}
|
||||
|
|
@ -187,9 +187,9 @@ pub struct SessionInfo {
|
|||
pub warnings_issued: Vec<u64>,
|
||||
}
|
||||
|
||||
/// Full daemon state snapshot
|
||||
/// Full service state snapshot
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DaemonStateSnapshot {
|
||||
pub struct ServiceStateSnapshot {
|
||||
pub api_version: u32,
|
||||
pub policy_loaded: bool,
|
||||
pub current_session: Option<SessionInfo>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! 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 shepherd_api::{EntryKind, WarningSeverity, WarningThreshold};
|
||||
use shepherd_util::{DaysOfWeek, EntryId, TimeWindow, WallClock};
|
||||
|
|
@ -11,8 +11,8 @@ use std::time::Duration;
|
|||
/// Validated policy ready for use by the core engine
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Policy {
|
||||
/// Daemon configuration
|
||||
pub daemon: DaemonConfig,
|
||||
/// Service configuration
|
||||
pub service: ServiceConfig,
|
||||
|
||||
/// Validated entries
|
||||
pub entries: Vec<Entry>,
|
||||
|
|
@ -31,7 +31,7 @@ impl Policy {
|
|||
/// Convert from raw config (after validation)
|
||||
pub fn from_raw(raw: RawConfig) -> Self {
|
||||
let default_warnings = raw
|
||||
.daemon
|
||||
.service
|
||||
.default_warnings
|
||||
.clone()
|
||||
.map(|w| w.into_iter().map(convert_warning).collect())
|
||||
|
|
@ -39,13 +39,13 @@ impl Policy {
|
|||
|
||||
// 0 means unlimited, None means use 1 hour default
|
||||
let default_max_run = raw
|
||||
.daemon
|
||||
.service
|
||||
.default_max_run_seconds
|
||||
.map(seconds_to_duration_or_unlimited)
|
||||
.unwrap_or(Some(Duration::from_secs(3600))); // 1 hour default
|
||||
|
||||
let global_volume = raw
|
||||
.daemon
|
||||
.service
|
||||
.volume
|
||||
.as_ref()
|
||||
.map(convert_volume_config)
|
||||
|
|
@ -58,7 +58,7 @@ impl Policy {
|
|||
.collect();
|
||||
|
||||
Self {
|
||||
daemon: DaemonConfig::from_raw(raw.daemon),
|
||||
service: ServiceConfig::from_raw(raw.service),
|
||||
entries,
|
||||
default_warnings,
|
||||
default_max_run,
|
||||
|
|
@ -72,16 +72,16 @@ impl Policy {
|
|||
}
|
||||
}
|
||||
|
||||
/// Daemon configuration
|
||||
/// Service configuration
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DaemonConfig {
|
||||
pub struct ServiceConfig {
|
||||
pub socket_path: PathBuf,
|
||||
pub log_dir: PathBuf,
|
||||
pub data_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl DaemonConfig {
|
||||
fn from_raw(raw: crate::schema::RawDaemonConfig) -> Self {
|
||||
impl ServiceConfig {
|
||||
fn from_raw(raw: RawServiceConfig) -> Self {
|
||||
Self {
|
||||
socket_path: raw
|
||||
.socket_path
|
||||
|
|
@ -96,7 +96,7 @@ impl DaemonConfig {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for DaemonConfig {
|
||||
impl Default for ServiceConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
socket_path: PathBuf::from("/run/shepherdd/shepherdd.sock"),
|
||||
|
|
@ -208,9 +208,9 @@ pub struct LimitsPolicy {
|
|||
/// Volume control policy
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct VolumePolicy {
|
||||
/// Maximum volume percentage allowed (enforced by daemon)
|
||||
/// Maximum volume percentage allowed (enforced by the service)
|
||||
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>,
|
||||
/// Whether mute toggle is allowed
|
||||
pub allow_mute: bool,
|
||||
|
|
|
|||
|
|
@ -10,18 +10,18 @@ pub struct RawConfig {
|
|||
/// Config schema version
|
||||
pub config_version: u32,
|
||||
|
||||
/// Global daemon settings
|
||||
#[serde(default)]
|
||||
pub daemon: RawDaemonConfig,
|
||||
/// Global service settings
|
||||
#[serde(default, alias = "daemon")]
|
||||
pub service: RawServiceConfig,
|
||||
|
||||
/// List of allowed entries
|
||||
#[serde(default)]
|
||||
pub entries: Vec<RawEntry>,
|
||||
}
|
||||
|
||||
/// Daemon-level settings
|
||||
/// Service-level settings
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct RawDaemonConfig {
|
||||
pub struct RawServiceConfig {
|
||||
/// IPC socket path (default: /run/shepherdd/shepherdd.sock)
|
||||
pub socket_path: Option<PathBuf>,
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ fn validate_entry(entry: &RawEntry, config: &RawConfig) -> Vec<ValidationError>
|
|||
.limits
|
||||
.as_ref()
|
||||
.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)
|
||||
if let (Some(warnings), Some(max_run)) = (&entry.warnings, max_run) {
|
||||
|
|
@ -245,7 +245,7 @@ mod tests {
|
|||
fn test_duplicate_id_detection() {
|
||||
let config = RawConfig {
|
||||
config_version: 1,
|
||||
daemon: Default::default(),
|
||||
service: Default::default(),
|
||||
entries: vec![
|
||||
RawEntry {
|
||||
id: "game".into(),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use chrono::{DateTime, Local};
|
||||
use shepherd_api::{
|
||||
DaemonStateSnapshot, EntryKindTag, EntryView, ReasonCode, SessionEndReason,
|
||||
ServiceStateSnapshot, EntryKindTag, EntryView, ReasonCode, SessionEndReason,
|
||||
WarningSeverity, API_VERSION,
|
||||
};
|
||||
use shepherd_config::{Entry, Policy};
|
||||
|
|
@ -472,8 +472,8 @@ impl CoreEngine {
|
|||
})
|
||||
}
|
||||
|
||||
/// Get current daemon state snapshot
|
||||
pub fn get_state(&self) -> DaemonStateSnapshot {
|
||||
/// Get current service state snapshot
|
||||
pub fn get_state(&self) -> ServiceStateSnapshot {
|
||||
let current_session = self.current_session.as_ref().map(|s| {
|
||||
s.to_session_info(MonotonicInstant::now())
|
||||
});
|
||||
|
|
@ -481,7 +481,7 @@ impl CoreEngine {
|
|||
// Build entry views for the snapshot
|
||||
let entries = self.list_entries(shepherd_util::now());
|
||||
|
||||
DaemonStateSnapshot {
|
||||
ServiceStateSnapshot {
|
||||
api_version: API_VERSION,
|
||||
policy_loaded: true,
|
||||
current_session,
|
||||
|
|
@ -553,7 +553,7 @@ mod tests {
|
|||
|
||||
fn make_test_policy() -> Policy {
|
||||
Policy {
|
||||
daemon: Default::default(),
|
||||
service: Default::default(),
|
||||
entries: vec![Entry {
|
||||
id: EntryId::new("test-game"),
|
||||
label: "Test Game".into(),
|
||||
|
|
@ -661,7 +661,7 @@ mod tests {
|
|||
disabled: false,
|
||||
disabled_reason: None,
|
||||
}],
|
||||
daemon: Default::default(),
|
||||
service: Default::default(),
|
||||
default_warnings: vec![],
|
||||
default_max_run: Some(Duration::from_secs(3600)),
|
||||
volume: Default::default(),
|
||||
|
|
@ -722,7 +722,7 @@ mod tests {
|
|||
disabled: false,
|
||||
disabled_reason: None,
|
||||
}],
|
||||
daemon: Default::default(),
|
||||
service: Default::default(),
|
||||
default_warnings: vec![],
|
||||
default_max_run: Some(Duration::from_secs(3600)),
|
||||
volume: Default::default(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! 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.
|
||||
|
||||
mod capabilities;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Volume control trait interfaces
|
||||
//!
|
||||
//! 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 serde::{Deserialize, Serialize};
|
||||
|
|
@ -67,9 +67,9 @@ pub struct VolumeCapabilities {
|
|||
/// Volume restrictions that can be enforced by policy
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct VolumeRestrictions {
|
||||
/// Maximum volume percentage allowed (enforced by daemon)
|
||||
/// Maximum volume percentage allowed (enforced by the service)
|
||||
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>,
|
||||
/// Whether mute toggle is allowed
|
||||
pub allow_mute: bool,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ impl LinuxHost {
|
|||
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
|
||||
// The daemon should track the mapping
|
||||
// The service should track the mapping
|
||||
let handle = HostSessionHandle::new(
|
||||
SessionId::new(), // This will be matched by PID
|
||||
HostHandlePayload::Linux { pid, pgid },
|
||||
|
|
|
|||
|
|
@ -225,8 +225,8 @@ impl ManagedProcess {
|
|||
|
||||
// Special handling for WAYLAND_DISPLAY:
|
||||
// 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
|
||||
// runs on the parent compositor. When the daemon runs inside the nested
|
||||
// This allows apps to be launched on a nested compositor while the service
|
||||
// runs on the parent compositor. When the service runs inside the nested
|
||||
// compositor, this is not needed as WAYLAND_DISPLAY is already correct.
|
||||
if let Ok(shepherd_display) = std::env::var("SHEPHERD_WAYLAND_DISPLAY") {
|
||||
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.add_css_class("volume-slider");
|
||||
|
||||
// Set initial value from daemon
|
||||
// Set initial value from shepherdd
|
||||
if let Some(info) = crate::volume::get_volume_status() {
|
||||
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();
|
||||
if let Some(session_id) = session_state.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")
|
||||
.unwrap_or_else(|_| "./dev-runtime/shepherd.sock".to_string());
|
||||
std::thread::spawn(move || {
|
||||
|
|
@ -349,7 +349,7 @@ fn build_hud_content(state: SharedState) -> gtk4::Box {
|
|||
}
|
||||
}
|
||||
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
|
||||
//!
|
||||
//! Provides volume status and control via the shepherdd daemon.
|
||||
//! The daemon handles actual volume control and enforces restrictions.
|
||||
//! Provides volume status and control via shepherdd.
|
||||
//! The service handles actual volume control and enforces restrictions.
|
||||
|
||||
use shepherd_api::{Command, ResponsePayload, VolumeInfo};
|
||||
use shepherd_ipc::IpcClient;
|
||||
|
|
@ -15,7 +15,7 @@ fn get_socket_path() -> PathBuf {
|
|||
.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> {
|
||||
let socket_path = get_socket_path();
|
||||
|
||||
|
|
@ -45,14 +45,14 @@ pub fn get_volume_status() -> Option<VolumeInfo> {
|
|||
}
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::debug!("Failed to connect to daemon for volume: {}", e);
|
||||
tracing::debug!("Failed to connect to shepherdd for volume: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Toggle mute state via the daemon
|
||||
/// Toggle mute state via shepherdd
|
||||
pub fn toggle_mute() -> anyhow::Result<()> {
|
||||
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<()> {
|
||||
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<()> {
|
||||
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<()> {
|
||||
let socket_path = get_socket_path();
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub struct IpcClient {
|
|||
}
|
||||
|
||||
impl IpcClient {
|
||||
/// Connect to the daemon
|
||||
/// Connect to shepherdd
|
||||
pub async fn connect(socket_path: impl AsRef<Path>) -> IpcResult<Self> {
|
||||
let stream = UnixStream::connect(socket_path).await?;
|
||||
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 {
|
||||
reader: BufReader<tokio::net::unix::OwnedReadHalf>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use tokio::runtime::Runtime;
|
|||
use tokio::sync::mpsc;
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
use crate::client::{ClientCommand, CommandClient, DaemonClient};
|
||||
use crate::client::{ClientCommand, CommandClient, ServiceClient};
|
||||
use crate::grid::LauncherGrid;
|
||||
use crate::state::{LauncherState, SharedState};
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ impl LauncherApp {
|
|||
match client.launch(&entry_id).await {
|
||||
Ok(response) => {
|
||||
debug!(response = ?response, "Launch response");
|
||||
// Handle error responses from daemon
|
||||
// Handle error responses from shepherdd
|
||||
match response.result {
|
||||
shepherd_api::ResponseResult::Ok(payload) => {
|
||||
// Check what kind of success response we got
|
||||
|
|
@ -227,7 +227,7 @@ impl LauncherApp {
|
|||
shepherd_api::ResponseResult::Err(err) => {
|
||||
// Launch failed on server side - refresh state to recover
|
||||
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 {
|
||||
Ok(state_resp) => {
|
||||
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
|
||||
let state_for_client = state.clone();
|
||||
let socket_for_client = socket_path.clone();
|
||||
std::thread::spawn(move || {
|
||||
let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime for event loop");
|
||||
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;
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ pub enum ClientCommand {
|
|||
}
|
||||
|
||||
/// Client connection manager
|
||||
pub struct DaemonClient {
|
||||
pub struct ServiceClient {
|
||||
socket_path: std::path::PathBuf,
|
||||
state: SharedState,
|
||||
command_rx: mpsc::UnboundedReceiver<ClientCommand>,
|
||||
}
|
||||
|
||||
impl DaemonClient {
|
||||
impl ServiceClient {
|
||||
pub fn new(
|
||||
socket_path: impl AsRef<Path>,
|
||||
state: SharedState,
|
||||
|
|
@ -67,13 +67,13 @@ impl DaemonClient {
|
|||
async fn connect_and_run(&mut self) -> Result<()> {
|
||||
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)
|
||||
.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)
|
||||
info!("Sending GetState command");
|
||||
|
|
@ -116,11 +116,11 @@ impl DaemonClient {
|
|||
}
|
||||
}
|
||||
|
||||
// Handle events from daemon
|
||||
// Handle events from shepherdd
|
||||
event_result = events.next() => {
|
||||
match event_result {
|
||||
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);
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Launcher application state management
|
||||
|
||||
use shepherd_api::{DaemonStateSnapshot, EntryView, Event, EventPayload};
|
||||
use shepherd_api::{ServiceStateSnapshot, EntryView, Event, EventPayload};
|
||||
use shepherd_util::SessionId;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
|
@ -9,7 +9,7 @@ use tokio::sync::watch;
|
|||
/// Current state of the launcher UI
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum LauncherState {
|
||||
/// Not connected to daemon
|
||||
/// Not connected to shepherdd
|
||||
Disconnected,
|
||||
/// Connected, waiting for initial state
|
||||
Connecting,
|
||||
|
|
@ -58,9 +58,9 @@ impl SharedState {
|
|||
self.receiver.clone()
|
||||
}
|
||||
|
||||
/// Update state from daemon event
|
||||
/// Update state from shepherdd 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 {
|
||||
EventPayload::StateChanged(snapshot) => {
|
||||
tracing::info!(has_session = snapshot.current_session.is_some(), "Applying state snapshot");
|
||||
|
|
@ -109,7 +109,7 @@ impl SharedState {
|
|||
self.set(LauncherState::Connecting);
|
||||
}
|
||||
EventPayload::Shutdown => {
|
||||
// Daemon is shutting down
|
||||
// Service is shutting down
|
||||
self.set(LauncherState::Disconnected);
|
||||
}
|
||||
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 {
|
||||
let now = shepherd_util::now();
|
||||
// For unlimited sessions (deadline=None), time_remaining is None
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ use std::time::Duration;
|
|||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum AuditEventType {
|
||||
/// Daemon started
|
||||
DaemonStarted,
|
||||
/// Service started
|
||||
ServiceStarted,
|
||||
|
||||
/// Daemon stopped
|
||||
DaemonStopped,
|
||||
/// Service stopped
|
||||
ServiceStopped,
|
||||
|
||||
/// Policy loaded/reloaded
|
||||
PolicyLoaded { entry_count: usize },
|
||||
|
|
|
|||
|
|
@ -272,12 +272,12 @@ mod tests {
|
|||
fn test_audit_log() {
|
||||
let store = SqliteStore::in_memory().unwrap();
|
||||
|
||||
let event = AuditEvent::new(AuditEventType::DaemonStarted);
|
||||
let event = AuditEvent::new(AuditEventType::ServiceStarted);
|
||||
store.append_audit(event).unwrap();
|
||||
|
||||
let events = store.get_recent_audits(10).unwrap();
|
||||
assert_eq!(events.len(), 1);
|
||||
assert!(matches!(events[0].event, AuditEventType::DaemonStarted));
|
||||
assert!(matches!(events[0].event, AuditEventType::ServiceStarted));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ name = "shepherdd"
|
|||
version.workspace = true
|
||||
edition.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]]
|
||||
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.
|
||||
//! It wires together all the components:
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
use anyhow::{Context, Result};
|
||||
use clap::Parser;
|
||||
use shepherd_api::{
|
||||
Command, DaemonStateSnapshot, ErrorCode, ErrorInfo, Event, EventPayload, HealthStatus,
|
||||
Command, ServiceStateSnapshot, ErrorCode, ErrorInfo, Event, EventPayload, HealthStatus,
|
||||
Response, ResponsePayload, SessionEndReason, StopMode, VolumeInfo, VolumeRestrictions,
|
||||
API_VERSION,
|
||||
};
|
||||
|
|
@ -30,10 +30,10 @@ use tokio::sync::Mutex;
|
|||
use tracing::{debug, error, info, warn, Level};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
/// shepherdd - Policy enforcement daemon for child-focused computing
|
||||
/// shepherdd - Policy enforcement service for child-focused computing
|
||||
#[derive(Parser, Debug)]
|
||||
#[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 {
|
||||
/// Configuration file path
|
||||
#[arg(short, long, default_value = "/etc/shepherdd/config.toml")]
|
||||
|
|
@ -52,8 +52,8 @@ struct Args {
|
|||
log_level: String,
|
||||
}
|
||||
|
||||
/// Main daemon state
|
||||
struct Daemon {
|
||||
/// Main service state
|
||||
struct Service {
|
||||
engine: CoreEngine,
|
||||
host: Arc<LinuxHost>,
|
||||
volume: Arc<LinuxVolumeController>,
|
||||
|
|
@ -62,7 +62,7 @@ struct Daemon {
|
|||
rate_limiter: RateLimiter,
|
||||
}
|
||||
|
||||
impl Daemon {
|
||||
impl Service {
|
||||
async fn new(args: &Args) -> Result<Self> {
|
||||
// Load configuration
|
||||
let policy = load_config(&args.config)
|
||||
|
|
@ -78,12 +78,12 @@ impl Daemon {
|
|||
let socket_path = args
|
||||
.socket
|
||||
.clone()
|
||||
.unwrap_or_else(|| policy.daemon.socket_path.clone());
|
||||
.unwrap_or_else(|| policy.service.socket_path.clone());
|
||||
|
||||
let data_dir = args
|
||||
.data_dir
|
||||
.clone()
|
||||
.unwrap_or_else(|| policy.daemon.data_dir.clone());
|
||||
.unwrap_or_else(|| policy.service.data_dir.clone());
|
||||
|
||||
// Create data directory
|
||||
std::fs::create_dir_all(&data_dir)
|
||||
|
|
@ -98,8 +98,8 @@ impl Daemon {
|
|||
|
||||
info!(db_path = %db_path.display(), "Store initialized");
|
||||
|
||||
// Log daemon start
|
||||
store.append_audit(AuditEvent::new(AuditEventType::DaemonStarted))?;
|
||||
// Log service start
|
||||
store.append_audit(AuditEvent::new(AuditEventType::ServiceStarted))?;
|
||||
|
||||
// Initialize host adapter
|
||||
let host = Arc::new(LinuxHost::new());
|
||||
|
|
@ -168,7 +168,7 @@ impl Daemon {
|
|||
let tick_interval = Duration::from_millis(100);
|
||||
let mut tick_timer = tokio::time::interval(tick_interval);
|
||||
|
||||
info!("Daemon running");
|
||||
info!("Service running");
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
|
|
@ -940,7 +940,7 @@ async fn main() -> Result<()> {
|
|||
"shepherdd starting"
|
||||
);
|
||||
|
||||
// Create and run daemon
|
||||
let daemon = Daemon::new(&args).await?;
|
||||
daemon.run().await
|
||||
// Create and run the service
|
||||
let service = Service::new(&args).await?;
|
||||
service.run().await
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! 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_config::{AvailabilityPolicy, Entry, LimitsPolicy, Policy};
|
||||
|
|
@ -14,7 +14,7 @@ use std::time::Duration;
|
|||
|
||||
fn make_test_policy() -> Policy {
|
||||
Policy {
|
||||
daemon: Default::default(),
|
||||
service: Default::default(),
|
||||
entries: vec![
|
||||
Entry {
|
||||
id: EntryId::new("test-game"),
|
||||
|
|
|
|||
|
|
@ -132,16 +132,16 @@ workspace 1 output *
|
|||
|
||||
### 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
|
||||
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)
|
||||
exec sleep 1 && $hud
|
||||
|
||||
# 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
|
||||
|
||||
### Disable workspace switching
|
||||
|
|
|
|||
Loading…
Reference in a new issue