2023-03-13 20:59:50 +00:00
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 < u32 > ,
end : Option < u32 > ,
tags : Option < String > ,
r : u8 ,
b : u8 ,
g : u8 ,
}
impl LigthSetting {
pub fn get_start ( & self ) -> Option < u32 > {
self . start
}
pub fn get_end ( & self ) -> Option < u32 > {
self . end
}
pub fn get_tags ( & self ) -> Option < String > {
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 < LigthSetting >
}
impl KeyFrame {
pub fn get_settings ( & self ) -> Vec < LigthSetting > {
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 < KeyFrame > ,
priority : Option < u32 > ,
name : String ,
repeat : bool ,
}
impl Animation {
pub fn get_frames ( & self ) -> Vec < KeyFrame > {
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= " <data> " ) ]
pub async fn animation ( data : Json < Animation > , db : & State < DBPool > ) -> 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 < Option < u32 > , Box < dyn Error > > {
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 < Option < u32 > , Box < dyn Error > > {
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 < Animation > , pool : & State < DBPool > ) -> Result < String , Box < dyn Error > > {
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/<name> " ) ]
pub async fn stop_animation ( name : & str , stop_sender : & State < ASender < String > > ) -> 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/<name> " ) ]
pub async fn start_animation ( name : & str , start_sender : & State < ASender < Animation > > , db : & State < DBPool > ) -> 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/<name> " ) ]
pub async fn clear ( name : & str , start_sender : & State < ASender < Animation > > , db : & State < DBPool > , action : & State < ASender < Action > > ) -> 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 < DBPool > ) -> Result < Option < Animation > , Box < dyn Error > > {
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
2023-03-15 23:27:37 +00:00
}
2023-03-13 20:59:50 +00:00
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/<name> " ) ]
2023-03-15 23:27:37 +00:00
pub async fn delete ( name : & str , db : & State < DBPool > ) -> String {
2023-03-13 20:59:50 +00:00
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 < DBPool > ) -> Result < ( ) , Box < dyn Error > > {
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 ( ( ) )
}