mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 14:57:56 +01:00
Make work
This commit is contained in:
parent
143416a308
commit
bd635d97ac
@ -1,7 +1,13 @@
|
|||||||
-- { actor_connections = [] : List { _1 : Text, _2 : Text }
|
-- { actor_connections = [] : List { _1 : Text, _2 : Text }
|
||||||
{ actor_connections = [{ _1 = "Testmachine", _2 = "Actor" }]
|
{ actor_connections =
|
||||||
|
[ { _1 = "Testmachine", _2 = "Actor" }
|
||||||
|
, { _1 = "Another", _2 = "Actor2" }
|
||||||
|
, { _1 = "Yetmore", _2 = "Actor3" }
|
||||||
|
]
|
||||||
, actors =
|
, actors =
|
||||||
{ Actor = { module = "Shelly", params = {=} }
|
{ Actor = { module = "Dummy", params = {=} }
|
||||||
|
, Actor2 = { module = "Dummy", params = {=} }
|
||||||
|
, Actor3 = { module = "Dummy", params = {=} }
|
||||||
}
|
}
|
||||||
, init_connections = [] : List { _1 : Text, _2 : Text }
|
, init_connections = [] : List { _1 : Text, _2 : Text }
|
||||||
--, init_connections = [{ _1 = "Initiator", _2 = "Testmachine" }]
|
--, init_connections = [{ _1 = "Initiator", _2 = "Testmachine" }]
|
||||||
@ -11,6 +17,7 @@
|
|||||||
, listens =
|
, listens =
|
||||||
[ { address = "127.0.0.1", port = Some 59661 }
|
[ { address = "127.0.0.1", port = Some 59661 }
|
||||||
, { address = "::1", port = Some 59661 }
|
, { address = "::1", port = Some 59661 }
|
||||||
|
, { address = "192.168.0.114", port = Some 59661 }
|
||||||
]
|
]
|
||||||
, machines =
|
, machines =
|
||||||
{ Testmachine =
|
{ Testmachine =
|
||||||
@ -38,12 +45,21 @@
|
|||||||
, write = "lab.test.write"
|
, write = "lab.test.write"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, mqtt_url = "tcp://localhost:1883"
|
, mqtt_url = ""
|
||||||
, db_path = "/tmp/bffh"
|
, db_path = "/tmp/bffh"
|
||||||
, roles =
|
, roles =
|
||||||
{ Testrole =
|
{ testrole =
|
||||||
{ parents = [] : List Text
|
{ permissions = [ "lab.test.*" ] }
|
||||||
, permissions = [] : List Text
|
, somerole =
|
||||||
|
{ parents = ["testparent"]
|
||||||
|
, permissions = [ "lab.some.admin" ]
|
||||||
|
}
|
||||||
|
, testparent =
|
||||||
|
{ permissions =
|
||||||
|
[ "lab.some.write"
|
||||||
|
, "lab.some.read"
|
||||||
|
, "lab.some.disclose"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
[Testuser]
|
[Testuser]
|
||||||
# Define them in roles.toml as well
|
# Define them in roles.toml as well
|
||||||
roles = ["somerole/lmdb", "testrole/lmdb"]
|
roles = ["somerole/internal", "testrole/internal"]
|
||||||
|
|
||||||
# If two or more users want to use the same machine at once the higher prio
|
# If two or more users want to use the same machine at once the higher prio
|
||||||
# wins
|
# wins
|
||||||
priority = 0
|
priority = 0
|
||||||
|
|
||||||
|
passwd = "secret"
|
||||||
|
|
||||||
# You can add whatever random data you want.
|
# You can add whatever random data you want.
|
||||||
# It will get stored in the `kv` field in UserData.
|
# It will get stored in the `kv` field in UserData.
|
||||||
noot = "noot!"
|
noot = "noot!"
|
||||||
|
13
src/actor.rs
13
src/actor.rs
@ -126,11 +126,11 @@ impl Actuator for Dummy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(log: &Logger, client: &AsyncClient, config: &Config) -> Result<(ActorMap, Vec<Actor>)> {
|
pub fn load(log: &Logger, config: &Config) -> Result<(ActorMap, Vec<Actor>)> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
let actuators = config.actors.iter()
|
let actuators = config.actors.iter()
|
||||||
.map(|(k,v)| (k, load_single(log, client, k, &v.module, &v.params)))
|
.map(|(k,v)| (k, load_single(log, k, &v.module, &v.params)))
|
||||||
.filter_map(|(k, n)| match n {
|
.filter_map(|(k, n)| match n {
|
||||||
None => None,
|
None => None,
|
||||||
Some(a) => Some((k, a))
|
Some(a) => Some((k, a))
|
||||||
@ -149,7 +149,6 @@ pub fn load(log: &Logger, client: &AsyncClient, config: &Config) -> Result<(Acto
|
|||||||
|
|
||||||
fn load_single(
|
fn load_single(
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
client: &AsyncClient,
|
|
||||||
name: &String,
|
name: &String,
|
||||||
module_name: &String,
|
module_name: &String,
|
||||||
params: &HashMap<String, String>
|
params: &HashMap<String, String>
|
||||||
@ -157,14 +156,8 @@ fn load_single(
|
|||||||
{
|
{
|
||||||
use crate::modules::*;
|
use crate::modules::*;
|
||||||
|
|
||||||
|
info!(log, "Loading actor \"{}\" with module {} and params {:?}", name, module_name, params);
|
||||||
match module_name.as_ref() {
|
match module_name.as_ref() {
|
||||||
"Shelly" => {
|
|
||||||
if !params.is_empty() {
|
|
||||||
warn!(log, "\"{}\" module expects no parameters. Configured as \"{}\".",
|
|
||||||
module_name, name);
|
|
||||||
}
|
|
||||||
Some(Box::new(Shelly::new(log, name.clone(), client.clone())))
|
|
||||||
},
|
|
||||||
"Dummy" => {
|
"Dummy" => {
|
||||||
Some(Box::new(Dummy::new(log)))
|
Some(Box::new(Dummy::new(log)))
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ use crate::db::user::{Internal as UserDB, UserId, User};
|
|||||||
use crate::db::access::AccessControl as AccessDB;
|
use crate::db::access::AccessControl as AccessDB;
|
||||||
|
|
||||||
pub struct AppData {
|
pub struct AppData {
|
||||||
passdb: Arc<PassDB>,
|
|
||||||
userdb: Arc<UserDB>,
|
userdb: Arc<UserDB>,
|
||||||
}
|
}
|
||||||
pub struct SessionData {
|
pub struct SessionData {
|
||||||
@ -93,7 +92,7 @@ impl Auth {
|
|||||||
pub fn new(log: Logger, dbs: Databases, session: Rc<RefCell<Option<Session>>>) -> Self {
|
pub fn new(log: Logger, dbs: Databases, session: Rc<RefCell<Option<Session>>>) -> Self {
|
||||||
let mut ctx = SASL::new().unwrap();
|
let mut ctx = SASL::new().unwrap();
|
||||||
|
|
||||||
let appdata = Box::new(AppData { passdb: dbs.passdb.clone(), userdb: dbs.userdb.clone() });
|
let appdata = Box::new(AppData { userdb: dbs.userdb.clone() });
|
||||||
|
|
||||||
ctx.store(appdata);
|
ctx.store(appdata);
|
||||||
ctx.install_callback::<CB>();
|
ctx.install_callback::<CB>();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use capnp::capability::Promise;
|
use capnp::capability::Promise;
|
||||||
use capnp::Error;
|
use capnp::Error;
|
||||||
@ -102,23 +103,33 @@ impl use_::Server for Machine {
|
|||||||
let userid = self.userid.clone();
|
let userid = self.userid.clone();
|
||||||
let f = async move {
|
let f = async move {
|
||||||
let mut guard = machine.lock().await;
|
let mut guard = machine.lock().await;
|
||||||
match guard.read_state().lock_ref().state {
|
let mut ok = false;
|
||||||
Status::Free => {
|
{
|
||||||
guard.do_state_change(MachineState::used(Some(userid)));
|
match { guard.read_state().lock_ref().state.clone() } {
|
||||||
},
|
Status::Free => {
|
||||||
Status::Reserved(ref whom) => {
|
ok = true;
|
||||||
// If it's reserved for us or we're allowed to take over
|
},
|
||||||
if &userid == whom {
|
Status::Reserved(ref whom) => {
|
||||||
guard.do_state_change(MachineState::used(Some(userid)));
|
// If it's reserved for us or we're allowed to take over
|
||||||
}
|
if &userid == whom {
|
||||||
},
|
ok = true;
|
||||||
_ => { }
|
}
|
||||||
|
},
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
guard.do_state_change(MachineState::used(Some(userid)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
Promise::from_future(f)
|
let g = smol::future::race(f, smol::Timer::after(Duration::from_secs(4))
|
||||||
|
.map(|_| Err(capnp::Error::failed("Waiting for machine lock timed out!".to_string()))));
|
||||||
|
|
||||||
|
Promise::from_future(g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,13 +143,20 @@ impl in_use::Server for Machine {
|
|||||||
let userid = self.userid.clone();
|
let userid = self.userid.clone();
|
||||||
let f = async move {
|
let f = async move {
|
||||||
let mut guard = machine.lock().await;
|
let mut guard = machine.lock().await;
|
||||||
match guard.read_state().lock_ref().state {
|
let mut ok = false;
|
||||||
Status::InUse(ref whom) => {
|
{
|
||||||
if &Some(userid) == whom {
|
match { guard.read_state().lock_ref().state.clone() } {
|
||||||
guard.reset_state()
|
Status::InUse(ref whom) => {
|
||||||
}
|
if &Some(userid) == whom {
|
||||||
},
|
ok = true;
|
||||||
_ => {}
|
}
|
||||||
|
},
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
guard.reset_state()
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -152,7 +152,6 @@ impl machines::Server for Machines {
|
|||||||
let machineapi = Machine::new(user.clone(), perms, machine.clone());
|
let machineapi = Machine::new(user.clone(), perms, machine.clone());
|
||||||
if perms.write {
|
if perms.write {
|
||||||
builder.set_use(capnp_rpc::new_client(machineapi.clone()));
|
builder.set_use(capnp_rpc::new_client(machineapi.clone()));
|
||||||
builder.set_inuse(capnp_rpc::new_client(machineapi.clone()));
|
|
||||||
}
|
}
|
||||||
if perms.manage {
|
if perms.manage {
|
||||||
builder.set_transfer(capnp_rpc::new_client(machineapi.clone()));
|
builder.set_transfer(capnp_rpc::new_client(machineapi.clone()));
|
||||||
@ -163,17 +162,25 @@ impl machines::Server for Machines {
|
|||||||
builder.set_admin(capnp_rpc::new_client(machineapi.clone()));
|
builder.set_admin(capnp_rpc::new_client(machineapi.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.set_info(capnp_rpc::new_client(machineapi));
|
|
||||||
|
|
||||||
let s = match machine.get_status().await {
|
let s = match machine.get_status().await {
|
||||||
Status::Free => MachineState::Free,
|
Status::Free => MachineState::Free,
|
||||||
Status::Disabled => MachineState::Disabled,
|
Status::Disabled => MachineState::Disabled,
|
||||||
Status::Blocked(_) => MachineState::Blocked,
|
Status::Blocked(_) => MachineState::Blocked,
|
||||||
Status::InUse(_) => MachineState::InUse,
|
Status::InUse(u) => {
|
||||||
|
if let Some(owner) = u.as_ref() {
|
||||||
|
if owner == user {
|
||||||
|
builder.set_inuse(capnp_rpc::new_client(machineapi.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MachineState::InUse
|
||||||
|
},
|
||||||
Status::Reserved(_) => MachineState::Reserved,
|
Status::Reserved(_) => MachineState::Reserved,
|
||||||
Status::ToCheck(_) => MachineState::ToCheck,
|
Status::ToCheck(_) => MachineState::ToCheck,
|
||||||
};
|
};
|
||||||
builder.set_state(s);
|
builder.set_state(s);
|
||||||
|
|
||||||
|
builder.set_info(capnp_rpc::new_client(machineapi));
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -44,8 +44,10 @@ pub struct Config {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct RoleConfig {
|
pub struct RoleConfig {
|
||||||
parents: Vec<String>,
|
#[serde(default = "Vec::new")]
|
||||||
permissions: Vec<PermRule>,
|
pub parents: Vec<String>,
|
||||||
|
#[serde(default = "Vec::new")]
|
||||||
|
pub permissions: Vec<PermRule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
@ -28,7 +28,6 @@ pub mod machine;
|
|||||||
pub struct Databases {
|
pub struct Databases {
|
||||||
pub access: Arc<access::AccessControl>,
|
pub access: Arc<access::AccessControl>,
|
||||||
pub machine: Arc<machine::internal::Internal>,
|
pub machine: Arc<machine::internal::Internal>,
|
||||||
pub passdb: Arc<pass::PassDB>,
|
|
||||||
pub userdb: Arc<user::Internal>,
|
pub userdb: Arc<user::Internal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,13 +52,10 @@ impl Databases {
|
|||||||
let permdb = access::init(log.new(o!("system" => "permissions")), &config, env.clone())?;
|
let permdb = access::init(log.new(o!("system" => "permissions")), &config, env.clone())?;
|
||||||
let ac = access::AccessControl::new(permdb);
|
let ac = access::AccessControl::new(permdb);
|
||||||
|
|
||||||
let passdb = pass::PassDB::init(log.new(o!("system" => "passwords")), env.clone()).unwrap();
|
|
||||||
|
|
||||||
let userdb = user::init(log.new(o!("system" => "users")), &config, env.clone())?;
|
let userdb = user::init(log.new(o!("system" => "users")), &config, env.clone())?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
access: Arc::new(ac),
|
access: Arc::new(ac),
|
||||||
passdb: Arc::new(passdb),
|
|
||||||
machine: Arc::new(mdb),
|
machine: Arc::new(mdb),
|
||||||
userdb: Arc::new(userdb),
|
userdb: Arc::new(userdb),
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
//! Access control logic
|
//! Access control logic
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use slog::Logger;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@ -15,11 +18,23 @@ use crate::error::Result;
|
|||||||
|
|
||||||
pub mod internal;
|
pub mod internal;
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
use crate::db::user::UserData;
|
use crate::db::user::UserData;
|
||||||
pub use internal::{init, Internal};
|
pub use internal::Internal;
|
||||||
|
|
||||||
pub struct AccessControl {
|
pub struct AccessControl {
|
||||||
pub internal: Internal,
|
internal: HashMap<RoleIdentifier, Role>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(_log: Logger, config: &Config, _env: Arc<lmdb::Environment>)
|
||||||
|
-> std::result::Result<HashMap<RoleIdentifier, Role>, crate::error::Error>
|
||||||
|
{
|
||||||
|
Ok(config.roles.iter().map(|(name, cfg)| {
|
||||||
|
let id = RoleIdentifier::new(name, "internal");
|
||||||
|
let parents = cfg.parents.iter().map(|n| RoleIdentifier::new(n, "internal")).collect();
|
||||||
|
let role = Role::new(parents, cfg.permissions.clone());
|
||||||
|
(id, role)
|
||||||
|
}).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ADMINPERM: &'static str = "bffh.admin";
|
pub const ADMINPERM: &'static str = "bffh.admin";
|
||||||
@ -28,7 +43,7 @@ pub fn admin_perm() -> &'static Permission {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AccessControl {
|
impl AccessControl {
|
||||||
pub fn new(internal: Internal) -> Self {
|
pub fn new(internal: HashMap<RoleIdentifier, Role>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
internal,
|
internal,
|
||||||
}
|
}
|
||||||
@ -39,7 +54,7 @@ impl AccessControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_roles(&self) -> Result<Vec<(RoleIdentifier, Role)>> {
|
pub fn dump_roles(&self) -> Result<Vec<(RoleIdentifier, Role)>> {
|
||||||
self.internal.dump_roles()
|
Ok(self.internal.iter().map(|(k,v)| (k.clone(), v.clone())).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,38 +71,6 @@ pub trait RoleDB {
|
|||||||
|
|
||||||
fn get_role(&self, role_id: &RoleIdentifier) -> Result<Option<Role>>;
|
fn get_role(&self, role_id: &RoleIdentifier) -> Result<Option<Role>>;
|
||||||
|
|
||||||
/// Check if a given user has the given permission
|
|
||||||
///
|
|
||||||
/// Default implementation which adapter may overwrite with more efficient specialized
|
|
||||||
/// implementations.
|
|
||||||
fn check(&self, user: &UserData, perm: &Permission) -> Result<bool> {
|
|
||||||
self.check_roles(&user.roles, perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if a given permission is granted by any of the given roles or their respective
|
|
||||||
/// parents
|
|
||||||
///
|
|
||||||
/// A Default implementation exists which adapter may overwrite with more efficient specialized
|
|
||||||
/// implementations.
|
|
||||||
fn check_roles(&self, roles: &[RoleIdentifier], perm: &Permission) -> Result<bool> {
|
|
||||||
// Tally all roles. Makes dependent roles easier
|
|
||||||
let mut roleset = HashMap::new();
|
|
||||||
for role_id in roles {
|
|
||||||
self.tally_role(&mut roleset, role_id)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iter all unique role->permissions we've found and early return on match.
|
|
||||||
for (_roleid, role) in roleset.iter() {
|
|
||||||
for perm_rule in role.permissions.iter() {
|
|
||||||
if perm_rule.match_perm(&perm) {
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tally a role dependency tree into a set
|
/// Tally a role dependency tree into a set
|
||||||
///
|
///
|
||||||
/// A Default implementation exists which adapter may overwrite with more efficient
|
/// A Default implementation exists which adapter may overwrite with more efficient
|
||||||
@ -125,6 +108,16 @@ pub trait RoleDB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RoleDB for HashMap<RoleIdentifier, Role> {
|
||||||
|
fn get_type_name(&self) -> &'static str {
|
||||||
|
"Internal"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_role(&self, role_id: &RoleIdentifier) -> Result<Option<Role>> {
|
||||||
|
Ok(self.get(role_id).cloned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A "Role" from the Authorization perspective
|
/// A "Role" from the Authorization perspective
|
||||||
///
|
///
|
||||||
/// You can think of a role as a bundle of permissions relating to other roles. In most cases a
|
/// You can think of a role as a bundle of permissions relating to other roles. In most cases a
|
||||||
@ -162,6 +155,10 @@ impl Role {
|
|||||||
(RoleIdentifier::local_from_str("lmdb".to_string(), key), value)
|
(RoleIdentifier::local_from_str("lmdb".to_string(), key), value)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new(parents: Vec<RoleIdentifier>, permissions: Vec<PermRule>) -> Self {
|
||||||
|
Self { parents, permissions }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Role {
|
impl fmt::Display for Role {
|
||||||
@ -209,6 +206,15 @@ pub struct RoleIdentifier {
|
|||||||
source: SourceID,
|
source: SourceID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RoleIdentifier {
|
||||||
|
pub fn new<>(name: &str, source: &str) -> Self {
|
||||||
|
Self { name: name.to_string(), source: source.to_string() }
|
||||||
|
}
|
||||||
|
pub fn from_strings(name: String, source: String) -> Self {
|
||||||
|
Self { name, source }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for RoleIdentifier {
|
impl fmt::Display for RoleIdentifier {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}/{}", self.name, self.source)
|
write!(f, "{}/{}", self.name, self.source)
|
||||||
|
@ -145,11 +145,6 @@ impl RoleDB for Internal {
|
|||||||
"Internal"
|
"Internal"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(&self, user: &UserData, perm: &Permission) -> Result<bool> {
|
|
||||||
let txn = self.env.begin_ro_txn()?;
|
|
||||||
self._check(&txn, user, &perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_role(&self, role_id: &RoleIdentifier) -> Result<Option<Role>> {
|
fn get_role(&self, role_id: &RoleIdentifier) -> Result<Option<Role>> {
|
||||||
let txn = self.env.begin_ro_txn()?;
|
let txn = self.env.begin_ro_txn()?;
|
||||||
self._get_role(&txn, role_id)
|
self._get_role(&txn, role_id)
|
||||||
|
@ -115,11 +115,22 @@ pub fn load_file<P: AsRef<Path>>(path: P) -> Result<HashMap<String, User>> {
|
|||||||
let f = fs::read(path)?;
|
let f = fs::read(path)?;
|
||||||
let mut map: HashMap<String, UserData> = toml::from_slice(&f)?;
|
let mut map: HashMap<String, UserData> = toml::from_slice(&f)?;
|
||||||
|
|
||||||
Ok(HashMap::from_iter(map.drain().map(|(uid, user_data)|
|
Ok(HashMap::from_iter(map.drain().map(|(uid, mut user_data)| {
|
||||||
|
user_data.passwd = user_data.passwd.map(|pw| if !pw.starts_with("$argon2") {
|
||||||
|
let config = argon2::Config::default();
|
||||||
|
let salt: [u8; 16] = rand::random();
|
||||||
|
let hash = argon2::hash_encoded(pw.as_bytes(), &salt, &config)
|
||||||
|
.expect(&format!("Failed to hash password for {}: ", uid));
|
||||||
|
println!("Hashed pw for {} to {}", uid, hash);
|
||||||
|
|
||||||
|
hash
|
||||||
|
} else {
|
||||||
|
pw
|
||||||
|
});
|
||||||
( uid.clone()
|
( uid.clone()
|
||||||
, User::new(UserId::new(uid, None, None), user_data)
|
, User::new(UserId::new(uid, None, None), user_data)
|
||||||
)
|
)
|
||||||
)))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(log: Logger, _config: &Config, env: Arc<lmdb::Environment>) -> Result<Internal> {
|
pub fn init(log: Logger, _config: &Config, env: Arc<lmdb::Environment>) -> Result<Internal> {
|
||||||
|
@ -117,7 +117,8 @@ impl Future for Initiator {
|
|||||||
debug!(this.log, "Sensor returned a new state");
|
debug!(this.log, "Sensor returned a new state");
|
||||||
this.future.take();
|
this.future.take();
|
||||||
let f = this.machine.as_mut().map(|machine| {
|
let f = this.machine.as_mut().map(|machine| {
|
||||||
machine.request_state_change(user.as_ref(), state)
|
unimplemented!()
|
||||||
|
//machine.request_state_change(user.as_ref(), state)
|
||||||
});
|
});
|
||||||
this.state_change_fut = f;
|
this.state_change_fut = f;
|
||||||
}
|
}
|
||||||
@ -127,11 +128,11 @@ impl Future for Initiator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(log: &Logger, client: &AsyncClient, config: &Config) -> Result<(InitMap, Vec<Initiator>)> {
|
pub fn load(log: &Logger, config: &Config) -> Result<(InitMap, Vec<Initiator>)> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
let initiators = config.initiators.iter()
|
let initiators = config.initiators.iter()
|
||||||
.map(|(k,v)| (k, load_single(log, client, k, &v.module, &v.params)))
|
.map(|(k,v)| (k, load_single(log, k, &v.module, &v.params)))
|
||||||
.filter_map(|(k,n)| match n {
|
.filter_map(|(k,n)| match n {
|
||||||
None => None,
|
None => None,
|
||||||
Some(i) => Some((k, i)),
|
Some(i) => Some((k, i)),
|
||||||
@ -149,7 +150,6 @@ pub fn load(log: &Logger, client: &AsyncClient, config: &Config) -> Result<(Init
|
|||||||
|
|
||||||
fn load_single(
|
fn load_single(
|
||||||
log: &Logger,
|
log: &Logger,
|
||||||
_client: &AsyncClient,
|
|
||||||
name: &String,
|
name: &String,
|
||||||
module_name: &String,
|
module_name: &String,
|
||||||
_params: &HashMap<String, String>
|
_params: &HashMap<String, String>
|
||||||
|
@ -29,28 +29,10 @@ use crate::db::user::{User, UserData};
|
|||||||
use crate::network::MachineMap;
|
use crate::network::MachineMap;
|
||||||
use crate::space;
|
use crate::space;
|
||||||
|
|
||||||
// Registry of all machines configured.
|
|
||||||
// TODO:
|
|
||||||
// - Serialize machines into config
|
|
||||||
// - Deserialize machines from config
|
|
||||||
// - Index machines on deserialization to we can look them up efficiently
|
|
||||||
// - Maybe store that index too
|
|
||||||
// - Iterate over all or a subset of machines efficiently
|
|
||||||
pub struct Machines {
|
pub struct Machines {
|
||||||
machines: Vec<Machine>
|
machines: Vec<Machine>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Machines {
|
|
||||||
/// Load machines from the config, looking up and linking the database entries as necessary
|
|
||||||
pub fn load() -> Self {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lookup(id: String) -> Option<Machine> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Index {
|
pub struct Index {
|
||||||
inner: HashMap<String, Machine>,
|
inner: HashMap<String, Machine>,
|
||||||
@ -80,15 +62,13 @@ pub struct Machine {
|
|||||||
pub desc: MachineDescription,
|
pub desc: MachineDescription,
|
||||||
|
|
||||||
inner: Arc<Mutex<Inner>>,
|
inner: Arc<Mutex<Inner>>,
|
||||||
access: Arc<access::AccessControl>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
pub fn new(inner: Inner, desc: MachineDescription, access: Arc<access::AccessControl>) -> Self {
|
pub fn new(inner: Inner, desc: MachineDescription, ) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: uuid::Uuid::default(),
|
id: uuid::Uuid::default(),
|
||||||
inner: Arc::new(Mutex::new(inner)),
|
inner: Arc::new(Mutex::new(inner)),
|
||||||
access,
|
|
||||||
desc,
|
desc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,83 +77,25 @@ impl Machine {
|
|||||||
( id: MachineIdentifier
|
( id: MachineIdentifier
|
||||||
, desc: MachineDescription
|
, desc: MachineDescription
|
||||||
, state: MachineState
|
, state: MachineState
|
||||||
, access: Arc<access::AccessControl>
|
|
||||||
) -> Machine
|
) -> Machine
|
||||||
{
|
{
|
||||||
Self::new(Inner::new(id, state), desc, access)
|
Self::new(Inner::new(id, state), desc)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_file<P: AsRef<Path>>(path: P, access: Arc<access::AccessControl>)
|
|
||||||
-> Result<Vec<Machine>>
|
|
||||||
{
|
|
||||||
let mut map: HashMap<MachineIdentifier, MachineDescription> = MachineDescription::load_file(path)?;
|
|
||||||
Ok(map.drain().map(|(id, desc)| {
|
|
||||||
Self::construct(id, desc, MachineState::new(), access.clone())
|
|
||||||
}).collect())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Requests to use a machine. Returns a return token if successful.
|
|
||||||
///
|
|
||||||
/// This will update the internal state of the machine, notifying connected actors, if any.
|
|
||||||
/// The return token is a channel that considers the machine 'returned' if anything is sent
|
|
||||||
/// along it or if the sending end gets dropped. Anybody who holds this token needs to check if
|
|
||||||
/// the receiving end was canceled which indicates that the machine has been taken off their
|
|
||||||
/// hands.
|
|
||||||
pub fn request_state_change(&self, who: Option<&User>, new_state: MachineState)
|
|
||||||
-> BoxFuture<'static, Result<ReturnToken>>
|
|
||||||
{
|
|
||||||
let this = self.clone();
|
|
||||||
let perms: Vec<access::PermRule> = who
|
|
||||||
.map(|u| self.access.collect_permrules(&u.data))
|
|
||||||
.and_then(|result| result.ok())
|
|
||||||
.unwrap_or(vec![]);
|
|
||||||
let write: bool = perms.iter().any(|rule| rule.match_perm(&self.desc.privs.write));
|
|
||||||
let manage: bool = perms.iter().any(|rule| rule.match_perm(&self.desc.privs.manage));
|
|
||||||
|
|
||||||
let f = async move {
|
|
||||||
match &new_state.state {
|
|
||||||
Status::Free => {
|
|
||||||
let mut guard = this.inner.lock().await;
|
|
||||||
guard.do_state_change(new_state);
|
|
||||||
return Ok(ReturnToken::new(this.inner.clone()));
|
|
||||||
},
|
|
||||||
Status::InUse(_) | Status::ToCheck(_) if manage || write => {
|
|
||||||
let mut guard = this.inner.lock().await;
|
|
||||||
guard.do_state_change(new_state);
|
|
||||||
return Ok(ReturnToken::new(this.inner.clone()))
|
|
||||||
},
|
|
||||||
Status::Blocked(_) | Status::Disabled | Status::Reserved(_) if manage => {
|
|
||||||
let mut guard = this.inner.lock().await;
|
|
||||||
guard.do_state_change(new_state);
|
|
||||||
return Ok(ReturnToken::new(this.inner.clone()))
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
return Err(Error::Denied);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Box::pin(f)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_state_change(&self, new_state: MachineState)
|
pub fn do_state_change(&self, new_state: MachineState)
|
||||||
-> BoxFuture<'static, Result<ReturnToken>>
|
-> BoxFuture<'static, Result<()>>
|
||||||
{
|
{
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
|
|
||||||
let f = async move {
|
let f = async move {
|
||||||
let mut guard = this.inner.lock().await;
|
let mut guard = this.inner.lock().await;
|
||||||
guard.do_state_change(new_state);
|
guard.do_state_change(new_state);
|
||||||
return Ok(ReturnToken::new(this.inner.clone()))
|
return Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
Box::pin(f)
|
Box::pin(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_token(&self) -> ReturnToken {
|
|
||||||
ReturnToken::new(self.inner.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_status(&self) -> Status {
|
pub async fn get_status(&self) -> Status {
|
||||||
let guard = self.inner.lock().await;
|
let guard = self.inner.lock().await;
|
||||||
guard.state.get_cloned().state
|
guard.state.get_cloned().state
|
||||||
@ -241,7 +163,9 @@ impl Inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_state_change(&mut self, new_state: MachineState) {
|
pub fn do_state_change(&mut self, new_state: MachineState) {
|
||||||
|
print!("State {:?}", &new_state);
|
||||||
let old_state = self.state.replace(new_state);
|
let old_state = self.state.replace(new_state);
|
||||||
|
print!("<- {:?}", &old_state);
|
||||||
self.reset.replace(old_state);
|
self.reset.replace(old_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +240,7 @@ impl MachineDescription {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(config: &crate::config::Config, access: Arc<access::AccessControl>)
|
pub fn load(config: &crate::config::Config)
|
||||||
-> Result<MachineMap>
|
-> Result<MachineMap>
|
||||||
{
|
{
|
||||||
let mut map = config.machines.clone();
|
let mut map = config.machines.clone();
|
||||||
@ -324,7 +248,7 @@ pub fn load(config: &crate::config::Config, access: Arc<access::AccessControl>)
|
|||||||
let it = map.drain()
|
let it = map.drain()
|
||||||
.map(|(k,v)| {
|
.map(|(k,v)| {
|
||||||
// TODO: Read state from the state db
|
// TODO: Read state from the state db
|
||||||
(v.name.clone(), Machine::construct(k, v, MachineState::new(), access.clone()))
|
(v.name.clone(), Machine::construct(k, v, MachineState::new()))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
47
src/main.rs
47
src/main.rs
@ -69,7 +69,6 @@ fn main() {
|
|||||||
.help("Dump all databases into the given directory")
|
.help("Dump all databases into the given directory")
|
||||||
.long("dump")
|
.long("dump")
|
||||||
.conflicts_with("load")
|
.conflicts_with("load")
|
||||||
.takes_value(true)
|
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("load")
|
.arg(Arg::with_name("load")
|
||||||
.help("Load databases from the given directory")
|
.help("Load databases from the given directory")
|
||||||
@ -145,6 +144,11 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
|
|||||||
for (id, role) in v.iter() {
|
for (id, role) in v.iter() {
|
||||||
info!(log, "Role {}:\n{}", id, role);
|
info!(log, "Role {}:\n{}", id, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let v = db.userdb.list_users()?;
|
||||||
|
for user in v.iter() {
|
||||||
|
info!(log, "User {}:\n{:?}", user.id, user.data);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if matches.is_present("load") {
|
} else if matches.is_present("load") {
|
||||||
let db = db::Databases::new(&log, &config)?;
|
let db = db::Databases::new(&log, &config)?;
|
||||||
@ -158,41 +162,34 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
|
|||||||
debug!(log, "Loaded users: {:?}", map);
|
debug!(log, "Loaded users: {:?}", map);
|
||||||
dir.pop();
|
dir.pop();
|
||||||
|
|
||||||
dir.push("roles.toml");
|
|
||||||
db.access.internal.load_roles(&dir)?;
|
|
||||||
dir.pop();
|
|
||||||
|
|
||||||
dir.push("pass.toml");
|
|
||||||
db.passdb.load_file(&dir);
|
|
||||||
dir.pop();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let ex = Executor::new();
|
let ex = Executor::new();
|
||||||
let db = db::Databases::new(&log, &config)?;
|
let db = db::Databases::new(&log, &config)?;
|
||||||
|
|
||||||
let mqtt = AsyncClient::new(config.mqtt_url.clone())?;
|
//let mqtt = AsyncClient::new(config.mqtt_url.clone())?;
|
||||||
let tok = mqtt.connect(paho_mqtt::ConnectOptions::new());
|
//let tok = mqtt.connect(paho_mqtt::ConnectOptions::new());
|
||||||
|
|
||||||
smol::block_on(tok)?;
|
//smol::block_on(tok)?;
|
||||||
|
|
||||||
let machines = machine::load(&config, db.access.clone())?;
|
let machines = machine::load(&config)?;
|
||||||
let (actor_map, actors) = actor::load(&log, &mqtt, &config)?;
|
let (actor_map, actors) = actor::load(&log, &config)?;
|
||||||
let (init_map, initiators) = initiator::load(&log, &mqtt, &config)?;
|
let (init_map, initiators) = initiator::load(&log, &config)?;
|
||||||
|
|
||||||
// TODO: restore connections between initiators, machines, actors
|
|
||||||
let mut network = network::Network::new(machines, actor_map, init_map);
|
let mut network = network::Network::new(machines, actor_map, init_map);
|
||||||
|
|
||||||
for (a,b) in config.actor_connections.iter() {
|
for (a,b) in config.actor_connections.iter() {
|
||||||
if let Err(e) = network.connect_actor(a,b) {
|
if let Err(e) = network.connect_actor(a,b) {
|
||||||
error!(log, "{}", e);
|
error!(log, "{}", e);
|
||||||
}
|
}
|
||||||
|
info!(log, "[Actor] Connected {} to {}", a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (a,b) in config.init_connections.iter() {
|
for (a,b) in config.init_connections.iter() {
|
||||||
if let Err(e) = network.connect_init(a,b) {
|
if let Err(e) = network.connect_init(a,b) {
|
||||||
error!(log, "{}", e);
|
error!(log, "{}", e);
|
||||||
}
|
}
|
||||||
|
info!(log, "[Initi] Connected {} to {}", a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
for actor in actors.into_iter() {
|
for actor in actors.into_iter() {
|
||||||
@ -202,22 +199,6 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
|
|||||||
ex.spawn(init).detach();
|
ex.spawn(init).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (signal, shutdown) = async_channel::bounded::<()>(1);
|
server::serve_api_connections(log.clone(), config, db, network, ex)
|
||||||
let (_, r) = easy_parallel::Parallel::new()
|
|
||||||
.each(0..4, |_| smol::block_on(ex.run(shutdown.recv())))
|
|
||||||
.finish(|| {
|
|
||||||
// TODO: Spawn api connections on their own (non-main) thread, use the main thread to
|
|
||||||
// handle signals (a cli if stdin is not closed?) and make it stop and clean up all threads
|
|
||||||
// when bffh should exit
|
|
||||||
let r = server::serve_api_connections(log.clone(), config, db, network);
|
|
||||||
|
|
||||||
// One of them would be enough really, but *shrug*
|
|
||||||
signal.try_send(());
|
|
||||||
std::mem::drop(signal);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
});
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,17 @@ pub type InitMap = HashMap<String, Mutable<Option<Machine>>>;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
NoSuchInitiator,
|
NoSuchInitiator(String),
|
||||||
NoSuchMachine,
|
NoSuchMachine(String),
|
||||||
NoSuchActor,
|
NoSuchActor(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::NoSuchInitiator => write!(f, "No initiator found with that name"),
|
Error::NoSuchInitiator(n) => write!(f, "No initiator \"{}\" found.", n),
|
||||||
Error::NoSuchActor => write!(f, "No actor found with that name"),
|
Error::NoSuchActor(n) => write!(f, "No actor \"{}\" found.", n),
|
||||||
Error::NoSuchMachine => write!(f, "No machine found with that name"),
|
Error::NoSuchMachine(n) => write!(f, "No machine \"{}\" found.", n),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,9 +57,9 @@ impl Network {
|
|||||||
|
|
||||||
pub fn connect_init(&self, init_key: &String, machine_key: &String) -> Result<()> {
|
pub fn connect_init(&self, init_key: &String, machine_key: &String) -> Result<()> {
|
||||||
let init = self.inits.get(init_key)
|
let init = self.inits.get(init_key)
|
||||||
.ok_or(Error::NoSuchInitiator)?;
|
.ok_or_else(|| Error::NoSuchInitiator(init_key.clone()))?;
|
||||||
let machine = self.machines.get(machine_key)
|
let machine = self.machines.get(machine_key)
|
||||||
.ok_or(Error::NoSuchMachine)?;
|
.ok_or_else(|| Error::NoSuchMachine(machine_key.clone()))?;
|
||||||
|
|
||||||
init.set(Some(machine.clone()));
|
init.set(Some(machine.clone()));
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -69,13 +69,14 @@ impl Network {
|
|||||||
-> Result<()>
|
-> Result<()>
|
||||||
{
|
{
|
||||||
let machine = self.machines.get(machine_key)
|
let machine = self.machines.get(machine_key)
|
||||||
.ok_or(Error::NoSuchMachine)?;
|
.ok_or_else(|| Error::NoSuchMachine(machine_key.clone()))?;
|
||||||
let actor = self.actors.get(actor_key)
|
let actor = self.actors.get(actor_key)
|
||||||
.ok_or(Error::NoSuchActor)?;
|
.ok_or_else(|| Error::NoSuchActor(actor_key.clone()))?;
|
||||||
|
|
||||||
// FIXME Yeah this should not unwrap. Really, really shoudln't.
|
// FIXME Yeah this should not unwrap. Really, really shoudln't.
|
||||||
let mut guard = actor.try_lock().unwrap();
|
let mut guard = actor.try_lock().unwrap();
|
||||||
|
|
||||||
guard.try_send(Some(Box::new(machine.signal()))).map_err(|_| Error::NoSuchActor.into())
|
guard.try_send(Some(Box::new(machine.signal())))
|
||||||
|
.map_err(|_| Error::NoSuchActor(actor_key.clone()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use crate::connection;
|
|||||||
use smol::net::TcpListener;
|
use smol::net::TcpListener;
|
||||||
use smol::net::unix::UnixStream;
|
use smol::net::unix::UnixStream;
|
||||||
use smol::LocalExecutor;
|
use smol::LocalExecutor;
|
||||||
|
use smol::Executor;
|
||||||
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ use crate::db::Databases;
|
|||||||
use crate::network::Network;
|
use crate::network::Network;
|
||||||
|
|
||||||
/// Handle all API connections and run the RPC tasks spawned from that on the local thread.
|
/// Handle all API connections and run the RPC tasks spawned from that on the local thread.
|
||||||
pub fn serve_api_connections(log: Arc<Logger>, config: Config, db: Databases, nw: Network)
|
pub fn serve_api_connections(log: Arc<Logger>, config: Config, db: Databases, nw: Network, ex: Executor)
|
||||||
-> Result<(), Error>
|
-> Result<(), Error>
|
||||||
{
|
{
|
||||||
let signal = Box::pin(async {
|
let signal = Box::pin(async {
|
||||||
@ -72,13 +73,11 @@ pub fn serve_api_connections(log: Arc<Logger>, config: Config, db: Databases, nw
|
|||||||
let inner_log = log.clone();
|
let inner_log = log.clone();
|
||||||
let loop_log = log.clone();
|
let loop_log = log.clone();
|
||||||
|
|
||||||
smol::block_on(local_ex.run(async {
|
let control_fut = async {
|
||||||
// Generate a stream of TcpStreams appearing on any of the interfaces we listen to
|
// Generate a stream of TcpStreams appearing on any of the interfaces we listen to
|
||||||
let listeners = listeners_s.await;
|
let listeners = listeners_s.await;
|
||||||
let incoming = stream::select_all(listeners.iter().map(|l| l.incoming()));
|
let incoming = stream::select_all(listeners.iter().map(|l| l.incoming()));
|
||||||
|
|
||||||
let mut handler = connection::ConnectionHandler::new(inner_log.new(o!()), db, network.clone());
|
|
||||||
|
|
||||||
// For each incoming connection start a new task to handle it
|
// For each incoming connection start a new task to handle it
|
||||||
let handle_sockets = incoming.map(|socket| {
|
let handle_sockets = incoming.map(|socket| {
|
||||||
// incoming.next() returns an error when the underlying `accept` call yielded an error
|
// incoming.next() returns an error when the underlying `accept` call yielded an error
|
||||||
@ -94,18 +93,26 @@ pub fn serve_api_connections(log: Arc<Logger>, config: Config, db: Databases, nw
|
|||||||
inner_log.new(o!())
|
inner_log.new(o!())
|
||||||
};
|
};
|
||||||
|
|
||||||
// We handle the error using map_err
|
let db = db.clone();
|
||||||
let f = handler.handle(socket)
|
let network = network.clone();
|
||||||
.map_err(move |e| {
|
let tlog = inner_log.new(o!());
|
||||||
error!(log, "Error occured during protocol handling: {}", e);
|
std::thread::spawn(move || {
|
||||||
})
|
let local_ex = LocalExecutor::new();
|
||||||
// Void any and all results since pool.spawn allows no return value.
|
|
||||||
.map(|_| ());
|
|
||||||
|
|
||||||
// Spawn the connection context onto the local executor since it isn't Send
|
let mut handler = connection::ConnectionHandler::new(tlog, db, network);
|
||||||
// Also `detach` it so the task isn't canceled as soon as it's dropped.
|
// We handle the error using map_err
|
||||||
// TODO: Store all those tasks to have a easier way of managing them?
|
let f = handler.handle(socket)
|
||||||
local_ex.spawn(f).detach();
|
.map_err(move |e| {
|
||||||
|
error!(log, "Error occured during protocol handling: {}", e);
|
||||||
|
})
|
||||||
|
// Void any and all results since pool.spawn allows no return value.
|
||||||
|
.map(|_| ());
|
||||||
|
|
||||||
|
// Spawn the connection context onto the local executor since it isn't Send
|
||||||
|
// Also `detach` it so the task isn't canceled as soon as it's dropped.
|
||||||
|
// TODO: Store all those tasks to have a easier way of managing them?
|
||||||
|
smol::block_on(f);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!(inner_log, "Socket `accept` error: {}", e);
|
error!(inner_log, "Socket `accept` error: {}", e);
|
||||||
@ -147,7 +154,9 @@ pub fn serve_api_connections(log: Arc<Logger>, config: Config, db: Databases, nw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
};
|
||||||
|
|
||||||
|
smol::block_on(smol::future::race(control_fut, ex.run(smol::future::pending())));
|
||||||
|
|
||||||
// TODO: Run actual shut down code here
|
// TODO: Run actual shut down code here
|
||||||
info!(log, "Shutting down...");
|
info!(log, "Shutting down...");
|
||||||
|
Loading…
Reference in New Issue
Block a user