Many fixes related to error message passing
This commit is contained in:
parent
e2952cb614
commit
4bc1ef4ba2
@ -1,4 +1,3 @@
|
|||||||
use hex;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -87,9 +86,9 @@ pub fn merge_colors(from_color: Rgb, to_color: Rgb, factor: f32) -> Rgb {
|
|||||||
let (to_r, to_g, to_b) = to_color.to_float_tuple();
|
let (to_r, to_g, to_b) = to_color.to_float_tuple();
|
||||||
|
|
||||||
// TODO: Do not use as u8
|
// TODO: Do not use as u8
|
||||||
let r = ((to_r - from_r) * factor + from_r) as u8;
|
let r = (to_r - from_r).mul_add(factor, from_r) as u8;
|
||||||
let g = ((to_g - from_g) * factor + from_g) as u8;
|
let g = (to_g - from_g).mul_add(factor, from_g) as u8;
|
||||||
let b = ((to_b - from_b) * factor + from_b) as u8;
|
let b = (to_b - from_b).mul_add(factor, from_b) as u8;
|
||||||
|
|
||||||
Rgb(r, g, b)
|
Rgb(r, g, b)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,23 @@
|
|||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub type ProgramResult<T> = Result<T, ProgramError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Message {
|
||||||
|
Error(ProgramError),
|
||||||
|
Terminated,
|
||||||
|
String(String),
|
||||||
|
InputPrompt(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ProgramError {
|
pub enum ProgramError {
|
||||||
General(String),
|
General(String),
|
||||||
UiError(String),
|
UiError(String),
|
||||||
Boxed(Box<dyn Any + Send>),
|
Boxed(Box<dyn Any + Send>),
|
||||||
|
IoError(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for ProgramError {
|
impl From<String> for ProgramError {
|
||||||
@ -32,6 +44,7 @@ impl fmt::Display for ProgramError {
|
|||||||
Self::General(s) => write!(f, "{}", s),
|
Self::General(s) => write!(f, "{}", s),
|
||||||
Self::UiError(s) => write!(f, "Critial UI error: {}", s),
|
Self::UiError(s) => write!(f, "Critial UI error: {}", s),
|
||||||
Self::Boxed(s) => write!(f, "{:?}", s),
|
Self::Boxed(s) => write!(f, "{:?}", s),
|
||||||
|
Self::IoError(e) => write!(f, "{:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
72
src/main.rs
72
src/main.rs
@ -32,16 +32,22 @@ mod pattern;
|
|||||||
mod strip;
|
mod strip;
|
||||||
mod ui;
|
mod ui;
|
||||||
mod webui;
|
mod webui;
|
||||||
use errors::ProgramError;
|
use errors::{ProgramError, ProgramResult};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::sync::mpsc::channel;
|
use std::io::Write;
|
||||||
|
use std::sync::mpsc::{channel, Sender};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use strip::{LedStrip, Message};
|
use strip::LedStrip;
|
||||||
use ui::console_ui_loop;
|
use ui::console_ui_loop;
|
||||||
|
|
||||||
fn main() -> Result<(), ProgramError> {
|
fn main() -> ProgramResult<()> {
|
||||||
let (tx, rx) = channel::<Message>();
|
// Strip control transmitter and receiver
|
||||||
let strip_handle = thread::spawn(move || -> Result<(), ProgramError> {
|
let (strip_tx, strip_rx) = channel::<strip::Message>();
|
||||||
|
let (console_strip_tx, webui_strip_tx) = (strip_tx.clone(), strip_tx);
|
||||||
|
|
||||||
|
let (message_tx, message_rx) = channel::<errors::Message>();
|
||||||
|
|
||||||
|
make_child(message_tx.clone(), move |message_tx| -> ProgramResult<()> {
|
||||||
let mut strip = LedStrip::new(strip::Config {
|
let mut strip = LedStrip::new(strip::Config {
|
||||||
// I have 89 right now, but start off with 20
|
// I have 89 right now, but start off with 20
|
||||||
num_lights: 89,
|
num_lights: 89,
|
||||||
@ -51,25 +57,47 @@ fn main() -> Result<(), ProgramError> {
|
|||||||
global_brightness_max: 255,
|
global_brightness_max: 255,
|
||||||
tick_time_ms: strip::DEFAULT_TICK_TIME_MS,
|
tick_time_ms: strip::DEFAULT_TICK_TIME_MS,
|
||||||
})?;
|
})?;
|
||||||
strip.strip_loop(&rx)
|
strip.strip_loop(message_tx, &strip_rx)
|
||||||
});
|
});
|
||||||
|
|
||||||
// I do not care if the console ui crashes
|
make_child(message_tx.clone(), move |message_tx| -> ProgramResult<()> {
|
||||||
let (g, h) = (tx.clone(), tx.clone());
|
console_ui_loop(message_tx, &console_strip_tx)
|
||||||
let _console_ui_handle = thread::spawn(move || -> Result<(), ProgramError> {
|
|
||||||
let ret = console_ui_loop(&g);
|
|
||||||
println!("Console ui dead: {:?}", ret);
|
|
||||||
ret
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// I do not care if the web ui crashes
|
make_child(message_tx, move |message_tx| -> ProgramResult<()> {
|
||||||
let _web_ui_handle = thread::spawn(move || -> Result<(), io::Error> {
|
webui::start(message_tx.clone(), webui_strip_tx).map_err(ProgramError::IoError)
|
||||||
let ret = webui::start(h);
|
});
|
||||||
println!("Webui dead: {:?}", ret);
|
|
||||||
ret
|
|
||||||
// TODO: Do not join -- this is just because we are running on a computer with no spi env
|
|
||||||
})
|
|
||||||
.join()?;
|
|
||||||
|
|
||||||
strip_handle.join()?
|
let mut input_prompt: Option<String> = None;
|
||||||
|
loop {
|
||||||
|
match message_rx.recv() {
|
||||||
|
Ok(errors::Message::String(s)) => println!("\r{}", s),
|
||||||
|
Ok(errors::Message::Error(e)) => println!("\rError!! {:?}", e),
|
||||||
|
Ok(errors::Message::Terminated) => {
|
||||||
|
panic!("A thread terminated")
|
||||||
|
}
|
||||||
|
Ok(errors::Message::InputPrompt(i)) => input_prompt = Some(i),
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ProgramError::General(format!(
|
||||||
|
"All transmitters hung up! {:?}",
|
||||||
|
e
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ref s) = input_prompt {
|
||||||
|
print!("{}: ", s);
|
||||||
|
// We do not care if we can't flush
|
||||||
|
let _ = io::stdout().flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_child<F: 'static>(message_tx: Sender<errors::Message>, f: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(&Sender<errors::Message>) -> ProgramResult<()> + std::marker::Send,
|
||||||
|
{
|
||||||
|
thread::spawn(move || match f(&message_tx) {
|
||||||
|
Ok(()) => message_tx.send(errors::Message::Terminated),
|
||||||
|
Err(e) => message_tx.send(errors::Message::Error(e)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ impl Pattern for MovingRainbow {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
fn init(&mut self, num_lights: u16) -> Result<(), ()> {
|
fn init(&mut self, num_lights: u16) -> Result<(), ()> {
|
||||||
if num_lights < 1 || num_lights > 255 {
|
if !(1..=255).contains(&num_lights) {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
if self.width < 1 {
|
if self.width < 1 {
|
||||||
@ -39,14 +39,15 @@ impl Pattern for MovingRainbow {
|
|||||||
|
|
||||||
// The length of the buffer
|
// The length of the buffer
|
||||||
// Always a factor of RAINBOW.len() * width
|
// Always a factor of RAINBOW.len() * width
|
||||||
let length_factor = u16::try_from(RAINBOW.len()).or(Err(()))? * u16::from(self.width);
|
let length_factor = u16::try_from(RAINBOW.len()).or(Err(()))?.saturating_mul(u16::from(self.width));
|
||||||
let buf_length = num_lights
|
let buf_length = num_lights
|
||||||
.checked_sub(1)
|
.checked_sub(1)
|
||||||
.ok_or(())?
|
.ok_or(())?
|
||||||
.div_euclid(length_factor)
|
.div_euclid(length_factor)
|
||||||
.checked_add(1)
|
.checked_add(1)
|
||||||
.ok_or(())?
|
.ok_or(())?
|
||||||
* length_factor;
|
.saturating_mul(length_factor)
|
||||||
|
;
|
||||||
|
|
||||||
self.lights_buf = RAINBOW
|
self.lights_buf = RAINBOW
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -32,7 +32,7 @@ impl Orb {
|
|||||||
color,
|
color,
|
||||||
center_width,
|
center_width,
|
||||||
backoff_width,
|
backoff_width,
|
||||||
total_width: center_width + backoff_width * 2,
|
total_width: center_width.saturating_add(backoff_width.saturating_mul(2)),
|
||||||
bounces: false,
|
bounces: false,
|
||||||
step: 0,
|
step: 0,
|
||||||
step_max: 0,
|
step_max: 0,
|
||||||
@ -75,7 +75,7 @@ impl Pattern for Orb {
|
|||||||
self.lights_buf = iter::empty::<Rgb>()
|
self.lights_buf = iter::empty::<Rgb>()
|
||||||
.chain(ramp.clone().into_iter())
|
.chain(ramp.clone().into_iter())
|
||||||
.chain(iter::repeat(self.color).take(self.center_width.into()))
|
.chain(iter::repeat(self.color).take(self.center_width.into()))
|
||||||
.chain(ramp.clone().into_iter().rev())
|
.chain(ramp.into_iter().rev())
|
||||||
.chain(
|
.chain(
|
||||||
iter::repeat(other_color)
|
iter::repeat(other_color)
|
||||||
.take(num_lights.saturating_sub(self.total_width.into()).into()),
|
.take(num_lights.saturating_sub(self.total_width.into()).into()),
|
||||||
@ -86,7 +86,7 @@ impl Pattern for Orb {
|
|||||||
.lights_buf
|
.lights_buf
|
||||||
.len()
|
.len()
|
||||||
.checked_sub(self.total_width.into())
|
.checked_sub(self.total_width.into())
|
||||||
.unwrap_or(self.lights_buf.len());
|
.unwrap_or_else(|| self.lights_buf.len());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
30
src/strip.rs
30
src/strip.rs
@ -1,10 +1,11 @@
|
|||||||
use crate::color;
|
use crate::color;
|
||||||
|
use crate::errors;
|
||||||
use crate::errors::ProgramError;
|
use crate::errors::ProgramError;
|
||||||
use crate::pattern::{self, Pattern};
|
use crate::pattern::{self, Pattern};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use ws2818_rgb_led_spi_driver::adapter_gen::Ws28xxAdapter;
|
use ws2818_rgb_led_spi_driver::adapter_gen::Ws28xxAdapter;
|
||||||
use ws2818_rgb_led_spi_driver::adapter_spi::Ws28xxSpiAdapter;
|
use ws2818_rgb_led_spi_driver::adapter_spi::Ws28xxSpiAdapter;
|
||||||
@ -99,7 +100,11 @@ impl LedStrip {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn strip_loop(&mut self, rx: &Receiver<Message>) -> Result<(), ProgramError> {
|
pub fn strip_loop(
|
||||||
|
&mut self,
|
||||||
|
message_tx: &Sender<errors::Message>,
|
||||||
|
rx: &Receiver<Message>,
|
||||||
|
) -> Result<(), ProgramError> {
|
||||||
let mut exit = false;
|
let mut exit = false;
|
||||||
loop {
|
loop {
|
||||||
let target_time = Instant::now().add(Duration::from_millis(self.config.tick_time_ms));
|
let target_time = Instant::now().add(Duration::from_millis(self.config.tick_time_ms));
|
||||||
@ -111,7 +116,10 @@ impl LedStrip {
|
|||||||
if pat.init(self.config.num_lights).is_ok() {
|
if pat.init(self.config.num_lights).is_ok() {
|
||||||
self.pattern = pat;
|
self.pattern = pat;
|
||||||
} else {
|
} else {
|
||||||
println!("Clearing light strip: {:?}", pat);
|
let _ = message_tx.send(errors::Message::String(format!(
|
||||||
|
"Clearing light strip: {:?}",
|
||||||
|
pat
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ChangePattern(pat) => {
|
Message::ChangePattern(pat) => {
|
||||||
@ -119,7 +127,10 @@ impl LedStrip {
|
|||||||
if pat.init(self.config.num_lights).is_ok() {
|
if pat.init(self.config.num_lights).is_ok() {
|
||||||
self.pattern = pat;
|
self.pattern = pat;
|
||||||
} else {
|
} else {
|
||||||
println!("Error with pattern: {:?}", pat);
|
let _ = message_tx.send(errors::Message::String(format!(
|
||||||
|
"Error with pattern: {:?}",
|
||||||
|
pat
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SetNumLights(num_lights) => {
|
Message::SetNumLights(num_lights) => {
|
||||||
@ -127,7 +138,10 @@ impl LedStrip {
|
|||||||
}
|
}
|
||||||
Message::SetTickTime(tick_time_ms) => {
|
Message::SetTickTime(tick_time_ms) => {
|
||||||
if tick_time_ms < MIN_TICK_TIME {
|
if tick_time_ms < MIN_TICK_TIME {
|
||||||
println!("Error with tick time: {}", tick_time_ms);
|
let _ = message_tx.send(errors::Message::String(format!(
|
||||||
|
"Error with tick time: {}",
|
||||||
|
tick_time_ms
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
self.config.tick_time_ms = tick_time_ms;
|
self.config.tick_time_ms = tick_time_ms;
|
||||||
}
|
}
|
||||||
@ -137,7 +151,9 @@ impl LedStrip {
|
|||||||
if pat.init(self.config.num_lights).is_ok() {
|
if pat.init(self.config.num_lights).is_ok() {
|
||||||
self.pattern = Box::new(pat);
|
self.pattern = Box::new(pat);
|
||||||
} else {
|
} else {
|
||||||
println!("Could not construct clear pattern");
|
let _ = message_tx.send(errors::Message::String(
|
||||||
|
String::from("Could not construct clear pattern")
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +168,7 @@ impl LedStrip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if exit {
|
if exit {
|
||||||
println!("Exiting as requested");
|
let _ = message_tx.send(errors::Message::String(String::from("Exiting as requested")));
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
57
src/ui.rs
57
src/ui.rs
@ -1,21 +1,24 @@
|
|||||||
use crate::color::Rgb;
|
use crate::color::Rgb;
|
||||||
use crate::errors::ProgramError;
|
use crate::errors::{self, ProgramError, ProgramResult};
|
||||||
use crate::pattern::{self, Pattern};
|
use crate::pattern::{self, Pattern};
|
||||||
use crate::strip;
|
use crate::strip;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
pub fn console_ui_loop(tx: &Sender<strip::Message>) -> Result<(), ProgramError> {
|
pub fn console_ui_loop(
|
||||||
|
message_tx: &Sender<errors::Message>,
|
||||||
|
strip_tx: &Sender<strip::Message>,
|
||||||
|
) -> ProgramResult<()> {
|
||||||
loop {
|
loop {
|
||||||
let line = get_line("Command (cfqs)")?;
|
let line = get_line(message_tx, "Command (cfqs)")?;
|
||||||
if let Err(msg) = parse_cmd(tx, &line) {
|
if let Err(msg) = parse_cmd(strip_tx, &line) {
|
||||||
println!("Command error: {}", msg);
|
println!("Command error: {}", msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cmd(tx: &Sender<strip::Message>, s: &str) -> Result<(), String> {
|
fn parse_cmd(strip_tx: &Sender<strip::Message>, s: &str) -> Result<(), String> {
|
||||||
match s
|
match s
|
||||||
.split(char::is_whitespace)
|
.split(char::is_whitespace)
|
||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
@ -30,14 +33,14 @@ fn parse_cmd(tx: &Sender<strip::Message>, s: &str) -> Result<(), String> {
|
|||||||
b.parse::<u8>()
|
b.parse::<u8>()
|
||||||
.map_err(|_| String::from("Blue could not be parsed"))?,
|
.map_err(|_| String::from("Blue could not be parsed"))?,
|
||||||
);
|
);
|
||||||
change_pattern(tx, Box::new(pattern::Fade::new(color)))
|
change_pattern(strip_tx, Box::new(pattern::Fade::new(color)))
|
||||||
}
|
}
|
||||||
["f", c] => {
|
["f", c] => {
|
||||||
let color_value = c
|
let color_value = c
|
||||||
.parse::<u8>()
|
.parse::<u8>()
|
||||||
.map_err(|_| String::from("Could not parse color"))?;
|
.map_err(|_| String::from("Could not parse color"))?;
|
||||||
let color = Rgb(color_value, color_value, color_value);
|
let color = Rgb(color_value, color_value, color_value);
|
||||||
change_pattern(tx, Box::new(pattern::Fade::new(color)))
|
change_pattern(strip_tx, Box::new(pattern::Fade::new(color)))
|
||||||
}
|
}
|
||||||
["m", r, g, b] => {
|
["m", r, g, b] => {
|
||||||
let color = Rgb(
|
let color = Rgb(
|
||||||
@ -48,49 +51,53 @@ fn parse_cmd(tx: &Sender<strip::Message>, s: &str) -> Result<(), String> {
|
|||||||
b.parse::<u8>()
|
b.parse::<u8>()
|
||||||
.map_err(|_| String::from("Blue could not be parsed"))?,
|
.map_err(|_| String::from("Blue could not be parsed"))?,
|
||||||
);
|
);
|
||||||
change_pattern(tx, Box::new(pattern::MovingPixel::new(color)))
|
change_pattern(strip_tx, Box::new(pattern::MovingPixel::new(color)))
|
||||||
}
|
}
|
||||||
["m", c] => {
|
["m", c] => {
|
||||||
let color_value = c
|
let color_value = c
|
||||||
.parse::<u8>()
|
.parse::<u8>()
|
||||||
.map_err(|_| String::from("Could not parse color"))?;
|
.map_err(|_| String::from("Could not parse color"))?;
|
||||||
let color = Rgb(color_value, color_value, color_value);
|
let color = Rgb(color_value, color_value, color_value);
|
||||||
change_pattern(tx, Box::new(pattern::MovingPixel::new(color)))
|
change_pattern(strip_tx, Box::new(pattern::MovingPixel::new(color)))
|
||||||
},
|
},
|
||||||
["c", r, g, b] => {
|
["c", r, g, b] => {
|
||||||
let color = parse_color(r, g, b)?;
|
let color = parse_color(r, g, b)?;
|
||||||
change_pattern(tx, Box::new(pattern::Solid::new(color)))
|
change_pattern(strip_tx, Box::new(pattern::Solid::new(color)))
|
||||||
}
|
}
|
||||||
["c", c] => {
|
["c", c] => {
|
||||||
let color = parse_color(c, c, c)?;
|
let color = parse_color(c, c, c)?;
|
||||||
change_pattern(tx, Box::new(pattern::Solid::new(color)))
|
change_pattern(strip_tx, Box::new(pattern::Solid::new(color)))
|
||||||
},
|
},
|
||||||
["r"] =>change_pattern(tx, Box::new(pattern::MovingRainbow::new(4, true))),
|
["r"] =>change_pattern(strip_tx, Box::new(pattern::MovingRainbow::new(4, true))),
|
||||||
["r", w] => {
|
["r", w] => {
|
||||||
let width = w.parse::<u8>().map_err(|_| String::from("Width could not be parsed"))?;
|
let width = w.parse::<u8>().map_err(|_| String::from("Width could not be parsed"))?;
|
||||||
change_pattern(tx, Box::new(pattern::MovingRainbow::new(width, true)))
|
change_pattern(strip_tx, Box::new(pattern::MovingRainbow::new(width, true)))
|
||||||
},
|
},
|
||||||
["r", w, f] => {
|
["r", w, f] => {
|
||||||
let width = w.parse::<u8>().map_err(|_| String::from("Width could not be parsed"))?;
|
let width = w.parse::<u8>().map_err(|_| String::from("Width could not be parsed"))?;
|
||||||
change_pattern(tx, Box::new(pattern::MovingRainbow::new(width, ["t", "T"].contains(f))))
|
change_pattern(strip_tx, Box::new(pattern::MovingRainbow::new(width, ["t", "T"].contains(f))))
|
||||||
},
|
},
|
||||||
["b", r1, g1, b1, r2, g2, b2, r3, g3, b3] => {
|
["b", r1, g1, b1, r2, g2, b2, r3, g3, b3] => {
|
||||||
let left = parse_color(r1, g1, b1)?;
|
let left = parse_color(r1, g1, b1)?;
|
||||||
let right = parse_color(r2, g2, b2)?;
|
let right = parse_color(r2, g2, b2)?;
|
||||||
let combined = parse_color(r3, g3, b3)?;
|
let combined = parse_color(r3, g3, b3)?;
|
||||||
change_pattern(tx, Box::new(pattern::Collide::new(left, right, combined)))
|
change_pattern(strip_tx, Box::new(pattern::Collide::new(left, right, combined)))
|
||||||
}
|
}
|
||||||
["x"] => tx
|
["x"] => strip_tx
|
||||||
.send(strip::Message::ClearLights)
|
.send(strip::Message::ClearLights)
|
||||||
.map_err(|e| e.to_string()),
|
.map_err(|e| e.to_string()),
|
||||||
["q"] => tx.send(strip::Message::Quit).map_err(|e| e.to_string()),
|
["q"] => {
|
||||||
["s", n] => tx
|
strip_tx.send(strip::Message::Quit).map_err(|e| e.to_string())?;
|
||||||
|
// TODO
|
||||||
|
panic!("i");
|
||||||
|
},
|
||||||
|
["s", n] => strip_tx
|
||||||
.send(strip::Message::SetNumLights(
|
.send(strip::Message::SetNumLights(
|
||||||
n.parse::<u16>()
|
n.parse::<u16>()
|
||||||
.map_err(|_| String::from("Could not parse light count"))?,
|
.map_err(|_| String::from("Could not parse light count"))?,
|
||||||
))
|
))
|
||||||
.map_err(|e| e.to_string()),
|
.map_err(|e| e.to_string()),
|
||||||
["t", n] => tx.send(strip::Message::SetTickTime(
|
["t", n] => strip_tx.send(strip::Message::SetTickTime(
|
||||||
n.parse::<u64>()
|
n.parse::<u64>()
|
||||||
.map_err(|_| String::from("Could not parse light count"))?,
|
.map_err(|_| String::from("Could not parse light count"))?,
|
||||||
))
|
))
|
||||||
@ -110,13 +117,17 @@ fn parse_color(r: &str, g: &str, b: &str) -> Result<Rgb, String> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_pattern(tx: &Sender<strip::Message>, pat: Box<dyn Pattern + Send>) -> Result<(), String> {
|
fn change_pattern(
|
||||||
tx.send(strip::Message::ChangePattern(pat))
|
strip_tx: &Sender<strip::Message>,
|
||||||
|
pat: Box<dyn Pattern + Send>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
strip_tx
|
||||||
|
.send(strip::Message::ChangePattern(pat))
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_line(prompt: &str) -> Result<String, ProgramError> {
|
fn get_line(message_tx: &Sender<errors::Message>, prompt: &str) -> ProgramResult<String> {
|
||||||
print!("{}: ", prompt);
|
let _ = message_tx.send(errors::Message::InputPrompt(String::from(prompt)));
|
||||||
std::io::stdout()
|
std::io::stdout()
|
||||||
.flush()
|
.flush()
|
||||||
.map_err(|_| ProgramError::UiError(String::from("Could not flush stdout")))?;
|
.map_err(|_| ProgramError::UiError(String::from("Could not flush stdout")))?;
|
||||||
|
23
src/webui.rs
23
src/webui.rs
@ -1,9 +1,10 @@
|
|||||||
|
use crate::errors;
|
||||||
use crate::pattern;
|
use crate::pattern;
|
||||||
use crate::strip;
|
use crate::strip;
|
||||||
use actix_web::error::JsonPayloadError;
|
use actix_web::error::JsonPayloadError;
|
||||||
use actix_web::web::JsonConfig;
|
use actix_web::web::JsonConfig;
|
||||||
use actix_web::{post, web, App, HttpServer, Responder, Result};
|
use actix_web::{post, web, App, HttpServer, Responder, Result};
|
||||||
use actix_web_static_files;
|
use actix_web_static_files::ResourceFiles;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
@ -23,38 +24,42 @@ async fn set_color(
|
|||||||
println!("Got params: {:?}", params);
|
println!("Got params: {:?}", params);
|
||||||
data.strip_tx
|
data.strip_tx
|
||||||
.lock()
|
.lock()
|
||||||
.or(Err(io::Error::new(
|
.map_err(|_| io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
"Failed to get a lock",
|
"Failed to get a lock",
|
||||||
)))?
|
))?
|
||||||
.send(strip::Message::ChangePattern(params.0.to_pattern()))
|
.send(strip::Message::ChangePattern(params.0.to_pattern()))
|
||||||
.or(Err(io::Error::new(
|
.map_err(|_| io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
"Failed to send to channel",
|
"Failed to send to channel",
|
||||||
)))?;
|
))?;
|
||||||
Ok(format!("{:?}", params))
|
Ok(format!("{:?}", params))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
pub async fn start(tx: Sender<strip::Message>) -> std::io::Result<()> {
|
pub async fn start(
|
||||||
println!("Starting webui");
|
message_tx: Sender<errors::Message>,
|
||||||
|
strip_tx: Sender<strip::Message>,
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
let _ = message_tx.send(errors::Message::String(String::from("Starting webui")));
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
let generated = generate();
|
let generated = generate();
|
||||||
App::new()
|
App::new()
|
||||||
.data(AppState {
|
.data(AppState {
|
||||||
strip_tx: Arc::new(Mutex::new(tx.clone())),
|
strip_tx: Arc::new(Mutex::new(strip_tx.clone())),
|
||||||
})
|
})
|
||||||
.service(
|
.service(
|
||||||
web::scope("/api")
|
web::scope("/api")
|
||||||
.app_data(
|
.app_data(
|
||||||
JsonConfig::default().error_handler(|err: JsonPayloadError, _req| {
|
JsonConfig::default().error_handler(|err: JsonPayloadError, _req| {
|
||||||
|
// let _ = message_tx.send(errors::Message::String(format!("JSON error: {:?}", err)));
|
||||||
println!("JSON error: {:?}", err);
|
println!("JSON error: {:?}", err);
|
||||||
err.into()
|
err.into()
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.service(set_color),
|
.service(set_color),
|
||||||
)
|
)
|
||||||
.service(actix_web_static_files::ResourceFiles::new("/", generated))
|
.service(ResourceFiles::new("/", generated))
|
||||||
})
|
})
|
||||||
.bind(("0.0.0.0", 8080))?
|
.bind(("0.0.0.0", 8080))?
|
||||||
.run()
|
.run()
|
||||||
|
@ -62,17 +62,17 @@
|
|||||||
const response = fetch(url, {
|
const response = fetch(url, {
|
||||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||||
// mode: 'no-cors', // no-cors, *cors, same-origin
|
// mode: 'no-cors', // no-cors, *cors, same-origin
|
||||||
//cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
|
// cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
|
||||||
//credentials: 'same-origin', // include, *same-origin, omit
|
// credentials: 'same-origin', // include, *same-origin, omit
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
},
|
},
|
||||||
//redirect: 'follow', // manual, *follow, error
|
// redirect: 'follow', // manual, *follow, error
|
||||||
//referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
|
// referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
|
||||||
body: JSON.stringify(getFormData()) // body data type must match "Content-Type" header
|
body: JSON.stringify(getFormData()) // body data type must match "Content-Type" header
|
||||||
}).then(r => console.log(response));
|
}).then(r => console.log(response));
|
||||||
//return response.json(); // parses JSON response into native JavaScript objects
|
// return response.json(); // parses JSON response into native JavaScript objects
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user