Skip to content

Commit 8abc347

Browse files
committed
webapi: Move known animations logic to animations storage
1 parent d87009c commit 8abc347

20 files changed

+391
-218
lines changed

.sqlx/query-0cbb2657f00c44bdbb0ad1d3d414de0ed40dde1bbd3b7b0d13ea37ce2946f1f7.json

+32
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-78afc9b901519283ad27e136c44d1a7d99fe029de281fc033c7922bf8ab1b892.json

+32
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.sqlx/query-cfed83611225392dd95a14b6051a406229ed9068d6498c99f7083292e90df894.json

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

animation-wrapper/src/config.rs

+13-25
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{
33
process::{Command, Stdio},
44
};
55

6-
use serde::Deserialize;
6+
use serde::{Deserialize, Serialize};
77

88
use crate::unwrap::PluginUnwrapError;
99

@@ -19,30 +19,30 @@ pub enum PluginConfigError {
1919
NonUtf8DirectoryName,
2020
}
2121

22-
#[derive(Debug, Clone, Copy, Default, PartialEq, Deserialize)]
22+
#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
2323
#[serde(rename_all = "snake_case")]
2424
pub enum PluginType {
2525
#[default]
2626
Native,
2727
Wasm,
2828
}
2929

30-
#[derive(Debug, Clone, Deserialize)]
30+
#[derive(Debug, Clone, Serialize, Deserialize)]
3131
pub struct PluginManifest {
32-
display_name: String,
32+
pub display_name: String,
3333
#[serde(default)]
34-
plugin_type: PluginType,
34+
pub plugin_type: PluginType,
3535
}
3636

37-
#[derive(Debug, Clone)]
37+
#[derive(Debug, Clone, Serialize, Deserialize)]
3838
pub struct PluginConfig {
39-
pub(crate) animation_id: String,
40-
pub(crate) manifest: PluginManifest,
41-
pub(crate) path: PathBuf,
39+
pub animation_id: String,
40+
pub manifest: PluginManifest,
41+
pub path: PathBuf,
4242
}
4343

4444
impl PluginConfig {
45-
pub fn new(path: PathBuf) -> Result<Self, PluginConfigError> {
45+
pub fn from_path(path: &Path) -> Result<Self, PluginConfigError> {
4646
let manifest: PluginManifest =
4747
serde_json::from_slice(&std::fs::read(path.join("manifest.json")).map_err(|e| {
4848
PluginConfigError::InvalidManifest {
@@ -63,24 +63,12 @@ impl PluginConfig {
6363
Ok(Self {
6464
animation_id,
6565
manifest,
66-
path,
66+
path: path.to_owned(),
6767
})
6868
}
6969

70-
pub fn animation_id(&self) -> &str {
71-
&self.animation_id
72-
}
73-
74-
pub fn animation_name(&self) -> &str {
75-
&self.manifest.display_name
76-
}
77-
78-
pub fn plugin_type(&self) -> PluginType {
79-
self.manifest.plugin_type
80-
}
81-
82-
pub fn path(&self) -> &Path {
83-
self.path.as_path()
70+
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, PluginConfigError> {
71+
Self::from_path(path.as_ref())
8472
}
8573

8674
pub fn executable_path(&self) -> PathBuf {

animator/src/controller.rs

+17-115
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use std::collections::HashMap;
22
use std::error::Error;
3-
use std::path::{Path, PathBuf};
43
use std::sync::Arc;
54

65
use animation_api::event::Event;
76
use animation_api::schema::{Configuration, ParameterValue};
87
use animation_wrapper::config::PluginConfig;
98
use chrono::{DateTime, Duration, Utc};
10-
use client::combined::{CombinedLightClient, CombinedLightClientBuilder};
9+
use client::combined::CombinedLightClient;
1110
#[cfg(feature = "audio")]
1211
use events::beat_generator::BeatEventGenerator;
1312
use events::event_generator::EventGenerator;
@@ -22,7 +21,7 @@ use rustmas_light_client::LightClientError;
2221
use tokio::sync::{mpsc, Mutex};
2322
use tokio::task::JoinHandle;
2423

25-
use crate::factory::{AnimationFactory, AnimationFactoryError};
24+
use crate::factory::AnimationFactoryError;
2625
use crate::plugin::{AnimationPluginError, Plugin};
2726
use crate::ControllerConfig;
2827

@@ -71,7 +70,6 @@ pub struct Controller {
7170
animation_join_handle: JoinHandle<()>,
7271
event_generator_join_handle: JoinHandle<()>,
7372
state: Arc<Mutex<ControllerState>>,
74-
animation_factory: AnimationFactory,
7573
event_sender: mpsc::Sender<Event>,
7674
}
7775

@@ -81,10 +79,9 @@ enum PollFrameResult {
8179
}
8280

8381
impl Controller {
84-
fn new<P: AsRef<Path>>(
85-
points: Vec<(f64, f64, f64)>,
86-
plugin_dir: P,
82+
fn new(
8783
client: Box<dyn rustmas_light_client::LightClient + Sync + Send>,
84+
points_count: usize,
8885
) -> Self {
8986
let now = Utc::now();
9087
let (event_sender, event_receiver) = mpsc::channel(16);
@@ -97,16 +94,14 @@ impl Controller {
9794
event_generators: Self::start_generators(event_sender.clone()),
9895
}));
9996

100-
let animation_join_handle = tokio::spawn(Self::run(state.clone(), client, points.len()));
97+
let animation_join_handle = tokio::spawn(Self::run(state.clone(), client, points_count));
10198
let event_generator_join_handle =
10299
tokio::spawn(Self::event_loop(state.clone(), event_receiver));
103-
let animation_factory = AnimationFactory::new(plugin_dir, points);
104100

105101
Self {
106102
state,
107103
animation_join_handle,
108104
event_generator_join_handle,
109-
animation_factory,
110105
event_sender,
111106
}
112107
}
@@ -220,25 +215,19 @@ impl Controller {
220215
}
221216
}
222217

223-
pub fn builder() -> ControllerBuilder {
224-
ControllerBuilder {
225-
points: None,
226-
plugin_dir_: None,
227-
client_builder: CombinedLightClient::builder(),
228-
}
229-
}
230-
231-
pub fn builder_from(config: &ControllerConfig) -> Result<ControllerBuilder, Box<dyn Error>> {
232-
ControllerBuilder {
233-
points: None,
234-
plugin_dir_: Some(config.plugin_path.clone()),
235-
client_builder: CombinedLightClient::builder().with_config(&config.lights)?,
218+
pub fn from_config(
219+
config: &ControllerConfig,
220+
feedback: Option<mpsc::Sender<lightfx::Frame>>,
221+
point_count: usize,
222+
) -> Result<Self, Box<dyn Error>> {
223+
let mut light_client_builder =
224+
CombinedLightClient::builder().with_config(&config.lights)?;
225+
if let Some(sender) = feedback {
226+
light_client_builder =
227+
light_client_builder.with(client::feedback::FeedbackLightClient::new(sender));
236228
}
237-
.points_from_file(&config.points_path)
238-
}
239229

240-
pub fn points(&self) -> &[(f64, f64, f64)] {
241-
self.animation_factory.points()
230+
Ok(Self::new(light_client_builder.build(), point_count))
242231
}
243232

244233
pub async fn restart_event_generators(&self) {
@@ -296,28 +285,10 @@ impl Controller {
296285
})
297286
}
298287

299-
pub async fn reload_animation(&self) -> Result<Configuration, ControllerError> {
300-
let mut state = self.state.lock().await;
301-
let Some(id) = state
302-
.animation
303-
.as_ref()
304-
.map(|a| a.plugin_config().animation_id())
305-
else {
306-
return Err(ControllerError::NoAnimationSelected);
307-
};
308-
info!("Reloading animation \"{}\"", id);
309-
let animation = self.animation_factory.make(id).await?;
310-
let configuration = animation.configuration().await?;
311-
state.set_animation(Some(animation)).await?;
312-
Ok(configuration)
313-
}
314-
315288
pub async fn switch_animation(
316289
&self,
317-
animation_id: &str,
290+
animation: Box<dyn Plugin>,
318291
) -> Result<Configuration, ControllerError> {
319-
info!("Trying to switch animation to \"{}\"", animation_id);
320-
let animation = self.animation_factory.make(animation_id).await?;
321292
let configuration = animation.configuration().await?;
322293
let mut state = self.state.lock().await;
323294
state.set_animation(Some(animation)).await?;
@@ -377,73 +348,4 @@ impl Controller {
377348

378349
Ok(())
379350
}
380-
381-
pub fn discover_animations(&mut self) -> Result<(), ControllerError> {
382-
self.animation_factory.discover()?;
383-
Ok(())
384-
}
385-
386-
pub fn list_animations(&self) -> &HashMap<String, PluginConfig> {
387-
self.animation_factory.list()
388-
}
389-
}
390-
391-
pub struct ControllerBuilder {
392-
points: Option<Vec<(f64, f64, f64)>>,
393-
plugin_dir_: Option<PathBuf>,
394-
client_builder: CombinedLightClientBuilder,
395-
}
396-
397-
impl ControllerBuilder {
398-
pub fn points_from_file<P: AsRef<Path>>(mut self, path: P) -> Result<Self, Box<dyn Error>> {
399-
fn points_from_path(path: &Path) -> Result<Vec<(f64, f64, f64)>, ControllerError> {
400-
let points: Vec<_> = csv::ReaderBuilder::new()
401-
.has_headers(false)
402-
.from_path(path)
403-
.map_err(|e| ControllerError::InternalError {
404-
reason: format!("Could not read CSV file: {}", e),
405-
})?
406-
.deserialize()
407-
.filter_map(|record: Result<(f64, f64, f64), _>| record.ok())
408-
.collect();
409-
info!(
410-
"Loaded {} points from {}",
411-
points.len(),
412-
path.to_string_lossy()
413-
);
414-
Ok(points)
415-
}
416-
417-
let path = path.as_ref();
418-
self.points = Some(points_from_path(path)?);
419-
Ok(self)
420-
}
421-
422-
pub fn lights(
423-
mut self,
424-
config: &[rustmas_light_client::LightsConfig],
425-
) -> Result<Self, Box<dyn Error>> {
426-
self.client_builder = self.client_builder.with_config(config)?;
427-
Ok(self)
428-
}
429-
430-
pub fn lights_feedback(mut self, sender: mpsc::Sender<lightfx::Frame>) -> Self {
431-
self.client_builder = self
432-
.client_builder
433-
.with(client::feedback::FeedbackLightClient::new(sender));
434-
self
435-
}
436-
437-
pub fn plugin_dir<P: AsRef<Path>>(mut self, path: P) -> Self {
438-
self.plugin_dir_ = Some(path.as_ref().into());
439-
self
440-
}
441-
442-
pub fn build(self) -> Controller {
443-
Controller::new(
444-
self.points.unwrap(),
445-
self.plugin_dir_.unwrap(),
446-
self.client_builder.build(),
447-
)
448-
}
449351
}

0 commit comments

Comments
 (0)