use std::{u8, error::Error}; use rocket::{serde::{json::{Json, serde_json::json}, Deserialize, Serialize}, State}; use crate::{utils::ApiResponse, DBConn, ASender, Action}; use crate::DBPool; #[derive(Debug, Deserialize, Serialize, Clone)] #[serde(crate = "rocket::serde")] #[serde(rename_all = "camelCase")] pub struct LigthSetting { start: Option, end: Option, tags: Option, r: u8, b: u8, g: u8, } impl LigthSetting { pub fn get_start(&self) -> Option{ self.start } pub fn get_end(&self) -> Option{ self.end } pub fn get_tags(&self) -> Option{ if self.tags.as_ref().is_some() { return Some(self.tags.as_ref().unwrap().to_string()); } None } pub fn get_r(&self) -> u8 { self.r } pub fn get_b(&self) -> u8 { self.b } pub fn get_g(&self) -> u8 { self.g } } #[derive(Debug, Deserialize, Serialize, Clone)] #[serde(crate = "rocket::serde")] #[serde(rename_all = "camelCase")] pub struct KeyFrame { duration: u32, settings: Vec } impl KeyFrame { pub fn get_settings(&self) -> Vec { self.settings.clone() } pub fn get_duration(&self) -> u32 { self.duration } } #[derive(Debug, Deserialize, Serialize, Clone)] #[serde(crate = "rocket::serde")] #[serde(rename_all = "camelCase")] pub struct Animation { key_frames: Vec, priority: Option, name: String, repeat: bool, } impl Animation { pub fn get_frames(&self) -> Vec { self.key_frames.clone() } pub fn get_name(&self) -> String { self.name.to_string() } pub fn get_priority(&self) -> u32 { if self.priority.is_none() { 0 } else {self.priority.unwrap()} } pub fn get_repeat(&self) -> bool { self.repeat } } #[post("/animation", data= "")] pub async fn animation(data: Json, db: &State) -> String { if data.key_frames.is_empty() { return json!(ApiResponse {code: 400, message: "KeyFrame are nessesary".to_string()}).to_string(); } if data.name.is_empty() { return json!(ApiResponse {code: 400, message: "Name must not be empty".to_string()}).to_string(); } for key_frame in data.key_frames.iter() { if key_frame.settings.is_empty() { return json!(ApiResponse {code: 400, message: "keyFrames.settings can not be empty".to_string()}).to_string(); } if key_frame.duration == 0 { return json!(ApiResponse {code: 400, message: "keyFrames.duration can not be 0".to_string()}).to_string(); } for setting in key_frame.settings.iter() { if setting.tags.is_none() && (setting.start.is_none() || setting.end.is_none()) { return json!(ApiResponse {code: 400, message: "Either tags or start end pair is needed".to_string()}).to_string(); } if !(setting.start.is_none() && setting.end.is_none()) && (setting.start.is_none() || setting.end.is_none()) { return json!(ApiResponse {code: 400, message: "Both start and end need to be filled".to_string()}).to_string(); } } } let db_status = add_animation_to_db(data, db); if db_status.is_err() || db_status.as_ref().ok().is_none() { return json!(ApiResponse {code: 500, message: format!("Error setting the animation. Err: {:?}", db_status.err()).to_string()}).to_string(); } let db_status = db_status.ok().unwrap(); if !db_status.is_empty() { return db_status; } json!(ApiResponse {code: 200, message: "Configuration was successful".to_string()}).to_string() } fn get_animation_from_name(conn: &DBConn, name: String) -> Result, Box> { let mut stmt = conn.prepare("SELECT id FROM animation WHERE name=?1")?; let next = stmt.query_map([name], |row| { row.get(0) })?.next(); if next.is_none() { return Ok(None); } Ok(next.unwrap()?) } fn get_keyframe_from_index(conn: &DBConn, animation: u32, index: u32) -> Result, Box> { let mut stmt = conn.prepare("SELECT id FROM keyframe WHERE animation=?1 AND i=?2")?; let next = stmt.query_map([animation, index], |row| { row.get(0) })?.next(); if next.is_none() { return Ok(None); } Ok(next.unwrap()?) } fn add_animation_to_db(data: Json, pool: &State) -> Result>{ let priority = if data.priority.is_some() { data.priority.unwrap() } else { 0 }; let conn = pool.get()?; println!("g: {}", data.name); let name = get_animation_from_name(&conn, data.name.to_string())?; println!("t: {:?}", name); if name.is_some() { return Ok(json!(ApiResponse {code: 500, message: "Animation with that name is already exists.".to_string()}).to_string()); } conn.execute("INSERT INTO animation (priority, name, repeat) VALUES (?1, ?2, ?3);", (priority, data.name.to_string(), data.repeat ))?; let name = get_animation_from_name(&conn, data.name.to_string())?; if name.is_none() { return Ok(json!(ApiResponse {code: 500, message: "Failed to create animation.".to_string()}).to_string()); } let animation_id = name.unwrap(); let mut i = 0; for key_frame in data.key_frames.clone() { conn.execute("INSERT INTO keyframe (duration, animation, i) VALUES (?1, ?2, ?3);", (key_frame.duration, animation_id, i))?; let keyframe = get_keyframe_from_index(&conn, animation_id, i)?; if keyframe.is_none() { return Ok(json!(ApiResponse {code: 500, message: "Failed to create animation.".to_string()}).to_string()); } let keyframe = keyframe.unwrap(); for setting in key_frame.settings { conn.execute("INSERT INTO lightsetting (start, end, tags, r, b, g, keyframe) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7);", (setting.start, setting.end, setting.tags, setting.r, setting.b, setting.g, keyframe))?; } i += 1; } Ok("".to_string()) } /** * * Stop animations * */ #[get("/stop/")] pub async fn stop_animation(name: &str, stop_sender: &State>) -> String { let r = stop_sender.lock().unwrap().send(name.to_string()); if r.is_err() || r.ok().is_none() { return json!(ApiResponse {code: 500, message: "Something went wrong".to_string()}).to_string() } json!(ApiResponse {code: 200, message: "Configuration was successful".to_string()}).to_string() } /** * * Start animations * */ #[get("/start/")] pub async fn start_animation(name: &str, start_sender: &State>, db: &State) -> String { let animation = get_animation(name, db); if animation.is_err() || animation.as_ref().ok().is_none() { return json!(ApiResponse {code: 500, message: format!("Probelms with the db: {:?}", animation.err()).to_string()}).to_string() } let animation = animation.ok().unwrap(); if animation.is_none() { return json!(ApiResponse {code: 404, message: "Animation not found".to_string()}).to_string() } let animation = animation.unwrap(); let r = start_sender.lock().unwrap().send(animation); if r.is_err() || r.as_ref().ok().is_none() { return json!(ApiResponse {code: 500, message: "Probelms with the db".to_string()}).to_string() } json!(ApiResponse {code: 200, message: "Started animation".to_string()}).to_string() } /** * * Clear animations * */ #[get("/clear/")] pub async fn clear(name: &str, start_sender: &State>, db: &State, action: &State>) -> String { let r = action.lock().unwrap().send(Action::Clear); if r.is_err() || r.ok().is_none() { return json!(ApiResponse {code: 500, message: "Something went wrong".to_string()}).to_string() } let animation = get_animation(name, db); if animation.is_err() || animation.as_ref().ok().is_none() { return json!(ApiResponse {code: 500, message: format!("Probelms with the db: {:?}", animation.err()).to_string()}).to_string() } let animation = animation.ok().unwrap(); if animation.is_none() { return json!(ApiResponse {code: 404, message: "Animation not found".to_string()}).to_string() } let animation = animation.unwrap(); let r = start_sender.lock().unwrap().send(animation); if r.is_err() || r.as_ref().ok().is_none() { return json!(ApiResponse {code: 500, message: "Probelms with the db".to_string()}).to_string() } json!(ApiResponse {code: 200, message: "Started animation".to_string()}).to_string() } pub fn get_animation(name: &str, db: &State) -> Result, Box> { let conn = db.get()?; let mut stmt = conn.prepare("SELECT id, priority, name, repeat FROM animation WHERE name=?1;")?; struct AnimationId { animation: Animation, id: u8 } let next = stmt.query_map([name], |row| { Ok(AnimationId { animation: Animation { key_frames: Vec::new(), priority: Some(row.get(1)?), name: row.get(2)?, repeat: row.get(3)? }, id: row.get(0)? }) })?.next(); if next.is_none() { return Ok(None); } let mut animation = next.unwrap()?; struct KeyFrameId { keyframe: KeyFrame, id: u8, } let mut stmt = conn.prepare("SELECT id, duration from keyframe where animation=?1 order by i asc")?; let mut map = stmt.query_map([animation.id], |row| { Ok(KeyFrameId { id: row.get(0)?, keyframe: KeyFrame { duration: row.get(1)?, settings: Vec::new() } }) })?; while let Some(key_frame_id) = map.next() { let mut key_frame_id = key_frame_id?; let mut stmt = conn.prepare("SELECT start, end, tags, r, b, g from lightsetting where keyframe=?1")?; let mut light_setting_map = stmt.query_map([key_frame_id.id], |row| { Ok(LigthSetting { start: row.get(0)?, end: row.get(1)?, tags: row.get(2)?, r: row.get(3)?, b: row.get(4)?, g: row.get(5)? }) })?; while let Some(light_setting) = light_setting_map.next() { key_frame_id.keyframe.settings.push(light_setting?); } animation.animation.key_frames.push(key_frame_id.keyframe); } Ok(Some(animation.animation)) } /** * * Delete animations * */ #[get("/delete/")] pub async fn delete(name: &str, db: &State) -> String { let animation = remove_animation(name, db); if animation.is_err() || animation.as_ref().ok().is_none() { return json!(ApiResponse {code: 500, message: format!("Probelms with the db: {:?}", animation.err()).to_string()}).to_string() } json!(ApiResponse {code: 200, message: "Deleted animation".to_string()}).to_string() } pub fn remove_animation(name: &str, db: &State) -> Result<(), Box> { let conn = db.get()?; conn.execute("delete from lightsetting where id in (select l.id from lightsetting as l left join keyframe as k on l.keyframe = k.id left join animation as a on k.animation = a.id where a.name=?1);", [name])?; conn.execute("delete from keyframe where id in (select k.id from keyframe as k left join animation as a on k.animation = a.id where a.name=?1);", [name])?; conn.execute("delete from animation where name=?1;", [name])?; Ok(()) }