Andre Henriques
9ce96269df
All checks were successful
continuous-integration/drone/push Build is passing
371 lines
9.2 KiB
Rust
371 lines
9.2 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;
|
|
|
|
use animations::Animation;
|
|
use r2d2::PooledConnection;
|
|
use utils::ApiResponse;
|
|
|
|
use rocket::{serde::json::serde_json::json, State};
|
|
|
|
use r2d2_sqlite::SqliteConnectionManager;
|
|
|
|
//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>>>;
|
|
|
|
#[get("/")]
|
|
fn index() -> &'static str {
|
|
"Hello World"
|
|
}
|
|
|
|
pub enum Action {
|
|
Reload,
|
|
Stop,
|
|
Clear,
|
|
}
|
|
|
|
#[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()
|
|
}
|
|
|
|
fn ligth_controll(
|
|
pool: DBPool,
|
|
action: Receiver<Action>,
|
|
start_ani: Receiver<Animation>,
|
|
stop_ani: Receiver<String>,
|
|
) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
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 {
|
|
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 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,
|
|
);
|
|
});
|
|
|
|
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)))
|
|
.launch()
|
|
.await?;
|
|
ligths_controll.join().unwrap();
|
|
|
|
Ok(())
|
|
}
|