lights/src/main.rs
Andre Henriques 5c84875dd9
All checks were successful
continuous-integration/drone/push Build is passing
chore: added option to get list of active animations
2023-07-01 23:11:46 +01:00

273 lines
7.0 KiB
Rust

#[macro_use]
extern crate rocket;
//use std::{thread, time::Duration, sync::Arc, io};
use ::std::sync::Arc;
mod animations;
mod configure;
mod render;
mod utils;
mod db;
use animations::Animation;
use r2d2::PooledConnection;
use utils::{ApiResponse, ApiResponseActiveList};
use rocket::{serde::json::{serde_json::json, self}, State};
use r2d2_sqlite::SqliteConnectionManager;
use crate::db::setup_database;
//use std::sync::atomic::AtomicBool;
use std::{
error::Error,
sync::{
mpsc::{self, Receiver, Sender},
Mutex,
},
};
pub type DBPool = Arc<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>;
pub type DBConn = PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
pub type GResult = Result<(), Box<dyn Error>>;
pub type ASender<T> = Arc<Mutex<Sender<T>>>;
pub type AReceiver<T> = Arc<Mutex<Receiver<T>>>;
#[get("/")]
fn index() -> &'static str {
"Hello World"
}
pub enum Action {
Reload,
Stop,
Clear,
GetActiveList,
}
pub enum RenderMessage {
ActiveList(Vec<String>),
// TODO remove none where other are added
None
}
#[get("/quit")]
async fn quit(shutdown: rocket::Shutdown, action: &State<ASender<Action>>) -> String {
println!("Got Shutdown");
let send = action.lock().unwrap().send(Action::Stop);
if send.is_err() || send.ok().is_none() {
return json!(ApiResponse {
code: 500,
message: "Failed to stop".to_string()
})
.to_string();
}
shutdown.notify();
json!(ApiResponse {
code: 200,
message: "Stoped".to_string()
})
.to_string()
}
#[get("/reload")]
async fn reload(action: &State<ASender<Action>>) -> String {
println!("Got Shutdown");
let send = action.lock().unwrap().send(Action::Reload);
if send.is_err() || send.ok().is_none() {
return json!(ApiResponse {
code: 500,
message: "Failed to reload".to_string()
})
.to_string();
}
json!(ApiResponse {
code: 200,
message: "Reloaded".to_string()
})
.to_string()
}
#[get("/active")]
async fn get_active(action: &State<ASender<Action>>, messages: &State<AReceiver<RenderMessage>>) -> String {
println!("Getting active");
let send = action.lock().unwrap().send(Action::GetActiveList);
if send.is_err() || send.ok().is_none() {
return json!(ApiResponse{
code: 500,
message: "Failed to get list".to_string()
}).to_string();
}
let data = messages.lock().unwrap().recv();
if data.is_err() || data.as_ref().ok().is_none() {
return json!(ApiResponse {
code: 500,
message: "Failed to get list".to_string()
}).to_string();
}
if let RenderMessage::ActiveList(list) = data.ok().unwrap() {
return json!(ApiResponseActiveList {
code: 200,
active_animations: list
}).to_string();
}
return json!(ApiResponse {
code: 500,
message: "Failed to get list".to_string()
}).to_string();
}
fn ligth_controll(
pool: DBPool,
action: Receiver<Action>,
start_ani: Receiver<Animation>,
stop_ani: Receiver<String>,
message_server: Sender<RenderMessage>,
) {
println!("Data loop started");
let render = render::Render::new(pool.clone());
if render.is_err() || render.as_ref().ok().is_none() {
println!("something every wrong {:?}", render.err());
return;
}
let mut render = render.ok().unwrap();
'mainloop: loop {
let action = action.try_recv();
if action.is_ok() {
match action.ok().unwrap() {
Action::Reload => {
let result = render.load_config();
if result.is_err() || result.as_ref().ok().is_none() {
println!("Ehh failed to load config i guess: {:?}", result.err());
}
}
Action::Clear => {
render.blank();
}
Action::Stop => {
render.blank();
render.im_render();
break 'mainloop;
}
Action::GetActiveList => {
if message_server.send(RenderMessage::ActiveList(render.get_active_animations())).is_err() {
println!("Failed to send message ups");
}
}
}
}
let ani = start_ani.try_recv();
if ani.is_ok() {
println!("Added animation");
//TODO
render.add_animation(ani.ok().unwrap());
//ani.ok().unwrap().
}
let ani = stop_ani.try_recv();
if ani.is_ok() {
render.remove_animation(ani.ok().unwrap());
}
render.render();
}
println!("stoped main loop");
}
#[rocket::main]
async fn main() -> GResult {
println!("Program start");
println!("Try to connect db");
let sqlite_conn_manager = SqliteConnectionManager::file("ligths.db");
let conn_pool = r2d2::Pool::new(sqlite_conn_manager).expect("Failed to create pool");
let conn_pool_arc = Arc::new(conn_pool);
{
let pool = conn_pool_arc.clone();
let dd = setup_database(pool);
println!("{:?}", dd);
dd.ok().unwrap();
}
let (action_sender, action_receiver): (Sender<Action>, Receiver<Action>) = mpsc::channel();
let (start_animation_sender, start_animation_receiver): (
Sender<Animation>,
Receiver<Animation>,
) = mpsc::channel();
let (stop_animation_sender, stop_animation_receiver): (Sender<String>, Receiver<String>) =
mpsc::channel();
let (messager_sender, messager_revicer): (Sender<RenderMessage>, Receiver<RenderMessage>) =
mpsc::channel();
let pool_clone = conn_pool_arc.clone();
let ligths_controll = std::thread::spawn(move || {
ligth_controll(
pool_clone,
action_receiver,
start_animation_receiver,
stop_animation_receiver,
messager_sender
);
});
let cfg = rocket::Config::figment()
.merge(("port", 3000))
.merge(("address", "0.0.0.0"));
let _rocket = rocket::custom(cfg)
.mount(
"/",
routes![
index,
quit,
reload,
configure::configure,
animations::animation,
animations::start_animation,
animations::stop_animation,
animations::clear,
animations::delete,
animations::clear_all,
],
)
.manage(conn_pool_arc.clone())
.manage(Arc::new(Mutex::new(action_sender)))
.manage(Arc::new(Mutex::new(start_animation_sender)))
.manage(Arc::new(Mutex::new(stop_animation_sender)))
.manage(Arc::new(Mutex::new(messager_revicer)))
.launch()
.await?;
ligths_controll.join().unwrap();
Ok(())
}