diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..ceb81d8 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,161 @@ +use std::error::Error; + +use crate::DBPool; + +pub type GResult = Result<(), Box>; +const DATAVERSION: &str = "0.0.10"; + +fn create_database(pool: DBPool) -> GResult { + let conn = pool.get()?; + + println!("Createing the database"); + + println!("Createing new meta table. With version {}", DATAVERSION); + println!("Drop old meta table"); + conn.execute("DROP TABLE IF EXISTS meta;", ())?; + // Create the database + println!("create new meta table"); + conn.execute( + "CREATE TABLE meta ( + id INTEGER PRIMARY KEY, + version TEXT, + configured Boolean + );", + (), + )?; + println!("insert data"); + conn.execute( + "INSERT INTO meta (version, configured) VALUES (?1, ?2);", + (&DATAVERSION, false), + )?; + + println!( + "Createing new configuration table. With version {}", + DATAVERSION + ); + println!("Drop configuration table"); + conn.execute("DROP TABLE IF EXISTS configuration", ())?; + println!("Create new configuration table"); + conn.execute( + "CREATE TABLE configuration ( + id INTEGER PRIMARY KEY, + ledcount INTEGER, + directionX INTEGER, + directionY INTEGER, + directionZ INTEGER, + tags VARCHAR(255) + );", + (), + )?; + + println!( + "Createing new Animation table. With version {}", + DATAVERSION + ); + println!("Drop Animation table and references"); + conn.execute("DROP TABLE IF EXISTS lightsetting", ())?; + conn.execute("DROP TABLE IF EXISTS keyframe", ())?; + conn.execute("DROP TABLE IF EXISTS animation", ())?; + println!("Create new animation table"); + conn.execute( + "CREATE TABLE animation ( + id INTEGER PRIMARY KEY, + priority INTEGER, + name VARCHAR(255), + repeat BOOLEAN + );", + (), + )?; + + println!( + "Createing new key_frame table. With version {}", + DATAVERSION + ); + println!("Drop key_frame table"); + println!("Create new key_frame table"); + conn.execute( + "CREATE TABLE keyframe ( + id INTEGER PRIMARY KEY, + i INTEGER, + duration INTEGER, + animation INTEGER, + FOREIGN KEY(animation) REFERENCES animation(id) ON DELETE CASCADE + );", + (), + )?; + + println!( + "Createing new LigthSetting table. With version {}", + DATAVERSION + ); + println!("Drop LigthSetting table"); + println!("Create new light_setting table"); + conn.execute( + "CREATE TABLE lightsetting ( + id INTEGER PRIMARY KEY, + start INTEGER, + end INTEGER, + tags VARCHAR(255), + r INTEGER, + b INTEGER, + g INTEGER, + keyframe INTEGER, + FOREIGN KEY(keyframe) REFERENCES keyframe(id) ON DELETE CASCADE + );", + (), + )?; + + Ok(()) +} + +pub fn setup_database(pool: DBPool) -> GResult { + let conn = pool.get()?; + + println!("Trying to get meta data"); + + let stmt = conn.prepare("SELECT version from meta"); + + if stmt.is_err() || stmt.as_ref().ok().is_none() { + return create_database(pool); + } + + let mut stmt = stmt?; + + struct Data { + version: String, + } + + let version_iter = stmt.query_map([], |row| { + Ok(Data { + version: row.get(0)?, + }) + }); + + println!("Process meta"); + + if version_iter.is_err() || version_iter.as_ref().ok().is_none() { + create_database(pool)?; + } else { + let version_iter = version_iter.ok().unwrap(); + + let mut recreate = true; + + for data in version_iter { + let version = data.unwrap().version; + println!("Found version {}", version); + + if !DATAVERSION.to_string().eq(&version) { + println!("Mismatched versions recreating database"); + recreate = true; + break; + } + + recreate = false; + } + + if recreate { + create_database(pool)?; + } + } + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index cac6387..b66c3ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,15 +7,18 @@ mod animations; mod configure; mod render; mod utils; +mod db; use animations::Animation; use r2d2::PooledConnection; -use utils::ApiResponse; +use utils::{ApiResponse, ApiResponseActiveList}; -use rocket::{serde::json::serde_json::json, State}; +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::{ @@ -30,6 +33,7 @@ pub type DBPool = Arc>; pub type DBConn = PooledConnection; pub type GResult = Result<(), Box>; pub type ASender = Arc>>; +pub type AReceiver = Arc>>; #[get("/")] fn index() -> &'static str { @@ -40,6 +44,13 @@ pub enum Action { Reload, Stop, Clear, + GetActiveList, +} + +pub enum RenderMessage { + ActiveList(Vec), + // TODO remove none where other are added + None } #[get("/quit")] @@ -86,11 +97,48 @@ async fn reload(action: &State>) -> String { .to_string() } +#[get("/active")] +async fn get_active(action: &State>, messages: &State>) -> 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, start_ani: Receiver, stop_ani: Receiver, + message_server: Sender, ) { println!("Data loop started"); @@ -122,6 +170,11 @@ fn ligth_controll( 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"); + } + } } } @@ -146,162 +199,6 @@ fn ligth_controll( println!("stoped main loop"); } -const DATAVERSION: &str = "0.0.10"; - -fn setup_database(pool: DBPool) -> GResult { - let conn = pool.get()?; - - println!("Trying to get meta data"); - - let stmt = conn.prepare("SELECT version from meta"); - - if stmt.is_err() || stmt.as_ref().ok().is_none() { - return create_database(pool); - } - - let mut stmt = stmt?; - - struct Data { - version: String, - } - - let version_iter = stmt.query_map([], |row| { - Ok(Data { - version: row.get(0)?, - }) - }); - - println!("Process meta"); - - if version_iter.is_err() || version_iter.as_ref().ok().is_none() { - create_database(pool)?; - } else { - let version_iter = version_iter.ok().unwrap(); - - let mut recreate = true; - - for data in version_iter { - let version = data.unwrap().version; - println!("Found version {}", version); - - if !DATAVERSION.to_string().eq(&version) { - println!("Mismatched versions recreating database"); - recreate = true; - break; - } - - recreate = false; - } - - if recreate { - create_database(pool)?; - } - } - Ok(()) -} - -fn create_database(pool: DBPool) -> GResult { - let conn = pool.get()?; - - println!("Createing the database"); - - println!("Createing new meta table. With version {}", DATAVERSION); - println!("Drop old meta table"); - conn.execute("DROP TABLE IF EXISTS meta;", ())?; - // Create the database - println!("create new meta table"); - conn.execute( - "CREATE TABLE meta ( - id INTEGER PRIMARY KEY, - version TEXT, - configured Boolean - );", - (), - )?; - println!("insert data"); - conn.execute( - "INSERT INTO meta (version, configured) VALUES (?1, ?2);", - (&DATAVERSION, false), - )?; - - println!( - "Createing new configuration table. With version {}", - DATAVERSION - ); - println!("Drop configuration table"); - conn.execute("DROP TABLE IF EXISTS configuration", ())?; - println!("Create new configuration table"); - conn.execute( - "CREATE TABLE configuration ( - id INTEGER PRIMARY KEY, - ledcount INTEGER, - directionX INTEGER, - directionY INTEGER, - directionZ INTEGER, - tags VARCHAR(255) - );", - (), - )?; - - println!( - "Createing new Animation table. With version {}", - DATAVERSION - ); - println!("Drop Animation table and references"); - conn.execute("DROP TABLE IF EXISTS lightsetting", ())?; - conn.execute("DROP TABLE IF EXISTS keyframe", ())?; - conn.execute("DROP TABLE IF EXISTS animation", ())?; - println!("Create new animation table"); - conn.execute( - "CREATE TABLE animation ( - id INTEGER PRIMARY KEY, - priority INTEGER, - name VARCHAR(255), - repeat BOOLEAN - );", - (), - )?; - - println!( - "Createing new key_frame table. With version {}", - DATAVERSION - ); - println!("Drop key_frame table"); - println!("Create new key_frame table"); - conn.execute( - "CREATE TABLE keyframe ( - id INTEGER PRIMARY KEY, - i INTEGER, - duration INTEGER, - animation INTEGER, - FOREIGN KEY(animation) REFERENCES animation(id) ON DELETE CASCADE - );", - (), - )?; - - println!( - "Createing new LigthSetting table. With version {}", - DATAVERSION - ); - println!("Drop LigthSetting table"); - println!("Create new light_setting table"); - conn.execute( - "CREATE TABLE lightsetting ( - id INTEGER PRIMARY KEY, - start INTEGER, - end INTEGER, - tags VARCHAR(255), - r INTEGER, - b INTEGER, - g INTEGER, - keyframe INTEGER, - FOREIGN KEY(keyframe) REFERENCES keyframe(id) ON DELETE CASCADE - );", - (), - )?; - - Ok(()) -} #[rocket::main] async fn main() -> GResult { @@ -327,6 +224,9 @@ async fn main() -> GResult { let (stop_animation_sender, stop_animation_receiver): (Sender, Receiver) = mpsc::channel(); + let (messager_sender, messager_revicer): (Sender, Receiver) = + mpsc::channel(); + let pool_clone = conn_pool_arc.clone(); let ligths_controll = std::thread::spawn(move || { @@ -335,6 +235,7 @@ async fn main() -> GResult { action_receiver, start_animation_receiver, stop_animation_receiver, + messager_sender ); }); @@ -362,6 +263,7 @@ async fn main() -> GResult { .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(); diff --git a/src/render.rs b/src/render.rs index e8c9497..c97e0bd 100644 --- a/src/render.rs +++ b/src/render.rs @@ -91,6 +91,10 @@ impl Render { return Ok(render); } + pub fn get_active_animations(&mut self) -> Vec { + self.animations.iter().map(|animation| animation.name.clone()).collect() + } + pub fn load_config(&mut self) -> Result<(), Box> { println!("Load config"); // GPIO Pin 10 is SPI diff --git a/src/utils.rs b/src/utils.rs index ef736c9..912a376 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,5 +7,12 @@ pub struct ApiResponse { pub message: String } +#[derive(Deserialize, Serialize)] +#[serde(crate="rocket::serde")] +pub struct ApiResponseActiveList { + pub code: u32, + pub active_animations: Vec, +} + #[derive(Responder)] pub struct ApiResponder(String);