hyperion/models/backend/
db.rs

1use std::{collections::BTreeMap, convert::TryFrom};
2
3use async_trait::async_trait;
4
5use super::ConfigBackend;
6use crate::{
7    db::{models as db_models, Db},
8    models::*,
9};
10
11pub struct DbBackend {
12    db: Db,
13}
14
15impl DbBackend {
16    pub fn new(db: Db) -> Self {
17        Self::from(db)
18    }
19}
20
21impl From<Db> for DbBackend {
22    fn from(db: Db) -> Self {
23        Self { db }
24    }
25}
26
27#[async_trait]
28impl ConfigBackend for DbBackend {
29    async fn load(&mut self) -> Result<Config, ConfigError> {
30        let mut instances = BTreeMap::new();
31        let mut global = GlobalConfigCreator::default();
32
33        for instance in sqlx::query_as::<_, db_models::DbInstance>("SELECT * FROM instances")
34            .fetch_all(&mut *self.db)
35            .await?
36            .into_iter()
37            .map(Instance::try_from)
38        {
39            let instance = instance?;
40            instances.insert(instance.id, InstanceConfigCreator::new(instance));
41        }
42
43        for setting in sqlx::query_as::<_, db_models::DbSetting>("SELECT * FROM settings")
44            .fetch_all(&mut *self.db)
45            .await?
46            .into_iter()
47            .map(Setting::try_from)
48        {
49            let setting = setting?;
50            match setting.config {
51                SettingData::BackgroundEffect(config) => {
52                    match instances.get_mut(
53                        &setting
54                            .hyperion_inst
55                            .ok_or(ConfigError::MissingHyperionInst("backgroundEffect"))?,
56                    ) {
57                        Some(instance) => instance.background_effect = Some(config),
58                        None => continue,
59                    }
60                }
61                SettingData::BlackBorderDetector(config) => {
62                    match instances.get_mut(
63                        &setting
64                            .hyperion_inst
65                            .ok_or(ConfigError::MissingHyperionInst("blackborderdetector"))?,
66                    ) {
67                        Some(instance) => instance.black_border_detector = Some(config),
68                        None => continue,
69                    }
70                }
71                SettingData::BoblightServer(config) => {
72                    match instances.get_mut(
73                        &setting
74                            .hyperion_inst
75                            .ok_or(ConfigError::MissingHyperionInst("boblightServer"))?,
76                    ) {
77                        Some(instance) => instance.boblight_server = Some(config),
78                        None => continue,
79                    }
80                }
81                SettingData::ColorAdjustment(config) => {
82                    match instances.get_mut(
83                        &setting
84                            .hyperion_inst
85                            .ok_or(ConfigError::MissingHyperionInst("color"))?,
86                    ) {
87                        Some(instance) => instance.color = Some(config),
88                        None => continue,
89                    }
90                }
91                SettingData::Device(config) => {
92                    match instances.get_mut(
93                        &setting
94                            .hyperion_inst
95                            .ok_or(ConfigError::MissingHyperionInst("device"))?,
96                    ) {
97                        Some(instance) => instance.device = Some(config),
98                        None => continue,
99                    }
100                }
101                SettingData::Effects(config) => {
102                    match instances.get_mut(
103                        &setting
104                            .hyperion_inst
105                            .ok_or(ConfigError::MissingHyperionInst("effects"))?,
106                    ) {
107                        Some(instance) => instance.effects = Some(config),
108                        None => continue,
109                    }
110                }
111                SettingData::ForegroundEffect(config) => {
112                    match instances.get_mut(
113                        &setting
114                            .hyperion_inst
115                            .ok_or(ConfigError::MissingHyperionInst("foregroundEffect"))?,
116                    ) {
117                        Some(instance) => instance.foreground_effect = Some(config),
118                        None => continue,
119                    }
120                }
121                SettingData::InstanceCapture(config) => {
122                    match instances.get_mut(
123                        &setting
124                            .hyperion_inst
125                            .ok_or(ConfigError::MissingHyperionInst("instCapture"))?,
126                    ) {
127                        Some(instance) => instance.instance_capture = Some(config),
128                        None => continue,
129                    }
130                }
131                SettingData::LedConfig(config) => {
132                    match instances.get_mut(
133                        &setting
134                            .hyperion_inst
135                            .ok_or(ConfigError::MissingHyperionInst("ledConfig"))?,
136                    ) {
137                        Some(instance) => instance.led_config = Some(config),
138                        None => continue,
139                    }
140                }
141                SettingData::Leds(config) => {
142                    match instances.get_mut(
143                        &setting
144                            .hyperion_inst
145                            .ok_or(ConfigError::MissingHyperionInst("leds"))?,
146                    ) {
147                        Some(instance) => instance.leds = Some(config),
148                        None => continue,
149                    }
150                }
151                SettingData::Smoothing(config) => {
152                    match instances.get_mut(
153                        &setting
154                            .hyperion_inst
155                            .ok_or(ConfigError::MissingHyperionInst("smoothing"))?,
156                    ) {
157                        Some(instance) => instance.smoothing = Some(config),
158                        None => continue,
159                    }
160                }
161
162                SettingData::FlatbuffersServer(config) => {
163                    global.flatbuffers_server = Some(config);
164                }
165                SettingData::Forwarder(config) => {
166                    global.forwarder = Some(config);
167                }
168                SettingData::Framegrabber(config) => {
169                    global.framegrabber = Some(config);
170                }
171                SettingData::General(config) => {
172                    global.general = Some(config);
173                }
174                SettingData::GrabberV4L2(config) => {
175                    global.grabber_v4l2 = Some(config);
176                }
177                SettingData::JsonServer(config) => {
178                    global.json_server = Some(config);
179                }
180                SettingData::Logger(config) => {
181                    global.logger = Some(config);
182                }
183                SettingData::Network(config) => {
184                    global.network = Some(config);
185                }
186                SettingData::ProtoServer(config) => {
187                    global.proto_server = Some(config);
188                }
189                SettingData::WebConfig(config) => {
190                    global.web_config = Some(config);
191                }
192                SettingData::Hooks(config) => {
193                    global.hooks = Some(config);
194                }
195            }
196        }
197
198        let meta: Result<Vec<_>, _> = sqlx::query_as::<_, db_models::DbMeta>("SELECT * FROM meta")
199            .fetch_all(&mut *self.db)
200            .await?
201            .into_iter()
202            .map(Meta::try_from)
203            .collect();
204        let meta = meta?;
205
206        let users: Result<Vec<_>, _> = sqlx::query_as::<_, db_models::DbUser>("SELECT * FROM auth")
207            .fetch_all(&mut *self.db)
208            .await?
209            .into_iter()
210            .map(User::try_from)
211            .collect();
212        let users = users?;
213
214        let instances: BTreeMap<i32, InstanceConfig> =
215            instances.into_iter().map(|(k, v)| (k, v.into())).collect();
216
217        let global: GlobalConfig = global.into();
218
219        debug!(
220            name = %global.general.name,
221            instances = %instances.len(),
222            meta = %meta.len(),
223            users = %users.len(),
224            "loaded",
225        );
226
227        Ok(Config {
228            instances,
229            global,
230            meta,
231            users,
232        })
233    }
234}
235
236struct InstanceConfigCreator {
237    instance: Instance,
238    background_effect: Option<BackgroundEffect>,
239    black_border_detector: Option<BlackBorderDetector>,
240    boblight_server: Option<BoblightServer>,
241    color: Option<ColorAdjustment>,
242    device: Option<Device>,
243    effects: Option<Effects>,
244    foreground_effect: Option<ForegroundEffect>,
245    instance_capture: Option<InstanceCapture>,
246    led_config: Option<LedConfig>,
247    leds: Option<Leds>,
248    smoothing: Option<Smoothing>,
249}
250
251impl From<InstanceConfigCreator> for InstanceConfig {
252    fn from(creator: InstanceConfigCreator) -> Self {
253        Self {
254            instance: creator.instance,
255            background_effect: creator.background_effect.unwrap_or_default(),
256            black_border_detector: creator.black_border_detector.unwrap_or_default(),
257            boblight_server: creator.boblight_server.unwrap_or_default(),
258            color: creator.color.unwrap_or_default(),
259            device: creator.device.unwrap_or_default(),
260            effects: creator.effects.unwrap_or_default(),
261            foreground_effect: creator.foreground_effect.unwrap_or_default(),
262            instance_capture: creator.instance_capture.unwrap_or_default(),
263            led_config: creator.led_config.unwrap_or_default(),
264            leds: creator.leds.unwrap_or_default(),
265            smoothing: creator.smoothing.unwrap_or_default(),
266        }
267    }
268}
269
270impl InstanceConfigCreator {
271    fn new(instance: Instance) -> Self {
272        Self {
273            instance,
274            background_effect: None,
275            black_border_detector: None,
276            boblight_server: None,
277            color: None,
278            device: None,
279            effects: None,
280            foreground_effect: None,
281            instance_capture: None,
282            led_config: None,
283            leds: None,
284            smoothing: None,
285        }
286    }
287}
288
289impl From<GlobalConfigCreator> for GlobalConfig {
290    fn from(creator: GlobalConfigCreator) -> Self {
291        Self {
292            flatbuffers_server: creator.flatbuffers_server.unwrap_or_default(),
293            forwarder: creator.forwarder.unwrap_or_default(),
294            framegrabber: creator.framegrabber.unwrap_or_default(),
295            general: creator.general.unwrap_or_default(),
296            grabber_v4l2: creator.grabber_v4l2.unwrap_or_default(),
297            json_server: creator.json_server.unwrap_or_default(),
298            logger: creator.logger.unwrap_or_default(),
299            network: creator.network.unwrap_or_default(),
300            proto_server: creator.proto_server.unwrap_or_default(),
301            web_config: creator.web_config.unwrap_or_default(),
302            hooks: creator.hooks.unwrap_or_default(),
303        }
304    }
305}
306
307#[derive(Default)]
308struct GlobalConfigCreator {
309    flatbuffers_server: Option<FlatbuffersServer>,
310    forwarder: Option<Forwarder>,
311    framegrabber: Option<Framegrabber>,
312    general: Option<General>,
313    grabber_v4l2: Option<GrabberV4L2>,
314    json_server: Option<JsonServer>,
315    logger: Option<Logger>,
316    network: Option<Network>,
317    proto_server: Option<ProtoServer>,
318    web_config: Option<WebConfig>,
319    hooks: Option<Hooks>,
320}