raspberry-web 0.1.0

Control the GPIO pins on your Raspberry Pi with a simple web service. Currently supports output only.
Documentation
use crate::rpi::{set_gpio_level_rpi, GpioArcMutex};
use crate::utilities::{set_gpio_in_use_db, set_gpio_level_db, set_gpio_mode_db};
use diesel::SqliteConnection;
use std::collections::HashMap;
use std::env;
use std::env::VarError;
use std::io::{Error, ErrorKind};
use std::num::ParseIntError;

pub fn read_env_delimiter() -> String {
    // Get delimiter from .env - if not set, use
    let default_delimiter = ",".to_string();
    let env_delimiter = env::var("DELIMITER");
    let delimiter = match env_delimiter {
        Ok(val) => {
            debug!("Using '{}' as delimiter in .env", val);
            val
        }
        Err(_err) => {
            debug!("No delimiter set - defaulting to '{}'", default_delimiter);
            default_delimiter
        }
    };
    return delimiter;
}

// Given a string (read from env_var), read into vec
pub fn parse_string_to_vec(delimiter: &str, parse_str: &str) -> Result<Vec<i32>, ParseIntError> {
    let vec: Result<Vec<i32>, _> = parse_str
        .split(&delimiter)
        .map(|x| x.parse::<i32>())
        .collect();

    match vec {
        Ok(parsed) => {
            debug!("Parsed '{}' to {:?}", parse_str, parsed);
            Ok(parsed)
        }
        Err(err) => {
            warn!("Could not parse '{}' to Vec<i32>: {}", parse_str, err);
            Err(err)
        }
    }
}

// Read env_var into string, handle errors
pub fn read_env_to_str(var_to_read: &str) -> Result<String, VarError> {
    let env_var = env::var(var_to_read);

    match env_var {
        Ok(read_str) => {
            debug!("Read {}, got: {}", var_to_read, read_str);
            Ok(read_str)
        }
        Err(err) => {
            warn!("Could not read {}: {}", var_to_read, err);
            Err(err)
        }
    }
}

pub fn read_env_to_hashmap(env_keys: &Vec<&'static str>) -> HashMap<&'static str, Vec<i32>> {
    let delimiter = read_env_delimiter();
    let mut parsed_variables: HashMap<&'static str, Vec<i32>> = HashMap::new();

    for env_key in env_keys {
        let env_str = read_env_to_str(env_key);
        //parsed_variables.insert(env_key, None);

        if let Ok(env_var) = env_str {
            let env_vec = parse_string_to_vec(&delimiter, &env_var);

            if let Ok(parsed_vec) = env_vec {
                parsed_variables.insert(&env_key, parsed_vec);
            }
        }
    }
    return parsed_variables;
}

pub fn _validate_setup(_map: &HashMap<&'static str, Vec<i32>>) -> Result<(), VarError> {
    // Unimplemented
    Ok(())
}

pub fn commit_variables_to_db(
    map: &HashMap<&'static str, Vec<i32>>,
    conn: &SqliteConnection,
    gpio_arc_mutex: GpioArcMutex,
) -> Result<(), Error> {
    // Should be set to 1
    match map.get("GPIOS_IN_USE") {
        Some(vec) => {
            for idx in vec.iter() {
                let _ = set_gpio_in_use_db(*idx, 1, conn)
                    .map_err(|err| Error::new(ErrorKind::Other, err.to_string()))?;
            }
        }
        _ => debug!("GPIOS_IN_USE not set"),
    }

    // Should be set to OUTPUT
    match map.get("GPIOS_MODE_OUTPUT") {
        Some(vec) => {
            for idx in vec.iter() {
                let _ = set_gpio_mode_db(*idx, "output", conn)
                    .map_err(|err| Error::new(ErrorKind::Other, err.to_string()))?;
            }
        }
        _ => debug!("GPIOS_MODE_OUTPUT not set"),
    }

    // Should be set to INPUT
    match map.get("GPIOS_MODE_INPUT") {
        Some(vec) => {
            for idx in vec.iter() {
                let _ = set_gpio_mode_db(*idx, "input", conn)
                    .map_err(|err| Error::new(ErrorKind::Other, err.to_string()))?;
            }
        }
        _ => debug!("GPIOS_MODE_INPUT not set"),
    }

    // Should be set to LOW
    match map.get("GPIOS_LEVEL_LOW") {
        Some(vec) => {
            for idx in vec.iter() {
                let _ = set_gpio_level_rpi(*idx, "low", gpio_arc_mutex.clone())?;
                let _ = set_gpio_level_db(*idx, "low", conn)
                    .map_err(|err| Error::new(ErrorKind::Other, err.to_string()))?;
            }
        }
        _ => debug!("GPIOS_LEVEL_LOW not set"),
    }

    // Should be set to HIGH
    match map.get("GPIOS_LEVEL_HIGH") {
        Some(vec) => {
            for idx in vec.iter() {
                let _ = set_gpio_level_rpi(*idx, "high", gpio_arc_mutex.clone())?;
                let _ = set_gpio_level_db(*idx, "high", conn)
                    .map_err(|err| Error::new(ErrorKind::Other, err.to_string()))?;
            }
        }
        _ => debug!("GPIOS_LEVEL_HIGH not set"),
    }
    Ok(())
}