Commit current state

This commit is contained in:
Nadja Reitzenstein 2021-12-17 16:43:31 +01:00
parent d7a66e2149
commit 4778c7a8d3
11 changed files with 282 additions and 58 deletions

44
Cargo.lock generated
View File

@ -836,7 +836,6 @@ dependencies = [
"rsasl", "rsasl",
"rust-argon2", "rust-argon2",
"rustls", "rustls",
"sdk",
"serde", "serde",
"serde_dhall", "serde_dhall",
"serde_json", "serde_json",
@ -878,6 +877,13 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dummy"
version = "0.1.0"
dependencies = [
"sdk",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.6.1" version = "1.6.1"
@ -2104,8 +2110,19 @@ dependencies = [
name = "sdk" name = "sdk"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait", "diflouroborane",
"futures-util", "futures-util",
"sdk-proc",
]
[[package]]
name = "sdk-proc"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
"trybuild",
] ]
[[package]] [[package]]
@ -2410,6 +2427,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.29" version = "0.1.29"
@ -2499,6 +2525,20 @@ dependencies = [
"tracing-log", "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]] [[package]]
name = "typed-arena" name = "typed-arena"
version = "1.7.0" version = "1.7.0"

View File

@ -25,8 +25,6 @@ path = "bin/bffhd/main.rs"
[dependencies] [dependencies]
libc = "0.2.101" libc = "0.2.101"
sdk = { path = "modules/sdk", default-features = false }
lazy_static = "1.4.0" lazy_static = "1.4.0"
uuid = { version = "0.8.2", features = ["serde", "v4"] } uuid = { version = "0.8.2", features = ["serde", "v4"] }
async-trait = "0.1.51" async-trait = "0.1.51"

View File

@ -6,18 +6,48 @@ use async_oneshot as oneshot;
use futures_signals::signal::Signal; use futures_signals::signal::Signal;
use futures_util::future::BoxFuture; use futures_util::future::BoxFuture;
use smol::future::FutureExt; use smol::future::FutureExt;
use sdk::initiators::{Initiator, InitiatorError, UpdateError, UpdateSink, UserID, ResourceID};
use crate::resource::{Error, Update}; 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)] #[derive(Clone)]
pub struct BffhUpdateSink { pub struct UpdateSink {
tx: channel::Sender<(Option<UserID>, sdk::initiators::State)>, tx: channel::Sender<(Option<UserID>, State)>,
rx: channel::Receiver<Result<(), Error>>, rx: channel::Receiver<Result<(), Error>>,
} }
#[async_trait::async_trait] impl UpdateSink {
impl UpdateSink for BffhUpdateSink { fn new(tx: channel::Sender<(Option<UserID>, State)>,
async fn send(&mut self, userid: Option<UserID>, state: sdk::initiators::State) rx: channel::Receiver<Result<(), Error>>)
-> Self
{
Self { tx, rx }
}
async fn send(&mut self, userid: Option<UserID>, state: State)
-> Result<(), UpdateError> -> Result<(), UpdateError>
{ {
if let Err(_e) = self.tx.send((userid, state)).await { 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; struct Resource;
pub struct InitiatorDriver<S, I: Initiator> { pub struct InitiatorDriver<S, I: Initiator> {
resource_signal: S, resource_signal: S,
@ -51,8 +72,8 @@ pub struct InitiatorDriver<S, I: Initiator> {
initiator: I, initiator: I,
initiator_future: Option<BoxFuture<'static, Result<(), Box<dyn InitiatorError>>>>, initiator_future: Option<BoxFuture<'static, Result<(), Box<dyn InitiatorError>>>>,
update_sink: BffhUpdateSink, update_sink: UpdateSink,
initiator_req_rx: channel::Receiver<(Option<UserID>, sdk::initiators::State)>, initiator_req_rx: channel::Receiver<(Option<UserID>, State)>,
initiator_reply_tx: channel::Sender<Result<(), Error>>, 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 { pub fn new(resource_signal: S, initiator: I) -> Self {
let (initiator_reply_tx, initiator_reply_rx) = channel::bounded(1); let (initiator_reply_tx, initiator_reply_rx) = channel::bounded(1);
let (initiator_req_tx, initiator_req_rx) = async_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 { Self {
resource: None, resource: None,
resource_signal, resource_signal,

View File

@ -1,4 +1,6 @@
use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use lmdb::{RwTransaction, Transaction};
use crate::db::{RawDB, DB, AllocAdapter, Environment, Result}; use crate::db::{RawDB, DB, AllocAdapter, Environment, Result};
use crate::db::{DatabaseFlags, LMDBorrow, RoTransaction, WriteFlags, }; use crate::db::{DatabaseFlags, LMDBorrow, RoTransaction, WriteFlags, };
use super::User; use super::User;
@ -61,4 +63,60 @@ impl UserDB {
Ok(out) 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(())
}
} }

View File

@ -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 rkyv::{Archive, Serialize, Deserialize};
use capnp::capability::Promise; use capnp::capability::Promise;
@ -26,7 +34,9 @@ pub struct User {
} }
impl User { impl User {
pub fn new(id: u128, username: String, roles: Vec<String>) -> Self {
User { id, username, roles }
}
} }
impl info::Server for User { impl info::Server for User {

View File

@ -6,5 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
async-trait = "0.1.51" sdk-proc = { path = "sdk_proc" }
futures-util = "0.3" futures-util = "0.3"
diflouroborane = { path = "../.." }

View 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()
}

View 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() {}

View File

@ -0,0 +1,11 @@
#[sdk_proc::module]
enum EnumModule {
}
#[sdk_proc::module]
struct UnitStructModule;
fn main() {}

View File

@ -1,35 +1,10 @@
use async_trait::async_trait; pub use diflouroborane::{
use futures_util::future::BoxFuture; initiators::{
UpdateSink,
UpdateError,
pub struct State; Initiator,
pub struct UserID; InitiatorError,
pub struct ResourceID; },
pub struct Error; resource::claim::ResourceID,
};
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>>>;
}

View File

@ -1,7 +1,20 @@
#[forbid(private_in_public)] #[forbid(private_in_public)]
pub use sdk_proc::module;
pub use futures_util::future::BoxFuture;
pub mod initiators; 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)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]