mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-12-22 03:33:48 +01:00
Merge branch 'release/0.4.2'
* release/0.4.2: (51 commits) Update process initiator to make shelly-timeout doable Improve error messages on missing config Refactor Config into dhall module Add dumping the user db Fix log format settings Implement password change functionality Better error wrapper type Start taking control over exit on argument parsing failure Return a better error when --load is given a directory Output plentiful trace info for API calls log all api calls with `TRACE` level Add a connection-specific span to each API handler Runtime things furthermore Allow tracking cgroups with futures Oh whoops handle that Get started on supervision trees Attach a GroupID to all LightProcs Noting down improvement ideas for procs More ideas about how to record data A number of small updates batched into one commit ...
This commit is contained in:
commit
95ee4228bd
@ -1,2 +0,0 @@
|
||||
[build]
|
||||
rustflags = ["-C", "target-cpu=native"]
|
@ -75,6 +75,47 @@ When you want feedback on your current progress or are ready to have it merged u
|
||||
request. Don't worry we don't bite! ^^
|
||||
|
||||
|
||||
# Development Setup
|
||||
|
||||
## Cross-compilation
|
||||
|
||||
If you want to cross-compile you need both a C-toolchain for your target
|
||||
and install the Rust stdlib for said target.
|
||||
|
||||
As an example for the target `aarch64-unknown-linux-gnu` (64-bit ARMv8
|
||||
running Linux with the glibc, e.g. a Raspberry Pi 3 or later with a 64-bit
|
||||
Debian Linux installation):
|
||||
|
||||
1. Install C-toolchain using your distro package manager:
|
||||
- On Archlinux: `pacman -S aarch64-unknown-linux-gnu-gcc`
|
||||
2. Install the Rust stdlib:
|
||||
- using rustup: `rustup target add aarch64-unknown-linux-gnu`
|
||||
3. Configure your cargo config:
|
||||
|
||||
### Configuring cargo
|
||||
|
||||
You need to tell Cargo to use your C-toolchain. For this you need to have
|
||||
a block in [your user cargo config](https://doc.rust-lang.org/cargo/reference/config.html) setting at
|
||||
least the paths to the gcc as `linker` and ar as `ar`:
|
||||
|
||||
```toml
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
# You must set the gcc as linker since a lot of magic must happen here.
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
ar = "aarch64-linux-gnu-ar"
|
||||
```
|
||||
|
||||
This block should be added to your **user** cargo config (usually
|
||||
`~/.cargo/config.toml`), since these values can differ between distros and
|
||||
users.
|
||||
|
||||
To actually compile for the given triple you need to call `cargo build`
|
||||
with the `--target` flag:
|
||||
|
||||
```
|
||||
$ cargo build --release --target=aarch64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Sadly, still very much `// TODO:`. We're working on it! :/
|
||||
|
1290
Cargo.lock
generated
1290
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
21
Cargo.toml
21
Cargo.toml
@ -37,7 +37,11 @@ pin-utils = "0.1.0"
|
||||
futures-util = "0.3"
|
||||
futures-lite = "1.12.0"
|
||||
async-net = "1.6.1"
|
||||
anyhow = "1.0.56"
|
||||
async-io = "1.7.0"
|
||||
async-process = "1.4.0"
|
||||
backtrace = "0.3.65"
|
||||
miette = { version = "4.7.1", features = ["fancy"] }
|
||||
thiserror = "1.0.31"
|
||||
toml = "0.5.8"
|
||||
|
||||
# Well-known paths/dirs for e.g. cache
|
||||
@ -45,6 +49,8 @@ dirs = "4.0.0"
|
||||
|
||||
# Runtime
|
||||
executor = { path = "runtime/executor" }
|
||||
lightproc = { path = "runtime/lightproc" }
|
||||
console = { path = "runtime/console" }
|
||||
|
||||
# Catch&Handle POSIX process signals
|
||||
signal-hook = "0.3.13"
|
||||
@ -68,9 +74,9 @@ rust-argon2 = "0.8.3"
|
||||
rand = "0.8.4"
|
||||
|
||||
# Async aware logging and tracing
|
||||
tracing = "0.1.28"
|
||||
tracing-subscriber = { version = "0.2.25", features = ["env-filter"] }
|
||||
tracing-futures = { version = "0.2.5", features = ["futures-03"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "registry", "std"] }
|
||||
tracing-futures = { version = "0.2", features = ["futures-03"] }
|
||||
|
||||
# API
|
||||
api = { path = "api" }
|
||||
@ -103,6 +109,8 @@ async-compat = "0.2.1"
|
||||
url = "2.2.2"
|
||||
rustls-native-certs = "0.6.1"
|
||||
|
||||
shadow-rs = "0.11"
|
||||
|
||||
[dependencies.rsasl]
|
||||
git = "https://github.com/dequbed/rsasl.git"
|
||||
rev = "0b5012d0"
|
||||
@ -113,5 +121,8 @@ features = ["unstable_custom_mechanism", "provider", "registry_static", "plain"]
|
||||
futures-test = "0.3.16"
|
||||
tempfile = "3.2"
|
||||
|
||||
[build-dependencies]
|
||||
shadow-rs = "0.11"
|
||||
|
||||
[workspace]
|
||||
members = ["modules/*", "api"]
|
||||
members = ["runtime/*", "modules/*", "api"]
|
||||
|
26
INSTALL.md
26
INSTALL.md
@ -1,4 +1,4 @@
|
||||
## Installation
|
||||
# Installation
|
||||
|
||||
Currently there are no distribution packages available.
|
||||
However installation is reasonably straight-forward, since Diflouroborane compiles into a single
|
||||
@ -7,7 +7,7 @@ mostly static binary with few dependencies.
|
||||
At the moment only Linux is supported. If you managed to compile Diflouroborane please open an issue
|
||||
outlining your steps or add a merge request expanding this part. Thanks!
|
||||
|
||||
### Requirements
|
||||
## Requirements
|
||||
|
||||
General requirements; scroll down for distribution-specific instructions
|
||||
|
||||
@ -24,7 +24,7 @@ General requirements; scroll down for distribution-specific instructions
|
||||
$ pacman -S gsasl rust capnproto
|
||||
```
|
||||
|
||||
### Compiling from source
|
||||
## Compiling from source
|
||||
|
||||
Diflouroborane uses Cargo, so compilation boils down to:
|
||||
|
||||
@ -32,4 +32,22 @@ Diflouroborane uses Cargo, so compilation boils down to:
|
||||
$ cargo build --release
|
||||
```
|
||||
|
||||
The compiled binary can then be found in `./target/release/diflouroborane`
|
||||
The compiled binary can then be found in `./target/release/bffhd`
|
||||
|
||||
### Cross-compiling
|
||||
|
||||
If you need to compile for a different CPU target than your own (e.g. you want
|
||||
to use BFFH on a raspberry pi but compile on your desktop PC), you need to
|
||||
setup a cross-compilation toolchain and configure your Cargo correctly.
|
||||
[The `CONTRIBUTING.md` has a section on how to setup a cross-compilation system.](CONTRIBUTING.md#cross-compilation)
|
||||
|
||||
# Running bffhd
|
||||
|
||||
The server can be ran either using `cargo`, which will also compile the binary if necessary, or directly.
|
||||
|
||||
When running using `cargo` you need to pass arguments to bffh after a `--`, so
|
||||
e.g. `cargo run --release -- --help` or `cargo run --release -- -c examples/bffh.toml`.
|
||||
|
||||
When running directly the `bffhd` binary can be copied anywhere.
|
||||
|
||||
A list of arguments for the server is found in the help, so `bffhd --help` or `cargo run --release -- --help`.
|
||||
|
@ -1,10 +1,9 @@
|
||||
[package]
|
||||
name = "api"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
generated = []
|
||||
@ -17,4 +16,4 @@ capnpc = "0.14.4"
|
||||
[build-dependencies]
|
||||
capnpc = "0.14.4"
|
||||
# Used in build.rs to iterate over all files in schema/
|
||||
walkdir = "2.3.2"
|
||||
walkdir = "2.3.2"
|
33
api/build.rs
33
api/build.rs
@ -8,8 +8,7 @@ fn is_hidden(entry: &DirEntry) -> bool {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "gen_static"))]
|
||||
fn main() {
|
||||
fn generate_api() {
|
||||
println!("cargo:rerun-if-changed=schema");
|
||||
let mut compile_command = ::capnpc::CompilerCommand::new();
|
||||
compile_command
|
||||
@ -38,34 +37,6 @@ fn main() {
|
||||
compile_command.run().expect("Failed to generate API code");
|
||||
}
|
||||
|
||||
#[cfg(feature = "gen_static")]
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=schema");
|
||||
let mut compile_command = ::capnpc::CompilerCommand::new();
|
||||
compile_command
|
||||
.src_prefix("schema")
|
||||
.output_path("src/schema")
|
||||
.default_parent_module(vec!["schema".to_string()]);
|
||||
|
||||
for entry in WalkDir::new("schema")
|
||||
.max_depth(2)
|
||||
.into_iter()
|
||||
.filter_entry(|e| !is_hidden(e))
|
||||
.filter_map(Result::ok) // Filter all entries that access failed on
|
||||
.filter(|e| !e.file_type().is_dir()) // Filter directories
|
||||
// Filter non-schema files
|
||||
.filter(|e| {
|
||||
e.file_name()
|
||||
.to_str()
|
||||
.map(|s| s.ends_with(".capnp"))
|
||||
.unwrap_or(false)
|
||||
})
|
||||
{
|
||||
println!("Collecting schema file {}", entry.path().display());
|
||||
compile_command.file(entry.path());
|
||||
}
|
||||
|
||||
compile_command
|
||||
.run()
|
||||
.expect("Failed to generate extra API code");
|
||||
generate_api();
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 244eb9bd1b59cfcf36c067ff0d6208c0992766ba
|
||||
Subproject commit 19f20f5154f0eced6288ff56cac840025ee51da1
|
@ -1,71 +1,41 @@
|
||||
pub use capnpc::schema_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod authenticationsystem_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/authenticationsystem_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod authenticationsystem_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod connection_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/connection_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod connection_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod general_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/general_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod general_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod machine_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/machine_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod machine_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod machinesystem_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/machinesystem_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod machinesystem_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod permissionsystem_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/permissionsystem_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod permissionsystem_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod role_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/role_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod role_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod space_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/space_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod space_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod user_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/user_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod user_capnp;
|
||||
|
||||
#[cfg(feature = "generated")]
|
||||
pub mod usersystem_capnp {
|
||||
include!(concat!(env!("OUT_DIR"), "/usersystem_capnp.rs"));
|
||||
}
|
||||
#[cfg(not(feature = "generated"))]
|
||||
pub mod usersystem_capnp;
|
||||
|
@ -1,996 +0,0 @@
|
||||
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
|
||||
// DO NOT EDIT.
|
||||
// source: authenticationsystem.capnp
|
||||
|
||||
|
||||
pub mod response {
|
||||
pub use self::Which::{Failed,Challenge,Successful};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
pub fn has_challenge(&self) -> bool {
|
||||
if self.reader.get_data_field::<u16>(1) != 1 { return false; }
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn which(self) -> ::core::result::Result<WhichReader<'a,>, ::capnp::NotInSchema> {
|
||||
match self.reader.get_data_field::<u16>(1) {
|
||||
0 => {
|
||||
::core::result::Result::Ok(Failed(
|
||||
::capnp::traits::FromStructReader::new(self.reader)
|
||||
))
|
||||
}
|
||||
1 => {
|
||||
::core::result::Result::Ok(Challenge(
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
))
|
||||
}
|
||||
2 => {
|
||||
::core::result::Result::Ok(Successful(
|
||||
::capnp::traits::FromStructReader::new(self.reader)
|
||||
))
|
||||
}
|
||||
x => ::core::result::Result::Err(::capnp::NotInSchema(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_failed(self, ) -> crate::schema::authenticationsystem_capnp::response::failed::Builder<'a> {
|
||||
self.builder.set_data_field::<u16>(1, 0);
|
||||
self.builder.set_data_field::<u16>(0, 0u16);
|
||||
self.builder.get_pointer_field(0).clear();
|
||||
::capnp::traits::FromStructBuilder::new(self.builder)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_challenge(&mut self, value: ::capnp::data::Reader<'_>) {
|
||||
self.builder.set_data_field::<u16>(1, 1);
|
||||
self.builder.get_pointer_field(0).set_data(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_challenge(self, size: u32) -> ::capnp::data::Builder<'a> {
|
||||
self.builder.set_data_field::<u16>(1, 1);
|
||||
self.builder.get_pointer_field(0).init_data(size)
|
||||
}
|
||||
pub fn has_challenge(&self) -> bool {
|
||||
if self.builder.get_data_field::<u16>(1) != 1 { return false; }
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_successful(self, ) -> crate::schema::authenticationsystem_capnp::response::successful::Builder<'a> {
|
||||
self.builder.set_data_field::<u16>(1, 2);
|
||||
self.builder.get_pointer_field(0).clear();
|
||||
self.builder.get_pointer_field(1).clear();
|
||||
::capnp::traits::FromStructBuilder::new(self.builder)
|
||||
}
|
||||
#[inline]
|
||||
pub fn which(self) -> ::core::result::Result<WhichBuilder<'a,>, ::capnp::NotInSchema> {
|
||||
match self.builder.get_data_field::<u16>(1) {
|
||||
0 => {
|
||||
::core::result::Result::Ok(Failed(
|
||||
::capnp::traits::FromStructBuilder::new(self.builder)
|
||||
))
|
||||
}
|
||||
1 => {
|
||||
::core::result::Result::Ok(Challenge(
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
))
|
||||
}
|
||||
2 => {
|
||||
::core::result::Result::Ok(Successful(
|
||||
::capnp::traits::FromStructBuilder::new(self.builder)
|
||||
))
|
||||
}
|
||||
x => ::core::result::Result::Err(::capnp::NotInSchema(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 1, pointers: 2 };
|
||||
pub const TYPE_ID: u64 = 0xe76b_4158_bdde_4934;
|
||||
}
|
||||
pub enum Which<A0,A1,A2> {
|
||||
Failed(A0),
|
||||
Challenge(A1),
|
||||
Successful(A2),
|
||||
}
|
||||
pub type WhichReader<'a,> = Which<crate::schema::authenticationsystem_capnp::response::failed::Reader<'a>,::capnp::Result<::capnp::data::Reader<'a>>,crate::schema::authenticationsystem_capnp::response::successful::Reader<'a>>;
|
||||
pub type WhichBuilder<'a,> = Which<crate::schema::authenticationsystem_capnp::response::failed::Builder<'a>,::capnp::Result<::capnp::data::Builder<'a>>,crate::schema::authenticationsystem_capnp::response::successful::Builder<'a>>;
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
Aborted = 0,
|
||||
BadMechanism = 1,
|
||||
InvalidCredentials = 2,
|
||||
Failed = 3,
|
||||
}
|
||||
impl ::capnp::traits::FromU16 for Error {
|
||||
#[inline]
|
||||
fn from_u16(value: u16) -> ::core::result::Result<Error, ::capnp::NotInSchema> {
|
||||
match value {
|
||||
0 => ::core::result::Result::Ok(Error::Aborted),
|
||||
1 => ::core::result::Result::Ok(Error::BadMechanism),
|
||||
2 => ::core::result::Result::Ok(Error::InvalidCredentials),
|
||||
3 => ::core::result::Result::Ok(Error::Failed),
|
||||
n => ::core::result::Result::Err(::capnp::NotInSchema(n)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::capnp::traits::ToU16 for Error {
|
||||
#[inline]
|
||||
fn to_u16(self) -> u16 { self as u16 }
|
||||
}
|
||||
impl ::capnp::traits::HasTypeId for Error {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { 0xe87e_ae86_8b88_cfc1u64 }
|
||||
}
|
||||
|
||||
pub mod failed {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_code(self) -> ::core::result::Result<crate::schema::authenticationsystem_capnp::response::Error,::capnp::NotInSchema> {
|
||||
::capnp::traits::FromU16::from_u16(self.reader.get_data_field::<u16>(0))
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_additional_data(self) -> ::capnp::Result<::capnp::data::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_additional_data(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_code(self) -> ::core::result::Result<crate::schema::authenticationsystem_capnp::response::Error,::capnp::NotInSchema> {
|
||||
::capnp::traits::FromU16::from_u16(self.builder.get_data_field::<u16>(0))
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_code(&mut self, value: crate::schema::authenticationsystem_capnp::response::Error) {
|
||||
self.builder.set_data_field::<u16>(0, value as u16)
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_additional_data(self) -> ::capnp::Result<::capnp::data::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_additional_data(&mut self, value: ::capnp::data::Reader<'_>) {
|
||||
self.builder.get_pointer_field(0).set_data(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_additional_data(self, size: u32) -> ::capnp::data::Builder<'a> {
|
||||
self.builder.get_pointer_field(0).init_data(size)
|
||||
}
|
||||
pub fn has_additional_data(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 1, pointers: 2 };
|
||||
pub const TYPE_ID: u64 = 0xd726_d467_66b2_fd0c;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod successful {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_session(self) -> ::capnp::Result<crate::schema::connection_capnp::session::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_session(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_additional_data(self) -> ::capnp::Result<::capnp::data::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(1), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_additional_data(&self) -> bool {
|
||||
!self.reader.get_pointer_field(1).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_session(self) -> ::capnp::Result<crate::schema::connection_capnp::session::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_session(&mut self, value: crate::schema::connection_capnp::session::Reader<'_>) -> ::capnp::Result<()> {
|
||||
::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_session(self, ) -> crate::schema::connection_capnp::session::Builder<'a> {
|
||||
::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), 0)
|
||||
}
|
||||
pub fn has_session(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_additional_data(self) -> ::capnp::Result<::capnp::data::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(1), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_additional_data(&mut self, value: ::capnp::data::Reader<'_>) {
|
||||
self.builder.get_pointer_field(1).set_data(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_additional_data(self, size: u32) -> ::capnp::data::Builder<'a> {
|
||||
self.builder.get_pointer_field(1).init_data(size)
|
||||
}
|
||||
pub fn has_additional_data(&self) -> bool {
|
||||
!self.builder.get_pointer_field(1).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
pub fn get_session(&self) -> crate::schema::connection_capnp::session::Pipeline {
|
||||
::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(0))
|
||||
}
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 1, pointers: 2 };
|
||||
pub const TYPE_ID: u64 = 0xbf3b_c966_6eea_ffa0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub mod authentication {
|
||||
#![allow(unused_variables)]
|
||||
pub type StepParams<> = ::capnp::capability::Params<crate::schema::authenticationsystem_capnp::authentication::step_params::Owned>;
|
||||
pub type StepResults<> = ::capnp::capability::Results<crate::schema::authenticationsystem_capnp::response::Owned>;
|
||||
pub type AbortParams<> = ::capnp::capability::Params<crate::schema::authenticationsystem_capnp::authentication::abort_params::Owned>;
|
||||
pub type AbortResults<> = ::capnp::capability::Results<crate::schema::authenticationsystem_capnp::authentication::abort_results::Owned>;
|
||||
|
||||
pub struct Client {
|
||||
pub client: ::capnp::capability::Client,
|
||||
}
|
||||
impl ::capnp::capability::FromClientHook for Client {
|
||||
fn new(hook: Box<dyn (::capnp::private::capability::ClientHook)>) -> Client {
|
||||
Client { client: ::capnp::capability::Client::new(hook), }
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Client; type Builder = Client; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Client; }
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Client<> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, _default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Client<>> {
|
||||
::core::result::Result::Ok(::capnp::capability::FromClientHook::new(reader.get_capability()?))
|
||||
}
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Client<> {
|
||||
fn init_pointer(_builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Client<> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Client<>> {
|
||||
::core::result::Result::Ok(::capnp::capability::FromClientHook::new(builder.get_capability()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <> ::capnp::traits::SetPointerBuilder for Client<> {
|
||||
fn set_pointer_builder(pointer: ::capnp::private::layout::PointerBuilder<'_>, from: Client<>, _canonicalize: bool) -> ::capnp::Result<()> {
|
||||
pointer.set_capability(from.client.hook);
|
||||
::core::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
impl ::capnp::traits::HasTypeId for Client {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl Clone for Client {
|
||||
fn clone(&self) -> Client {
|
||||
Client { client: ::capnp::capability::Client::new(self.client.hook.add_ref()), }
|
||||
}
|
||||
}
|
||||
impl Client {
|
||||
pub fn step_request(&self) -> ::capnp::capability::Request<crate::schema::authenticationsystem_capnp::authentication::step_params::Owned,crate::schema::authenticationsystem_capnp::response::Owned> {
|
||||
self.client.new_call(_private::TYPE_ID, 0, None)
|
||||
}
|
||||
pub fn abort_request(&self) -> ::capnp::capability::Request<crate::schema::authenticationsystem_capnp::authentication::abort_params::Owned,crate::schema::authenticationsystem_capnp::authentication::abort_results::Owned> {
|
||||
self.client.new_call(_private::TYPE_ID, 1, None)
|
||||
}
|
||||
}
|
||||
pub trait Server<> {
|
||||
fn step(&mut self, _: StepParams<>, _: StepResults<>) -> ::capnp::capability::Promise<(), ::capnp::Error> { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("method not implemented".to_string())) }
|
||||
fn abort(&mut self, _: AbortParams<>, _: AbortResults<>) -> ::capnp::capability::Promise<(), ::capnp::Error> { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("method not implemented".to_string())) }
|
||||
}
|
||||
pub struct ServerDispatch<_T,> {
|
||||
pub server: _T,
|
||||
}
|
||||
impl <_S: Server + 'static, > ::capnp::capability::FromServer<_S> for Client {
|
||||
type Dispatch = ServerDispatch<_S, >;
|
||||
fn from_server(s: _S) -> ServerDispatch<_S, > {
|
||||
ServerDispatch { server: s, }
|
||||
}
|
||||
}
|
||||
impl <_T: Server> ::core::ops::Deref for ServerDispatch<_T> {
|
||||
type Target = _T;
|
||||
fn deref(&self) -> &_T { &self.server}
|
||||
}
|
||||
impl <_T: Server> ::core::ops::DerefMut for ServerDispatch<_T> {
|
||||
fn deref_mut(&mut self) -> &mut _T { &mut self.server}
|
||||
}
|
||||
impl <_T: Server> ::capnp::capability::Server for ServerDispatch<_T> {
|
||||
fn dispatch_call(&mut self, interface_id: u64, method_id: u16, params: ::capnp::capability::Params<::capnp::any_pointer::Owned>, results: ::capnp::capability::Results<::capnp::any_pointer::Owned>) -> ::capnp::capability::Promise<(), ::capnp::Error> {
|
||||
match interface_id {
|
||||
_private::TYPE_ID => ServerDispatch::<_T, >::dispatch_call_internal(&mut self.server, method_id, params, results),
|
||||
_ => { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("Method not implemented.".to_string())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
impl <_T :Server> ServerDispatch<_T> {
|
||||
pub fn dispatch_call_internal(server: &mut _T, method_id: u16, params: ::capnp::capability::Params<::capnp::any_pointer::Owned>, results: ::capnp::capability::Results<::capnp::any_pointer::Owned>) -> ::capnp::capability::Promise<(), ::capnp::Error> {
|
||||
match method_id {
|
||||
0 => server.step(::capnp::private::capability::internal_get_typed_params(params), ::capnp::private::capability::internal_get_typed_results(results)),
|
||||
1 => server.abort(::capnp::private::capability::internal_get_typed_params(params), ::capnp::private::capability::internal_get_typed_results(results)),
|
||||
_ => { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("Method not implemented.".to_string())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod _private {
|
||||
pub const TYPE_ID: u64 = 0xe657_e27e_b5ff_b1ad;
|
||||
}
|
||||
|
||||
pub mod step_params {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_data(self) -> ::capnp::Result<::capnp::data::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_data(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_data(self) -> ::capnp::Result<::capnp::data::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_data(&mut self, value: ::capnp::data::Reader<'_>) {
|
||||
self.builder.get_pointer_field(0).set_data(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_data(self, size: u32) -> ::capnp::data::Builder<'a> {
|
||||
self.builder.get_pointer_field(0).init_data(size)
|
||||
}
|
||||
pub fn has_data(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0xcb98_01a0_63fb_684e;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod abort_params {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 0 };
|
||||
pub const TYPE_ID: u64 = 0x9dbb_e5bb_dcce_a62c;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod abort_results {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 0 };
|
||||
pub const TYPE_ID: u64 = 0xce2f_5a64_8658_0299;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,699 +0,0 @@
|
||||
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
|
||||
// DO NOT EDIT.
|
||||
// source: general.capnp
|
||||
|
||||
|
||||
pub mod u_u_i_d {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_uuid0(self) -> u64 {
|
||||
self.reader.get_data_field::<u64>(0)
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_uuid1(self) -> u64 {
|
||||
self.reader.get_data_field::<u64>(1)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_uuid0(self) -> u64 {
|
||||
self.builder.get_data_field::<u64>(0)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_uuid0(&mut self, value: u64) {
|
||||
self.builder.set_data_field::<u64>(0, value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_uuid1(self) -> u64 {
|
||||
self.builder.get_data_field::<u64>(1)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_uuid1(&mut self, value: u64) {
|
||||
self.builder.set_data_field::<u64>(1, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 2, pointers: 0 };
|
||||
pub const TYPE_ID: u64 = 0xb01b_03d4_f827_7597;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod key_value_pair {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_key(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_value(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(1), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_value(&self) -> bool {
|
||||
!self.reader.get_pointer_field(1).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_key(&mut self, value: ::capnp::text::Reader<'_>) {
|
||||
self.builder.get_pointer_field(0).set_text(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_key(self, size: u32) -> ::capnp::text::Builder<'a> {
|
||||
self.builder.get_pointer_field(0).init_text(size)
|
||||
}
|
||||
pub fn has_key(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_value(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(1), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_value(&mut self, value: ::capnp::text::Reader<'_>) {
|
||||
self.builder.get_pointer_field(1).set_text(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_value(self, size: u32) -> ::capnp::text::Builder<'a> {
|
||||
self.builder.get_pointer_field(1).init_text(size)
|
||||
}
|
||||
pub fn has_value(&self) -> bool {
|
||||
!self.builder.get_pointer_field(1).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 2 };
|
||||
pub const TYPE_ID: u64 = 0xfb54_3b21_ce63_7bf1;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod optional { /* T */
|
||||
pub use self::Which::{Nothing,Just};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned<T> {
|
||||
_phantom: ::core::marker::PhantomData<T>
|
||||
}
|
||||
impl <'a, T> ::capnp::traits::Owned<'a> for Owned <T> where T: for<'c> ::capnp::traits::Owned<'c> { type Reader = Reader<'a, T>; type Builder = Builder<'a, T>; }
|
||||
impl <'a, T> ::capnp::traits::OwnedStruct<'a> for Owned <T> where T: for<'c> ::capnp::traits::Owned<'c> { type Reader = Reader<'a, T>; type Builder = Builder<'a, T>; }
|
||||
impl <T> ::capnp::traits::Pipelined for Owned<T> where T: for<'c> ::capnp::traits::Owned<'c> { type Pipeline = Pipeline<T>; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
reader: ::capnp::private::layout::StructReader<'a>,
|
||||
_phantom: ::core::marker::PhantomData<T>
|
||||
}
|
||||
|
||||
impl <'a,T> ::capnp::traits::HasTypeId for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,T> ::capnp::traits::FromStructReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,T> {
|
||||
Reader { reader, _phantom: ::core::marker::PhantomData, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T> ::capnp::traits::FromPointerReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,T>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T> ::capnp::traits::Imbue<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T> Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
pub fn reborrow(&self) -> Reader<'_,T> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
pub fn has_just(&self) -> bool {
|
||||
if self.reader.get_data_field::<u16>(0) != 1 { return false; }
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn which(self) -> ::core::result::Result<WhichReader<'a,T>, ::capnp::NotInSchema> {
|
||||
match self.reader.get_data_field::<u16>(0) {
|
||||
0 => {
|
||||
::core::result::Result::Ok(Nothing(
|
||||
()
|
||||
))
|
||||
}
|
||||
1 => {
|
||||
::core::result::Result::Ok(Just(
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
))
|
||||
}
|
||||
x => ::core::result::Result::Err(::capnp::NotInSchema(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
builder: ::capnp::private::layout::StructBuilder<'a>,
|
||||
_phantom: ::core::marker::PhantomData<T>
|
||||
}
|
||||
impl <'a,T> ::capnp::traits::HasStructSize for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,T> ::capnp::traits::HasTypeId for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,T> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, T> {
|
||||
Builder { builder, _phantom: ::core::marker::PhantomData, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T> ::capnp::traits::ImbueMut<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,T> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,T>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T> ::capnp::traits::SetPointerBuilder for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,T>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,T> Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c> {
|
||||
pub fn into_reader(self) -> Reader<'a,T> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,T> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,T> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_nothing(&mut self, _value: ()) {
|
||||
self.builder.set_data_field::<u16>(0, 0);
|
||||
}
|
||||
#[inline]
|
||||
pub fn initn_just(self, length: u32) -> <T as ::capnp::traits::Owned<'a>>::Builder {
|
||||
self.builder.set_data_field::<u16>(0, 1);
|
||||
::capnp::any_pointer::Builder::new(self.builder.get_pointer_field(0)).initn_as(length)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_just(&mut self, value: <T as ::capnp::traits::Owned<'_>>::Reader) -> ::capnp::Result<()> {
|
||||
self.builder.set_data_field::<u16>(0, 1);
|
||||
::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_just(self, ) -> <T as ::capnp::traits::Owned<'a>>::Builder {
|
||||
self.builder.set_data_field::<u16>(0, 1);
|
||||
::capnp::any_pointer::Builder::new(self.builder.get_pointer_field(0)).init_as()
|
||||
}
|
||||
pub fn has_just(&self) -> bool {
|
||||
if self.builder.get_data_field::<u16>(0) != 1 { return false; }
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn which(self) -> ::core::result::Result<WhichBuilder<'a,T>, ::capnp::NotInSchema> {
|
||||
match self.builder.get_data_field::<u16>(0) {
|
||||
0 => {
|
||||
::core::result::Result::Ok(Nothing(
|
||||
()
|
||||
))
|
||||
}
|
||||
1 => {
|
||||
::core::result::Result::Ok(Just(
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
))
|
||||
}
|
||||
x => ::core::result::Result::Err(::capnp::NotInSchema(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline<T> {
|
||||
_typeless: ::capnp::any_pointer::Pipeline,
|
||||
_phantom: ::core::marker::PhantomData<T>
|
||||
}
|
||||
impl<T> ::capnp::capability::FromTypelessPipeline for Pipeline<T> {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline<T> {
|
||||
Pipeline { _typeless: typeless, _phantom: ::core::marker::PhantomData, }
|
||||
}
|
||||
}
|
||||
impl<T> Pipeline<T> where T: ::capnp::traits::Pipelined, <T as ::capnp::traits::Pipelined>::Pipeline: ::capnp::capability::FromTypelessPipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 1, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0xd77e_cca2_05b0_6927;
|
||||
}
|
||||
pub enum Which<A0> {
|
||||
Nothing(()),
|
||||
Just(A0),
|
||||
}
|
||||
pub type WhichReader<'a,T> = Which<::capnp::Result<<T as ::capnp::traits::Owned<'a>>::Reader>>;
|
||||
pub type WhichBuilder<'a,T> = Which<::capnp::Result<<T as ::capnp::traits::Owned<'a>>::Builder>>;
|
||||
}
|
||||
|
||||
pub mod fallible { /* T,E */
|
||||
pub use self::Which::{Failed,Successful};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned<T,E> {
|
||||
_phantom: ::core::marker::PhantomData<(T,E)>
|
||||
}
|
||||
impl <'a, T,E> ::capnp::traits::Owned<'a> for Owned <T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> { type Reader = Reader<'a, T,E>; type Builder = Builder<'a, T,E>; }
|
||||
impl <'a, T,E> ::capnp::traits::OwnedStruct<'a> for Owned <T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> { type Reader = Reader<'a, T,E>; type Builder = Builder<'a, T,E>; }
|
||||
impl <T,E> ::capnp::traits::Pipelined for Owned<T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> { type Pipeline = Pipeline<T,E>; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
reader: ::capnp::private::layout::StructReader<'a>,
|
||||
_phantom: ::core::marker::PhantomData<(T,E)>
|
||||
}
|
||||
|
||||
impl <'a,T,E> ::capnp::traits::HasTypeId for Reader<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,T,E> ::capnp::traits::FromStructReader<'a> for Reader<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,T,E> {
|
||||
Reader { reader, _phantom: ::core::marker::PhantomData, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T,E> ::capnp::traits::FromPointerReader<'a> for Reader<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,T,E>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T,E> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T,E> ::capnp::traits::Imbue<'a> for Reader<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T,E> Reader<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
pub fn reborrow(&self) -> Reader<'_,T,E> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
pub fn has_failed(&self) -> bool {
|
||||
if self.reader.get_data_field::<u16>(0) != 0 { return false; }
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
pub fn has_successful(&self) -> bool {
|
||||
if self.reader.get_data_field::<u16>(0) != 1 { return false; }
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn which(self) -> ::core::result::Result<WhichReader<'a,T,E>, ::capnp::NotInSchema> {
|
||||
match self.reader.get_data_field::<u16>(0) {
|
||||
0 => {
|
||||
::core::result::Result::Ok(Failed(
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
))
|
||||
}
|
||||
1 => {
|
||||
::core::result::Result::Ok(Successful(
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
))
|
||||
}
|
||||
x => ::core::result::Result::Err(::capnp::NotInSchema(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
builder: ::capnp::private::layout::StructBuilder<'a>,
|
||||
_phantom: ::core::marker::PhantomData<(T,E)>
|
||||
}
|
||||
impl <'a,T,E> ::capnp::traits::HasStructSize for Builder<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,T,E> ::capnp::traits::HasTypeId for Builder<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,T,E> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, T,E> {
|
||||
Builder { builder, _phantom: ::core::marker::PhantomData, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T,E> ::capnp::traits::ImbueMut<'a> for Builder<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T,E> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,T,E> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,T,E>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,T,E> ::capnp::traits::SetPointerBuilder for Reader<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,T,E>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,T,E> Builder<'a,T,E> where T: for<'c> ::capnp::traits::Owned<'c>, E: for<'c> ::capnp::traits::Owned<'c> {
|
||||
pub fn into_reader(self) -> Reader<'a,T,E> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,T,E> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,T,E> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn initn_failed(self, length: u32) -> <E as ::capnp::traits::Owned<'a>>::Builder {
|
||||
self.builder.set_data_field::<u16>(0, 0);
|
||||
::capnp::any_pointer::Builder::new(self.builder.get_pointer_field(0)).initn_as(length)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_failed(&mut self, value: <E as ::capnp::traits::Owned<'_>>::Reader) -> ::capnp::Result<()> {
|
||||
self.builder.set_data_field::<u16>(0, 0);
|
||||
::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_failed(self, ) -> <E as ::capnp::traits::Owned<'a>>::Builder {
|
||||
self.builder.set_data_field::<u16>(0, 0);
|
||||
::capnp::any_pointer::Builder::new(self.builder.get_pointer_field(0)).init_as()
|
||||
}
|
||||
pub fn has_failed(&self) -> bool {
|
||||
if self.builder.get_data_field::<u16>(0) != 0 { return false; }
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn initn_successful(self, length: u32) -> <T as ::capnp::traits::Owned<'a>>::Builder {
|
||||
self.builder.set_data_field::<u16>(0, 1);
|
||||
::capnp::any_pointer::Builder::new(self.builder.get_pointer_field(0)).initn_as(length)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_successful(&mut self, value: <T as ::capnp::traits::Owned<'_>>::Reader) -> ::capnp::Result<()> {
|
||||
self.builder.set_data_field::<u16>(0, 1);
|
||||
::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_successful(self, ) -> <T as ::capnp::traits::Owned<'a>>::Builder {
|
||||
self.builder.set_data_field::<u16>(0, 1);
|
||||
::capnp::any_pointer::Builder::new(self.builder.get_pointer_field(0)).init_as()
|
||||
}
|
||||
pub fn has_successful(&self) -> bool {
|
||||
if self.builder.get_data_field::<u16>(0) != 1 { return false; }
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn which(self) -> ::core::result::Result<WhichBuilder<'a,T,E>, ::capnp::NotInSchema> {
|
||||
match self.builder.get_data_field::<u16>(0) {
|
||||
0 => {
|
||||
::core::result::Result::Ok(Failed(
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
))
|
||||
}
|
||||
1 => {
|
||||
::core::result::Result::Ok(Successful(
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
))
|
||||
}
|
||||
x => ::core::result::Result::Err(::capnp::NotInSchema(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline<T,E> {
|
||||
_typeless: ::capnp::any_pointer::Pipeline,
|
||||
_phantom: ::core::marker::PhantomData<(T,E)>
|
||||
}
|
||||
impl<T,E> ::capnp::capability::FromTypelessPipeline for Pipeline<T,E> {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline<T,E> {
|
||||
Pipeline { _typeless: typeless, _phantom: ::core::marker::PhantomData, }
|
||||
}
|
||||
}
|
||||
impl<T,E> Pipeline<T,E> where T: ::capnp::traits::Pipelined, <T as ::capnp::traits::Pipelined>::Pipeline: ::capnp::capability::FromTypelessPipeline, E: ::capnp::traits::Pipelined, <E as ::capnp::traits::Pipelined>::Pipeline: ::capnp::capability::FromTypelessPipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 1, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0xf477_aafa_9205_11aa;
|
||||
}
|
||||
pub enum Which<A0,A1> {
|
||||
Failed(A0),
|
||||
Successful(A1),
|
||||
}
|
||||
pub type WhichReader<'a,T,E> = Which<::capnp::Result<<E as ::capnp::traits::Owned<'a>>::Reader>,::capnp::Result<<T as ::capnp::traits::Owned<'a>>::Reader>>;
|
||||
pub type WhichBuilder<'a,T,E> = Which<::capnp::Result<<E as ::capnp::traits::Owned<'a>>::Builder>,::capnp::Result<<T as ::capnp::traits::Owned<'a>>::Builder>>;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,756 +0,0 @@
|
||||
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
|
||||
// DO NOT EDIT.
|
||||
// source: machinesystem.capnp
|
||||
|
||||
|
||||
pub mod machine_system {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_info(self) -> ::capnp::Result<crate::schema::machinesystem_capnp::machine_system::info::Client> {
|
||||
match self.reader.get_pointer_field(0).get_capability() { ::core::result::Result::Ok(c) => ::core::result::Result::Ok(::capnp::capability::FromClientHook::new(c)), ::core::result::Result::Err(e) => ::core::result::Result::Err(e)}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_info(self) -> ::capnp::Result<crate::schema::machinesystem_capnp::machine_system::info::Client> {
|
||||
match self.builder.get_pointer_field(0).get_capability() { ::core::result::Result::Ok(c) => ::core::result::Result::Ok(::capnp::capability::FromClientHook::new(c)), ::core::result::Result::Err(e) => ::core::result::Result::Err(e)}
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_info(&mut self, value: crate::schema::machinesystem_capnp::machine_system::info::Client) {
|
||||
self.builder.get_pointer_field(0).set_capability(value.client.hook);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
pub fn get_info(&self) -> crate::schema::machinesystem_capnp::machine_system::info::Client {
|
||||
::capnp::capability::FromClientHook::new(self._typeless.get_pointer_field(0).as_cap())
|
||||
}
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0x8771_90c7_e487_ddb6;
|
||||
}
|
||||
|
||||
|
||||
pub mod info {
|
||||
#![allow(unused_variables)]
|
||||
pub type GetMachineListParams<> = ::capnp::capability::Params<crate::schema::machinesystem_capnp::machine_system::info::get_machine_list_params::Owned>;
|
||||
pub type GetMachineListResults<> = ::capnp::capability::Results<crate::schema::machinesystem_capnp::machine_system::info::get_machine_list_results::Owned>;
|
||||
pub type GetMachineParams<> = ::capnp::capability::Params<crate::schema::machinesystem_capnp::machine_system::info::get_machine_params::Owned>;
|
||||
pub type GetMachineResults<> = ::capnp::capability::Results<crate::schema::general_capnp::optional::Owned<crate::schema::machine_capnp::machine::Owned>>;
|
||||
pub type GetMachineURNParams<> = ::capnp::capability::Params<crate::schema::machinesystem_capnp::machine_system::info::get_machine_u_r_n_params::Owned>;
|
||||
pub type GetMachineURNResults<> = ::capnp::capability::Results<crate::schema::general_capnp::optional::Owned<crate::schema::machine_capnp::machine::Owned>>;
|
||||
|
||||
pub struct Client {
|
||||
pub client: ::capnp::capability::Client,
|
||||
}
|
||||
impl ::capnp::capability::FromClientHook for Client {
|
||||
fn new(hook: Box<dyn (::capnp::private::capability::ClientHook)>) -> Client {
|
||||
Client { client: ::capnp::capability::Client::new(hook), }
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Client; type Builder = Client; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Client; }
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Client<> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, _default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Client<>> {
|
||||
::core::result::Result::Ok(::capnp::capability::FromClientHook::new(reader.get_capability()?))
|
||||
}
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Client<> {
|
||||
fn init_pointer(_builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Client<> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Client<>> {
|
||||
::core::result::Result::Ok(::capnp::capability::FromClientHook::new(builder.get_capability()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <> ::capnp::traits::SetPointerBuilder for Client<> {
|
||||
fn set_pointer_builder(pointer: ::capnp::private::layout::PointerBuilder<'_>, from: Client<>, _canonicalize: bool) -> ::capnp::Result<()> {
|
||||
pointer.set_capability(from.client.hook);
|
||||
::core::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
impl ::capnp::traits::HasTypeId for Client {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl Clone for Client {
|
||||
fn clone(&self) -> Client {
|
||||
Client { client: ::capnp::capability::Client::new(self.client.hook.add_ref()), }
|
||||
}
|
||||
}
|
||||
impl Client {
|
||||
pub fn get_machine_list_request(&self) -> ::capnp::capability::Request<crate::schema::machinesystem_capnp::machine_system::info::get_machine_list_params::Owned,crate::schema::machinesystem_capnp::machine_system::info::get_machine_list_results::Owned> {
|
||||
self.client.new_call(_private::TYPE_ID, 0, None)
|
||||
}
|
||||
pub fn get_machine_request(&self) -> ::capnp::capability::Request<crate::schema::machinesystem_capnp::machine_system::info::get_machine_params::Owned,crate::schema::general_capnp::optional::Owned<crate::schema::machine_capnp::machine::Owned>> {
|
||||
self.client.new_call(_private::TYPE_ID, 1, None)
|
||||
}
|
||||
pub fn get_machine_u_r_n_request(&self) -> ::capnp::capability::Request<crate::schema::machinesystem_capnp::machine_system::info::get_machine_u_r_n_params::Owned,crate::schema::general_capnp::optional::Owned<crate::schema::machine_capnp::machine::Owned>> {
|
||||
self.client.new_call(_private::TYPE_ID, 2, None)
|
||||
}
|
||||
}
|
||||
pub trait Server<> {
|
||||
fn get_machine_list(&mut self, _: GetMachineListParams<>, _: GetMachineListResults<>) -> ::capnp::capability::Promise<(), ::capnp::Error> { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("method not implemented".to_string())) }
|
||||
fn get_machine(&mut self, _: GetMachineParams<>, _: GetMachineResults<>) -> ::capnp::capability::Promise<(), ::capnp::Error> { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("method not implemented".to_string())) }
|
||||
fn get_machine_u_r_n(&mut self, _: GetMachineURNParams<>, _: GetMachineURNResults<>) -> ::capnp::capability::Promise<(), ::capnp::Error> { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("method not implemented".to_string())) }
|
||||
}
|
||||
pub struct ServerDispatch<_T,> {
|
||||
pub server: _T,
|
||||
}
|
||||
impl <_S: Server + 'static, > ::capnp::capability::FromServer<_S> for Client {
|
||||
type Dispatch = ServerDispatch<_S, >;
|
||||
fn from_server(s: _S) -> ServerDispatch<_S, > {
|
||||
ServerDispatch { server: s, }
|
||||
}
|
||||
}
|
||||
impl <_T: Server> ::core::ops::Deref for ServerDispatch<_T> {
|
||||
type Target = _T;
|
||||
fn deref(&self) -> &_T { &self.server}
|
||||
}
|
||||
impl <_T: Server> ::core::ops::DerefMut for ServerDispatch<_T> {
|
||||
fn deref_mut(&mut self) -> &mut _T { &mut self.server}
|
||||
}
|
||||
impl <_T: Server> ::capnp::capability::Server for ServerDispatch<_T> {
|
||||
fn dispatch_call(&mut self, interface_id: u64, method_id: u16, params: ::capnp::capability::Params<::capnp::any_pointer::Owned>, results: ::capnp::capability::Results<::capnp::any_pointer::Owned>) -> ::capnp::capability::Promise<(), ::capnp::Error> {
|
||||
match interface_id {
|
||||
_private::TYPE_ID => ServerDispatch::<_T, >::dispatch_call_internal(&mut self.server, method_id, params, results),
|
||||
_ => { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("Method not implemented.".to_string())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
impl <_T :Server> ServerDispatch<_T> {
|
||||
pub fn dispatch_call_internal(server: &mut _T, method_id: u16, params: ::capnp::capability::Params<::capnp::any_pointer::Owned>, results: ::capnp::capability::Results<::capnp::any_pointer::Owned>) -> ::capnp::capability::Promise<(), ::capnp::Error> {
|
||||
match method_id {
|
||||
0 => server.get_machine_list(::capnp::private::capability::internal_get_typed_params(params), ::capnp::private::capability::internal_get_typed_results(results)),
|
||||
1 => server.get_machine(::capnp::private::capability::internal_get_typed_params(params), ::capnp::private::capability::internal_get_typed_results(results)),
|
||||
2 => server.get_machine_u_r_n(::capnp::private::capability::internal_get_typed_params(params), ::capnp::private::capability::internal_get_typed_results(results)),
|
||||
_ => { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("Method not implemented.".to_string())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod _private {
|
||||
pub const TYPE_ID: u64 = 0xf8a1_a0ce_79e3_a4ae;
|
||||
}
|
||||
|
||||
pub mod get_machine_list_params {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 0 };
|
||||
pub const TYPE_ID: u64 = 0xae72_5a44_381c_cb81;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod get_machine_list_results {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_machine_list(self) -> ::capnp::Result<::capnp::struct_list::Reader<'a,crate::schema::machine_capnp::machine::Owned>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_machine_list(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_machine_list(self) -> ::capnp::Result<::capnp::struct_list::Builder<'a,crate::schema::machine_capnp::machine::Owned>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_machine_list(&mut self, value: ::capnp::struct_list::Reader<'a,crate::schema::machine_capnp::machine::Owned>) -> ::capnp::Result<()> {
|
||||
::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_machine_list(self, size: u32) -> ::capnp::struct_list::Builder<'a,crate::schema::machine_capnp::machine::Owned> {
|
||||
::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), size)
|
||||
}
|
||||
pub fn has_machine_list(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0x9964_3fc1_40c0_b2c1;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod get_machine_params {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_id(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_id(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_id(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_id(&mut self, value: ::capnp::text::Reader<'_>) {
|
||||
self.builder.get_pointer_field(0).set_text(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_id(self, size: u32) -> ::capnp::text::Builder<'a> {
|
||||
self.builder.get_pointer_field(0).init_text(size)
|
||||
}
|
||||
pub fn has_id(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0xe315_5a06_09f4_4bed;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod get_machine_u_r_n_params {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_urn(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_urn(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_urn(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_urn(&mut self, value: ::capnp::text::Reader<'_>) {
|
||||
self.builder.get_pointer_field(0).set_text(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_urn(self, size: u32) -> ::capnp::text::Builder<'a> {
|
||||
self.builder.get_pointer_field(0).init_text(size)
|
||||
}
|
||||
pub fn has_urn(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0xeb9d_c2e7_8963_51aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,572 +0,0 @@
|
||||
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
|
||||
// DO NOT EDIT.
|
||||
// source: permissionsystem.capnp
|
||||
|
||||
|
||||
pub mod permission_system {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_info(self) -> ::capnp::Result<crate::schema::permissionsystem_capnp::permission_system::info::Client> {
|
||||
match self.reader.get_pointer_field(0).get_capability() { ::core::result::Result::Ok(c) => ::core::result::Result::Ok(::capnp::capability::FromClientHook::new(c)), ::core::result::Result::Err(e) => ::core::result::Result::Err(e)}
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_manage(self) -> ::capnp::Result<crate::schema::permissionsystem_capnp::permission_system::manage::Client> {
|
||||
match self.reader.get_pointer_field(1).get_capability() { ::core::result::Result::Ok(c) => ::core::result::Result::Ok(::capnp::capability::FromClientHook::new(c)), ::core::result::Result::Err(e) => ::core::result::Result::Err(e)}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_info(self) -> ::capnp::Result<crate::schema::permissionsystem_capnp::permission_system::info::Client> {
|
||||
match self.builder.get_pointer_field(0).get_capability() { ::core::result::Result::Ok(c) => ::core::result::Result::Ok(::capnp::capability::FromClientHook::new(c)), ::core::result::Result::Err(e) => ::core::result::Result::Err(e)}
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_info(&mut self, value: crate::schema::permissionsystem_capnp::permission_system::info::Client) {
|
||||
self.builder.get_pointer_field(0).set_capability(value.client.hook);
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_manage(self) -> ::capnp::Result<crate::schema::permissionsystem_capnp::permission_system::manage::Client> {
|
||||
match self.builder.get_pointer_field(1).get_capability() { ::core::result::Result::Ok(c) => ::core::result::Result::Ok(::capnp::capability::FromClientHook::new(c)), ::core::result::Result::Err(e) => ::core::result::Result::Err(e)}
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_manage(&mut self, value: crate::schema::permissionsystem_capnp::permission_system::manage::Client) {
|
||||
self.builder.get_pointer_field(1).set_capability(value.client.hook);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
pub fn get_info(&self) -> crate::schema::permissionsystem_capnp::permission_system::info::Client {
|
||||
::capnp::capability::FromClientHook::new(self._typeless.get_pointer_field(0).as_cap())
|
||||
}
|
||||
pub fn get_manage(&self) -> crate::schema::permissionsystem_capnp::permission_system::manage::Client {
|
||||
::capnp::capability::FromClientHook::new(self._typeless.get_pointer_field(1).as_cap())
|
||||
}
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 2 };
|
||||
pub const TYPE_ID: u64 = 0xcafb_f059_d7a0_0c3b;
|
||||
}
|
||||
|
||||
|
||||
pub mod info {
|
||||
#![allow(unused_variables)]
|
||||
pub type GetRoleListParams<> = ::capnp::capability::Params<crate::schema::permissionsystem_capnp::permission_system::info::get_role_list_params::Owned>;
|
||||
pub type GetRoleListResults<> = ::capnp::capability::Results<crate::schema::permissionsystem_capnp::permission_system::info::get_role_list_results::Owned>;
|
||||
|
||||
pub struct Client {
|
||||
pub client: ::capnp::capability::Client,
|
||||
}
|
||||
impl ::capnp::capability::FromClientHook for Client {
|
||||
fn new(hook: Box<dyn (::capnp::private::capability::ClientHook)>) -> Client {
|
||||
Client { client: ::capnp::capability::Client::new(hook), }
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Client; type Builder = Client; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Client; }
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Client<> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, _default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Client<>> {
|
||||
::core::result::Result::Ok(::capnp::capability::FromClientHook::new(reader.get_capability()?))
|
||||
}
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Client<> {
|
||||
fn init_pointer(_builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Client<> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Client<>> {
|
||||
::core::result::Result::Ok(::capnp::capability::FromClientHook::new(builder.get_capability()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <> ::capnp::traits::SetPointerBuilder for Client<> {
|
||||
fn set_pointer_builder(pointer: ::capnp::private::layout::PointerBuilder<'_>, from: Client<>, _canonicalize: bool) -> ::capnp::Result<()> {
|
||||
pointer.set_capability(from.client.hook);
|
||||
::core::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
impl ::capnp::traits::HasTypeId for Client {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl Clone for Client {
|
||||
fn clone(&self) -> Client {
|
||||
Client { client: ::capnp::capability::Client::new(self.client.hook.add_ref()), }
|
||||
}
|
||||
}
|
||||
impl Client {
|
||||
pub fn get_role_list_request(&self) -> ::capnp::capability::Request<crate::schema::permissionsystem_capnp::permission_system::info::get_role_list_params::Owned,crate::schema::permissionsystem_capnp::permission_system::info::get_role_list_results::Owned> {
|
||||
self.client.new_call(_private::TYPE_ID, 0, None)
|
||||
}
|
||||
}
|
||||
pub trait Server<> {
|
||||
fn get_role_list(&mut self, _: GetRoleListParams<>, _: GetRoleListResults<>) -> ::capnp::capability::Promise<(), ::capnp::Error> { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("method not implemented".to_string())) }
|
||||
}
|
||||
pub struct ServerDispatch<_T,> {
|
||||
pub server: _T,
|
||||
}
|
||||
impl <_S: Server + 'static, > ::capnp::capability::FromServer<_S> for Client {
|
||||
type Dispatch = ServerDispatch<_S, >;
|
||||
fn from_server(s: _S) -> ServerDispatch<_S, > {
|
||||
ServerDispatch { server: s, }
|
||||
}
|
||||
}
|
||||
impl <_T: Server> ::core::ops::Deref for ServerDispatch<_T> {
|
||||
type Target = _T;
|
||||
fn deref(&self) -> &_T { &self.server}
|
||||
}
|
||||
impl <_T: Server> ::core::ops::DerefMut for ServerDispatch<_T> {
|
||||
fn deref_mut(&mut self) -> &mut _T { &mut self.server}
|
||||
}
|
||||
impl <_T: Server> ::capnp::capability::Server for ServerDispatch<_T> {
|
||||
fn dispatch_call(&mut self, interface_id: u64, method_id: u16, params: ::capnp::capability::Params<::capnp::any_pointer::Owned>, results: ::capnp::capability::Results<::capnp::any_pointer::Owned>) -> ::capnp::capability::Promise<(), ::capnp::Error> {
|
||||
match interface_id {
|
||||
_private::TYPE_ID => ServerDispatch::<_T, >::dispatch_call_internal(&mut self.server, method_id, params, results),
|
||||
_ => { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("Method not implemented.".to_string())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
impl <_T :Server> ServerDispatch<_T> {
|
||||
pub fn dispatch_call_internal(server: &mut _T, method_id: u16, params: ::capnp::capability::Params<::capnp::any_pointer::Owned>, results: ::capnp::capability::Results<::capnp::any_pointer::Owned>) -> ::capnp::capability::Promise<(), ::capnp::Error> {
|
||||
match method_id {
|
||||
0 => server.get_role_list(::capnp::private::capability::internal_get_typed_params(params), ::capnp::private::capability::internal_get_typed_results(results)),
|
||||
_ => { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("Method not implemented.".to_string())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod _private {
|
||||
pub const TYPE_ID: u64 = 0xdff7_7e8f_ec2d_a43b;
|
||||
}
|
||||
|
||||
pub mod get_role_list_params {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 0 };
|
||||
pub const TYPE_ID: u64 = 0xd5b5_fb0f_7259_c89b;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod get_role_list_results {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_role_list(self) -> ::capnp::Result<::capnp::struct_list::Reader<'a,crate::schema::role_capnp::role::Owned>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_role_list(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_role_list(self) -> ::capnp::Result<::capnp::struct_list::Builder<'a,crate::schema::role_capnp::role::Owned>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_role_list(&mut self, value: ::capnp::struct_list::Reader<'a,crate::schema::role_capnp::role::Owned>) -> ::capnp::Result<()> {
|
||||
::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_role_list(self, size: u32) -> ::capnp::struct_list::Builder<'a,crate::schema::role_capnp::role::Owned> {
|
||||
::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), size)
|
||||
}
|
||||
pub fn has_role_list(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0xc506_980d_e52d_5ab2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub mod manage {
|
||||
#![allow(unused_variables)]
|
||||
|
||||
pub struct Client {
|
||||
pub client: ::capnp::capability::Client,
|
||||
}
|
||||
impl ::capnp::capability::FromClientHook for Client {
|
||||
fn new(hook: Box<dyn (::capnp::private::capability::ClientHook)>) -> Client {
|
||||
Client { client: ::capnp::capability::Client::new(hook), }
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Client; type Builder = Client; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Client; }
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Client<> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, _default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Client<>> {
|
||||
::core::result::Result::Ok(::capnp::capability::FromClientHook::new(reader.get_capability()?))
|
||||
}
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Client<> {
|
||||
fn init_pointer(_builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Client<> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Client<>> {
|
||||
::core::result::Result::Ok(::capnp::capability::FromClientHook::new(builder.get_capability()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <> ::capnp::traits::SetPointerBuilder for Client<> {
|
||||
fn set_pointer_builder(pointer: ::capnp::private::layout::PointerBuilder<'_>, from: Client<>, _canonicalize: bool) -> ::capnp::Result<()> {
|
||||
pointer.set_capability(from.client.hook);
|
||||
::core::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
impl ::capnp::traits::HasTypeId for Client {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl Clone for Client {
|
||||
fn clone(&self) -> Client {
|
||||
Client { client: ::capnp::capability::Client::new(self.client.hook.add_ref()), }
|
||||
}
|
||||
}
|
||||
impl Client {
|
||||
}
|
||||
pub trait Server<> {
|
||||
}
|
||||
pub struct ServerDispatch<_T,> {
|
||||
pub server: _T,
|
||||
}
|
||||
impl <_S: Server + 'static, > ::capnp::capability::FromServer<_S> for Client {
|
||||
type Dispatch = ServerDispatch<_S, >;
|
||||
fn from_server(s: _S) -> ServerDispatch<_S, > {
|
||||
ServerDispatch { server: s, }
|
||||
}
|
||||
}
|
||||
impl <_T: Server> ::core::ops::Deref for ServerDispatch<_T> {
|
||||
type Target = _T;
|
||||
fn deref(&self) -> &_T { &self.server}
|
||||
}
|
||||
impl <_T: Server> ::core::ops::DerefMut for ServerDispatch<_T> {
|
||||
fn deref_mut(&mut self) -> &mut _T { &mut self.server}
|
||||
}
|
||||
impl <_T: Server> ::capnp::capability::Server for ServerDispatch<_T> {
|
||||
fn dispatch_call(&mut self, interface_id: u64, method_id: u16, params: ::capnp::capability::Params<::capnp::any_pointer::Owned>, results: ::capnp::capability::Results<::capnp::any_pointer::Owned>) -> ::capnp::capability::Promise<(), ::capnp::Error> {
|
||||
match interface_id {
|
||||
_private::TYPE_ID => ServerDispatch::<_T, >::dispatch_call_internal(&mut self.server, method_id, params, results),
|
||||
_ => { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("Method not implemented.".to_string())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
impl <_T :Server> ServerDispatch<_T> {
|
||||
pub fn dispatch_call_internal(server: &mut _T, method_id: u16, params: ::capnp::capability::Params<::capnp::any_pointer::Owned>, results: ::capnp::capability::Results<::capnp::any_pointer::Owned>) -> ::capnp::capability::Promise<(), ::capnp::Error> {
|
||||
match method_id {
|
||||
_ => { ::capnp::capability::Promise::err(::capnp::Error::unimplemented("Method not implemented.".to_string())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod _private {
|
||||
pub const TYPE_ID: u64 = 0xfd2c_0c85_d50a_57e6;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
|
||||
// DO NOT EDIT.
|
||||
// source: programming_language/csharp.capnp
|
||||
|
||||
|
||||
#[repr(u16)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum TypeVisibility {
|
||||
Public = 0,
|
||||
Internal = 1,
|
||||
}
|
||||
impl ::capnp::traits::FromU16 for TypeVisibility {
|
||||
#[inline]
|
||||
fn from_u16(value: u16) -> ::core::result::Result<TypeVisibility, ::capnp::NotInSchema> {
|
||||
match value {
|
||||
0 => ::core::result::Result::Ok(TypeVisibility::Public),
|
||||
1 => ::core::result::Result::Ok(TypeVisibility::Internal),
|
||||
n => ::core::result::Result::Err(::capnp::NotInSchema(n)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::capnp::traits::ToU16 for TypeVisibility {
|
||||
#[inline]
|
||||
fn to_u16(self) -> u16 { self as u16 }
|
||||
}
|
||||
impl ::capnp::traits::HasTypeId for TypeVisibility {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { 0xeb0d_8316_68c6_eda5u64 }
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
|
||||
// DO NOT EDIT.
|
||||
// source: programming_language/rust.capnp
|
||||
|
@ -1,139 +0,0 @@
|
||||
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
|
||||
// DO NOT EDIT.
|
||||
// source: role.capnp
|
||||
|
||||
|
||||
pub mod role {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_name(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_name(&mut self, value: ::capnp::text::Reader<'_>) {
|
||||
self.builder.get_pointer_field(0).set_text(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> {
|
||||
self.builder.get_pointer_field(0).init_text(size)
|
||||
}
|
||||
pub fn has_name(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
|
||||
pub const TYPE_ID: u64 = 0xd53a_c00e_04e0_4b2d;
|
||||
}
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
|
||||
// DO NOT EDIT.
|
||||
// source: space.capnp
|
||||
|
||||
|
||||
pub mod space {
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Owned(());
|
||||
impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
|
||||
impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
|
||||
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,> {
|
||||
fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
|
||||
Reader { reader, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,> {
|
||||
fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,> {
|
||||
fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
|
||||
self.reader
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,> {
|
||||
fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
|
||||
self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> Reader<'a,> {
|
||||
pub fn reborrow(&self) -> Reader<'_,> {
|
||||
Reader { .. *self }
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_id(self) -> ::capnp::Result<crate::schema::general_capnp::u_u_i_d::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_id(&self) -> bool {
|
||||
!self.reader.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(1), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_name(&self) -> bool {
|
||||
!self.reader.get_pointer_field(1).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_info(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
|
||||
::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(2), ::core::option::Option::None)
|
||||
}
|
||||
pub fn has_info(&self) -> bool {
|
||||
!self.reader.get_pointer_field(2).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
|
||||
impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,> {
|
||||
#[inline]
|
||||
fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,> {
|
||||
#[inline]
|
||||
fn type_id() -> u64 { _private::TYPE_ID }
|
||||
}
|
||||
impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,> {
|
||||
fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
|
||||
Builder { builder, }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,> {
|
||||
fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
|
||||
self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,> {
|
||||
fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
|
||||
::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
|
||||
}
|
||||
fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
|
||||
::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,> {
|
||||
fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
|
||||
}
|
||||
|
||||
impl <'a,> Builder<'a,> {
|
||||
pub fn into_reader(self) -> Reader<'a,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
pub fn reborrow(&mut self) -> Builder<'_,> {
|
||||
Builder { .. *self }
|
||||
}
|
||||
pub fn reborrow_as_reader(&self) -> Reader<'_,> {
|
||||
::capnp::traits::FromStructReader::new(self.builder.into_reader())
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
|
||||
self.builder.into_reader().total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_id(self) -> ::capnp::Result<crate::schema::general_capnp::u_u_i_d::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_id(&mut self, value: crate::schema::general_capnp::u_u_i_d::Reader<'_>) -> ::capnp::Result<()> {
|
||||
::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_id(self, ) -> crate::schema::general_capnp::u_u_i_d::Builder<'a> {
|
||||
::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), 0)
|
||||
}
|
||||
pub fn has_id(&self) -> bool {
|
||||
!self.builder.get_pointer_field(0).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(1), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_name(&mut self, value: ::capnp::text::Reader<'_>) {
|
||||
self.builder.get_pointer_field(1).set_text(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> {
|
||||
self.builder.get_pointer_field(1).init_text(size)
|
||||
}
|
||||
pub fn has_name(&self) -> bool {
|
||||
!self.builder.get_pointer_field(1).is_null()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_info(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
|
||||
::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(2), ::core::option::Option::None)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_info(&mut self, value: ::capnp::text::Reader<'_>) {
|
||||
self.builder.get_pointer_field(2).set_text(value);
|
||||
}
|
||||
#[inline]
|
||||
pub fn init_info(self, size: u32) -> ::capnp::text::Builder<'a> {
|
||||
self.builder.get_pointer_field(2).init_text(size)
|
||||
}
|
||||
pub fn has_info(&self) -> bool {
|
||||
!self.builder.get_pointer_field(2).is_null()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
|
||||
impl ::capnp::capability::FromTypelessPipeline for Pipeline {
|
||||
fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
|
||||
Pipeline { _typeless: typeless, }
|
||||
}
|
||||
}
|
||||
impl Pipeline {
|
||||
pub fn get_id(&self) -> crate::schema::general_capnp::u_u_i_d::Pipeline {
|
||||
::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(0))
|
||||
}
|
||||
}
|
||||
mod _private {
|
||||
use capnp::private::layout;
|
||||
pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 3 };
|
||||
pub const TYPE_ID: u64 = 0x9e5f_9a6a_0528_b772;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@ use std::future::Future;
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
use miette::IntoDiagnostic;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
|
||||
@ -110,11 +111,11 @@ static ROOT_CERTS: Lazy<RootCertStore> = Lazy::new(|| {
|
||||
store
|
||||
});
|
||||
|
||||
pub fn load(executor: Executor, config: &Config, resources: ResourcesHandle) -> anyhow::Result<()> {
|
||||
pub fn load(executor: Executor, config: &Config, resources: ResourcesHandle) -> miette::Result<()> {
|
||||
let span = tracing::info_span!("loading actors");
|
||||
let _guard = span;
|
||||
|
||||
let mqtt_url = Url::parse(config.mqtt_url.as_str())?;
|
||||
let mqtt_url = Url::parse(config.mqtt_url.as_str()).into_diagnostic()?;
|
||||
let (transport, default_port) = match mqtt_url.scheme() {
|
||||
"mqtts" | "ssl" => (
|
||||
rumqttc::Transport::tls_with_config(
|
||||
@ -131,12 +132,12 @@ pub fn load(executor: Executor, config: &Config, resources: ResourcesHandle) ->
|
||||
|
||||
scheme => {
|
||||
tracing::error!(%scheme, "MQTT url uses invalid scheme");
|
||||
anyhow::bail!("invalid config");
|
||||
miette::bail!("invalid config");
|
||||
}
|
||||
};
|
||||
let host = mqtt_url.host_str().ok_or_else(|| {
|
||||
tracing::error!("MQTT url must contain a hostname");
|
||||
anyhow::anyhow!("invalid config")
|
||||
miette::miette!("invalid config")
|
||||
})?;
|
||||
let port = mqtt_url.port().unwrap_or(default_port);
|
||||
|
||||
@ -167,7 +168,7 @@ pub fn load(executor: Executor, config: &Config, resources: ResourcesHandle) ->
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!(?error, "MQTT connection failed");
|
||||
anyhow::bail!("mqtt connection failed")
|
||||
miette::bail!("mqtt connection failed")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ use serde_json::Serializer;
|
||||
|
||||
pub static AUDIT: OnceCell<AuditLog> = OnceCell::new();
|
||||
|
||||
// TODO: Make the audit log a tracing layer
|
||||
#[derive(Debug)]
|
||||
pub struct AuditLog {
|
||||
writer: Mutex<LineWriter<File>>,
|
||||
@ -51,7 +52,7 @@ impl AuditLog {
|
||||
let mut ser = Serializer::new(&mut writer);
|
||||
line.serialize(&mut ser)
|
||||
.expect("failed to serialize audit log line");
|
||||
writer.write("\n".as_bytes())?;
|
||||
writer.write_all("\n".as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ impl FabFire {
|
||||
card_info: None,
|
||||
key_info: None,
|
||||
auth_info: None,
|
||||
app_id: 1,
|
||||
app_id: 0x464142,
|
||||
local_urn: "urn:fabaccess:lab:innovisionlab".to_string(),
|
||||
desfire: Desfire {
|
||||
card: None,
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::users::Users;
|
||||
use miette::{Context, IntoDiagnostic};
|
||||
use rsasl::error::SessionError;
|
||||
use rsasl::mechname::Mechname;
|
||||
use rsasl::property::{AuthId, Password};
|
||||
@ -127,8 +128,13 @@ impl AuthenticationHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&self, mechanism: &Mechname) -> anyhow::Result<Session> {
|
||||
Ok(self.inner.rsasl.server_start(mechanism)?)
|
||||
pub fn start(&self, mechanism: &Mechname) -> miette::Result<Session> {
|
||||
Ok(self
|
||||
.inner
|
||||
.rsasl
|
||||
.server_start(mechanism)
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to start a SASL authentication with the given mechanism")?)
|
||||
}
|
||||
|
||||
pub fn list_available_mechs(&self) -> impl IntoIterator<Item = &Mechname> {
|
||||
|
@ -27,6 +27,10 @@ impl Roles {
|
||||
self.roles.get(roleid)
|
||||
}
|
||||
|
||||
pub fn list(&self) -> impl Iterator<Item = &String> {
|
||||
self.roles.keys()
|
||||
}
|
||||
|
||||
/// Tally a role dependency tree into a set
|
||||
///
|
||||
/// A Default implementation exists which adapter may overwrite with more efficient
|
||||
@ -67,17 +71,20 @@ impl Roles {
|
||||
role_id: &String,
|
||||
perm: &Permission,
|
||||
) -> bool {
|
||||
let _guard = tracing::debug_span!("tally", %role_id, perm=perm.as_str());
|
||||
if let Some(role) = self.get(role_id) {
|
||||
// Only check and tally parents of a role at the role itself if it's the first time we
|
||||
// see it
|
||||
if !roles.contains(role_id) {
|
||||
for perm_rule in role.permissions.iter() {
|
||||
if perm_rule.match_perm(perm) {
|
||||
tracing::debug!("Permission granted by direct role");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for parent in role.parents.iter() {
|
||||
if self.permitted_tally(roles, parent, perm) {
|
||||
tracing::debug!(%parent, "Permission granted by parent role");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -86,10 +93,13 @@ impl Roles {
|
||||
}
|
||||
}
|
||||
|
||||
tracing::trace!(%role_id, "Permission not granted by role");
|
||||
false
|
||||
}
|
||||
|
||||
pub fn is_permitted(&self, user: &UserData, perm: impl AsRef<Permission>) -> bool {
|
||||
let perm = perm.as_ref();
|
||||
tracing::debug!(perm = perm.as_str(), "Checking permission");
|
||||
let mut seen = HashSet::new();
|
||||
for role_id in user.roles.iter() {
|
||||
if self.permitted_tally(&mut seen, role_id, perm.as_ref()) {
|
||||
|
@ -1,9 +1,13 @@
|
||||
use capnp::capability::Promise;
|
||||
use capnp::Error;
|
||||
use capnp_rpc::pry;
|
||||
use rsasl::mechname::Mechname;
|
||||
use rsasl::property::AuthId;
|
||||
use rsasl::session::{Session, Step};
|
||||
use std::fmt;
|
||||
use std::fmt::{Formatter, Write};
|
||||
use std::io::Cursor;
|
||||
use tracing::Span;
|
||||
|
||||
use crate::capnp::session::APISession;
|
||||
use crate::session::SessionManager;
|
||||
@ -12,19 +16,46 @@ use api::authenticationsystem_capnp::authentication::{
|
||||
};
|
||||
use api::authenticationsystem_capnp::{response, response::Error as ErrorCode};
|
||||
|
||||
const TARGET: &str = "bffh::api::authenticationsystem";
|
||||
|
||||
pub struct Authentication {
|
||||
span: Span,
|
||||
state: State,
|
||||
}
|
||||
|
||||
impl Authentication {
|
||||
pub fn new(session: Session, sessionmanager: SessionManager) -> Self {
|
||||
pub fn new(
|
||||
parent: &Span,
|
||||
mechanism: &Mechname, /* TODO: this is stored in session as well, get it out of there. */
|
||||
session: Session,
|
||||
sessionmanager: SessionManager,
|
||||
) -> Self {
|
||||
let span = tracing::info_span!(
|
||||
target: TARGET,
|
||||
parent: parent,
|
||||
"Authentication",
|
||||
mechanism = mechanism.as_str()
|
||||
);
|
||||
tracing::trace!(
|
||||
target: TARGET,
|
||||
parent: &span,
|
||||
"constructing valid authentication system"
|
||||
);
|
||||
Self {
|
||||
span,
|
||||
state: State::Running(session, sessionmanager),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invalid_mechanism() -> Self {
|
||||
let span = tracing::info_span!(target: TARGET, "Authentication",);
|
||||
tracing::trace!(
|
||||
target: TARGET,
|
||||
parent: &span,
|
||||
"constructing invalid mechanism authentication system"
|
||||
);
|
||||
Self {
|
||||
span,
|
||||
state: State::InvalidMechanism,
|
||||
}
|
||||
}
|
||||
@ -44,6 +75,19 @@ impl Authentication {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Authentication {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("Authentication(")?;
|
||||
match &self.state {
|
||||
State::InvalidMechanism => f.write_str("invalid mechanism")?,
|
||||
State::Finished => f.write_str("finished")?,
|
||||
State::Aborted => f.write_str("aborted")?,
|
||||
State::Running(_, _) => f.write_str("running")?,
|
||||
}
|
||||
f.write_char(')')
|
||||
}
|
||||
}
|
||||
|
||||
enum State {
|
||||
InvalidMechanism,
|
||||
Finished,
|
||||
@ -53,24 +97,49 @@ enum State {
|
||||
|
||||
impl AuthenticationSystem for Authentication {
|
||||
fn step(&mut self, params: StepParams, mut results: StepResults) -> Promise<(), Error> {
|
||||
let span = tracing::trace_span!("step");
|
||||
let _guard = span.enter();
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(target: TARGET, "step",).entered();
|
||||
|
||||
tracing::trace!(params.data = "<authentication data>", "method call");
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Response {
|
||||
union_field: &'static str,
|
||||
}
|
||||
impl fmt::Display for Response {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("Response(")?;
|
||||
f.write_str(self.union_field)?;
|
||||
f.write_char(')')
|
||||
}
|
||||
}
|
||||
let mut response;
|
||||
|
||||
let mut builder = results.get();
|
||||
if let State::Running(mut session, manager) =
|
||||
std::mem::replace(&mut self.state, State::Aborted)
|
||||
{
|
||||
let data: &[u8] = pry!(pry!(params.get()).get_data());
|
||||
|
||||
let mut out = Cursor::new(Vec::new());
|
||||
match session.step(Some(data), &mut out) {
|
||||
Ok(Step::Done(data)) => {
|
||||
self.state = State::Finished;
|
||||
|
||||
let uid = pry!(session.get_property::<AuthId>().ok_or(capnp::Error::failed(
|
||||
"Authentication didn't provide an authid as required".to_string()
|
||||
)));
|
||||
let session = pry!(manager.open(uid.as_ref()).ok_or(capnp::Error::failed(
|
||||
"Failed to lookup the given user".to_string()
|
||||
)));
|
||||
let uid = pry!(session.get_property::<AuthId>().ok_or_else(|| {
|
||||
tracing::warn!("Authentication didn't provide an authid as required.");
|
||||
capnp::Error::failed(
|
||||
"Authentication didn't provide an authid as required".to_string(),
|
||||
)
|
||||
}));
|
||||
let session = pry!(manager.open(&self.span, uid.as_ref()).ok_or_else(|| {
|
||||
tracing::warn!(uid = uid.as_str(), "Failed to lookup the given user");
|
||||
capnp::Error::failed("Failed to lookup the given user".to_string())
|
||||
}));
|
||||
|
||||
response = Response {
|
||||
union_field: "successful",
|
||||
};
|
||||
|
||||
let mut builder = builder.init_successful();
|
||||
if data.is_some() {
|
||||
@ -82,21 +151,49 @@ impl AuthenticationSystem for Authentication {
|
||||
Ok(Step::NeedsMore(_)) => {
|
||||
self.state = State::Running(session, manager);
|
||||
builder.set_challenge(out.into_inner().as_slice());
|
||||
|
||||
response = Response {
|
||||
union_field: "challenge",
|
||||
};
|
||||
}
|
||||
Err(_) => {
|
||||
self.state = State::Aborted;
|
||||
self.build_error(builder);
|
||||
|
||||
response = Response {
|
||||
union_field: "error",
|
||||
};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.build_error(builder);
|
||||
response = Response {
|
||||
union_field: "error",
|
||||
};
|
||||
}
|
||||
|
||||
tracing::trace!(
|
||||
results = %response,
|
||||
"method return"
|
||||
);
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn abort(&mut self, _: AbortParams, _: AbortResults) -> Promise<(), Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(
|
||||
target: TARGET,
|
||||
parent: &self.span,
|
||||
"abort",
|
||||
)
|
||||
.entered();
|
||||
|
||||
tracing::trace!("method call");
|
||||
|
||||
self.state = State::Aborted;
|
||||
|
||||
tracing::trace!("method return");
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use api::connection_capnp::bootstrap;
|
||||
pub use api::connection_capnp::bootstrap::Client;
|
||||
use std::fmt;
|
||||
use std::fmt::{Formatter, Write};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use crate::authentication::AuthenticationHandle;
|
||||
@ -8,12 +10,14 @@ use crate::session::SessionManager;
|
||||
use capnp::capability::Promise;
|
||||
use capnp_rpc::pry;
|
||||
use rsasl::mechname::Mechname;
|
||||
use tracing::Span;
|
||||
|
||||
/// Cap'n Proto API Handler
|
||||
pub struct BootCap {
|
||||
peer_addr: SocketAddr,
|
||||
authentication: AuthenticationHandle,
|
||||
sessionmanager: SessionManager,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl BootCap {
|
||||
@ -21,12 +25,13 @@ impl BootCap {
|
||||
peer_addr: SocketAddr,
|
||||
authentication: AuthenticationHandle,
|
||||
sessionmanager: SessionManager,
|
||||
span: Span,
|
||||
) -> Self {
|
||||
tracing::trace!(%peer_addr, "bootstrapping RPC");
|
||||
Self {
|
||||
peer_addr,
|
||||
authentication,
|
||||
sessionmanager,
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,8 +42,14 @@ impl bootstrap::Server for BootCap {
|
||||
_: bootstrap::GetAPIVersionParams,
|
||||
_: bootstrap::GetAPIVersionResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let span = tracing::trace_span!("get_api_version", peer_addr=%self.peer_addr);
|
||||
let _guard = span.enter();
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(
|
||||
target: "bffh::api",
|
||||
"Bootstrap",
|
||||
method = "getAPIVersion",
|
||||
)
|
||||
.entered();
|
||||
tracing::trace!("method call");
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
@ -47,11 +58,24 @@ impl bootstrap::Server for BootCap {
|
||||
_: bootstrap::GetServerReleaseParams,
|
||||
mut result: bootstrap::GetServerReleaseResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let span = tracing::trace_span!("get_server_release", peer_addr=%self.peer_addr);
|
||||
let _guard = span.enter();
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(
|
||||
target: "bffh::api",
|
||||
"Bootstrap",
|
||||
method = "getServerRelease",
|
||||
)
|
||||
.entered();
|
||||
tracing::trace!("method call");
|
||||
|
||||
let mut builder = result.get();
|
||||
builder.set_name("bffhd");
|
||||
builder.set_release(crate::RELEASE_STRING);
|
||||
builder.set_release(crate::env::VERSION);
|
||||
|
||||
tracing::trace!(
|
||||
results.name = "bffhd",
|
||||
results.release = crate::env::VERSION,
|
||||
"method return"
|
||||
);
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
@ -60,10 +84,13 @@ impl bootstrap::Server for BootCap {
|
||||
_params: bootstrap::MechanismsParams,
|
||||
mut result: bootstrap::MechanismsResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let span = tracing::trace_span!("mechanisms", peer_addr=%self.peer_addr);
|
||||
let _guard = span.enter();
|
||||
|
||||
tracing::trace!("mechanisms");
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(
|
||||
target: "bffh::api",
|
||||
"mechanisms",
|
||||
)
|
||||
.entered();
|
||||
tracing::trace!(target: "bffh::api", "method call");
|
||||
|
||||
let builder = result.get();
|
||||
let mechs: Vec<_> = self
|
||||
@ -77,6 +104,28 @@ impl bootstrap::Server for BootCap {
|
||||
mechbuilder.set(i as u32, m);
|
||||
}
|
||||
|
||||
struct DisMechs<'a>(Vec<&'a str>);
|
||||
impl fmt::Display for DisMechs<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_char('[')?;
|
||||
let mut first = true;
|
||||
for mechanism in self.0.iter() {
|
||||
if first {
|
||||
first = false;
|
||||
f.write_str(mechanism)?;
|
||||
} else {
|
||||
f.write_str(" ,")?;
|
||||
f.write_str(mechanism)?;
|
||||
}
|
||||
}
|
||||
f.write_char(']')?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
tracing::trace!(
|
||||
results.mechs = %DisMechs(mechs),
|
||||
"method return"
|
||||
);
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
@ -85,18 +134,22 @@ impl bootstrap::Server for BootCap {
|
||||
params: bootstrap::CreateSessionParams,
|
||||
mut result: bootstrap::CreateSessionResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let span = tracing::trace_span!("create_session", peer_addr=%self.peer_addr);
|
||||
let _guard = span.enter();
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(
|
||||
target: "bffh::api",
|
||||
"createSession",
|
||||
)
|
||||
.entered();
|
||||
|
||||
let params = pry!(params.get());
|
||||
let mechanism: &str = pry!(params.get_mechanism());
|
||||
|
||||
tracing::trace!(mechanism);
|
||||
tracing::trace!(params.mechanism = mechanism, "method call");
|
||||
|
||||
let mechname = Mechname::new(mechanism.as_bytes());
|
||||
let auth = if let Ok(mechname) = mechname {
|
||||
if let Ok(session) = self.authentication.start(mechname) {
|
||||
Authentication::new(session, self.sessionmanager.clone())
|
||||
Authentication::new(&self.span, mechname, session, self.sessionmanager.clone())
|
||||
} else {
|
||||
Authentication::invalid_mechanism()
|
||||
}
|
||||
@ -104,6 +157,11 @@ impl bootstrap::Server for BootCap {
|
||||
Authentication::invalid_mechanism()
|
||||
};
|
||||
|
||||
tracing::trace!(
|
||||
results.authentication = %auth,
|
||||
"method return"
|
||||
);
|
||||
|
||||
let mut builder = result.get();
|
||||
builder.set_authentication(capnp_rpc::new_client(auth));
|
||||
|
||||
|
@ -6,17 +6,27 @@ use crate::RESOURCES;
|
||||
use api::machinesystem_capnp::machine_system::info;
|
||||
use capnp::capability::Promise;
|
||||
use capnp_rpc::pry;
|
||||
use tracing::Span;
|
||||
|
||||
const TARGET: &str = "bffh::api::machinesystem";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Machines {
|
||||
span: Span,
|
||||
session: SessionHandle,
|
||||
resources: ResourcesHandle,
|
||||
}
|
||||
|
||||
impl Machines {
|
||||
pub fn new(session: SessionHandle) -> Self {
|
||||
let span = tracing::info_span!(
|
||||
target: TARGET,
|
||||
parent: &session.span,
|
||||
"MachineSystem",
|
||||
);
|
||||
// FIXME no unwrap bad
|
||||
Self {
|
||||
span,
|
||||
session,
|
||||
resources: RESOURCES.get().unwrap().clone(),
|
||||
}
|
||||
@ -29,6 +39,16 @@ impl info::Server for Machines {
|
||||
_: info::GetMachineListParams,
|
||||
mut result: info::GetMachineListResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(
|
||||
target: TARGET,
|
||||
parent: &self.span,
|
||||
"getMachineList",
|
||||
)
|
||||
.entered();
|
||||
|
||||
tracing::trace!("method call");
|
||||
|
||||
let machine_list: Vec<(usize, &Resource)> = self
|
||||
.resources
|
||||
.list_all()
|
||||
@ -43,6 +63,9 @@ impl info::Server for Machines {
|
||||
Machine::build(self.session.clone(), resource, mbuilder);
|
||||
}
|
||||
|
||||
// TODO: indicate result?
|
||||
tracing::trace!("method return");
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
@ -51,12 +74,25 @@ impl info::Server for Machines {
|
||||
params: info::GetMachineParams,
|
||||
mut result: info::GetMachineResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(
|
||||
target: TARGET,
|
||||
parent: &self.span,
|
||||
"getMachine",
|
||||
)
|
||||
.entered();
|
||||
|
||||
let params = pry!(params.get());
|
||||
let id = pry!(params.get_id());
|
||||
|
||||
tracing::trace!(params.id = id, "method call");
|
||||
|
||||
if let Some(resource) = self.resources.get_by_id(id) {
|
||||
tracing::trace!(results = "Just", results.inner = id, "method return");
|
||||
let builder = result.get();
|
||||
Machine::optional_build(self.session.clone(), resource.clone(), builder);
|
||||
} else {
|
||||
tracing::trace!(results = "Nothing", "method return");
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
@ -67,12 +103,29 @@ impl info::Server for Machines {
|
||||
params: info::GetMachineURNParams,
|
||||
mut result: info::GetMachineURNResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(
|
||||
target: TARGET,
|
||||
parent: &self.span,
|
||||
"getMachineURN",
|
||||
)
|
||||
.entered();
|
||||
|
||||
let params = pry!(params.get());
|
||||
let urn = pry!(params.get_urn());
|
||||
|
||||
tracing::trace!(params.urn = urn, "method call");
|
||||
|
||||
if let Some(resource) = self.resources.get_by_urn(urn) {
|
||||
tracing::trace!(
|
||||
results = "Just",
|
||||
results.inner = resource.get_id(),
|
||||
"method return"
|
||||
);
|
||||
let builder = result.get();
|
||||
Machine::optional_build(self.session.clone(), resource.clone(), builder);
|
||||
} else {
|
||||
tracing::trace!(results = "Nothing", "method return");
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
|
@ -3,7 +3,7 @@ use async_net::TcpListener;
|
||||
use capnp_rpc::rpc_twoparty_capnp::Side;
|
||||
use capnp_rpc::twoparty::VatNetwork;
|
||||
use capnp_rpc::RpcSystem;
|
||||
use executor::prelude::Executor;
|
||||
use executor::prelude::{Executor, GroupId, SupervisionRegistry};
|
||||
use futures_rustls::server::TlsStream;
|
||||
use futures_rustls::TlsAcceptor;
|
||||
use futures_util::stream::FuturesUnordered;
|
||||
@ -12,7 +12,7 @@ use futures_util::{stream, AsyncRead, AsyncWrite, FutureExt, StreamExt};
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
|
||||
use crate::authentication::AuthenticationHandle;
|
||||
use crate::session::SessionManager;
|
||||
@ -60,7 +60,7 @@ impl APIServer {
|
||||
acceptor: TlsAcceptor,
|
||||
sessionmanager: SessionManager,
|
||||
authentication: AuthenticationHandle,
|
||||
) -> anyhow::Result<Self> {
|
||||
) -> miette::Result<Self> {
|
||||
let span = tracing::info_span!("binding API listen sockets");
|
||||
let _guard = span.enter();
|
||||
|
||||
@ -145,12 +145,36 @@ impl APIServer {
|
||||
peer_addr: SocketAddr,
|
||||
stream: impl Future<Output = io::Result<TlsStream<IO>>>,
|
||||
) {
|
||||
tracing::debug!("handling new API connection");
|
||||
let span = tracing::trace_span!("api.handle");
|
||||
let _guard = span.enter();
|
||||
|
||||
struct Peer {
|
||||
ip: IpAddr,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
let peer = Peer {
|
||||
ip: peer_addr.ip(),
|
||||
port: peer_addr.port(),
|
||||
};
|
||||
tracing::debug!(
|
||||
%peer.ip,
|
||||
peer.port,
|
||||
"spawning api handler"
|
||||
);
|
||||
|
||||
let connection_span = tracing::info_span!(
|
||||
target: "bffh::api",
|
||||
"connection",
|
||||
%peer.ip,
|
||||
peer.port,
|
||||
);
|
||||
let f = async move {
|
||||
tracing::trace!(parent: &connection_span, "starting tls exchange");
|
||||
let stream = match stream.await {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
tracing::error!("TLS handshake failed: {}", e);
|
||||
Err(error) => {
|
||||
tracing::error!(parent: &connection_span, %error, "TLS handshake failed");
|
||||
return;
|
||||
}
|
||||
};
|
||||
@ -161,12 +185,18 @@ impl APIServer {
|
||||
peer_addr,
|
||||
self.authentication.clone(),
|
||||
self.sessionmanager.clone(),
|
||||
connection_span.clone(),
|
||||
));
|
||||
|
||||
if let Err(e) = RpcSystem::new(Box::new(vat), Some(bootstrap.client)).await {
|
||||
tracing::error!("Error during RPC handling: {}", e);
|
||||
if let Err(error) = RpcSystem::new(Box::new(vat), Some(bootstrap.client)).await {
|
||||
tracing::error!(
|
||||
parent: &connection_span,
|
||||
%error,
|
||||
"error occured during rpc handling",
|
||||
);
|
||||
}
|
||||
};
|
||||
self.executor.spawn_local(f);
|
||||
let cgroup = SupervisionRegistry::with(SupervisionRegistry::new_group);
|
||||
self.executor.spawn_local_cgroup(f, cgroup);
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,49 @@
|
||||
use api::permissionsystem_capnp::permission_system::info::Server as PermissionSystem;
|
||||
use crate::authorization::roles::Role;
|
||||
use crate::Roles;
|
||||
use api::permissionsystem_capnp::permission_system::info::{
|
||||
GetRoleListParams, GetRoleListResults, Server as PermissionSystem,
|
||||
};
|
||||
use capnp::capability::Promise;
|
||||
use capnp::Error;
|
||||
use tracing::Span;
|
||||
|
||||
use crate::session::SessionHandle;
|
||||
|
||||
pub struct Permissions;
|
||||
const TARGET: &str = "bffh::api::permissionsystem";
|
||||
|
||||
pub struct Permissions {
|
||||
span: Span,
|
||||
roles: Roles,
|
||||
}
|
||||
|
||||
impl Permissions {
|
||||
pub fn new(_session: SessionHandle) -> Self {
|
||||
Self
|
||||
pub fn new(session: SessionHandle) -> Self {
|
||||
let span = tracing::info_span!(target: TARGET, "PermissionSystem",);
|
||||
Self {
|
||||
span,
|
||||
roles: session.roles,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PermissionSystem for Permissions {}
|
||||
impl PermissionSystem for Permissions {
|
||||
fn get_role_list(
|
||||
&mut self,
|
||||
_: GetRoleListParams,
|
||||
mut results: GetRoleListResults,
|
||||
) -> Promise<(), Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(target: TARGET, "getRoleList",).entered();
|
||||
|
||||
tracing::trace!("method call");
|
||||
let roles = self.roles.list().collect::<Vec<&String>>();
|
||||
let mut builder = results.get();
|
||||
let mut b = builder.init_role_list(roles.len() as u32);
|
||||
for (i, role) in roles.into_iter().enumerate() {
|
||||
let mut role_builder = b.reborrow().get(i as u32);
|
||||
role_builder.set_name(role);
|
||||
}
|
||||
tracing::trace!("method return");
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
@ -79,12 +79,21 @@ impl info::Server for User {
|
||||
impl manage::Server for User {
|
||||
fn pwd(
|
||||
&mut self,
|
||||
_params: manage::PwdParams,
|
||||
params: manage::PwdParams,
|
||||
_results: manage::PwdResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
Promise::err(::capnp::Error::unimplemented(
|
||||
"method not implemented".to_string(),
|
||||
))
|
||||
let params = pry!(params.get());
|
||||
let old_pw = pry!(params.get_old_pwd());
|
||||
let new_pw = pry!(params.get_new_pwd());
|
||||
|
||||
let uid = self.user.get_username();
|
||||
if let Some(mut user) = self.session.users.get_user(uid) {
|
||||
if let Ok(true) = user.check_password(old_pw.as_bytes()) {
|
||||
user.set_pw(new_pw.as_bytes());
|
||||
self.session.users.put_user(uid, &user);
|
||||
}
|
||||
}
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,9 +157,17 @@ impl admin::Server for User {
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
fn pwd(&mut self, _: admin::PwdParams, _: admin::PwdResults) -> Promise<(), ::capnp::Error> {
|
||||
Promise::err(::capnp::Error::unimplemented(
|
||||
"method not implemented".to_string(),
|
||||
))
|
||||
fn pwd(
|
||||
&mut self,
|
||||
param: admin::PwdParams,
|
||||
_: admin::PwdResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let new_pw = pry!(pry!(param.get()).get_new_pwd());
|
||||
let uid = self.user.get_username();
|
||||
if let Some(mut user) = self.session.users.get_user(uid) {
|
||||
user.set_pw(new_pw.as_bytes());
|
||||
self.session.users.put_user(uid, &user);
|
||||
}
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,25 @@
|
||||
use api::usersystem_capnp::user_system::{info, manage, search};
|
||||
use capnp::capability::Promise;
|
||||
use capnp_rpc::pry;
|
||||
use tracing::Span;
|
||||
|
||||
use crate::capnp::user::User;
|
||||
|
||||
use crate::session::SessionHandle;
|
||||
use crate::users::{db, UserRef};
|
||||
|
||||
const TARGET: &str = "bffh::api::usersystem";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Users {
|
||||
span: Span,
|
||||
session: SessionHandle,
|
||||
}
|
||||
|
||||
impl Users {
|
||||
pub fn new(session: SessionHandle) -> Self {
|
||||
Self { session }
|
||||
let span = tracing::info_span!(target: TARGET, "UserSystem",);
|
||||
Self { span, session }
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,8 +29,14 @@ impl info::Server for Users {
|
||||
_: info::GetUserSelfParams,
|
||||
mut result: info::GetUserSelfResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(target: TARGET, "getUserSelf").entered();
|
||||
tracing::trace!("method call");
|
||||
|
||||
let builder = result.get();
|
||||
User::build(self.session.clone(), builder);
|
||||
|
||||
tracing::trace!("method return");
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
@ -36,26 +47,43 @@ impl manage::Server for Users {
|
||||
_: manage::GetUserListParams,
|
||||
mut result: manage::GetUserListResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(target: TARGET, "getUserList",).entered();
|
||||
tracing::trace!("method call");
|
||||
|
||||
let userdb = self.session.users.into_inner();
|
||||
let users = pry!(userdb
|
||||
.get_all()
|
||||
.map_err(|e| capnp::Error::failed(format!("UserDB error: {:?}", e))));
|
||||
let mut builder = result.get().init_user_list(users.len() as u32);
|
||||
for (i, (_, user)) in users.into_iter().enumerate() {
|
||||
for (i, (id, userdata)) in users.into_iter().enumerate() {
|
||||
let user = db::User { id, userdata };
|
||||
User::fill(&self.session, user, builder.reborrow().get(i as u32));
|
||||
}
|
||||
|
||||
tracing::trace!("method return");
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn add_user_fallible(
|
||||
&mut self,
|
||||
params: manage::AddUserFallibleParams,
|
||||
mut result: manage::AddUserFallibleResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(target: TARGET, "addUserFallible").entered();
|
||||
|
||||
let params = pry!(params.get());
|
||||
let username = pry!(params.get_username());
|
||||
let password = pry!(params.get_password());
|
||||
// FIXME: saslprep passwords & usernames before storing them
|
||||
|
||||
tracing::trace!(
|
||||
params.username = username,
|
||||
params.password = "<redacted>",
|
||||
"method call"
|
||||
);
|
||||
|
||||
let mut builder = result.get();
|
||||
|
||||
if !username.is_empty() && !password.is_empty() {
|
||||
@ -81,21 +109,29 @@ impl manage::Server for Users {
|
||||
}
|
||||
}
|
||||
|
||||
tracing::trace!("method return");
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn remove_user(
|
||||
&mut self,
|
||||
params: manage::RemoveUserParams,
|
||||
_: manage::RemoveUserResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(target: TARGET, "removeUser",).entered();
|
||||
|
||||
let who: &str = pry!(pry!(pry!(params.get()).get_user()).get_username());
|
||||
|
||||
tracing::trace!(params.user = who, "method call");
|
||||
|
||||
if let Err(e) = self.session.users.del_user(who) {
|
||||
tracing::warn!("Failed to delete user: {:?}", e);
|
||||
} else {
|
||||
tracing::info!("Deleted user {}", who);
|
||||
}
|
||||
|
||||
tracing::trace!("method return");
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
@ -106,9 +142,17 @@ impl search::Server for Users {
|
||||
params: search::GetUserByNameParams,
|
||||
mut result: search::GetUserByNameResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let _guard = self.span.enter();
|
||||
let _span = tracing::trace_span!(target: TARGET, "getUserByName",).entered();
|
||||
|
||||
let username: &str = pry!(pry!(params.get()).get_username());
|
||||
|
||||
tracing::trace!(params.username = username, "method call");
|
||||
|
||||
let userref = UserRef::new(username.to_string());
|
||||
User::build_optional(&self.session, Some(userref), result.get());
|
||||
|
||||
tracing::trace!("method return");
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,169 @@
|
||||
use crate::Config;
|
||||
use std::collections::HashMap;
|
||||
use std::default::Default;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::authorization::permissions::PrivilegesBuf;
|
||||
use crate::authorization::roles::Role;
|
||||
use crate::capnp::{Listen, TlsListen};
|
||||
use crate::logging::LogConfig;
|
||||
|
||||
use miette::IntoDiagnostic;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DhallConfig<'a> {
|
||||
path: &'a Path,
|
||||
}
|
||||
|
||||
pub fn read_config_file(path: impl AsRef<Path>) -> Result<Config, serde_dhall::Error> {
|
||||
serde_dhall::from_file(path).parse().map_err(Into::into)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
/// A description of a machine
|
||||
///
|
||||
/// This is the struct that a machine is serialized to/from.
|
||||
/// Combining this with the actual state of the system will return a machine
|
||||
pub struct MachineDescription {
|
||||
/// The name of the machine. Doesn't need to be unique but is what humans will be presented.
|
||||
pub name: String,
|
||||
|
||||
/// An optional description of the Machine.
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "deser_option"
|
||||
)]
|
||||
pub description: Option<String>,
|
||||
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "deser_option"
|
||||
)]
|
||||
pub wiki: Option<String>,
|
||||
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "deser_option"
|
||||
)]
|
||||
pub category: Option<String>,
|
||||
|
||||
/// The permission required
|
||||
#[serde(flatten)]
|
||||
pub privs: PrivilegesBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
/// A list of address/port pairs to listen on.
|
||||
pub listens: Vec<Listen>,
|
||||
|
||||
/// Machine descriptions to load
|
||||
pub machines: HashMap<String, MachineDescription>,
|
||||
|
||||
/// Actors to load and their configuration options
|
||||
pub actors: HashMap<String, ModuleConfig>,
|
||||
|
||||
/// Initiators to load and their configuration options
|
||||
pub initiators: HashMap<String, ModuleConfig>,
|
||||
|
||||
pub mqtt_url: String,
|
||||
|
||||
pub actor_connections: Vec<(String, String)>,
|
||||
pub init_connections: Vec<(String, String)>,
|
||||
|
||||
pub db_path: PathBuf,
|
||||
pub auditlog_path: PathBuf,
|
||||
|
||||
pub roles: HashMap<String, Role>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub tlsconfig: TlsListen,
|
||||
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub tlskeylog: Option<PathBuf>,
|
||||
|
||||
#[serde(default, skip)]
|
||||
pub verbosity: isize,
|
||||
|
||||
#[serde(default, skip)]
|
||||
pub logging: LogConfig,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn is_quiet(&self) -> bool {
|
||||
self.verbosity < 0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ModuleConfig {
|
||||
pub module: String,
|
||||
pub params: HashMap<String, String>,
|
||||
}
|
||||
|
||||
pub(crate) fn deser_option<'de, D, T>(d: D) -> std::result::Result<Option<T>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
T: serde::Deserialize<'de>,
|
||||
{
|
||||
Ok(T::deserialize(d).ok())
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
let mut actors: HashMap<String, ModuleConfig> = HashMap::new();
|
||||
let mut initiators: HashMap<String, ModuleConfig> = HashMap::new();
|
||||
let machines = HashMap::new();
|
||||
|
||||
actors.insert(
|
||||
"Actor".to_string(),
|
||||
ModuleConfig {
|
||||
module: "Shelly".to_string(),
|
||||
params: HashMap::new(),
|
||||
},
|
||||
);
|
||||
initiators.insert(
|
||||
"Initiator".to_string(),
|
||||
ModuleConfig {
|
||||
module: "TCP-Listen".to_string(),
|
||||
params: HashMap::new(),
|
||||
},
|
||||
);
|
||||
|
||||
Config {
|
||||
listens: vec![Listen {
|
||||
address: "127.0.0.1".to_string(),
|
||||
port: None,
|
||||
}],
|
||||
actors,
|
||||
initiators,
|
||||
machines,
|
||||
mqtt_url: "tcp://localhost:1883".to_string(),
|
||||
actor_connections: vec![("Testmachine".to_string(), "Actor".to_string())],
|
||||
init_connections: vec![("Initiator".to_string(), "Testmachine".to_string())],
|
||||
|
||||
db_path: PathBuf::from("/run/bffh/database"),
|
||||
auditlog_path: PathBuf::from("/var/log/bffh/audit.log"),
|
||||
roles: HashMap::new(),
|
||||
|
||||
tlsconfig: TlsListen {
|
||||
certfile: PathBuf::from("./bffh.crt"),
|
||||
keyfile: PathBuf::from("./bffh.key"),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
tlskeylog: None,
|
||||
verbosity: 0,
|
||||
logging: LogConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,157 +1,50 @@
|
||||
use std::collections::HashMap;
|
||||
use std::default::Default;
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use miette::Diagnostic;
|
||||
use thiserror::Error;
|
||||
|
||||
pub(crate) use dhall::deser_option;
|
||||
pub use dhall::{Config, MachineDescription, ModuleConfig};
|
||||
mod dhall;
|
||||
pub use dhall::read_config_file as read;
|
||||
|
||||
use crate::authorization::permissions::PrivilegesBuf;
|
||||
use crate::authorization::roles::Role;
|
||||
use crate::capnp::{Listen, TlsListen};
|
||||
use crate::logging::LogConfig;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
/// A description of a machine
|
||||
///
|
||||
/// This is the struct that a machine is serialized to/from.
|
||||
/// Combining this with the actual state of the system will return a machine
|
||||
pub struct MachineDescription {
|
||||
/// The name of the machine. Doesn't need to be unique but is what humans will be presented.
|
||||
pub name: String,
|
||||
|
||||
/// An optional description of the Machine.
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "deser_option"
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
pub enum ConfigError {
|
||||
#[error("The config file '{0}' does not exist or is not readable")]
|
||||
#[diagnostic(
|
||||
code(config::notfound),
|
||||
help("Make sure the config file and the directory it's in are readable by the user running bffh")
|
||||
)]
|
||||
pub description: Option<String>,
|
||||
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "deser_option"
|
||||
NotFound(String),
|
||||
#[error("The path '{0}' does not point to a file")]
|
||||
#[diagnostic(
|
||||
code(config::notafile),
|
||||
help("The config must be a file in the dhall format")
|
||||
)]
|
||||
pub wiki: Option<String>,
|
||||
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "deser_option"
|
||||
)]
|
||||
pub category: Option<String>,
|
||||
|
||||
/// The permission required
|
||||
#[serde(flatten)]
|
||||
pub privs: PrivilegesBuf,
|
||||
NotAFile(String),
|
||||
#[error("failed to parse config: {0}")]
|
||||
#[diagnostic(code(config::parse))]
|
||||
Parse(
|
||||
#[from]
|
||||
#[source]
|
||||
serde_dhall::Error,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
/// A list of address/port pairs to listen on.
|
||||
pub listens: Vec<Listen>,
|
||||
|
||||
/// Machine descriptions to load
|
||||
pub machines: HashMap<String, MachineDescription>,
|
||||
|
||||
/// Actors to load and their configuration options
|
||||
pub actors: HashMap<String, ModuleConfig>,
|
||||
|
||||
/// Initiators to load and their configuration options
|
||||
pub initiators: HashMap<String, ModuleConfig>,
|
||||
|
||||
pub mqtt_url: String,
|
||||
|
||||
pub actor_connections: Vec<(String, String)>,
|
||||
pub init_connections: Vec<(String, String)>,
|
||||
|
||||
pub db_path: PathBuf,
|
||||
pub auditlog_path: PathBuf,
|
||||
|
||||
pub roles: HashMap<String, Role>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub tlsconfig: TlsListen,
|
||||
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub tlskeylog: Option<PathBuf>,
|
||||
|
||||
#[serde(default, skip)]
|
||||
pub verbosity: isize,
|
||||
|
||||
#[serde(default, skip)]
|
||||
pub logging: LogConfig,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn is_quiet(&self) -> bool {
|
||||
self.verbosity < 0
|
||||
pub fn read(file: impl AsRef<Path>) -> Result<Config, ConfigError> {
|
||||
let path = file.as_ref();
|
||||
if !path.exists() {
|
||||
return Err(ConfigError::NotFound(path.to_string_lossy().to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ModuleConfig {
|
||||
pub module: String,
|
||||
pub params: HashMap<String, String>,
|
||||
}
|
||||
|
||||
pub(crate) fn deser_option<'de, D, T>(d: D) -> std::result::Result<Option<T>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
T: serde::Deserialize<'de>,
|
||||
{
|
||||
Ok(T::deserialize(d).ok())
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
let mut actors: HashMap<String, ModuleConfig> = HashMap::new();
|
||||
let mut initiators: HashMap<String, ModuleConfig> = HashMap::new();
|
||||
let machines = HashMap::new();
|
||||
|
||||
actors.insert(
|
||||
"Actor".to_string(),
|
||||
ModuleConfig {
|
||||
module: "Shelly".to_string(),
|
||||
params: HashMap::new(),
|
||||
},
|
||||
);
|
||||
initiators.insert(
|
||||
"Initiator".to_string(),
|
||||
ModuleConfig {
|
||||
module: "TCP-Listen".to_string(),
|
||||
params: HashMap::new(),
|
||||
},
|
||||
);
|
||||
|
||||
Config {
|
||||
listens: vec![Listen {
|
||||
address: "127.0.0.1".to_string(),
|
||||
port: None,
|
||||
}],
|
||||
actors,
|
||||
initiators,
|
||||
machines,
|
||||
mqtt_url: "tcp://localhost:1883".to_string(),
|
||||
actor_connections: vec![("Testmachine".to_string(), "Actor".to_string())],
|
||||
init_connections: vec![("Initiator".to_string(), "Testmachine".to_string())],
|
||||
|
||||
db_path: PathBuf::from("/run/bffh/database"),
|
||||
auditlog_path: PathBuf::from("/var/log/bffh/audit.log"),
|
||||
roles: HashMap::new(),
|
||||
|
||||
tlsconfig: TlsListen {
|
||||
certfile: PathBuf::from("./bffh.crt"),
|
||||
keyfile: PathBuf::from("./bffh.key"),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
tlskeylog: None,
|
||||
verbosity: 0,
|
||||
logging: LogConfig::default(),
|
||||
if !path.is_file() {
|
||||
return Err(ConfigError::NotAFile(path.to_string_lossy().to_string()));
|
||||
}
|
||||
let mut config = dhall::read_config_file(file)?;
|
||||
for (envvar, value) in std::env::vars() {
|
||||
match envvar.as_str() {
|
||||
// Do things like this?
|
||||
// "BFFH_LOG" => config.logging.filter = Some(value),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(config)
|
||||
}
|
||||
|
@ -1,7 +1,81 @@
|
||||
use thiserror::Error;
|
||||
|
||||
mod raw;
|
||||
|
||||
use miette::{Diagnostic, LabeledSpan, Severity, SourceCode};
|
||||
pub use raw::RawDB;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
mod typed;
|
||||
pub use typed::{Adapter, AlignedAdapter, ArchivedValue, DB};
|
||||
|
||||
pub type Error = lmdb::Error;
|
||||
pub type ErrorO = lmdb::Error;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Error)]
|
||||
#[error(transparent)]
|
||||
pub struct Error(#[from] lmdb::Error);
|
||||
|
||||
impl Diagnostic for Error {
|
||||
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
Some(Box::new(match self.0 {
|
||||
lmdb::Error::KeyExist => "bffh::db::raw::key_exists".to_string(),
|
||||
lmdb::Error::NotFound => "bffh::db::raw::not_found".to_string(),
|
||||
lmdb::Error::PageNotFound => "bffh::db::raw::page_not_found".to_string(),
|
||||
lmdb::Error::Corrupted => "bffh::db::raw::corrupted".to_string(),
|
||||
lmdb::Error::Panic => "bffh::db::raw::panic".to_string(),
|
||||
lmdb::Error::VersionMismatch => "bffh::db::raw::version_mismatch".to_string(),
|
||||
lmdb::Error::Invalid => "bffh::db::raw::invalid".to_string(),
|
||||
lmdb::Error::MapFull => "bffh::db::raw::map_full".to_string(),
|
||||
lmdb::Error::DbsFull => "bffh::db::raw::dbs_full".to_string(),
|
||||
lmdb::Error::ReadersFull => "bffh::db::raw::readers_full".to_string(),
|
||||
lmdb::Error::TlsFull => "bffh::db::raw::tls_full".to_string(),
|
||||
lmdb::Error::TxnFull => "bffh::db::raw::txn_full".to_string(),
|
||||
lmdb::Error::CursorFull => "bffh::db::raw::cursor_full".to_string(),
|
||||
lmdb::Error::PageFull => "bffh::db::raw::page_full".to_string(),
|
||||
lmdb::Error::MapResized => "bffh::db::raw::map_resized".to_string(),
|
||||
lmdb::Error::Incompatible => "bffh::db::raw::incompatible".to_string(),
|
||||
lmdb::Error::BadRslot => "bffh::db::raw::bad_rslot".to_string(),
|
||||
lmdb::Error::BadTxn => "bffh::db::raw::bad_txn".to_string(),
|
||||
lmdb::Error::BadValSize => "bffh::db::raw::bad_val_size".to_string(),
|
||||
lmdb::Error::BadDbi => "bffh::db::raw::bad_dbi".to_string(),
|
||||
lmdb::Error::Other(n) => format!("bffh::db::raw::e{}", n),
|
||||
}))
|
||||
}
|
||||
|
||||
fn severity(&self) -> Option<Severity> {
|
||||
Some(Severity::Error)
|
||||
}
|
||||
|
||||
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
match self.0 {
|
||||
lmdb::Error::KeyExist => Some(Box::new("The provided key already exists in the database")),
|
||||
lmdb::Error::NotFound => Some(Box::new("The requested key was not found in the database")),
|
||||
lmdb::Error::PageNotFound => Some(Box::new("The requested page was not found. This usually indicates corruption.")),
|
||||
lmdb::Error::Corrupted => None,
|
||||
lmdb::Error::Panic => None,
|
||||
lmdb::Error::VersionMismatch => None,
|
||||
lmdb::Error::Invalid => None,
|
||||
lmdb::Error::MapFull => None,
|
||||
lmdb::Error::DbsFull => None,
|
||||
lmdb::Error::ReadersFull => None,
|
||||
lmdb::Error::TlsFull => None,
|
||||
lmdb::Error::TxnFull => None,
|
||||
lmdb::Error::CursorFull => None,
|
||||
lmdb::Error::PageFull => None,
|
||||
lmdb::Error::MapResized => None,
|
||||
lmdb::Error::Incompatible => None,
|
||||
lmdb::Error::BadRslot => Some(Box::new("This usually indicates that the operation can't complete because an incompatible transaction is still open.")),
|
||||
lmdb::Error::BadTxn => None,
|
||||
lmdb::Error::BadValSize => None,
|
||||
lmdb::Error::BadDbi => None,
|
||||
lmdb::Error::Other(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use super::Result;
|
||||
use lmdb::{DatabaseFlags, Environment, RwTransaction, Transaction, WriteFlags};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -142,11 +142,11 @@ impl<A: Adapter> DB<A> {
|
||||
}
|
||||
|
||||
pub fn del(&self, txn: &mut RwTransaction, key: &impl AsRef<[u8]>) -> Result<(), db::Error> {
|
||||
self.db.del::<_, &[u8]>(txn, key, None)
|
||||
Ok(self.db.del::<_, &[u8]>(txn, key, None)?)
|
||||
}
|
||||
|
||||
pub fn clear(&self, txn: &mut RwTransaction) -> Result<(), db::Error> {
|
||||
self.db.clear(txn)
|
||||
Ok(self.db.clear(txn)?)
|
||||
}
|
||||
|
||||
pub fn get_all<'txn, T: Transaction>(
|
||||
|
145
bffhd/error.rs
145
bffhd/error.rs
@ -1,74 +1,97 @@
|
||||
use crate::db;
|
||||
use rsasl::error::SessionError;
|
||||
use std::fmt;
|
||||
use miette::{Diagnostic, LabeledSpan, Severity, SourceCode};
|
||||
use std::error;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
type DBError = db::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Shared error type
|
||||
pub enum Error {
|
||||
SASL(SessionError),
|
||||
IO(io::Error),
|
||||
Boxed(Box<dyn std::error::Error>),
|
||||
Capnp(capnp::Error),
|
||||
DB(DBError),
|
||||
Denied,
|
||||
pub trait Description {
|
||||
const DESCRIPTION: Option<&'static str> = None;
|
||||
const CODE: &'static str;
|
||||
const HELP: Option<&'static str> = None;
|
||||
const URL: Option<&'static str> = None;
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::SASL(e) => {
|
||||
write!(f, "SASL Error: {}", e)
|
||||
}
|
||||
Error::IO(e) => {
|
||||
write!(f, "IO Error: {}", e)
|
||||
}
|
||||
Error::Boxed(e) => {
|
||||
write!(f, "{}", e)
|
||||
}
|
||||
Error::Capnp(e) => {
|
||||
write!(f, "Cap'n Proto Error: {}", e)
|
||||
}
|
||||
Error::DB(e) => {
|
||||
write!(f, "DB Error: {:?}", e)
|
||||
}
|
||||
Error::Denied => {
|
||||
write!(f, "You do not have the permission required to do that.")
|
||||
}
|
||||
pub fn wrap<D: Description>(error: Source) -> Error {
|
||||
Error::new::<D>(error)
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
pub enum Source {
|
||||
#[error("io error occured")]
|
||||
Io(
|
||||
#[source]
|
||||
#[from]
|
||||
io::Error,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
description: Option<&'static str>,
|
||||
code: &'static str,
|
||||
severity: Option<Severity>,
|
||||
help: Option<&'static str>,
|
||||
url: Option<&'static str>,
|
||||
source: Source,
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&self.source, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
Some(&self.source)
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
if let Some(desc) = self.description {
|
||||
desc
|
||||
} else {
|
||||
self.source.description()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SessionError> for Error {
|
||||
fn from(e: SessionError) -> Error {
|
||||
Error::SASL(e)
|
||||
impl Error {
|
||||
pub fn new<D: Description>(source: Source) -> Self {
|
||||
Self {
|
||||
description: D::DESCRIPTION,
|
||||
code: D::CODE,
|
||||
severity: source.severity(),
|
||||
help: D::HELP,
|
||||
url: D::URL,
|
||||
source,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(e: io::Error) -> Error {
|
||||
Error::IO(e)
|
||||
impl miette::Diagnostic for Error {
|
||||
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
Some(Box::new(self.code))
|
||||
}
|
||||
|
||||
fn severity(&self) -> Option<Severity> {
|
||||
self.severity
|
||||
}
|
||||
|
||||
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
self.help.map(|r| {
|
||||
let b: Box<dyn Display + 'a> = Box::new(r);
|
||||
b
|
||||
})
|
||||
}
|
||||
|
||||
fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
self.url.map(|r| {
|
||||
let b: Box<dyn Display + 'a> = Box::new(r);
|
||||
b
|
||||
})
|
||||
}
|
||||
|
||||
fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
|
||||
Some(&self.source)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<dyn std::error::Error>> for Error {
|
||||
fn from(e: Box<dyn std::error::Error>) -> Error {
|
||||
Error::Boxed(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<capnp::Error> for Error {
|
||||
fn from(e: capnp::Error) -> Error {
|
||||
Error::Capnp(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DBError> for Error {
|
||||
fn from(e: DBError) -> Error {
|
||||
Error::DB(e)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
118
bffhd/initiators/dummy.rs
Normal file
118
bffhd/initiators/dummy.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use miette::{miette, Diagnostic};
|
||||
use thiserror::Error;
|
||||
|
||||
use super::Initiator;
|
||||
use crate::initiators::InitiatorCallbacks;
|
||||
use crate::resources::modules::fabaccess::Status;
|
||||
use crate::session::SessionHandle;
|
||||
use crate::users::UserRef;
|
||||
use async_io::Timer;
|
||||
use futures_util::future::BoxFuture;
|
||||
use futures_util::ready;
|
||||
use lmdb::Stat;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::mem;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub struct Dummy {
|
||||
callbacks: InitiatorCallbacks,
|
||||
session: SessionHandle,
|
||||
state: DummyState,
|
||||
}
|
||||
|
||||
enum DummyState {
|
||||
Empty,
|
||||
Sleeping(Timer, Option<Status>),
|
||||
Updating(BoxFuture<'static, Status>),
|
||||
}
|
||||
|
||||
impl Dummy {
|
||||
fn timer() -> Timer {
|
||||
Timer::after(Duration::from_secs(2))
|
||||
}
|
||||
|
||||
fn flip(&self, status: Status) -> BoxFuture<'static, Status> {
|
||||
let session = self.session.clone();
|
||||
let mut callbacks = self.callbacks.clone();
|
||||
Box::pin(async move {
|
||||
let next = match &status {
|
||||
Status::Free => Status::InUse(session.get_user_ref()),
|
||||
Status::InUse(_) => Status::Free,
|
||||
_ => Status::Free,
|
||||
};
|
||||
callbacks.try_update(session, status).await;
|
||||
|
||||
next
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
pub enum DummyError {}
|
||||
|
||||
impl Future for Dummy {
|
||||
type Output = ();
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let span = tracing::debug_span!("Dummy initiator poll");
|
||||
let _guard = span.enter();
|
||||
tracing::trace!("polling Dummy initiator");
|
||||
loop {
|
||||
match &mut self.state {
|
||||
DummyState::Empty => {
|
||||
tracing::trace!("Dummy initiator is empty, initializing…");
|
||||
mem::replace(
|
||||
&mut self.state,
|
||||
DummyState::Sleeping(Self::timer(), Some(Status::Free)),
|
||||
);
|
||||
}
|
||||
DummyState::Sleeping(timer, next) => {
|
||||
tracing::trace!("Sleep timer exists, polling it.");
|
||||
|
||||
let _: Instant = ready!(Pin::new(timer).poll(cx));
|
||||
|
||||
tracing::trace!("Timer has fired, poking out an update!");
|
||||
|
||||
let status = next.take().unwrap();
|
||||
let f = self.flip(status);
|
||||
mem::replace(&mut self.state, DummyState::Updating(f));
|
||||
}
|
||||
DummyState::Updating(f) => {
|
||||
tracing::trace!("Update future exists, polling it .");
|
||||
|
||||
let next = ready!(Pin::new(f).poll(cx));
|
||||
|
||||
tracing::trace!("Update future completed, sleeping!");
|
||||
|
||||
mem::replace(
|
||||
&mut self.state,
|
||||
DummyState::Sleeping(Self::timer(), Some(next)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Initiator for Dummy {
|
||||
fn new(params: &HashMap<String, String>, callbacks: InitiatorCallbacks) -> miette::Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let uid = params
|
||||
.get("uid")
|
||||
.ok_or_else(|| miette!("Dummy initiator configured without an UID"))?;
|
||||
let session = callbacks
|
||||
.open_session(uid)
|
||||
.ok_or_else(|| miette!("The configured user for the dummy initiator does not exist"))?;
|
||||
|
||||
Ok(Self {
|
||||
callbacks,
|
||||
session,
|
||||
state: DummyState::Empty,
|
||||
})
|
||||
}
|
||||
}
|
@ -1,161 +1,180 @@
|
||||
use crate::initiators::dummy::Dummy;
|
||||
use crate::initiators::process::Process;
|
||||
use crate::resources::modules::fabaccess::Status;
|
||||
use crate::session::SessionHandle;
|
||||
use crate::{
|
||||
AuthenticationHandle, Config, MachineState, Resource, ResourcesHandle, SessionManager,
|
||||
};
|
||||
use async_compat::CompatExt;
|
||||
use executor::prelude::Executor;
|
||||
use futures_util::ready;
|
||||
use miette::IntoDiagnostic;
|
||||
use rumqttc::ConnectReturnCode::Success;
|
||||
use rumqttc::{AsyncClient, ConnectionError, Event, Incoming, MqttOptions};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use async_channel as channel;
|
||||
use async_oneshot as oneshot;
|
||||
use futures_signals::signal::Signal;
|
||||
use futures_util::future::BoxFuture;
|
||||
use crate::resources::claim::{ResourceID, UserID};
|
||||
use crate::resources::state::State;
|
||||
use std::time::Duration;
|
||||
use tracing::Span;
|
||||
use url::Url;
|
||||
|
||||
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,
|
||||
mod dummy;
|
||||
mod process;
|
||||
|
||||
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>>>;
|
||||
pub trait Initiator: Future<Output = ()> {
|
||||
fn new(params: &HashMap<String, String>, callbacks: InitiatorCallbacks) -> miette::Result<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
|
||||
<Self as Future>::poll(self, cx)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UpdateSink {
|
||||
tx: channel::Sender<(Option<UserID>, State)>,
|
||||
rx: channel::Receiver<Result<(), Error>>,
|
||||
pub struct InitiatorCallbacks {
|
||||
span: Span,
|
||||
resource: Resource,
|
||||
sessions: SessionManager,
|
||||
}
|
||||
|
||||
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 {
|
||||
return Err(UpdateError::Closed);
|
||||
}
|
||||
|
||||
match self.rx.recv().await {
|
||||
Ok(Ok(())) => Ok(()),
|
||||
Ok(Err(Error::Denied)) => Err(UpdateError::Denied),
|
||||
Ok(Err(Error::Internal(e))) => Err(UpdateError::Other(e)),
|
||||
// RecvError is send only when the channel is closed
|
||||
Err(_) => Err(UpdateError::Closed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Resource;
|
||||
pub struct InitiatorDriver<S, I: Initiator> {
|
||||
// TODO: make this a static reference to the resources because it's much easier and we don't
|
||||
// need to replace resources at runtime at the moment.
|
||||
resource_signal: S,
|
||||
resource: Option<channel::Sender<Update>>,
|
||||
|
||||
// TODO: Initiators should instead
|
||||
error_channel: Option<oneshot::Receiver<Error>>,
|
||||
|
||||
initiator: I,
|
||||
initiator_future: Option<BoxFuture<'static, Result<(), Box<dyn InitiatorError>>>>,
|
||||
update_sink: UpdateSink,
|
||||
initiator_req_rx: channel::Receiver<(Option<UserID>, State)>,
|
||||
initiator_reply_tx: channel::Sender<Result<(), Error>>,
|
||||
}
|
||||
|
||||
pub struct ResourceSink {
|
||||
pub id: ResourceID,
|
||||
pub state_sink: channel::Sender<Update>,
|
||||
}
|
||||
|
||||
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 = UpdateSink::new(initiator_req_tx, initiator_reply_rx);
|
||||
impl InitiatorCallbacks {
|
||||
pub fn new(span: Span, resource: Resource, sessions: SessionManager) -> Self {
|
||||
Self {
|
||||
resource: None,
|
||||
resource_signal,
|
||||
error_channel: None,
|
||||
|
||||
initiator,
|
||||
initiator_future: None,
|
||||
update_sink,
|
||||
initiator_req_rx,
|
||||
initiator_reply_tx,
|
||||
span,
|
||||
resource,
|
||||
sessions,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn try_update(&mut self, session: SessionHandle, status: Status) {
|
||||
self.resource.try_update(session, status).await
|
||||
}
|
||||
|
||||
pub fn set_status(&mut self, status: Status) {
|
||||
self.resource.set_status(status)
|
||||
}
|
||||
|
||||
pub fn open_session(&self, uid: &str) -> Option<SessionHandle> {
|
||||
self.sessions.open(&self.span, uid)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Signal<Item=ResourceSink> + Unpin, I: Initiator + Unpin> Future for InitiatorDriver<S, I> {
|
||||
pub struct InitiatorDriver {
|
||||
span: Span,
|
||||
name: String,
|
||||
initiator: Box<dyn Initiator + Unpin + Send>,
|
||||
}
|
||||
|
||||
impl InitiatorDriver {
|
||||
pub fn new<I>(
|
||||
span: Span,
|
||||
name: String,
|
||||
params: &HashMap<String, String>,
|
||||
resource: Resource,
|
||||
sessions: SessionManager,
|
||||
) -> miette::Result<Self>
|
||||
where
|
||||
I: 'static + Initiator + Unpin + Send,
|
||||
{
|
||||
let callbacks = InitiatorCallbacks::new(span.clone(), resource, sessions);
|
||||
let initiator = Box::new(I::new(params, callbacks)?);
|
||||
Ok(Self {
|
||||
span,
|
||||
name,
|
||||
initiator,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for InitiatorDriver {
|
||||
type Output = ();
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
match Pin::new(&mut self.resource_signal).poll_change(cx) {
|
||||
Poll::Ready(Some(resource)) => {
|
||||
self.resource = Some(resource.state_sink);
|
||||
self.error_channel = None;
|
||||
let f = Box::pin(self.initiator.start_for(resource.id));
|
||||
self.initiator_future.replace(f);
|
||||
},
|
||||
Poll::Ready(None) => self.resource = None,
|
||||
Poll::Pending => {}
|
||||
}
|
||||
let _guard = tracing::info_span!("initiator poll", initiator=%self.name);
|
||||
tracing::trace!(initiator=%self.name, "polling initiator");
|
||||
|
||||
// do while there is work to do
|
||||
while {
|
||||
// First things first:
|
||||
// If we've send an update to the resources in question we have error channel set, so
|
||||
// we poll that first to determine if the resources has acted on it yet.
|
||||
if let Some(ref mut errchan) = self.error_channel {
|
||||
match Pin::new(errchan).poll(cx) {
|
||||
// In case there's an ongoing
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(Ok(error)) => {
|
||||
self.error_channel = None;
|
||||
self.initiator_reply_tx.send(Err(error));
|
||||
}
|
||||
Poll::Ready(Err(_closed)) => {
|
||||
// Error channel was dropped which means there was no error
|
||||
self.error_channel = None;
|
||||
self.initiator_reply_tx.send(Ok(()));
|
||||
}
|
||||
}
|
||||
}
|
||||
ready!(Pin::new(&mut self.initiator).poll(cx));
|
||||
|
||||
if let Some(ref mut init_fut) = self.initiator_future {
|
||||
match init_fut.as_mut().poll(cx) {
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(Ok(())) => {},
|
||||
Poll::Ready(Err(_e)) => {
|
||||
// TODO: Log initiator error here
|
||||
}
|
||||
}
|
||||
} else if let Some(ref mut _resource) = self.resource {
|
||||
let mut s = self.update_sink.clone();
|
||||
let f = self.initiator.run(&mut s);
|
||||
self.initiator_future.replace(f);
|
||||
}
|
||||
|
||||
self.error_channel.is_some()
|
||||
} {}
|
||||
tracing::warn!(initiator=%self.name, "initiator module ran to completion!");
|
||||
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(
|
||||
executor: Executor,
|
||||
config: &Config,
|
||||
resources: ResourcesHandle,
|
||||
sessions: SessionManager,
|
||||
authentication: AuthenticationHandle,
|
||||
) -> miette::Result<()> {
|
||||
let span = tracing::info_span!("loading initiators");
|
||||
let _guard = span.enter();
|
||||
|
||||
let mut initiator_map: HashMap<String, Resource> = config
|
||||
.init_connections
|
||||
.iter()
|
||||
.filter_map(|(k, v)| {
|
||||
if let Some(resource) = resources.get_by_id(v) {
|
||||
Some((k.clone(), resource.clone()))
|
||||
} else {
|
||||
tracing::error!(initiator=%k, machine=%v,
|
||||
"Machine configured for initiator not found!");
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (name, cfg) in config.initiators.iter() {
|
||||
if let Some(resource) = initiator_map.remove(name) {
|
||||
if let Some(driver) = load_single(name, &cfg.module, &cfg.params, resource, &sessions) {
|
||||
tracing::debug!(module_name=%cfg.module, %name, "starting initiator task");
|
||||
executor.spawn(driver);
|
||||
} else {
|
||||
tracing::error!(module_name=%cfg.module, %name, "Initiator module could not be configured");
|
||||
}
|
||||
} else {
|
||||
tracing::warn!(actor=%name, ?config, "Initiator has no machine configured. Skipping!");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_single(
|
||||
name: &String,
|
||||
module_name: &String,
|
||||
params: &HashMap<String, String>,
|
||||
resource: Resource,
|
||||
sessions: &SessionManager,
|
||||
) -> Option<InitiatorDriver> {
|
||||
let span = tracing::info_span!(
|
||||
"initiator",
|
||||
name = %name,
|
||||
module = %module_name,
|
||||
);
|
||||
tracing::info!(%name, %module_name, ?params, "Loading initiator");
|
||||
let o = match module_name.as_ref() {
|
||||
"Dummy" => Some(InitiatorDriver::new::<Dummy>(
|
||||
span,
|
||||
name.clone(),
|
||||
params,
|
||||
resource,
|
||||
sessions.clone(),
|
||||
)),
|
||||
"Process" => Some(InitiatorDriver::new::<Process>(
|
||||
span,
|
||||
name.clone(),
|
||||
params,
|
||||
resource,
|
||||
sessions.clone(),
|
||||
)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
o.transpose().unwrap_or_else(|error| {
|
||||
tracing::error!(%error, "failed to configure initiator");
|
||||
None
|
||||
})
|
||||
}
|
||||
|
227
bffhd/initiators/process.rs
Normal file
227
bffhd/initiators/process.rs
Normal file
@ -0,0 +1,227 @@
|
||||
use super::Initiator;
|
||||
use super::InitiatorCallbacks;
|
||||
use crate::resources::state::State;
|
||||
use crate::utils::linebuffer::LineBuffer;
|
||||
use async_process::{Child, ChildStderr, ChildStdout, Command, Stdio};
|
||||
use futures_lite::{ready, AsyncRead};
|
||||
use miette::{miette, IntoDiagnostic};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use crate::resources::modules::fabaccess::Status;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum InputMessage {
|
||||
#[serde(rename = "state")]
|
||||
SetState(Status),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct OutputLine {}
|
||||
|
||||
pub struct Process {
|
||||
pub cmd: String,
|
||||
pub args: Vec<String>,
|
||||
state: Option<ProcessState>,
|
||||
buffer: LineBuffer,
|
||||
err_buffer: LineBuffer,
|
||||
callbacks: InitiatorCallbacks,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
fn spawn(&mut self) -> io::Result<()> {
|
||||
let mut child = Command::new(&self.cmd)
|
||||
.args(&self.args)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?;
|
||||
self.state = Some(ProcessState::new(
|
||||
child
|
||||
.stdout
|
||||
.take()
|
||||
.expect("Child just spawned with piped stdout has no stdout"),
|
||||
child
|
||||
.stderr
|
||||
.take()
|
||||
.expect("Child just spawned with piped stderr has no stderr"),
|
||||
child,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcessState {
|
||||
pub stdout: ChildStdout,
|
||||
pub stderr: ChildStderr,
|
||||
pub stderr_closed: bool,
|
||||
pub child: Child,
|
||||
}
|
||||
|
||||
impl ProcessState {
|
||||
pub fn new(stdout: ChildStdout, stderr: ChildStderr, child: Child) -> Self {
|
||||
Self { stdout, stderr, stderr_closed: false, child }
|
||||
}
|
||||
|
||||
fn try_process(&mut self, buffer: &[u8], callbacks: &mut InitiatorCallbacks) -> usize {
|
||||
tracing::trace!("trying to process current buffer");
|
||||
|
||||
let mut end = 0;
|
||||
|
||||
while let Some(idx) = buffer[end..].iter().position(|b| *b == b'\n') {
|
||||
if idx == 0 {
|
||||
end += 1;
|
||||
continue;
|
||||
}
|
||||
let line = &buffer[end..(end + idx)];
|
||||
self.process_line(line, callbacks);
|
||||
end = idx;
|
||||
}
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
fn process_line(&mut self, line: &[u8], callbacks: &mut InitiatorCallbacks) {
|
||||
if !line.is_empty() {
|
||||
let res = std::str::from_utf8(line);
|
||||
if let Err(error) = &res {
|
||||
tracing::warn!(%error, "Initiator sent line with invalid UTF-8");
|
||||
return;
|
||||
}
|
||||
let string = res.unwrap().trim();
|
||||
// Ignore whitespace-only lines
|
||||
if !string.is_empty() {
|
||||
match serde_json::from_str::<InputMessage>(res.unwrap()) {
|
||||
Ok(state) => {
|
||||
tracing::trace!(?state, "got new state for process initiator");
|
||||
let InputMessage::SetState(status) = state;
|
||||
callbacks.set_status(status);
|
||||
}
|
||||
Err(error) => tracing::warn!(%error, "process initiator did not send a valid line"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for Process {
|
||||
type Output = ();
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
if let Process {
|
||||
state: Some(state),
|
||||
buffer,
|
||||
err_buffer,
|
||||
callbacks,
|
||||
..
|
||||
} = self.get_mut()
|
||||
{
|
||||
match state.child.try_status() {
|
||||
Err(error) => {
|
||||
tracing::error!(%error, "checking child exit code returned an error");
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Ok(Some(exitcode)) => {
|
||||
tracing::warn!(%exitcode, "child process exited");
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Ok(None) => {
|
||||
tracing::trace!("process initiator checking on process");
|
||||
|
||||
let stdout = &mut state.stdout;
|
||||
|
||||
loop {
|
||||
let buf = buffer.get_mut_write(512);
|
||||
match AsyncRead::poll_read(Pin::new(stdout), cx, buf) {
|
||||
Poll::Pending => break,
|
||||
Poll::Ready(Ok(read)) => {
|
||||
buffer.advance_valid(read);
|
||||
continue;
|
||||
}
|
||||
Poll::Ready(Err(error)) => {
|
||||
tracing::warn!(%error, "reading from child stdout errored");
|
||||
return Poll::Ready(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let processed = state.try_process(buffer, callbacks);
|
||||
buffer.consume(processed);
|
||||
|
||||
if !state.stderr_closed {
|
||||
let stderr = &mut state.stderr;
|
||||
loop {
|
||||
let buf = err_buffer.get_mut_write(512);
|
||||
match AsyncRead::poll_read(Pin::new(stderr), cx, buf) {
|
||||
Poll::Pending => break,
|
||||
Poll::Ready(Ok(read)) => {
|
||||
err_buffer.advance_valid(read);
|
||||
continue;
|
||||
}
|
||||
Poll::Ready(Err(error)) => {
|
||||
tracing::warn!(%error, "reading from child stderr errored");
|
||||
state.stderr_closed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut consumed = 0;
|
||||
|
||||
while let Some(idx) = buffer[consumed..].iter().position(|b| *b == b'\n') {
|
||||
if idx == 0 {
|
||||
consumed += 1;
|
||||
continue;
|
||||
}
|
||||
let line = &buffer[consumed..(consumed + idx)];
|
||||
match std::str::from_utf8(line) {
|
||||
Ok(line) => tracing::debug!(line, "initiator STDERR"),
|
||||
Err(error) => tracing::debug!(%error,
|
||||
"invalid UTF-8 on initiator STDERR"),
|
||||
}
|
||||
consumed = idx;
|
||||
}
|
||||
err_buffer.consume(consumed);
|
||||
}
|
||||
|
||||
return Poll::Pending;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tracing::warn!("process initiator has no process attached!");
|
||||
}
|
||||
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Initiator for Process {
|
||||
fn new(params: &HashMap<String, String>, callbacks: InitiatorCallbacks) -> miette::Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let cmd = params
|
||||
.get("cmd")
|
||||
.ok_or(miette!("Process initiator requires a `cmd` parameter."))?
|
||||
.clone();
|
||||
let args = params
|
||||
.get("args")
|
||||
.map(|argv| argv.split_whitespace().map(|s| s.to_string()).collect())
|
||||
.unwrap_or_else(Vec::new);
|
||||
let mut this = Self {
|
||||
cmd,
|
||||
args,
|
||||
state: None,
|
||||
buffer: LineBuffer::new(),
|
||||
err_buffer: LineBuffer::new(),
|
||||
callbacks,
|
||||
};
|
||||
this.spawn().into_diagnostic()?;
|
||||
Ok(this)
|
||||
}
|
||||
}
|
105
bffhd/lib.rs
105
bffhd/lib.rs
@ -24,6 +24,7 @@ pub mod users;
|
||||
pub mod resources;
|
||||
|
||||
pub mod actors;
|
||||
pub mod initiators;
|
||||
|
||||
pub mod sensors;
|
||||
|
||||
@ -31,6 +32,9 @@ pub mod capnp;
|
||||
|
||||
pub mod utils;
|
||||
|
||||
// Store build information in the `env` module.
|
||||
shadow_rs::shadow!(env);
|
||||
|
||||
mod audit;
|
||||
mod keylog;
|
||||
mod logging;
|
||||
@ -39,9 +43,8 @@ mod tls;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
|
||||
use futures_util::StreamExt;
|
||||
use futures_util::{FutureExt, StreamExt};
|
||||
use miette::{Context, IntoDiagnostic, Report};
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::audit::AuditLog;
|
||||
@ -58,10 +61,9 @@ use crate::tls::TlsConfig;
|
||||
use crate::users::db::UserDB;
|
||||
use crate::users::Users;
|
||||
use executor::pool::Executor;
|
||||
use lightproc::recoverable_handle::RecoverableHandle;
|
||||
use signal_hook::consts::signal::*;
|
||||
|
||||
pub const VERSION_STRING: &'static str = env!("BFFHD_VERSION_STRING");
|
||||
pub const RELEASE_STRING: &'static str = env!("BFFHD_RELEASE_STRING");
|
||||
use tracing::Span;
|
||||
|
||||
pub struct Diflouroborane {
|
||||
config: Config,
|
||||
@ -70,28 +72,58 @@ pub struct Diflouroborane {
|
||||
pub users: Users,
|
||||
pub roles: Roles,
|
||||
pub resources: ResourcesHandle,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
pub static RESOURCES: OnceCell<ResourcesHandle> = OnceCell::new();
|
||||
|
||||
impl Diflouroborane {
|
||||
pub fn new(config: Config) -> anyhow::Result<Self> {
|
||||
logging::init(&config.logging);
|
||||
tracing::info!(version = VERSION_STRING, "Starting BFFH");
|
||||
struct SignalHandlerErr;
|
||||
impl error::Description for SignalHandlerErr {
|
||||
const CODE: &'static str = "signals::new";
|
||||
}
|
||||
|
||||
let span = tracing::info_span!("setup");
|
||||
let _guard = span.enter();
|
||||
impl Diflouroborane {
|
||||
pub fn setup() {}
|
||||
|
||||
pub fn new(config: Config) -> miette::Result<Self> {
|
||||
let mut server = logging::init(&config.logging);
|
||||
let span = tracing::info_span!(
|
||||
target: "bffh",
|
||||
"bffh"
|
||||
);
|
||||
let span2 = span.clone();
|
||||
let _guard = span2.enter();
|
||||
tracing::info!(version = env::VERSION, "Starting BFFH");
|
||||
|
||||
let executor = Executor::new();
|
||||
|
||||
let env = StateDB::open_env(&config.db_path)?;
|
||||
let statedb =
|
||||
StateDB::create_with_env(env.clone()).context("Failed to open state DB file")?;
|
||||
if let Some(aggregator) = server.aggregator.take() {
|
||||
executor.spawn(aggregator.run());
|
||||
}
|
||||
tracing::info!("Server is being spawned");
|
||||
let handle = executor.spawn(server.serve());
|
||||
executor.spawn(handle.map(|result| match result {
|
||||
Some(Ok(())) => {
|
||||
tracing::info!("console server finished without error");
|
||||
}
|
||||
Some(Err(error)) => {
|
||||
tracing::info!(%error, "console server finished with error");
|
||||
}
|
||||
None => {
|
||||
tracing::info!("console server finished with panic");
|
||||
}
|
||||
}));
|
||||
|
||||
let users = Users::new(env.clone()).context("Failed to open users DB file")?;
|
||||
let env = StateDB::open_env(&config.db_path)?;
|
||||
|
||||
let statedb = StateDB::create_with_env(env.clone())?;
|
||||
|
||||
let users = Users::new(env.clone())?;
|
||||
let roles = Roles::new(config.roles.clone());
|
||||
|
||||
let _audit_log = AuditLog::new(&config).context("Failed to initialize audit log")?;
|
||||
let _audit_log = AuditLog::new(&config)
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to initialize audit log")?;
|
||||
|
||||
let resources = ResourcesHandle::new(config.machines.iter().map(|(id, desc)| {
|
||||
Resource::new(Arc::new(resources::Inner::new(
|
||||
@ -109,21 +141,31 @@ impl Diflouroborane {
|
||||
users,
|
||||
roles,
|
||||
resources,
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> anyhow::Result<()> {
|
||||
pub fn run(&mut self) -> miette::Result<()> {
|
||||
let _guard = self.span.enter();
|
||||
let mut signals = signal_hook_async_std::Signals::new(&[SIGINT, SIGQUIT, SIGTERM])
|
||||
.context("Failed to construct signal handler")?;
|
||||
|
||||
actors::load(self.executor.clone(), &self.config, self.resources.clone())?;
|
||||
|
||||
let tlsconfig = TlsConfig::new(self.config.tlskeylog.as_ref(), !self.config.is_quiet())?;
|
||||
let acceptor = tlsconfig.make_tls_acceptor(&self.config.tlsconfig)?;
|
||||
.map_err(|ioerr| error::wrap::<SignalHandlerErr>(ioerr.into()))?;
|
||||
|
||||
let sessionmanager = SessionManager::new(self.users.clone(), self.roles.clone());
|
||||
let authentication = AuthenticationHandle::new(self.users.clone());
|
||||
|
||||
initiators::load(
|
||||
self.executor.clone(),
|
||||
&self.config,
|
||||
self.resources.clone(),
|
||||
sessionmanager.clone(),
|
||||
authentication.clone(),
|
||||
);
|
||||
actors::load(self.executor.clone(), &self.config, self.resources.clone())?;
|
||||
|
||||
let tlsconfig = TlsConfig::new(self.config.tlskeylog.as_ref(), !self.config.is_quiet())
|
||||
.into_diagnostic()?;
|
||||
let acceptor = tlsconfig.make_tls_acceptor(&self.config.tlsconfig)?;
|
||||
|
||||
let apiserver = self.executor.run(APIServer::bind(
|
||||
self.executor.clone(),
|
||||
&self.config.listens,
|
||||
@ -150,3 +192,18 @@ impl Diflouroborane {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ShutdownHandler {
|
||||
tasks: Vec<RecoverableHandle<()>>,
|
||||
}
|
||||
impl ShutdownHandler {
|
||||
pub fn new(tasks: Vec<RecoverableHandle<()>>) -> Self {
|
||||
Self { tasks }
|
||||
}
|
||||
|
||||
pub fn shutdown(&mut self) {
|
||||
for handle in self.tasks.drain(..) {
|
||||
handle.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use tracing_subscriber::fmt::format::Format;
|
||||
use tracing_subscriber::prelude::*;
|
||||
use tracing_subscriber::reload::Handle;
|
||||
use tracing_subscriber::{reload, EnvFilter};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LogConfig {
|
||||
@ -24,21 +27,49 @@ impl Default for LogConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(config: &LogConfig) {
|
||||
pub enum LogOutput<'a> {
|
||||
Journald,
|
||||
Stdout,
|
||||
File(&'a Path),
|
||||
}
|
||||
pub struct LogConfig2<'a, F> {
|
||||
output: LogOutput<'a>,
|
||||
filter_str: Option<&'a str>,
|
||||
format: Format<F>,
|
||||
}
|
||||
|
||||
pub fn init(config: &LogConfig) -> console::Server {
|
||||
let subscriber = tracing_subscriber::registry();
|
||||
|
||||
let (console_layer, server) = console::ConsoleLayer::new();
|
||||
let subscriber = subscriber.with(console_layer);
|
||||
|
||||
let filter = if let Some(ref filter) = config.filter {
|
||||
EnvFilter::new(filter.as_str())
|
||||
} else {
|
||||
EnvFilter::from_env("BFFH_LOG")
|
||||
};
|
||||
|
||||
let builder = tracing_subscriber::fmt().with_env_filter(filter);
|
||||
|
||||
let format = config.format.to_lowercase();
|
||||
match format.as_str() {
|
||||
"compact" => builder.compact().init(),
|
||||
"pretty" => builder.pretty().init(),
|
||||
"full" => builder.init(),
|
||||
_ => builder.init(),
|
||||
|
||||
let fmt_layer = tracing_subscriber::fmt::layer();
|
||||
|
||||
match format.as_ref() {
|
||||
"pretty" => {
|
||||
let fmt_layer = fmt_layer.pretty().with_filter(filter);
|
||||
subscriber.with(fmt_layer).init();
|
||||
}
|
||||
"compact" => {
|
||||
let fmt_layer = fmt_layer.compact().with_filter(filter);
|
||||
subscriber.with(fmt_layer).init();
|
||||
}
|
||||
_ => {
|
||||
let fmt_layer = fmt_layer.with_filter(filter);
|
||||
subscriber.with(fmt_layer).init();
|
||||
}
|
||||
}
|
||||
tracing::info!(format = format.as_str(), "Logging initialized")
|
||||
|
||||
tracing::info!(format = format.as_str(), "Logging initialized");
|
||||
|
||||
server
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ pub mod modules;
|
||||
|
||||
pub struct PermissionDenied;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Inner {
|
||||
id: String,
|
||||
db: StateDB,
|
||||
@ -94,7 +95,7 @@ impl Inner {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Resource {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
@ -165,7 +166,7 @@ impl Resource {
|
||||
self.inner.set_state(archived)
|
||||
}
|
||||
|
||||
fn set_status(&self, state: Status) {
|
||||
pub fn set_status(&self, state: Status) {
|
||||
let old = self.inner.get_state();
|
||||
let oldref: &Archived<State> = old.as_ref();
|
||||
let previous: &Archived<Option<UserRef>> = &oldref.inner.previous;
|
||||
|
@ -1,9 +1,9 @@
|
||||
use crate::config::deser_option;
|
||||
use crate::utils::oid::ObjectIdentifier;
|
||||
use once_cell::sync::Lazy;
|
||||
use rkyv::{Archive, Archived, Deserialize, Infallible};
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
//use crate::oidvalue;
|
||||
@ -54,6 +54,11 @@ pub enum Status {
|
||||
/// The status of the machine
|
||||
pub struct MachineState {
|
||||
pub state: Status,
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
deserialize_with = "deser_option"
|
||||
)]
|
||||
pub previous: Option<UserRef>,
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::db;
|
||||
use crate::db::{AlignedAdapter, ArchivedValue, RawDB, DB};
|
||||
use lmdb::{DatabaseFlags, Environment, EnvironmentFlags, Transaction, WriteFlags};
|
||||
use miette::{Diagnostic, LabeledSpan, Severity, SourceCode};
|
||||
use std::any::TypeId;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
use crate::resources::state::State;
|
||||
@ -11,8 +17,24 @@ pub struct StateDB {
|
||||
db: DB<AlignedAdapter<State>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
pub enum StateDBError {
|
||||
#[error("opening the state db environment failed")]
|
||||
#[diagnostic(
|
||||
code(bffh::db::state::open_env),
|
||||
help("does the parent directory for state_db exist?")
|
||||
)]
|
||||
OpenEnv(#[source] db::Error),
|
||||
#[error("opening the state db failed")]
|
||||
#[diagnostic(code(bffh::db::state::open))]
|
||||
Open(#[source] db::Error),
|
||||
#[error("creating the state db failed")]
|
||||
#[diagnostic(code(bffh::db::state::create))]
|
||||
Create(#[source] db::Error),
|
||||
}
|
||||
|
||||
impl StateDB {
|
||||
pub fn open_env<P: AsRef<Path>>(path: P) -> lmdb::Result<Arc<Environment>> {
|
||||
pub fn open_env<P: AsRef<Path>>(path: P) -> Result<Arc<Environment>, StateDBError> {
|
||||
Environment::new()
|
||||
.set_flags(
|
||||
EnvironmentFlags::WRITE_MAP
|
||||
@ -23,6 +45,7 @@ impl StateDB {
|
||||
.set_max_dbs(8)
|
||||
.open(path.as_ref())
|
||||
.map(Arc::new)
|
||||
.map_err(|e| StateDBError::OpenEnv(e.into()))
|
||||
}
|
||||
|
||||
fn new(env: Arc<Environment>, db: RawDB) -> Self {
|
||||
@ -30,30 +53,32 @@ impl StateDB {
|
||||
Self { env, db }
|
||||
}
|
||||
|
||||
pub fn open_with_env(env: Arc<Environment>) -> lmdb::Result<Self> {
|
||||
let db = unsafe { RawDB::open(&env, Some("state"))? };
|
||||
pub fn open_with_env(env: Arc<Environment>) -> Result<Self, StateDBError> {
|
||||
let db = unsafe { RawDB::open(&env, Some("state")) };
|
||||
let db = db.map_err(|e| StateDBError::Open(e.into()))?;
|
||||
Ok(Self::new(env, db))
|
||||
}
|
||||
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, StateDBError> {
|
||||
let env = Self::open_env(path)?;
|
||||
Self::open_with_env(env)
|
||||
}
|
||||
|
||||
pub fn create_with_env(env: Arc<Environment>) -> lmdb::Result<Self> {
|
||||
pub fn create_with_env(env: Arc<Environment>) -> Result<Self, StateDBError> {
|
||||
let flags = DatabaseFlags::empty();
|
||||
let db = unsafe { RawDB::create(&env, Some("state"), flags)? };
|
||||
let db = unsafe { RawDB::create(&env, Some("state"), flags) };
|
||||
let db = db.map_err(|e| StateDBError::Create(e.into()))?;
|
||||
|
||||
Ok(Self::new(env, db))
|
||||
}
|
||||
|
||||
pub fn create<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
|
||||
pub fn create<P: AsRef<Path>>(path: P) -> Result<Self, StateDBError> {
|
||||
let env = Self::open_env(path)?;
|
||||
Self::create_with_env(env)
|
||||
}
|
||||
|
||||
pub fn begin_ro_txn(&self) -> Result<impl Transaction + '_, db::Error> {
|
||||
self.env.begin_ro_txn()
|
||||
self.env.begin_ro_txn().map_err(db::Error::from)
|
||||
}
|
||||
|
||||
pub fn get(&self, key: impl AsRef<[u8]>) -> Result<Option<ArchivedValue<State>>, db::Error> {
|
||||
@ -72,7 +97,7 @@ impl StateDB {
|
||||
let mut txn = self.env.begin_rw_txn()?;
|
||||
let flags = WriteFlags::empty();
|
||||
self.db.put(&mut txn, key, val, flags)?;
|
||||
txn.commit()
|
||||
Ok(txn.commit()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ use crate::authorization::roles::Roles;
|
||||
use crate::resources::Resource;
|
||||
use crate::users::{db, UserRef};
|
||||
use crate::Users;
|
||||
use tracing::Span;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SessionManager {
|
||||
@ -16,11 +17,18 @@ impl SessionManager {
|
||||
}
|
||||
|
||||
// TODO: make infallible
|
||||
pub fn open(&self, uid: impl AsRef<str>) -> Option<SessionHandle> {
|
||||
pub fn open(&self, parent: &Span, uid: impl AsRef<str>) -> Option<SessionHandle> {
|
||||
let uid = uid.as_ref();
|
||||
if let Some(user) = self.users.get_user(uid) {
|
||||
tracing::trace!(uid, ?user, "opening new session for user");
|
||||
let span = tracing::info_span!(
|
||||
target: "bffh::api",
|
||||
parent: parent,
|
||||
"session",
|
||||
uid = uid,
|
||||
);
|
||||
tracing::trace!(parent: &span, uid, ?user, "opening session");
|
||||
Some(SessionHandle {
|
||||
span,
|
||||
users: self.users.clone(),
|
||||
roles: self.roles.clone(),
|
||||
user: UserRef::new(user.id),
|
||||
@ -33,6 +41,8 @@ impl SessionManager {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SessionHandle {
|
||||
pub span: Span,
|
||||
|
||||
pub users: Users,
|
||||
pub roles: Roles,
|
||||
|
||||
|
22
bffhd/tls.rs
22
bffhd/tls.rs
@ -6,6 +6,7 @@ use std::sync::Arc;
|
||||
|
||||
use crate::capnp::TlsListen;
|
||||
use futures_rustls::TlsAcceptor;
|
||||
use miette::IntoDiagnostic;
|
||||
use rustls::version::{TLS12, TLS13};
|
||||
use rustls::{Certificate, PrivateKey, ServerConfig, SupportedCipherSuite};
|
||||
use tracing::Level;
|
||||
@ -74,26 +75,27 @@ impl TlsConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_tls_acceptor(&self, config: &TlsListen) -> anyhow::Result<TlsAcceptor> {
|
||||
pub fn make_tls_acceptor(&self, config: &TlsListen) -> miette::Result<TlsAcceptor> {
|
||||
let span = tracing::debug_span!("tls");
|
||||
let _guard = span.enter();
|
||||
|
||||
tracing::debug!(path = %config.certfile.as_path().display(), "reading certificates");
|
||||
let mut certfp = BufReader::new(File::open(config.certfile.as_path())?);
|
||||
let certs = rustls_pemfile::certs(&mut certfp)?
|
||||
let mut certfp = BufReader::new(File::open(config.certfile.as_path()).into_diagnostic()?);
|
||||
let certs = rustls_pemfile::certs(&mut certfp)
|
||||
.into_diagnostic()?
|
||||
.into_iter()
|
||||
.map(Certificate)
|
||||
.collect();
|
||||
|
||||
tracing::debug!(path = %config.keyfile.as_path().display(), "reading private key");
|
||||
let mut keyfp = BufReader::new(File::open(config.keyfile.as_path())?);
|
||||
let key = match rustls_pemfile::read_one(&mut keyfp)? {
|
||||
let mut keyfp = BufReader::new(File::open(config.keyfile.as_path()).into_diagnostic()?);
|
||||
let key = match rustls_pemfile::read_one(&mut keyfp).into_diagnostic()? {
|
||||
Some(rustls_pemfile::Item::PKCS8Key(key) | rustls_pemfile::Item::RSAKey(key)) => {
|
||||
PrivateKey(key)
|
||||
}
|
||||
_ => {
|
||||
tracing::error!("private key file invalid");
|
||||
anyhow::bail!("private key file must contain a PEM-encoded private key")
|
||||
miette::bail!("private key file must contain a PEM-encoded private key")
|
||||
}
|
||||
};
|
||||
|
||||
@ -105,15 +107,17 @@ impl TlsConfig {
|
||||
match min.as_str() {
|
||||
"tls12" => tls_builder.with_protocol_versions(&[&TLS12]),
|
||||
"tls13" => tls_builder.with_protocol_versions(&[&TLS13]),
|
||||
x => anyhow::bail!("TLS version {} is invalid", x),
|
||||
x => miette::bail!("TLS version {} is invalid", x),
|
||||
}
|
||||
} else {
|
||||
tls_builder.with_safe_default_protocol_versions()
|
||||
}?;
|
||||
}
|
||||
.into_diagnostic()?;
|
||||
|
||||
let mut tls_config = tls_builder
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(certs, key)?;
|
||||
.with_single_cert(certs, key)
|
||||
.into_diagnostic()?;
|
||||
|
||||
if let Some(keylog) = &self.keylog {
|
||||
tls_config.key_log = keylog.clone();
|
||||
|
@ -2,7 +2,7 @@ use lmdb::{DatabaseFlags, Environment, RwTransaction, Transaction, WriteFlags};
|
||||
use rkyv::Infallible;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Context;
|
||||
use miette::{Context, IntoDiagnostic};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::db;
|
||||
@ -27,19 +27,25 @@ pub struct User {
|
||||
pub userdata: UserData,
|
||||
}
|
||||
|
||||
fn hash_pw(pw: &[u8]) -> argon2::Result<String> {
|
||||
let config = argon2::Config::default();
|
||||
let salt: [u8; 16] = rand::random();
|
||||
argon2::hash_encoded(pw, &salt, &config)
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub fn check_password(&self, pwd: &[u8]) -> anyhow::Result<bool> {
|
||||
pub fn check_password(&self, pwd: &[u8]) -> miette::Result<bool> {
|
||||
if let Some(ref encoded) = self.userdata.passwd {
|
||||
argon2::verify_encoded(encoded, pwd).context("Stored password is an invalid string")
|
||||
argon2::verify_encoded(encoded, pwd)
|
||||
.into_diagnostic()
|
||||
.wrap_err("Stored password is an invalid string")
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_plain_pw(username: &str, password: impl AsRef<[u8]>) -> Self {
|
||||
let config = argon2::Config::default();
|
||||
let salt: [u8; 16] = rand::random();
|
||||
let hash = argon2::hash_encoded(password.as_ref(), &salt, &config)
|
||||
let hash = hash_pw(password.as_ref())
|
||||
.expect(&format!("Failed to hash password for {}: ", username));
|
||||
tracing::debug!("Hashed pw for {} to {}", username, hash);
|
||||
|
||||
@ -51,6 +57,13 @@ impl User {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_pw(&mut self, password: impl AsRef<[u8]>) {
|
||||
self.userdata.passwd = Some(hash_pw(password.as_ref()).expect(&format!(
|
||||
"failed to update hashed password for {}",
|
||||
&self.id
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
@ -109,7 +122,7 @@ impl UserDB {
|
||||
// TODO: Make an userdb-specific Transaction newtype to make this safe
|
||||
pub unsafe fn get_rw_txn(&self) -> Result<RwTransaction, db::Error> {
|
||||
// The returned transaction is only valid for *this* environment.
|
||||
self.env.begin_rw_txn()
|
||||
Ok(self.env.begin_rw_txn()?)
|
||||
}
|
||||
|
||||
pub unsafe fn new(env: Arc<Environment>, db: RawDB) -> Self {
|
||||
@ -174,15 +187,15 @@ impl UserDB {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_all(&self) -> Result<Vec<(String, User)>, db::Error> {
|
||||
pub fn get_all(&self) -> Result<HashMap<String, UserData>, db::Error> {
|
||||
let txn = self.env.begin_ro_txn()?;
|
||||
let iter = self.db.get_all(&txn)?;
|
||||
let mut out = Vec::new();
|
||||
let mut out = HashMap::new();
|
||||
for (uid, user) in iter {
|
||||
let uid = unsafe { std::str::from_utf8_unchecked(uid).to_string() };
|
||||
let user: User =
|
||||
Deserialize::<User, _>::deserialize(user.as_ref(), &mut Infallible).unwrap();
|
||||
out.push((uid, user));
|
||||
out.insert(uid, user.userdata);
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
|
@ -1,12 +1,17 @@
|
||||
use anyhow::Context;
|
||||
use std::fs;
|
||||
|
||||
use lmdb::{Environment, Transaction};
|
||||
use once_cell::sync::OnceCell;
|
||||
use rkyv::{Archive, Deserialize, Infallible, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter, Write};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::io::Write;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use miette::{Context, Diagnostic, IntoDiagnostic, SourceOffset, SourceSpan};
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
pub mod db;
|
||||
|
||||
@ -65,7 +70,7 @@ pub struct Users {
|
||||
}
|
||||
|
||||
impl Users {
|
||||
pub fn new(env: Arc<Environment>) -> anyhow::Result<Self> {
|
||||
pub fn new(env: Arc<Environment>) -> miette::Result<Self> {
|
||||
let span = tracing::debug_span!("users", ?env, "Creating Users handle");
|
||||
let _guard = span.enter();
|
||||
|
||||
@ -74,7 +79,7 @@ impl Users {
|
||||
tracing::debug!("Global resource not yet initialized, initializing…");
|
||||
unsafe { UserDB::create(env) }
|
||||
})
|
||||
.context("Failed to open userdb")?;
|
||||
.wrap_err("Failed to open userdb")?;
|
||||
|
||||
Ok(Self { userdb })
|
||||
}
|
||||
@ -90,19 +95,48 @@ impl Users {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn put_user(&self, uid: &str, user: &db::User) -> Result<(), lmdb::Error> {
|
||||
pub fn put_user(&self, uid: &str, user: &db::User) -> Result<(), crate::db::Error> {
|
||||
tracing::trace!(uid, ?user, "Updating user");
|
||||
self.userdb.put(uid, user)
|
||||
}
|
||||
|
||||
pub fn del_user(&self, uid: &str) -> Result<(), lmdb::Error> {
|
||||
pub fn del_user(&self, uid: &str) -> Result<(), crate::db::Error> {
|
||||
tracing::trace!(uid, "Deleting user");
|
||||
self.userdb.delete(uid)
|
||||
}
|
||||
|
||||
pub fn load_file<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
|
||||
let f = std::fs::read(path)?;
|
||||
let map: HashMap<String, UserData> = toml::from_slice(&f)?;
|
||||
pub fn load_file(&self, path_str: &str) -> miette::Result<()> {
|
||||
let path: &Path = Path::new(path_str);
|
||||
if path.is_dir() {
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("load takes a file, not a directory")]
|
||||
#[diagnostic(
|
||||
code(load::file),
|
||||
url("https://gitlab.com/fabinfra/fabaccess/bffh/-/issues/55")
|
||||
)]
|
||||
struct LoadIsDirError {
|
||||
#[source_code]
|
||||
src: String,
|
||||
|
||||
#[label("path provided")]
|
||||
dir_path: SourceSpan,
|
||||
|
||||
#[help]
|
||||
help: String,
|
||||
}
|
||||
|
||||
Err(LoadIsDirError {
|
||||
src: format!("--load {}", path_str),
|
||||
dir_path: (7, path_str.as_bytes().len()).into(),
|
||||
help: format!(
|
||||
"Provide a path to a file instead, e.g. {}/users.toml",
|
||||
path_str
|
||||
),
|
||||
})?;
|
||||
return Ok(());
|
||||
}
|
||||
let f = std::fs::read(path).into_diagnostic()?;
|
||||
let map: HashMap<String, UserData> = toml::from_slice(&f).into_diagnostic()?;
|
||||
|
||||
let mut txn = unsafe { self.userdb.get_rw_txn()? };
|
||||
|
||||
@ -132,7 +166,44 @@ impl Users {
|
||||
}
|
||||
}
|
||||
|
||||
txn.commit()?;
|
||||
txn.commit().map_err(crate::db::Error::from)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn dump_file(&self, path_str: &str, force: bool) -> miette::Result<usize> {
|
||||
let path = Path::new(path_str);
|
||||
let exists = path.exists();
|
||||
if exists {
|
||||
if !force {
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("given file already exists, refusing to clobber")]
|
||||
#[diagnostic(code(dump::clobber))]
|
||||
struct DumpFileExists {
|
||||
#[source_code]
|
||||
src: String,
|
||||
|
||||
#[label("file provided")]
|
||||
dir_path: SourceSpan,
|
||||
|
||||
#[help]
|
||||
help: &'static str,
|
||||
}
|
||||
|
||||
Err(DumpFileExists {
|
||||
src: format!("--load {}", path_str),
|
||||
dir_path: (7, path_str.as_bytes().len()).into(),
|
||||
help: "to force overwriting the file add `--force` as argument",
|
||||
})?;
|
||||
} else {
|
||||
tracing::info!("output file already exists, overwriting due to `--force`");
|
||||
}
|
||||
}
|
||||
let mut file = fs::File::create(path).into_diagnostic()?;
|
||||
|
||||
let users = self.userdb.get_all()?;
|
||||
let encoded = toml::ser::to_vec(&users).into_diagnostic()?;
|
||||
file.write_all(&encoded[..]).into_diagnostic()?;
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
60
bffhd/utils/linebuffer.rs
Normal file
60
bffhd/utils/linebuffer.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
pub struct LineBuffer {
|
||||
buffer: Vec<u8>,
|
||||
valid: usize,
|
||||
}
|
||||
|
||||
impl LineBuffer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
buffer: Vec::new(),
|
||||
valid: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Resize the internal Vec so that buffer.len() == buffer.capacity()
|
||||
fn resize(&mut self) {
|
||||
// SAFETY: Whatever is in memory is always valid as u8.
|
||||
unsafe { self.buffer.set_len(self.buffer.capacity()) }
|
||||
}
|
||||
|
||||
/// Get an (initialized but empty) writeable buffer of at least `atleast` bytes
|
||||
pub fn get_mut_write(&mut self, atleast: usize) -> &mut [u8] {
|
||||
let avail = self.buffer.len() - self.valid;
|
||||
if avail < atleast {
|
||||
self.buffer.reserve(atleast - avail);
|
||||
self.resize()
|
||||
}
|
||||
&mut self.buffer[self.valid..]
|
||||
}
|
||||
|
||||
pub fn advance_valid(&mut self, amount: usize) {
|
||||
self.valid += amount
|
||||
}
|
||||
|
||||
/// Mark `amount` bytes as 'consumed'
|
||||
///
|
||||
/// This will move any remaining data to the start of the buffer for future processing
|
||||
pub fn consume(&mut self, amount: usize) {
|
||||
assert!(amount <= self.valid);
|
||||
|
||||
if amount < self.valid {
|
||||
self.buffer.copy_within(amount..self.valid, 0);
|
||||
}
|
||||
self.valid -= amount;
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for LineBuffer {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.buffer[0..self.valid]
|
||||
}
|
||||
}
|
||||
impl DerefMut for LineBuffer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.buffer[0..self.valid]
|
||||
}
|
||||
}
|
@ -8,3 +8,5 @@ pub mod varint;
|
||||
pub mod l10nstring;
|
||||
|
||||
pub mod uuid;
|
||||
|
||||
pub mod linebuffer;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clap::{Arg, Command};
|
||||
use clap::{Arg, Command, ValueHint};
|
||||
use diflouroborane::{config, Diflouroborane};
|
||||
|
||||
use std::str::FromStr;
|
||||
@ -6,33 +6,38 @@ use std::{env, io, io::Write, path::PathBuf};
|
||||
|
||||
use nix::NixPath;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
fn main() -> miette::Result<()> {
|
||||
// Argument parsing
|
||||
// values for the name, description and version are pulled from `Cargo.toml`.
|
||||
let matches = Command::new(clap::crate_name!())
|
||||
.version(clap::crate_version!())
|
||||
.long_version(diflouroborane::VERSION_STRING)
|
||||
.long_version(&*format!("{version}\n\
|
||||
FabAccess {apiver}\n\
|
||||
\t[{build_kind} build built on {build_time}]\n\
|
||||
\t {rustc_version}\n\t {cargo_version}",
|
||||
version=diflouroborane::env::PKG_VERSION,
|
||||
apiver="0.3",
|
||||
rustc_version=diflouroborane::env::RUST_VERSION,
|
||||
cargo_version=diflouroborane::env::CARGO_VERSION,
|
||||
build_time=diflouroborane::env::BUILD_TIME_3339,
|
||||
build_kind=diflouroborane::env::BUILD_RUST_CHANNEL))
|
||||
.about(clap::crate_description!())
|
||||
.arg(
|
||||
Arg::new("config")
|
||||
.arg(Arg::new("config")
|
||||
.help("Path to the config file to use")
|
||||
.long("config")
|
||||
.short('c')
|
||||
.takes_value(true),
|
||||
)
|
||||
.takes_value(true))
|
||||
.arg(Arg::new("verbosity")
|
||||
.help("Increase logging verbosity")
|
||||
.long("verbose")
|
||||
.short('v')
|
||||
.multiple_occurrences(true)
|
||||
.max_occurrences(3)
|
||||
.conflicts_with("quiet")
|
||||
)
|
||||
.conflicts_with("quiet"))
|
||||
.arg(Arg::new("quiet")
|
||||
.help("Decrease logging verbosity")
|
||||
.long("quiet")
|
||||
.conflicts_with("verbosity")
|
||||
)
|
||||
.conflicts_with("verbosity"))
|
||||
.arg(Arg::new("log format")
|
||||
.help("Use an alternative log formatter. Available: Full, Compact, Pretty")
|
||||
.long("log-format")
|
||||
@ -46,26 +51,36 @@ fn main() -> anyhow::Result<()> {
|
||||
.arg(
|
||||
Arg::new("print default")
|
||||
.help("Print a default config to stdout instead of running")
|
||||
.long("print-default"),
|
||||
)
|
||||
.long("print-default"))
|
||||
.arg(
|
||||
Arg::new("check config")
|
||||
.help("Check config for validity")
|
||||
.long("check"),
|
||||
)
|
||||
.long("check"))
|
||||
.arg(
|
||||
Arg::new("dump")
|
||||
.help("Dump all internal databases")
|
||||
.long("dump")
|
||||
.conflicts_with("load"),
|
||||
.conflicts_with("load"))
|
||||
.arg(
|
||||
Arg::new("dump-users")
|
||||
.help("Dump the users db to the given file as TOML")
|
||||
.long("dump-users")
|
||||
.takes_value(true)
|
||||
.value_name("FILE")
|
||||
.value_hint(ValueHint::AnyPath)
|
||||
.default_missing_value("users.toml")
|
||||
.conflicts_with("load"))
|
||||
.arg(
|
||||
Arg::new("force")
|
||||
.help("force ops that may clobber")
|
||||
.long("force")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("load")
|
||||
.help("Load values into the internal databases")
|
||||
.long("load")
|
||||
.takes_value(true)
|
||||
.conflicts_with("dump"),
|
||||
)
|
||||
.conflicts_with("dump"))
|
||||
.arg(Arg::new("keylog")
|
||||
.help("log TLS keys into PATH. If no path is specified the value of the envvar SSLKEYLOGFILE is used.")
|
||||
.long("tls-key-log")
|
||||
@ -73,9 +88,13 @@ fn main() -> anyhow::Result<()> {
|
||||
.takes_value(true)
|
||||
.max_values(1)
|
||||
.min_values(0)
|
||||
.default_missing_value("")
|
||||
)
|
||||
.get_matches();
|
||||
.default_missing_value(""))
|
||||
.try_get_matches();
|
||||
|
||||
let matches = match matches {
|
||||
Ok(m) => m,
|
||||
Err(error) => error.exit(),
|
||||
};
|
||||
|
||||
let configpath = matches
|
||||
.value_of("config")
|
||||
@ -116,24 +135,28 @@ fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let mut config = config::read(&PathBuf::from_str(configpath).unwrap()).unwrap();
|
||||
let mut config = config::read(&PathBuf::from_str(configpath).unwrap())?;
|
||||
|
||||
if matches.is_present("dump") {
|
||||
unimplemented!()
|
||||
return Err(miette::miette!("DB Dumping is currently not implemented, except for the users db, using `--dump-users`"));
|
||||
} else if matches.is_present("dump-users") {
|
||||
let bffh = Diflouroborane::new(config)?;
|
||||
|
||||
let number = bffh.users.dump_file(
|
||||
matches.value_of("dump-users").unwrap(),
|
||||
matches.is_present("force"),
|
||||
)?;
|
||||
|
||||
tracing::info!("successfully dumped {} users", number);
|
||||
|
||||
return Ok(());
|
||||
} else if matches.is_present("load") {
|
||||
let bffh = Diflouroborane::new(config)?;
|
||||
if bffh
|
||||
.users
|
||||
.load_file(matches.value_of("load").unwrap())
|
||||
.is_ok()
|
||||
{
|
||||
tracing::info!("loaded users from {}", matches.value_of("load").unwrap());
|
||||
} else {
|
||||
tracing::error!(
|
||||
"failed to load users from {}",
|
||||
matches.value_of("load").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
bffh.users.load_file(matches.value_of("load").unwrap())?;
|
||||
|
||||
tracing::info!("loaded users from {}", matches.value_of("load").unwrap());
|
||||
|
||||
return Ok(());
|
||||
} else {
|
||||
let keylog = matches.value_of("keylog");
|
||||
|
60
build.rs
60
build.rs
@ -1,60 +1,4 @@
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
println!(">>> Building version number...");
|
||||
|
||||
let rustc = std::env::var("RUSTC").unwrap();
|
||||
let out = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
let rustc_version =
|
||||
String::from_utf8(out.stdout).expect("rustc --version returned invalid UTF-8");
|
||||
let rustc_version = rustc_version.trim();
|
||||
println!("cargo:rustc-env=CARGO_RUSTC_VERSION={}", rustc_version);
|
||||
|
||||
println!("cargo:rerun-if-env-changed=BFFHD_BUILD_TAGGED_RELEASE");
|
||||
let tagged_release = option_env!("BFFHD_BUILD_TAGGED_RELEASE") == Some("1");
|
||||
let version_string = if tagged_release {
|
||||
format!(
|
||||
"{version} [{rustc}]",
|
||||
version = env!("CARGO_PKG_VERSION"),
|
||||
rustc = rustc_version
|
||||
)
|
||||
} else {
|
||||
// Build version number using the current git commit id
|
||||
let out = Command::new("git")
|
||||
.arg("rev-list")
|
||||
.args(["HEAD", "-1"])
|
||||
.output()
|
||||
.expect("failed to run `git rev-list HEAD -1`");
|
||||
let owned_gitrev =
|
||||
String::from_utf8(out.stdout).expect("git rev-list output was not valid UTF8");
|
||||
let gitrev = owned_gitrev.trim();
|
||||
let abbrev = match gitrev.len() {
|
||||
0 => "unknown",
|
||||
_ => &gitrev[0..9],
|
||||
};
|
||||
|
||||
let out = Command::new("git")
|
||||
.arg("log")
|
||||
.args(["-1", "--format=%as"])
|
||||
.output()
|
||||
.expect("failed to run `git log -1 --format=\"format:%as\"`");
|
||||
let commit_date = String::from_utf8(out.stdout).expect("git log output was not valid UTF8");
|
||||
let commit_date = commit_date.trim();
|
||||
|
||||
format!(
|
||||
"{version} ({gitrev} {date}) [{rustc}]",
|
||||
version = env!("CARGO_PKG_VERSION"),
|
||||
gitrev = abbrev,
|
||||
date = commit_date,
|
||||
rustc = rustc_version
|
||||
)
|
||||
};
|
||||
println!("cargo:rustc-env=BFFHD_VERSION_STRING={}", version_string);
|
||||
println!(
|
||||
"cargo:rustc-env=BFFHD_RELEASE_STRING=\"BFFH {}\"",
|
||||
version_string
|
||||
);
|
||||
// Extract build-time information using the `shadow-rs` crate
|
||||
shadow_rs::new();
|
||||
}
|
||||
|
13
examples/init.py
Executable file
13
examples/init.py
Executable file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
while True:
|
||||
print('{ "state": { "1.3.6.1.4.1.48398.612.2.4": { "state": "Free" } } }')
|
||||
sys.stdout.flush()
|
||||
time.sleep(2)
|
||||
|
||||
print('{ "state": { "1.3.6.1.4.1.48398.612.2.4": { "state": { "InUse": { "id": "Testuser" } } } } }')
|
||||
sys.stdout.flush()
|
||||
time.sleep(2)
|
30
runtime/console/Cargo.toml
Normal file
30
runtime/console/Cargo.toml
Normal file
@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "console"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
console-api = "0.3"
|
||||
prost-types = "0.10"
|
||||
tonic = { version = "0.7.2", default_features = false, features = [] }
|
||||
hyper = { version = "0.14", default_features = false, features = ["http2", "server", "stream"] }
|
||||
thread_local = "1.1"
|
||||
tracing = "0.1"
|
||||
tracing-core = "0.1"
|
||||
tracing-subscriber = { version = "0.3", default_features = false, features = ["registry"] }
|
||||
crossbeam-utils = "0.8"
|
||||
crossbeam-channel = "0.5"
|
||||
async-net = "1.6"
|
||||
async-compat = "0.2"
|
||||
async-channel = "1.6"
|
||||
async-oneshot = "0.5"
|
||||
async-io = "1.7"
|
||||
tokio-util = "0.7"
|
||||
futures-util = "0.3"
|
||||
tokio = { version = "1.19", default_features = false, features = []}
|
||||
hdrhistogram = "7.5"
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3"
|
461
runtime/console/src/aggregate.rs
Normal file
461
runtime/console/src/aggregate.rs
Normal file
@ -0,0 +1,461 @@
|
||||
use crate::id_map::{IdMap, ToProto};
|
||||
use crate::server::{Watch, WatchRequest};
|
||||
use crate::stats::{TimeAnchor, Unsent};
|
||||
use crate::{server, stats};
|
||||
use crate::{Event, Shared};
|
||||
use console_api::{async_ops, instrument, resources, tasks};
|
||||
use crossbeam_channel::{Receiver, TryRecvError};
|
||||
use futures_util::{FutureExt, StreamExt};
|
||||
use std::collections::HashMap;
|
||||
use std::num::NonZeroU64;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tracing::span;
|
||||
use tracing_core::Metadata;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Resource {
|
||||
id: span::Id,
|
||||
is_dirty: AtomicBool,
|
||||
parent_id: Option<span::Id>,
|
||||
metadata: &'static Metadata<'static>,
|
||||
concrete_type: String,
|
||||
kind: resources::resource::Kind,
|
||||
location: Option<console_api::Location>,
|
||||
is_internal: bool,
|
||||
}
|
||||
|
||||
/// Represents static data for tasks
|
||||
#[derive(Debug)]
|
||||
struct Task {
|
||||
id: span::Id,
|
||||
is_dirty: AtomicBool,
|
||||
metadata: &'static Metadata<'static>,
|
||||
fields: Vec<console_api::Field>,
|
||||
location: Option<console_api::Location>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AsyncOp {
|
||||
id: span::Id,
|
||||
is_dirty: AtomicBool,
|
||||
parent_id: Option<span::Id>,
|
||||
resource_id: span::Id,
|
||||
metadata: &'static Metadata<'static>,
|
||||
source: String,
|
||||
}
|
||||
|
||||
impl ToProto for Task {
|
||||
type Output = tasks::Task;
|
||||
|
||||
fn to_proto(&self, _: &stats::TimeAnchor) -> Self::Output {
|
||||
tasks::Task {
|
||||
id: Some(self.id.clone().into()),
|
||||
// TODO: more kinds of tasks...
|
||||
kind: tasks::task::Kind::Spawn as i32,
|
||||
metadata: Some(self.metadata.into()),
|
||||
parents: Vec::new(), // TODO: implement parents nicely
|
||||
fields: self.fields.clone(),
|
||||
location: self.location.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Unsent for Task {
|
||||
fn take_unsent(&self) -> bool {
|
||||
self.is_dirty.swap(false, Ordering::AcqRel)
|
||||
}
|
||||
|
||||
fn is_unsent(&self) -> bool {
|
||||
self.is_dirty.load(Ordering::Acquire)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToProto for Resource {
|
||||
type Output = resources::Resource;
|
||||
|
||||
fn to_proto(&self, _: &stats::TimeAnchor) -> Self::Output {
|
||||
resources::Resource {
|
||||
id: Some(self.id.clone().into()),
|
||||
parent_resource_id: self.parent_id.clone().map(Into::into),
|
||||
kind: Some(self.kind.clone()),
|
||||
metadata: Some(self.metadata.into()),
|
||||
concrete_type: self.concrete_type.clone(),
|
||||
location: self.location.clone(),
|
||||
is_internal: self.is_internal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Unsent for Resource {
|
||||
fn take_unsent(&self) -> bool {
|
||||
self.is_dirty.swap(false, Ordering::AcqRel)
|
||||
}
|
||||
|
||||
fn is_unsent(&self) -> bool {
|
||||
self.is_dirty.load(Ordering::Acquire)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToProto for AsyncOp {
|
||||
type Output = async_ops::AsyncOp;
|
||||
|
||||
fn to_proto(&self, _: &stats::TimeAnchor) -> Self::Output {
|
||||
async_ops::AsyncOp {
|
||||
id: Some(self.id.clone().into()),
|
||||
metadata: Some(self.metadata.into()),
|
||||
resource_id: Some(self.resource_id.clone().into()),
|
||||
source: self.source.clone(),
|
||||
parent_async_op_id: self.parent_id.clone().map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Unsent for AsyncOp {
|
||||
fn take_unsent(&self) -> bool {
|
||||
self.is_dirty.swap(false, Ordering::AcqRel)
|
||||
}
|
||||
|
||||
fn is_unsent(&self) -> bool {
|
||||
self.is_dirty.load(Ordering::Acquire)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub(crate) enum Include {
|
||||
All,
|
||||
UpdatedOnly,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Aggregator {
|
||||
shared: Arc<Shared>,
|
||||
events: Receiver<Event>,
|
||||
rpcs: async_channel::Receiver<server::Command>,
|
||||
watchers: Vec<Watch<instrument::Update>>,
|
||||
details_watchers: HashMap<span::Id, Vec<Watch<tasks::TaskDetails>>>,
|
||||
all_metadata: Vec<console_api::register_metadata::NewMetadata>,
|
||||
new_metadata: Vec<console_api::register_metadata::NewMetadata>,
|
||||
running: bool,
|
||||
publish_interval: Duration,
|
||||
base_time: TimeAnchor,
|
||||
tasks: IdMap<Task>,
|
||||
task_stats: IdMap<Arc<stats::TaskStats>>,
|
||||
resources: IdMap<Resource>,
|
||||
resource_stats: IdMap<Arc<stats::ResourceStats>>,
|
||||
async_ops: IdMap<AsyncOp>,
|
||||
async_op_stats: IdMap<Arc<stats::AsyncOpStats>>,
|
||||
poll_ops: Vec<console_api::resources::PollOp>,
|
||||
}
|
||||
|
||||
impl Aggregator {
|
||||
pub(crate) fn new(
|
||||
shared: Arc<Shared>,
|
||||
events: Receiver<Event>,
|
||||
rpcs: async_channel::Receiver<server::Command>,
|
||||
) -> Self {
|
||||
Self {
|
||||
shared,
|
||||
events,
|
||||
rpcs,
|
||||
watchers: Vec::new(),
|
||||
details_watchers: HashMap::default(),
|
||||
running: true,
|
||||
publish_interval: Duration::from_secs(1),
|
||||
all_metadata: Vec::new(),
|
||||
new_metadata: Vec::new(),
|
||||
base_time: TimeAnchor::new(),
|
||||
tasks: IdMap::default(),
|
||||
task_stats: IdMap::default(),
|
||||
resources: IdMap::default(),
|
||||
resource_stats: IdMap::default(),
|
||||
async_ops: IdMap::default(),
|
||||
async_op_stats: IdMap::default(),
|
||||
poll_ops: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_instrument_subscription(&mut self, subscription: Watch<instrument::Update>) {
|
||||
tracing::debug!("new instrument subscription");
|
||||
|
||||
let task_update = Some(self.task_update(Include::All));
|
||||
let resource_update = Some(self.resource_update(Include::All));
|
||||
let async_op_update = Some(self.async_op_update(Include::All));
|
||||
let now = Instant::now();
|
||||
|
||||
let update = &instrument::Update {
|
||||
task_update,
|
||||
resource_update,
|
||||
async_op_update,
|
||||
now: Some(self.base_time.to_timestamp(now)),
|
||||
new_metadata: Some(console_api::RegisterMetadata {
|
||||
metadata: (self.all_metadata).clone(),
|
||||
}),
|
||||
};
|
||||
|
||||
// Send the initial state --- if this fails, the subscription is already dead
|
||||
if subscription.update(update) {
|
||||
self.watchers.push(subscription)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the task details subscription to the watchers after sending the first update,
|
||||
/// if the task is found.
|
||||
fn add_task_detail_subscription(
|
||||
&mut self,
|
||||
watch_request: WatchRequest<console_api::tasks::TaskDetails>,
|
||||
) {
|
||||
let WatchRequest {
|
||||
id,
|
||||
mut stream_sender,
|
||||
buffer,
|
||||
} = watch_request;
|
||||
tracing::debug!(id = ?id, "new task details subscription");
|
||||
if let Some(stats) = self.task_stats.get(&id) {
|
||||
let (tx, rx) = async_channel::bounded(buffer);
|
||||
let subscription = Watch(tx);
|
||||
let now = Some(self.base_time.to_timestamp(Instant::now()));
|
||||
// Send back the stream receiver.
|
||||
// Then send the initial state --- if this fails, the subscription is already dead.
|
||||
if stream_sender.send(rx).is_ok()
|
||||
&& subscription.update(&console_api::tasks::TaskDetails {
|
||||
task_id: Some(id.clone().into()),
|
||||
now,
|
||||
poll_times_histogram: Some(stats.poll_duration_histogram()),
|
||||
})
|
||||
{
|
||||
self.details_watchers
|
||||
.entry(id.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(subscription);
|
||||
}
|
||||
}
|
||||
// If the task is not found, drop `stream_sender` which will result in a not found error
|
||||
}
|
||||
|
||||
fn task_update(&mut self, include: Include) -> tasks::TaskUpdate {
|
||||
tasks::TaskUpdate {
|
||||
new_tasks: self.tasks.as_proto_list(include, &self.base_time),
|
||||
stats_update: self.task_stats.as_proto(include, &self.base_time),
|
||||
dropped_events: self.shared.dropped_tasks.swap(0, Ordering::AcqRel) as u64,
|
||||
}
|
||||
}
|
||||
|
||||
fn resource_update(&mut self, include: Include) -> resources::ResourceUpdate {
|
||||
let new_poll_ops = match include {
|
||||
Include::All => self.poll_ops.clone(),
|
||||
Include::UpdatedOnly => std::mem::take(&mut self.poll_ops),
|
||||
};
|
||||
resources::ResourceUpdate {
|
||||
new_resources: self.resources.as_proto_list(include, &self.base_time),
|
||||
stats_update: self.resource_stats.as_proto(include, &self.base_time),
|
||||
new_poll_ops,
|
||||
dropped_events: self.shared.dropped_resources.swap(0, Ordering::AcqRel) as u64,
|
||||
}
|
||||
}
|
||||
|
||||
fn async_op_update(&mut self, include: Include) -> async_ops::AsyncOpUpdate {
|
||||
async_ops::AsyncOpUpdate {
|
||||
new_async_ops: self.async_ops.as_proto_list(include, &self.base_time),
|
||||
stats_update: self.async_op_stats.as_proto(include, &self.base_time),
|
||||
dropped_events: self.shared.dropped_async_ops.swap(0, Ordering::AcqRel) as u64,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(mut self) {
|
||||
let mut timer = StreamExt::fuse(async_io::Timer::interval(self.publish_interval));
|
||||
loop {
|
||||
let mut recv = self.rpcs.recv().fuse();
|
||||
let should_send: bool = futures_util::select! {
|
||||
_ = timer.next() => self.running,
|
||||
cmd = recv => {
|
||||
match cmd {
|
||||
Ok(server::Command::Instrument(subscription)) => {
|
||||
self.add_instrument_subscription(subscription);
|
||||
}
|
||||
Ok(server::Command::WatchTaskDetail(request)) => {
|
||||
}
|
||||
Ok(server::Command::Pause) => {
|
||||
self.running = false;
|
||||
}
|
||||
Ok(server::Command::Resume) => {
|
||||
self.running = true;
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::debug!("rpc channel closed, exiting");
|
||||
return
|
||||
}
|
||||
}
|
||||
false
|
||||
},
|
||||
};
|
||||
|
||||
// drain and aggregate buffered events.
|
||||
//
|
||||
// Note: we *don't* want to actually await the call to `recv` --- we
|
||||
// don't want the aggregator task to be woken on every event,
|
||||
// because it will then be woken when its own `poll` calls are
|
||||
// exited. that would result in a busy-loop. instead, we only want
|
||||
// to be woken when the flush interval has elapsed, or when the
|
||||
// channel is almost full.
|
||||
while let Ok(event) = self.events.try_recv() {
|
||||
self.update_state(event);
|
||||
}
|
||||
if let Err(TryRecvError::Disconnected) = self.events.try_recv() {
|
||||
tracing::debug!("event channel closed; terminating");
|
||||
return;
|
||||
}
|
||||
|
||||
// flush data to clients, if there are any currently subscribed
|
||||
// watchers and we should send a new update.
|
||||
if !self.watchers.is_empty() && should_send {
|
||||
self.publish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn publish(&mut self) {
|
||||
let new_metadata = if !self.new_metadata.is_empty() {
|
||||
Some(console_api::RegisterMetadata {
|
||||
metadata: std::mem::take(&mut self.new_metadata),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let task_update = Some(self.task_update(Include::UpdatedOnly));
|
||||
let resource_update = Some(self.resource_update(Include::UpdatedOnly));
|
||||
let async_op_update = Some(self.async_op_update(Include::UpdatedOnly));
|
||||
|
||||
let update = instrument::Update {
|
||||
now: Some(self.base_time.to_timestamp(Instant::now())),
|
||||
new_metadata,
|
||||
task_update,
|
||||
resource_update,
|
||||
async_op_update,
|
||||
};
|
||||
|
||||
self.watchers
|
||||
.retain(|watch: &Watch<instrument::Update>| watch.update(&update));
|
||||
|
||||
let stats = &self.task_stats;
|
||||
// Assuming there are much fewer task details subscribers than there are
|
||||
// stats updates, iterate over `details_watchers` and compact the map.
|
||||
self.details_watchers.retain(|id, watchers| {
|
||||
if let Some(task_stats) = stats.get(id) {
|
||||
let details = tasks::TaskDetails {
|
||||
task_id: Some(id.clone().into()),
|
||||
now: Some(self.base_time.to_timestamp(Instant::now())),
|
||||
poll_times_histogram: Some(task_stats.poll_duration_histogram()),
|
||||
};
|
||||
watchers.retain(|watch| watch.update(&details));
|
||||
!watchers.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Update the current state with data from a single event.
|
||||
fn update_state(&mut self, event: Event) {
|
||||
// do state update
|
||||
match event {
|
||||
Event::Metadata(meta) => {
|
||||
self.all_metadata.push(meta.into());
|
||||
self.new_metadata.push(meta.into());
|
||||
}
|
||||
|
||||
Event::Spawn {
|
||||
id,
|
||||
metadata,
|
||||
stats,
|
||||
fields,
|
||||
location,
|
||||
} => {
|
||||
self.tasks.insert(
|
||||
id.clone(),
|
||||
Task {
|
||||
id: id.clone(),
|
||||
is_dirty: AtomicBool::new(true),
|
||||
metadata,
|
||||
fields,
|
||||
location,
|
||||
// TODO: parents
|
||||
},
|
||||
);
|
||||
|
||||
self.task_stats.insert(id, stats);
|
||||
}
|
||||
|
||||
Event::Resource {
|
||||
id,
|
||||
parent_id,
|
||||
metadata,
|
||||
kind,
|
||||
concrete_type,
|
||||
location,
|
||||
is_internal,
|
||||
stats,
|
||||
} => {
|
||||
self.resources.insert(
|
||||
id.clone(),
|
||||
Resource {
|
||||
id: id.clone(),
|
||||
is_dirty: AtomicBool::new(true),
|
||||
parent_id,
|
||||
kind,
|
||||
metadata,
|
||||
concrete_type,
|
||||
location,
|
||||
is_internal,
|
||||
},
|
||||
);
|
||||
|
||||
self.resource_stats.insert(id, stats);
|
||||
}
|
||||
|
||||
Event::PollOp {
|
||||
metadata,
|
||||
resource_id,
|
||||
op_name,
|
||||
async_op_id,
|
||||
task_id,
|
||||
is_ready,
|
||||
} => {
|
||||
let poll_op = resources::PollOp {
|
||||
metadata: Some(metadata.into()),
|
||||
resource_id: Some(resource_id.into()),
|
||||
name: op_name,
|
||||
task_id: Some(task_id.into()),
|
||||
async_op_id: Some(async_op_id.into()),
|
||||
is_ready,
|
||||
};
|
||||
|
||||
self.poll_ops.push(poll_op);
|
||||
}
|
||||
|
||||
Event::AsyncResourceOp {
|
||||
id,
|
||||
source,
|
||||
resource_id,
|
||||
metadata,
|
||||
parent_id,
|
||||
stats,
|
||||
} => {
|
||||
self.async_ops.insert(
|
||||
id.clone(),
|
||||
AsyncOp {
|
||||
id: id.clone(),
|
||||
is_dirty: AtomicBool::new(true),
|
||||
resource_id,
|
||||
metadata,
|
||||
source,
|
||||
parent_id,
|
||||
},
|
||||
);
|
||||
|
||||
self.async_op_stats.insert(id, stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
113
runtime/console/src/attribute.rs
Normal file
113
runtime/console/src/attribute.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use std::collections::HashMap;
|
||||
use tracing_core::span::Id;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct Attributes {
|
||||
attributes: HashMap<FieldKey, console_api::Attribute>,
|
||||
}
|
||||
|
||||
impl Attributes {
|
||||
pub(crate) fn values(&self) -> impl Iterator<Item = &console_api::Attribute> {
|
||||
self.attributes.values()
|
||||
}
|
||||
|
||||
pub(crate) fn update(&mut self, id: &Id, update: &Update) {
|
||||
let field_name = match update.field.name.as_ref() {
|
||||
Some(name) => name.clone(),
|
||||
None => {
|
||||
tracing::warn!(?update.field, "field missing name, skipping...");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let update_id = id.clone();
|
||||
let key = FieldKey {
|
||||
update_id,
|
||||
field_name,
|
||||
};
|
||||
|
||||
self.attributes
|
||||
.entry(key)
|
||||
.and_modify(|attr| update_attribute(attr, update))
|
||||
.or_insert_with(|| update.clone().into());
|
||||
}
|
||||
}
|
||||
|
||||
fn update_attribute(attribute: &mut console_api::Attribute, update: &Update) {
|
||||
use console_api::field::Value::*;
|
||||
let attribute_val = attribute.field.as_mut().and_then(|a| a.value.as_mut());
|
||||
let update_val = update.field.value.clone();
|
||||
let update_name = update.field.name.clone();
|
||||
match (attribute_val, update_val) {
|
||||
(Some(BoolVal(v)), Some(BoolVal(upd))) => *v = upd,
|
||||
|
||||
(Some(StrVal(v)), Some(StrVal(upd))) => *v = upd,
|
||||
|
||||
(Some(DebugVal(v)), Some(DebugVal(upd))) => *v = upd,
|
||||
|
||||
(Some(U64Val(v)), Some(U64Val(upd))) => match update.op {
|
||||
Some(UpdateOp::Add) => *v = v.saturating_add(upd),
|
||||
|
||||
Some(UpdateOp::Sub) => *v = v.saturating_sub(upd),
|
||||
|
||||
Some(UpdateOp::Override) => *v = upd,
|
||||
|
||||
None => tracing::warn!(
|
||||
"numeric attribute update {:?} needs to have an op field",
|
||||
update_name
|
||||
),
|
||||
},
|
||||
|
||||
(Some(I64Val(v)), Some(I64Val(upd))) => match update.op {
|
||||
Some(UpdateOp::Add) => *v = v.saturating_add(upd),
|
||||
|
||||
Some(UpdateOp::Sub) => *v = v.saturating_sub(upd),
|
||||
|
||||
Some(UpdateOp::Override) => *v = upd,
|
||||
|
||||
None => tracing::warn!(
|
||||
"numeric attribute update {:?} needs to have an op field",
|
||||
update_name
|
||||
),
|
||||
},
|
||||
|
||||
(val, update) => {
|
||||
tracing::warn!(
|
||||
"attribute {:?} cannot be updated by update {:?}",
|
||||
val,
|
||||
update
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Update> for console_api::Attribute {
|
||||
fn from(upd: Update) -> Self {
|
||||
console_api::Attribute {
|
||||
field: Some(upd.field),
|
||||
unit: upd.unit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Update {
|
||||
pub(crate) field: console_api::Field,
|
||||
pub(crate) op: Option<UpdateOp>,
|
||||
pub(crate) unit: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum UpdateOp {
|
||||
Add,
|
||||
Override,
|
||||
Sub,
|
||||
}
|
||||
|
||||
/// Represents a key for a `proto::field::Name`. Because the
|
||||
/// proto::field::Name might not be unique we also include the
|
||||
/// resource id in this key
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
struct FieldKey {
|
||||
update_id: Id,
|
||||
field_name: console_api::field::Name,
|
||||
}
|
75
runtime/console/src/callsites.rs
Normal file
75
runtime/console/src/callsites.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use std::fmt;
|
||||
use std::fmt::Formatter;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
||||
use tracing::Metadata;
|
||||
|
||||
pub(crate) struct Callsites<const MAX_CALLSITES: usize> {
|
||||
array: [AtomicPtr<Metadata<'static>>; MAX_CALLSITES],
|
||||
len: AtomicUsize,
|
||||
}
|
||||
|
||||
impl<const MAX_CALLSITES: usize> Callsites<MAX_CALLSITES> {
|
||||
pub(crate) fn insert(&self, callsite: &'static Metadata<'static>) {
|
||||
if self.contains(callsite) {
|
||||
return;
|
||||
}
|
||||
|
||||
let idx = self.len.fetch_add(1, Ordering::AcqRel);
|
||||
if idx <= MAX_CALLSITES {
|
||||
self.array[idx]
|
||||
.compare_exchange(
|
||||
ptr::null_mut(),
|
||||
callsite as *const _ as *mut _,
|
||||
Ordering::AcqRel,
|
||||
Ordering::Acquire,
|
||||
)
|
||||
.expect("would have clobbered callsite array");
|
||||
} else {
|
||||
todo!("Need to spill callsite over into backup storage");
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, callsite: &Metadata<'static>) -> bool {
|
||||
let mut idx = 0;
|
||||
let mut end = self.len.load(Ordering::Acquire);
|
||||
while {
|
||||
for cs in &self.array[idx..end] {
|
||||
let ptr = cs.load(Ordering::Acquire);
|
||||
let meta = unsafe { &*ptr };
|
||||
if meta.callsite() == callsite.callsite() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
idx = end;
|
||||
|
||||
// Check if new callsites were added since we iterated
|
||||
end = self.len.load(Ordering::Acquire);
|
||||
end > idx
|
||||
} {}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MAX_CALLSITES: usize> Default for Callsites<MAX_CALLSITES> {
|
||||
fn default() -> Self {
|
||||
const NULLPTR: AtomicPtr<Metadata<'static>> = AtomicPtr::new(ptr::null_mut());
|
||||
Self {
|
||||
array: [NULLPTR; MAX_CALLSITES],
|
||||
len: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MAX_CALLSITES: usize> fmt::Debug for Callsites<MAX_CALLSITES> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let len = self.len.load(Ordering::Acquire);
|
||||
f.debug_struct("Callsites")
|
||||
.field("MAX_CALLSITES", &MAX_CALLSITES)
|
||||
.field("array", &&self.array[..len])
|
||||
.field("len", &len)
|
||||
.finish()
|
||||
}
|
||||
}
|
66
runtime/console/src/event.rs
Normal file
66
runtime/console/src/event.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use crate::stats;
|
||||
use console_api::resources;
|
||||
use std::sync::Arc;
|
||||
use tracing::span;
|
||||
use tracing_core::Metadata;
|
||||
|
||||
pub(crate) enum Event {
|
||||
Metadata(&'static Metadata<'static>),
|
||||
Spawn {
|
||||
id: span::Id,
|
||||
metadata: &'static Metadata<'static>,
|
||||
stats: Arc<stats::TaskStats>,
|
||||
fields: Vec<console_api::Field>,
|
||||
location: Option<console_api::Location>,
|
||||
},
|
||||
Resource {
|
||||
id: span::Id,
|
||||
parent_id: Option<span::Id>,
|
||||
metadata: &'static Metadata<'static>,
|
||||
concrete_type: String,
|
||||
kind: resources::resource::Kind,
|
||||
location: Option<console_api::Location>,
|
||||
is_internal: bool,
|
||||
stats: Arc<stats::ResourceStats>,
|
||||
},
|
||||
PollOp {
|
||||
metadata: &'static Metadata<'static>,
|
||||
resource_id: span::Id,
|
||||
op_name: String,
|
||||
async_op_id: span::Id,
|
||||
task_id: span::Id,
|
||||
is_ready: bool,
|
||||
},
|
||||
AsyncResourceOp {
|
||||
id: span::Id,
|
||||
parent_id: Option<span::Id>,
|
||||
resource_id: span::Id,
|
||||
metadata: &'static Metadata<'static>,
|
||||
source: String,
|
||||
|
||||
stats: Arc<stats::AsyncOpStats>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub(crate) enum WakeOp {
|
||||
Wake { self_wake: bool },
|
||||
WakeByRef { self_wake: bool },
|
||||
Clone,
|
||||
Drop,
|
||||
}
|
||||
|
||||
impl WakeOp {
|
||||
/// Returns `true` if `self` is a `Wake` or `WakeByRef` event.
|
||||
pub(crate) fn is_wake(self) -> bool {
|
||||
matches!(self, Self::Wake { .. } | Self::WakeByRef { .. })
|
||||
}
|
||||
|
||||
pub(crate) fn self_wake(self, self_wake: bool) -> Self {
|
||||
match self {
|
||||
Self::Wake { .. } => Self::Wake { self_wake },
|
||||
Self::WakeByRef { .. } => Self::WakeByRef { self_wake },
|
||||
x => x,
|
||||
}
|
||||
}
|
||||
}
|
126
runtime/console/src/id_map.rs
Normal file
126
runtime/console/src/id_map.rs
Normal file
@ -0,0 +1,126 @@
|
||||
use crate::aggregate::Include;
|
||||
use crate::stats::{DroppedAt, TimeAnchor, Unsent};
|
||||
use std::collections::HashMap;
|
||||
use std::time::{Duration, Instant};
|
||||
use tracing_core::span::Id;
|
||||
|
||||
pub(crate) trait ToProto {
|
||||
type Output;
|
||||
fn to_proto(&self, base_time: &TimeAnchor) -> Self::Output;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct IdMap<T> {
|
||||
data: HashMap<Id, T>,
|
||||
}
|
||||
|
||||
impl<T> Default for IdMap<T> {
|
||||
fn default() -> Self {
|
||||
IdMap {
|
||||
data: HashMap::<Id, T>::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unsent> IdMap<T> {
|
||||
pub(crate) fn insert(&mut self, id: Id, data: T) {
|
||||
self.data.insert(id, data);
|
||||
}
|
||||
|
||||
pub(crate) fn since_last_update(&mut self) -> impl Iterator<Item = (&Id, &mut T)> {
|
||||
self.data.iter_mut().filter_map(|(id, data)| {
|
||||
if data.take_unsent() {
|
||||
Some((id, data))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn all(&self) -> impl Iterator<Item = (&Id, &T)> {
|
||||
self.data.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, id: &Id) -> Option<&T> {
|
||||
self.data.get(id)
|
||||
}
|
||||
|
||||
pub(crate) fn as_proto_list(
|
||||
&mut self,
|
||||
include: Include,
|
||||
base_time: &TimeAnchor,
|
||||
) -> Vec<T::Output>
|
||||
where
|
||||
T: ToProto,
|
||||
{
|
||||
match include {
|
||||
Include::UpdatedOnly => self
|
||||
.since_last_update()
|
||||
.map(|(_, d)| d.to_proto(base_time))
|
||||
.collect(),
|
||||
Include::All => self.all().map(|(_, d)| d.to_proto(base_time)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_proto(
|
||||
&mut self,
|
||||
include: Include,
|
||||
base_time: &TimeAnchor,
|
||||
) -> HashMap<u64, T::Output>
|
||||
where
|
||||
T: ToProto,
|
||||
{
|
||||
match include {
|
||||
Include::UpdatedOnly => self
|
||||
.since_last_update()
|
||||
.map(|(id, d)| (id.into_u64(), d.to_proto(base_time)))
|
||||
.collect(),
|
||||
Include::All => self
|
||||
.all()
|
||||
.map(|(id, d)| (id.into_u64(), d.to_proto(base_time)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn drop_closed<R: DroppedAt + Unsent>(
|
||||
&mut self,
|
||||
stats: &mut IdMap<R>,
|
||||
now: Instant,
|
||||
retention: Duration,
|
||||
has_watchers: bool,
|
||||
) {
|
||||
let _span = tracing::debug_span!(
|
||||
"drop_closed",
|
||||
entity = %std::any::type_name::<T>(),
|
||||
stats = %std::any::type_name::<R>(),
|
||||
)
|
||||
.entered();
|
||||
|
||||
// drop closed entities
|
||||
tracing::trace!(?retention, has_watchers, "dropping closed");
|
||||
|
||||
stats.data.retain(|id, stats| {
|
||||
if let Some(dropped_at) = stats.dropped_at() {
|
||||
let dropped_for = now.checked_duration_since(dropped_at).unwrap_or_default();
|
||||
let dirty = stats.is_unsent();
|
||||
let should_drop =
|
||||
// if there are any clients watching, retain all dirty tasks regardless of age
|
||||
(dirty && has_watchers)
|
||||
|| dropped_for > retention;
|
||||
tracing::trace!(
|
||||
stats.id = ?id,
|
||||
stats.dropped_at = ?dropped_at,
|
||||
stats.dropped_for = ?dropped_for,
|
||||
stats.dirty = dirty,
|
||||
should_drop,
|
||||
);
|
||||
return !should_drop;
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
|
||||
// drop closed entities which no longer have stats.
|
||||
self.data.retain(|id, _| stats.data.contains_key(id));
|
||||
}
|
||||
}
|
514
runtime/console/src/lib.rs
Normal file
514
runtime/console/src/lib.rs
Normal file
@ -0,0 +1,514 @@
|
||||
use crossbeam_channel::{Sender, TrySendError};
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use thread_local::ThreadLocal;
|
||||
use tracing::span;
|
||||
use tracing_core::span::Attributes;
|
||||
use tracing_core::{Interest, Metadata, Subscriber};
|
||||
use tracing_subscriber::layer::{Context, Filter};
|
||||
use tracing_subscriber::registry::{LookupSpan, SpanRef};
|
||||
use tracing_subscriber::Layer;
|
||||
|
||||
mod aggregate;
|
||||
mod attribute;
|
||||
mod callsites;
|
||||
mod event;
|
||||
mod id_map;
|
||||
mod server;
|
||||
mod stack;
|
||||
mod stats;
|
||||
mod visitors;
|
||||
|
||||
use crate::aggregate::Aggregator;
|
||||
use crate::callsites::Callsites;
|
||||
use crate::visitors::{
|
||||
AsyncOpVisitor, PollOpVisitor, ResourceVisitor, ResourceVisitorResult, StateUpdateVisitor,
|
||||
TaskVisitor, WakerVisitor,
|
||||
};
|
||||
use event::Event;
|
||||
pub use server::Server;
|
||||
use stack::SpanStack;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConsoleLayer {
|
||||
current_spans: ThreadLocal<RefCell<SpanStack>>,
|
||||
|
||||
tx: Sender<Event>,
|
||||
shared: Arc<Shared>,
|
||||
|
||||
spawn_callsites: Callsites<8>,
|
||||
waker_callsites: Callsites<8>,
|
||||
resource_callsites: Callsites<8>,
|
||||
|
||||
/// Set of callsites for spans representing async operations on resources
|
||||
///
|
||||
/// TODO: Take some time to determine more reasonable numbers
|
||||
async_op_callsites: Callsites<32>,
|
||||
|
||||
/// Set of callsites for spans representing async op poll operations
|
||||
///
|
||||
/// TODO: Take some time to determine more reasonable numbers
|
||||
async_op_poll_callsites: Callsites<32>,
|
||||
|
||||
/// Set of callsites for events representing poll operation invocations on resources
|
||||
///
|
||||
/// TODO: Take some time to determine more reasonable numbers
|
||||
poll_op_callsites: Callsites<32>,
|
||||
|
||||
/// Set of callsites for events representing state attribute state updates on resources
|
||||
///
|
||||
/// TODO: Take some time to determine more reasonable numbers
|
||||
resource_state_update_callsites: Callsites<32>,
|
||||
|
||||
/// Set of callsites for events representing state attribute state updates on async resource ops
|
||||
///
|
||||
/// TODO: Take some time to determine more reasonable numbers
|
||||
async_op_state_update_callsites: Callsites<32>,
|
||||
|
||||
max_poll_duration_nanos: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Builder {
|
||||
/// Network Address the console server will listen on
|
||||
server_addr: IpAddr,
|
||||
/// Network Port the console server will listen on
|
||||
server_port: u16,
|
||||
|
||||
/// Number of events that can be buffered before events are dropped.
|
||||
///
|
||||
/// A smaller number will reduce the memory footprint but may lead to more events being dropped
|
||||
/// during activity bursts.
|
||||
event_buffer_capacity: usize,
|
||||
|
||||
client_buffer_capacity: usize,
|
||||
|
||||
poll_duration_max: Duration,
|
||||
}
|
||||
impl Builder {
|
||||
pub fn build(self) -> (ConsoleLayer, Server) {
|
||||
ConsoleLayer::build(self)
|
||||
}
|
||||
}
|
||||
impl Default for Builder {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// Listen on `::1` (aka localhost) by default
|
||||
server_addr: Server::DEFAULT_ADDR,
|
||||
server_port: Server::DEFAULT_PORT,
|
||||
event_buffer_capacity: ConsoleLayer::DEFAULT_EVENT_BUFFER_CAPACITY,
|
||||
client_buffer_capacity: 1024,
|
||||
poll_duration_max: ConsoleLayer::DEFAULT_POLL_DURATION_MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Shared {
|
||||
dropped_tasks: AtomicUsize,
|
||||
dropped_resources: AtomicUsize,
|
||||
dropped_async_ops: AtomicUsize,
|
||||
}
|
||||
|
||||
impl ConsoleLayer {
|
||||
pub fn new() -> (Self, Server) {
|
||||
Self::builder().build()
|
||||
}
|
||||
pub fn builder() -> Builder {
|
||||
Builder::default()
|
||||
}
|
||||
fn build(config: Builder) -> (Self, Server) {
|
||||
tracing::debug!(
|
||||
?config.server_addr,
|
||||
config.event_buffer_capacity,
|
||||
"configured console subscriber"
|
||||
);
|
||||
|
||||
let (tx, events) = crossbeam_channel::bounded(config.event_buffer_capacity);
|
||||
let shared = Arc::new(Shared::default());
|
||||
let (subscribe, rpcs) = async_channel::bounded(config.client_buffer_capacity);
|
||||
let aggregator = Aggregator::new(shared.clone(), events, rpcs);
|
||||
let server = Server::new(aggregator, config.client_buffer_capacity, subscribe);
|
||||
let layer = Self {
|
||||
current_spans: ThreadLocal::new(),
|
||||
tx,
|
||||
shared,
|
||||
spawn_callsites: Callsites::default(),
|
||||
waker_callsites: Callsites::default(),
|
||||
resource_callsites: Callsites::default(),
|
||||
async_op_callsites: Callsites::default(),
|
||||
async_op_poll_callsites: Callsites::default(),
|
||||
poll_op_callsites: Callsites::default(),
|
||||
resource_state_update_callsites: Callsites::default(),
|
||||
async_op_state_update_callsites: Callsites::default(),
|
||||
max_poll_duration_nanos: config.poll_duration_max.as_nanos() as u64,
|
||||
};
|
||||
|
||||
(layer, server)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConsoleLayer {
|
||||
const DEFAULT_EVENT_BUFFER_CAPACITY: usize = 1024;
|
||||
const DEFAULT_CLIENT_BUFFER_CAPACITY: usize = 1024;
|
||||
|
||||
/// The default maximum value for task poll duration histograms.
|
||||
///
|
||||
/// Any poll duration exceeding this will be clamped to this value. By
|
||||
/// default, the maximum poll duration is one second.
|
||||
///
|
||||
/// See also [`Builder::poll_duration_histogram_max`].
|
||||
pub const DEFAULT_POLL_DURATION_MAX: Duration = Duration::from_secs(1);
|
||||
|
||||
fn is_spawn(&self, metadata: &Metadata<'static>) -> bool {
|
||||
self.spawn_callsites.contains(metadata)
|
||||
}
|
||||
|
||||
fn is_waker(&self, metadata: &Metadata<'static>) -> bool {
|
||||
self.waker_callsites.contains(metadata)
|
||||
}
|
||||
|
||||
fn is_resource(&self, meta: &'static Metadata<'static>) -> bool {
|
||||
self.resource_callsites.contains(meta)
|
||||
}
|
||||
|
||||
fn is_async_op(&self, meta: &'static Metadata<'static>) -> bool {
|
||||
self.async_op_callsites.contains(meta)
|
||||
}
|
||||
|
||||
fn is_id_spawned<S>(&self, id: &span::Id, cx: &Context<'_, S>) -> bool
|
||||
where
|
||||
S: Subscriber + for<'a> LookupSpan<'a>,
|
||||
{
|
||||
cx.span(id)
|
||||
.map(|span| self.is_spawn(span.metadata()))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn is_id_resource<S>(&self, id: &span::Id, cx: &Context<'_, S>) -> bool
|
||||
where
|
||||
S: Subscriber + for<'a> LookupSpan<'a>,
|
||||
{
|
||||
cx.span(id)
|
||||
.map(|span| self.is_resource(span.metadata()))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn is_id_async_op<S>(&self, id: &span::Id, cx: &Context<'_, S>) -> bool
|
||||
where
|
||||
S: Subscriber + for<'a> LookupSpan<'a>,
|
||||
{
|
||||
cx.span(id)
|
||||
.map(|span| self.is_async_op(span.metadata()))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn first_entered<P>(&self, stack: &SpanStack, p: P) -> Option<span::Id>
|
||||
where
|
||||
P: Fn(&span::Id) -> bool,
|
||||
{
|
||||
stack
|
||||
.stack()
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|id| p(id.id()))
|
||||
.map(|id| id.id())
|
||||
.cloned()
|
||||
}
|
||||
|
||||
fn send_stats<S>(
|
||||
&self,
|
||||
dropped: &AtomicUsize,
|
||||
mkEvent: impl FnOnce() -> (Event, S),
|
||||
) -> Option<S> {
|
||||
if self.tx.is_full() {
|
||||
dropped.fetch_add(1, Ordering::Release);
|
||||
return None;
|
||||
}
|
||||
|
||||
let (event, stats) = mkEvent();
|
||||
match self.tx.try_send(event) {
|
||||
Ok(()) => Some(stats),
|
||||
Err(TrySendError::Full(_)) => {
|
||||
dropped.fetch_add(1, Ordering::Release);
|
||||
None
|
||||
}
|
||||
Err(TrySendError::Disconnected(_)) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn send_metadata(&self, dropped: &AtomicUsize, event: Event) -> bool {
|
||||
self.send_stats(dropped, || (event, ())).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Layer<S> for ConsoleLayer
|
||||
where
|
||||
S: Subscriber + for<'a> LookupSpan<'a>,
|
||||
{
|
||||
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
|
||||
let dropped = match (metadata.name(), metadata.target()) {
|
||||
(_, TaskVisitor::SPAWN_TARGET) | (TaskVisitor::SPAWN_NAME, _) => {
|
||||
self.spawn_callsites.insert(metadata);
|
||||
&self.shared.dropped_tasks
|
||||
}
|
||||
(_, WakerVisitor::WAKER_EVENT_TARGET) => {
|
||||
self.waker_callsites.insert(metadata);
|
||||
&self.shared.dropped_tasks
|
||||
}
|
||||
(ResourceVisitor::RES_SPAN_NAME, _) => {
|
||||
self.resource_callsites.insert(metadata);
|
||||
&self.shared.dropped_resources
|
||||
}
|
||||
(AsyncOpVisitor::ASYNC_OP_SPAN_NAME, _) => {
|
||||
self.async_op_callsites.insert(metadata);
|
||||
&self.shared.dropped_async_ops
|
||||
}
|
||||
(AsyncOpVisitor::ASYNC_OP_POLL_NAME, _) => {
|
||||
self.async_op_poll_callsites.insert(metadata);
|
||||
&self.shared.dropped_async_ops
|
||||
}
|
||||
(_, PollOpVisitor::POLL_OP_EVENT_TARGET) => {
|
||||
self.poll_op_callsites.insert(metadata);
|
||||
&self.shared.dropped_async_ops
|
||||
}
|
||||
(_, StateUpdateVisitor::RE_STATE_UPDATE_EVENT_TARGET) => {
|
||||
self.resource_state_update_callsites.insert(metadata);
|
||||
&self.shared.dropped_resources
|
||||
}
|
||||
(_, StateUpdateVisitor::AO_STATE_UPDATE_EVENT_TARGET) => {
|
||||
self.async_op_state_update_callsites.insert(metadata);
|
||||
&self.shared.dropped_async_ops
|
||||
}
|
||||
(_, _) => &self.shared.dropped_tasks,
|
||||
};
|
||||
|
||||
self.send_metadata(dropped, Event::Metadata(metadata));
|
||||
|
||||
Interest::always()
|
||||
}
|
||||
|
||||
fn on_new_span(&self, attrs: &Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
|
||||
let metadata = attrs.metadata();
|
||||
if self.is_spawn(metadata) {
|
||||
let at = Instant::now();
|
||||
let mut task_visitor = TaskVisitor::new(metadata.into());
|
||||
attrs.record(&mut task_visitor);
|
||||
let (fields, location) = task_visitor.result();
|
||||
if let Some(stats) = self.send_stats(&self.shared.dropped_tasks, move || {
|
||||
let stats = Arc::new(stats::TaskStats::new(self.max_poll_duration_nanos, at));
|
||||
let event = Event::Spawn {
|
||||
id: id.clone(),
|
||||
stats: stats.clone(),
|
||||
metadata,
|
||||
fields,
|
||||
location,
|
||||
};
|
||||
(event, stats)
|
||||
}) {
|
||||
ctx.span(id)
|
||||
.expect("`on_new_span` called with nonexistent span. This is a tracing bug.")
|
||||
.extensions_mut()
|
||||
.insert(stats);
|
||||
}
|
||||
} else if self.is_resource(metadata) {
|
||||
let at = Instant::now();
|
||||
let mut resource_visitor = ResourceVisitor::default();
|
||||
attrs.record(&mut resource_visitor);
|
||||
if let Some(result) = resource_visitor.result() {
|
||||
let ResourceVisitorResult {
|
||||
concrete_type,
|
||||
kind,
|
||||
location,
|
||||
is_internal,
|
||||
inherit_child_attrs,
|
||||
} = result;
|
||||
let parent_id = self.current_spans.get().and_then(|stack| {
|
||||
self.first_entered(&stack.borrow(), |id| self.is_id_resource(id, &ctx))
|
||||
});
|
||||
if let Some(stats) = self.send_stats(&self.shared.dropped_resources, move || {
|
||||
let stats = Arc::new(stats::ResourceStats::new(
|
||||
at,
|
||||
inherit_child_attrs,
|
||||
parent_id.clone(),
|
||||
));
|
||||
let event = Event::Resource {
|
||||
id: id.clone(),
|
||||
parent_id,
|
||||
metadata,
|
||||
concrete_type,
|
||||
kind,
|
||||
location,
|
||||
is_internal,
|
||||
stats: stats.clone(),
|
||||
};
|
||||
(event, stats)
|
||||
}) {
|
||||
ctx.span(id)
|
||||
.expect("if `on_new_span` was called, the span must exist; this is a `tracing` bug!")
|
||||
.extensions_mut()
|
||||
.insert(stats);
|
||||
}
|
||||
}
|
||||
} else if self.is_async_op(metadata) {
|
||||
let at = Instant::now();
|
||||
let mut async_op_visitor = AsyncOpVisitor::default();
|
||||
attrs.record(&mut async_op_visitor);
|
||||
if let Some((source, inherit_child_attrs)) = async_op_visitor.result() {
|
||||
let resource_id = self.current_spans.get().and_then(|stack| {
|
||||
self.first_entered(&stack.borrow(), |id| self.is_id_resource(id, &ctx))
|
||||
});
|
||||
|
||||
let parent_id = self.current_spans.get().and_then(|stack| {
|
||||
self.first_entered(&stack.borrow(), |id| self.is_id_async_op(id, &ctx))
|
||||
});
|
||||
|
||||
if let Some(resource_id) = resource_id {
|
||||
if let Some(stats) =
|
||||
self.send_stats(&self.shared.dropped_async_ops, move || {
|
||||
let stats = Arc::new(stats::AsyncOpStats::new(
|
||||
at,
|
||||
inherit_child_attrs,
|
||||
parent_id.clone(),
|
||||
));
|
||||
let event = Event::AsyncResourceOp {
|
||||
id: id.clone(),
|
||||
parent_id,
|
||||
resource_id,
|
||||
metadata,
|
||||
source,
|
||||
stats: stats.clone(),
|
||||
};
|
||||
(event, stats)
|
||||
})
|
||||
{
|
||||
ctx.span(id)
|
||||
.expect("if `on_new_span` was called, the span must exist; this is a `tracing` bug!")
|
||||
.extensions_mut()
|
||||
.insert(stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_event(&self, event: &tracing::Event<'_>, ctx: Context<'_, S>) {
|
||||
let metadata = event.metadata();
|
||||
if self.waker_callsites.contains(metadata) {
|
||||
let at = Instant::now();
|
||||
let mut visitor = WakerVisitor::default();
|
||||
event.record(&mut visitor);
|
||||
if let Some((id, mut op)) = visitor.result() {
|
||||
if let Some(span) = ctx.span(&id) {
|
||||
let exts = span.extensions();
|
||||
if let Some(stats) = exts.get::<Arc<stats::TaskStats>>() {
|
||||
if op.is_wake() {
|
||||
let self_wake = self
|
||||
.current_spans
|
||||
.get()
|
||||
.map(|spans| spans.borrow().iter().any(|span| span == &id))
|
||||
.unwrap_or(false);
|
||||
op = op.self_wake(self_wake);
|
||||
}
|
||||
|
||||
stats.record_wake_op(op, at);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if self.poll_op_callsites.contains(metadata) {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_enter(&self, id: &span::Id, cx: Context<'_, S>) {
|
||||
fn update<S: Subscriber + for<'a> LookupSpan<'a>>(
|
||||
span: &SpanRef<S>,
|
||||
at: Option<Instant>,
|
||||
) -> Option<Instant> {
|
||||
let exts = span.extensions();
|
||||
// if the span we are entering is a task or async op, record the
|
||||
// poll stats.
|
||||
if let Some(stats) = exts.get::<Arc<stats::TaskStats>>() {
|
||||
let at = at.unwrap_or_else(Instant::now);
|
||||
stats.start_poll(at);
|
||||
Some(at)
|
||||
} else if let Some(stats) = exts.get::<Arc<stats::AsyncOpStats>>() {
|
||||
let at = at.unwrap_or_else(Instant::now);
|
||||
stats.start_poll(at);
|
||||
Some(at)
|
||||
// otherwise, is the span a resource? in that case, we also want
|
||||
// to enter it, although we don't care about recording poll
|
||||
// stats.
|
||||
} else if exts.get::<Arc<stats::ResourceStats>>().is_some() {
|
||||
Some(at.unwrap_or_else(Instant::now))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(span) = cx.span(id) {
|
||||
if let Some(now) = update(&span, None) {
|
||||
if let Some(parent) = span.parent() {
|
||||
update(&parent, Some(now));
|
||||
}
|
||||
self.current_spans
|
||||
.get_or_default()
|
||||
.borrow_mut()
|
||||
.push(id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_exit(&self, id: &span::Id, cx: Context<'_, S>) {
|
||||
fn update<S: Subscriber + for<'a> LookupSpan<'a>>(
|
||||
span: &SpanRef<S>,
|
||||
at: Option<Instant>,
|
||||
) -> Option<Instant> {
|
||||
let exts = span.extensions();
|
||||
// if the span we are entering is a task or async op, record the
|
||||
// poll stats.
|
||||
if let Some(stats) = exts.get::<Arc<stats::TaskStats>>() {
|
||||
let at = at.unwrap_or_else(Instant::now);
|
||||
stats.end_poll(at);
|
||||
Some(at)
|
||||
} else if let Some(stats) = exts.get::<Arc<stats::AsyncOpStats>>() {
|
||||
let at = at.unwrap_or_else(Instant::now);
|
||||
stats.end_poll(at);
|
||||
Some(at)
|
||||
// otherwise, is the span a resource? in that case, we also want
|
||||
// to enter it, although we don't care about recording poll
|
||||
// stats.
|
||||
} else if exts.get::<Arc<stats::ResourceStats>>().is_some() {
|
||||
Some(at.unwrap_or_else(Instant::now))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(span) = cx.span(id) {
|
||||
if let Some(now) = update(&span, None) {
|
||||
if let Some(parent) = span.parent() {
|
||||
update(&parent, Some(now));
|
||||
}
|
||||
self.current_spans.get_or_default().borrow_mut().pop(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_close(&self, id: span::Id, cx: Context<'_, S>) {
|
||||
if let Some(span) = cx.span(&id) {
|
||||
let now = Instant::now();
|
||||
let exts = span.extensions();
|
||||
if let Some(stats) = exts.get::<Arc<stats::TaskStats>>() {
|
||||
stats.drop_task(now);
|
||||
} else if let Some(stats) = exts.get::<Arc<stats::AsyncOpStats>>() {
|
||||
stats.drop_async_op(now);
|
||||
} else if let Some(stats) = exts.get::<Arc<stats::ResourceStats>>() {
|
||||
stats.drop_resource(now);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
223
runtime/console/src/server.rs
Normal file
223
runtime/console/src/server.rs
Normal file
@ -0,0 +1,223 @@
|
||||
use crate::Aggregator;
|
||||
use async_channel::{Receiver, Sender};
|
||||
use async_compat::CompatExt;
|
||||
use console_api::instrument;
|
||||
use console_api::instrument::instrument_server::{Instrument, InstrumentServer};
|
||||
use console_api::tasks;
|
||||
use futures_util::TryStreamExt;
|
||||
use std::error::Error;
|
||||
use std::future::Future;
|
||||
use std::io::IoSlice;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::io::AsyncRead as TokioAsyncRead;
|
||||
use tokio::io::{AsyncWrite as TokioAsyncWrite, ReadBuf};
|
||||
use tonic::transport::server::Connected;
|
||||
use tonic::Status;
|
||||
use tracing_core::span::Id;
|
||||
|
||||
struct StreamWrapper<T>(T);
|
||||
impl<T> Connected for StreamWrapper<T> {
|
||||
type ConnectInfo = ();
|
||||
|
||||
fn connect_info(&self) -> Self::ConnectInfo {
|
||||
()
|
||||
}
|
||||
}
|
||||
impl<T: TokioAsyncWrite + Unpin> TokioAsyncWrite for StreamWrapper<T> {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<Result<usize, std::io::Error>> {
|
||||
TokioAsyncWrite::poll_write(Pin::new(&mut self.0), cx, buf)
|
||||
}
|
||||
|
||||
fn poll_flush(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), std::io::Error>> {
|
||||
TokioAsyncWrite::poll_flush(Pin::new(&mut self.0), cx)
|
||||
}
|
||||
|
||||
fn poll_shutdown(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), std::io::Error>> {
|
||||
TokioAsyncWrite::poll_shutdown(Pin::new(&mut self.0), cx)
|
||||
}
|
||||
|
||||
fn poll_write_vectored(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
bufs: &[IoSlice<'_>],
|
||||
) -> Poll<Result<usize, std::io::Error>> {
|
||||
TokioAsyncWrite::poll_write_vectored(Pin::new(&mut self.0), cx, bufs)
|
||||
}
|
||||
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
TokioAsyncWrite::is_write_vectored(&self.0)
|
||||
}
|
||||
}
|
||||
impl<T: TokioAsyncRead + Unpin> TokioAsyncRead for StreamWrapper<T> {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf<'_>,
|
||||
) -> Poll<std::io::Result<()>> {
|
||||
TokioAsyncRead::poll_read(Pin::new(&mut self.0), cx, buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Server {
|
||||
pub aggregator: Option<Aggregator>,
|
||||
client_buffer_size: usize,
|
||||
subscribe: Sender<Command>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
//pub(crate) const DEFAULT_ADDR: IpAddr = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
|
||||
pub(crate) const DEFAULT_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
|
||||
pub(crate) const DEFAULT_PORT: u16 = 49289;
|
||||
|
||||
pub(crate) fn new(
|
||||
aggregator: Aggregator,
|
||||
client_buffer_size: usize,
|
||||
subscribe: Sender<Command>,
|
||||
) -> Self {
|
||||
Self {
|
||||
aggregator: Some(aggregator),
|
||||
client_buffer_size,
|
||||
subscribe,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn serve(
|
||||
mut self, /*, incoming: I */
|
||||
) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
||||
let svc = InstrumentServer::new(self);
|
||||
|
||||
tonic::transport::Server::builder()
|
||||
.add_service(svc)
|
||||
.serve(SocketAddr::new(Self::DEFAULT_ADDR, Self::DEFAULT_PORT))
|
||||
.compat()
|
||||
.await?;
|
||||
|
||||
// TODO: Kill the aggregator task if the serve task has ended.
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Watch<T>(pub(crate) Sender<Result<T, tonic::Status>>);
|
||||
impl<T: Clone> Watch<T> {
|
||||
pub fn update(&self, update: &T) -> bool {
|
||||
self.0.try_send(Ok(update.clone())).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct WatchRequest<T> {
|
||||
pub id: Id,
|
||||
pub stream_sender: async_oneshot::Sender<Receiver<Result<T, tonic::Status>>>,
|
||||
pub buffer: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Command {
|
||||
Instrument(Watch<instrument::Update>),
|
||||
WatchTaskDetail(WatchRequest<tasks::TaskDetails>),
|
||||
Pause,
|
||||
Resume,
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl Instrument for Server {
|
||||
type WatchUpdatesStream = async_channel::Receiver<Result<instrument::Update, Status>>;
|
||||
|
||||
async fn watch_updates(
|
||||
&self,
|
||||
request: tonic::Request<instrument::InstrumentRequest>,
|
||||
) -> Result<tonic::Response<Self::WatchUpdatesStream>, tonic::Status> {
|
||||
match request.remote_addr() {
|
||||
Some(addr) => tracing::debug!(client.addr = %addr, "starting a new watch"),
|
||||
None => tracing::debug!(client.addr = %"<unknown>", "starting a new watch"),
|
||||
}
|
||||
|
||||
if !self.subscribe.is_full() {
|
||||
let (tx, rx) = async_channel::bounded(self.client_buffer_size);
|
||||
self.subscribe.send(Command::Instrument(Watch(tx))).await;
|
||||
tracing::debug!("watch started");
|
||||
Ok(tonic::Response::new(rx))
|
||||
} else {
|
||||
Err(tonic::Status::internal(
|
||||
"cannot start new watch, aggregation task is not running",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
type WatchTaskDetailsStream = async_channel::Receiver<Result<tasks::TaskDetails, Status>>;
|
||||
|
||||
async fn watch_task_details(
|
||||
&self,
|
||||
request: tonic::Request<instrument::TaskDetailsRequest>,
|
||||
) -> Result<tonic::Response<Self::WatchTaskDetailsStream>, tonic::Status> {
|
||||
let task_id = request
|
||||
.into_inner()
|
||||
.id
|
||||
.ok_or_else(|| tonic::Status::invalid_argument("missing task_id"))?
|
||||
.id;
|
||||
|
||||
// `tracing` reserves span ID 0 for niche optimization for `Option<Id>`.
|
||||
let id = std::num::NonZeroU64::new(task_id)
|
||||
.map(Id::from_non_zero_u64)
|
||||
.ok_or_else(|| tonic::Status::invalid_argument("task_id cannot be 0"))?;
|
||||
|
||||
if !self.subscribe.is_full() {
|
||||
// Check with the aggregator task to request a stream if the task exists.
|
||||
let (stream_sender, stream_recv) = async_oneshot::oneshot();
|
||||
self.subscribe
|
||||
.send(Command::WatchTaskDetail(WatchRequest {
|
||||
id,
|
||||
stream_sender,
|
||||
buffer: self.client_buffer_size,
|
||||
}))
|
||||
.await;
|
||||
// If the aggregator drops the sender, the task doesn't exist.
|
||||
let rx = stream_recv.await.map_err(|_| {
|
||||
tracing::warn!(id = ?task_id, "requested task not found");
|
||||
tonic::Status::not_found("task not found")
|
||||
})?;
|
||||
|
||||
tracing::debug!(id = ?task_id, "task details watch started");
|
||||
Ok(tonic::Response::new(rx))
|
||||
} else {
|
||||
Err(tonic::Status::internal(
|
||||
"cannot start new watch, aggregation task is not running",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
async fn pause(
|
||||
&self,
|
||||
_request: tonic::Request<instrument::PauseRequest>,
|
||||
) -> Result<tonic::Response<instrument::PauseResponse>, tonic::Status> {
|
||||
self.subscribe.send(Command::Pause).await.map_err(|_| {
|
||||
tonic::Status::internal("cannot pause, aggregation task is not running")
|
||||
})?;
|
||||
Ok(tonic::Response::new(instrument::PauseResponse {}))
|
||||
}
|
||||
|
||||
async fn resume(
|
||||
&self,
|
||||
_request: tonic::Request<instrument::ResumeRequest>,
|
||||
) -> Result<tonic::Response<instrument::ResumeResponse>, tonic::Status> {
|
||||
self.subscribe.send(Command::Resume).await.map_err(|_| {
|
||||
tonic::Status::internal("cannot resume, aggregation task is not running")
|
||||
})?;
|
||||
Ok(tonic::Response::new(instrument::ResumeResponse {}))
|
||||
}
|
||||
}
|
64
runtime/console/src/stack.rs
Normal file
64
runtime/console/src/stack.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use tracing_core::span::Id;
|
||||
|
||||
// This has been copied from tracing-subscriber. Once the library adds
|
||||
// the ability to iterate over entered spans, this code will
|
||||
// no longer be needed here
|
||||
//
|
||||
// https://github.com/tokio-rs/tracing/blob/master/tracing-subscriber/src/registry/stack.rs
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ContextId {
|
||||
id: Id,
|
||||
duplicate: bool,
|
||||
}
|
||||
|
||||
impl ContextId {
|
||||
pub fn id(&self) -> &Id {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
/// `SpanStack` tracks what spans are currently executing on a thread-local basis.
|
||||
///
|
||||
/// A "separate current span" for each thread is a semantic choice, as each span
|
||||
/// can be executing in a different thread.
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct SpanStack {
|
||||
stack: Vec<ContextId>,
|
||||
}
|
||||
|
||||
impl SpanStack {
|
||||
#[inline]
|
||||
pub(crate) fn push(&mut self, id: Id) -> bool {
|
||||
let duplicate = self.stack.iter().any(|i| i.id == id);
|
||||
self.stack.push(ContextId { id, duplicate });
|
||||
!duplicate
|
||||
}
|
||||
|
||||
/// Pop a currently entered span.
|
||||
///
|
||||
/// Returns `true` if the span was actually exited.
|
||||
#[inline]
|
||||
pub(crate) fn pop(&mut self, expected_id: &Id) -> bool {
|
||||
if let Some((idx, _)) = self
|
||||
.stack
|
||||
.iter()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find(|(_, ctx_id)| ctx_id.id == *expected_id)
|
||||
{
|
||||
let ContextId { id: _, duplicate } = self.stack.remove(idx);
|
||||
return !duplicate;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &Id> {
|
||||
self.stack
|
||||
.iter()
|
||||
.filter_map(|ContextId { id, duplicate }| if *duplicate { None } else { Some(id) })
|
||||
}
|
||||
|
||||
pub(crate) fn stack(&self) -> &Vec<ContextId> {
|
||||
&self.stack
|
||||
}
|
||||
}
|
610
runtime/console/src/stats.rs
Normal file
610
runtime/console/src/stats.rs
Normal file
@ -0,0 +1,610 @@
|
||||
use crate::id_map::ToProto;
|
||||
use crate::{attribute, event};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use hdrhistogram::serialization::{Serializer, V2Serializer};
|
||||
use std::cmp;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant, SystemTime};
|
||||
use tracing::span;
|
||||
|
||||
/// A type which records whether it has unsent updates.
|
||||
///
|
||||
/// If something implementing this trait has been changed since the last time
|
||||
/// data was sent to a client, it will indicate that it is "dirty". If it has
|
||||
/// not been changed, it does not have to be included in the current update.
|
||||
pub(crate) trait Unsent {
|
||||
/// Returns `true` if this type has unsent updates, and if it does, clears
|
||||
/// the flag indicating there are unsent updates.
|
||||
///
|
||||
/// This is called when filtering which stats need to be included in the
|
||||
/// current update. If this returns `true`, it will be included, so it
|
||||
/// becomes no longer dirty.
|
||||
fn take_unsent(&self) -> bool;
|
||||
|
||||
/// Returns `true` if this type has unsent updates, without changing the
|
||||
/// flag.
|
||||
fn is_unsent(&self) -> bool;
|
||||
}
|
||||
|
||||
// An entity (e.g Task, Resource) that at some point in
|
||||
// time can be dropped. This generally refers to spans that
|
||||
// have been closed indicating that a task, async op or a
|
||||
// resource is not in use anymore
|
||||
pub(crate) trait DroppedAt {
|
||||
fn dropped_at(&self) -> Option<Instant>;
|
||||
}
|
||||
|
||||
impl<T: DroppedAt> DroppedAt for Arc<T> {
|
||||
fn dropped_at(&self) -> Option<Instant> {
|
||||
T::dropped_at(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unsent> Unsent for Arc<T> {
|
||||
fn take_unsent(&self) -> bool {
|
||||
T::take_unsent(self)
|
||||
}
|
||||
|
||||
fn is_unsent(&self) -> bool {
|
||||
T::is_unsent(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToProto> ToProto for Arc<T> {
|
||||
type Output = T::Output;
|
||||
fn to_proto(&self, base_time: &TimeAnchor) -> T::Output {
|
||||
T::to_proto(self, base_time)
|
||||
}
|
||||
}
|
||||
|
||||
/// Anchors an `Instant` with a `SystemTime` timestamp to allow converting
|
||||
/// monotonic `Instant`s into timestamps that can be sent over the wire.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct TimeAnchor {
|
||||
mono: Instant,
|
||||
sys: SystemTime,
|
||||
}
|
||||
|
||||
impl TimeAnchor {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
mono: Instant::now(),
|
||||
sys: SystemTime::now(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_system_time(&self, t: Instant) -> SystemTime {
|
||||
let dur = t
|
||||
.checked_duration_since(self.mono)
|
||||
.unwrap_or_else(|| Duration::from_secs(0));
|
||||
self.sys + dur
|
||||
}
|
||||
|
||||
pub(crate) fn to_timestamp(&self, t: Instant) -> prost_types::Timestamp {
|
||||
self.to_system_time(t).into()
|
||||
}
|
||||
}
|
||||
|
||||
trait RecordPoll {
|
||||
fn record_poll_duration(&mut self, duration: Duration);
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct PollStats<H> {
|
||||
/// The number of polls in progress
|
||||
current_polls: AtomicUsize,
|
||||
/// The total number of polls
|
||||
polls: AtomicUsize,
|
||||
timestamps: Mutex<PollTimestamps<H>>,
|
||||
}
|
||||
|
||||
impl<H: RecordPoll> PollStats<H> {
|
||||
fn start_poll(&self, at: Instant) {
|
||||
if self.current_polls.fetch_add(1, Ordering::AcqRel) == 0 {
|
||||
// We are starting the first poll
|
||||
let mut timestamps = self.timestamps.lock().unwrap();
|
||||
if timestamps.first_poll.is_none() {
|
||||
timestamps.first_poll = Some(at);
|
||||
}
|
||||
|
||||
timestamps.last_poll_started = Some(at);
|
||||
|
||||
self.polls.fetch_add(1, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
fn end_poll(&self, at: Instant) {
|
||||
// Are we ending the last current poll?
|
||||
if self.current_polls.fetch_sub(1, Ordering::AcqRel) > 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut timestamps = self.timestamps.lock().unwrap();
|
||||
let started = match timestamps.last_poll_started {
|
||||
Some(last_poll) => last_poll,
|
||||
None => {
|
||||
eprintln!(
|
||||
"a poll ended, but start timestamp was recorded. \
|
||||
this is probably a `console-subscriber` bug"
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
timestamps.last_poll_ended = Some(at);
|
||||
let elapsed = match at.checked_duration_since(started) {
|
||||
Some(elapsed) => elapsed,
|
||||
None => {
|
||||
eprintln!(
|
||||
"possible Instant clock skew detected: a poll's end timestamp \
|
||||
was before its start timestamp\nstart = {:?}\n end = {:?}",
|
||||
started, at
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// if we have a poll time histogram, add the timestamp
|
||||
timestamps.histogram.record_poll_duration(elapsed);
|
||||
|
||||
timestamps.busy_time += elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
impl<H> ToProto for PollStats<H> {
|
||||
type Output = console_api::PollStats;
|
||||
|
||||
fn to_proto(&self, base_time: &TimeAnchor) -> Self::Output {
|
||||
let timestamps = self.timestamps.lock().unwrap();
|
||||
console_api::PollStats {
|
||||
polls: self.polls.load(Ordering::Acquire) as u64,
|
||||
first_poll: timestamps.first_poll.map(|at| base_time.to_timestamp(at)),
|
||||
last_poll_started: timestamps
|
||||
.last_poll_started
|
||||
.map(|at| base_time.to_timestamp(at)),
|
||||
last_poll_ended: timestamps
|
||||
.last_poll_ended
|
||||
.map(|at| base_time.to_timestamp(at)),
|
||||
busy_time: Some(timestamps.busy_time.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stats associated with a task.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TaskStats {
|
||||
is_dirty: AtomicBool,
|
||||
is_dropped: AtomicBool,
|
||||
// task stats
|
||||
pub(crate) created_at: Instant,
|
||||
timestamps: Mutex<TaskTimestamps>,
|
||||
|
||||
// waker stats
|
||||
wakes: AtomicUsize,
|
||||
waker_clones: AtomicUsize,
|
||||
waker_drops: AtomicUsize,
|
||||
self_wakes: AtomicUsize,
|
||||
|
||||
/// Poll durations and other stats.
|
||||
poll_stats: PollStats<Histogram>,
|
||||
}
|
||||
|
||||
impl TaskStats {
|
||||
pub(crate) fn new(poll_duration_max: u64, created_at: Instant) -> Self {
|
||||
Self {
|
||||
is_dirty: AtomicBool::new(true),
|
||||
is_dropped: AtomicBool::new(false),
|
||||
created_at,
|
||||
timestamps: Mutex::new(TaskTimestamps::default()),
|
||||
poll_stats: PollStats {
|
||||
timestamps: Mutex::new(PollTimestamps {
|
||||
histogram: Histogram::new(poll_duration_max),
|
||||
first_poll: None,
|
||||
last_poll_started: None,
|
||||
last_poll_ended: None,
|
||||
busy_time: Duration::new(0, 0),
|
||||
}),
|
||||
current_polls: AtomicUsize::new(0),
|
||||
polls: AtomicUsize::new(0),
|
||||
},
|
||||
wakes: AtomicUsize::new(0),
|
||||
waker_clones: AtomicUsize::new(1),
|
||||
waker_drops: AtomicUsize::new(0),
|
||||
self_wakes: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn poll_duration_histogram(
|
||||
&self,
|
||||
) -> console_api::tasks::task_details::PollTimesHistogram {
|
||||
let hist = self
|
||||
.poll_stats
|
||||
.timestamps
|
||||
.lock()
|
||||
.unwrap()
|
||||
.histogram
|
||||
.to_proto();
|
||||
console_api::tasks::task_details::PollTimesHistogram::Histogram(hist)
|
||||
}
|
||||
|
||||
pub(crate) fn record_wake_op(&self, op: event::WakeOp, at: Instant) {
|
||||
use event::WakeOp;
|
||||
match op {
|
||||
WakeOp::Wake { self_wake } => {
|
||||
self.wake(at, self_wake);
|
||||
}
|
||||
WakeOp::WakeByRef { self_wake } => {
|
||||
self.wake(at, self_wake);
|
||||
}
|
||||
WakeOp::Clone => {
|
||||
self.waker_clones.fetch_add(1, Ordering::Release);
|
||||
}
|
||||
WakeOp::Drop => {
|
||||
self.waker_drops.fetch_add(1, Ordering::Release);
|
||||
}
|
||||
}
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
fn wake(&self, at: Instant, self_wake: bool) {
|
||||
let mut timestamps = self.timestamps.lock().unwrap();
|
||||
timestamps.last_wake = cmp::max(timestamps.last_wake, Some(at));
|
||||
if self_wake {
|
||||
self.wakes.fetch_add(1, Ordering::Release);
|
||||
}
|
||||
self.wakes.fetch_add(1, Ordering::Release);
|
||||
}
|
||||
|
||||
pub(crate) fn start_poll(&self, at: Instant) {
|
||||
self.poll_stats.start_poll(at);
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
pub(crate) fn end_poll(&self, at: Instant) {
|
||||
self.poll_stats.end_poll(at);
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
pub(crate) fn drop_task(&self, dropped_at: Instant) {
|
||||
if self.is_dropped.swap(true, Ordering::AcqRel) {
|
||||
// The task was already dropped.
|
||||
// TODO(eliza): this could maybe panic in debug mode...
|
||||
return;
|
||||
}
|
||||
|
||||
let mut timestamps = self.timestamps.lock().unwrap();
|
||||
let _prev = timestamps.dropped_at.replace(dropped_at);
|
||||
debug_assert_eq!(_prev, None, "tried to drop a task twice; this is a bug!");
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
fn make_dirty(&self) {
|
||||
self.is_dirty.swap(true, Ordering::AcqRel);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToProto for TaskStats {
|
||||
type Output = console_api::tasks::Stats;
|
||||
|
||||
fn to_proto(&self, base_time: &TimeAnchor) -> Self::Output {
|
||||
let poll_stats = Some(self.poll_stats.to_proto(base_time));
|
||||
let timestamps = self.timestamps.lock().unwrap();
|
||||
console_api::tasks::Stats {
|
||||
poll_stats,
|
||||
created_at: Some(base_time.to_timestamp(self.created_at)),
|
||||
dropped_at: timestamps.dropped_at.map(|at| base_time.to_timestamp(at)),
|
||||
wakes: self.wakes.load(Ordering::Acquire) as u64,
|
||||
waker_clones: self.waker_clones.load(Ordering::Acquire) as u64,
|
||||
self_wakes: self.self_wakes.load(Ordering::Acquire) as u64,
|
||||
waker_drops: self.waker_drops.load(Ordering::Acquire) as u64,
|
||||
last_wake: timestamps.last_wake.map(|at| base_time.to_timestamp(at)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Unsent for TaskStats {
|
||||
#[inline]
|
||||
fn take_unsent(&self) -> bool {
|
||||
self.is_dirty.swap(false, Ordering::AcqRel)
|
||||
}
|
||||
|
||||
fn is_unsent(&self) -> bool {
|
||||
self.is_dirty.load(Ordering::Acquire)
|
||||
}
|
||||
}
|
||||
|
||||
impl DroppedAt for TaskStats {
|
||||
fn dropped_at(&self) -> Option<Instant> {
|
||||
// avoid acquiring the lock if we know we haven't tried to drop this
|
||||
// thing yet
|
||||
if self.is_dropped.load(Ordering::Acquire) {
|
||||
return self.timestamps.lock().unwrap().dropped_at;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Stats associated with an async operation.
|
||||
///
|
||||
/// This shares all of the same fields as [`ResourceStats]`, with the addition
|
||||
/// of [`PollStats`] tracking when the async operation is polled, and the task
|
||||
/// ID of the last task to poll the async op.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct AsyncOpStats {
|
||||
/// The task ID of the last task to poll this async op.
|
||||
///
|
||||
/// This is set every time the async op is polled, in case a future is
|
||||
/// passed between tasks.
|
||||
task_id: AtomicCell<u64>,
|
||||
|
||||
/// Fields shared with `ResourceStats`.
|
||||
pub(crate) stats: ResourceStats,
|
||||
|
||||
/// Poll durations and other stats.
|
||||
poll_stats: PollStats<()>,
|
||||
}
|
||||
|
||||
impl AsyncOpStats {
|
||||
pub(crate) fn new(
|
||||
created_at: Instant,
|
||||
inherit_child_attributes: bool,
|
||||
parent_id: Option<span::Id>,
|
||||
) -> Self {
|
||||
Self {
|
||||
task_id: AtomicCell::new(0),
|
||||
stats: ResourceStats::new(created_at, inherit_child_attributes, parent_id),
|
||||
poll_stats: PollStats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn task_id(&self) -> Option<u64> {
|
||||
let id = self.task_id.load();
|
||||
if id > 0 {
|
||||
Some(id as u64)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_task_id(&self, id: &tracing::span::Id) {
|
||||
self.task_id.store(id.into_u64());
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
pub(crate) fn drop_async_op(&self, dropped_at: Instant) {
|
||||
self.stats.drop_resource(dropped_at)
|
||||
}
|
||||
|
||||
pub(crate) fn start_poll(&self, at: Instant) {
|
||||
self.poll_stats.start_poll(at);
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
pub(crate) fn end_poll(&self, at: Instant) {
|
||||
self.poll_stats.end_poll(at);
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn make_dirty(&self) {
|
||||
self.stats.make_dirty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Unsent for AsyncOpStats {
|
||||
#[inline]
|
||||
fn take_unsent(&self) -> bool {
|
||||
self.stats.take_unsent()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_unsent(&self) -> bool {
|
||||
self.stats.is_unsent()
|
||||
}
|
||||
}
|
||||
|
||||
impl DroppedAt for AsyncOpStats {
|
||||
fn dropped_at(&self) -> Option<Instant> {
|
||||
self.stats.dropped_at()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToProto for AsyncOpStats {
|
||||
type Output = console_api::async_ops::Stats;
|
||||
|
||||
fn to_proto(&self, base_time: &TimeAnchor) -> Self::Output {
|
||||
let attributes = self
|
||||
.stats
|
||||
.attributes
|
||||
.lock()
|
||||
.unwrap()
|
||||
.values()
|
||||
.cloned()
|
||||
.collect();
|
||||
console_api::async_ops::Stats {
|
||||
poll_stats: Some(self.poll_stats.to_proto(base_time)),
|
||||
created_at: Some(base_time.to_timestamp(self.stats.created_at)),
|
||||
dropped_at: self
|
||||
.stats
|
||||
.dropped_at
|
||||
.lock()
|
||||
.unwrap()
|
||||
.map(|at| base_time.to_timestamp(at)),
|
||||
task_id: self.task_id().map(Into::into),
|
||||
attributes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stats associated with a resource.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ResourceStats {
|
||||
is_dirty: AtomicBool,
|
||||
is_dropped: AtomicBool,
|
||||
created_at: Instant,
|
||||
dropped_at: Mutex<Option<Instant>>,
|
||||
attributes: Mutex<attribute::Attributes>,
|
||||
pub(crate) inherit_child_attributes: bool,
|
||||
pub(crate) parent_id: Option<span::Id>,
|
||||
}
|
||||
|
||||
impl ResourceStats {
|
||||
pub(crate) fn new(
|
||||
created_at: Instant,
|
||||
inherit_child_attributes: bool,
|
||||
parent_id: Option<span::Id>,
|
||||
) -> Self {
|
||||
Self {
|
||||
is_dirty: AtomicBool::new(true),
|
||||
is_dropped: AtomicBool::new(false),
|
||||
created_at,
|
||||
dropped_at: Mutex::new(None),
|
||||
attributes: Default::default(),
|
||||
inherit_child_attributes,
|
||||
parent_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_attribute(&self, id: &span::Id, update: &attribute::Update) {
|
||||
self.attributes.lock().unwrap().update(id, update);
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn drop_resource(&self, dropped_at: Instant) {
|
||||
if self.is_dropped.swap(true, Ordering::AcqRel) {
|
||||
// The task was already dropped.
|
||||
// TODO(eliza): this could maybe panic in debug mode...
|
||||
return;
|
||||
}
|
||||
|
||||
let mut timestamp = self.dropped_at.lock().unwrap();
|
||||
let _prev = timestamp.replace(dropped_at);
|
||||
debug_assert_eq!(
|
||||
_prev, None,
|
||||
"tried to drop a resource/async op twice; this is a bug!"
|
||||
);
|
||||
self.make_dirty();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn make_dirty(&self) {
|
||||
self.is_dirty.swap(true, Ordering::AcqRel);
|
||||
}
|
||||
}
|
||||
|
||||
impl Unsent for ResourceStats {
|
||||
#[inline]
|
||||
fn take_unsent(&self) -> bool {
|
||||
self.is_dirty.swap(false, Ordering::AcqRel)
|
||||
}
|
||||
|
||||
fn is_unsent(&self) -> bool {
|
||||
self.is_dirty.load(Ordering::Acquire)
|
||||
}
|
||||
}
|
||||
|
||||
impl DroppedAt for ResourceStats {
|
||||
fn dropped_at(&self) -> Option<Instant> {
|
||||
// avoid acquiring the lock if we know we haven't tried to drop this
|
||||
// thing yet
|
||||
if self.is_dropped.load(Ordering::Acquire) {
|
||||
return *self.dropped_at.lock().unwrap();
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl ToProto for ResourceStats {
|
||||
type Output = console_api::resources::Stats;
|
||||
|
||||
fn to_proto(&self, base_time: &TimeAnchor) -> Self::Output {
|
||||
let attributes = self.attributes.lock().unwrap().values().cloned().collect();
|
||||
console_api::resources::Stats {
|
||||
created_at: Some(base_time.to_timestamp(self.created_at)),
|
||||
dropped_at: self
|
||||
.dropped_at
|
||||
.lock()
|
||||
.unwrap()
|
||||
.map(|at| base_time.to_timestamp(at)),
|
||||
attributes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct TaskTimestamps {
|
||||
dropped_at: Option<Instant>,
|
||||
last_wake: Option<Instant>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct PollTimestamps<H> {
|
||||
first_poll: Option<Instant>,
|
||||
last_poll_started: Option<Instant>,
|
||||
last_poll_ended: Option<Instant>,
|
||||
busy_time: Duration,
|
||||
histogram: H,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Histogram {
|
||||
histogram: hdrhistogram::Histogram<u64>,
|
||||
max: u64,
|
||||
outliers: u64,
|
||||
max_outlier: Option<u64>,
|
||||
}
|
||||
|
||||
impl Histogram {
|
||||
fn new(max: u64) -> Self {
|
||||
// significant figures should be in the [0-5] range and memory usage
|
||||
// grows exponentially with higher a sigfig
|
||||
let histogram = hdrhistogram::Histogram::new_with_max(max, 2).unwrap();
|
||||
Self {
|
||||
histogram,
|
||||
max,
|
||||
max_outlier: None,
|
||||
outliers: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_proto(&self) -> console_api::tasks::DurationHistogram {
|
||||
let mut serializer = V2Serializer::new();
|
||||
let mut raw_histogram = Vec::new();
|
||||
serializer
|
||||
.serialize(&self.histogram, &mut raw_histogram)
|
||||
.expect("histogram failed to serialize");
|
||||
console_api::tasks::DurationHistogram {
|
||||
raw_histogram,
|
||||
max_value: self.max,
|
||||
high_outliers: self.outliers,
|
||||
highest_outlier: self.max_outlier,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RecordPoll for Histogram {
|
||||
fn record_poll_duration(&mut self, duration: Duration) {
|
||||
let mut duration_ns = duration.as_nanos() as u64;
|
||||
|
||||
// clamp the duration to the histogram's max value
|
||||
if duration_ns > self.max {
|
||||
self.outliers += 1;
|
||||
self.max_outlier = cmp::max(self.max_outlier, Some(duration_ns));
|
||||
duration_ns = self.max;
|
||||
}
|
||||
|
||||
self.histogram
|
||||
.record(duration_ns)
|
||||
.expect("duration has already been clamped to histogram max value")
|
||||
}
|
||||
}
|
||||
|
||||
impl RecordPoll for () {
|
||||
fn record_poll_duration(&mut self, _: Duration) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
535
runtime/console/src/visitors.rs
Normal file
535
runtime/console/src/visitors.rs
Normal file
@ -0,0 +1,535 @@
|
||||
use crate::{attribute, event};
|
||||
use console_api::resources::resource;
|
||||
use tracing::{field, span};
|
||||
use tracing_core::field::Visit;
|
||||
|
||||
const LOCATION_FILE: &str = "loc.file";
|
||||
const LOCATION_LINE: &str = "loc.line";
|
||||
const LOCATION_COLUMN: &str = "loc.col";
|
||||
const INHERIT_FIELD_NAME: &str = "inherits_child_attrs";
|
||||
|
||||
/// Used to extract the fields needed to construct
|
||||
/// an Event::Resource from the metadata of a tracing span
|
||||
/// that has the following shape:
|
||||
///
|
||||
/// tracing::trace_span!(
|
||||
/// "runtime.resource",
|
||||
/// concrete_type = "Sleep",
|
||||
/// kind = "timer",
|
||||
/// is_internal = true,
|
||||
/// inherits_child_attrs = true,
|
||||
/// );
|
||||
///
|
||||
/// Fields:
|
||||
/// concrete_type - indicates the concrete rust type for this resource
|
||||
/// kind - indicates the type of resource (i.e. timer, sync, io )
|
||||
/// is_internal - whether this is a resource type that is not exposed publicly (i.e. BatchSemaphore)
|
||||
/// inherits_child_attrs - whether this resource should inherit the state attributes of its children
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ResourceVisitor {
|
||||
concrete_type: Option<String>,
|
||||
kind: Option<resource::Kind>,
|
||||
is_internal: bool,
|
||||
inherit_child_attrs: bool,
|
||||
line: Option<u32>,
|
||||
file: Option<String>,
|
||||
column: Option<u32>,
|
||||
}
|
||||
|
||||
pub(crate) struct ResourceVisitorResult {
|
||||
pub(crate) concrete_type: String,
|
||||
pub(crate) kind: resource::Kind,
|
||||
pub(crate) location: Option<console_api::Location>,
|
||||
pub(crate) is_internal: bool,
|
||||
pub(crate) inherit_child_attrs: bool,
|
||||
}
|
||||
|
||||
/// Used to extract all fields from the metadata
|
||||
/// of a tracing span
|
||||
pub(crate) struct FieldVisitor {
|
||||
fields: Vec<console_api::Field>,
|
||||
meta_id: console_api::MetaId,
|
||||
}
|
||||
|
||||
/// Used to extract the fields needed to construct
|
||||
/// an `Event::Spawn` from the metadata of a tracing span
|
||||
/// that has the following shape:
|
||||
///
|
||||
/// ```
|
||||
/// tracing::trace_span!(
|
||||
/// target: "tokio::task",
|
||||
/// "runtime.spawn",
|
||||
/// kind = "local",
|
||||
/// task.name = "some_name",
|
||||
/// loc.file = "some_file.rs",
|
||||
/// loc.line = 555,
|
||||
/// loc.col = 5,
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// # Fields
|
||||
///
|
||||
/// This visitor has special behavior for `loc.line`, `loc.file`, and `loc.col`
|
||||
/// fields, which are interpreted as a Rust source code location where the task
|
||||
/// was spawned, if they are present. Other fields are recorded as arbitrary
|
||||
/// key-value pairs.
|
||||
pub(crate) struct TaskVisitor {
|
||||
field_visitor: FieldVisitor,
|
||||
line: Option<u32>,
|
||||
file: Option<String>,
|
||||
column: Option<u32>,
|
||||
}
|
||||
|
||||
/// Used to extract the fields needed to construct
|
||||
/// an Event::AsyncOp from the metadata of a tracing span
|
||||
/// that has the following shape:
|
||||
///
|
||||
/// tracing::trace_span!(
|
||||
/// "runtime.resource.async_op",
|
||||
/// source = "Sleep::new_timeout",
|
||||
/// );
|
||||
///
|
||||
/// Fields:
|
||||
/// source - the method which has created an instance of this async operation
|
||||
#[derive(Default)]
|
||||
pub(crate) struct AsyncOpVisitor {
|
||||
source: Option<String>,
|
||||
inherit_child_attrs: bool,
|
||||
}
|
||||
|
||||
/// Used to extract the fields needed to construct
|
||||
/// an Event::Waker from the metadata of a tracing span
|
||||
/// that has the following shape:
|
||||
///
|
||||
/// tracing::trace!(
|
||||
/// target: "tokio::task::waker",
|
||||
/// op = "waker.clone",
|
||||
/// task.id = id.into_u64(),
|
||||
/// );
|
||||
///
|
||||
/// Fields:
|
||||
/// task.id - the id of the task this waker will wake
|
||||
/// op - the operation associated with this waker event
|
||||
#[derive(Default)]
|
||||
pub(crate) struct WakerVisitor {
|
||||
id: Option<span::Id>,
|
||||
op: Option<event::WakeOp>,
|
||||
}
|
||||
|
||||
/// Used to extract the fields needed to construct
|
||||
/// an Event::PollOp from the metadata of a tracing event
|
||||
/// that has the following shape:
|
||||
///
|
||||
/// tracing::trace!(
|
||||
/// target: "runtime::resource::poll_op",
|
||||
/// op_name = "poll_elapsed",
|
||||
/// readiness = "pending"
|
||||
/// );
|
||||
///
|
||||
/// Fields:
|
||||
/// op_name - the name of this resource poll operation
|
||||
/// readiness - the result of invoking this poll op, describing its readiness
|
||||
#[derive(Default)]
|
||||
pub(crate) struct PollOpVisitor {
|
||||
op_name: Option<String>,
|
||||
is_ready: Option<bool>,
|
||||
}
|
||||
|
||||
/// Used to extract the fields needed to construct
|
||||
/// an Event::StateUpdate from the metadata of a tracing event
|
||||
/// that has the following shape:
|
||||
///
|
||||
/// tracing::trace!(
|
||||
/// target: "runtime::resource::state_update",
|
||||
/// duration = duration,
|
||||
/// duration.unit = "ms",
|
||||
/// duration.op = "override",
|
||||
/// );
|
||||
///
|
||||
/// Fields:
|
||||
/// attribute_name - a field value for a field that has the name of the resource attribute being updated
|
||||
/// value - the value for this update
|
||||
/// unit - the unit for the value being updated (e.g. ms, s, bytes)
|
||||
/// op - the operation that this update performs to the value of the resource attribute (one of: ovr, sub, add)
|
||||
pub(crate) struct StateUpdateVisitor {
|
||||
meta_id: console_api::MetaId,
|
||||
field: Option<console_api::Field>,
|
||||
unit: Option<String>,
|
||||
op: Option<attribute::UpdateOp>,
|
||||
}
|
||||
|
||||
impl ResourceVisitor {
|
||||
pub(crate) const RES_SPAN_NAME: &'static str = "runtime.resource";
|
||||
const RES_CONCRETE_TYPE_FIELD_NAME: &'static str = "concrete_type";
|
||||
const RES_VIZ_FIELD_NAME: &'static str = "is_internal";
|
||||
const RES_KIND_FIELD_NAME: &'static str = "kind";
|
||||
const RES_KIND_TIMER: &'static str = "timer";
|
||||
|
||||
pub(crate) fn result(self) -> Option<ResourceVisitorResult> {
|
||||
let concrete_type = self.concrete_type?;
|
||||
let kind = self.kind?;
|
||||
|
||||
let location = if self.file.is_some() && self.line.is_some() && self.column.is_some() {
|
||||
Some(console_api::Location {
|
||||
file: self.file,
|
||||
line: self.line,
|
||||
column: self.column,
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Some(ResourceVisitorResult {
|
||||
concrete_type,
|
||||
kind,
|
||||
location,
|
||||
is_internal: self.is_internal,
|
||||
inherit_child_attrs: self.inherit_child_attrs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for ResourceVisitor {
|
||||
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
|
||||
|
||||
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
||||
match field.name() {
|
||||
Self::RES_CONCRETE_TYPE_FIELD_NAME => self.concrete_type = Some(value.to_string()),
|
||||
Self::RES_KIND_FIELD_NAME => {
|
||||
let kind = Some(match value {
|
||||
Self::RES_KIND_TIMER => {
|
||||
resource::kind::Kind::Known(resource::kind::Known::Timer as i32)
|
||||
}
|
||||
other => resource::kind::Kind::Other(other.to_string()),
|
||||
});
|
||||
self.kind = Some(resource::Kind { kind });
|
||||
}
|
||||
LOCATION_FILE => self.file = Some(value.to_string()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
||||
match field.name() {
|
||||
Self::RES_VIZ_FIELD_NAME => self.is_internal = value,
|
||||
INHERIT_FIELD_NAME => self.inherit_child_attrs = value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
|
||||
match field.name() {
|
||||
LOCATION_LINE => self.line = Some(value as u32),
|
||||
LOCATION_COLUMN => self.column = Some(value as u32),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldVisitor {
|
||||
pub(crate) fn new(meta_id: console_api::MetaId) -> Self {
|
||||
FieldVisitor {
|
||||
fields: Vec::default(),
|
||||
meta_id,
|
||||
}
|
||||
}
|
||||
pub(crate) fn result(self) -> Vec<console_api::Field> {
|
||||
self.fields
|
||||
}
|
||||
}
|
||||
|
||||
impl TaskVisitor {
|
||||
pub(crate) const SPAWN_TARGET: &'static str = "executor::task";
|
||||
pub(crate) const SPAWN_NAME: &'static str = "runtime.spawn";
|
||||
|
||||
pub(crate) fn new(meta_id: console_api::MetaId) -> Self {
|
||||
TaskVisitor {
|
||||
field_visitor: FieldVisitor::new(meta_id),
|
||||
line: None,
|
||||
file: None,
|
||||
column: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn result(self) -> (Vec<console_api::Field>, Option<console_api::Location>) {
|
||||
let fields = self.field_visitor.result();
|
||||
let location = if self.file.is_some() && self.line.is_some() && self.column.is_some() {
|
||||
Some(console_api::Location {
|
||||
file: self.file,
|
||||
line: self.line,
|
||||
column: self.column,
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(fields, location)
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for TaskVisitor {
|
||||
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
|
||||
self.field_visitor.record_debug(field, value);
|
||||
}
|
||||
|
||||
fn record_i64(&mut self, field: &tracing_core::Field, value: i64) {
|
||||
self.field_visitor.record_i64(field, value);
|
||||
}
|
||||
|
||||
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
|
||||
match field.name() {
|
||||
LOCATION_LINE => self.line = Some(value as u32),
|
||||
LOCATION_COLUMN => self.column = Some(value as u32),
|
||||
_ => self.field_visitor.record_u64(field, value),
|
||||
}
|
||||
}
|
||||
|
||||
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
||||
self.field_visitor.record_bool(field, value);
|
||||
}
|
||||
|
||||
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
||||
if field.name() == LOCATION_FILE {
|
||||
self.file = Some(value.to_string());
|
||||
} else {
|
||||
self.field_visitor.record_str(field, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for FieldVisitor {
|
||||
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
|
||||
self.fields.push(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
|
||||
fn record_i64(&mut self, field: &tracing_core::Field, value: i64) {
|
||||
self.fields.push(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
|
||||
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
|
||||
self.fields.push(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
|
||||
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
||||
self.fields.push(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
|
||||
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
||||
self.fields.push(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncOpVisitor {
|
||||
pub(crate) const ASYNC_OP_SPAN_NAME: &'static str = "runtime.resource.async_op";
|
||||
pub(crate) const ASYNC_OP_POLL_NAME: &'static str = "runtime.resource.async_op.poll";
|
||||
const ASYNC_OP_SRC_FIELD_NAME: &'static str = "source";
|
||||
|
||||
pub(crate) fn result(self) -> Option<(String, bool)> {
|
||||
let inherit = self.inherit_child_attrs;
|
||||
self.source.map(|s| (s, inherit))
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for AsyncOpVisitor {
|
||||
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
|
||||
|
||||
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
||||
if field.name() == Self::ASYNC_OP_SRC_FIELD_NAME {
|
||||
self.source = Some(value.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
||||
if field.name() == INHERIT_FIELD_NAME {
|
||||
self.inherit_child_attrs = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WakerVisitor {
|
||||
pub(crate) const WAKER_EVENT_TARGET: &'static str = "executor::waker";
|
||||
|
||||
const WAKE: &'static str = "waker.wake";
|
||||
const WAKE_BY_REF: &'static str = "waker.wake_by_ref";
|
||||
const CLONE: &'static str = "waker.clone";
|
||||
const DROP: &'static str = "waker.drop";
|
||||
const TASK_ID_FIELD_NAME: &'static str = "task.id";
|
||||
|
||||
pub(crate) fn result(self) -> Option<(span::Id, event::WakeOp)> {
|
||||
self.id.zip(self.op)
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for WakerVisitor {
|
||||
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {
|
||||
// don't care (yet?)
|
||||
}
|
||||
|
||||
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
|
||||
if field.name() == Self::TASK_ID_FIELD_NAME {
|
||||
self.id = Some(span::Id::from_u64(value));
|
||||
}
|
||||
}
|
||||
|
||||
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
||||
use crate::event::WakeOp;
|
||||
if field.name() == "op" {
|
||||
self.op = Some(match value {
|
||||
Self::WAKE => WakeOp::Wake { self_wake: false },
|
||||
Self::WAKE_BY_REF => WakeOp::WakeByRef { self_wake: false },
|
||||
Self::CLONE => WakeOp::Clone,
|
||||
Self::DROP => WakeOp::Drop,
|
||||
_ => return,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PollOpVisitor {
|
||||
pub(crate) const POLL_OP_EVENT_TARGET: &'static str = "runtime::resource::poll_op";
|
||||
const OP_NAME_FIELD_NAME: &'static str = "op_name";
|
||||
const OP_READINESS_FIELD_NAME: &'static str = "is_ready";
|
||||
|
||||
pub(crate) fn result(self) -> Option<(String, bool)> {
|
||||
let op_name = self.op_name?;
|
||||
let is_ready = self.is_ready?;
|
||||
Some((op_name, is_ready))
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for PollOpVisitor {
|
||||
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
|
||||
|
||||
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
||||
if field.name() == Self::OP_READINESS_FIELD_NAME {
|
||||
self.is_ready = Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
||||
if field.name() == Self::OP_NAME_FIELD_NAME {
|
||||
self.op_name = Some(value.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StateUpdateVisitor {
|
||||
pub(crate) const RE_STATE_UPDATE_EVENT_TARGET: &'static str = "runtime::resource::state_update";
|
||||
pub(crate) const AO_STATE_UPDATE_EVENT_TARGET: &'static str =
|
||||
"runtime::resource::async_op::state_update";
|
||||
|
||||
const STATE_OP_SUFFIX: &'static str = ".op";
|
||||
const STATE_UNIT_SUFFIX: &'static str = ".unit";
|
||||
|
||||
const OP_ADD: &'static str = "add";
|
||||
const OP_SUB: &'static str = "sub";
|
||||
const OP_OVERRIDE: &'static str = "override";
|
||||
|
||||
pub(crate) fn new(meta_id: console_api::MetaId) -> Self {
|
||||
StateUpdateVisitor {
|
||||
meta_id,
|
||||
field: None,
|
||||
unit: None,
|
||||
op: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn result(self) -> Option<attribute::Update> {
|
||||
Some(attribute::Update {
|
||||
field: self.field?,
|
||||
op: self.op,
|
||||
unit: self.unit,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for StateUpdateVisitor {
|
||||
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
|
||||
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
|
||||
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
|
||||
{
|
||||
self.field = Some(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn record_i64(&mut self, field: &field::Field, value: i64) {
|
||||
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
|
||||
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
|
||||
{
|
||||
self.field = Some(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn record_u64(&mut self, field: &field::Field, value: u64) {
|
||||
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
|
||||
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
|
||||
{
|
||||
self.field = Some(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn record_bool(&mut self, field: &field::Field, value: bool) {
|
||||
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
|
||||
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
|
||||
{
|
||||
self.field = Some(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn record_str(&mut self, field: &field::Field, value: &str) {
|
||||
if field.name().ends_with(Self::STATE_OP_SUFFIX) {
|
||||
match value {
|
||||
Self::OP_ADD => self.op = Some(attribute::UpdateOp::Add),
|
||||
Self::OP_SUB => self.op = Some(attribute::UpdateOp::Sub),
|
||||
Self::OP_OVERRIDE => self.op = Some(attribute::UpdateOp::Override),
|
||||
_ => {}
|
||||
};
|
||||
} else if field.name().ends_with(Self::STATE_UNIT_SUFFIX) {
|
||||
self.unit = Some(value.to_string());
|
||||
} else {
|
||||
self.field = Some(console_api::Field {
|
||||
name: Some(field.name().into()),
|
||||
value: Some(value.into()),
|
||||
metadata_id: Some(self.meta_id.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -39,14 +39,21 @@ lazy_static = "1.4"
|
||||
libc = "0.2"
|
||||
num_cpus = "1.13"
|
||||
pin-utils = "0.1.0"
|
||||
slab = "0.4"
|
||||
parking_lot = "0.12"
|
||||
|
||||
# Allocator
|
||||
arrayvec = { version = "0.7.0" }
|
||||
futures-timer = "3.0.2"
|
||||
once_cell = "1.4.0"
|
||||
tracing = "0.1.19"
|
||||
crossbeam-queue = "0.3.0"
|
||||
hdrhistogram = "7.5"
|
||||
|
||||
# Stats & Tracing
|
||||
tracing = "0.1"
|
||||
|
||||
# Supervision trees
|
||||
sharded-slab = "0.1"
|
||||
thread_local = "1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
async-std = "1.10.0"
|
||||
|
@ -32,6 +32,7 @@ pub mod manage;
|
||||
pub mod placement;
|
||||
pub mod pool;
|
||||
pub mod run;
|
||||
mod supervision;
|
||||
mod thread_manager;
|
||||
mod worker;
|
||||
|
||||
@ -39,4 +40,6 @@ mod worker;
|
||||
/// Prelude of Bastion Executor
|
||||
pub mod prelude {
|
||||
pub use crate::pool::*;
|
||||
pub use crate::supervision::SupervisionRegistry;
|
||||
pub use lightproc::GroupId;
|
||||
}
|
||||
|
@ -8,11 +8,13 @@
|
||||
//! [`Worker`]: crate::run_queue::Worker
|
||||
|
||||
use crate::run::block;
|
||||
use crate::supervision::SupervisionRegistry;
|
||||
use crate::thread_manager::{DynamicRunner, ThreadManager};
|
||||
use crate::worker::{Sleeper, WorkerThread};
|
||||
use crossbeam_deque::{Injector, Stealer};
|
||||
use lightproc::lightproc::LightProc;
|
||||
use lightproc::recoverable_handle::RecoverableHandle;
|
||||
use lightproc::GroupId;
|
||||
use std::cell::Cell;
|
||||
use std::future::Future;
|
||||
use std::iter::Iterator;
|
||||
@ -20,6 +22,9 @@ use std::marker::PhantomData;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tracing::field::FieldSet;
|
||||
use tracing::metadata::Kind;
|
||||
use tracing::{Instrument, Level, Span};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Spooler<'a> {
|
||||
@ -45,12 +50,19 @@ impl Spooler<'_> {
|
||||
/// Global executor
|
||||
pub struct Executor<'a> {
|
||||
spooler: Arc<Spooler<'a>>,
|
||||
root_cgroup: GroupId,
|
||||
}
|
||||
|
||||
impl<'a, 'executor: 'a> Executor<'executor> {
|
||||
pub fn new() -> Self {
|
||||
let root_cgroup = SupervisionRegistry::with(|registry| {
|
||||
let cgroup = registry.new_root_group();
|
||||
registry.set_current(&cgroup);
|
||||
cgroup
|
||||
});
|
||||
Executor {
|
||||
spooler: Arc::new(Spooler::new()),
|
||||
root_cgroup,
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,22 +106,75 @@ impl<'a, 'executor: 'a> Executor<'executor> {
|
||||
/// );
|
||||
/// # }
|
||||
/// ```
|
||||
#[track_caller]
|
||||
pub fn spawn<F, R>(&self, future: F) -> RecoverableHandle<R>
|
||||
where
|
||||
F: Future<Output = R> + Send + 'a,
|
||||
R: Send + 'a,
|
||||
{
|
||||
let (task, handle) = LightProc::recoverable(future, self.schedule());
|
||||
let location = std::panic::Location::caller();
|
||||
let cgroup = SupervisionRegistry::current();
|
||||
let id = cgroup.as_ref().map(|id| id.into_u64()).unwrap_or(0);
|
||||
let span = tracing::trace_span!(
|
||||
target: "executor::task",
|
||||
"runtime.spawn",
|
||||
loc.file = location.file(),
|
||||
loc.line = location.line(),
|
||||
loc.col = location.column(),
|
||||
kind = "global",
|
||||
cgroup = id,
|
||||
);
|
||||
|
||||
let (task, handle) = LightProc::recoverable(future, self.schedule(), span, cgroup);
|
||||
tracing::trace!("spawning sendable task");
|
||||
task.schedule();
|
||||
handle
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn spawn_local<F, R>(&self, future: F) -> RecoverableHandle<R>
|
||||
where
|
||||
F: Future<Output = R> + 'a,
|
||||
R: Send + 'a,
|
||||
{
|
||||
let (task, handle) = LightProc::recoverable(future, schedule_local());
|
||||
let location = std::panic::Location::caller();
|
||||
let cgroup = SupervisionRegistry::current();
|
||||
let id = cgroup.as_ref().map(|id| id.into_u64()).unwrap_or(0);
|
||||
let span = tracing::trace_span!(
|
||||
target: "executor::task",
|
||||
"runtime.spawn",
|
||||
loc.file = location.file(),
|
||||
loc.line = location.line(),
|
||||
loc.col = location.column(),
|
||||
kind = "local",
|
||||
cgroup = id,
|
||||
);
|
||||
|
||||
let (task, handle) = LightProc::recoverable(future, schedule_local(), span, cgroup);
|
||||
tracing::trace!("spawning sendable task");
|
||||
task.schedule();
|
||||
handle
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn spawn_local_cgroup<F, R>(&self, future: F, cgroup: GroupId) -> RecoverableHandle<R>
|
||||
where
|
||||
F: Future<Output = R> + 'a,
|
||||
R: Send + 'a,
|
||||
{
|
||||
let location = std::panic::Location::caller();
|
||||
let span = tracing::trace_span!(
|
||||
target: "executor::task",
|
||||
"runtime.spawn",
|
||||
loc.file = location.file(),
|
||||
loc.line = location.line(),
|
||||
loc.col = location.column(),
|
||||
kind = "local",
|
||||
cgroup = cgroup.into_u64(),
|
||||
);
|
||||
|
||||
let (task, handle) = LightProc::recoverable(future, schedule_local(), span, Some(cgroup));
|
||||
tracing::trace!("spawning sendable task");
|
||||
task.schedule();
|
||||
handle
|
||||
}
|
||||
|
179
runtime/executor/src/supervision.rs
Normal file
179
runtime/executor/src/supervision.rs
Normal file
@ -0,0 +1,179 @@
|
||||
use lightproc::GroupId;
|
||||
use once_cell::sync::OnceCell;
|
||||
use sharded_slab::pool::Ref;
|
||||
use sharded_slab::{Clear, Pool};
|
||||
use std::borrow::Borrow;
|
||||
use std::cell;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::atomic::{fence, AtomicUsize, Ordering};
|
||||
use thread_local::ThreadLocal;
|
||||
|
||||
static REGISTRY: OnceCell<SupervisionRegistry> = OnceCell::new();
|
||||
|
||||
fn id_to_idx(id: &GroupId) -> usize {
|
||||
(id.into_u64() as usize).wrapping_sub(1)
|
||||
}
|
||||
|
||||
fn idx_to_id(idx: usize) -> GroupId {
|
||||
GroupId::from_u64(idx.wrapping_add(1) as u64)
|
||||
}
|
||||
|
||||
pub struct SupervisionRegistry {
|
||||
groups: Pool<GroupInner>,
|
||||
// TODO: would this be better as the full stack?
|
||||
current: ThreadLocal<RefCell<GroupId>>,
|
||||
}
|
||||
|
||||
impl SupervisionRegistry {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
groups: Pool::new(),
|
||||
current: ThreadLocal::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with<T>(f: impl FnOnce(&Self) -> T) -> T {
|
||||
let this = REGISTRY.get_or_init(SupervisionRegistry::new);
|
||||
f(&this)
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, id: &GroupId) -> Option<Ref<'_, GroupInner>> {
|
||||
self.groups.get(id_to_idx(id))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn current_ref(&self) -> Option<cell::Ref<GroupId>> {
|
||||
self.current.get().map(|c| c.borrow())
|
||||
}
|
||||
|
||||
pub fn current() -> Option<GroupId> {
|
||||
Self::with(|this| this.current_ref().map(|id| this.clone_group(&id)))
|
||||
}
|
||||
|
||||
pub(crate) fn set_current(&self, id: &GroupId) {
|
||||
self.current.get_or(|| RefCell::new(id.clone()));
|
||||
}
|
||||
|
||||
pub fn new_root_group(&self) -> GroupId {
|
||||
self.new_group_inner(None)
|
||||
}
|
||||
|
||||
pub fn new_group(&self) -> GroupId {
|
||||
let parent = self.current_ref().map(|id| self.clone_group(&id));
|
||||
self.new_group_inner(parent)
|
||||
}
|
||||
|
||||
fn new_group_inner(&self, parent: Option<GroupId>) -> GroupId {
|
||||
tracing::trace_span!(
|
||||
target: "executor::supervision",
|
||||
"new_group"
|
||||
);
|
||||
let parent_id = parent.as_ref().map(|id| id.into_non_zero_u64());
|
||||
let idx = self
|
||||
.groups
|
||||
.create_with(|group| {
|
||||
group.parent = parent;
|
||||
|
||||
let ref_cnt = group.ref_count.get_mut();
|
||||
debug_assert_eq!(0, *ref_cnt);
|
||||
*ref_cnt = 1;
|
||||
})
|
||||
.expect("Failed to allocate a new group");
|
||||
|
||||
let id = idx_to_id(idx);
|
||||
tracing::trace!(
|
||||
target: "executor::supervision",
|
||||
parent = parent_id,
|
||||
id = id.into_non_zero_u64(),
|
||||
"process group created"
|
||||
);
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
fn clone_group(&self, id: &GroupId) -> GroupId {
|
||||
tracing::trace!(
|
||||
target: "executor::supervision",
|
||||
id = id.into_u64(),
|
||||
"cloning process group"
|
||||
);
|
||||
let group = self
|
||||
.get(&id)
|
||||
.unwrap_or_else(|| panic!("tried to clone group {:?}, but no such group exists!", id));
|
||||
|
||||
let ref_cnt = group.ref_count.fetch_add(1, Ordering::Relaxed);
|
||||
assert_ne!(
|
||||
0, ref_cnt,
|
||||
"tried cloning group {:?} that was already closed",
|
||||
id
|
||||
);
|
||||
id.clone()
|
||||
}
|
||||
|
||||
/// Try to close the group with the given ID
|
||||
///
|
||||
/// If this method returns `true` the Group was closed. Otherwise there are still references
|
||||
/// left open.
|
||||
fn try_close(&self, id: GroupId) -> bool {
|
||||
tracing::trace!(
|
||||
target: "executor::supervision",
|
||||
id = id.into_u64(),
|
||||
"dropping process group"
|
||||
);
|
||||
let group = match self.get(&id) {
|
||||
None if std::thread::panicking() => return false,
|
||||
None => panic!("tried to drop a ref to {:?}, but no such group exists!", id),
|
||||
Some(group) => group,
|
||||
};
|
||||
|
||||
// Reference count *decreases* on the other hand must observe strong ordering — when
|
||||
let remaining = group.ref_count.fetch_sub(1, Ordering::Release);
|
||||
if !std::thread::panicking() {
|
||||
assert!(remaining < usize::MAX, "group reference count overflow");
|
||||
}
|
||||
if remaining > 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate a compiler fence making sure that all other calls to `try_close` are finished
|
||||
// before the one that returns `true`.
|
||||
fence(Ordering::Acquire);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct GroupInner {
|
||||
parent: Option<GroupId>,
|
||||
ref_count: AtomicUsize,
|
||||
}
|
||||
|
||||
impl GroupInner {
|
||||
#[inline]
|
||||
/// Increment the reference count of this group and return the previous value
|
||||
fn increment_refcnt(&self) -> usize {
|
||||
// Reference count increases don't need strong ordering. The increments can be done in
|
||||
// any order as long as they *do* happen.
|
||||
self.ref_count.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GroupInner {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
parent: None,
|
||||
ref_count: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clear for GroupInner {
|
||||
fn clear(&mut self) {
|
||||
// A group is always alive as long as at least one of its children is alive. So each
|
||||
// Group holds a reference to its parent if it has one. If a group is being deleted this
|
||||
// reference must be closed too, i.e. the parent reference count reduced by one.
|
||||
if let Some(parent) = self.parent.take() {
|
||||
SupervisionRegistry::with(|reg| reg.try_close(parent));
|
||||
}
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ crossbeam-utils = "0.8"
|
||||
pin-utils = "0.1.0"
|
||||
bitfield = "0.13.2"
|
||||
bitflags = "1.3.2"
|
||||
tracing = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
crossbeam = "0.8"
|
||||
|
@ -16,9 +16,9 @@
|
||||
#![forbid(missing_docs)]
|
||||
#![forbid(missing_debug_implementations)]
|
||||
#![forbid(unused_import_braces)]
|
||||
#![forbid(unused_imports)]
|
||||
#![warn(unused_imports)]
|
||||
#![forbid(unused_must_use)]
|
||||
#![forbid(unused_variables)]
|
||||
//TODO: reenable #![forbid(unused_variables)]
|
||||
|
||||
mod catch_unwind;
|
||||
mod layout_helpers;
|
||||
@ -33,6 +33,8 @@ pub mod lightproc;
|
||||
pub mod proc_handle;
|
||||
pub mod recoverable_handle;
|
||||
|
||||
pub use proc_data::GroupId;
|
||||
|
||||
/// The lightproc prelude.
|
||||
///
|
||||
/// The prelude re-exports lightproc structs and handles from this crate.
|
||||
|
@ -31,11 +31,13 @@ use crate::proc_ext::ProcFutureExt;
|
||||
use crate::proc_handle::ProcHandle;
|
||||
use crate::raw_proc::RawProc;
|
||||
use crate::recoverable_handle::RecoverableHandle;
|
||||
use crate::GroupId;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::future::Future;
|
||||
use std::mem;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::panic::AssertUnwindSafe;
|
||||
use std::ptr::NonNull;
|
||||
use tracing::Span;
|
||||
|
||||
/// Shared functionality for both Send and !Send LightProc
|
||||
pub struct LightProc {
|
||||
@ -45,8 +47,8 @@ pub struct LightProc {
|
||||
|
||||
// LightProc is both Sync and Send because it explicitly handles synchronization internally:
|
||||
// The state of a `LightProc` is only modified atomically guaranteeing a consistent view from all
|
||||
// threads. Existing handles are atomically reference counted so the proc itself will not be dropped
|
||||
// until all pointers to it are themselves dropped.
|
||||
// threads. Existing wakers (and the proc_handle) are atomically reference counted so the proc
|
||||
// itself will not be dropped until all pointers to it are themselves dropped.
|
||||
// However, if the future or result inside the LightProc is !Send the executor must ensure that
|
||||
// the `schedule` function does not move the LightProc to a different thread.
|
||||
unsafe impl Send for LightProc {}
|
||||
@ -76,14 +78,19 @@ impl LightProc {
|
||||
/// println!("future panicked!: {}", &reason);
|
||||
/// });
|
||||
/// ```
|
||||
pub fn recoverable<'a, F, R, S>(future: F, schedule: S) -> (Self, RecoverableHandle<R>)
|
||||
pub fn recoverable<'a, F, R, S>(
|
||||
future: F,
|
||||
schedule: S,
|
||||
span: Span,
|
||||
cgroup: Option<GroupId>,
|
||||
) -> (Self, RecoverableHandle<R>)
|
||||
where
|
||||
F: Future<Output = R> + 'a,
|
||||
R: 'a,
|
||||
S: Fn(LightProc) + 'a,
|
||||
{
|
||||
let recovery_future = AssertUnwindSafe(future).catch_unwind();
|
||||
let (proc, handle) = Self::build(recovery_future, schedule);
|
||||
let (proc, handle) = Self::build(recovery_future, schedule, span, cgroup);
|
||||
(proc, RecoverableHandle::new(handle))
|
||||
}
|
||||
|
||||
@ -92,6 +99,7 @@ impl LightProc {
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use tracing::Span;
|
||||
/// # use lightproc::prelude::*;
|
||||
/// #
|
||||
/// # // ... future that does work
|
||||
@ -113,15 +121,22 @@ impl LightProc {
|
||||
/// let standard = LightProc::build(
|
||||
/// future,
|
||||
/// schedule_function,
|
||||
/// Span::current(),
|
||||
/// None,
|
||||
/// );
|
||||
/// ```
|
||||
pub fn build<'a, F, R, S>(future: F, schedule: S) -> (Self, ProcHandle<R>)
|
||||
pub fn build<'a, F, R, S>(
|
||||
future: F,
|
||||
schedule: S,
|
||||
span: Span,
|
||||
cgroup: Option<GroupId>,
|
||||
) -> (Self, ProcHandle<R>)
|
||||
where
|
||||
F: Future<Output = R> + 'a,
|
||||
R: 'a,
|
||||
S: Fn(LightProc) + 'a,
|
||||
{
|
||||
let raw_proc = RawProc::allocate(future, schedule);
|
||||
let raw_proc = RawProc::allocate(future, schedule, span, cgroup);
|
||||
let proc = LightProc { raw_proc };
|
||||
let handle = ProcHandle::new(raw_proc);
|
||||
(proc, handle)
|
||||
@ -130,9 +145,9 @@ impl LightProc {
|
||||
///
|
||||
/// Schedule the lightweight process with passed `schedule` function at the build time.
|
||||
pub fn schedule(self) {
|
||||
let ptr = self.raw_proc.as_ptr();
|
||||
let this = ManuallyDrop::new(self);
|
||||
let ptr = this.raw_proc.as_ptr();
|
||||
let pdata = ptr as *const ProcData;
|
||||
mem::forget(self);
|
||||
|
||||
unsafe {
|
||||
((*pdata).vtable.schedule)(ptr);
|
||||
@ -144,9 +159,9 @@ impl LightProc {
|
||||
/// "Running" a lightproc means ticking it once and if it doesn't complete
|
||||
/// immediately re-scheduling it as soon as it's Waker wakes it back up.
|
||||
pub fn run(self) {
|
||||
let ptr = self.raw_proc.as_ptr();
|
||||
let this = ManuallyDrop::new(self);
|
||||
let ptr = this.raw_proc.as_ptr();
|
||||
let pdata = ptr as *const ProcData;
|
||||
mem::forget(self);
|
||||
|
||||
unsafe {
|
||||
((*pdata).vtable.tick)(ptr);
|
||||
|
@ -3,8 +3,49 @@ use crate::state::*;
|
||||
use crossbeam_utils::Backoff;
|
||||
use std::cell::Cell;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::num::NonZeroU64;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::task::Waker;
|
||||
use tracing::Span;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[repr(transparent)]
|
||||
/// Opaque id of the group this proc belongs to
|
||||
pub struct GroupId(NonZeroU64);
|
||||
|
||||
impl GroupId {
|
||||
/// Construct an ID from an u64
|
||||
///
|
||||
/// # Panics
|
||||
/// - if the provided `u64` is `0`.
|
||||
pub fn from_u64(i: u64) -> Self {
|
||||
Self(NonZeroU64::new(i).expect("group id must be > 0"))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Construct an ID from a NonZeroU64
|
||||
///
|
||||
/// This method can't fail
|
||||
pub const fn from_non_zero_u64(i: NonZeroU64) -> Self {
|
||||
Self(i)
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
//noinspection RsSelfConvention
|
||||
#[inline]
|
||||
/// Convert a GroupId into a u64
|
||||
pub const fn into_u64(&self) -> u64 {
|
||||
self.0.get()
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
//noinspection RsSelfConvention
|
||||
#[inline]
|
||||
/// Convert a GroupId into a NonZeroU64
|
||||
pub const fn into_non_zero_u64(&self) -> NonZeroU64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// The pdata of a proc.
|
||||
///
|
||||
@ -25,6 +66,17 @@ pub(crate) struct ProcData {
|
||||
/// In addition to the actual waker virtual table, it also contains pointers to several other
|
||||
/// methods necessary for bookkeeping the heap-allocated proc.
|
||||
pub(crate) vtable: &'static ProcVTable,
|
||||
|
||||
/// The span assigned to this process.
|
||||
///
|
||||
/// A lightproc has a tracing span associated that allow recording occurances of vtable calls
|
||||
/// for this process.
|
||||
pub(crate) span: Span,
|
||||
|
||||
/// Control group assigned to this process.
|
||||
///
|
||||
/// The control group links this process to its supervision tree
|
||||
pub(crate) cgroup: Option<GroupId>,
|
||||
}
|
||||
|
||||
impl ProcData {
|
||||
@ -61,7 +113,7 @@ impl ProcData {
|
||||
}
|
||||
}
|
||||
|
||||
/// Notifies the proc blocked on the proc.
|
||||
/// Notifies the proc blocked on this proc, if any.
|
||||
///
|
||||
/// If there is a registered waker, it will be removed from the pdata and woken.
|
||||
#[inline]
|
||||
|
@ -6,6 +6,7 @@ use crate::state::*;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::future::Future;
|
||||
use std::marker::{PhantomData, Unpin};
|
||||
use std::mem::MaybeUninit;
|
||||
use std::pin::Pin;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::atomic::Ordering;
|
||||
@ -22,7 +23,9 @@ pub struct ProcHandle<R> {
|
||||
pub(crate) raw_proc: NonNull<()>,
|
||||
|
||||
/// A marker capturing the generic type `R`.
|
||||
pub(crate) result: PhantomData<R>,
|
||||
// TODO: Instead of writing the future output to the RawProc on heap, put it in the handle
|
||||
// (if still available).
|
||||
pub(crate) marker: PhantomData<R>,
|
||||
}
|
||||
|
||||
unsafe impl<R: Send> Send for ProcHandle<R> {}
|
||||
@ -34,7 +37,7 @@ impl<R> ProcHandle<R> {
|
||||
pub(crate) fn new(raw_proc: NonNull<()>) -> Self {
|
||||
Self {
|
||||
raw_proc,
|
||||
result: PhantomData,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +51,13 @@ impl<R> ProcHandle<R> {
|
||||
let pdata = ptr as *const ProcData;
|
||||
|
||||
unsafe {
|
||||
let id = (&(*pdata).span).id().map(|id| id.into_u64()).unwrap_or(0);
|
||||
tracing::trace!(
|
||||
target: "executor::handle",
|
||||
op = "handle.cancel",
|
||||
task.id = id,
|
||||
);
|
||||
|
||||
let mut state = (*pdata).state.load(Ordering::Acquire);
|
||||
|
||||
loop {
|
||||
@ -189,6 +199,14 @@ impl<R> Drop for ProcHandle<R> {
|
||||
let mut output = None;
|
||||
|
||||
unsafe {
|
||||
// Record dropping the handle for this task
|
||||
let id = (&(*pdata).span).id().map(|id| id.into_u64()).unwrap_or(0);
|
||||
tracing::trace!(
|
||||
target: "executor::handle",
|
||||
op = "handle.drop",
|
||||
task.id = id,
|
||||
);
|
||||
|
||||
// Optimistically assume the `ProcHandle` is being dropped just after creating the
|
||||
// proc. This is a common case so if the handle is not used, the overhead of it is only
|
||||
// one compare-exchange operation.
|
||||
|
@ -15,17 +15,30 @@ use std::pin::Pin;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use crate::GroupId;
|
||||
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
|
||||
use tracing::Span;
|
||||
|
||||
/// Raw pointers to the fields of a proc.
|
||||
// TODO: Make generic over the Allocator used!
|
||||
// TODO: The actual layout stored could be expressed as a struct w/ union. Maybe do that?
|
||||
pub(crate) struct RawProc<'a, F, R, S> {
|
||||
pub(crate) pdata: *const ProcData,
|
||||
pub(crate) schedule: *const S,
|
||||
pub(crate) future: *mut F,
|
||||
// TODO: Replace with `*mut MaybeUninit`? And also, store the result in the handle if that's
|
||||
// still available, instead of copying it to the heap.
|
||||
pub(crate) output: *mut R,
|
||||
|
||||
// Make the lifetime 'a of the future invariant
|
||||
_marker: PhantomData<&'a ()>,
|
||||
// TODO: We should link a proc to a process group for scheduling and tracing
|
||||
// - sub-tasks should start in the same group by default
|
||||
// - that data needs to be available when calling `spawn` and to decide which task to run.
|
||||
// So there must be a thread-local reference to it that's managed by the executor, and
|
||||
// updated when a new task is being polled.
|
||||
// Additionally `schedule` must have a reference to it to be able to push to the right
|
||||
// queue? The `schedule` fn could just come from the group instead.
|
||||
}
|
||||
|
||||
impl<'a, F, R, S> RawProc<'a, F, R, S>
|
||||
@ -37,7 +50,12 @@ where
|
||||
/// Allocates a proc with the given `future` and `schedule` function.
|
||||
///
|
||||
/// It is assumed there are initially only the `LightProc` reference and the `ProcHandle`.
|
||||
pub(crate) fn allocate(future: F, schedule: S) -> NonNull<()> {
|
||||
pub(crate) fn allocate(
|
||||
future: F,
|
||||
schedule: S,
|
||||
span: Span,
|
||||
cgroup: Option<GroupId>,
|
||||
) -> NonNull<()> {
|
||||
// Compute the layout of the proc for allocation. Abort if the computation fails.
|
||||
let proc_layout = Self::proc_layout();
|
||||
|
||||
@ -70,6 +88,8 @@ where
|
||||
destroy: Self::destroy,
|
||||
tick: Self::tick,
|
||||
},
|
||||
span,
|
||||
cgroup,
|
||||
});
|
||||
|
||||
// Write the schedule function as the third field of the proc.
|
||||
@ -128,6 +148,15 @@ where
|
||||
/// Wakes a waker.
|
||||
unsafe fn wake(ptr: *const ()) {
|
||||
let raw = Self::from_ptr(ptr);
|
||||
let id = (&(*raw.pdata).span)
|
||||
.id()
|
||||
.map(|id| id.into_u64())
|
||||
.unwrap_or(0);
|
||||
tracing::trace!(
|
||||
target: "executor::waker",
|
||||
op = "waker.wake",
|
||||
task.id = id,
|
||||
);
|
||||
|
||||
let mut state = (*raw.pdata).state.load(Ordering::Acquire);
|
||||
|
||||
@ -191,6 +220,15 @@ where
|
||||
/// Wakes a waker by reference.
|
||||
unsafe fn wake_by_ref(ptr: *const ()) {
|
||||
let raw = Self::from_ptr(ptr);
|
||||
let id = (&(*raw.pdata).span)
|
||||
.id()
|
||||
.map(|id| id.into_u64())
|
||||
.unwrap_or(0);
|
||||
tracing::trace!(
|
||||
target: "executor::waker",
|
||||
op = "waker.wake_by_ref",
|
||||
task.id = id,
|
||||
);
|
||||
|
||||
let mut state = (*raw.pdata).state.load(Ordering::Acquire);
|
||||
|
||||
@ -250,6 +288,16 @@ where
|
||||
/// Clones a waker.
|
||||
unsafe fn clone_waker(ptr: *const ()) -> RawWaker {
|
||||
let raw = Self::from_ptr(ptr);
|
||||
let id = (&(*raw.pdata).span)
|
||||
.id()
|
||||
.map(|id| id.into_u64())
|
||||
.unwrap_or(0);
|
||||
tracing::trace!(
|
||||
target: "executor::waker",
|
||||
op = "waker.clone",
|
||||
task.id = id,
|
||||
);
|
||||
|
||||
let raw_waker = &(*raw.pdata).vtable.raw_waker;
|
||||
|
||||
// Increment the reference count. With any kind of reference-counted data structure,
|
||||
@ -271,6 +319,15 @@ where
|
||||
#[inline]
|
||||
unsafe fn decrement(ptr: *const ()) {
|
||||
let raw = Self::from_ptr(ptr);
|
||||
let id = (&(*raw.pdata).span)
|
||||
.id()
|
||||
.map(|id| id.into_u64())
|
||||
.unwrap_or(0);
|
||||
tracing::trace!(
|
||||
target: "executor::waker",
|
||||
op = "waker.drop",
|
||||
task.id = id,
|
||||
);
|
||||
|
||||
// Decrement the reference count.
|
||||
let new = (*raw.pdata).state.fetch_sub(1, Ordering::AcqRel);
|
||||
@ -310,10 +367,11 @@ where
|
||||
raw.output as *const ()
|
||||
}
|
||||
|
||||
/// Cleans up proc's resources and deallocates it.
|
||||
/// Cleans up the procs resources and deallocates the associated memory.
|
||||
///
|
||||
/// If the proc has not been closed, then its future or the output will be dropped. The
|
||||
/// schedule function gets dropped too.
|
||||
/// The future or output stored will *not* be dropped, but its memory will be freed. Callers
|
||||
/// must ensure that they are correctly dropped beforehand if either of those is still alive to
|
||||
/// prevent use-after-free.
|
||||
#[inline]
|
||||
unsafe fn destroy(ptr: *const ()) {
|
||||
let raw = Self::from_ptr(ptr);
|
||||
@ -323,6 +381,9 @@ where
|
||||
// Drop the schedule function.
|
||||
(raw.schedule as *mut S).drop_in_place();
|
||||
|
||||
// Drop the proc data containing the associated Span
|
||||
(raw.pdata as *mut ProcData).drop_in_place();
|
||||
|
||||
// Finally, deallocate the memory reserved by the proc.
|
||||
alloc::dealloc(ptr as *mut u8, proc_layout.layout);
|
||||
}
|
||||
@ -332,9 +393,11 @@ where
|
||||
/// Ticking will call `poll` once and re-schedule the task if it returns `Poll::Pending`. If
|
||||
/// polling its future panics, the proc will be closed and the panic propagated into the caller.
|
||||
unsafe fn tick(ptr: *const ()) {
|
||||
let raw = Self::from_ptr(ptr);
|
||||
let mut raw = Self::from_ptr(ptr);
|
||||
// Enter the span associated with the process to track execution time if enabled.
|
||||
let _guard = (&(*raw.pdata).span).enter();
|
||||
|
||||
// Create a context from the raw proc pointer and the vtable inside the its pdata.
|
||||
// Create a context from the raw proc pointer and the vtable inside its pdata.
|
||||
let waker = ManuallyDrop::new(Waker::from_raw(RawWaker::new(
|
||||
ptr,
|
||||
&(*raw.pdata).vtable.raw_waker,
|
||||
@ -380,9 +443,9 @@ where
|
||||
|
||||
// Poll the inner future, but surround it with a guard that closes the proc in case polling
|
||||
// panics.
|
||||
let guard = Guard(raw);
|
||||
let poll = <F as Future>::poll(Pin::new_unchecked(&mut *raw.future), cx);
|
||||
mem::forget(guard);
|
||||
let drop_guard = Guard(&mut raw);
|
||||
let poll = <F as Future>::poll(drop_guard.pin_future(), cx);
|
||||
drop_guard.disable();
|
||||
|
||||
match poll {
|
||||
Poll::Ready(out) => {
|
||||
@ -497,21 +560,43 @@ impl<'a, F, R, S> Clone for RawProc<'a, F, R, S> {
|
||||
}
|
||||
impl<'a, F, R, S> Copy for RawProc<'a, F, R, S> {}
|
||||
|
||||
#[repr(transparent)]
|
||||
/// A guard that closes the proc if polling its future panics.
|
||||
struct Guard<'a, F, R, S>(RawProc<'a, F, R, S>)
|
||||
struct Guard<'guard, 'a, F, R, S>(&'guard mut RawProc<'a, F, R, S>)
|
||||
where
|
||||
F: Future<Output = R> + 'a,
|
||||
R: 'a,
|
||||
S: Fn(LightProc) + 'a;
|
||||
|
||||
impl<'a, F, R, S> Drop for Guard<'a, F, R, S>
|
||||
impl<'guard, 'a, F, R, S> Guard<'guard, 'a, F, R, S>
|
||||
where
|
||||
F: Future<Output = R> + 'a,
|
||||
R: 'a,
|
||||
S: Fn(LightProc) + 'a,
|
||||
{
|
||||
#[inline(always)]
|
||||
/// Disable the guard again.
|
||||
///
|
||||
/// This does essentially nothing but prevents the Drop implementation from being called
|
||||
fn disable(self) {
|
||||
// Put `self` in a ManuallyDrop telling the compiler to explicitly not call Drop::drop
|
||||
let _ = ManuallyDrop::new(self);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn pin_future(&self) -> Pin<&mut F> {
|
||||
Pin::new_unchecked(&mut *self.0.future)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F, R, S> Drop for Guard<'_, 'a, F, R, S>
|
||||
where
|
||||
F: Future<Output = R> + 'a,
|
||||
R: 'a,
|
||||
S: Fn(LightProc) + 'a,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
let raw = self.0;
|
||||
let raw = &self.0;
|
||||
let ptr = raw.pdata as *const ();
|
||||
|
||||
unsafe {
|
||||
|
8
test/duplicate-users.toml
Normal file
8
test/duplicate-users.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[UniqueUser]
|
||||
roles = ["foorole", "barrole"]
|
||||
|
||||
[DuplicateUser]
|
||||
roles = ["somerole"]
|
||||
|
||||
[DuplicateUser]
|
||||
roles = ["different", "roles"]
|
Loading…
Reference in New Issue
Block a user