use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::{fs, io, num, path, result, sync};
use toml::{de, ser};
#[cfg(feature = "monitor")]
pub mod monitor;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum SessionClass {
#[default]
User,
Greeter,
LockScreen,
Background,
BackgroundLight,
Manager,
ManagerEarly,
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum SessionState {
#[default]
Online,
Active,
Closing,
Opening,
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum UserState {
Offline,
Lingering,
Online,
Active,
Closing,
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct User {
pub state: UserState,
}
#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct State {
pub cgroup_root: path::PathBuf,
pub next_session_id: u32,
#[serde(default)]
pub users: BTreeMap<u32, User>,
#[serde(default)]
pub sessions: BTreeMap<String, Session>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Session {
pub uid: u32,
pub class: SessionClass,
pub vt: Option<num::NonZeroU32>,
pub leader: Option<num::NonZeroU32>,
pub remote_host: Option<sync::Arc<str>>,
pub timestamp: u128,
pub env: BTreeMap<sync::Arc<str>, sync::Arc<str>>,
#[serde(alias = "active")]
pub state: SessionState,
pub recoverable: bool,
pub display: u32,
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("state file I/O failed: {0}")]
Io(#[from] io::Error),
#[error("invalid state file: {0}")]
Decode(#[from] de::Error),
#[error("failed to serialize state: {0}")]
Encode(#[from] ser::Error),
}
impl State {
pub fn path() -> path::PathBuf {
path::PathBuf::from("/run/sessiond/state.toml")
}
#[cfg(feature = "monitor")]
pub fn monitor(&self) -> io::Result<monitor::Monitor> {
monitor::Monitor::new(Self::path())
}
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn try_read(&mut self) -> Result<()> {
let contents = fs::read_to_string(Self::path())?;
*self = toml::from_str::<Self>(&contents)?;
Ok(())
}
}