use std::collections::HashMap; use std::rc::Rc; use zbus::dbus_proxy; use zvariant::derive::Type; use serde::{Serialize,Deserialize}; use crate::error::{Error, Result}; #[derive(Deserialize,Serialize,Type)] pub struct RealmItem { name: String, description: String, realmfs: String, namespace: u64, status: u8, } impl RealmItem { pub fn name(&self) -> &str { &self.name } } #[derive(Debug,Clone)] pub struct RealmConfig { options: Rc>, realmfs_list: Rc>, } impl RealmConfig { pub fn new_default(realmfs_list: Vec) -> Self { let config = libcitadel::RealmConfig::default(); let mut vars = HashMap::new(); vars.insert("use-gpu".to_string(), config.gpu().to_string()); vars.insert("use-wayland".to_string(), config.wayland().to_string()); vars.insert("use-x11".to_string(), config.x11().to_string()); vars.insert("use-sound".to_string(), config.sound().to_string()); vars.insert("use-shared-dir".to_string(), config.shared_dir().to_string()); vars.insert("use-network".to_string(), config.network().to_string()); vars.insert("use-kvm".to_string(), config.kvm().to_string()); vars.insert("use-ephemeral-home".to_string(), config.ephemeral_home().to_string()); if realmfs_list.contains(&String::from("main")) { vars.insert("realmfs".to_string(), String::from("main")); } else if let Some(first) = realmfs_list.first() { vars.insert("realmfs".to_string(), first.clone()); } Self::new(vars, realmfs_list) } fn new(options: HashMap, realmfs_list: Vec) -> Self { RealmConfig { options: Rc::new(options), realmfs_list: Rc::new(realmfs_list), } } pub fn get_string(&self, id: &str) -> Option<&str> { self.options.get(id).map(|s| s.as_str()) } fn parse_bool(val: &str) -> bool { match val.parse::() { Ok(v) => v, _ => { warn!("Failed to parse value '{}' as bool", val); false } } } pub fn get_bool(&self, id: &str) -> bool { match self.get_string(id) { Some(val) => Self::parse_bool(val), None => { warn!("No value found for option '{}'", id); false } } } pub fn realmfs_list(&self) -> &[String] { &self.realmfs_list } } #[dbus_proxy( default_service = "com.subgraph.realms", interface = "com.subgraph.realms.Manager", default_path = "/com/subgraph/realms" )] pub trait RealmsManager { fn get_current(&self) -> zbus::Result; fn realm_set_config(&self, name: &str, vars: Vec<(String,String)>) -> zbus::Result<()>; fn list(&self) -> zbus::Result>; fn realm_config(&self, name: &str) -> zbus::Result>; fn realm_exists(&self, name: &str) -> zbus::Result; fn list_realm_f_s(&self) -> zbus::Result>; fn create_realm(&self, name: &str) -> zbus::Result; } impl RealmsManagerProxy<'_> { pub fn connect() -> Result { let connection = zbus::Connection::new_system()?; let proxy = RealmsManagerProxy::new(&connection) .map_err(|_| Error::ManagerConnect)?; // Test connection proxy.get_current().map_err(|_| Error::ManagerConnect)?; Ok(proxy) } pub fn realm_names(&self) -> Result> { let realms = self.list()?; let names = realms.iter() .map(|r| r.name().to_string()) .collect(); Ok(names) } pub fn default_config(&self) -> Result { let realmfs_list = self.list_realm_f_s()?; Ok(RealmConfig::new_default(realmfs_list)) } pub fn config(&self, realm: &str) -> Result { if !self.realm_exists(realm)? { return Err(Error::NoSuchRealm(realm.to_string())); } let options = self.realm_config(realm)?; let realmfs_list = self.list_realm_f_s()?; Ok(RealmConfig::new(options, realmfs_list)) } pub fn configure_realm(&self, realm: &str, config: Vec<(String, String)>) -> Result<()> { self.realm_set_config(realm, config)?; Ok(()) } pub fn create_new_realm(&self, realm: &str, config: Vec<(String, String)>) -> Result<()> { if self.create_realm(realm)? { if !config.is_empty() { self.realm_set_config(realm, config)?; } } else { return Err(Error::CreateRealmFailed); } Ok(()) } }