1use std::{
2 path::PathBuf,
3 sync::{OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard},
4};
5
6use lunar_lib::{
7 config::{Config, ConfigError},
8 debug,
9};
10use selene_core::runtime_dir;
11use serde::{Deserialize, Serialize};
12
13pub static DAEMON_CONFIG: OnceLock<RwLock<DaemonConfig>> = OnceLock::new();
14pub fn initialize_daemon_config() -> Result<(), ConfigError> {
15 if DAEMON_CONFIG.get().is_some() {
16 return Ok(());
17 }
18
19 let config = DaemonConfig::load()?;
20 let _ = DAEMON_CONFIG.set(RwLock::new(config));
21
22 Ok(())
23}
24
25pub fn daemon_config() -> RwLockReadGuard<'static, DaemonConfig> {
31 DAEMON_CONFIG
32 .get()
33 .expect("Config wasn't intialized")
34 .read()
35 .unwrap()
36}
37
38pub fn daemon_config_mut() -> RwLockWriteGuard<'static, DaemonConfig> {
44 DAEMON_CONFIG
45 .get()
46 .expect("Config wasn't initialized")
47 .write()
48 .unwrap()
49}
50
51#[derive(Debug, Serialize, Deserialize, Default)]
52pub struct DaemonConfig {
53 pub main: MainSettings,
54 pub playback: PlaybackSettings,
55}
56
57impl Config for DaemonConfig {
58 const CONFIG_FILE_NAME: &'static str = "daemon";
59
60 fn config_dir() -> PathBuf {
61 selene_core::config_dir().to_owned()
62 }
63}
64
65impl DaemonConfig {
66 pub fn reload() -> Result<(), ConfigError> {
68 debug!("Reloading daemon config");
69 initialize_daemon_config()?;
70
71 let mut current_config = daemon_config_mut();
72 let loaded_config = Self::load()?;
73
74 *current_config = loaded_config;
75
76 Ok(())
77 }
78}
79
80#[derive(Debug, Serialize, Deserialize)]
81pub struct MainSettings {
82 pub scrobbling: bool,
84
85 pub socket_path: PathBuf,
87}
88
89impl Default for MainSettings {
90 fn default() -> Self {
91 Self {
92 scrobbling: true,
93 socket_path: runtime_dir().join("selene.sock"),
94 }
95 }
96}
97
98#[derive(Debug, Serialize, Deserialize)]
99pub struct PlaybackSettings {
100 pub audio_buffer_size: usize,
102
103 pub previous_restart_thresh: Option<f64>,
105}
106
107impl Default for PlaybackSettings {
108 fn default() -> Self {
109 Self {
110 audio_buffer_size: 16,
111 previous_restart_thresh: Some(5.0),
112 }
113 }
114}
115
116#[derive(Debug, Serialize, Deserialize)]
117pub struct NotificationSettings {
118 pub enabled: bool,
119 pub body_format: String,
120 pub header_format: String,
121}
122
123impl Default for NotificationSettings {
124 fn default() -> Self {
125 Self {
126 enabled: true,
127 header_format: "Now playing: {$title?UNKNOWN TITLE}".to_owned(),
128 body_format: "by {$main_track_artist?UNKNOWN_ARTIST} {$feat_track_artists< (feat. >)}"
129 .to_owned(),
130 }
131 }
132}