mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-26 00:24:55 +01:00
Better initialization
This commit is contained in:
parent
02570fea6f
commit
5a42b34fe3
40
src/actor.rs
40
src/actor.rs
@ -11,11 +11,13 @@ use futures::channel::mpsc;
|
|||||||
use futures_signals::signal::{Signal, MutableSignalCloned, MutableSignal, Mutable};
|
use futures_signals::signal::{Signal, MutableSignalCloned, MutableSignal, Mutable};
|
||||||
|
|
||||||
use crate::db::machine::MachineState;
|
use crate::db::machine::MachineState;
|
||||||
use crate::config::Settings;
|
use crate::config::Config;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
|
||||||
use crate::network::ActorMap;
|
use crate::network::ActorMap;
|
||||||
|
|
||||||
|
use paho_mqtt::AsyncClient;
|
||||||
|
use slog::Logger;
|
||||||
|
|
||||||
pub trait Actuator {
|
pub trait Actuator {
|
||||||
fn apply(&mut self, state: MachineState) -> BoxFuture<'static, ()>;
|
fn apply(&mut self, state: MachineState) -> BoxFuture<'static, ()>;
|
||||||
}
|
}
|
||||||
@ -104,12 +106,34 @@ impl Actuator for Dummy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load() -> Result<(ActorMap, Vec<Actor>)> {
|
pub fn load(log: &Logger, client: &AsyncClient, config: &Config) -> Result<(ActorMap, Vec<Actor>)> {
|
||||||
let d = Box::new(Dummy);
|
|
||||||
let (tx, a) = Actor::wrap(d);
|
|
||||||
|
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
map.insert("Dummy".to_string(), tx);
|
|
||||||
|
|
||||||
Ok(( map, vec![a] ))
|
let actuators = config.actors.iter()
|
||||||
|
.map(|(k,v)| (k, load_single(log, client, k, &v.name, &v.params)))
|
||||||
|
.filter_map(|(k, n)| match n {
|
||||||
|
None => None,
|
||||||
|
Some(a) => Some((k, a))
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut v = Vec::new();
|
||||||
|
for (name, actuator) in actuators {
|
||||||
|
let (tx, a) = Actor::wrap(actuator);
|
||||||
|
map.insert(name.clone(), tx);
|
||||||
|
v.push(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ok(( map, v ))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_single(log: &Logger, client: &AsyncClient, name: &String, module_name: &String, params: &HashMap<String, String>) -> Option<Box<dyn Actuator + Sync + Send>> {
|
||||||
|
use crate::modules::*;
|
||||||
|
|
||||||
|
match module_name.as_ref() {
|
||||||
|
"Shelly" => {
|
||||||
|
Some(Box::new(Shelly::new(log, name.clone(), client.clone())))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,9 @@ use crate::machine::MachineDescription;
|
|||||||
use crate::db::machine::MachineIdentifier;
|
use crate::db::machine::MachineIdentifier;
|
||||||
|
|
||||||
pub fn read(path: &Path) -> Result<Config> {
|
pub fn read(path: &Path) -> Result<Config> {
|
||||||
serde_dhall::from_file(path).parse().map_err(Into::into)
|
serde_dhall::from_file(path)
|
||||||
|
.parse()
|
||||||
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated]
|
#[deprecated]
|
||||||
@ -29,8 +31,13 @@ pub struct Config {
|
|||||||
/// Machine descriptions to load
|
/// Machine descriptions to load
|
||||||
pub machines: HashMap<MachineIdentifier, MachineDescription>,
|
pub machines: HashMap<MachineIdentifier, MachineDescription>,
|
||||||
|
|
||||||
/// Modules to load and their configuration options
|
/// Actors to load and their configuration options
|
||||||
pub modules: HashMap<String, HashMap<String, String>>,
|
pub actors: HashMap<String, ModuleConfig>,
|
||||||
|
|
||||||
|
/// Initiators to load and their configuration options
|
||||||
|
pub initiators: HashMap<String, ModuleConfig>,
|
||||||
|
|
||||||
|
pub mqtt_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -39,13 +46,38 @@ pub struct Listen {
|
|||||||
pub port: Option<u16>,
|
pub port: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Settings {
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ModuleConfig {
|
||||||
|
pub name: String,
|
||||||
|
#[serde(skip_serializing_if = "HashMap::is_empty")]
|
||||||
|
pub params: HashMap<String, String>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let modules: HashMap::<String, HashMap<String, String>> = HashMap::new();
|
let mut actors: HashMap::<String, ModuleConfig> = HashMap::new();
|
||||||
|
let mut initiators: HashMap::<String, ModuleConfig> = HashMap::new();
|
||||||
|
|
||||||
|
actors.insert("Actor".to_string(), ModuleConfig {
|
||||||
|
name: "Shelly".to_string(),
|
||||||
|
params: HashMap::new(),
|
||||||
|
});
|
||||||
|
initiators.insert("Initiator".to_string(), ModuleConfig {
|
||||||
|
name: "TCP-Listen".to_string(),
|
||||||
|
params: HashMap::new(),
|
||||||
|
});
|
||||||
|
|
||||||
Config {
|
Config {
|
||||||
listens: Box::new([]),
|
listens: Box::new([
|
||||||
|
Listen {
|
||||||
|
address: "localhost".to_string(),
|
||||||
|
port: Some(DEFAULT_PORT),
|
||||||
|
}
|
||||||
|
]),
|
||||||
machines: HashMap::new(),
|
machines: HashMap::new(),
|
||||||
modules: modules,
|
actors: actors,
|
||||||
|
initiators: initiators,
|
||||||
|
mqtt_url: "tcp://localhost:1883".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
src/main.rs
20
src/main.rs
@ -46,6 +46,8 @@ use error::Error;
|
|||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
|
use paho_mqtt::AsyncClient;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
use clap::{crate_version, crate_description, crate_name};
|
use clap::{crate_version, crate_description, crate_name};
|
||||||
|
|
||||||
@ -81,14 +83,14 @@ fn main() {
|
|||||||
// 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::Settings::default();
|
let config = config::Config::default();
|
||||||
let encoded = toml::to_vec(&config).unwrap();
|
let encoded = serde_dhall::serialize(&config).to_string().unwrap();
|
||||||
|
|
||||||
// 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
|
||||||
// invalidate the generated TOML
|
// invalidate the generated TOML
|
||||||
let stdout = io::stdout();
|
let stdout = io::stdout();
|
||||||
let mut handle = stdout.lock();
|
let mut handle = stdout.lock();
|
||||||
handle.write_all(&encoded).unwrap();
|
handle.write_all(&encoded.as_bytes()).unwrap();
|
||||||
|
|
||||||
// Early return to exit.
|
// Early return to exit.
|
||||||
return;
|
return;
|
||||||
@ -123,7 +125,7 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
|
|||||||
// If no `config` option is given use a preset default.
|
// If no `config` option is given use a preset default.
|
||||||
let configpath = matches.value_of("config").unwrap_or("/etc/bffh/config.toml");
|
let configpath = matches.value_of("config").unwrap_or("/etc/bffh/config.toml");
|
||||||
let config = config::read(&PathBuf::from_str(configpath).unwrap())?;
|
let config = config::read(&PathBuf::from_str(configpath).unwrap())?;
|
||||||
|
debug!(log, "Loaded Config: {:?}", config);
|
||||||
|
|
||||||
if matches.is_present("dump") {
|
if matches.is_present("dump") {
|
||||||
error!(log, "Dumping is currently not implemented");
|
error!(log, "Dumping is currently not implemented");
|
||||||
@ -134,8 +136,13 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
|
|||||||
} else {
|
} else {
|
||||||
let ex = Executor::new();
|
let ex = Executor::new();
|
||||||
|
|
||||||
|
let mqtt = AsyncClient::new(config.mqtt_url.clone())?;
|
||||||
|
let tok = mqtt.connect(paho_mqtt::ConnectOptions::new());
|
||||||
|
|
||||||
|
smol::block_on(tok);
|
||||||
|
|
||||||
let machines = machine::load(&config)?;
|
let machines = machine::load(&config)?;
|
||||||
let (mut actor_map, actors) = actor::load()?;
|
let (mut actor_map, actors) = actor::load(&log, &mqtt, &config)?;
|
||||||
let (mut init_map, initiators) = initiator::load()?;
|
let (mut init_map, initiators) = initiator::load()?;
|
||||||
|
|
||||||
let network = network::Network::new(machines, actor_map, init_map);
|
let network = network::Network::new(machines, actor_map, init_map);
|
||||||
@ -143,9 +150,6 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
|
|||||||
|
|
||||||
// TODO HERE: restore connections between initiators, machines, actors
|
// TODO HERE: restore connections between initiators, machines, actors
|
||||||
|
|
||||||
// TODO HERE: Spawn all actors & inits
|
|
||||||
|
|
||||||
// Like so
|
|
||||||
let actor_tasks = actors.into_iter().map(|actor| ex.spawn(actor));
|
let actor_tasks = actors.into_iter().map(|actor| ex.spawn(actor));
|
||||||
let init_tasks = initiators.into_iter().map(|init| ex.spawn(init));
|
let init_tasks = initiators.into_iter().map(|init| ex.spawn(init));
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
mod shelly;
|
mod shelly;
|
||||||
|
pub use shelly::Shelly;
|
||||||
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use futures::task::Spawn;
|
use futures::task::Spawn;
|
||||||
|
@ -23,7 +23,7 @@ use paho_mqtt as mqtt;
|
|||||||
/// This actuator will toggle the shellie with the given `name`.
|
/// This actuator will toggle the shellie with the given `name`.
|
||||||
/// If you need to toggle shellies on multiple brokers you need multiple instanced of this
|
/// If you need to toggle shellies on multiple brokers you need multiple instanced of this
|
||||||
/// actuator with different clients.
|
/// actuator with different clients.
|
||||||
struct Shelly {
|
pub struct Shelly {
|
||||||
log: Logger,
|
log: Logger,
|
||||||
name: String,
|
name: String,
|
||||||
client: mqtt::AsyncClient,
|
client: mqtt::AsyncClient,
|
||||||
|
@ -39,6 +39,7 @@ impl fmt::Display for Error {
|
|||||||
/// Main signal network
|
/// Main signal network
|
||||||
///
|
///
|
||||||
/// Network as per FRP, not the one with packages and frames
|
/// Network as per FRP, not the one with packages and frames
|
||||||
|
// TODO De/Serialize established connection on startup/shutdown.
|
||||||
pub struct Network {
|
pub struct Network {
|
||||||
inits: InitMap,
|
inits: InitMap,
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user