mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 06:47:56 +01:00
Better configuration stuff
This commit is contained in:
parent
ff981a768b
commit
c742fb0a5d
@ -24,10 +24,13 @@ capnp = "0.13"
|
|||||||
capnp-rpc = "0.13"
|
capnp-rpc = "0.13"
|
||||||
capnp-futures = "0.13"
|
capnp-futures = "0.13"
|
||||||
|
|
||||||
toml = "0.5"
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
flexbuffers = "0.1"
|
flexbuffers = "0.1"
|
||||||
|
|
||||||
|
glob = "0.3"
|
||||||
|
toml = "0.5"
|
||||||
|
config = { version = "0.10", default-features = false, features = ["toml"] }
|
||||||
|
|
||||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
|
|
||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
|
@ -15,7 +15,7 @@ use serde::{Serialize, Deserialize};
|
|||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
use lmdb::{Transaction, RwTransaction, Cursor};
|
use lmdb::{Transaction, RwTransaction, Cursor};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Settings;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
|
||||||
// FIXME: fabinfra/fabaccess/bffh#3
|
// FIXME: fabinfra/fabaccess/bffh#3
|
||||||
@ -196,11 +196,11 @@ impl PermissionsProvider {
|
|||||||
let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::<u64>());
|
let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::<u64>());
|
||||||
let roleID = u64::from_ne_bytes(kbytes.try_into().unwrap());
|
let roleID = u64::from_ne_bytes(kbytes.try_into().unwrap());
|
||||||
let role: Role = flexbuffers::from_slice(vbuf)?;
|
let role: Role = flexbuffers::from_slice(vbuf)?;
|
||||||
let filename = format!("{:x}.toml", roleID);
|
let filename = format!("{:x}.yml", roleID);
|
||||||
path.set_file_name(filename);
|
path.set_file_name(filename);
|
||||||
let mut fp = std::fs::File::create(&path)?;
|
let mut fp = std::fs::File::create(&path)?;
|
||||||
let toml = toml::to_vec(&role)?;
|
let out = toml::to_vec(&role)?;
|
||||||
fp.write_all(&toml)?;
|
fp.write_all(&out)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -213,11 +213,11 @@ impl PermissionsProvider {
|
|||||||
let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::<u64>());
|
let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::<u64>());
|
||||||
let permID = u64::from_ne_bytes(kbytes.try_into().unwrap());
|
let permID = u64::from_ne_bytes(kbytes.try_into().unwrap());
|
||||||
let perm: Perm = flexbuffers::from_slice(vbuf)?;
|
let perm: Perm = flexbuffers::from_slice(vbuf)?;
|
||||||
let filename = format!("{:x}.toml", permID);
|
let filename = format!("{:x}.yml", permID);
|
||||||
path.set_file_name(filename);
|
path.set_file_name(filename);
|
||||||
let mut fp = std::fs::File::create(&path)?;
|
let mut fp = std::fs::File::create(&path)?;
|
||||||
let toml = toml::to_vec(&perm)?;
|
let out = toml::to_vec(&perm)?;
|
||||||
fp.write_all(&toml)?;
|
fp.write_all(&out)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -230,11 +230,11 @@ impl PermissionsProvider {
|
|||||||
let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::<u64>());
|
let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::<u64>());
|
||||||
let userID = u64::from_ne_bytes(kbytes.try_into().unwrap());
|
let userID = u64::from_ne_bytes(kbytes.try_into().unwrap());
|
||||||
let user: User = flexbuffers::from_slice(vbuf)?;
|
let user: User = flexbuffers::from_slice(vbuf)?;
|
||||||
let filename = format!("{:x}.toml", userID);
|
let filename = format!("{:x}.yml", userID);
|
||||||
path.set_file_name(filename);
|
path.set_file_name(filename);
|
||||||
let mut fp = std::fs::File::create(&path)?;
|
let mut fp = std::fs::File::create(&path)?;
|
||||||
let toml = toml::to_vec(&user)?;
|
let out = toml::to_vec(&user)?;
|
||||||
fp.write_all(&toml)?;
|
fp.write_all(&out)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -408,7 +408,7 @@ impl PermissionsProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This line documents init
|
/// This line documents init
|
||||||
pub fn init(log: Logger, config: &Config, env: &lmdb::Environment) -> std::result::Result<PermissionsProvider, crate::error::Error> {
|
pub fn init(log: Logger, config: &Settings, env: &lmdb::Environment) -> std::result::Result<PermissionsProvider, crate::error::Error> {
|
||||||
let mut flags = lmdb::DatabaseFlags::empty();
|
let mut flags = lmdb::DatabaseFlags::empty();
|
||||||
flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true);
|
flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true);
|
||||||
let roledb = env.create_db(Some("role"), flags)?;
|
let roledb = env.create_db(Some("role"), flags)?;
|
||||||
|
@ -9,7 +9,7 @@ use rsasl::{SASL, Property, Session, ReturnCode};
|
|||||||
use rsasl::sys::{Gsasl, Gsasl_session};
|
use rsasl::sys::{Gsasl, Gsasl_session};
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::config::Config;
|
use crate::config::Settings;
|
||||||
|
|
||||||
pub mod auth_capnp {
|
pub mod auth_capnp {
|
||||||
include!(concat!(env!("OUT_DIR"), "/schema/auth_capnp.rs"));
|
include!(concat!(env!("OUT_DIR"), "/schema/auth_capnp.rs"));
|
||||||
@ -53,6 +53,6 @@ impl Auth {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init(log: Logger, config: Config) -> Result<Auth> {
|
pub async fn init(log: Logger, config: Settings) -> Result<Auth> {
|
||||||
Ok(Auth::new())
|
Ok(Auth::new())
|
||||||
}
|
}
|
||||||
|
@ -8,29 +8,29 @@ use crate::error::Result;
|
|||||||
|
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
|
||||||
pub fn read(path: &Path) -> Result<Config> {
|
use std::collections::HashMap;
|
||||||
let mut fp = File::open(path)?;
|
|
||||||
let mut contents = String::new();
|
|
||||||
fp.read_to_string(&mut contents)?;
|
|
||||||
|
|
||||||
let config = toml::from_str(&contents)?;
|
use config::Config;
|
||||||
Ok(config)
|
pub use config::ConfigError;
|
||||||
|
use glob::glob;
|
||||||
|
|
||||||
|
pub fn read(path: &Path) -> Result<Settings> {
|
||||||
|
let mut settings = Config::default();
|
||||||
|
settings
|
||||||
|
.merge(config::File::from(path)).unwrap();
|
||||||
|
|
||||||
|
Ok(settings.try_into()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Settings {
|
||||||
pub db: PathBuf,
|
pub listens: Box<[Listen]>,
|
||||||
pub machinedb: PathBuf,
|
pub shelly: Option<ShellyCfg>
|
||||||
pub passdb: PathBuf,
|
|
||||||
pub(crate) access: Access,
|
|
||||||
pub listen: Box<[Listen]>,
|
|
||||||
pub mqtt_url: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Access {
|
pub struct ShellyCfg {
|
||||||
pub(crate) model: PathBuf,
|
pub mqtt_url: String
|
||||||
pub(crate) policy: PathBuf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -39,25 +39,20 @@ pub struct Listen {
|
|||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Settings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Config {
|
Settings {
|
||||||
db: PathBuf::from_str("/tmp/bffh.db").unwrap(),
|
listens: Box::new([Listen {
|
||||||
machinedb: PathBuf::from_str("/tmp/machines.db").unwrap(),
|
|
||||||
access: Access {
|
|
||||||
model: PathBuf::from_str("/tmp/model.conf").unwrap(),
|
|
||||||
policy: PathBuf::from_str("/tmp/policy.csv").unwrap(),
|
|
||||||
},
|
|
||||||
passdb: PathBuf::from_str("/tmp/passwd.db").unwrap(),
|
|
||||||
listen: Box::new([Listen {
|
|
||||||
address: "127.0.0.1".to_string(),
|
address: "127.0.0.1".to_string(),
|
||||||
port: Some(DEFAULT_PORT)
|
port: Some(DEFAULT_PORT)
|
||||||
},
|
},
|
||||||
Listen {
|
Listen {
|
||||||
address: "::1".to_string(),
|
address: "::1".to_string(),
|
||||||
port: Some(DEFAULT_PORT)
|
port: Some(DEFAULT_PORT)
|
||||||
}]),
|
}]),
|
||||||
mqtt_url: "127.0.0.1:1883".to_string(),
|
shelly: Some(ShellyCfg {
|
||||||
|
mqtt_url: "127.0.0.1:1883".to_string()
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
src/error.rs
10
src/error.rs
@ -22,6 +22,7 @@ pub enum Error {
|
|||||||
FlexbuffersSer(flexbuffers::SerializationError),
|
FlexbuffersSer(flexbuffers::SerializationError),
|
||||||
FuturesSpawn(futures::SpawnError),
|
FuturesSpawn(futures::SpawnError),
|
||||||
MQTT(mqtt::Error),
|
MQTT(mqtt::Error),
|
||||||
|
Config(config::ConfigError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@ -60,6 +61,9 @@ impl fmt::Display for Error {
|
|||||||
Error::MQTT(e) => {
|
Error::MQTT(e) => {
|
||||||
write!(f, "Paho MQTT encountered an error: {}", e)
|
write!(f, "Paho MQTT encountered an error: {}", e)
|
||||||
},
|
},
|
||||||
|
Error::Config(e) => {
|
||||||
|
write!(f, "Failed to parse config: {}", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,4 +134,10 @@ impl From<mqtt::Error> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<config::ConfigError> for Error {
|
||||||
|
fn from(e: config::ConfigError) -> Error {
|
||||||
|
Error::Config(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) type Result<T> = std::result::Result<T, Error>;
|
pub(crate) type Result<T> = std::result::Result<T, Error>;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use slog::{Drain, Logger};
|
use slog::{Drain, Logger};
|
||||||
use slog_async;
|
use slog_async;
|
||||||
use slog_term::{TermDecorator, FullFormat};
|
use slog_term::{TermDecorator, FullFormat};
|
||||||
use crate::config::Config;
|
use crate::config::Settings;
|
||||||
|
|
||||||
pub fn init(_config: &Config) -> Logger {
|
pub fn init(_config: &Settings) -> Logger {
|
||||||
let decorator = TermDecorator::new().build();
|
let decorator = TermDecorator::new().build();
|
||||||
let drain = FullFormat::new(decorator).build().fuse();
|
let drain = FullFormat::new(decorator).build().fuse();
|
||||||
let drain = slog_async::Async::new(drain).build().fuse();
|
let drain = slog_async::Async::new(drain).build().fuse();
|
||||||
|
@ -5,13 +5,12 @@ use std::io::{Read, Write};
|
|||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use toml;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use smol::lock::RwLock;
|
use smol::lock::RwLock;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::config::Config;
|
use crate::config::Settings;
|
||||||
|
|
||||||
use capnp::Error;
|
use capnp::Error;
|
||||||
|
|
||||||
@ -161,23 +160,6 @@ impl Machine {
|
|||||||
|
|
||||||
pub type MachineDB = HashMap<Uuid, Machine>;
|
pub type MachineDB = HashMap<Uuid, Machine>;
|
||||||
|
|
||||||
pub async fn init(log: Logger, config: &Config) -> Result<MachinesProvider> {
|
pub async fn init(log: Logger, config: &Settings) -> Result<MachinesProvider> {
|
||||||
let mdb = if config.machinedb.is_file() {
|
unimplemented!()
|
||||||
let mut fp = File::open(&config.machinedb)?;
|
|
||||||
let mut content = String::new();
|
|
||||||
fp.read_to_string(&mut content)?;
|
|
||||||
let map = toml::from_str(&content)?;
|
|
||||||
map
|
|
||||||
} else {
|
|
||||||
HashMap::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(MachinesProvider::new(log, mdb))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save(config: &Config, mdb: &MachineDB) -> Result<()> {
|
|
||||||
let mut fp = File::create(&config.machinedb)?;
|
|
||||||
let toml = toml::to_string(mdb)?;
|
|
||||||
fp.write_all(&toml.as_bytes())?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ fn main() -> Result<(), Error> {
|
|||||||
// Check for the --print-default option first because we don't need to do anything else in that
|
// Check for the --print-default option first because we don't need to do anything else in that
|
||||||
// case.
|
// case.
|
||||||
if matches.is_present("print default") {
|
if matches.is_present("print default") {
|
||||||
let config = config::Config::default();
|
let config = config::Settings::default();
|
||||||
let encoded = toml::to_vec(&config)?;
|
let encoded = toml::to_vec(&config)?;
|
||||||
|
|
||||||
// Direct writing to fd 1 is faster but also prevents any print-formatting that could
|
// Direct writing to fd 1 is faster but also prevents any print-formatting that could
|
||||||
@ -177,7 +177,7 @@ fn main() -> Result<(), Error> {
|
|||||||
// Bind to each address in config.listen.
|
// Bind to each address in config.listen.
|
||||||
// This is a Stream over Futures so it will do absolutely nothing unless polled to completion
|
// This is a Stream over Futures so it will do absolutely nothing unless polled to completion
|
||||||
let listeners_s: futures::stream::Collect<_, Vec<TcpListener>>
|
let listeners_s: futures::stream::Collect<_, Vec<TcpListener>>
|
||||||
= stream::iter((&config).listen.iter())
|
= stream::iter((&config).listens.iter())
|
||||||
.map(|l| {
|
.map(|l| {
|
||||||
let addr = l.address.clone();
|
let addr = l.address.clone();
|
||||||
let port = l.port.unwrap_or(config::DEFAULT_PORT);
|
let port = l.port.unwrap_or(config::DEFAULT_PORT);
|
||||||
|
@ -12,12 +12,12 @@ mod shelly;
|
|||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use futures::task::LocalSpawn;
|
use futures::task::LocalSpawn;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Settings;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::registries::Registries;
|
use crate::registries::Registries;
|
||||||
|
|
||||||
// spawner is a type that allows 'tasks' to be spawned on it, running them to completion.
|
// spawner is a type that allows 'tasks' to be spawned on it, running them to completion.
|
||||||
pub fn init<S: LocalSpawn>(log: Logger, config: &Config, spawner: &S, registries: Registries) -> Result<()> {
|
pub fn init<S: LocalSpawn>(log: Logger, config: &Settings, spawner: &S, registries: Registries) -> Result<()> {
|
||||||
let f = Box::new(shelly::run(log.clone(), config.clone(), registries.clone()));
|
let f = Box::new(shelly::run(log.clone(), config.clone(), registries.clone()));
|
||||||
spawner.spawn_local_obj(f.into())?;
|
spawner.spawn_local_obj(f.into())?;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Settings;
|
||||||
use crate::registries::{Registries, Actuator, ActBox};
|
use crate::registries::{Registries, Actuator, ActBox};
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ use paho_mqtt as mqtt;
|
|||||||
// TODO: Late config parsing. Right now the config is validated at the very startup in its
|
// TODO: Late config parsing. Right now the config is validated at the very startup in its
|
||||||
// entirety. This works reasonably enough for this static modules here but if we do dynamic loading
|
// entirety. This works reasonably enough for this static modules here but if we do dynamic loading
|
||||||
// via dlopen(), lua API, python API etc it will not.
|
// via dlopen(), lua API, python API etc it will not.
|
||||||
pub async fn run(log: Logger, config: Config, registries: Registries) {
|
pub async fn run(log: Logger, config: Settings, registries: Registries) {
|
||||||
let shelly_r = Shelly::new(config).await;
|
let shelly_r = Shelly::new(config).await;
|
||||||
if let Err(e) = shelly_r {
|
if let Err(e) = shelly_r {
|
||||||
error!(log, "Shelly module errored: {}", e);
|
error!(log, "Shelly module errored: {}", e);
|
||||||
@ -36,8 +36,8 @@ struct Shelly {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Shelly {
|
impl Shelly {
|
||||||
pub async fn new(config: Config) -> Result<ActBox> {
|
pub async fn new(config: Settings) -> Result<ActBox> {
|
||||||
let client = mqtt::AsyncClient::new(config.mqtt_url)?;
|
let client = mqtt::AsyncClient::new(config.shelly.unwrap().mqtt_url)?;
|
||||||
|
|
||||||
client.connect(mqtt::ConnectOptions::new()).await?;
|
client.connect(mqtt::ConnectOptions::new()).await?;
|
||||||
|
|
||||||
@ -49,14 +49,14 @@ impl Shelly {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Actuator for Shelly {
|
impl Actuator for Shelly {
|
||||||
async fn power_on(&mut self, name: String) {
|
async fn power_on(&mut self, name: String) {
|
||||||
let topic = "";
|
let topic = format!("shellies/{}/relay/0/command", name);
|
||||||
let msg = mqtt::Message::new(topic, "1", 0);
|
let msg = mqtt::Message::new(topic, "on", 0);
|
||||||
self.client.publish(msg).map(|_| ()).await
|
self.client.publish(msg).map(|_| ()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn power_off(&mut self, name: String) {
|
async fn power_off(&mut self, name: String) {
|
||||||
let topic = "";
|
let topic = format!("shellies/{}/relay/0/command", name);
|
||||||
let msg = mqtt::Message::new(topic, "0", 0);
|
let msg = mqtt::Message::new(topic, "off", 0);
|
||||||
self.client.publish(msg).map(|_| ()).await
|
self.client.publish(msg).map(|_| ()).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user