raspberry_web/
lib.rs

1#![forbid(unsafe_code)]
2// to avoid the warning from diesel macros
3#![allow(proc_macro_derive_resolution_fallback)]
4
5#[macro_use]
6extern crate diesel;
7#[macro_use]
8extern crate log;
9#[macro_use]
10extern crate serde_derive;
11
12pub mod app;
13pub mod cli;
14pub mod errors;
15pub mod handlers;
16pub mod models;
17pub mod rpi;
18pub mod schema;
19pub mod settings;
20pub mod setup;
21pub mod utilities;
22pub mod validation;
23
24use crate::app::AppState;
25use crate::cli::get_cli_args;
26use crate::handlers::DbExecutor;
27use crate::setup::setup_rpi_and_db;
28use crate::utilities::reset_table_gpio_state;
29use crate::validation::validate_setup;
30use actix::SyncArbiter;
31use actix_web::server;
32use diesel::{r2d2::ConnectionManager, SqliteConnection};
33use dotenv::dotenv;
34
35pub fn setup_and_run() {
36    // Get CLI args
37    let cli_args = get_cli_args();
38
39    // Get settings from configuration file
40    let config = settings::Settings::new(cli_args).expect("Could not read config file");
41    let database_url = &config.database.database_url;
42    let hostname = config.webserver.hostname;
43    let port = config.webserver.port;
44
45    // Read environment variables from .env - must come before env_logger::init()
46    dotenv().ok();
47
48    // Initialize logger
49    env_logger::init();
50
51    // Create database connection pool
52    let manager = ConnectionManager::<SqliteConnection>::new(database_url.to_string());
53    let pool = r2d2::Pool::builder()
54        .build(manager)
55        .expect("Failed to create r2d2 pool.");
56    let connection = pool.get().expect("Failed to acquire connection");
57
58    // Reset database
59    reset_table_gpio_state(&connection).expect("Unable to update table 'gpio_state'");
60
61    // Check consistency of parsed_variables
62    validate_setup(&config.gpioconfig).expect("Provided setup variables are inconsistent");
63
64    // Arc<Mutex<rppal::gpio::Gpio>> or ARM, Arc<Mutex<i32>> on other architectures
65    let gpio_arc_mutex = rpi::create_gpio_arc_mutex().expect("Could not acquire GPIO");
66
67    // If variables are consistent, setup Raspberry Pi and database
68    setup_rpi_and_db(&config.gpioconfig, &connection, gpio_arc_mutex.clone())
69        .expect("Error when setting up Raspberry Pi and database");
70
71    let sys = actix::System::new("raspberry-web");
72    // https://github.com/actix/actix-website/blob/master/content/docs/databases.md
73    // https://docs.rs/actix-web/0.6.3/actix_web/struct.State.html
74    let addr = SyncArbiter::start(3, move || DbExecutor(pool.clone()));
75
76    let ip_port = format!("{}:{}", hostname, port);
77    let _server = server::new(move || {
78        app::create_app(AppState {
79            db: addr.clone(),
80            gpio_arc_mutex: gpio_arc_mutex.clone(),
81        })
82    })
83    .bind(&ip_port)
84    .expect(&format!("Can not bind to {}", &ip_port))
85    .start();
86
87    let _sys = sys.run();
88}