From 6a86f2265ac7b316e3f6dad92d639ea8d6f18a52 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sat, 3 Jun 2023 18:33:27 -0400 Subject: [PATCH] json api work --- Cargo.lock | 42 ++++ veilid-core/Cargo.toml | 1 + veilid-core/proto/veilid.capnp | 14 +- veilid-core/src/crypto/mod.rs | 3 +- veilid-core/src/lib.rs | 1 + veilid-core/src/rpc_processor/coders/mod.rs | 2 + .../rpc_processor/coders/operations/answer.rs | 15 ++ .../rpc_processor/coders/operations/mod.rs | 20 +- .../operations/operation_cancel_tunnel.rs | 2 + .../operations/operation_complete_tunnel.rs | 2 + .../operations/operation_start_tunnel.rs | 2 + .../coders/operations/question.rs | 15 ++ veilid-core/src/rpc_processor/mod.rs | 13 +- veilid-core/src/veilid_api/api.rs | 3 + veilid-core/src/veilid_api/error.rs | 6 +- .../src/veilid_api/json_api/crypto_system.rs | 66 ++++++ veilid-core/src/veilid_api/json_api/mod.rs | 203 ++++++++++++++++++ .../veilid_api/json_api/routing_context.rs | 52 +++++ .../src/veilid_api/json_api/table_db.rs | 26 +++ veilid-core/src/veilid_api/mod.rs | 2 + .../serialize_range_set_blaze.rs | 10 +- .../src/veilid_api/types/aligned_u64.rs | 11 +- .../src/veilid_api/types/app_message_call.rs | 55 ++++- .../types/dht/dht_record_descriptor.rs | 4 + .../src/veilid_api/types/dht/schema/dflt.rs | 1 + .../src/veilid_api/types/dht/schema/mod.rs | 1 + .../src/veilid_api/types/dht/schema/smpl.rs | 3 + .../src/veilid_api/types/dht/value_data.rs | 12 ++ .../types/dht/value_subkey_range_set.rs | 7 +- veilid-core/src/veilid_api/types/fourcc.rs | 16 ++ veilid-core/src/veilid_api/types/mod.rs | 2 + veilid-core/src/veilid_api/types/safety.rs | 5 + veilid-core/src/veilid_api/types/stats.rs | 20 +- veilid-core/src/veilid_api/types/tunnel.rs | 34 ++- .../src/veilid_api/types/veilid_log.rs | 12 +- .../src/veilid_api/types/veilid_state.rs | 81 ++++++- veilid-core/src/veilid_config.rs | 22 +- veilid-server/src/cmdline.rs | 8 + veilid-server/src/main.rs | 19 ++ 39 files changed, 751 insertions(+), 62 deletions(-) create mode 100644 veilid-core/src/veilid_api/json_api/crypto_system.rs create mode 100644 veilid-core/src/veilid_api/json_api/mod.rs create mode 100644 veilid-core/src/veilid_api/json_api/routing_context.rs create mode 100644 veilid-core/src/veilid_api/json_api/table_db.rs diff --git a/Cargo.lock b/Cargo.lock index 047c015a..9866cef7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1678,6 +1678,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + [[package]] name = "ed25519" version = "1.5.3" @@ -4689,6 +4695,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schemars" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -4854,6 +4884,17 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_json" version = "1.0.96" @@ -6212,6 +6253,7 @@ dependencies = [ "rusqlite", "rustls 0.19.1", "rustls-pemfile 0.2.1", + "schemars", "secrecy", "send_wrapper 0.6.0", "serde", diff --git a/veilid-core/Cargo.toml b/veilid-core/Cargo.toml index 6eb99b12..e73f3db9 100644 --- a/veilid-core/Cargo.toml +++ b/veilid-core/Cargo.toml @@ -72,6 +72,7 @@ data-encoding = { version = "^2" } weak-table = "0.3.2" range-set-blaze = "0.1.5" argon2 = "0.5.0" +schemars = "0.8.12" # Dependencies for native builds only # Linux, Windows, Mac, iOS, Android diff --git a/veilid-core/proto/veilid.capnp b/veilid-core/proto/veilid.capnp index 2fa813b6..7e0ba4fb 100644 --- a/veilid-core/proto/veilid.capnp +++ b/veilid-core/proto/veilid.capnp @@ -500,9 +500,10 @@ struct Question @0xd8510bc33492ef70 { findBlockQ @9 :OperationFindBlockQ; # Tunnel operations - startTunnelQ @10 :OperationStartTunnelQ; - completeTunnelQ @11 :OperationCompleteTunnelQ; - cancelTunnelQ @12 :OperationCancelTunnelQ; + # #[cfg(feature="unstable-tunnels")] + # startTunnelQ @10 :OperationStartTunnelQ; + # completeTunnelQ @11 :OperationCompleteTunnelQ; + # cancelTunnelQ @12 :OperationCancelTunnelQ; } } @@ -537,9 +538,10 @@ struct Answer @0xacacb8b6988c1058 { findBlockA @7 :OperationFindBlockA; # Tunnel operations - startTunnelA @8 :OperationStartTunnelA; - completeTunnelA @9 :OperationCompleteTunnelA; - cancelTunnelA @10 :OperationCancelTunnelA; + # #[cfg(feature="unstable-tunnels")] + # startTunnelA @8 :OperationStartTunnelA; + # completeTunnelA @9 :OperationCompleteTunnelA; + # cancelTunnelA @10 :OperationCancelTunnelA; } } diff --git a/veilid-core/src/crypto/mod.rs b/veilid-core/src/crypto/mod.rs index 822687eb..966633dd 100644 --- a/veilid-core/src/crypto/mod.rs +++ b/veilid-core/src/crypto/mod.rs @@ -25,11 +25,10 @@ pub use none::*; #[cfg(feature = "enable-crypto-vld0")] pub use vld0::*; -use crate::*; +use super::*; use core::convert::TryInto; use hashlink::linked_hash_map::Entry; use hashlink::LruCache; -use serde::{Deserialize, Serialize}; /// Handle to a particular cryptosystem pub type CryptoSystemVersion = Arc; diff --git a/veilid-core/src/lib.rs b/veilid-core/src/lib.rs index bca8a6fe..ff7a311d 100644 --- a/veilid-core/src/lib.rs +++ b/veilid-core/src/lib.rs @@ -47,6 +47,7 @@ use rkyv::{ Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize, }; type RkyvDefaultValidator<'t> = rkyv::validation::validators::DefaultValidator<'t>; +use schemars::{schema_for, JsonSchema}; use serde::*; pub mod veilid_capnp { diff --git a/veilid-core/src/rpc_processor/coders/mod.rs b/veilid-core/src/rpc_processor/coders/mod.rs index 34bc7913..4f76486a 100644 --- a/veilid-core/src/rpc_processor/coders/mod.rs +++ b/veilid-core/src/rpc_processor/coders/mod.rs @@ -22,6 +22,7 @@ mod signed_relayed_node_info; mod signed_value_data; mod signed_value_descriptor; mod socket_address; +#[cfg(feature = "unstable-tunnels")] mod tunnel; mod typed_key; mod typed_signature; @@ -50,6 +51,7 @@ pub use signed_relayed_node_info::*; pub use signed_value_data::*; pub use signed_value_descriptor::*; pub use socket_address::*; +#[cfg(feature = "unstable-tunnels")] pub use tunnel::*; pub use typed_key::*; pub use typed_signature::*; diff --git a/veilid-core/src/rpc_processor/coders/operations/answer.rs b/veilid-core/src/rpc_processor/coders/operations/answer.rs index 9f01da68..c1aeb4c4 100644 --- a/veilid-core/src/rpc_processor/coders/operations/answer.rs +++ b/veilid-core/src/rpc_processor/coders/operations/answer.rs @@ -39,8 +39,11 @@ pub enum RPCAnswerDetail { WatchValueA(RPCOperationWatchValueA), SupplyBlockA(RPCOperationSupplyBlockA), FindBlockA(RPCOperationFindBlockA), + #[cfg(feature = "unstable-tunnels")] StartTunnelA(RPCOperationStartTunnelA), + #[cfg(feature = "unstable-tunnels")] CompleteTunnelA(RPCOperationCompleteTunnelA), + #[cfg(feature = "unstable-tunnels")] CancelTunnelA(RPCOperationCancelTunnelA), } @@ -55,8 +58,11 @@ impl RPCAnswerDetail { RPCAnswerDetail::WatchValueA(_) => "WatchValueA", RPCAnswerDetail::SupplyBlockA(_) => "SupplyBlockA", RPCAnswerDetail::FindBlockA(_) => "FindBlockA", + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::StartTunnelA(_) => "StartTunnelA", + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::CompleteTunnelA(_) => "CompleteTunnelA", + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::CancelTunnelA(_) => "CancelTunnelA", } } @@ -70,8 +76,11 @@ impl RPCAnswerDetail { RPCAnswerDetail::WatchValueA(r) => r.validate(validate_context), RPCAnswerDetail::SupplyBlockA(r) => r.validate(validate_context), RPCAnswerDetail::FindBlockA(r) => r.validate(validate_context), + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::StartTunnelA(r) => r.validate(validate_context), + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::CompleteTunnelA(r) => r.validate(validate_context), + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::CancelTunnelA(r) => r.validate(validate_context), } } @@ -120,16 +129,19 @@ impl RPCAnswerDetail { let out = RPCOperationFindBlockA::decode(&op_reader)?; RPCAnswerDetail::FindBlockA(out) } + #[cfg(feature = "unstable-tunnels")] veilid_capnp::answer::detail::StartTunnelA(r) => { let op_reader = r.map_err(RPCError::protocol)?; let out = RPCOperationStartTunnelA::decode(&op_reader)?; RPCAnswerDetail::StartTunnelA(out) } + #[cfg(feature = "unstable-tunnels")] veilid_capnp::answer::detail::CompleteTunnelA(r) => { let op_reader = r.map_err(RPCError::protocol)?; let out = RPCOperationCompleteTunnelA::decode(&op_reader)?; RPCAnswerDetail::CompleteTunnelA(out) } + #[cfg(feature = "unstable-tunnels")] veilid_capnp::answer::detail::CancelTunnelA(r) => { let op_reader = r.map_err(RPCError::protocol)?; let out = RPCOperationCancelTunnelA::decode(&op_reader)?; @@ -155,12 +167,15 @@ impl RPCAnswerDetail { d.encode(&mut builder.reborrow().init_supply_block_a()) } RPCAnswerDetail::FindBlockA(d) => d.encode(&mut builder.reborrow().init_find_block_a()), + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::StartTunnelA(d) => { d.encode(&mut builder.reborrow().init_start_tunnel_a()) } + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::CompleteTunnelA(d) => { d.encode(&mut builder.reborrow().init_complete_tunnel_a()) } + #[cfg(feature = "unstable-tunnels")] RPCAnswerDetail::CancelTunnelA(d) => { d.encode(&mut builder.reborrow().init_cancel_tunnel_a()) } diff --git a/veilid-core/src/rpc_processor/coders/operations/mod.rs b/veilid-core/src/rpc_processor/coders/operations/mod.rs index 7caf0fb2..db390b9f 100644 --- a/veilid-core/src/rpc_processor/coders/operations/mod.rs +++ b/veilid-core/src/rpc_processor/coders/operations/mod.rs @@ -2,8 +2,6 @@ mod answer; mod operation; mod operation_app_call; mod operation_app_message; -mod operation_cancel_tunnel; -mod operation_complete_tunnel; mod operation_find_block; mod operation_find_node; mod operation_get_value; @@ -11,7 +9,6 @@ mod operation_return_receipt; mod operation_route; mod operation_set_value; mod operation_signal; -mod operation_start_tunnel; mod operation_status; mod operation_supply_block; mod operation_validate_dial_info; @@ -21,12 +18,17 @@ mod question; mod respond_to; mod statement; +#[cfg(feature = "unstable-tunnels")] +mod operation_cancel_tunnel; +#[cfg(feature = "unstable-tunnels")] +mod operation_complete_tunnel; +#[cfg(feature = "unstable-tunnels")] +mod operation_start_tunnel; + pub use answer::*; pub use operation::*; pub use operation_app_call::*; pub use operation_app_message::*; -pub use operation_cancel_tunnel::*; -pub use operation_complete_tunnel::*; pub use operation_find_block::*; pub use operation_find_node::*; pub use operation_get_value::*; @@ -34,7 +36,6 @@ pub use operation_return_receipt::*; pub use operation_route::*; pub use operation_set_value::*; pub use operation_signal::*; -pub use operation_start_tunnel::*; pub use operation_status::*; pub use operation_supply_block::*; pub use operation_validate_dial_info::*; @@ -44,4 +45,11 @@ pub use question::*; pub use respond_to::*; pub use statement::*; +#[cfg(feature = "unstable-tunnels")] +pub use operation_cancel_tunnel::*; +#[cfg(feature = "unstable-tunnels")] +pub use operation_complete_tunnel::*; +#[cfg(feature = "unstable-tunnels")] +pub use operation_start_tunnel::*; + use super::*; diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_cancel_tunnel.rs b/veilid-core/src/rpc_processor/coders/operations/operation_cancel_tunnel.rs index 4bb6ac06..c7254421 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_cancel_tunnel.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_cancel_tunnel.rs @@ -1,5 +1,6 @@ use super::*; +#[cfg(feature = "unstable-tunnels")] #[derive(Debug, Clone)] pub struct RPCOperationCancelTunnelQ { id: TunnelId, @@ -37,6 +38,7 @@ impl RPCOperationCancelTunnelQ { } } +#[cfg(feature = "unstable-tunnels")] #[derive(Debug, Clone)] pub enum RPCOperationCancelTunnelA { Tunnel(TunnelId), diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_complete_tunnel.rs b/veilid-core/src/rpc_processor/coders/operations/operation_complete_tunnel.rs index 46b0258a..f699d613 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_complete_tunnel.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_complete_tunnel.rs @@ -1,5 +1,6 @@ use super::*; +#[cfg(feature = "unstable-tunnels")] #[derive(Debug, Clone)] pub struct RPCOperationCompleteTunnelQ { id: TunnelId, @@ -74,6 +75,7 @@ impl RPCOperationCompleteTunnelQ { } } +#[cfg(feature = "unstable-tunnels")] #[derive(Debug, Clone)] pub enum RPCOperationCompleteTunnelA { Tunnel(FullTunnel), diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_start_tunnel.rs b/veilid-core/src/rpc_processor/coders/operations/operation_start_tunnel.rs index b3741462..5df5d78a 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_start_tunnel.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_start_tunnel.rs @@ -1,5 +1,6 @@ use super::*; +#[cfg(feature = "unstable-tunnels")] #[derive(Debug, Clone)] pub struct RPCOperationStartTunnelQ { id: TunnelId, @@ -64,6 +65,7 @@ impl RPCOperationStartTunnelQ { } } +#[cfg(feature = "unstable-tunnels")] #[derive(Debug, Clone)] pub enum RPCOperationStartTunnelA { Partial(PartialTunnel), diff --git a/veilid-core/src/rpc_processor/coders/operations/question.rs b/veilid-core/src/rpc_processor/coders/operations/question.rs index f0f2c056..03debcb5 100644 --- a/veilid-core/src/rpc_processor/coders/operations/question.rs +++ b/veilid-core/src/rpc_processor/coders/operations/question.rs @@ -51,8 +51,11 @@ pub enum RPCQuestionDetail { WatchValueQ(RPCOperationWatchValueQ), SupplyBlockQ(RPCOperationSupplyBlockQ), FindBlockQ(RPCOperationFindBlockQ), + #[cfg(feature = "unstable-tunnels")] StartTunnelQ(RPCOperationStartTunnelQ), + #[cfg(feature = "unstable-tunnels")] CompleteTunnelQ(RPCOperationCompleteTunnelQ), + #[cfg(feature = "unstable-tunnels")] CancelTunnelQ(RPCOperationCancelTunnelQ), } @@ -67,8 +70,11 @@ impl RPCQuestionDetail { RPCQuestionDetail::WatchValueQ(_) => "WatchValueQ", RPCQuestionDetail::SupplyBlockQ(_) => "SupplyBlockQ", RPCQuestionDetail::FindBlockQ(_) => "FindBlockQ", + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::StartTunnelQ(_) => "StartTunnelQ", + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::CompleteTunnelQ(_) => "CompleteTunnelQ", + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::CancelTunnelQ(_) => "CancelTunnelQ", } } @@ -82,8 +88,11 @@ impl RPCQuestionDetail { RPCQuestionDetail::WatchValueQ(r) => r.validate(validate_context), RPCQuestionDetail::SupplyBlockQ(r) => r.validate(validate_context), RPCQuestionDetail::FindBlockQ(r) => r.validate(validate_context), + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::StartTunnelQ(r) => r.validate(validate_context), + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::CompleteTunnelQ(r) => r.validate(validate_context), + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::CancelTunnelQ(r) => r.validate(validate_context), } } @@ -133,16 +142,19 @@ impl RPCQuestionDetail { let out = RPCOperationFindBlockQ::decode(&op_reader)?; RPCQuestionDetail::FindBlockQ(out) } + #[cfg(feature = "unstable-tunnels")] veilid_capnp::question::detail::StartTunnelQ(r) => { let op_reader = r.map_err(RPCError::protocol)?; let out = RPCOperationStartTunnelQ::decode(&op_reader)?; RPCQuestionDetail::StartTunnelQ(out) } + #[cfg(feature = "unstable-tunnels")] veilid_capnp::question::detail::CompleteTunnelQ(r) => { let op_reader = r.map_err(RPCError::protocol)?; let out = RPCOperationCompleteTunnelQ::decode(&op_reader)?; RPCQuestionDetail::CompleteTunnelQ(out) } + #[cfg(feature = "unstable-tunnels")] veilid_capnp::question::detail::CancelTunnelQ(r) => { let op_reader = r.map_err(RPCError::protocol)?; let out = RPCOperationCancelTunnelQ::decode(&op_reader)?; @@ -170,12 +182,15 @@ impl RPCQuestionDetail { RPCQuestionDetail::FindBlockQ(d) => { d.encode(&mut builder.reborrow().init_find_block_q()) } + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::StartTunnelQ(d) => { d.encode(&mut builder.reborrow().init_start_tunnel_q()) } + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::CompleteTunnelQ(d) => { d.encode(&mut builder.reborrow().init_complete_tunnel_q()) } + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::CancelTunnelQ(d) => { d.encode(&mut builder.reborrow().init_cancel_tunnel_q()) } diff --git a/veilid-core/src/rpc_processor/mod.rs b/veilid-core/src/rpc_processor/mod.rs index c526c77f..d76d31fe 100644 --- a/veilid-core/src/rpc_processor/mod.rs +++ b/veilid-core/src/rpc_processor/mod.rs @@ -4,8 +4,6 @@ mod fanout_call; mod operation_waiter; mod rpc_app_call; mod rpc_app_message; -mod rpc_cancel_tunnel; -mod rpc_complete_tunnel; mod rpc_error; mod rpc_find_block; mod rpc_find_node; @@ -14,13 +12,19 @@ mod rpc_return_receipt; mod rpc_route; mod rpc_set_value; mod rpc_signal; -mod rpc_start_tunnel; mod rpc_status; mod rpc_supply_block; mod rpc_validate_dial_info; mod rpc_value_changed; mod rpc_watch_value; +#[cfg(feature = "unstable-tunnels")] +mod rpc_cancel_tunnel; +#[cfg(feature = "unstable-tunnels")] +mod rpc_complete_tunnel; +#[cfg(feature = "unstable-tunnels")] +mod rpc_start_tunnel; + pub use coders::*; pub use destination::*; pub use fanout_call::*; @@ -1410,8 +1414,11 @@ impl RPCProcessor { RPCQuestionDetail::WatchValueQ(_) => self.process_watch_value_q(msg).await, RPCQuestionDetail::SupplyBlockQ(_) => self.process_supply_block_q(msg).await, RPCQuestionDetail::FindBlockQ(_) => self.process_find_block_q(msg).await, + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::StartTunnelQ(_) => self.process_start_tunnel_q(msg).await, + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::CompleteTunnelQ(_) => self.process_complete_tunnel_q(msg).await, + #[cfg(feature = "unstable-tunnels")] RPCQuestionDetail::CancelTunnelQ(_) => self.process_cancel_tunnel_q(msg).await, }, RPCOperationKind::Statement(s) => match s.detail() { diff --git a/veilid-core/src/veilid_api/api.rs b/veilid-core/src/veilid_api/api.rs index ab40f11f..59a9f2db 100644 --- a/veilid-core/src/veilid_api/api.rs +++ b/veilid-core/src/veilid_api/api.rs @@ -268,6 +268,7 @@ impl VeilidAPI { //////////////////////////////////////////////////////////////// // Tunnel Building + #[cfg(feature = "unstable-tunnels")] #[instrument(level = "debug", err, skip(self))] pub async fn start_tunnel( &self, @@ -277,6 +278,7 @@ impl VeilidAPI { panic!("unimplemented"); } + #[cfg(feature = "unstable-tunnels")] #[instrument(level = "debug", err, skip(self))] pub async fn complete_tunnel( &self, @@ -287,6 +289,7 @@ impl VeilidAPI { panic!("unimplemented"); } + #[cfg(feature = "unstable-tunnels")] #[instrument(level = "debug", err, skip(self))] pub async fn cancel_tunnel(&self, _tunnel_id: TunnelId) -> VeilidAPIResult { panic!("unimplemented"); diff --git a/veilid-core/src/veilid_api/error.rs b/veilid-core/src/veilid_api/error.rs index 778b4830..0eb7b791 100644 --- a/veilid-core/src/veilid_api/error.rs +++ b/veilid-core/src/veilid_api/error.rs @@ -117,6 +117,7 @@ macro_rules! apibail_already_initialized { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] #[serde(tag = "kind")] @@ -136,7 +137,10 @@ pub enum VeilidAPIError { #[error("No connection: {message}")] NoConnection { message: String }, #[error("Key not found: {key}")] - KeyNotFound { key: TypedKey }, + KeyNotFound { + #[schemars(with="String")] + key: TypedKey + }, #[error("Internal: {message}")] Internal { message: String }, #[error("Unimplemented: {message}")] diff --git a/veilid-core/src/veilid_api/json_api/crypto_system.rs b/veilid-core/src/veilid_api/json_api/crypto_system.rs new file mode 100644 index 00000000..73f08923 --- /dev/null +++ b/veilid-core/src/veilid_api/json_api/crypto_system.rs @@ -0,0 +1,66 @@ +use super::*; + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct CryptoSystemRequest { + cs_id: String, + #[serde(flatten)] + cs_op: CryptoSystemRequestOp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct CryptoSystemResponse { + cs_id: String, + #[serde(flatten)] + cs_op: CryptoSystemResponseOp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "cs_op")] +pub enum CryptoSystemRequestOp { + Release, + CachedDh, + ComputeDh, + RandomBytes, + DefaultSaltLength, + HashPassword, + VerifyPassword, + DeriveSharedSecret, + RandomNonce, + RandomSharedSecret, + GenerateKeyPair, + GenerateHash, + ValidateKeyPair, + ValidateHash, + Distance, + Sign, + Verify, + AeadOverhead, + DecryptAead, + EncryptAead, + CryptNoAuth, +} +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "cs_op")] +pub enum CryptoSystemResponseOp { + Release, + CachedDh, + ComputeDh, + RandomBytes, + DefaultSaltLength, + HashPassword, + VerifyPassword, + DeriveSharedSecret, + RandomNonce, + RandomSharedSecret, + GenerateKeyPair, + GenerateHash, + ValidateKeyPair, + ValidateHash, + Distance, + Sign, + Verify, + AeadOverhead, + DecryptAead, + EncryptAead, + CryptNoAuth, +} diff --git a/veilid-core/src/veilid_api/json_api/mod.rs b/veilid-core/src/veilid_api/json_api/mod.rs new file mode 100644 index 00000000..5fb4b07b --- /dev/null +++ b/veilid-core/src/veilid_api/json_api/mod.rs @@ -0,0 +1,203 @@ +use super::*; + +mod routing_context; +pub use routing_context::*; + +mod table_db; +pub use table_db::*; + +mod crypto_system; +pub use crypto_system::*; + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct Request { + /// Operation Id (pairs with Response) + id: String, + /// The request operation variant + #[serde(flatten)] + op: RequestOp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct Response { + /// Operation Id (pairs with Request) + id: String, + /// The response operation variant + #[serde(flatten)] + op: ResponseOp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "op")] +pub enum RequestOp { + GetState, + Attach, + Detach, + NewPrivateRoute, + NewCustomPrivateRoute { + #[schemars(with = "Vec")] + crypto_kinds: Vec, + #[serde(default)] + stability: Stability, + #[serde(default)] + sequencing: Sequencing, + }, + ImportRemotePrivateRoute { + #[serde( + serialize_with = "json_as_base64::serialize", + deserialize_with = "json_as_base64::deserialize" + )] + #[schemars(with = "String")] + blob: Vec, + }, + ReleasePrivateRoute { + #[schemars(with = "String")] + route_id: RouteId, + }, + AppCallReply { + #[schemars(with = "String")] + call_id: OperationId, + #[serde( + serialize_with = "json_as_base64::serialize", + deserialize_with = "json_as_base64::deserialize" + )] + #[schemars(with = "String")] + message: Vec, + }, + // Routing Context + NewRoutingContext, + RoutingContext(RoutingContextRequest), + // TableDb + OpenTableDb { + name: String, + column_count: u32, + }, + DeleteTableDb { + name: String, + }, + TableDb(TableDbRequest), + // Crypto + GetCryptoSystem { + #[schemars(with = "String")] + crypto_kind: CryptoKind, + }, + BestCryptoSystem, + CryptoSystem(CryptoSystemRequest), + VerifySignatures { + #[schemars(with = "Vec")] + node_ids: Vec, + #[serde( + serialize_with = "json_as_base64::serialize", + deserialize_with = "json_as_base64::deserialize" + )] + #[schemars(with = "String")] + data: Vec, + #[schemars(with = "Vec")] + signatures: Vec, + }, + GenerateSignatures { + #[serde( + serialize_with = "json_as_base64::serialize", + deserialize_with = "json_as_base64::deserialize" + )] + #[schemars(with = "String")] + data: Vec, + #[schemars(with = "Vec")] + key_pairs: Vec, + }, + GenerateKeyPair { + #[schemars(with = "String")] + crypto_kind: CryptoKind, + }, + // Misc + Now, + Debug { + command: String, + }, + VeilidVersionString, + VeilidVersion, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct NewPrivateRouteResult { + #[schemars(with = "String")] + route_id: RouteId, + #[serde( + serialize_with = "json_as_base64::serialize", + deserialize_with = "json_as_base64::deserialize" + )] + #[schemars(with = "String")] + blob: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "op")] +pub enum ResponseOp { + GetState { + #[serde(flatten)] + result: ApiResult, + }, + Attach { + #[serde(flatten)] + result: ApiResult<()>, + }, + Detach { + #[serde(flatten)] + result: ApiResult<()>, + }, + NewPrivateRoute { + #[serde(flatten)] + result: ApiResult, + }, + NewCustomPrivateRoute { + #[serde(flatten)] + result: ApiResult, + }, + ImportRemotePrivateRoute, + ReleasePrivateRoute, + AppCallReply, + // Routing Context + NewRoutingContext, + RoutingContext(RoutingContextResponse), + // TableDb + OpenTableDb, + DeleteTableDb, + TableDb(TableDbResponse), + // Crypto + GetCryptoSystem, + BestCryptoSystem, + CryptoSystem(CryptoSystemResponse), + VerifySignatures, + GenerateSignatures, + GenerateKeyPair, + // Misc + Now, + Debug, + VeilidVersionString, + VeilidVersion, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(untagged)] +pub enum ApiResult +where + T: Clone + fmt::Debug + JsonSchema, +{ + Ok { value: T }, + Err { error: VeilidAPIError }, +} + +pub fn emit_schemas(out: &mut HashMap) { + let schema_request = schema_for!(Request); + let schema_response = schema_for!(Response); + + out.insert( + "Request".to_owned(), + serde_json::to_string_pretty(&schema_request).unwrap(), + ); + + out.insert( + "Response".to_owned(), + serde_json::to_string_pretty(&schema_response).unwrap(), + ); +} diff --git a/veilid-core/src/veilid_api/json_api/routing_context.rs b/veilid-core/src/veilid_api/json_api/routing_context.rs new file mode 100644 index 00000000..c4a9405c --- /dev/null +++ b/veilid-core/src/veilid_api/json_api/routing_context.rs @@ -0,0 +1,52 @@ +use super::*; + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct RoutingContextRequest { + rc_id: String, + #[serde(flatten)] + rc_op: RoutingContextRequestOp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct RoutingContextResponse { + rc_id: String, + #[serde(flatten)] + rc_op: RoutingContextResponseOp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "rc_op")] +pub enum RoutingContextRequestOp { + Release, + WithPrivacy, + WithCustomPrivacy, + WithSequencing, + AppCall, + AppMessage, + CreateDhtRecord, + OpenDhtRecord, + CloseDhtRecord, + DeleteDhtRecord, + GetDhtValue, + SetDhtValue, + WatchDhtValues, + CancelDhtWatch, +} +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "rc_op")] +pub enum RoutingContextResponseOp { + Release, + WithPrivacy, + WithCustomPrivacy, + WithSequencing, + AppCall, + AppMessage, + CreateDhtRecord, + OpenDhtRecord, + CloseDhtRecord, + DeleteDhtRecord, + GetDhtValue, + SetDhtValue, + WatchDhtValues, + CancelDhtWatch, +} diff --git a/veilid-core/src/veilid_api/json_api/table_db.rs b/veilid-core/src/veilid_api/json_api/table_db.rs new file mode 100644 index 00000000..62190e83 --- /dev/null +++ b/veilid-core/src/veilid_api/json_api/table_db.rs @@ -0,0 +1,26 @@ +use super::*; + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct TableDbRequest { + db_id: String, + #[serde(flatten)] + db_op: TableDbRequestOp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +pub struct TableDbResponse { + db_id: String, + #[serde(flatten)] + db_op: TableDbResponseOp, +} + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "db_op")] +pub enum TableDbRequestOp { + Release, +} +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "db_op")] +pub enum TableDbResponseOp { + Release, +} diff --git a/veilid-core/src/veilid_api/mod.rs b/veilid-core/src/veilid_api/mod.rs index d046b71f..50afee6f 100644 --- a/veilid-core/src/veilid_api/mod.rs +++ b/veilid-core/src/veilid_api/mod.rs @@ -3,6 +3,7 @@ mod api; mod debug; mod error; +mod json_api; mod routing_context; mod serialize_helpers; mod types; @@ -12,6 +13,7 @@ pub mod tests; pub use api::*; pub use debug::*; pub use error::*; +pub use json_api::*; pub use routing_context::*; pub use serialize_helpers::*; pub use types::*; diff --git a/veilid-core/src/veilid_api/serialize_helpers/serialize_range_set_blaze.rs b/veilid-core/src/veilid_api/serialize_helpers/serialize_range_set_blaze.rs index 5ef5fa46..2b98a3e3 100644 --- a/veilid-core/src/veilid_api/serialize_helpers/serialize_range_set_blaze.rs +++ b/veilid-core/src/veilid_api/serialize_helpers/serialize_range_set_blaze.rs @@ -9,11 +9,10 @@ pub fn serialize( v: &RangeSetBlaze, s: S, ) -> Result { - let cnt = v.ranges_len() * 2; + let cnt = v.ranges_len(); let mut seq = s.serialize_seq(Some(cnt))?; for range in v.ranges() { - seq.serialize_element(range.start())?; - seq.serialize_element(range.end())?; + seq.serialize_element(&(range.start(), range.end()))?; } seq.end() } @@ -41,10 +40,7 @@ pub fn deserialize<'de, T: Integer + Deserialize<'de>, D: Deserializer<'de>>( { let mut values = RangeSetBlaze::::new(); - while let Some(start) = seq.next_element()? { - let Some(end) = seq.next_element()? else { - break; - }; + while let Some((start, end)) = seq.next_element()? { values.ranges_insert(start..=end); } diff --git a/veilid-core/src/veilid_api/types/aligned_u64.rs b/veilid-core/src/veilid_api/types/aligned_u64.rs index 6a64b86d..11ee022d 100644 --- a/veilid-core/src/veilid_api/types/aligned_u64.rs +++ b/veilid-core/src/veilid_api/types/aligned_u64.rs @@ -18,10 +18,19 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[repr(C, align(8))] #[archive_attr(repr(C, align(8)), derive(CheckBytes))] -pub struct AlignedU64(u64); +#[serde(transparent)] +pub struct AlignedU64( + #[serde( + serialize_with = "json_as_string::serialize", + deserialize_with = "json_as_string::deserialize" + )] + #[schemars(with = "String")] + u64, +); impl From for AlignedU64 { fn from(v: u64) -> Self { diff --git a/veilid-core/src/veilid_api/types/app_message_call.rs b/veilid-core/src/veilid_api/types/app_message_call.rs index 6f0805fe..2f3c77be 100644 --- a/veilid-core/src/veilid_api/types/app_message_call.rs +++ b/veilid-core/src/veilid_api/types/app_message_call.rs @@ -2,15 +2,33 @@ use super::*; /// Direct statement blob passed to hosting application for processing #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidAppMessage { /// Some(sender) if the message was sent directly, None if received via a private/safety route - #[serde(with = "opt_json_as_string")] + #[serde( + serialize_with = "opt_json_as_string::serialize", + deserialize_with = "opt_json_as_string::deserialize" + )] + #[schemars(with = "Option")] sender: Option, + /// The content of the message to deliver to the application - #[serde(with = "json_as_base64")] + #[serde( + serialize_with = "json_as_base64::serialize", + deserialize_with = "json_as_base64::deserialize" + )] + #[schemars(with = "String")] message: Vec, } @@ -29,18 +47,41 @@ impl VeilidAppMessage { /// Direct question blob passed to hosting application for processing to send an eventual AppReply #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidAppCall { /// Some(sender) if the request was sent directly, None if received via a private/safety route - #[serde(with = "opt_json_as_string")] + #[serde( + serialize_with = "opt_json_as_string::serialize", + deserialize_with = "opt_json_as_string::deserialize" + )] + #[schemars(with = "Option")] sender: Option, + /// The content of the request to deliver to the application - #[serde(with = "json_as_base64")] + #[serde( + serialize_with = "json_as_base64::serialize", + deserialize_with = "json_as_base64::deserialize" + )] + #[schemars(with = "String")] message: Vec, + /// The id to reply to - #[serde(with = "json_as_string")] + #[serde( + serialize_with = "json_as_string::serialize", + deserialize_with = "json_as_string::deserialize" + )] + #[schemars(with = "String")] id: OperationId, } diff --git a/veilid-core/src/veilid_api/types/dht/dht_record_descriptor.rs b/veilid-core/src/veilid_api/types/dht/dht_record_descriptor.rs index 1c4d114e..6162fd9f 100644 --- a/veilid-core/src/veilid_api/types/dht/dht_record_descriptor.rs +++ b/veilid-core/src/veilid_api/types/dht/dht_record_descriptor.rs @@ -13,15 +13,19 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct DHTRecordDescriptor { /// DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ] + #[schemars(with = "String")] key: TypedKey, /// The public key of the owner + #[schemars(with = "String")] owner: PublicKey, /// If this key is being created: Some(the secret key of the owner) /// If this key is just being opened: None + #[schemars(with = "Option")] owner_secret: Option, /// The schema in use associated with the key schema: DHTSchema, diff --git a/veilid-core/src/veilid_api/types/dht/schema/dflt.rs b/veilid-core/src/veilid_api/types/dht/schema/dflt.rs index bd9c0858..a742bdec 100644 --- a/veilid-core/src/veilid_api/types/dht/schema/dflt.rs +++ b/veilid-core/src/veilid_api/types/dht/schema/dflt.rs @@ -13,6 +13,7 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct DHTSchemaDFLT { diff --git a/veilid-core/src/veilid_api/types/dht/schema/mod.rs b/veilid-core/src/veilid_api/types/dht/schema/mod.rs index b043afcc..2361e32c 100644 --- a/veilid-core/src/veilid_api/types/dht/schema/mod.rs +++ b/veilid-core/src/veilid_api/types/dht/schema/mod.rs @@ -19,6 +19,7 @@ pub use smpl::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] #[serde(tag = "kind")] diff --git a/veilid-core/src/veilid_api/types/dht/schema/smpl.rs b/veilid-core/src/veilid_api/types/dht/schema/smpl.rs index 90b20b86..9b2c7df1 100644 --- a/veilid-core/src/veilid_api/types/dht/schema/smpl.rs +++ b/veilid-core/src/veilid_api/types/dht/schema/smpl.rs @@ -13,10 +13,12 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct DHTSchemaSMPLMember { /// Member key + #[schemars(with = "String")] pub m_key: PublicKey, /// Member subkey count pub m_cnt: u16, @@ -35,6 +37,7 @@ pub struct DHTSchemaSMPLMember { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct DHTSchemaSMPL { diff --git a/veilid-core/src/veilid_api/types/dht/value_data.rs b/veilid-core/src/veilid_api/types/dht/value_data.rs index 734e735d..eae2e2c4 100644 --- a/veilid-core/src/veilid_api/types/dht/value_data.rs +++ b/veilid-core/src/veilid_api/types/dht/value_data.rs @@ -13,11 +13,23 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct ValueData { + /// An increasing sequence number to time-order the DHT record changes seq: ValueSeqNum, + + /// The contents of a DHT Record + #[serde( + serialize_with = "json_as_base64::serialize", + deserialize_with = "json_as_base64::deserialize" + )] + #[schemars(with = "String")] data: Vec, + + /// The public identity key of the writer of the data + #[schemars(with = "String")] writer: PublicKey, } impl ValueData { diff --git a/veilid-core/src/veilid_api/types/dht/value_subkey_range_set.rs b/veilid-core/src/veilid_api/types/dht/value_subkey_range_set.rs index 3dd40f67..955c9d01 100644 --- a/veilid-core/src/veilid_api/types/dht/value_subkey_range_set.rs +++ b/veilid-core/src/veilid_api/types/dht/value_subkey_range_set.rs @@ -15,11 +15,16 @@ use range_set_blaze::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct ValueSubkeyRangeSet { #[with(RkyvRangeSetBlaze)] - #[serde(with = "serialize_range_set_blaze")] + #[serde( + serialize_with = "serialize_range_set_blaze::serialize", + deserialize_with = "serialize_range_set_blaze::deserialize" + )] + #[schemars(with = "Vec<(u32,u32)>")] data: RangeSetBlaze, } diff --git a/veilid-core/src/veilid_api/types/fourcc.rs b/veilid-core/src/veilid_api/types/fourcc.rs index edce2b03..1d56da33 100644 --- a/veilid-core/src/veilid_api/types/fourcc.rs +++ b/veilid-core/src/veilid_api/types/fourcc.rs @@ -15,8 +15,11 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes, PartialOrd, Ord, PartialEq, Eq, Hash))] +#[serde(try_from = "String")] +#[serde(into = "String")] pub struct FourCC(pub [u8; 4]); impl From<[u8; 4]> for FourCC { @@ -37,6 +40,12 @@ impl From for u32 { } } +impl From for String { + fn from(u: FourCC) -> Self { + String::from_utf8_lossy(&u.0).to_string() + } +} + impl TryFrom<&[u8]> for FourCC { type Error = VeilidAPIError; fn try_from(b: &[u8]) -> Result { @@ -44,6 +53,13 @@ impl TryFrom<&[u8]> for FourCC { } } +impl TryFrom for FourCC { + type Error = VeilidAPIError; + fn try_from(s: String) -> Result { + Self::from_str(s.as_str()) + } +} + impl fmt::Display for FourCC { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{}", String::from_utf8_lossy(&self.0)) diff --git a/veilid-core/src/veilid_api/types/mod.rs b/veilid-core/src/veilid_api/types/mod.rs index 6dea3db5..d3c2d9dc 100644 --- a/veilid-core/src/veilid_api/types/mod.rs +++ b/veilid-core/src/veilid_api/types/mod.rs @@ -4,6 +4,7 @@ mod dht; mod fourcc; mod safety; mod stats; +#[cfg(feature = "unstable-tunnels")] mod tunnel; mod veilid_log; mod veilid_state; @@ -16,6 +17,7 @@ pub use dht::*; pub use fourcc::*; pub use safety::*; pub use stats::*; +#[cfg(feature = "unstable-tunnels")] pub use tunnel::*; pub use veilid_log::*; pub use veilid_state::*; diff --git a/veilid-core/src/veilid_api/types/safety.rs b/veilid-core/src/veilid_api/types/safety.rs index 27cb46ba..970619c2 100644 --- a/veilid-core/src/veilid_api/types/safety.rs +++ b/veilid-core/src/veilid_api/types/safety.rs @@ -15,6 +15,7 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] pub enum Sequencing { @@ -44,6 +45,7 @@ impl Default for Sequencing { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] pub enum Stability { @@ -72,6 +74,7 @@ impl Default for Stability { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] pub enum SafetySelection { @@ -111,10 +114,12 @@ impl Default for SafetySelection { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct SafetySpec { /// preferred safety route set id if it still exists + #[schemars(with = "Option")] pub preferred_route: Option, /// must be greater than 0 pub hop_count: usize, diff --git a/veilid-core/src/veilid_api/types/stats.rs b/veilid-core/src/veilid_api/types/stats.rs index 8ea79e11..a7bbce14 100644 --- a/veilid-core/src/veilid_api/types/stats.rs +++ b/veilid-core/src/veilid_api/types/stats.rs @@ -11,14 +11,12 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct LatencyStats { - #[serde(with = "json_as_string")] pub fastest: TimestampDuration, // fastest latency in the ROLLING_LATENCIES_SIZE last latencies - #[serde(with = "json_as_string")] pub average: TimestampDuration, // average latency over the ROLLING_LATENCIES_SIZE last latencies - #[serde(with = "json_as_string")] pub slowest: TimestampDuration, // slowest latency in the ROLLING_LATENCIES_SIZE last latencies } @@ -33,16 +31,13 @@ pub struct LatencyStats { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct TransferStats { - #[serde(with = "json_as_string")] - pub total: ByteCount, // total amount transferred ever - #[serde(with = "json_as_string")] + pub total: ByteCount, // total amount transferred ever pub maximum: ByteCount, // maximum rate over the ROLLING_TRANSFERS_SIZE last amounts - #[serde(with = "json_as_string")] pub average: ByteCount, // average rate over the ROLLING_TRANSFERS_SIZE last amounts - #[serde(with = "json_as_string")] pub minimum: ByteCount, // minimum rate over the ROLLING_TRANSFERS_SIZE last amounts } @@ -57,6 +52,7 @@ pub struct TransferStats { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct TransferStatsDownUp { @@ -75,17 +71,15 @@ pub struct TransferStatsDownUp { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct RPCStats { pub messages_sent: u32, // number of rpcs that have been sent in the total_time range pub messages_rcvd: u32, // number of rpcs that have been received in the total_time range pub questions_in_flight: u32, // number of questions issued that have yet to be answered - #[serde(with = "opt_json_as_string")] pub last_question_ts: Option, // when the peer was last questioned (either successfully or not) and we wanted an answer - #[serde(with = "opt_json_as_string")] pub last_seen_ts: Option, // when the peer was last seen for any reason, including when we first attempted to reach out to it - #[serde(with = "opt_json_as_string")] pub first_consecutive_seen_ts: Option, // the timestamp of the first consecutive proof-of-life for this node (an answer or received question) pub recent_lost_answers: u32, // number of answers that have been lost since we lost reliability pub failed_to_send: u32, // number of messages that have failed to send since we last successfully sent one @@ -102,12 +96,12 @@ pub struct RPCStats { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct PeerStats { - #[serde(with = "json_as_string")] pub time_added: Timestamp, // when the peer was added to the routing table - pub rpc_stats: RPCStats, // information about RPCs + pub rpc_stats: RPCStats, // information about RPCs pub latency: Option, // latencies for communications with the peer pub transfer: TransferStatsDownUp, // Stats for communications with the peer } diff --git a/veilid-core/src/veilid_api/types/tunnel.rs b/veilid-core/src/veilid_api/types/tunnel.rs index 968c7695..d7dd0326 100644 --- a/veilid-core/src/veilid_api/types/tunnel.rs +++ b/veilid-core/src/veilid_api/types/tunnel.rs @@ -1,8 +1,11 @@ +#[cfg(feature = "unstable-tunnels")] use super::*; /// Tunnel identifier +#[cfg(feature = "unstable-tunnels")] pub type TunnelId = AlignedU64; +#[cfg(feature = "unstable-tunnels")] #[derive( Copy, Clone, @@ -16,6 +19,7 @@ pub type TunnelId = AlignedU64; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] pub enum TunnelMode { @@ -23,6 +27,7 @@ pub enum TunnelMode { Turn, } +#[cfg(feature = "unstable-tunnels")] #[derive( Copy, Clone, @@ -36,6 +41,7 @@ pub enum TunnelMode { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] pub enum TunnelError { @@ -45,13 +51,17 @@ pub enum TunnelError { NoCapacity, // Endpoint is full } -#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)] +#[cfg(feature = "unstable-tunnels")] +#[derive( + Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, JsonSchema, +)] #[archive_attr(repr(C), derive(CheckBytes))] pub struct TunnelEndpoint { pub mode: TunnelMode, pub description: String, // XXX: TODO } +#[cfg(feature = "unstable-tunnels")] impl Default for TunnelEndpoint { fn default() -> Self { Self { @@ -61,8 +71,17 @@ impl Default for TunnelEndpoint { } } +#[cfg(feature = "unstable-tunnels")] #[derive( - Clone, Debug, Default, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Clone, + Debug, + Default, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct FullTunnel { @@ -72,8 +91,17 @@ pub struct FullTunnel { pub remote: TunnelEndpoint, } +#[cfg(feature = "unstable-tunnels")] #[derive( - Clone, Debug, Default, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Clone, + Debug, + Default, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct PartialTunnel { diff --git a/veilid-core/src/veilid_api/types/veilid_log.rs b/veilid-core/src/veilid_api/types/veilid_log.rs index 5eab945c..66852e14 100644 --- a/veilid-core/src/veilid_api/types/veilid_log.rs +++ b/veilid-core/src/veilid_api/types/veilid_log.rs @@ -14,6 +14,7 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] pub enum VeilidLogLevel { @@ -78,7 +79,16 @@ impl fmt::Display for VeilidLogLevel { /// A VeilidCore log message with optional backtrace #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidLog { diff --git a/veilid-core/src/veilid_api/types/veilid_state.rs b/veilid-core/src/veilid_api/types/veilid_state.rs index 09f21a24..01902e2a 100644 --- a/veilid-core/src/veilid_api/types/veilid_state.rs +++ b/veilid-core/src/veilid_api/types/veilid_state.rs @@ -12,6 +12,7 @@ use super::*; RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(u8), derive(CheckBytes))] pub enum AttachmentState { @@ -60,7 +61,16 @@ impl TryFrom for AttachmentState { } #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidStateAttachment { @@ -70,39 +80,76 @@ pub struct VeilidStateAttachment { } #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct PeerTableData { + #[schemars(with = "Vec")] pub node_ids: Vec, pub peer_address: String, pub peer_stats: PeerStats, } #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidStateNetwork { pub started: bool, - #[serde(with = "json_as_string")] pub bps_down: ByteCount, - #[serde(with = "json_as_string")] pub bps_up: ByteCount, pub peers: Vec, } #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidRouteChange { + #[schemars(with = "Vec")] pub dead_routes: Vec, + #[schemars(with = "Vec")] pub dead_remote_routes: Vec, } #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidStateConfig { @@ -110,17 +157,29 @@ pub struct VeilidStateConfig { } #[derive( - Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, + JsonSchema, )] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidValueChange { + #[schemars(with = "String")] key: TypedKey, subkeys: Vec, count: u32, value: ValueData, } -#[derive(Debug, Clone, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)] +#[derive( + Debug, Clone, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, JsonSchema, +)] #[archive_attr(repr(u8), derive(CheckBytes))] #[serde(tag = "kind")] pub enum VeilidUpdate { @@ -135,7 +194,9 @@ pub enum VeilidUpdate { Shutdown, } -#[derive(Debug, Clone, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)] +#[derive( + Debug, Clone, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, JsonSchema, +)] #[archive_attr(repr(C), derive(CheckBytes))] pub struct VeilidState { pub attachment: VeilidStateAttachment, diff --git a/veilid-core/src/veilid_config.rs b/veilid-core/src/veilid_config.rs index 68c06e6f..8559ba47 100644 --- a/veilid-core/src/veilid_config.rs +++ b/veilid-core/src/veilid_config.rs @@ -25,6 +25,7 @@ pub type ConfigCallback = Arc ConfigCallbackReturn + Send + Sy RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigHTTPS { pub enabled: bool, @@ -54,6 +55,7 @@ pub struct VeilidConfigHTTPS { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigHTTP { pub enabled: bool, @@ -79,6 +81,7 @@ pub struct VeilidConfigHTTP { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigApplication { pub https: VeilidConfigHTTPS, @@ -106,6 +109,7 @@ pub struct VeilidConfigApplication { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigUDP { pub enabled: bool, @@ -135,6 +139,7 @@ pub struct VeilidConfigUDP { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigTCP { pub connect: bool, @@ -166,6 +171,7 @@ pub struct VeilidConfigTCP { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigWS { pub connect: bool, @@ -198,6 +204,7 @@ pub struct VeilidConfigWS { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigWSS { pub connect: bool, @@ -226,6 +233,7 @@ pub struct VeilidConfigWSS { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigProtocol { pub udp: VeilidConfigUDP, @@ -253,6 +261,7 @@ pub struct VeilidConfigProtocol { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigTLS { pub certificate_path: String, @@ -273,6 +282,7 @@ pub struct VeilidConfigTLS { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigDHT { pub max_find_node_count: u32, @@ -309,6 +319,7 @@ pub struct VeilidConfigDHT { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigRPC { pub concurrency: u32, @@ -333,9 +344,12 @@ pub struct VeilidConfigRPC { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigRoutingTable { + #[schemars(with = "Vec")] pub node_id: TypedKeySet, + #[schemars(with = "Vec")] pub node_id_secret: TypedSecretSet, pub bootstrap: Vec, pub limit_over_attached: u32, @@ -358,6 +372,7 @@ pub struct VeilidConfigRoutingTable { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigNetwork { pub connection_initial_timeout_ms: u32, @@ -391,6 +406,7 @@ pub struct VeilidConfigNetwork { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigTableStore { pub directory: String, @@ -408,6 +424,7 @@ pub struct VeilidConfigTableStore { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigBlockStore { pub directory: String, @@ -425,6 +442,7 @@ pub struct VeilidConfigBlockStore { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigProtectedStore { pub allow_insecure_fallback: bool, @@ -446,6 +464,7 @@ pub struct VeilidConfigProtectedStore { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigCapabilities { pub protocol_udp: bool, @@ -468,6 +487,7 @@ pub struct VeilidConfigCapabilities { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub enum VeilidConfigLogLevel { Off, @@ -537,6 +557,7 @@ impl Default for VeilidConfigLogLevel { RkyvArchive, RkyvSerialize, RkyvDeserialize, + JsonSchema, )] pub struct VeilidConfigInner { pub program_name: String, @@ -737,7 +758,6 @@ impl VeilidConfig { safe_cfg.protected_store.device_encryption_key_password = "".to_owned(); safe_cfg.protected_store.new_device_encryption_key_password = None; - safe_cfg } diff --git a/veilid-server/src/cmdline.rs b/veilid-server/src/cmdline.rs index 3d4fe163..cdc4158a 100644 --- a/veilid-server/src/cmdline.rs +++ b/veilid-server/src/cmdline.rs @@ -132,6 +132,14 @@ fn do_clap_matches(default_config_path: &OsStr) -> Result EyreResult<()> { bail!("missing crypto kind"); } } + // -- Emit JSON-Schema -- + if matches.occurrences_of("emit-schema") != 0 { + if let Some(esstr) = matches.value_of("emit-schema") { + let mut schemas = HashMap::::new(); + veilid_core::emit_schemas(&mut schemas); + + if let Some(schema) = schemas.get(esstr) { + println!("{}", schema); + } else { + println!("Valid schemas:"); + for s in schemas.keys() { + println!(" {}", s); + } + } + + return Ok(()); + } + } // See if we're just running a quick command let (server_mode, success, failure) = if matches.occurrences_of("set-node-id") != 0 {