mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-24 23:57:57 +01:00
Commit current state
This commit is contained in:
parent
d7a66e2149
commit
4778c7a8d3
44
Cargo.lock
generated
44
Cargo.lock
generated
@ -836,7 +836,6 @@ dependencies = [
|
||||
"rsasl",
|
||||
"rust-argon2",
|
||||
"rustls",
|
||||
"sdk",
|
||||
"serde",
|
||||
"serde_dhall",
|
||||
"serde_json",
|
||||
@ -878,6 +877,13 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "dummy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"sdk",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
@ -2104,8 +2110,19 @@ dependencies = [
|
||||
name = "sdk"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"diflouroborane",
|
||||
"futures-util",
|
||||
"sdk-proc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sdk-proc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"trybuild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2410,6 +2427,15 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.29"
|
||||
@ -2499,6 +2525,20 @@ dependencies = [
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trybuild"
|
||||
version = "1.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d664de8ea7e531ad4c0f5a834f20b8cb2b8e6dfe88d05796ee7887518ed67b9"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"termcolor",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "1.7.0"
|
||||
|
@ -25,8 +25,6 @@ path = "bin/bffhd/main.rs"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.101"
|
||||
|
||||
sdk = { path = "modules/sdk", default-features = false }
|
||||
lazy_static = "1.4.0"
|
||||
uuid = { version = "0.8.2", features = ["serde", "v4"] }
|
||||
async-trait = "0.1.51"
|
||||
|
@ -6,18 +6,48 @@ use async_oneshot as oneshot;
|
||||
use futures_signals::signal::Signal;
|
||||
use futures_util::future::BoxFuture;
|
||||
use smol::future::FutureExt;
|
||||
use sdk::initiators::{Initiator, InitiatorError, UpdateError, UpdateSink, UserID, ResourceID};
|
||||
use crate::resource::{Error, Update};
|
||||
use crate::resource::claim::{ResourceID, UserID};
|
||||
use crate::resource::state::State;
|
||||
|
||||
pub enum UpdateError {
|
||||
/// We're not connected to anything anymore. You can't do anything about this error and the
|
||||
/// only reason why you even get it is because your future was called a last time before
|
||||
/// being shelved so best way to handle this error is to just return from your loop entirely,
|
||||
/// cleaning up any state that doesn't survive a freeze.
|
||||
Closed,
|
||||
|
||||
Denied,
|
||||
|
||||
Other(Box<dyn std::error::Error + Send>),
|
||||
}
|
||||
|
||||
pub trait InitiatorError: std::error::Error + Send {
|
||||
}
|
||||
|
||||
pub trait Initiator {
|
||||
fn start_for(&mut self, machine: ResourceID)
|
||||
-> BoxFuture<'static, Result<(), Box<dyn InitiatorError>>>;
|
||||
|
||||
fn run(&mut self, request: &mut UpdateSink)
|
||||
-> BoxFuture<'static, Result<(), Box<dyn InitiatorError>>>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BffhUpdateSink {
|
||||
tx: channel::Sender<(Option<UserID>, sdk::initiators::State)>,
|
||||
pub struct UpdateSink {
|
||||
tx: channel::Sender<(Option<UserID>, State)>,
|
||||
rx: channel::Receiver<Result<(), Error>>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl UpdateSink for BffhUpdateSink {
|
||||
async fn send(&mut self, userid: Option<UserID>, state: sdk::initiators::State)
|
||||
impl UpdateSink {
|
||||
fn new(tx: channel::Sender<(Option<UserID>, State)>,
|
||||
rx: channel::Receiver<Result<(), Error>>)
|
||||
-> Self
|
||||
{
|
||||
Self { tx, rx }
|
||||
}
|
||||
|
||||
async fn send(&mut self, userid: Option<UserID>, state: State)
|
||||
-> Result<(), UpdateError>
|
||||
{
|
||||
if let Err(_e) = self.tx.send((userid, state)).await {
|
||||
@ -34,15 +64,6 @@ impl UpdateSink for BffhUpdateSink {
|
||||
}
|
||||
}
|
||||
|
||||
impl BffhUpdateSink {
|
||||
fn new(tx: channel::Sender<(Option<UserID>, sdk::initiators::State)>,
|
||||
rx: channel::Receiver<Result<(), Error>>)
|
||||
-> Self
|
||||
{
|
||||
Self { tx, rx }
|
||||
}
|
||||
}
|
||||
|
||||
struct Resource;
|
||||
pub struct InitiatorDriver<S, I: Initiator> {
|
||||
resource_signal: S,
|
||||
@ -51,8 +72,8 @@ pub struct InitiatorDriver<S, I: Initiator> {
|
||||
|
||||
initiator: I,
|
||||
initiator_future: Option<BoxFuture<'static, Result<(), Box<dyn InitiatorError>>>>,
|
||||
update_sink: BffhUpdateSink,
|
||||
initiator_req_rx: channel::Receiver<(Option<UserID>, sdk::initiators::State)>,
|
||||
update_sink: UpdateSink,
|
||||
initiator_req_rx: channel::Receiver<(Option<UserID>, State)>,
|
||||
initiator_reply_tx: channel::Sender<Result<(), Error>>,
|
||||
}
|
||||
|
||||
@ -65,7 +86,7 @@ impl<S: Signal<Item=ResourceSink>, I: Initiator> InitiatorDriver<S, I> {
|
||||
pub fn new(resource_signal: S, initiator: I) -> Self {
|
||||
let (initiator_reply_tx, initiator_reply_rx) = channel::bounded(1);
|
||||
let (initiator_req_tx, initiator_req_rx) = async_channel::bounded(1);
|
||||
let update_sink = BffhUpdateSink::new(initiator_req_tx, initiator_reply_rx);
|
||||
let update_sink = UpdateSink::new(initiator_req_tx, initiator_reply_rx);
|
||||
Self {
|
||||
resource: None,
|
||||
resource_signal,
|
||||
|
@ -1,4 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use lmdb::{RwTransaction, Transaction};
|
||||
use crate::db::{RawDB, DB, AllocAdapter, Environment, Result};
|
||||
use crate::db::{DatabaseFlags, LMDBorrow, RoTransaction, WriteFlags, };
|
||||
use super::User;
|
||||
@ -62,3 +64,59 @@ impl UserDB {
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserIndex {
|
||||
env: Arc<Environment>,
|
||||
usernames: RawDB,
|
||||
roles: RawDB,
|
||||
}
|
||||
|
||||
impl UserIndex {
|
||||
pub fn update(&self, old: &User, new: &User) -> Result<()> {
|
||||
assert_eq!(old.id, new.id);
|
||||
let mut txn = self.env.begin_rw_txn()?;
|
||||
if old.username != new.username {
|
||||
self.update_username(&mut txn, new.id, &old.username, &new.username)?;
|
||||
}
|
||||
|
||||
let mut to_remove: HashSet<&String> = old.roles.iter().collect();
|
||||
let mut to_add: HashSet<&String> = HashSet::new();
|
||||
for role in new.roles.iter() {
|
||||
// If a role wasn't found in the old ones it's a new one that's being added
|
||||
if !to_remove.remove(role) {
|
||||
to_add.insert(role);
|
||||
}
|
||||
// Otherwise it's in both sets so we just ignore it.
|
||||
}
|
||||
|
||||
self.update_roles(&mut txn, new.id, to_remove, to_add)?;
|
||||
txn.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_username(&self, txn: &mut RwTransaction, uid: u128, old: &String, new: &String)
|
||||
-> Result<()>
|
||||
{
|
||||
let flags = WriteFlags::empty();
|
||||
self.usernames.del(txn, &old.as_bytes(), Some(&uid.to_ne_bytes()))?;
|
||||
self.usernames.put(txn, &new.as_bytes(), &uid.to_ne_bytes(), flags)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_roles(&self,
|
||||
txn: &mut RwTransaction,
|
||||
uid: u128,
|
||||
remove: HashSet<&String>,
|
||||
add: HashSet<&String>
|
||||
) -> Result<()>
|
||||
{
|
||||
let flags = WriteFlags::empty();
|
||||
for role in remove.iter() {
|
||||
self.roles.del(txn, &role.as_bytes(), Some(&uid.to_ne_bytes()))?;
|
||||
}
|
||||
for role in add.iter() {
|
||||
self.roles.put(txn, &role.as_bytes(), &uid.to_ne_bytes(), flags)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2021. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
|
||||
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
|
||||
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
|
||||
* Vestibulum commodo. Ut rhoncus gravida arcu.
|
||||
*/
|
||||
|
||||
use rkyv::{Archive, Serialize, Deserialize};
|
||||
|
||||
use capnp::capability::Promise;
|
||||
@ -26,7 +34,9 @@ pub struct User {
|
||||
}
|
||||
|
||||
impl User {
|
||||
|
||||
pub fn new(id: u128, username: String, roles: Vec<String>) -> Self {
|
||||
User { id, username, roles }
|
||||
}
|
||||
}
|
||||
|
||||
impl info::Server for User {
|
||||
|
@ -6,5 +6,6 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.51"
|
||||
sdk-proc = { path = "sdk_proc" }
|
||||
futures-util = "0.3"
|
||||
diflouroborane = { path = "../.." }
|
87
modules/sdk/sdk_proc/src/lib.rs
Normal file
87
modules/sdk/sdk_proc/src/lib.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use proc_macro::TokenStream;
|
||||
use std::sync::Mutex;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{braced, parse_macro_input, Field, Ident, Token, Visibility, Type};
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::token::Brace;
|
||||
|
||||
mod keywords {
|
||||
syn::custom_keyword!(initiator);
|
||||
syn::custom_keyword!(actor);
|
||||
syn::custom_keyword!(sensor);
|
||||
}
|
||||
|
||||
enum ModuleAttrs {
|
||||
Nothing,
|
||||
Initiator,
|
||||
Actor,
|
||||
Sensor,
|
||||
}
|
||||
|
||||
impl Parse for ModuleAttrs {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
if input.is_empty() {
|
||||
Ok(ModuleAttrs::Nothing)
|
||||
} else {
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(keywords::initiator) {
|
||||
Ok(ModuleAttrs::Initiator)
|
||||
} else if lookahead.peek(keywords::actor) {
|
||||
Ok(ModuleAttrs::Actor)
|
||||
} else if lookahead.peek(keywords::sensor) {
|
||||
Ok(ModuleAttrs::Sensor)
|
||||
} else {
|
||||
Err(input.error("Module type must be empty or one of \"initiator\", \"actor\", or \
|
||||
\"sensor\""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ModuleInput {
|
||||
pub ident: Ident,
|
||||
pub fields: Punctuated<Field, Token![,]>,
|
||||
}
|
||||
|
||||
impl Parse for ModuleInput {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(Token![pub]) {
|
||||
let _vis: Visibility = input.parse()?;
|
||||
}
|
||||
if input.parse::<Token![struct]>().is_err() {
|
||||
return Err(input.error("Modules must be structs"));
|
||||
}
|
||||
let ident = input.parse::<Ident>()?;
|
||||
|
||||
let lookahead = input.lookahead1();
|
||||
if !lookahead.peek(Brace) {
|
||||
return Err(input.error("Modules can't be unit structs"));
|
||||
}
|
||||
|
||||
let content;
|
||||
braced!(content in input);
|
||||
Ok(Self {
|
||||
ident,
|
||||
fields: content.parse_terminated(Field::parse_named)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn module(attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
let attrs = parse_macro_input!(attr as ModuleAttrs);
|
||||
let item = parse_macro_input!(tokens as ModuleInput);
|
||||
|
||||
let output = {
|
||||
let ident = item.ident;
|
||||
let fields = item.fields.iter();
|
||||
quote! {
|
||||
pub struct #ident {
|
||||
#(#fields),*
|
||||
}
|
||||
}
|
||||
};
|
||||
output.into()
|
||||
}
|
10
modules/sdk/sdk_proc/tests/01-parse-struct.rs
Normal file
10
modules/sdk/sdk_proc/tests/01-parse-struct.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// Check if the proc macro for modules exists and is correctly imported from top level
|
||||
|
||||
use sdk_proc::module;
|
||||
|
||||
#[module]
|
||||
pub struct Module {
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
11
modules/sdk/sdk_proc/tests/02-not-or-bad-struct.rs
Normal file
11
modules/sdk/sdk_proc/tests/02-not-or-bad-struct.rs
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
#[sdk_proc::module]
|
||||
enum EnumModule {
|
||||
|
||||
}
|
||||
|
||||
#[sdk_proc::module]
|
||||
struct UnitStructModule;
|
||||
|
||||
fn main() {}
|
@ -1,35 +1,10 @@
|
||||
use async_trait::async_trait;
|
||||
use futures_util::future::BoxFuture;
|
||||
pub use diflouroborane::{
|
||||
initiators::{
|
||||
UpdateSink,
|
||||
UpdateError,
|
||||
|
||||
pub struct State;
|
||||
pub struct UserID;
|
||||
pub struct ResourceID;
|
||||
pub struct Error;
|
||||
|
||||
pub enum UpdateError {
|
||||
/// We're not connected to anything anymore. You can't do anything about this error and the
|
||||
/// only reason why you even get it is because your future was called a last time before
|
||||
/// being shelved so best way to handle this error is to just return from your loop entirely,
|
||||
/// cleaning up any state that doesn't survive a freeze.
|
||||
Closed,
|
||||
|
||||
Denied,
|
||||
|
||||
Other(Box<dyn std::error::Error + Send>),
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UpdateSink: Send {
|
||||
async fn send(&mut self, userid: Option<UserID>, state: State) -> Result<(), UpdateError>;
|
||||
}
|
||||
|
||||
pub trait InitiatorError: std::error::Error + Send {
|
||||
}
|
||||
|
||||
pub trait Initiator {
|
||||
fn start_for(&mut self, machine: ResourceID)
|
||||
-> BoxFuture<'static, Result<(), Box<dyn InitiatorError>>>;
|
||||
|
||||
fn run(&mut self, request: &mut impl UpdateSink)
|
||||
-> BoxFuture<'static, Result<(), Box<dyn InitiatorError>>>;
|
||||
}
|
||||
Initiator,
|
||||
InitiatorError,
|
||||
},
|
||||
resource::claim::ResourceID,
|
||||
};
|
||||
|
@ -1,7 +1,20 @@
|
||||
#[forbid(private_in_public)]
|
||||
|
||||
pub use sdk_proc::module;
|
||||
|
||||
pub use futures_util::future::BoxFuture;
|
||||
pub mod initiators;
|
||||
|
||||
pub const VERSION_STRING: &'static str = env!("CARGO_PKG_VERSION");
|
||||
pub const VERSION_STRING_PARTS: (&'static str, &'static str, &'static str, &'static str) = (
|
||||
env!("CARGO_PKG_VERSION_MAJOR"),
|
||||
env!("CARGO_PKG_VERSION_MINOR"),
|
||||
env!("CARGO_PKG_VERSION_PATCH"),
|
||||
env!("CARGO_PKG_VERSION_PRE"),
|
||||
);
|
||||
|
||||
pub static VERSION_MAJOR: u32 = 0;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user