diff --git a/.github/actions/cache_nix/action.yml b/.github/actions/cache_nix/action.yml index 6e6a670a9d6..fc2928e754b 100644 --- a/.github/actions/cache_nix/action.yml +++ b/.github/actions/cache_nix/action.yml @@ -17,7 +17,7 @@ runs: - name: Restore and Save Cache id: nix-restore-and-save if: ${{ github.event_name == 'schedule' }} - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 + uses: actions/cache@v4 with: path: | /tmp/nix-cache @@ -26,7 +26,7 @@ runs: - name: Restore Cache id: nix-restore if: ${{ github.event_name != 'schedule' }} - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 + uses: actions/cache/restore@v4 with: path: | /tmp/nix-cache diff --git a/.github/actions/nix_installer_and_cache/action.yml b/.github/actions/nix_installer_and_cache/action.yml index 0b3d845aa03..bb9ea65b744 100644 --- a/.github/actions/nix_installer_and_cache/action.yml +++ b/.github/actions/nix_installer_and_cache/action.yml @@ -19,7 +19,7 @@ runs: - name: Restore and Save Cache id: nix-restore-and-save if: ${{ github.event_name == 'schedule' }} - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 + uses: actions/cache@v4 with: path: | /tmp/nix-cache @@ -28,7 +28,7 @@ runs: - name: Restore Cache id: nix-restore if: ${{ github.event_name != 'schedule' }} - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 + uses: actions/cache/restore@v4 with: path: | /tmp/nix-cache diff --git a/examples/rust/file_transfer/src/messages.rs b/examples/rust/file_transfer/src/messages.rs index 7414c04995a..9e6f595a3c4 100644 --- a/examples/rust/file_transfer/src/messages.rs +++ b/examples/rust/file_transfer/src/messages.rs @@ -1,18 +1,39 @@ -use ockam::Message; +use ockam::{deserialize, serialize, Decodable, Encodable, Encoded, Message}; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Message)] pub struct FileDescription { pub name: String, pub size: usize, } -impl Message for FileDescription {} -#[derive(Serialize, Deserialize)] +impl Encodable for FileDescription { + fn encode(self) -> ockam::Result { + serialize(self) + } +} + +impl Decodable for FileDescription { + fn decode(v: &[u8]) -> ockam::Result { + deserialize(v) + } +} + +#[derive(Serialize, Deserialize, Message)] pub enum FileData { Description(FileDescription), Data(Vec), Quit, } -impl Message for FileData {} +impl Encodable for FileData { + fn encode(self) -> ockam::Result { + serialize(self) + } +} + +impl Decodable for FileData { + fn decode(v: &[u8]) -> ockam::Result { + deserialize(v) + } +} diff --git a/examples/rust/get_started/examples/04-routing-over-transport-initiator.rs b/examples/rust/get_started/examples/04-routing-over-transport-initiator.rs index 4467fc79ce8..b572dda01aa 100644 --- a/examples/rust/get_started/examples/04-routing-over-transport-initiator.rs +++ b/examples/rust/get_started/examples/04-routing-over-transport-initiator.rs @@ -17,7 +17,7 @@ async fn main(ctx: Context) -> Result<()> { // Send a message to the "echoer" worker on a different node, over a tcp transport. // Wait to receive a reply and print it. let r = route![connection_to_responder, "echoer"]; - let reply = node.send_and_receive::(r, "Hello Ockam!".to_string()).await?; + let reply: String = node.send_and_receive(r, "Hello Ockam!".to_string()).await?; println!("App Received: {}", reply); // should print "Hello Ockam!" diff --git a/examples/rust/get_started/examples/04-routing-over-transport-two-hops-initiator.rs b/examples/rust/get_started/examples/04-routing-over-transport-two-hops-initiator.rs index 373309c8fa1..f982838ab65 100644 --- a/examples/rust/get_started/examples/04-routing-over-transport-two-hops-initiator.rs +++ b/examples/rust/get_started/examples/04-routing-over-transport-two-hops-initiator.rs @@ -17,7 +17,7 @@ async fn main(ctx: Context) -> Result<()> { // Send a message to the "echoer" worker, on a different node, over two tcp hops. // Wait to receive a reply and print it. let r = route![connection_to_middle_node, "forward_to_responder", "echoer"]; - let reply = node.send_and_receive::(r, "Hello Ockam!".to_string()).await?; + let reply: String = node.send_and_receive(r, "Hello Ockam!".to_string()).await?; println!("App Received: {}", reply); // should print "Hello Ockam!" // Stop all workers, stop the node, cleanup and return. diff --git a/examples/rust/get_started/examples/04-udp-transport-initiator.rs b/examples/rust/get_started/examples/04-udp-transport-initiator.rs index 1aef74c5f21..b83d6b3bc4a 100644 --- a/examples/rust/get_started/examples/04-udp-transport-initiator.rs +++ b/examples/rust/get_started/examples/04-udp-transport-initiator.rs @@ -16,7 +16,7 @@ async fn main(ctx: Context) -> Result<()> { // Send a message to the "echoer" worker on a different node, over a udp transport. // Wait to receive a reply and print it. let r = route![bind, (UDP, "localhost:4000"), "echoer"]; - let reply = node.send_and_receive::(r, "Hello Ockam!".to_string()).await?; + let reply: String = node.send_and_receive(r, "Hello Ockam!".to_string()).await?; println!("App Received: {}", reply); // should print "Hello Ockam!" diff --git a/examples/rust/get_started/examples/05-secure-channel-over-two-transport-hops-initiator.rs b/examples/rust/get_started/examples/05-secure-channel-over-two-transport-hops-initiator.rs index 0ca507f17a1..d552432dd95 100644 --- a/examples/rust/get_started/examples/05-secure-channel-over-two-transport-hops-initiator.rs +++ b/examples/rust/get_started/examples/05-secure-channel-over-two-transport-hops-initiator.rs @@ -25,8 +25,8 @@ async fn main(ctx: Context) -> Result<()> { // Send a message to the echoer worker via the channel. // Wait to receive a reply and print it. - let reply = node - .send_and_receive::(route![channel, "echoer"], "Hello Ockam!".to_string()) + let reply: String = node + .send_and_receive(route![channel, "echoer"], "Hello Ockam!".to_string()) .await?; println!("App Received: {}", reply); // should print "Hello Ockam!" diff --git a/examples/rust/get_started/examples/05-secure-channel-over-two-udp-hops-initiator.rs b/examples/rust/get_started/examples/05-secure-channel-over-two-udp-hops-initiator.rs index f59fdeb3d9d..fb60e7f48e8 100644 --- a/examples/rust/get_started/examples/05-secure-channel-over-two-udp-hops-initiator.rs +++ b/examples/rust/get_started/examples/05-secure-channel-over-two-udp-hops-initiator.rs @@ -29,8 +29,8 @@ async fn main(ctx: Context) -> Result<()> { // Send a message to the echoer worker via the channel. // Wait to receive a reply and print it. - let reply = node - .send_and_receive::(route![channel, "echoer"], "Hello Ockam!".to_string()) + let reply: String = node + .send_and_receive(route![channel, "echoer"], "Hello Ockam!".to_string()) .await?; println!("App Received: {}", reply); // should print "Hello Ockam!" diff --git a/examples/rust/get_started/examples/06-credentials-exchange-client.rs b/examples/rust/get_started/examples/06-credentials-exchange-client.rs index e242f56812a..65bff7fa0fc 100644 --- a/examples/rust/get_started/examples/06-credentials-exchange-client.rs +++ b/examples/rust/get_started/examples/06-credentials-exchange-client.rs @@ -81,8 +81,8 @@ async fn main(ctx: Context) -> Result<()> { // Send a message to the worker at address "echoer". // Wait to receive a reply and print it. - let reply = node - .send_and_receive::( + let reply: String = node + .send_and_receive( route![channel, DefaultAddress::ECHO_SERVICE], "Hello Ockam!".to_string(), ) diff --git a/implementations/rust/ockam/ockam/src/lib.rs b/implementations/rust/ockam/ockam/src/lib.rs index e21d35edde6..32d1c2df9ae 100644 --- a/implementations/rust/ockam/ockam/src/lib.rs +++ b/implementations/rust/ockam/ockam/src/lib.rs @@ -66,8 +66,9 @@ pub use ockam_core::processor; /// may be changed in the future to a [`Worker`](crate::Worker)-specific macro. pub use ockam_core::worker; pub use ockam_core::{ - allow, deny, errcode, route, Address, Any, Encoded, Error, LocalMessage, Mailbox, Mailboxes, - Message, Processor, ProtocolId, Result, Route, Routed, TransportMessage, TryClone, Worker, + allow, deny, deserialize, errcode, route, serialize, Address, Any, Decodable, Encodable, + Encoded, Error, LocalMessage, Mailbox, Mailboxes, Message, Processor, ProtocolId, Result, + Route, Routed, TransportMessage, TryClone, Worker, }; pub use ockam_identity as identity; // --- diff --git a/implementations/rust/ockam/ockam/src/remote/info.rs b/implementations/rust/ockam/ockam/src/remote/info.rs index c39f3e1da09..bb9f4d6890e 100644 --- a/implementations/rust/ockam/ockam/src/remote/info.rs +++ b/implementations/rust/ockam/ockam/src/remote/info.rs @@ -1,7 +1,7 @@ use crate::Message; use ockam_core::compat::string::String; use ockam_core::flow_control::FlowControlId; -use ockam_core::{Address, Route}; +use ockam_core::{deserialize, serialize, Address, Decodable, Encodable, Encoded, Route}; use serde::{Deserialize, Serialize}; /// Information about a remotely forwarded worker. @@ -13,6 +13,18 @@ pub struct RemoteRelayInfo { flow_control_id: Option, } +impl Encodable for RemoteRelayInfo { + fn encode(self) -> ockam_core::Result { + serialize(self) + } +} + +impl Decodable for RemoteRelayInfo { + fn decode(v: &[u8]) -> ockam_core::Result { + deserialize(v) + } +} + impl RemoteRelayInfo { /// Constructor pub fn new( diff --git a/implementations/rust/ockam/ockam/tests/message/test.rs b/implementations/rust/ockam/ockam/tests/message/test.rs index a10c50c71bf..969a32cf15d 100644 --- a/implementations/rust/ockam/ockam/tests/message/test.rs +++ b/implementations/rust/ockam/ockam/tests/message/test.rs @@ -1,4 +1,4 @@ -use ockam::Message; +use ockam::*; use serde::{Deserialize, Serialize}; #[derive(Message, Deserialize, Serialize)] @@ -6,12 +6,34 @@ pub struct Tmp { a: String, } +impl Encodable for Tmp { + fn encode(self) -> Result { + serialize(self) + } +} +impl Decodable for Tmp { + fn decode(e: &[u8]) -> Result { + deserialize(e) + } +} + #[derive(Message, Deserialize, Serialize)] pub struct Tmp1 { a: Vec, b: Vec, } +impl Encodable for Tmp1 { + fn encode(self) -> Result { + serialize(self) + } +} +impl Decodable for Tmp1 { + fn decode(e: &[u8]) -> Result { + deserialize(e) + } +} + fn assert_impl() {} fn main() { assert_impl::(); diff --git a/implementations/rust/ockam/ockam/tests/relay.rs b/implementations/rust/ockam/ockam/tests/relay.rs index de23abede06..ea5d20f6c7a 100644 --- a/implementations/rust/ockam/ockam/tests/relay.rs +++ b/implementations/rust/ockam/ockam/tests/relay.rs @@ -16,8 +16,8 @@ async fn test1(ctx: &mut Context) -> Result<()> { let remote_info = RemoteRelay::create(ctx, route![], RemoteRelayOptions::new()).await?; - let resp = ctx - .send_and_receive::( + let resp: String = ctx + .send_and_receive( route![remote_info.remote_address(), "echoer"], "Hello".to_string(), ) @@ -62,8 +62,8 @@ async fn test2(ctx: &mut Context) -> Result<()> { .connect(cloud_listener.socket_string(), TcpConnectionOptions::new()) .await?; - let resp = ctx - .send_and_receive::( + let resp: String = ctx + .send_and_receive( route![cloud_connection, remote_info.remote_address(), "echoer"], "Hello".to_string(), ) @@ -238,8 +238,8 @@ async fn test4(ctx: &mut Context) -> Result<()> { ) .await?; - let resp = ctx - .send_and_receive::(route![tunnel_channel, "echoer"], "Hello".to_string()) + let resp: String = ctx + .send_and_receive(route![tunnel_channel, "echoer"], "Hello".to_string()) .await?; assert_eq!(resp, "Hello"); diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/credential_issuer/credential_issuer_worker.rs b/implementations/rust/ockam/ockam_api/src/authenticator/credential_issuer/credential_issuer_worker.rs index 0bfaebae5af..4087cd18706 100644 --- a/implementations/rust/ockam/ockam_api/src/authenticator/credential_issuer/credential_issuer_worker.rs +++ b/implementations/rust/ockam/ockam_api/src/authenticator/credential_issuer/credential_issuer_worker.rs @@ -1,12 +1,11 @@ use core::time::Duration; -use minicbor::Decoder; use tracing::trace; use crate::authenticator::credential_issuer::CredentialIssuer; use crate::authenticator::direct::AccountAuthorityInfo; use crate::authenticator::AuthorityMembersRepository; use ockam::identity::{Credentials, Identifier, IdentitiesAttributes}; -use ockam_core::api::{Method, RequestHeader, Response}; +use ockam_core::api::{Method, Request, Response}; use ockam_core::compat::boxed::Box; use ockam_core::compat::sync::Arc; use ockam_core::compat::vec::Vec; @@ -49,13 +48,14 @@ impl CredentialIssuerWorker { #[ockam_core::worker] impl Worker for CredentialIssuerWorker { type Context = Context; - type Message = Vec; + type Message = Request>; async fn handle_message(&mut self, c: &mut Context, m: Routed) -> Result<()> { let secure_channel_info = match SecureChannelLocalInfo::find_info(m.local_message()) { Ok(secure_channel_info) => secure_channel_info, Err(_e) => { - let resp = Response::bad_request_no_request("secure channel required").to_vec()?; + let resp = + Response::bad_request_no_request("secure channel required").encode_body()?; c.send(m.return_route().clone(), resp).await?; return Ok(()); } @@ -63,27 +63,31 @@ impl Worker for CredentialIssuerWorker { let from = Identifier::from(secure_channel_info.their_identifier()); let return_route = m.return_route().clone(); - let body = m.into_body()?; - let mut dec = Decoder::new(&body); - let req: RequestHeader = dec.decode()?; + let request = m.into_body()?; + let header = request.header(); trace! { target: "credential_issuer", from = %from, - id = %req.id(), - method = ?req.method(), - path = %req.path(), - body = %req.has_body(), + id = %header.id(), + method = ?header.method(), + path = %header.path(), + body = %header.has_body(), "request" } - let res = match (req.method(), req.path()) { + let res = match (header.method(), header.path()) { (Some(Method::Post), "/") | (Some(Method::Post), "/credential") => { match self.credential_issuer.issue_credential(&from).await { - Ok(Some(crd)) => Response::ok().with_headers(&req).body(crd).to_vec()?, - Ok(None) => Response::forbidden(&req, "unauthorized member").to_vec()?, - Err(error) => Response::internal_error(&req, &error.to_string()).to_vec()?, + Ok(Some(crd)) => Response::ok() + .with_headers(header) + .body(crd) + .encode_body()?, + Ok(None) => Response::forbidden(header, "unauthorized member").encode_body()?, + Err(error) => { + Response::internal_error(header, &error.to_string()).encode_body()? + } } } - _ => Response::unknown_path(&req).to_vec()?, + _ => Response::unknown_path(header).encode_body()?, }; c.send(return_route, res).await diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/direct/client.rs b/implementations/rust/ockam/ockam_api/src/authenticator/direct/client.rs index 1ddae98aeb6..23c602f7dad 100644 --- a/implementations/rust/ockam/ockam_api/src/authenticator/direct/client.rs +++ b/implementations/rust/ockam/ockam_api/src/authenticator/direct/client.rs @@ -1,13 +1,14 @@ use miette::IntoDiagnostic; use std::collections::{BTreeMap, HashMap}; +use ockam::identity::models::IdentifierList; use ockam::identity::AttributesEntry; use ockam::identity::Identifier; use ockam_core::api::Request; use ockam_core::async_trait; use ockam_node::Context; -use crate::authenticator::direct::types::AddMember; +use crate::authenticator::direct::types::{AddMember, MemberList}; use crate::nodes::service::default_address::DefaultAddress; use crate::orchestrator::{AuthorityNodeClient, HasSecureClient}; @@ -90,12 +91,14 @@ impl Members for AuthorityNodeClient { async fn list_member_ids(&self, ctx: &Context) -> miette::Result> { let req = Request::get("/member_ids"); - self.get_secure_client() + let identifiers: IdentifierList = self + .get_secure_client() .ask(ctx, DefaultAddress::DIRECT_AUTHENTICATOR, req) .await .into_diagnostic()? .success() - .into_diagnostic() + .into_diagnostic()?; + Ok(identifiers.0) } async fn list_members( @@ -103,11 +106,13 @@ impl Members for AuthorityNodeClient { ctx: &Context, ) -> miette::Result> { let req = Request::get("/"); - self.get_secure_client() + let member_list: MemberList = self + .get_secure_client() .ask(ctx, DefaultAddress::DIRECT_AUTHENTICATOR, req) .await .into_diagnostic()? .success() - .into_diagnostic() + .into_diagnostic()?; + Ok(member_list.0) } } diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/direct/direct_authenticator_worker.rs b/implementations/rust/ockam/ockam_api/src/authenticator/direct/direct_authenticator_worker.rs index 4cf71640589..9fe6bc8f66f 100644 --- a/implementations/rust/ockam/ockam_api/src/authenticator/direct/direct_authenticator_worker.rs +++ b/implementations/rust/ockam/ockam_api/src/authenticator/direct/direct_authenticator_worker.rs @@ -1,14 +1,14 @@ use either::Either; -use minicbor::Decoder; use tracing::trace; +use ockam::identity::models::IdentifierList; use ockam::identity::{Identifier, IdentitiesAttributes}; -use ockam_core::api::{Method, RequestHeader, Response}; +use ockam_core::api::{Method, Request, Response}; use ockam_core::compat::sync::Arc; -use ockam_core::{Result, Routed, SecureChannelLocalInfo, Worker}; +use ockam_core::{Decodable, Result, Routed, SecureChannelLocalInfo, Worker}; use ockam_node::Context; -use crate::authenticator::direct::types::AddMember; +use crate::authenticator::direct::types::{AddMember, MemberList}; use crate::authenticator::direct::DirectAuthenticator; use crate::authenticator::AuthorityMembersRepository; @@ -38,14 +38,15 @@ impl DirectAuthenticatorWorker { #[ockam_core::worker] impl Worker for DirectAuthenticatorWorker { - type Message = Vec; + type Message = Request>; type Context = Context; async fn handle_message(&mut self, c: &mut Context, m: Routed) -> Result<()> { let secure_channel_info = match SecureChannelLocalInfo::find_info(m.local_message()) { Ok(secure_channel_info) => secure_channel_info, Err(_e) => { - let resp = Response::bad_request_no_request("secure channel required").to_vec()?; + let resp = + Response::bad_request_no_request("secure channel required").encode_body()?; c.send(m.return_route().clone(), resp).await?; return Ok(()); } @@ -53,29 +54,28 @@ impl Worker for DirectAuthenticatorWorker { let from = Identifier::from(secure_channel_info.their_identifier()); let return_route = m.return_route().clone(); - let body = m.into_body()?; - let mut dec = Decoder::new(&body); - let req: RequestHeader = dec.decode()?; + let request = m.into_body()?; + let (header, body) = request.into_parts(); trace! { target: "direct_authenticator", from = %from, - id = %req.id(), - method = ?req.method(), - path = %req.path(), - body = %req.has_body(), + id = %header.id(), + method = ?header.method(), + path = %header.path(), + body = %header.has_body(), "request" } - let path_segments = req.path_segments::<5>(); - let res = match (req.method(), path_segments.as_slice()) { + let path_segments = header.path_segments::<5>(); + let res: Response> = match (header.method(), path_segments.as_slice()) { (Some(Method::Post), [""]) | (Some(Method::Post), ["members"]) => { - let add: AddMember = dec.decode()?; + let add = AddMember::decode(&body.unwrap_or_default())?; let res = self .authenticator .add_member(&from, add.member(), add.attributes()) .await?; match res { - Either::Left(_) => Response::ok().with_headers(&req).to_vec()?, - Either::Right(error) => Response::forbidden(&req, &error.0).to_vec()?, + Either::Left(_) => Response::ok().with_headers(&header).encode_body()?, + Either::Right(error) => Response::forbidden(&header, &error.0).encode_body()?, } } (Some(Method::Get), ["member_ids"]) => { @@ -83,19 +83,23 @@ impl Worker for DirectAuthenticatorWorker { match res { Either::Left(entries) => { let ids: Vec = entries.into_keys().collect(); - Response::ok().with_headers(&req).body(ids).to_vec()? + Response::ok() + .with_headers(&header) + .body(IdentifierList(ids)) + .encode_body()? } - Either::Right(error) => Response::forbidden(&req, &error.0).to_vec()?, + Either::Right(error) => Response::forbidden(&header, &error.0).encode_body()?, } } (Some(Method::Get), [""]) | (Some(Method::Get), ["members"]) => { let res = self.authenticator.list_members(&from).await?; match res { - Either::Left(entries) => { - Response::ok().with_headers(&req).body(entries).to_vec()? - } - Either::Right(error) => Response::forbidden(&req, &error.0).to_vec()?, + Either::Left(entries) => Response::ok() + .with_headers(&header) + .body(MemberList(entries)) + .encode_body()?, + Either::Right(error) => Response::forbidden(&header, &error.0).encode_body()?, } } (Some(Method::Get), [id]) | (Some(Method::Get), ["members", id]) => { @@ -103,15 +107,18 @@ impl Worker for DirectAuthenticatorWorker { let res = self.authenticator.show_member(&from, &identifier).await?; match res { - Either::Left(body) => Response::ok().with_headers(&req).body(body).to_vec()?, - Either::Right(error) => Response::forbidden(&req, &error.0).to_vec()?, + Either::Left(body) => Response::ok() + .with_headers(&header) + .body(body) + .encode_body()?, + Either::Right(error) => Response::forbidden(&header, &error.0).encode_body()?, } } (Some(Method::Delete), ["members"]) => { let res = self.authenticator.delete_all_members(&from).await?; match res { - Either::Left(_) => Response::ok().with_headers(&req).to_vec()?, - Either::Right(error) => Response::forbidden(&req, &error.0).to_vec()?, + Either::Left(_) => Response::ok().with_headers(&header).encode_body()?, + Either::Right(error) => Response::forbidden(&header, &error.0).encode_body()?, } } (Some(Method::Delete), [id]) | (Some(Method::Delete), ["members", id]) => { @@ -119,11 +126,11 @@ impl Worker for DirectAuthenticatorWorker { let res = self.authenticator.delete_member(&from, &identifier).await?; match res { - Either::Left(_) => Response::ok().with_headers(&req).to_vec()?, - Either::Right(error) => Response::forbidden(&req, &error.0).to_vec()?, + Either::Left(_) => Response::ok().with_headers(&header).encode_body()?, + Either::Right(error) => Response::forbidden(&header, &error.0).encode_body()?, } } - _ => Response::unknown_path(&req).to_vec()?, + _ => Response::unknown_path(&header).encode_body()?, }; c.send(return_route, res).await?; diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/direct/types.rs b/implementations/rust/ockam/ockam_api/src/authenticator/direct/types.rs index 39e03772b60..38c9364b679 100644 --- a/implementations/rust/ockam/ockam_api/src/authenticator/direct/types.rs +++ b/implementations/rust/ockam/ockam_api/src/authenticator/direct/types.rs @@ -1,9 +1,11 @@ use minicbor::{CborLen, Decode, Encode}; -use ockam::identity::Identifier; -use std::collections::BTreeMap; +use ockam::identity::{AttributesEntry, Identifier}; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; +use std::collections::{BTreeMap, HashMap}; use std::time::Duration; -#[derive(Debug, Encode, Decode, CborLen)] +#[derive(Debug, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct AddMember { @@ -11,6 +13,18 @@ pub struct AddMember { #[b(2)] attributes: BTreeMap, } +impl Encodable for AddMember { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for AddMember { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl AddMember { pub fn new(member: Identifier) -> Self { AddMember { @@ -33,7 +47,7 @@ impl AddMember { } } -#[derive(Debug, Encode, Decode, CborLen)] +#[derive(Debug, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateToken { @@ -42,6 +56,18 @@ pub struct CreateToken { #[n(3)] ttl_count: Option, } +impl Encodable for CreateToken { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateToken { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateToken { #[allow(clippy::new_without_default)] pub fn new() -> Self { @@ -79,3 +105,19 @@ impl CreateToken { self.ttl_secs } } + +#[derive(Clone, Eq, PartialEq, Encode, Decode, CborLen, Message)] +#[cbor(transparent)] +pub struct MemberList(#[n(0)] pub HashMap); + +impl Encodable for MemberList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for MemberList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor_worker.rs b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor_worker.rs index 0eb9dffe9e5..1d31e72265f 100644 --- a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor_worker.rs +++ b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/acceptor_worker.rs @@ -2,11 +2,10 @@ use crate::authenticator::enrollment_tokens::EnrollmentTokenAcceptor; use crate::authenticator::one_time_code::OneTimeCode; use crate::authenticator::{AuthorityEnrollmentTokenRepository, AuthorityMembersRepository}; use either::Either; -use minicbor::Decoder; use ockam::identity::Identifier; -use ockam_core::api::{Method, RequestHeader, Response}; +use ockam_core::api::{Method, Request, Response}; use ockam_core::compat::sync::Arc; -use ockam_core::{Result, Routed, SecureChannelLocalInfo, Worker}; +use ockam_core::{Decodable, Result, Routed, SecureChannelLocalInfo, Worker}; use ockam_node::Context; use tracing::trace; @@ -29,13 +28,14 @@ impl EnrollmentTokenAcceptorWorker { #[ockam_core::worker] impl Worker for EnrollmentTokenAcceptorWorker { type Context = Context; - type Message = Vec; + type Message = Request>; async fn handle_message(&mut self, c: &mut Context, m: Routed) -> Result<()> { let secure_channel_info = match SecureChannelLocalInfo::find_info(m.local_message()) { Ok(secure_channel_info) => secure_channel_info, Err(_e) => { - let resp = Response::bad_request_no_request("secure channel required").to_vec()?; + let resp = + Response::bad_request_no_request("secure channel required").encode_body()?; c.send(m.return_route().clone(), resp).await?; return Ok(()); } @@ -43,28 +43,27 @@ impl Worker for EnrollmentTokenAcceptorWorker { let from = Identifier::from(secure_channel_info.their_identifier()); let return_route = m.return_route().clone(); - let body = m.into_body()?; - let mut dec = Decoder::new(&body); - let req: RequestHeader = dec.decode()?; + let request = m.into_body()?; + let (header, body) = request.into_parts(); trace! { target: "enrollment_token_acceptor", from = %from, - id = %req.id(), - method = ?req.method(), - path = %req.path(), - body = %req.has_body(), + id = %header.id(), + method = ?header.method(), + path = %header.path(), + body = %header.has_body(), "request" } - let res = match (req.method(), req.path()) { + let res = match (header.method(), header.path()) { (Some(Method::Post), "/") | (Some(Method::Post), "/credential") => { - let otc: OneTimeCode = dec.decode()?; + let otc = OneTimeCode::decode(&body.unwrap_or_default())?; let res = self.acceptor.accept_token(otc, &from).await?; match res { - Either::Left(_) => Response::ok().with_headers(&req).to_vec()?, - Either::Right(error) => Response::forbidden(&req, &error.0).to_vec()?, + Either::Left(_) => Response::ok().with_headers(&header).encode_body()?, + Either::Right(error) => Response::forbidden(&header, &error.0).encode_body()?, } } - _ => Response::unknown_path(&req).to_vec()?, + _ => Response::unknown_path(&header).encode_body()?, }; c.send(return_route, res).await } diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/issuer_worker.rs b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/issuer_worker.rs index 69ba0c47e25..f2cdcaad4c4 100644 --- a/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/issuer_worker.rs +++ b/implementations/rust/ockam/ockam_api/src/authenticator/enrollment_tokens/issuer_worker.rs @@ -1,12 +1,11 @@ use either::Either; -use minicbor::Decoder; use tracing::trace; use ockam::identity::{Identifier, IdentitiesAttributes}; -use ockam_core::api::{Method, RequestHeader, Response}; +use ockam_core::api::{Method, Request, Response}; use ockam_core::compat::sync::Arc; use ockam_core::compat::time::Duration; -use ockam_core::{Result, Routed, SecureChannelLocalInfo, Worker}; +use ockam_core::{Decodable, Result, Routed, SecureChannelLocalInfo, Worker}; use ockam_node::Context; use crate::authenticator::direct::types::CreateToken; @@ -41,13 +40,14 @@ impl EnrollmentTokenIssuerWorker { #[ockam_core::worker] impl Worker for EnrollmentTokenIssuerWorker { type Context = Context; - type Message = Vec; + type Message = Request>; async fn handle_message(&mut self, c: &mut Context, m: Routed) -> Result<()> { let secure_channel_info = match SecureChannelLocalInfo::find_info(m.local_message()) { Ok(secure_channel_info) => secure_channel_info, Err(_e) => { - let resp = Response::bad_request_no_request("secure channel required").to_vec()?; + let resp = + Response::bad_request_no_request("secure channel required").encode_body()?; c.send(m.return_route().clone(), resp).await?; return Ok(()); } @@ -55,21 +55,20 @@ impl Worker for EnrollmentTokenIssuerWorker { let from = Identifier::from(secure_channel_info.their_identifier()); let return_route = m.return_route().clone(); - let body = m.into_body()?; - let mut dec = Decoder::new(&body); - let req: RequestHeader = dec.decode()?; + let request = m.into_body()?; + let (header, body) = request.into_parts(); trace! { target: "enrollment_token_issuer", from = %from, - id = %req.id(), - method = ?req.method(), - path = %req.path(), - body = %req.has_body(), + id = %header.id(), + method = ?header.method(), + path = %header.path(), + body = %header.has_body(), "request" } - let res = match (req.method(), req.path()) { + let res = match (header.method(), header.path()) { (Some(Method::Post), "/") | (Some(Method::Post), "/tokens") => { - let att: CreateToken = dec.decode()?; + let att: CreateToken = CreateToken::decode(&body.unwrap_or_default())?; let duration = att.ttl_secs().map(Duration::from_secs); let ttl_count = att.ttl_count(); @@ -79,11 +78,14 @@ impl Worker for EnrollmentTokenIssuerWorker { .await?; match res { - Either::Left(otc) => Response::ok().with_headers(&req).body(&otc).to_vec()?, - Either::Right(error) => Response::forbidden(&req, &error.0).to_vec()?, + Either::Left(otc) => Response::ok() + .with_headers(&header) + .body(otc) + .encode_body()?, + Either::Right(error) => Response::forbidden(&header, &error.0).encode_body()?, } } - _ => Response::unknown_path(&req).to_vec()?, + _ => Response::unknown_path(&header).encode_body()?, }; c.send(return_route, res).await } diff --git a/implementations/rust/ockam/ockam_api/src/authenticator/one_time_code.rs b/implementations/rust/ockam/ockam_api/src/authenticator/one_time_code.rs index ad8d439a048..792c6982a57 100644 --- a/implementations/rust/ockam/ockam_api/src/authenticator/one_time_code.rs +++ b/implementations/rust/ockam/ockam_api/src/authenticator/one_time_code.rs @@ -1,25 +1,38 @@ use core::str::FromStr; use minicbor::bytes::ByteArray; use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; use ockam_core::compat::rand; use ockam_core::compat::rand::RngCore; use ockam_core::compat::string::String; use ockam_core::errcode::{Kind, Origin}; -use ockam_core::Error; -use ockam_core::Result; +use ockam_core::{cbor_encode_preallocate, Result}; +use ockam_core::{Decodable, Encodable, Encoded, Error}; use serde::{Deserialize, Serialize}; use std::fmt::{Debug, Formatter}; /// A one-time code can be used to enroll /// a node with some authenticated attributes /// It can be retrieved with a command like `ockam project ticket --attribute component=control` -#[derive(Clone, Encode, Decode, CborLen, PartialEq, Eq, Copy)] +#[derive(Clone, Encode, Decode, CborLen, PartialEq, Eq, Copy, Message)] #[rustfmt::skip] #[cbor(map)] pub struct OneTimeCode { #[n(1)] code: ByteArray<32>, } +impl Encodable for OneTimeCode { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for OneTimeCode { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl Debug for OneTimeCode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str("{ONE_TIME_CODE}") diff --git a/implementations/rust/ockam/ockam_api/src/enroll/enrollment.rs b/implementations/rust/ockam/ockam_api/src/enroll/enrollment.rs index c16327097ae..04def5b1b77 100644 --- a/implementations/rust/ockam/ockam_api/src/enroll/enrollment.rs +++ b/implementations/rust/ockam/ockam_api/src/enroll/enrollment.rs @@ -126,7 +126,7 @@ impl Enrollment for SecureClient { ctx: &Context, token: &OneTimeCode, ) -> miette::Result { - let req = Request::post("/").body(token); + let req = Request::post("/").body(*token); trace!(target: TARGET, "present a token"); match self .tell(ctx, DefaultAddress::ENROLLMENT_TOKEN_ACCEPTOR, req) diff --git a/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/node_service.rs b/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/node_service.rs index eda56daaf7d..6642c61dbd0 100644 --- a/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/node_service.rs +++ b/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/node_service.rs @@ -1,16 +1,16 @@ use crate::influxdb::influxdb_api_client::InfluxDBApiClient; use crate::influxdb::lease_issuer::processor::InfluxDBTokenLessorProcessor; use crate::influxdb::lease_issuer::worker::InfluxDBTokenLessorWorker; -use crate::influxdb::lease_token::LeaseToken; +use crate::influxdb::lease_token::{LeaseToken, LeaseTokenList}; use crate::nodes::models::services::{DeleteServiceRequest, StartServiceRequest}; -use crate::nodes::service::messages::Messages; use crate::nodes::{InMemoryNode, NodeManagerWorker}; use crate::{ApiError, DefaultAddress}; use miette::IntoDiagnostic; use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; use ockam_abac::{Action, PolicyExpression, Resource, ResourceType}; use ockam_core::api::{Error, Request, Response}; -use ockam_core::{async_trait, Address}; +use ockam_core::{async_trait, cbor_encode_preallocate, Address, Decodable, Encodable, Encoded}; use ockam_multiaddr::MultiAddr; use ockam_node::{Context, ProcessorBuilder, WorkerBuilder}; use std::cmp::Reverse; @@ -128,7 +128,7 @@ impl InMemoryNode { } } -#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq)] +#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq, Message)] #[rustfmt::skip] #[cbor(map)] pub struct StartInfluxDBLeaseIssuerRequest { @@ -140,6 +140,18 @@ pub struct StartInfluxDBLeaseIssuerRequest { #[n(6)] pub policy_expression: Option, } +impl Encodable for StartInfluxDBLeaseIssuerRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for StartInfluxDBLeaseIssuerRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + #[async_trait] pub trait InfluxDBTokenLessorNodeServiceTrait { async fn create_token(&self, ctx: &Context, at: &MultiAddr) -> miette::Result; @@ -164,9 +176,12 @@ pub trait InfluxDBTokenLessorNodeServiceTrait { #[async_trait] impl InfluxDBTokenLessorNodeServiceTrait for InMemoryNode { async fn create_token(&self, ctx: &Context, at: &MultiAddr) -> miette::Result { - let req = Request::post("/").to_vec().into_diagnostic()?; - let bytes = self.send_message(ctx, at, req, None).await?; - Response::parse_response_body::(bytes.as_slice()).into_diagnostic() + let client = self.node_manager.make_client(ctx, at, None).await?; + let reply = client + .ask(ctx, Request::post("/")) + .await + .into_diagnostic()?; + Ok(reply.success()?) } async fn get_token( @@ -175,11 +190,12 @@ impl InfluxDBTokenLessorNodeServiceTrait for InMemoryNode { at: &MultiAddr, token_id: &str, ) -> miette::Result { - let req = Request::get(format!("/{token_id}")) - .to_vec() + let client = self.node_manager.make_client(ctx, at, None).await?; + let reply = client + .ask(ctx, Request::get(format!("/{token_id}"))) + .await .into_diagnostic()?; - let bytes = self.send_message(ctx, at, req, None).await?; - Response::parse_response_body::(bytes.as_slice()).into_diagnostic() + Ok(reply.success()?) } async fn revoke_token( @@ -188,19 +204,22 @@ impl InfluxDBTokenLessorNodeServiceTrait for InMemoryNode { at: &MultiAddr, token_id: &str, ) -> miette::Result<()> { - let req = Request::delete(format!("/{token_id}")) - .to_vec() + let client = self.node_manager.make_client(ctx, at, None).await?; + let reply = client + .tell(ctx, Request::delete(format!("/{token_id}"))) + .await .into_diagnostic()?; - let bytes = self.send_message(ctx, at, req, None).await?; - Response::parse_response_reply_with_empty_body(bytes.as_slice()) - .and_then(|r| r.success()) - .into_diagnostic() + Ok(reply.success()?) } async fn list_tokens(&self, ctx: &Context, at: &MultiAddr) -> miette::Result> { - let req = Request::get("/").to_vec().into_diagnostic()?; - let bytes = self.send_message(ctx, at, req, None).await?; - Response::parse_response_body::>(bytes.as_slice()).into_diagnostic() + let client = self.node_manager.make_client(ctx, at, None).await?; + let lease_token_list: LeaseTokenList = client + .ask(ctx, Request::get("/")) + .await + .into_diagnostic()? + .miette_success("lease token list")?; + Ok(lease_token_list.0) } } diff --git a/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/worker.rs b/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/worker.rs index 6c870c88d16..c52fd91be63 100644 --- a/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/worker.rs +++ b/implementations/rust/ockam/ockam_api/src/influxdb/lease_issuer/worker.rs @@ -2,13 +2,12 @@ use crate::influxdb::influxdb_api_client::{ InfluxDBApi, InfluxDBApiClient, InfluxDBCreateTokenRequest, }; use crate::influxdb::lease_issuer::node_service::InfluxDBTokenLessorState; -use crate::influxdb::lease_token::LeaseToken; +use crate::influxdb::lease_token::{LeaseToken, LeaseTokenList}; use crate::nodes::service::encode_response; use crate::ApiError; -use minicbor::Decoder; use ockam::identity::Identifier; use ockam_core::api::Method::{Delete, Get, Post}; -use ockam_core::api::{RequestHeader, Response}; +use ockam_core::api::{Request, Response}; use ockam_core::{async_trait, Address, Routed, SecureChannelLocalInfo, Worker}; use ockam_node::Context; use std::cmp::Reverse; @@ -47,52 +46,51 @@ impl InfluxDBTokenLessorWorker { Ok(_self) } - #[instrument(skip_all, fields(method = ?req.method(), path = req.path()))] + #[instrument(skip_all, fields(method = ?request.header().method(), path = request.header().path()))] async fn handle_request( &mut self, _ctx: &mut Context, requester: &Identifier, - req: &RequestHeader, - _dec: &mut Decoder<'_>, - ) -> ockam_core::Result> { + request: Request>, + ) -> ockam_core::Result>> { + let header = request.header(); debug! { - id = %req.id(), - method = ?req.method(), - path = %req.path(), - body = %req.has_body(), + id = %header.id(), + method = ?header.method(), + path = %header.path(), + body = %header.has_body(), "request" } - let path = req.path(); - let path_segments = req.path_segments::<5>(); - let method = match req.method() { + let path = header.path(); + let path_segments = header.path_segments::<5>(); + let method = match header.method() { Some(m) => m, None => todo!(), }; debug!(path_segments = ?path_segments.as_slice().iter().map(|s| s.to_string()).collect::>(), "Handling request"); // [""] correspond to the root "/" path - let r = match (method, path_segments.as_slice()) { - (Post, [""]) => encode_response(req, self.create_token(requester).await)?, - (Get, [""]) => encode_response(req, self.list_tokens(requester).await)?, - (Get, [token_id]) => encode_response(req, self.get_token(requester, token_id).await)?, + match (method, path_segments.as_slice()) { + (Post, [""]) => encode_response(header, self.create_token(requester).await), + (Get, [""]) => encode_response(header, self.list_tokens(requester).await), + (Get, [token_id]) => encode_response(header, self.get_token(requester, token_id).await), (Delete, [token_id]) => { - encode_response(req, self.revoke_token(requester, token_id).await)? + encode_response(header, self.revoke_token(requester, token_id).await) } // ==*== Catch-all for Unimplemented APIs ==*== _ => { warn!(%method, %path, "Called invalid endpoint"); - Response::bad_request(req, &format!("Invalid endpoint: {} {}", method, path)) - .to_vec()? + Response::bad_request(header, &format!("Invalid endpoint: {} {}", method, path)) + .encode_body() } - }; - Ok(r) + } } } #[ockam::worker] impl Worker for InfluxDBTokenLessorWorker { - type Message = Vec; + type Message = Request>; type Context = Context; async fn shutdown(&mut self, _ctx: &mut Self::Context) -> ockam_core::Result<()> { @@ -104,45 +102,40 @@ impl Worker for InfluxDBTokenLessorWorker { async fn handle_message( &mut self, ctx: &mut Context, - msg: Routed>, + msg: Routed>>, ) -> ockam_core::Result<()> { let requester_identifier = Identifier::from( SecureChannelLocalInfo::find_info(msg.local_message())?.their_identifier(), ); let return_route = msg.return_route().clone(); - let body = msg.into_body()?; - let mut dec = Decoder::new(&body); - let req: RequestHeader = match dec.decode() { - Ok(r) => r, - Err(e) => { - error!("Failed to decode request: {:?}", e); - return Ok(()); - } - }; - + let request = msg.into_body()?; + let header = request.header().clone(); let r = match self - .handle_request(ctx, &requester_identifier, &req, &mut dec) + .handle_request(ctx, &requester_identifier, request) .await { Ok(r) => r, Err(err) => { error! { - re = %req.id(), - method = ?req.method(), - path = %req.path(), + re = %header.id(), + method = ?header.method(), + path = %header.path(), code = %err.code(), cause = ?err.source(), "failed to handle request" } - Response::internal_error(&req, &format!("failed to handle request: {err} {req:?}")) - .to_vec()? + Response::internal_error( + &header, + &format!("failed to handle request: {err} {header:?}"), + ) + .encode_body()? } }; debug! { - re = %req.id(), - method = ?req.method(), - path = %req.path(), + re = %header.id(), + method = ?header.method(), + path = %header.path(), "responding" } ctx.send(return_route, r).await @@ -171,7 +164,7 @@ pub trait InfluxDBTokenLessorWorkerApi { async fn list_tokens( &self, requester: &Identifier, - ) -> Result>, Response>; + ) -> Result, Response>; } #[async_trait] @@ -296,7 +289,7 @@ impl InfluxDBTokenLessorWorkerApi for InfluxDBTokenLessorWorker { async fn list_tokens( &self, requester: &Identifier, - ) -> Result>, Response> { + ) -> Result, Response> { debug!(%requester, "Listing tokens"); let influxdb_tokens = { let state = self.state.read().await; @@ -328,6 +321,6 @@ impl InfluxDBTokenLessorWorkerApi for InfluxDBTokenLessorWorker { state.active_tokens = lease_tokens.iter().map(|t| Reverse(t.clone())).collect(); } info!("Found {} tokens", lease_tokens.len()); - Ok(Response::ok().body(lease_tokens)) + Ok(Response::ok().body(LeaseTokenList(lease_tokens))) } } diff --git a/implementations/rust/ockam/ockam_api/src/influxdb/lease_token.rs b/implementations/rust/ockam/ockam_api/src/influxdb/lease_token.rs index aadb359ae04..36dffac617a 100644 --- a/implementations/rust/ockam/ockam_api/src/influxdb/lease_token.rs +++ b/implementations/rust/ockam/ockam_api/src/influxdb/lease_token.rs @@ -4,14 +4,16 @@ use crate::terminal::fmt; use crate::ApiError; use minicbor::{CborLen, Decode, Encode}; use ockam::identity::Identifier; +use ockam::Message; use ockam_core::compat::fmt::Error as FmtError; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use serde::{Deserialize, Serialize}; use std::cmp::PartialEq; use std::fmt::{Display, Formatter}; use strum::{Display, EnumString}; use time::OffsetDateTime; -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone, Message)] #[cbor(map)] pub struct LeaseToken { #[cbor(n(1))] @@ -33,6 +35,34 @@ pub struct LeaseToken { pub status: TokenStatus, } +impl Encodable for LeaseToken { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for LeaseToken { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone, Message)] +#[cbor(transparent)] +pub struct LeaseTokenList(#[n(0)] pub Vec); + +impl Encodable for LeaseTokenList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for LeaseTokenList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(LeaseTokenList(minicbor::decode(e)?)) + } +} + #[cfg(test)] impl Default for LeaseToken { fn default() -> Self { diff --git a/implementations/rust/ockam/ockam_api/src/influxdb/portal.rs b/implementations/rust/ockam/ockam_api/src/influxdb/portal.rs index b696bdfdfbe..0e61a56d122 100644 --- a/implementations/rust/ockam/ockam_api/src/influxdb/portal.rs +++ b/implementations/rust/ockam/ockam_api/src/influxdb/portal.rs @@ -10,12 +10,13 @@ use crate::{ApiError, DefaultAddress}; use minicbor::{CborLen, Decode, Encode}; use ockam::flow_control::FlowControls; use ockam::identity::Identifier; +use ockam::Message; use ockam::{Address, Context, Result}; use ockam_abac::PolicyExpression; use ockam_abac::{Action, Resource, ResourceType}; use ockam_core::api::{Error, Reply, Request, Response}; -use ockam_core::async_trait; -use ockam_core::route; +use ockam_core::{async_trait, Decodable, Encodable, Encoded}; +use ockam_core::{cbor_encode_preallocate, route}; use ockam_multiaddr::proto::Service; use ockam_multiaddr::MultiAddr; use ockam_transport_core::HostnamePort; @@ -396,7 +397,7 @@ impl InfluxDBPortals for BackgroundNodeClient { } /// Request body to create an influxdb inlet -#[derive(Clone, Debug, Encode, Decode, CborLen)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateInfluxDBInlet { @@ -407,6 +408,18 @@ pub struct CreateInfluxDBInlet { #[n(3)] pub(crate) lease_issuer_address: Option, } +impl Encodable for CreateInfluxDBInlet { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateInfluxDBInlet { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateInfluxDBInlet { pub fn new( tcp_inlet: CreateInlet, @@ -422,7 +435,7 @@ impl CreateInfluxDBInlet { } /// Request body to create an influxdb outlet -#[derive(Clone, Debug, Encode, Decode, CborLen)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateInfluxDBOutlet { @@ -430,6 +443,18 @@ pub struct CreateInfluxDBOutlet { #[n(2)] pub(crate) influxdb_config: InfluxDBOutletConfig, } +impl Encodable for CreateInfluxDBOutlet { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateInfluxDBOutlet { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + #[derive(Clone, Debug, Encode, Decode, CborLen)] #[rustfmt::skip] #[cbor(map)] diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/credentials.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/credentials.rs index 95e1279d3cd..9861d323140 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/credentials.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/credentials.rs @@ -1,9 +1,11 @@ //! Credential request/response types use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use ockam_multiaddr::MultiAddr; -#[derive(Clone, Debug, Encode, Decode, CborLen)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct GetCredentialRequest { @@ -11,6 +13,18 @@ pub struct GetCredentialRequest { #[n(2)] pub identity_name: Option, } +impl Encodable for GetCredentialRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for GetCredentialRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl GetCredentialRequest { pub fn new(overwrite: bool, identity_name: Option) -> Self { Self { diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/flow_controls.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/flow_controls.rs index db29b152018..c90ccd8de6d 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/flow_controls.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/flow_controls.rs @@ -1,8 +1,10 @@ use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; use ockam_core::flow_control::FlowControlId; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use ockam_multiaddr::MultiAddr; -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct AddConsumer { @@ -10,6 +12,18 @@ pub struct AddConsumer { #[n(2)] address: MultiAddr, } +impl Encodable for AddConsumer { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for AddConsumer { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl AddConsumer { pub fn new(flow_control_id: FlowControlId, address: MultiAddr) -> Self { Self { diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/node.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/node.rs index 4b844c996fc..bd30cec5aad 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/node.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/node.rs @@ -9,15 +9,16 @@ use crate::output::Output; use crate::terminal::fmt; use minicbor::{CborLen, Decode, Encode}; use ockam::identity::{Identifier, SecureChannelListener}; -use ockam_core::Result; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded, Result}; use ockam_multiaddr::MultiAddr; use serde::Serialize; use crate::config::lookup::InternetAddress; +use ockam::Message; use std::fmt::{Display, Formatter}; /// Response body for a node status request -#[derive(Debug, Clone, Serialize, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Serialize, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct NodeStatus { @@ -26,6 +27,18 @@ pub struct NodeStatus { #[n(3)] pub process_status: NodeProcessStatus, } +impl Encodable for NodeStatus { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for NodeStatus { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl NodeStatus { pub fn new( name: impl Into, @@ -50,7 +63,7 @@ impl From<&NodeInfo> for NodeStatus { } } -#[derive(Debug, Serialize, Encode, Decode, CborLen)] +#[derive(Debug, Serialize, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct NodeResources { @@ -68,6 +81,18 @@ pub struct NodeResources { #[n(11)] pub services: Vec, } +impl Encodable for NodeResources { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for NodeResources { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + #[allow(clippy::too_many_arguments)] impl NodeResources { pub fn from_parts( diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/policies.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/policies.rs index 55dc83a6e0a..6090c2f23b6 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/policies.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/policies.rs @@ -1,14 +1,15 @@ use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; use ockam_abac::{ Action, Expr, PolicyExpression, ResourceName, ResourcePolicy, ResourceType, ResourceTypePolicy, }; use ockam_core::errcode::{Kind, Origin}; -use ockam_core::Error; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded, Error}; use serde::Serialize; use std::fmt::{Display, Formatter}; use std::str::FromStr; -#[derive(Clone, Debug, Encode, Decode, CborLen)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct SetPolicyRequest { @@ -16,6 +17,18 @@ pub struct SetPolicyRequest { #[n(2)] pub expression: PolicyExpression, } +impl Encodable for SetPolicyRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for SetPolicyRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl SetPolicyRequest { pub fn new(resource: ResourceTypeOrName, expression: PolicyExpression) -> Self { Self { @@ -25,7 +38,7 @@ impl SetPolicyRequest { } } -#[derive(Debug, Encode, Decode, CborLen, PartialEq, Eq)] +#[derive(Debug, Encode, Decode, CborLen, PartialEq, Eq, Message)] #[rustfmt::skip] #[cbor(map)] pub struct PoliciesList { @@ -33,6 +46,18 @@ pub struct PoliciesList { #[n(2)] resource_type_policies: Vec, } +impl Encodable for PoliciesList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for PoliciesList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl PoliciesList { pub fn new( resource_policies: Vec, @@ -63,7 +88,7 @@ impl PoliciesList { /// A view for the specific policy types returned by policies repositories. This is used /// to simplify the type returned by the NodeManager in the api requests. -#[derive(Debug, Encode, Decode, CborLen, Serialize, PartialEq, Eq)] +#[derive(Debug, Encode, Decode, CborLen, Serialize, PartialEq, Eq, Message)] #[rustfmt::skip] #[cbor(map)] pub struct Policy { @@ -72,6 +97,18 @@ pub struct Policy { #[n(3)] expression: Expr, } +impl Encodable for Policy { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for Policy { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl Policy { pub fn resource(&self) -> &ResourceTypeOrName { &self.resource @@ -111,7 +148,7 @@ impl From for Policy { /// user-defined and can be anything. /// /// This type is used at the top level of the NodeManager to reduce the number of endpoints. -#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, PartialEq, Eq, Message)] #[serde(untagged)] #[rustfmt::skip] pub enum ResourceTypeOrName { @@ -119,6 +156,34 @@ pub enum ResourceTypeOrName { #[n(2)] Name(#[n(1)] ResourceName), } +impl Encodable for ResourceTypeOrName { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ResourceTypeOrName { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + +#[derive(Clone, Debug, Encode, Decode, CborLen, PartialEq, Eq, Message)] +#[cbor(transparent)] +pub struct ResourceTypeOrNameOption(#[n(0)] pub Option); + +impl Encodable for ResourceTypeOrNameOption { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ResourceTypeOrNameOption { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl ResourceTypeOrName { pub fn new( resource_type: Option<&ResourceType>, diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/portal.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/portal.rs index bcffc185474..695e33747df 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/portal.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/portal.rs @@ -4,24 +4,26 @@ use std::fmt::{Display, Formatter}; use std::sync::Arc; use std::time::Duration; -use minicbor::{CborLen, Decode, Encode}; -use ockam::identity::Identifier; -use ockam::transport::HostnamePort; -use ockam_abac::PolicyExpression; -use ockam_core::{Address, IncomingAccessControl, OutgoingAccessControl, Route}; -use ockam_multiaddr::MultiAddr; -use serde::{Deserialize, Serialize}; - use crate::colors::{color_primary, color_primary_alt}; use crate::error::ApiError; - use crate::output::Output; use crate::session::connection_status::ConnectionStatus; use crate::terminal::fmt; use crate::ReverseLocalConverter; +use minicbor::{CborLen, Decode, Encode}; +use ockam::identity::Identifier; +use ockam::transport::HostnamePort; +use ockam::Message; +use ockam_abac::PolicyExpression; +use ockam_core::{ + cbor_encode_preallocate, Address, Decodable, Encodable, Encoded, IncomingAccessControl, + OutgoingAccessControl, Route, +}; +use ockam_multiaddr::MultiAddr; +use serde::{Deserialize, Serialize}; /// Request body to create an inlet -#[derive(Clone, Debug, Encode, Decode, CborLen)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateInlet { @@ -63,6 +65,18 @@ pub struct CreateInlet { #[n(15)] pub(crate) enable_nagle: bool, } +impl Encodable for CreateInlet { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateInlet { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateInlet { #[allow(clippy::too_many_arguments)] pub fn via_project( @@ -163,7 +177,7 @@ impl CreateInlet { } /// Request body to create an outlet -#[derive(Clone, Debug, Encode, Decode, CborLen)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateOutlet { @@ -188,6 +202,18 @@ pub struct CreateOutlet { #[n(8)] pub(crate) enable_nagle: bool, } +impl Encodable for CreateOutlet { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateOutlet { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateOutlet { pub fn new( hostname_port: HostnamePort, @@ -216,7 +242,7 @@ impl CreateOutlet { } /// Response body when interacting with a portal endpoint -#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, Message)] #[rustfmt::skip] #[cbor(map)] pub struct InletStatus { @@ -231,6 +257,18 @@ pub struct InletStatus { #[n(8)] pub privileged: bool, } +impl Encodable for InletStatus { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for InletStatus { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl InletStatus { #[allow(clippy::too_many_arguments)] pub fn new( @@ -302,8 +340,23 @@ impl Output for InletStatus { } } +#[derive(Encode, Decode, CborLen, Debug, Default, Clone, Message)] +pub struct InletStatusList(#[n(0)] pub Vec); + +impl Encodable for InletStatusList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for InletStatusList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + /// Response body when interacting with a portal endpoint -#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, Deserialize, PartialEq, Message)] #[rustfmt::skip] #[cbor(map)] pub struct OutletStatus { @@ -314,6 +367,18 @@ pub struct OutletStatus { #[n(4)] pub privileged: bool, } +impl Encodable for OutletStatus { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for OutletStatus { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl OutletStatus { pub fn new( to: HostnamePort, @@ -368,6 +433,22 @@ impl Display for OutletStatus { } } +#[derive(Encode, Decode, CborLen, Debug, Default, Clone, Message)] +#[cbor(transparent)] +pub struct OutletStatusList(#[n(0)] pub Vec); + +impl Encodable for OutletStatusList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for OutletStatusList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl Output for OutletStatus { fn item(&self) -> Result { Ok(self.padded_display()) diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/relay.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/relay.rs index 8dfc7c90eb6..adc169f10e4 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/relay.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/relay.rs @@ -4,7 +4,9 @@ use std::fmt::Display; use ockam::identity::Identifier; use ockam::remote::RemoteRelayInfo; use ockam::route; +use ockam::Message; use ockam_core::flow_control::FlowControlId; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use ockam_multiaddr::MultiAddr; use crate::colors::color_primary; @@ -21,7 +23,7 @@ pub enum ReturnTiming { } /// Request body when instructing a node to create a relay -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateRelay { @@ -39,6 +41,18 @@ pub struct CreateRelay { #[n(5)] pub(crate) return_timing: ReturnTiming, } +impl Encodable for CreateRelay { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateRelay { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateRelay { pub fn new( address: MultiAddr, @@ -78,7 +92,7 @@ impl CreateRelay { } /// Response body when creating a relay -#[derive(Debug, Clone, Encode, Decode, CborLen, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Encode, Decode, CborLen, serde::Serialize, serde::Deserialize, Message)] #[rustfmt::skip] #[cbor(map)] pub struct RelayInfo { @@ -92,6 +106,18 @@ pub struct RelayInfo { #[n(8)] last_failure: Option, } +impl Encodable for RelayInfo { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for RelayInfo { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl RelayInfo { pub fn new( destination_address: MultiAddr, @@ -219,3 +245,18 @@ impl Output for RelayInfo { Ok(self.padded_display()) } } + +#[derive(Encode, Decode, CborLen, Debug, Default, Clone, Message)] +pub struct RelayInfoList(#[n(0)] pub Vec); + +impl Encodable for RelayInfoList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for RelayInfoList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/secure_channel.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/secure_channel.rs index 7dc2ea6067c..c09b5b4cf4d 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/secure_channel.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/secure_channel.rs @@ -7,8 +7,9 @@ use serde::Serialize; use ockam::identity::models::CredentialAndPurposeKey; use ockam::identity::{Identifier, SecureChannel, SecureChannelListener}; +use ockam::Message; use ockam_core::flow_control::FlowControlId; -use ockam_core::{route, Address, Result}; +use ockam_core::{cbor_encode_preallocate, route, Address, Decodable, Encodable, Encoded, Result}; use ockam_multiaddr::MultiAddr; use crate::colors::color_primary; @@ -18,7 +19,7 @@ use crate::ReverseLocalConverter; //Requests /// Request body when instructing a node to create a Secure Channel -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateSecureChannelRequest { @@ -29,6 +30,17 @@ pub struct CreateSecureChannelRequest { #[n(6)] pub credential: Option, } +impl Encodable for CreateSecureChannelRequest { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateSecureChannelRequest { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} impl CreateSecureChannelRequest { pub fn new( addr: &MultiAddr, @@ -47,13 +59,24 @@ impl CreateSecureChannelRequest { } /// Request body when instructing a node to delete a Secure Channel -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct DeleteSecureChannelRequest { #[n(1)] pub channel: Address, } +impl Encodable for DeleteSecureChannelRequest { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for DeleteSecureChannelRequest { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} impl DeleteSecureChannelRequest { pub fn new(channel: &Address) -> Self { Self { @@ -63,13 +86,24 @@ impl DeleteSecureChannelRequest { } /// Request body when instructing a node to show a Secure Channel -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct ShowSecureChannelRequest { #[n(1)] pub channel: Address, } +impl Encodable for ShowSecureChannelRequest { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ShowSecureChannelRequest { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} impl ShowSecureChannelRequest { pub fn new(channel: &Address) -> Self { Self { @@ -79,13 +113,24 @@ impl ShowSecureChannelRequest { } /// Request body when instructing a node to delete a Secure Channel Listener -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct DeleteSecureChannelListenerRequest { #[n(1)] pub addr: Address, } +impl Encodable for DeleteSecureChannelListenerRequest { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for DeleteSecureChannelListenerRequest { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} impl DeleteSecureChannelListenerRequest { pub fn new(addr: &Address) -> Self { Self { @@ -95,13 +140,25 @@ impl DeleteSecureChannelListenerRequest { } /// Request body to show a Secure Channel Listener -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct ShowSecureChannelListenerRequest { #[n(1)] pub addr: Address, } +impl Encodable for ShowSecureChannelListenerRequest { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ShowSecureChannelListenerRequest { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl ShowSecureChannelListenerRequest { pub fn new(addr: &Address) -> Self { Self { @@ -113,7 +170,7 @@ impl ShowSecureChannelListenerRequest { // Responses /// Response body when instructing a node to create a Secure Channel -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateSecureChannelResponse { @@ -121,6 +178,18 @@ pub struct CreateSecureChannelResponse { #[n(2)] pub flow_control_id: FlowControlId, } +impl Encodable for CreateSecureChannelResponse { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateSecureChannelResponse { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateSecureChannelResponse { pub fn new(secure_channel: SecureChannel) -> Self { Self { @@ -146,7 +215,7 @@ impl Output for CreateSecureChannelResponse { } } -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateSecureChannelListenerRequest { @@ -155,6 +224,17 @@ pub struct CreateSecureChannelListenerRequest { #[n(3)] pub identity_name: Option, } +impl Encodable for CreateSecureChannelListenerRequest { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateSecureChannelListenerRequest { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} impl CreateSecureChannelListenerRequest { pub fn new( addr: &Address, @@ -170,7 +250,7 @@ impl CreateSecureChannelListenerRequest { } /// Response body when deleting a Secure Channel Listener -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct DeleteSecureChannelListenerResponse { @@ -183,6 +263,18 @@ impl DeleteSecureChannelListenerResponse { } } +impl Encodable for DeleteSecureChannelListenerResponse { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for DeleteSecureChannelListenerResponse { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl Output for SecureChannelListener { fn item(&self) -> crate::Result { let addr = { @@ -194,13 +286,24 @@ impl Output for SecureChannelListener { } } -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct DeleteSecureChannelResponse { #[n(1)] pub channel: Option, } +impl Encodable for DeleteSecureChannelResponse { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for DeleteSecureChannelResponse { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} impl DeleteSecureChannelResponse { pub fn new(channel: Option
) -> Self { Self { @@ -209,7 +312,7 @@ impl DeleteSecureChannelResponse { } } -#[derive(Debug, Clone, Encode, Decode, CborLen, Serialize)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Serialize, Message)] #[rustfmt::skip] #[cbor(map)] pub struct ShowSecureChannelResponse { @@ -219,6 +322,17 @@ pub struct ShowSecureChannelResponse { #[n(4)] pub flow_control_id: Option, } +impl Encodable for ShowSecureChannelResponse { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ShowSecureChannelResponse { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} impl ShowSecureChannelResponse { pub fn new(info: Option) -> Self { Self { @@ -267,3 +381,18 @@ impl Output for ShowSecureChannelResponse { Ok(s) } } + +#[derive(Encode, Decode, CborLen, Debug, Default, Clone, Eq, PartialEq, Message)] +pub struct SecureChannelList(#[n(0)] pub Vec); + +impl Encodable for SecureChannelList { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for SecureChannelList { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/services.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/services.rs index 30a77253d8d..e7fc86a4f0c 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/services.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/services.rs @@ -2,22 +2,39 @@ use crate::colors::{color_primary, color_warn}; use crate::kafka::{ConsumerPublishing, ConsumerResolution}; use crate::output::Output; use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; use ockam_abac::PolicyExpression; -use ockam_core::Address; +use ockam_core::{cbor_encode_preallocate, Address, Decodable, Encodable, Encoded}; use ockam_multiaddr::MultiAddr; use ockam_transport_core::HostnamePort; use serde::Serialize; use std::fmt::Display; -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] -pub struct StartServiceRequest { +pub struct StartServiceRequest + CborLen<()> + for<'a> Decode<'a, ()> + Send + 'static> { #[n(1)] addr: String, #[n(2)] req: T, } -impl StartServiceRequest { +impl + CborLen<()> + for<'a> Decode<'a, ()> + Send + 'static> Encodable + for StartServiceRequest +{ + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl + CborLen<()> + for<'a> Decode<'a, ()> + Send + 'static> Decodable + for StartServiceRequest +{ + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + +impl + CborLen<()> + for<'a> Decode<'a, ()> + Send + 'static> StartServiceRequest { pub fn new>(req: T, addr: S) -> Self { Self { addr: addr.into(), @@ -34,13 +51,25 @@ impl StartServiceRequest { } } -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct DeleteServiceRequest { #[n(1)] addr: String, } +impl Encodable for DeleteServiceRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for DeleteServiceRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl DeleteServiceRequest { pub fn new>(addr: S) -> Self { Self { addr: addr.into() } @@ -51,7 +80,7 @@ impl DeleteServiceRequest { } } -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct StartKafkaOutletRequest { @@ -60,6 +89,18 @@ pub struct StartKafkaOutletRequest { #[n(3)] policy_expression: Option, } +impl Encodable for StartKafkaOutletRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for StartKafkaOutletRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl StartKafkaOutletRequest { pub fn new( bootstrap_server_addr: HostnamePort, @@ -86,7 +127,7 @@ impl StartKafkaOutletRequest { } } -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct StartKafkaInletRequest { @@ -102,6 +143,18 @@ pub struct StartKafkaInletRequest { #[n(10)] encrypted_fields: Vec, } +impl Encodable for StartKafkaInletRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for StartKafkaInletRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl StartKafkaInletRequest { #[allow(clippy::too_many_arguments)] pub fn new( @@ -170,13 +223,25 @@ impl StartKafkaInletRequest { } /// Request body when instructing a node to start an Uppercase service -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct StartUppercaseServiceRequest { #[n(1)] pub addr: String, } +impl Encodable for StartUppercaseServiceRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for StartUppercaseServiceRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl StartUppercaseServiceRequest { pub fn new(addr: impl Into) -> Self { Self { addr: addr.into() } @@ -184,13 +249,25 @@ impl StartUppercaseServiceRequest { } /// Request body when instructing a node to start an Echoer service -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct StartEchoerServiceRequest { #[n(1)] pub addr: String, } +impl Encodable for StartEchoerServiceRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for StartEchoerServiceRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl StartEchoerServiceRequest { pub fn new(addr: impl Into) -> Self { Self { addr: addr.into() } @@ -198,20 +275,32 @@ impl StartEchoerServiceRequest { } /// Request body when instructing a node to start a Hop service -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct StartHopServiceRequest { #[n(1)] pub addr: String, } +impl Encodable for StartHopServiceRequest { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for StartHopServiceRequest { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl StartHopServiceRequest { pub fn new(addr: impl Into) -> Self { Self { addr: addr.into() } } } -#[derive(Debug, Clone, Serialize, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Serialize, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct ServiceStatus { @@ -220,6 +309,18 @@ pub struct ServiceStatus { #[n(3)] pub service_type: String, } +impl Encodable for ServiceStatus { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ServiceStatus { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl ServiceStatus { pub fn new(addr: impl Into, service_type: impl Into) -> Self { Self { @@ -245,3 +346,17 @@ impl Output for ServiceStatus { Ok(self.padded_display()) } } + +#[derive(Encode, Decode, CborLen, Debug, Default, Clone, Message)] +pub struct ServiceStatusList(#[n(0)] pub Vec); + +impl Encodable for ServiceStatusList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} +impl Decodable for ServiceStatusList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/transport/request.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/transport/request.rs index bb88a32293a..7eff18fcb5f 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/transport/request.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/transport/request.rs @@ -1,7 +1,9 @@ use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; /// Request body when instructing a node to create a transport -#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq, Eq)] +#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq, Eq, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateTcpConnection { @@ -9,6 +11,18 @@ pub struct CreateTcpConnection { #[n(1)] pub addr: String, } +impl Encodable for CreateTcpConnection { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateTcpConnection { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateTcpConnection { pub fn new(addr: String) -> Self { Self { addr } @@ -16,7 +30,7 @@ impl CreateTcpConnection { } /// Request body when instructing a node to create a transport -#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq, Eq)] +#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq, Eq, Message)] #[rustfmt::skip] #[cbor(map)] pub struct CreateTcpListener { @@ -24,6 +38,18 @@ pub struct CreateTcpListener { #[n(1)] pub addr: String, } +impl Encodable for CreateTcpListener { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateTcpListener { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateTcpListener { pub fn new(addr: String) -> Self { Self { addr } @@ -31,7 +57,7 @@ impl CreateTcpListener { } /// Request to delete a transport -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct DeleteTransport { @@ -39,6 +65,18 @@ pub struct DeleteTransport { #[n(1)] pub address: String, } +impl Encodable for DeleteTransport { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for DeleteTransport { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl DeleteTransport { pub fn new(address: String) -> Self { Self { address } diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/transport/response.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/transport/response.rs index 11fa42a84ff..cfc4f833db8 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/transport/response.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/transport/response.rs @@ -4,16 +4,17 @@ use crate::nodes::service::ApiTransport; use crate::output::Output; use minicbor::{CborLen, Decode, Encode}; use ockam::tcp::{TcpConnection, TcpListener, TcpListenerInfo, TcpSenderInfo}; +use ockam::Message; use ockam_core::errcode::{Kind, Origin}; use ockam_core::flow_control::FlowControlId; -use ockam_core::{Error, Result}; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded, Error, Result}; use ockam_multiaddr::proto::Worker; use ockam_multiaddr::MultiAddr; use std::fmt::{Display, Formatter}; use std::net::SocketAddrV4; /// Response body when interacting with a transport -#[derive(Debug, Clone, Encode, Decode, CborLen, serde::Serialize)] +#[derive(Debug, Clone, Encode, Decode, CborLen, serde::Serialize, Message)] #[rustfmt::skip] #[cbor(map)] pub struct TransportStatus { @@ -33,6 +34,18 @@ pub struct TransportStatus { #[n(6)] pub flow_control_id: FlowControlId, } +impl Encodable for TransportStatus { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for TransportStatus { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl TransportStatus { pub fn new(api_transport: ApiTransport) -> Self { api_transport.into() @@ -139,3 +152,19 @@ impl Output for TransportStatus { Ok(self.padded_display()) } } + +#[derive(Encode, Decode, CborLen, Debug, Default, Clone, Message)] +#[cbor(transparent)] +pub struct TransportStatusList(#[n(0)] pub Vec); + +impl Encodable for TransportStatusList { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for TransportStatusList { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} diff --git a/implementations/rust/ockam/ockam_api/src/nodes/models/workers.rs b/implementations/rust/ockam/ockam_api/src/nodes/models/workers.rs index f389849cdd3..2480b2c3167 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/models/workers.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/models/workers.rs @@ -3,14 +3,28 @@ use crate::output::Output; use crate::Result; use colorful::Colorful; use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct WorkerStatus { #[n(2)] pub addr: String, } +impl Encodable for WorkerStatus { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for WorkerStatus { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl WorkerStatus { pub fn new(addr: impl Into) -> Self { Self { addr: addr.into() } @@ -29,13 +43,25 @@ impl Output for WorkerStatus { } /// Response body for listing workers -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] pub struct WorkerList { #[n(1)] pub list: Vec, } +impl Encodable for WorkerList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for WorkerList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl WorkerList { pub fn new(list: Vec) -> Self { Self { list } diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service.rs b/implementations/rust/ockam/ockam_api/src/nodes/service.rs index 03fed806739..09475940619 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service.rs @@ -1,7 +1,5 @@ //! Node Manager (Node Man, the superhero that we deserve) -use minicbor::Encode; - use ockam::Result; use ockam_core::api::{RequestHeader, Response}; @@ -28,21 +26,21 @@ mod trust; mod worker; pub use manager::*; +use ockam_core::Message; pub use secure_channel::SecureChannelType; pub use trust::*; pub use worker::*; const TARGET: &str = "ockam_api::nodemanager::service"; -/// Append the request header to the Response and encode in vector format -pub(crate) fn encode_response>( +/// Append the request header to the response and serialize the response body +pub(crate) fn encode_response( req: &RequestHeader, res: std::result::Result, Response>, -) -> Result> { +) -> Result>> { let v = match res { - Ok(r) => r.with_headers(req).to_vec()?, - Err(e) => e.with_headers(req).to_vec()?, + Ok(r) => r.with_headers(req).encode_body()?, + Err(e) => e.with_headers(req).encode_body()?, }; - Ok(v) } diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/background_node_client.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/background_node_client.rs index d8eedbdc014..daf6a6ef38d 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/background_node_client.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/background_node_client.rs @@ -2,12 +2,11 @@ use std::sync::Arc; use std::time::Duration; use miette::{miette, IntoDiagnostic}; -use minicbor::{Decode, Encode}; use ockam::identity::get_default_timeout; use ockam::tcp::{TcpConnection, TcpConnectionOptions, TcpTransport}; use ockam_core::api::{Reply, Request}; -use ockam_core::Route; +use ockam_core::{Message, Route}; use ockam_node::api::Client; use ockam_node::Context; @@ -111,8 +110,8 @@ impl BackgroundNodeClient { /// Send a request and expect a decodable response pub async fn ask(&self, ctx: &Context, req: Request) -> miette::Result where - T: Encode<()>, - R: for<'b> Decode<'b, ()>, + T: Message, + R: Message, { self.ask_and_get_reply(ctx, req) .await? @@ -128,8 +127,8 @@ impl BackgroundNodeClient { timeout: Duration, ) -> miette::Result where - T: Encode<()>, - R: for<'b> Decode<'b, ()>, + T: Message, + R: Message, { let (tcp_connection, client) = self.make_client_with_timeout(Some(timeout)).await?; @@ -152,12 +151,11 @@ impl BackgroundNodeClient { req: Request, ) -> miette::Result> where - T: Encode<()>, - R: for<'b> Decode<'b, ()>, + T: Message, + R: Message, { let (tcp_connection, client) = self.make_client().await?; let res = client.ask(ctx, req).await.into_diagnostic(); - let _ = tcp_connection.stop(ctx); res } @@ -165,7 +163,7 @@ impl BackgroundNodeClient { /// Send a request but don't decode the response pub async fn tell(&self, ctx: &Context, req: Request) -> miette::Result<()> where - T: Encode<()>, + T: Message, { let (tcp_connection, client) = self.make_client().await?; let res = client @@ -186,7 +184,7 @@ impl BackgroundNodeClient { req: Request, ) -> miette::Result> where - T: Encode<()>, + T: Message, { let (tcp_connection, client) = self.make_client().await?; let res = client.tell(ctx, req).await.into_diagnostic(); diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/manager.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/manager.rs index ee386f99f12..ed387bde904 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/manager.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/manager.rs @@ -39,6 +39,7 @@ use ockam_core::{ IncomingAccessControl, OutgoingAccessControl, TryClone, }; use ockam_multiaddr::MultiAddr; +use ockam_node::api::Client; use ockam_node::Context; use std::net::SocketAddr; use std::sync::Arc; @@ -297,6 +298,19 @@ impl NodeManager { Ok(()) } + pub async fn make_client( + &self, + ctx: &Context, + to: &MultiAddr, + timeout: Option, + ) -> ockam_core::Result { + let connection = self + .make_connection(ctx, to, self.identifier(), None, timeout) + .await?; + let route = connection.route()?; + Ok(Client::new(&route, timeout)) + } + pub async fn make_connection( &self, ctx: &Context, diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/messages.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/messages.rs index d5122f40c36..0af0293f042 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/messages.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/messages.rs @@ -1,56 +1,52 @@ +use crate::error::ApiError; +use crate::nodes::{BackgroundNodeClient, NodeManager, NodeManagerWorker}; use miette::IntoDiagnostic; -use std::str::FromStr; -use std::time::Duration; -use tracing::trace; - -use minicbor::{CborLen, Decode, Encode}; - +use minicbor::encode::Write; +use minicbor::{encode, CborLen, Decode, Decoder, Encode, Encoder}; use ockam_core::api::{Error, Request, Response}; -use ockam_core::{self, async_trait, Result}; +use ockam_core::{self, async_trait, Decodable, Encodable, Encoded, Message, Result}; use ockam_multiaddr::MultiAddr; use ockam_node::{Context, MessageSendReceiveOptions}; - -use crate::error::ApiError; -use crate::nodes::{BackgroundNodeClient, NodeManager, NodeManagerWorker}; +use std::str::FromStr; +use std::time::Duration; const TARGET: &str = "ockam_api::message"; #[async_trait] pub trait Messages { - async fn send_message( + async fn send_message( &self, ctx: &Context, to: &MultiAddr, - message: Vec, + message: T, timeout: Option, - ) -> miette::Result>; + ) -> miette::Result; } #[async_trait] impl Messages for NodeManager { #[instrument(skip_all)] - async fn send_message( + async fn send_message( &self, ctx: &Context, to: &MultiAddr, - message: Vec, + message: T, timeout: Option, - ) -> miette::Result> { - let msg_length = message.len(); + ) -> miette::Result { let connection = self .make_connection(ctx, to, self.identifier(), None, timeout) .await .into_diagnostic()?; let route = connection.route().into_diagnostic()?; - trace!(route = %route, msg_l = %msg_length, "sending message"); + trace!(route = %route, "sending message"); let options = if let Some(timeout) = timeout { MessageSendReceiveOptions::new().with_timeout(timeout) } else { MessageSendReceiveOptions::new() }; Ok(ctx - .send_and_receive_extended::>(route, message, options) + .send_and_receive_extended(route, message, options) .await .into_diagnostic()? .into_body() @@ -61,26 +57,26 @@ impl Messages for NodeManager { #[async_trait] impl Messages for BackgroundNodeClient { #[instrument(skip_all)] - async fn send_message( + async fn send_message( &self, ctx: &Context, to: &MultiAddr, - message: Vec, + message: T, timeout: Option, - ) -> miette::Result> { + ) -> miette::Result { let request = Request::post("v0/message").body(SendMessage::new(to, message)); Ok(self.clone().set_timeout(timeout).ask(ctx, request).await?) } } impl NodeManagerWorker { - pub(crate) async fn send_message( + pub(crate) async fn send_message( &self, ctx: &Context, - send_message: SendMessage, - ) -> Result>, Response> { + send_message: SendMessage, + ) -> Result, Response> { let multiaddr = send_message.multiaddr()?; - let msg = send_message.message.to_vec(); + let msg = send_message.message; let res = self .node_manager @@ -98,17 +94,54 @@ impl NodeManagerWorker { } } -#[derive(Encode, Decode, CborLen, Debug)] -#[cfg_attr(test, derive(Clone))] +#[derive(Debug, Clone, Encode, Decode, CborLen, Message)] #[rustfmt::skip] #[cbor(map)] -pub struct SendMessage { +pub struct SendMessage { #[n(1)] pub route: String, - #[n(2)] pub message: Vec, + #[n(2)] pub message: T, +} + +impl SendMessage { + fn encode_send_message(self, buf: W) -> Result<(), encode::Error> + where + W: Write, + { + let mut e = Encoder::new(buf); + e.encode(&self.route)?; + e.writer_mut() + .write_all(&::encode(self.message).map_err(encode::Error::message)?) + .map_err(|_| encode::Error::message("encoding error"))?; + Ok(()) + } + + fn into_vec(self) -> Result, encode::Error< as Write>::Error>> { + let mut buf = Vec::new(); + self.encode_send_message(&mut buf)?; + Ok(buf) + } +} + +impl Encodable for SendMessage { + fn encode(self) -> Result { + Ok(self.into_vec()?) + } +} + +impl Decodable for SendMessage { + fn decode(e: &[u8]) -> Result { + let mut dec = Decoder::new(e); + let route: String = dec.decode()?; + let message = dec.input().get(dec.position()..e.len()).unwrap(); + Ok(SendMessage { + route, + message: ::decode(message)?, + }) + } } -impl SendMessage { - pub fn new(route: &MultiAddr, message: Vec) -> Self { +impl SendMessage { + pub fn new(route: &MultiAddr, message: T) -> Self { Self { route: route.to_string(), message, diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/node_services.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/node_services.rs index e4081c62468..bafcb83dca0 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/node_services.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/node_services.rs @@ -10,7 +10,8 @@ use crate::error::ApiError; use crate::hop::Hop; use crate::nodes::models::node::{NodeResources, NodeStatus}; use crate::nodes::models::services::{ - ServiceStatus, StartEchoerServiceRequest, StartHopServiceRequest, StartUppercaseServiceRequest, + ServiceStatus, ServiceStatusList, StartEchoerServiceRequest, StartHopServiceRequest, + StartUppercaseServiceRequest, }; use crate::nodes::registry::KafkaServiceKind; use crate::nodes::service::default_address::DefaultAddress; @@ -66,16 +67,16 @@ impl NodeManagerWorker { pub(super) fn list_services_of_type( &self, service_type: &str, - ) -> Result>, Response> { + ) -> Result, Response> { match self.node_manager.list_services_of_type(service_type) { - Ok(Either::Left(services)) => Ok(Response::ok().body(services)), + Ok(Either::Left(services)) => Ok(Response::ok().body(ServiceStatusList(services))), Ok(Either::Right(message)) => Err(Response::bad_request_no_request(&message)), Err(e) => Err(Response::internal_error_no_request(&e.to_string())), } } - pub(super) fn list_services(&self) -> Result>, Response> { - Ok(Response::ok().body(self.node_manager.list_services())) + pub(super) fn list_services(&self) -> Result, Response> { + Ok(Response::ok().body(ServiceStatusList(self.node_manager.list_services()))) } #[instrument(skip_all)] diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/policy.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/policy.rs index e770289da15..d6de323431e 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/policy.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/policy.rs @@ -4,7 +4,9 @@ use ockam_core::{async_trait, Result}; use ockam_node::Context; use std::str::FromStr; -use crate::nodes::models::policies::{PoliciesList, Policy, ResourceTypeOrName, SetPolicyRequest}; +use crate::nodes::models::policies::{ + PoliciesList, Policy, ResourceTypeOrName, ResourceTypeOrNameOption, SetPolicyRequest, +}; use crate::nodes::{BackgroundNodeClient, NodeManagerWorker}; use super::NodeManager; @@ -191,7 +193,7 @@ impl Policies for BackgroundNodeClient { expression: &PolicyExpression, ) -> miette::Result<()> { let payload = SetPolicyRequest::new(resource.clone(), expression.clone()); - let request = Request::post(policy_path(action)).body(payload); + let request = Request::post(policy_path(action)).body(payload.clone()); self.tell(ctx, request).await?; Ok(()) } @@ -202,7 +204,7 @@ impl Policies for BackgroundNodeClient { resource: &ResourceTypeOrName, action: &Action, ) -> miette::Result { - let request = Request::get(policy_path(action)).body(resource); + let request = Request::get(policy_path(action)).body(resource.clone()); self.ask(ctx, request).await } @@ -211,7 +213,7 @@ impl Policies for BackgroundNodeClient { ctx: &Context, resource: Option<&ResourceTypeOrName>, ) -> miette::Result { - let request = Request::get("/policy").body(resource); + let request = Request::get("/policy").body(ResourceTypeOrNameOption(resource.cloned())); self.ask(ctx, request).await } @@ -221,7 +223,7 @@ impl Policies for BackgroundNodeClient { resource: &ResourceTypeOrName, action: &Action, ) -> miette::Result<()> { - let request = Request::delete(policy_path(action)).body(resource); + let request = Request::delete(policy_path(action)).body(resource.clone()); self.tell(ctx, request).await?; Ok(()) } diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/relay.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/relay.rs index a57f7fc89d9..c74845c7aee 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/relay.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/relay.rs @@ -19,7 +19,7 @@ use ockam_node::Context; use super::{NodeManager, NodeManagerWorker}; use crate::colors::color_primary; use crate::nodes::connection::Connection; -use crate::nodes::models::relay::{CreateRelay, RelayInfo, ReturnTiming}; +use crate::nodes::models::relay::{CreateRelay, RelayInfo, RelayInfoList, ReturnTiming}; use crate::nodes::models::secure_channel::{ CreateSecureChannelRequest, CreateSecureChannelResponse, }; @@ -99,11 +99,11 @@ impl NodeManagerWorker { pub async fn get_relays( &self, req: &RequestHeader, - ) -> Result>, Response> { + ) -> Result, Response> { debug!("Handling GetRelays request"); Ok(Response::ok() .with_headers(req) - .body(self.node_manager.get_relays().await)) + .body(RelayInfoList(self.node_manager.get_relays().await))) } } diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/secure_channel.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/secure_channel.rs index 8c87729ccdf..285d40e2798 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/secure_channel.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/secure_channel.rs @@ -1,11 +1,11 @@ use std::time::Duration; -use crate::nodes::models::secure_channel::CreateSecureChannelListenerRequest; use crate::nodes::models::secure_channel::CreateSecureChannelRequest; use crate::nodes::models::secure_channel::DeleteSecureChannelListenerRequest; use crate::nodes::models::secure_channel::DeleteSecureChannelRequest; use crate::nodes::models::secure_channel::ShowSecureChannelListenerRequest; use crate::nodes::models::secure_channel::ShowSecureChannelRequest; +use crate::nodes::models::secure_channel::{CreateSecureChannelListenerRequest, SecureChannelList}; use crate::nodes::models::secure_channel::{ CreateSecureChannelResponse, DeleteSecureChannelListenerResponse, DeleteSecureChannelResponse, ShowSecureChannelResponse, @@ -14,12 +14,12 @@ use crate::nodes::registry::SecureChannelInfo; use crate::nodes::service::default_address::DefaultAddress; use crate::nodes::{NodeManager, NodeManagerWorker}; use ockam::identity::models::CredentialAndPurposeKey; -use ockam::identity::Vault; use ockam::identity::{ Identifier, Identities, SecureChannelListenerOptions, SecureChannelOptions, SecureChannels, TrustMultiIdentifiersPolicy, }; use ockam::identity::{SecureChannel, SecureChannelListener}; +use ockam::identity::{SecureChannelListenerList, Vault}; use ockam::identity::{SecureChannelSqlxDatabase, TrustEveryonePolicy}; use ockam::{Address, Result, Route}; use ockam_core::api::{Error, Response}; @@ -36,8 +36,8 @@ pub enum SecureChannelType { /// SECURE CHANNELS impl NodeManagerWorker { - pub fn list_secure_channels(&self) -> Result>, Response> { - Ok(Response::ok().body(self.node_manager.list_secure_channels())) + pub fn list_secure_channels(&self) -> Result, Response> { + Ok(Response::ok().body(SecureChannelList(self.node_manager.list_secure_channels()))) } pub(super) async fn create_secure_channel( @@ -157,8 +157,10 @@ impl NodeManagerWorker { pub fn list_secure_channel_listener( &self, - ) -> Result>, Response> { - Ok(Response::ok().body(self.node_manager.list_secure_channel_listeners())) + ) -> Result, Response> { + Ok(Response::ok().body(SecureChannelListenerList( + self.node_manager.list_secure_channel_listeners(), + ))) } } diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager_worker.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager_worker.rs index c2119a73458..3e07494658b 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager_worker.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_inlets/node_manager_worker.rs @@ -2,13 +2,13 @@ use ockam::{route, Result}; use ockam_core::api::{Error, Response}; use ockam_node::Context; -use crate::nodes::models::portal::{CreateInlet, InletStatus}; +use crate::nodes::models::portal::{CreateInlet, InletStatus, InletStatusList}; use crate::nodes::NodeManagerWorker; impl NodeManagerWorker { - pub(crate) async fn get_inlets(&self) -> Result>, Response> { + pub(crate) async fn get_inlets(&self) -> Result, Response> { let inlets = self.node_manager.list_inlets().await; - Ok(Response::ok().body(inlets)) + Ok(Response::ok().body(InletStatusList(inlets))) } #[instrument(skip_all)] diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_outlets.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_outlets.rs index ff948c9a3f9..3943402f8fa 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_outlets.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/tcp_outlets.rs @@ -2,12 +2,14 @@ use ockam::tcp::TcpOutletOptions; use ockam::transport::HostnamePort; use ockam::{Address, Result}; use ockam_abac::{Action, PolicyExpression, Resource, ResourceType}; -use ockam_core::api::{Error, Request, RequestHeader, Response}; +use ockam_core::api::{Error, Request, Response}; use ockam_core::async_trait; use ockam_core::errcode::{Kind, Origin}; use ockam_node::Context; -use crate::nodes::models::portal::{CreateOutlet, OutletAccessControl, OutletStatus}; +use crate::nodes::models::portal::{ + CreateOutlet, OutletAccessControl, OutletStatus, OutletStatusList, +}; use crate::nodes::registry::OutletInfo; use crate::nodes::service::default_address::DefaultAddress; use crate::nodes::BackgroundNodeClient; @@ -84,10 +86,9 @@ impl NodeManagerWorker { } } - pub(super) fn get_outlets(&self, req: &RequestHeader) -> Response> { - Response::ok() - .with_headers(req) - .body(self.node_manager.list_outlets()) + pub(crate) async fn get_outlets(&self) -> Result, Response> { + let outlets = self.node_manager.list_outlets(); + Ok(Response::ok().body(OutletStatusList(outlets))) } } diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/transport.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/transport.rs index e56b4b53d36..1454666efd2 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/transport.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/transport.rs @@ -2,12 +2,12 @@ use std::net::SocketAddr; use ockam::tcp::{TcpConnectionOptions, TcpListenerOptions}; use ockam::Result; -use ockam_core::api::{Error, RequestHeader, Response}; +use ockam_core::api::{Error, Response}; use ockam_node::Context; use super::{NodeManager, NodeManagerWorker}; use crate::nodes::models::transport::{ - CreateTcpConnection, CreateTcpListener, DeleteTransport, TransportStatus, + CreateTcpConnection, CreateTcpListener, DeleteTransport, TransportStatus, TransportStatusList, }; impl NodeManager { @@ -99,13 +99,8 @@ impl NodeManager { } impl NodeManagerWorker { - pub(super) async fn get_tcp_connections( - &self, - req: &RequestHeader, - ) -> Response> { - Response::ok() - .with_headers(req) - .body(self.node_manager.get_tcp_connections()) + pub(super) async fn get_tcp_connections(&self) -> Response { + Response::ok().body(TransportStatusList(self.node_manager.get_tcp_connections())) } pub(super) async fn get_tcp_connection( @@ -121,13 +116,8 @@ impl NodeManagerWorker { }) } - pub(super) async fn get_tcp_listeners( - &self, - req: &RequestHeader, - ) -> Response> { - Response::ok() - .with_headers(req) - .body(self.node_manager.get_tcp_listeners()) + pub(super) async fn get_tcp_listeners(&self) -> Response { + Response::ok().body(TransportStatusList(self.node_manager.get_tcp_listeners())) } pub(super) async fn get_tcp_listener( diff --git a/implementations/rust/ockam/ockam_api/src/nodes/service/worker.rs b/implementations/rust/ockam/ockam_api/src/nodes/service/worker.rs index 9570daac5d7..2cabd567b15 100644 --- a/implementations/rust/ockam/ockam_api/src/nodes/service/worker.rs +++ b/implementations/rust/ockam/ockam_api/src/nodes/service/worker.rs @@ -1,11 +1,11 @@ -use crate::nodes::models::policies::SetPolicyRequest; +use crate::nodes::models::policies::{ResourceTypeOrNameOption, SetPolicyRequest}; use crate::nodes::registry::KafkaServiceKind; +use crate::nodes::service::messages::SendMessage; use crate::nodes::service::{encode_response, TARGET}; use crate::nodes::{InMemoryNode, NODEMANAGER_ADDR}; use crate::DefaultAddress; -use minicbor::Decoder; -use ockam_core::api::{RequestHeader, Response}; -use ockam_core::{Address, Result, Routed, Worker}; +use ockam_core::api::{Request, Response}; +use ockam_core::{Address, Decodable, Result, Routed, Worker}; use ockam_node::Context; use std::error::Error; use std::sync::Arc; @@ -31,216 +31,267 @@ impl NodeManagerWorker { impl NodeManagerWorker { //////// Request matching and response handling //////// - #[instrument(skip_all, fields(method = ?req.method(), path = req.path()))] + #[instrument(skip_all, fields(method = ?request.header().method(), path = request.header().path()))] async fn handle_request( &mut self, ctx: &mut Context, - req: &RequestHeader, - dec: &mut Decoder<'_>, - ) -> Result> { + request: Request>, + ) -> Result>> { + let (header, body) = request.into_parts(); + let body = body.unwrap_or_default(); debug! { target: TARGET, - id = %req.id(), - method = ?req.method(), - path = %req.path(), - body = %req.has_body(), + id = %header.id(), + method = ?header.method(), + path = %header.path(), + body = %header.has_body(), "request" } use ockam_core::api::Method::*; - let path = req.path(); - let path_segments = req.path_segments::<5>(); - let method = match req.method() { + let path = header.path(); + let path_segments = header.path_segments::<5>(); + let method = match header.method() { Some(m) => m, None => todo!(), }; - let r = match (method, path_segments.as_slice()) { + match (method, path_segments.as_slice()) { // ==*== Basic node information ==*== - (Get, ["node"]) => encode_response(req, self.get_node_status().await)?, - (Get, ["node", "resources"]) => encode_response(req, self.get_node_resources().await)?, + (Get, ["node"]) => encode_response(&header, self.get_node_status().await), + (Get, ["node", "resources"]) => { + encode_response(&header, self.get_node_resources().await) + } // ==*== Tcp Connection ==*== - (Get, ["node", "tcp", "connection"]) => self.get_tcp_connections(req).await.to_vec()?, - (Get, ["node", "tcp", "connection", address]) => { - encode_response(req, self.get_tcp_connection(address.to_string()).await)? - } - (Post, ["node", "tcp", "connection"]) => { - encode_response(req, self.create_tcp_connection(ctx, dec.decode()?).await)? + (Get, ["node", "tcp", "connection"]) => { + encode_response(&header, Ok(self.get_tcp_connections().await)) } - (Delete, ["node", "tcp", "connection"]) => { - encode_response(req, self.delete_tcp_connection(dec.decode()?))? + (Get, ["node", "tcp", "connection", address]) => { + encode_response(&header, self.get_tcp_connection(address.to_string()).await) } + (Post, ["node", "tcp", "connection"]) => encode_response( + &header, + self.create_tcp_connection(ctx, Decodable::decode(&body)?) + .await, + ), + (Delete, ["node", "tcp", "connection"]) => encode_response( + &header, + self.delete_tcp_connection(Decodable::decode(&body)?), + ), // ==*== Tcp Listeners ==*== - (Get, ["node", "tcp", "listener"]) => self.get_tcp_listeners(req).await.to_vec()?, - (Get, ["node", "tcp", "listener", address]) => { - encode_response(req, self.get_tcp_listener(address.to_string()).await)? + (Get, ["node", "tcp", "listener"]) => { + encode_response(&header, Ok(self.get_tcp_listeners().await)) } - (Post, ["node", "tcp", "listener"]) => { - encode_response(req, self.create_tcp_listener(dec.decode()?).await)? + (Get, ["node", "tcp", "listener", address]) => { + encode_response(&header, self.get_tcp_listener(address.to_string()).await) } + (Post, ["node", "tcp", "listener"]) => encode_response( + &header, + self.create_tcp_listener(Decodable::decode(&body)?).await, + ), (Delete, ["node", "tcp", "listener"]) => { - encode_response(req, self.delete_tcp_listener(dec.decode()?))? + encode_response(&header, self.delete_tcp_listener(Decodable::decode(&body)?)) } // ==*== Secure channels ==*== - (Get, ["node", "secure_channel"]) => encode_response(req, self.list_secure_channels())?, - (Get, ["node", "secure_channel_listener"]) => { - encode_response(req, self.list_secure_channel_listener())? - } - (Post, ["node", "secure_channel"]) => { - encode_response(req, self.create_secure_channel(dec.decode()?, ctx).await)? + (Get, ["node", "secure_channel"]) => { + encode_response(&header, self.list_secure_channels()) } - (Delete, ["node", "secure_channel"]) => { - encode_response(req, self.delete_secure_channel(dec.decode()?, ctx))? + (Get, ["node", "secure_channel_listener"]) => { + encode_response(&header, self.list_secure_channel_listener()) } + (Post, ["node", "secure_channel"]) => encode_response( + &header, + self.create_secure_channel(Decodable::decode(&body)?, ctx) + .await, + ), + (Delete, ["node", "secure_channel"]) => encode_response( + &header, + self.delete_secure_channel(Decodable::decode(&body)?, ctx), + ), (Get, ["node", "show_secure_channel"]) => { - encode_response(req, self.show_secure_channel(dec.decode()?))? + encode_response(&header, self.show_secure_channel(Decodable::decode(&body)?)) } (Post, ["node", "secure_channel_listener"]) => encode_response( - req, - self.create_secure_channel_listener(dec.decode()?, ctx) + &header, + self.create_secure_channel_listener(Decodable::decode(&body)?, ctx) .await, - )?, - (Delete, ["node", "secure_channel_listener"]) => { - encode_response(req, self.delete_secure_channel_listener(dec.decode()?, ctx))? - } - (Get, ["node", "show_secure_channel_listener"]) => { - encode_response(req, self.show_secure_channel_listener(dec.decode()?))? - } + ), + (Delete, ["node", "secure_channel_listener"]) => encode_response( + &header, + self.delete_secure_channel_listener(Decodable::decode(&body)?, ctx), + ), + (Get, ["node", "show_secure_channel_listener"]) => encode_response( + &header, + self.show_secure_channel_listener(Decodable::decode(&body)?), + ), // ==*== Services ==*== - (Post, ["node", "services", DefaultAddress::UPPERCASE_SERVICE]) => { - encode_response(req, self.start_uppercase_service(ctx, dec.decode()?))? - } - (Post, ["node", "services", DefaultAddress::ECHO_SERVICE]) => { - encode_response(req, self.start_echoer_service(ctx, dec.decode()?).await)? - } - (Post, ["node", "services", DefaultAddress::HOP_SERVICE]) => { - encode_response(req, self.start_hop_service(ctx, dec.decode()?))? - } + (Post, ["node", "services", DefaultAddress::UPPERCASE_SERVICE]) => encode_response( + &header, + self.start_uppercase_service(ctx, Decodable::decode(&body)?), + ), + (Post, ["node", "services", DefaultAddress::ECHO_SERVICE]) => encode_response( + &header, + self.start_echoer_service(ctx, Decodable::decode(&body)?) + .await, + ), + (Post, ["node", "services", DefaultAddress::HOP_SERVICE]) => encode_response( + &header, + self.start_hop_service(ctx, Decodable::decode(&body)?), + ), (Post, ["node", "services", DefaultAddress::KAFKA_OUTLET]) => encode_response( - req, - self.start_kafka_outlet_service(ctx, dec.decode()?).await, - )?, + &header, + self.start_kafka_outlet_service(ctx, Decodable::decode(&body)?) + .await, + ), (Delete, ["node", "services", DefaultAddress::KAFKA_OUTLET]) => encode_response( - req, - self.delete_kafka_service(ctx, dec.decode()?, KafkaServiceKind::Outlet) + &header, + self.delete_kafka_service(ctx, Decodable::decode(&body)?, KafkaServiceKind::Outlet) .await, - )?, + ), (Post, ["node", "services", DefaultAddress::KAFKA_INLET]) => encode_response( - req, - self.start_kafka_inlet_service(ctx, dec.decode()?).await, - )?, + &header, + self.start_kafka_inlet_service(ctx, Decodable::decode(&body)?) + .await, + ), (Delete, ["node", "services", DefaultAddress::KAFKA_INLET]) => encode_response( - req, - self.delete_kafka_service(ctx, dec.decode()?, KafkaServiceKind::Inlet) + &header, + self.delete_kafka_service(ctx, Decodable::decode(&body)?, KafkaServiceKind::Inlet) .await, - )?, + ), (Post, ["node", "services", DefaultAddress::LEASE_MANAGER]) => encode_response( - req, - self.start_influxdb_lease_issuer_service(ctx, dec.decode()?) + &header, + self.start_influxdb_lease_issuer_service(ctx, Decodable::decode(&body)?) .await, - )?, + ), (Delete, ["node", "services", DefaultAddress::LEASE_MANAGER]) => encode_response( - req, - self.delete_influxdb_lease_issuer_service(ctx, dec.decode()?), - )?, - (Get, ["node", "services"]) => encode_response(req, self.list_services())?, + &header, + self.delete_influxdb_lease_issuer_service(ctx, Decodable::decode(&body)?), + ), + (Get, ["node", "services"]) => encode_response(&header, self.list_services()), (Get, ["node", "services", service_type]) => { - encode_response(req, self.list_services_of_type(service_type))? + encode_response(&header, self.list_services_of_type(service_type)) } // ==*== Relay commands ==*== (Get, ["node", "relay", alias]) => { - encode_response(req, self.show_relay(req, alias).await)? + encode_response(&header, self.show_relay(&header, alias).await) } - (Get, ["node", "relay"]) => encode_response(req, self.get_relays(req).await)?, + (Get, ["node", "relay"]) => encode_response(&header, self.get_relays(&header).await), (Delete, ["node", "relay", alias]) => { - encode_response(req, self.delete_relay(req, alias).await)? - } - (Post, ["node", "relay"]) => { - encode_response(req, self.create_relay(ctx, req, dec.decode()?).await)? + encode_response(&header, self.delete_relay(&header, alias).await) } + (Post, ["node", "relay"]) => encode_response( + &header, + self.create_relay(ctx, &header, Decodable::decode(&body)?) + .await, + ), // ==*== Inlets & Outlets ==*== - (Get, ["node", "inlet"]) => encode_response(req, self.get_inlets().await)?, - (Get, ["node", "inlet", alias]) => encode_response(req, self.show_inlet(alias).await)?, - (Get, ["node", "outlet"]) => self.get_outlets(req).to_vec()?, + (Get, ["node", "inlet"]) => encode_response(&header, self.get_inlets().await), + (Get, ["node", "inlet", alias]) => { + encode_response(&header, self.show_inlet(alias).await) + } + (Get, ["node", "outlet"]) => encode_response(&header, self.get_outlets().await), (Get, ["node", "outlet", addr]) => { let addr: Address = addr.to_string().into(); - encode_response(req, self.show_outlet(&addr))? - } - (Post, ["node", "inlet"]) => { - encode_response(req, self.create_inlet(ctx, dec.decode()?).await)? - } - (Post, ["node", "outlet"]) => { - encode_response(req, self.create_outlet(ctx, dec.decode()?).await)? - } + encode_response(&header, self.show_outlet(&addr)) + } + (Post, ["node", "inlet"]) => encode_response( + &header, + self.create_inlet(ctx, Decodable::decode(&body)?).await, + ), + (Post, ["node", "outlet"]) => encode_response( + &header, + self.create_outlet(ctx, Decodable::decode(&body)?).await, + ), (Delete, ["node", "outlet", addr]) => { let addr: Address = addr.to_string().into(); - encode_response(req, self.delete_outlet(&addr).await)? + encode_response(&header, self.delete_outlet(&addr).await) } (Delete, ["node", "inlet", alias]) => { - encode_response(req, self.delete_inlet(alias).await)? + encode_response(&header, self.delete_inlet(alias).await) } (Delete, ["node", "portal"]) => todo!(), // ==*== InfluxDB Inlets & Outlets ==*== (Post, ["node", "influxdb_inlet"]) => encode_response( - req, - self.start_influxdb_inlet_service(ctx, dec.decode()?).await, - )?, + &header, + self.start_influxdb_inlet_service(ctx, Decodable::decode(&body)?) + .await, + ), (Post, ["node", "influxdb_outlet"]) => encode_response( - req, - self.start_influxdb_outlet_service(ctx, dec.decode()?).await, - )?, + &header, + self.start_influxdb_outlet_service(ctx, Decodable::decode(&body)?) + .await, + ), // ==*== Flow Controls ==*== - (Post, ["node", "flow_controls", "add_consumer"]) => { - encode_response(req, self.add_consumer(ctx, dec.decode()?).await)? - } + (Post, ["node", "flow_controls", "add_consumer"]) => encode_response( + &header, + self.add_consumer(ctx, Decodable::decode(&body)?).await, + ), // ==*== Workers ==*== - (Get, ["node", "workers"]) => encode_response(req, self.list_workers(ctx).await)?, + (Get, ["node", "workers"]) => encode_response(&header, self.list_workers(ctx).await), // ==*== Policies ==*== (Post, ["policy", action]) => { - let payload: SetPolicyRequest = dec.decode()?; + let payload: SetPolicyRequest = Decodable::decode(&body)?; encode_response( - req, + &header, self.add_policy(action, payload.resource, payload.expression) .await, - )? - } - (Get, ["policy", action]) => { - encode_response(req, self.get_policy(action, dec.decode()?).await)? - } - (Get, ["policy"]) => encode_response(req, self.list_policies(dec.decode()?).await)?, - (Delete, ["policy", action]) => { - encode_response(req, self.delete_policy(action, dec.decode()?).await)? - } + ) + } + (Get, ["policy", action]) => encode_response( + &header, + self.get_policy(action, Decodable::decode(&body)?).await, + ), + (Get, ["policy"]) => { + let resource_type_or_name_option: ResourceTypeOrNameOption = + Decodable::decode(&body)?; + encode_response( + &header, + self.list_policies(resource_type_or_name_option.0).await, + ) + } + (Delete, ["policy", action]) => encode_response( + &header, + self.delete_policy(action, Decodable::decode(&body)?).await, + ), // ==*== Messages ==*== (Post, ["v0", "message"]) => { - encode_response(req, self.send_message(ctx, dec.decode()?).await)? + let send_message: SendMessage> = Decodable::decode(&body)?; + encode_response( + &header, + self.send_message::, Vec>(ctx, send_message) + .await, + ) } // ==*== Catch-all for Unimplemented APIs ==*== _ => { warn!(%method, %path, "Called invalid endpoint"); - Response::bad_request(req, &format!("Invalid endpoint: {} {}", method, path)) - .to_vec()? + encode_response::>( + &header, + Err(Response::bad_request( + &header, + &format!("Invalid endpoint: {} {}", method, path), + )), + ) } - }; - Ok(r) + } } } #[ockam::worker] impl Worker for NodeManagerWorker { - type Message = Vec; + type Message = Request>; type Context = Context; async fn shutdown(&mut self, _ctx: &mut Self::Context) -> Result<()> { @@ -248,39 +299,38 @@ impl Worker for NodeManagerWorker { Ok(()) } - async fn handle_message(&mut self, ctx: &mut Context, msg: Routed>) -> Result<()> { + async fn handle_message( + &mut self, + ctx: &mut Context, + msg: Routed>>, + ) -> Result<()> { let return_route = msg.return_route().clone(); - let body = msg.into_body()?; - let mut dec = Decoder::new(&body); - let req: RequestHeader = match dec.decode() { - Ok(r) => r, - Err(e) => { - error!("Failed to decode request: {:?}", e); - return Ok(()); - } - }; - - let r = match self.handle_request(ctx, &req, &mut dec).await { + let request = msg.into_body()?; + let request_header = request.header().clone(); + let r = match self.handle_request(ctx, request).await { Ok(r) => r, Err(err) => { error! { target: TARGET, - re = %req.id(), - method = ?req.method(), - path = %req.path(), + re = %request_header.id(), + method = ?request_header.method(), + path = %request_header.path(), code = %err.code(), cause = ?err.source(), "failed to handle request" } - Response::internal_error(&req, &format!("failed to handle request: {err} {req:?}")) - .to_vec()? + Response::internal_error( + &request_header, + &format!("failed to handle request: {err}"), + ) + .encode_body()? } }; debug! { target: TARGET, - re = %req.id(), - method = ?req.method(), - path = %req.path(), + re = %request_header.id(), + method = ?request_header.method(), + path = %request_header.path(), "responding" } ctx.send(return_route, r).await diff --git a/implementations/rust/ockam/ockam_api/src/okta/mod.rs b/implementations/rust/ockam/ockam_api/src/okta/mod.rs index d3b8734497a..28a0c2ac11d 100644 --- a/implementations/rust/ockam/ockam_api/src/okta/mod.rs +++ b/implementations/rust/ockam/ockam_api/src/okta/mod.rs @@ -1,11 +1,11 @@ use crate::authenticator::{AuthorityMember, AuthorityMembersRepository}; use crate::error::ApiError; +use crate::orchestrator::enroll::auth0::AuthenticateOidcToken; use core::str; -use minicbor::Decoder; use ockam::identity::utils::now; use ockam::identity::Identifier; -use ockam_core::api::{Method, RequestHeader, Response}; -use ockam_core::{self, Result, Routed, SecureChannelLocalInfo, Worker}; +use ockam_core::api::{Method, Request, Response}; +use ockam_core::{self, Decodable, Result, Routed, SecureChannelLocalInfo, Worker}; use ockam_node::Context; use reqwest::StatusCode; use std::collections::HashMap; @@ -23,21 +23,20 @@ pub struct Server { #[ockam_core::worker] impl Worker for Server { type Context = Context; - type Message = Vec; + type Message = Request>; async fn handle_message(&mut self, c: &mut Context, m: Routed) -> Result<()> { if let Ok(i) = SecureChannelLocalInfo::find_info(m.local_message()) { let return_route = m.return_route().clone(); + let request = m.into_body()?; let reply = self - .on_request(&i.their_identifier().into(), &m.into_body()?) + .on_request(&i.their_identifier().into(), request) .await?; c.send(return_route, reply).await } else { let return_route = m.return_route().clone(); - let body = m.into_body()?; - let mut dec = Decoder::new(&body); - let req: RequestHeader = dec.decode()?; - let res = Response::forbidden(&req, "secure channel required").to_vec()?; + let request = m.into_body()?; + let res = Response::forbidden(request.header(), "secure channel required"); c.send(return_route, res).await } } @@ -62,28 +61,30 @@ impl Server { }) } - async fn on_request(&mut self, from: &Identifier, data: &[u8]) -> Result> { - let mut dec = Decoder::new(data); - let req: RequestHeader = dec.decode()?; + async fn on_request( + &mut self, + from: &Identifier, + request: Request>, + ) -> Result>> { + let (header, body) = request.into_parts(); trace! { target: "ockam_api::okta::server", from = %from, - id = %req.id(), - method = ?req.method(), - path = %req.path(), - body = %req.has_body(), + id = %header.id(), + method = ?header.method(), + path = %header.path(), + body = %header.has_body(), "request" } - let res = match req.method() { - Some(Method::Post) => match req.path_segments::<2>().as_slice() { + let res = match header.method() { + Some(Method::Post) => match header.path_segments::<2>().as_slice() { // Device Flow authentication ["v0", "enroll"] => { debug!("Checking token"); // TODO: check token_type // TODO: it's AuthenticateAuth0Token or something else?. Probably rename. - let token: crate::orchestrator::enroll::auth0::AuthenticateOidcToken = - dec.decode()?; + let token = AuthenticateOidcToken::decode(&body.unwrap_or_default())?; debug!("device code received: {token:#?}"); if let Some(attrs) = self.check_token(&token.access_token.0).await? { //TODO in some future, we will want to track that this entry @@ -100,14 +101,14 @@ impl Server { self.member_attributes_repository .add_member(&self.authority, member) .await?; - Response::ok().with_headers(&req).to_vec()? + Response::ok().with_headers(&header).encode_body()? } else { - Response::forbidden(&req, "Forbidden").to_vec()? + Response::forbidden(&header, "Forbidden").encode_body()? } } - _ => Response::unknown_path(&req).to_vec()?, + _ => Response::unknown_path(&header).encode_body()?, }, - _ => Response::invalid_method(&req).to_vec()?, + _ => Response::invalid_method(&header).encode_body()?, }; Ok(res) } diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/addon.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/addon.rs index 2faa26b1a59..a52359d623d 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/addon.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/addon.rs @@ -3,19 +3,19 @@ use minicbor::{CborLen, Decode, Encode}; use serde::{Deserialize, Serialize}; use std::fmt::Write; -use ockam_core::api::Request; -use ockam_core::async_trait; -use ockam_node::Context; - use crate::orchestrator::operation::CreateOperationResponse; use crate::orchestrator::project::models::{InfluxDBTokenLeaseManagerConfig, OktaConfig}; use crate::orchestrator::{ControllerClient, HasSecureClient}; use crate::output::Output; use crate::Result; +use ockam::Message; +use ockam_core::api::Request; +use ockam_core::{async_trait, cbor_encode_preallocate, Decodable, Encodable, Encoded}; +use ockam_node::Context; const API_SERVICE: &str = "projects"; -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Message)] #[cfg_attr(test, derive(Clone))] #[cbor(map)] pub struct Addon { @@ -27,6 +27,18 @@ pub struct Addon { pub enabled: bool, } +impl Encodable for Addon { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for Addon { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl Output for Addon { fn item(&self) -> Result { let mut w = String::new(); @@ -39,7 +51,22 @@ impl Output for Addon { } } -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] +#[derive(Encode, Decode, CborLen, Debug, Message)] +#[cbor(transparent)] +pub struct AddonList(#[n(0)] pub Vec); + +impl Encodable for AddonList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for AddonList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Message)] #[rustfmt::skip] #[cbor(map)] pub struct KafkaConfig { @@ -47,6 +74,18 @@ pub struct KafkaConfig { #[cbor(n(1))] pub bootstrap_server: String, } +impl Encodable for KafkaConfig { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for KafkaConfig { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl KafkaConfig { pub fn new>(bootstrap_server: S) -> Self { Self { @@ -64,13 +103,25 @@ impl quickcheck::Arbitrary for KafkaConfig { } } -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Message)] #[rustfmt::skip] #[cbor(map)] pub struct DisableAddon { #[cbor(n(1))] pub addon_id: String, } +impl Encodable for DisableAddon { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for DisableAddon { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl DisableAddon { pub fn new>(addon_id: S) -> Self { Self { @@ -118,11 +169,13 @@ impl Addons for ControllerClient { async fn list_addons(&self, ctx: &Context, project_id: &str) -> miette::Result> { trace!(project_id, "listing addons"); let req = Request::get(format!("/v0/{project_id}/addons")); - self.get_secure_client() + let addon_list: AddonList = self + .get_secure_client() .ask(ctx, API_SERVICE, req) .await .into_diagnostic()? - .miette_success("list addons") + .miette_success("list addons")?; + Ok(addon_list.0) } #[instrument(skip_all, fields(project_id = project_id))] diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/enroll.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/enroll.rs index db680e9820e..fce974fc623 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/enroll.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/enroll.rs @@ -24,8 +24,9 @@ impl Token { pub mod auth0 { use super::*; use crate::orchestrator::email_address::EmailAddress; + use ockam::Message; + use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use std::fmt::{Display, Formatter}; - // Req/Res types #[derive(serde::Deserialize, Debug, PartialEq, Eq)] @@ -86,7 +87,7 @@ pub mod auth0 { } } - #[derive(Encode, Decode, CborLen, Debug)] + #[derive(Encode, Decode, CborLen, Debug, Message)] #[cfg_attr(test, derive(Clone))] #[rustfmt::skip] #[cbor(map)] @@ -95,6 +96,18 @@ pub mod auth0 { #[n(2)] pub access_token: Token, } + impl Encodable for AuthenticateOidcToken { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } + } + + impl Decodable for AuthenticateOidcToken { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } + } + impl AuthenticateOidcToken { pub fn new(token: OidcToken) -> Self { Self { diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/operation.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/operation.rs index 8ace3d178dc..ca08f50cbfa 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/operation.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/operation.rs @@ -1,15 +1,16 @@ use crate::orchestrator::{ControllerClient, HasSecureClient, ORCHESTRATOR_AWAIT_TIMEOUT}; use miette::{miette, IntoDiagnostic}; use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; use ockam_core::api::Request; -use ockam_core::async_trait; +use ockam_core::{async_trait, cbor_encode_preallocate, Decodable, Encodable, Encoded}; use ockam_node::Context; use serde::{Deserialize, Serialize}; use tokio_retry::strategy::FixedInterval; use tokio_retry::Retry; use tracing::trace; -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone, Message)] #[cbor(map)] pub struct Operation { #[cbor(n(1))] @@ -19,6 +20,18 @@ pub struct Operation { pub status: Status, } +impl Encodable for Operation { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for Operation { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl Operation { pub fn is_successful(&self) -> bool { self.status == Status::Succeeded @@ -33,13 +46,24 @@ impl Operation { } } -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Default, Clone, Message)] #[cbor(map)] pub struct CreateOperationResponse { #[cbor(n(1))] pub operation_id: String, } +impl Encodable for CreateOperationResponse { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateOperationResponse { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} #[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone, PartialEq)] #[rustfmt::skip] #[cbor(index_only)] diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/project/controller_client.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/project/controller_client.rs index 1836c3f702f..97551939c37 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/project/controller_client.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/project/controller_client.rs @@ -1,5 +1,5 @@ use crate::orchestrator::operation::Operations; -use crate::orchestrator::project::models::CreateProject; +use crate::orchestrator::project::models::{AdminInfoList, CreateProject, ProjectModelList}; use crate::orchestrator::project::models::{OrchestratorVersionInfo, ProjectModel}; use crate::orchestrator::{ControllerClient, HasSecureClient, ORCHESTRATOR_AWAIT_TIMEOUT}; @@ -80,7 +80,7 @@ impl ControllerClient { email: &EmailAddress, ) -> miette::Result { trace!("adding new space administrator"); - let admins: Vec = self + let admins: AdminInfoList = self .get_secure_client() .ask( ctx, @@ -91,6 +91,7 @@ impl ControllerClient { .into_diagnostic()? .miette_success("add space admins")?; admins + .0 .into_iter() .find(|a| a.email == email.to_string()) .ok_or(miette!( @@ -104,7 +105,8 @@ impl ControllerClient { space_id: &str, ) -> miette::Result> { trace!("listing space administrators"); - self.get_secure_client() + let admin_info_list: AdminInfoList = self + .get_secure_client() .ask( ctx, "spaces", @@ -112,7 +114,8 @@ impl ControllerClient { ) .await .into_diagnostic()? - .miette_success("get space admins") + .miette_success("get space admins")?; + Ok(admin_info_list.0) } pub async fn delete_space_admin( @@ -122,7 +125,7 @@ impl ControllerClient { email: &EmailAddress, ) -> miette::Result<()> { trace!("deleting space administrator"); - let _admins: Vec = self + let _admins: AdminInfoList = self .get_secure_client() .ask( ctx, @@ -142,7 +145,7 @@ impl ControllerClient { email: &EmailAddress, ) -> miette::Result { trace!("adding new project administrator"); - let admins: Vec = self + let admins: AdminInfoList = self .get_secure_client() .ask( ctx, @@ -153,6 +156,7 @@ impl ControllerClient { .into_diagnostic()? .miette_success("add project admins")?; admins + .0 .into_iter() .find(|a| a.email == email.to_string()) .ok_or(miette!( @@ -166,7 +170,8 @@ impl ControllerClient { project_id: &str, ) -> miette::Result> { trace!("listing project administrators"); - self.get_secure_client() + let admin_info_list: AdminInfoList = self + .get_secure_client() .ask( ctx, "projects", @@ -174,7 +179,8 @@ impl ControllerClient { ) .await .into_diagnostic()? - .miette_success("get project admins") + .miette_success("get project admins")?; + Ok(admin_info_list.0) } pub async fn delete_project_admin( @@ -184,7 +190,7 @@ impl ControllerClient { email: &EmailAddress, ) -> miette::Result<()> { trace!("deleting project administrator"); - let _admins: Vec = self + let _admins: AdminInfoList = self .get_secure_client() .ask( ctx, @@ -200,11 +206,13 @@ impl ControllerClient { #[instrument(skip_all)] pub async fn list_projects(&self, ctx: &Context) -> miette::Result> { let req = Request::get("/v0"); - self.get_secure_client() + let project_model_list: ProjectModelList = self + .get_secure_client() .ask(ctx, "projects", req) .await .into_diagnostic()? - .miette_success("list projects") + .miette_success("list projects")?; + Ok(project_model_list.0) } pub async fn wait_until_project_creation_operation_is_complete( diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/project/models.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/project/models.rs index 948970eb728..662b27ff090 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/project/models.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/project/models.rs @@ -6,10 +6,14 @@ use crate::orchestrator::share::{RoleInShare, ShareScope}; use crate::output::Output; use minicbor::{CborLen, Decode, Encode}; use ockam::identity::Identifier; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] +#[derive( + Encode, Decode, CborLen, Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Message, +)] #[cbor(map)] pub struct ProjectModel { #[cbor(n(1))] @@ -63,7 +67,37 @@ pub struct ProjectModel { pub project_change_history: Option, } -#[derive(Encode, Decode, CborLen, Debug)] +impl Encodable for ProjectModel { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ProjectModel { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + +#[derive( + Encode, Decode, CborLen, Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Message, +)] +#[cbor(transparent)] +pub struct ProjectModelList(#[n(0)] pub(crate) Vec); + +impl Encodable for ProjectModelList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ProjectModelList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + +#[derive(Encode, Decode, CborLen, Debug, Message)] #[cfg_attr(test, derive(Clone))] #[rustfmt::skip] #[cbor(map)] @@ -72,13 +106,24 @@ pub struct CreateProject { #[n(3)] pub users: Vec, } +impl Encodable for CreateProject { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateProject { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} impl CreateProject { pub fn new(name: String, users: Vec) -> Self { Self { name, users } } } -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Message)] #[rustfmt::skip] #[cbor(map)] pub struct InfluxDBTokenLeaseManagerConfig { @@ -91,6 +136,18 @@ pub struct InfluxDBTokenLeaseManagerConfig { #[cbor(n(7))] pub admin_access_rule: Option, } +impl Encodable for InfluxDBTokenLeaseManagerConfig { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for InfluxDBTokenLeaseManagerConfig { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl InfluxDBTokenLeaseManagerConfig { pub fn new>( endpoint: S, @@ -117,7 +174,7 @@ impl InfluxDBTokenLeaseManagerConfig { } } -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Message)] #[rustfmt::skip] #[cbor(map)] pub struct OktaConfig { @@ -127,6 +184,18 @@ pub struct OktaConfig { #[cbor(n(4))] pub attributes: Vec, } +impl Encodable for OktaConfig { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for OktaConfig { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl OktaConfig { pub fn new( tenant_base_url: Url, @@ -156,7 +225,7 @@ impl OktaConfig { } } -#[derive(Decode, Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] #[cbor(map)] pub struct AdminInfo { /// The email of a space or project Admin @@ -171,13 +240,33 @@ impl Display for AdminInfo { } } +#[derive( + Encode, Decode, CborLen, Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Message, +)] +#[cbor(transparent)] +pub struct AdminInfoList(#[n(0)] pub(crate) Vec); + +impl Encodable for AdminInfoList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for AdminInfoList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl Output for AdminInfo { fn item(&self) -> crate::Result { Ok(self.padded_display()) } } -#[derive(Decode, Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] +#[derive( + Encode, Decode, CborLen, Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Message, +)] #[cbor(map)] pub struct OrchestratorVersionInfo { /// The version of the Orchestrator Controller @@ -189,6 +278,18 @@ pub struct OrchestratorVersionInfo { pub project_version: Option, } +impl Encodable for OrchestratorVersionInfo { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for OrchestratorVersionInfo { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl OrchestratorVersionInfo { pub fn version(&self) -> String { self.version.clone().unwrap_or("N/A".to_string()) diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/share/accept.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/share/accept.rs index 982c33dff43..c7335b4d238 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/share/accept.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/share/accept.rs @@ -1,16 +1,29 @@ +use super::RoleInShare; use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use serde::Serialize; -use super::RoleInShare; - -#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, Message)] #[cbor(map)] #[rustfmt::skip] pub struct AcceptInvitation { #[n(1)] pub id: String, } -#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize)] +impl Encodable for AcceptInvitation { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for AcceptInvitation { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + +#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, Message)] #[cbor(map)] #[rustfmt::skip] pub struct AcceptedInvitation { @@ -18,3 +31,15 @@ pub struct AcceptedInvitation { #[n(2)] pub scope: RoleInShare, #[n(3)] pub target_id: String, } + +impl Encodable for AcceptedInvitation { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for AcceptedInvitation { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/share/create.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/share/create.rs index d96027d130e..0c8141f8183 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/share/create.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/share/create.rs @@ -8,8 +8,10 @@ use crate::cli_state::{CliState, EnrollmentTicket}; use crate::error::ApiError; use crate::orchestrator::email_address::EmailAddress; use ockam::identity::Identifier; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; -#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, Message)] #[cbor(map)] #[rustfmt::skip] pub struct CreateInvitation { @@ -21,7 +23,19 @@ pub struct CreateInvitation { #[n(6)] pub target_id: String, } -#[derive(Clone, Debug, Encode, Decode, CborLen, Deserialize, Serialize)] +impl Encodable for CreateInvitation { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateInvitation { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + +#[derive(Clone, Debug, Encode, Decode, CborLen, Deserialize, Serialize, Message)] #[cbor(map)] #[rustfmt::skip] pub struct CreateServiceInvitation { @@ -39,6 +53,18 @@ pub struct CreateServiceInvitation { #[n(10)] pub enrollment_ticket: String, } +impl Encodable for CreateServiceInvitation { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateServiceInvitation { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateServiceInvitation { pub async fn new>( cli_state: &CliState, diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/share/invitation.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/share/invitation.rs index a8615494f2b..f80eda12491 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/share/invitation.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/share/invitation.rs @@ -6,6 +6,8 @@ use crate::orchestrator::email_address::EmailAddress; use crate::output::Output; use minicbor::{CborLen, Decode, Encode}; use ockam::identity::Identifier; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use serde::{Deserialize, Serialize}; use std::{fmt::Display, str::FromStr}; @@ -73,7 +75,7 @@ impl FromStr for ShareScope { } } -#[derive(Clone, Debug, Encode, Decode, CborLen, Deserialize, Serialize)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Deserialize, Serialize, Message)] #[cbor(map)] #[rustfmt::skip] pub struct InvitationWithAccess { @@ -81,6 +83,18 @@ pub struct InvitationWithAccess { #[n(2)] pub service_access_details: Option, } +impl Encodable for InvitationWithAccess { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for InvitationWithAccess { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl PartialEq for InvitationWithAccess { fn eq(&self, other: &Self) -> bool { self.invitation.id == other.invitation.id @@ -117,7 +131,7 @@ impl Output for ReceivedInvitation { } } -#[derive(Clone, Debug, Encode, Decode, CborLen, Deserialize, Serialize, PartialEq)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Deserialize, Serialize, PartialEq, Message)] #[cbor(map)] #[rustfmt::skip] pub struct SentInvitation { @@ -133,6 +147,18 @@ pub struct SentInvitation { #[n(10)] pub access_details: Option, } +impl Encodable for SentInvitation { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for SentInvitation { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl SentInvitation { pub fn is_expired(&self) -> ockam_core::Result { is_expired(&self.expires_at) diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/share/list.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/share/list.rs index 0ce5184e9ca..9cd0f67db25 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/share/list.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/share/list.rs @@ -1,15 +1,28 @@ +use super::{InvitationWithAccess, ReceivedInvitation, SentInvitation}; use minicbor::{CborLen, Decode, Encode}; +use ockam::Message; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded}; use serde::{Deserialize, Serialize}; -use super::{InvitationWithAccess, ReceivedInvitation, SentInvitation}; - -#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, Message)] #[cbor(map)] #[rustfmt::skip] pub struct ListInvitations { #[n(1)] pub kind: InvitationListKind, } +impl Encodable for ListInvitations { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ListInvitations { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + #[derive(Clone, Debug, PartialEq, Decode, Encode, CborLen, Deserialize, Serialize)] #[cbor(index_only)] #[rustfmt::skip] @@ -20,7 +33,7 @@ pub enum InvitationListKind { #[n(3)] Accepted, } -#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize)] +#[derive(Clone, Debug, Encode, Decode, CborLen, Serialize, Message)] #[cbor(map)] #[rustfmt::skip] pub struct InvitationList { @@ -28,3 +41,15 @@ pub struct InvitationList { #[n(2)] pub received: Option>, #[n(3)] pub accepted: Option>, } + +impl Encodable for InvitationList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for InvitationList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/space.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/space.rs index 5d2f0ff42ad..a55467b8658 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/space.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/space.rs @@ -3,8 +3,9 @@ use minicbor::{CborLen, Decode, Encode}; use serde::Serialize; use std::fmt::{Display, Formatter, Write}; +use ockam::Message; use ockam_core::api::Request; -use ockam_core::async_trait; +use ockam_core::{async_trait, cbor_encode_preallocate, Decodable, Encodable, Encoded}; use ockam_node::Context; use crate::colors::{color_primary, color_uri, color_warn}; @@ -18,7 +19,7 @@ use crate::output::{comma_separated, Output}; use crate::terminal::fmt; use crate::{fmt_log, UtcDateTime}; -#[derive(Encode, Decode, CborLen, Serialize, Debug, Clone, PartialEq, Eq)] +#[derive(Encode, Decode, CborLen, Serialize, Debug, Clone, PartialEq, Eq, Message)] #[rustfmt::skip] #[cbor(map)] pub struct Space { @@ -28,6 +29,18 @@ pub struct Space { #[n(4)] pub subscription: Option, } +impl Encodable for Space { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for Space { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl Space { pub fn space_id(&self) -> String { self.id.clone() @@ -122,7 +135,7 @@ impl Output for Space { } } -#[derive(Encode, Decode, CborLen, Debug)] +#[derive(Encode, Decode, CborLen, Debug, Message)] #[cfg_attr(test, derive(Clone))] #[rustfmt::skip] #[cbor(map)] @@ -131,6 +144,34 @@ pub struct CreateSpace { #[n(2)] pub users: Vec, } +impl Encodable for CreateSpace { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CreateSpace { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + +#[derive(Encode, Decode, CborLen, Debug, Message)] +#[cbor(transparent)] +pub struct SpaceList(#[n(0)] pub Vec); + +impl Encodable for SpaceList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for SpaceList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + impl CreateSpace { pub fn new(name: String, users: Vec) -> Self { Self { name, users } @@ -347,11 +388,13 @@ impl ControllerClient { pub async fn list_spaces(&self, ctx: &Context) -> miette::Result> { trace!("listing spaces"); - self.get_secure_client() + let space_list: SpaceList = self + .get_secure_client() .ask(ctx, "spaces", Request::get("/v0/")) .await .into_diagnostic()? - .miette_success("list spaces") + .miette_success("list spaces")?; + Ok(space_list.0) } } diff --git a/implementations/rust/ockam/ockam_api/src/orchestrator/subscription.rs b/implementations/rust/ockam/ockam_api/src/orchestrator/subscription.rs index 61a11d0a3b3..57cb8c7914c 100644 --- a/implementations/rust/ockam/ockam_api/src/orchestrator/subscription.rs +++ b/implementations/rust/ockam/ockam_api/src/orchestrator/subscription.rs @@ -4,9 +4,13 @@ use crate::orchestrator::{ControllerClient, HasSecureClient}; use crate::output::Output; use crate::terminal::fmt; use colorful::{Colorful, RGB}; +use miette::IntoDiagnostic; use minicbor::{decode, encode, CborLen, Decode, Decoder, Encode}; -use ockam_core::api::{Error, Reply, Request, Status}; -use ockam_core::{self, async_trait, Result}; +use ockam::Message; +use ockam_core::api::{Reply, Request}; +use ockam_core::{ + self, async_trait, cbor_encode_preallocate, Decodable, Encodable, Encoded, Result, +}; use ockam_node::Context; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter, Write}; @@ -17,7 +21,7 @@ const API_SERVICE: &str = "subscriptions"; pub const SUBSCRIPTION_PAGE: &str = "https://orchestrator.ockam.io"; -#[derive(Encode, Decode, CborLen, Debug)] +#[derive(Encode, Decode, CborLen, Debug, Message)] #[cfg_attr(test, derive(Clone))] #[rustfmt::skip] #[cbor(map)] @@ -28,6 +32,18 @@ pub struct ActivateSubscription { #[n(4)] pub owner_emails: Option>, } +impl Encodable for ActivateSubscription { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for ActivateSubscription { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl ActivateSubscription { /// Activates a subscription for an existing space pub fn existing>(space_id: S, subscription_data: S) -> Self { @@ -187,7 +203,7 @@ impl Encode for SubscriptionName { e: &mut minicbor::Encoder, ctx: &mut C, ) -> std::result::Result<(), encode::Error> { - self.to_string().encode(e, ctx) + >::encode(&self.to_string(), e, ctx) } } @@ -199,7 +215,7 @@ impl CborLen for SubscriptionName { impl<'b, C> Decode<'b, C> for SubscriptionName { fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> std::result::Result { - SubscriptionName::from_str(&String::decode(d, ctx)?) + SubscriptionName::from_str(&>::decode(d, ctx)?) .map_err(|_| decode::Error::message("Invalid subscription name")) } } @@ -220,7 +236,7 @@ impl SubscriptionName { /// The commands using this API were already removed, but the Controller still supports it. /// This struct along with the [Subscriptions] trait can be removed once the Controller stops /// supporting the legacy API. -#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Message)] #[cbor(map)] pub struct SubscriptionLegacy { #[n(1)] @@ -239,6 +255,18 @@ pub struct SubscriptionLegacy { pub space_id: Option, } +impl Encodable for SubscriptionLegacy { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for SubscriptionLegacy { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl Output for SubscriptionLegacy { fn item(&self) -> crate::Result { let mut w = String::new(); @@ -257,6 +285,22 @@ impl Output for SubscriptionLegacy { } } +#[derive(Encode, Decode, CborLen, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Message)] +#[cbor(map)] +pub struct SubscriptionLegacyList(#[n(0)] pub(crate) Vec); + +impl Encodable for SubscriptionLegacyList { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for SubscriptionLegacyList { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + #[async_trait] pub trait Subscriptions { async fn activate_subscription( @@ -264,41 +308,41 @@ pub trait Subscriptions { ctx: &Context, space_id: String, subscription_data: String, - ) -> Result>; + ) -> miette::Result; async fn unsubscribe( &self, ctx: &Context, subscription_id: String, - ) -> Result>; + ) -> miette::Result; async fn update_subscription_contact_info( &self, ctx: &Context, subscription_id: String, contact_info: String, - ) -> Result>; + ) -> miette::Result; async fn update_subscription_space( &self, ctx: &Context, subscription_id: String, new_space_id: String, - ) -> Result>; + ) -> miette::Result; - async fn get_subscriptions(&self, ctx: &Context) -> Result>>; + async fn get_subscriptions(&self, ctx: &Context) -> miette::Result>; async fn get_subscription( &self, ctx: &Context, subscription_id: String, - ) -> Result>; + ) -> miette::Result>; async fn get_subscription_by_space_id( &self, ctx: &Context, space_id: String, - ) -> Result>; + ) -> miette::Result>; } #[async_trait] @@ -309,11 +353,14 @@ impl Subscriptions for ControllerClient { ctx: &Context, space_id: String, subscription_data: String, - ) -> Result> { + ) -> miette::Result { let req_body = ActivateSubscription::existing(space_id, subscription_data); trace!(space_id = ?req_body.space_id, space_name = ?req_body.space_name, "activating subscription"); let req = Request::post("/v0/activate").body(req_body); - self.get_secure_client().ask(ctx, API_SERVICE, req).await + self.get_secure_client() + .ask(ctx, API_SERVICE, req) + .await? + .miette_success("subscription legacy") } #[instrument(skip_all, fields(subscription_id = subscription_id))] @@ -321,10 +368,13 @@ impl Subscriptions for ControllerClient { &self, ctx: &Context, subscription_id: String, - ) -> Result> { + ) -> miette::Result { trace!(subscription = %subscription_id, "unsubscribing"); let req = Request::put(format!("/v0/{subscription_id}/unsubscribe")); - self.get_secure_client().ask(ctx, API_SERVICE, req).await + self.get_secure_client() + .ask(ctx, API_SERVICE, req) + .await? + .miette_success("subscription legacy") } #[instrument(skip_all, fields(subscription_id = subscription_id, contact_info = contact_info))] @@ -333,10 +383,13 @@ impl Subscriptions for ControllerClient { ctx: &Context, subscription_id: String, contact_info: String, - ) -> Result> { + ) -> miette::Result { trace!(subscription = %subscription_id, "updating subscription contact info"); let req = Request::put(format!("/v0/{subscription_id}/contact_info")).body(contact_info); - self.get_secure_client().ask(ctx, API_SERVICE, req).await + self.get_secure_client() + .ask(ctx, API_SERVICE, req) + .await? + .miette_success("subscription legacy") } #[instrument(skip_all, fields(subscription_id = subscription_id, new_space_id = new_space_id))] @@ -345,17 +398,23 @@ impl Subscriptions for ControllerClient { ctx: &Context, subscription_id: String, new_space_id: String, - ) -> Result> { + ) -> miette::Result { trace!(subscription = %subscription_id, new_space_id = %new_space_id, "updating subscription space"); let req = Request::put(format!("/v0/{subscription_id}/space_id")).body(new_space_id); - self.get_secure_client().ask(ctx, API_SERVICE, req).await + self.get_secure_client() + .ask(ctx, API_SERVICE, req) + .await + .into_diagnostic()? + .miette_success("subscription legacy") } #[instrument(skip_all)] - async fn get_subscriptions(&self, ctx: &Context) -> Result>> { + async fn get_subscriptions(&self, ctx: &Context) -> miette::Result> { trace!("listing subscriptions"); let req = Request::get("/v0/"); - self.get_secure_client().ask(ctx, API_SERVICE, req).await + let subscription_legacy_list: Reply = + self.get_secure_client().ask(ctx, API_SERVICE, req).await?; + Ok(subscription_legacy_list.success()?.0) } #[instrument(skip_all, fields(subscription_id = subscription_id))] @@ -363,10 +422,12 @@ impl Subscriptions for ControllerClient { &self, ctx: &Context, subscription_id: String, - ) -> Result> { + ) -> miette::Result> { trace!(subscription = %subscription_id, "getting subscription"); let req = Request::get(format!("/v0/{subscription_id}")); - self.get_secure_client().ask(ctx, API_SERVICE, req).await + let reply: Reply = + self.get_secure_client().ask(ctx, API_SERVICE, req).await?; + Ok(reply.found()?) } #[instrument(skip_all, fields(space_id = space_id))] @@ -374,19 +435,11 @@ impl Subscriptions for ControllerClient { &self, ctx: &Context, space_id: String, - ) -> Result> { - let subscriptions: Vec = - self.get_subscriptions(ctx).await?.success()?; - let subscription = subscriptions + ) -> miette::Result> { + let subscriptions: Vec = self.get_subscriptions(ctx).await?; + Ok(subscriptions .into_iter() - .find(|s| s.space_id == Some(space_id.clone())); - match subscription { - Some(subscription) => Ok(Reply::Successful(subscription)), - None => Ok(Reply::Failed( - Error::new_without_path(), - Some(Status::NotFound), - )), - } + .find(|s| s.space_id == Some(space_id.clone()))) } } diff --git a/implementations/rust/ockam/ockam_api/src/uppercase.rs b/implementations/rust/ockam/ockam_api/src/uppercase.rs index d0d1bb79599..450e9973ba0 100644 --- a/implementations/rust/ockam/ockam_api/src/uppercase.rs +++ b/implementations/rust/ockam/ockam_api/src/uppercase.rs @@ -9,7 +9,8 @@ impl Worker for Uppercase { #[instrument(skip_all, name = "Uppercase::handle_message")] async fn handle_message(&mut self, ctx: &mut Context, msg: Routed) -> Result<()> { - ctx.send(msg.return_route().clone(), msg.into_body()?.to_uppercase()) + let return_route = msg.return_route().clone(); + ctx.send(return_route.clone(), msg.into_body()?.to_uppercase()) .await } } diff --git a/implementations/rust/ockam/ockam_command/src/admin/subscription.rs b/implementations/rust/ockam/ockam_command/src/admin/subscription.rs index 7347ff970b6..5b34e0b4c60 100644 --- a/implementations/rust/ockam/ockam_command/src/admin/subscription.rs +++ b/implementations/rust/ockam/ockam_command/src/admin/subscription.rs @@ -150,17 +150,11 @@ impl SubscriptionCommand { let response = controller .activate_subscription(ctx, space.clone(), json) - .await - .into_diagnostic()?; + .await?; opts.terminal.write_line(&response.item()?)? } SubscriptionSubcommand::List => { - let response = controller - .get_subscriptions(ctx) - .await - .into_diagnostic()? - .success() - .into_diagnostic()?; + let response = controller.get_subscriptions(ctx).await?; let output = opts .terminal .build_list(&response, "No Subscriptions found")?; @@ -179,10 +173,7 @@ impl SubscriptionCommand { .await? { Some(subscription) => { - let response = controller - .unsubscribe(ctx, subscription.id) - .await - .into_diagnostic()?; + let response = controller.unsubscribe(ctx, subscription.id).await?; opts.terminal.write_line(&response.item()?)? } None => opts @@ -212,8 +203,7 @@ impl SubscriptionCommand { Some(subscription) => { let response = controller .update_subscription_contact_info(ctx, subscription.id, json) - .await - .into_diagnostic()?; + .await?; opts.terminal.write_line(&response.item()?)? } None => opts.terminal.write_line( @@ -241,8 +231,7 @@ impl SubscriptionCommand { subscription.id, new_space_id.clone(), ) - .await - .into_diagnostic()?; + .await?; opts.terminal.write_line(&response.item()?)? } None => opts.terminal.write_line( diff --git a/implementations/rust/ockam/ockam_command/src/kafka/inlet/delete.rs b/implementations/rust/ockam/ockam_command/src/kafka/inlet/delete.rs index f1a8f687eb1..3de4a1a634e 100644 --- a/implementations/rust/ockam/ockam_command/src/kafka/inlet/delete.rs +++ b/implementations/rust/ockam/ockam_command/src/kafka/inlet/delete.rs @@ -5,7 +5,7 @@ use console::Term; use ockam_api::colors::color_primary; use ockam_api::{fmt_ok, DefaultAddress}; -use ockam_api::nodes::models::services::{DeleteServiceRequest, ServiceStatus}; +use ockam_api::nodes::models::services::{DeleteServiceRequest, ServiceStatusList}; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::terminal::{Terminal, TerminalStream}; use ockam_core::api::Request; @@ -91,14 +91,14 @@ impl DeleteCommandTui for DeleteTui { } async fn list_items_names(&self) -> miette::Result> { - let inlets: Vec = self + let inlets: ServiceStatusList = self .node .ask( &self.ctx, Request::get(format!("/node/services/{}", DefaultAddress::KAFKA_INLET)), ) .await?; - let addresses = inlets.into_iter().map(|i| i.addr).collect(); + let addresses = inlets.0.into_iter().map(|i| i.addr).collect(); Ok(addresses) } diff --git a/implementations/rust/ockam/ockam_command/src/kafka/inlet/list.rs b/implementations/rust/ockam/ockam_command/src/kafka/inlet/list.rs index 23683fff242..0c0db07fbde 100644 --- a/implementations/rust/ockam/ockam_command/src/kafka/inlet/list.rs +++ b/implementations/rust/ockam/ockam_command/src/kafka/inlet/list.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; use clap::Args; -use ockam_api::nodes::models::services::ServiceStatus; +use ockam_api::nodes::models::services::ServiceStatusList; use ockam_api::nodes::service::default_address::DefaultAddress; use ockam_api::nodes::BackgroundNodeClient; use ockam_core::api::Request; @@ -26,12 +26,13 @@ impl Command for ListCommand { async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> { let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?; - let services: Vec = node + let services: ServiceStatusList = node .ask( ctx, Request::get(format!("/node/services/{}", DefaultAddress::KAFKA_INLET)), ) .await?; + let services = services.0; let plain = opts.terminal.build_list( &services, diff --git a/implementations/rust/ockam/ockam_command/src/kafka/inlet/show.rs b/implementations/rust/ockam/ockam_command/src/kafka/inlet/show.rs index 92833dcb2dc..0cbadcde025 100644 --- a/implementations/rust/ockam/ockam_command/src/kafka/inlet/show.rs +++ b/implementations/rust/ockam/ockam_command/src/kafka/inlet/show.rs @@ -4,7 +4,7 @@ use console::Term; use miette::miette; use ockam_api::DefaultAddress; -use ockam_api::nodes::models::services::ServiceStatus; +use ockam_api::nodes::models::services::ServiceStatusList; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::output::Output; use ockam_api::terminal::{Terminal, TerminalStream}; @@ -76,25 +76,26 @@ impl<'a> ShowCommandTui for ShowTui<'a> { } async fn list_items_names(&self) -> miette::Result> { - let inlets: Vec = self + let inlets: ServiceStatusList = self .node .ask( self.ctx, Request::get(format!("/node/services/{}", DefaultAddress::KAFKA_INLET)), ) .await?; - let addresses = inlets.into_iter().map(|i| i.addr).collect(); + let addresses = inlets.0.into_iter().map(|i| i.addr).collect(); Ok(addresses) } async fn show_single(&self, item_name: &str) -> miette::Result<()> { - let inlets: Vec = self + let inlets: ServiceStatusList = self .node .ask( self.ctx, Request::get(format!("/node/services/{}", DefaultAddress::KAFKA_INLET)), ) .await?; + let inlets = inlets.0; let inlet = inlets .into_iter() .find(|i| i.addr == item_name) diff --git a/implementations/rust/ockam/ockam_command/src/kafka/outlet/delete.rs b/implementations/rust/ockam/ockam_command/src/kafka/outlet/delete.rs index 8447608c3db..791a5ca5215 100644 --- a/implementations/rust/ockam/ockam_command/src/kafka/outlet/delete.rs +++ b/implementations/rust/ockam/ockam_command/src/kafka/outlet/delete.rs @@ -5,7 +5,7 @@ use console::Term; use ockam_api::colors::color_primary; use ockam_api::{fmt_ok, DefaultAddress}; -use ockam_api::nodes::models::services::{DeleteServiceRequest, ServiceStatus}; +use ockam_api::nodes::models::services::{DeleteServiceRequest, ServiceStatusList}; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::terminal::{Terminal, TerminalStream}; use ockam_core::api::Request; @@ -88,14 +88,14 @@ impl DeleteCommandTui for DeleteTui { } async fn list_items_names(&self) -> miette::Result> { - let outlets: Vec = self + let outlets: ServiceStatusList = self .node .ask( &self.ctx, Request::get(format!("/node/services/{}", DefaultAddress::KAFKA_OUTLET)), ) .await?; - let addresses = outlets.into_iter().map(|i| i.addr).collect(); + let addresses = outlets.0.into_iter().map(|i| i.addr).collect(); Ok(addresses) } diff --git a/implementations/rust/ockam/ockam_command/src/kafka/outlet/list.rs b/implementations/rust/ockam/ockam_command/src/kafka/outlet/list.rs index 285f061d00c..ca04ad3ac36 100644 --- a/implementations/rust/ockam/ockam_command/src/kafka/outlet/list.rs +++ b/implementations/rust/ockam/ockam_command/src/kafka/outlet/list.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; use clap::Args; -use ockam_api::nodes::models::services::ServiceStatus; +use ockam_api::nodes::models::services::ServiceStatusList; use ockam_api::nodes::service::default_address::DefaultAddress; use ockam_api::nodes::BackgroundNodeClient; use ockam_core::api::Request; @@ -24,12 +24,13 @@ impl Command for ListCommand { async fn run(self, ctx: &Context, opts: CommandGlobalOpts) -> crate::Result<()> { let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node_opts.at_node).await?; - let services: Vec = node + let services: ServiceStatusList = node .ask( ctx, Request::get(format!("/node/services/{}", DefaultAddress::KAFKA_OUTLET)), ) .await?; + let services = services.0; let plain = opts.terminal.build_list( &services, diff --git a/implementations/rust/ockam/ockam_command/src/kafka/outlet/show.rs b/implementations/rust/ockam/ockam_command/src/kafka/outlet/show.rs index da946cbd452..8d94a523fab 100644 --- a/implementations/rust/ockam/ockam_command/src/kafka/outlet/show.rs +++ b/implementations/rust/ockam/ockam_command/src/kafka/outlet/show.rs @@ -4,7 +4,7 @@ use console::Term; use miette::miette; use ockam_api::DefaultAddress; -use ockam_api::nodes::models::services::ServiceStatus; +use ockam_api::nodes::models::services::ServiceStatusList; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::output::Output; use ockam_api::terminal::{Terminal, TerminalStream}; @@ -76,25 +76,26 @@ impl<'a> ShowCommandTui for ShowTui<'a> { } async fn list_items_names(&self) -> miette::Result> { - let outlets: Vec = self + let outlets: ServiceStatusList = self .node .ask( self.ctx, Request::get(format!("/node/services/{}", DefaultAddress::KAFKA_OUTLET)), ) .await?; - let addresses = outlets.into_iter().map(|i| i.addr).collect(); + let addresses = outlets.0.into_iter().map(|i| i.addr).collect(); Ok(addresses) } async fn show_single(&self, item_name: &str) -> miette::Result<()> { - let outlets: Vec = self + let outlets: ServiceStatusList = self .node .ask( self.ctx, Request::get(format!("/node/services/{}", DefaultAddress::KAFKA_OUTLET)), ) .await?; + let outlets = outlets.0; let outlet = outlets .into_iter() .find(|i| i.addr == item_name) diff --git a/implementations/rust/ockam/ockam_command/src/message/send.rs b/implementations/rust/ockam/ockam_command/src/message/send.rs index 97b47de5728..f9e646ddff7 100644 --- a/implementations/rust/ockam/ockam_command/src/message/send.rs +++ b/implementations/rust/ockam/ockam_command/src/message/send.rs @@ -6,8 +6,8 @@ use tracing::info; use ockam::Context; use ockam_api::address::extract_address_value; use ockam_api::nodes::service::messages::Messages; -use ockam_api::nodes::BackgroundNodeClient; use ockam_api::nodes::InMemoryNode; +use ockam_api::nodes::{BackgroundNodeClient, NodeManager}; use ockam_multiaddr::MultiAddr; use crate::project::util::{ @@ -71,21 +71,11 @@ impl Command for SendCommand { .context("Argument '--to' is invalid") .map_err(Error::Retry)?; - let msg_bytes = if self.hex { - hex::decode(self.message.clone()) - .into_diagnostic() - .context("The message is not a valid hex string")? - } else { - self.message.as_bytes().to_vec() - }; - // Setup environment depending on whether we are sending the message from a background node // or an in-memory node - let response: Vec = if let Some(node) = &self.from { - BackgroundNodeClient::create_to_node(ctx, &opts.state, node.as_str())? - .send_message(ctx, &to, msg_bytes, Some(self.timeout.timeout)) - .await - .map_err(Error::Retry)? + let result = if let Some(node) = &self.from { + let client = BackgroundNodeClient::create_to_node(ctx, &opts.state, node.as_str())?; + self.send_message(&client, ctx, &to).await? } else { let identity_name = opts .state @@ -120,21 +110,38 @@ impl Command for SendCommand { .map_err(Error::Retry)?; let to = clean_projects_multiaddr(to, projects_sc)?; info!("sending to {to}"); - node_manager - .send_message(ctx, &to, msg_bytes, Some(self.timeout.timeout)) - .await - .map_err(Error::Retry)? - }; - - let result = if self.hex { - hex::encode(response) - } else { - String::from_utf8(response) - .into_diagnostic() - .context("Received content is not a valid utf8 string")? + let n: &NodeManager = &node_manager; + self.send_message(n, ctx, &to).await? }; opts.terminal.stdout().plain(result).write_line()?; Ok(()) } } + +impl SendCommand { + async fn send_message( + self, + client: &impl Messages, + ctx: &Context, + to: &MultiAddr, + ) -> crate::Result { + if self.hex { + let to_send = hex::decode(self.message.clone()) + .into_diagnostic() + .context("The message is not a valid hex string")?; + let response: Vec = client + .send_message(ctx, to, to_send, Some(self.timeout.timeout)) + .await + .map_err(Error::Retry)?; + Ok(hex::encode(response)) + } else { + client + .send_message(ctx, to, self.message, Some(self.timeout.timeout)) + .await + .map_err(Error::Retry) + .into_diagnostic() + .context("Received content is not a valid utf8 string") + } + } +} diff --git a/implementations/rust/ockam/ockam_command/src/node/show.rs b/implementations/rust/ockam/ockam_command/src/node/show.rs index a4cf422571d..e4b83b29a35 100644 --- a/implementations/rust/ockam/ockam_command/src/node/show.rs +++ b/implementations/rust/ockam/ockam_command/src/node/show.rs @@ -10,6 +10,7 @@ use ockam_api::terminal::{Terminal, TerminalStream}; use ockam_api::CliState; use ockam_core::TryClone; use ockam_node::Context; +use tracing::error; use crate::terminal::tui::ShowCommandTui; use crate::tui::PluralTerm; @@ -116,16 +117,21 @@ pub async fn get_node_resources( cli_state: &CliState, node: &mut BackgroundNodeClient, ) -> miette::Result { - if let Ok(resources) = node + match node .ask_with_timeout(ctx, api::get_node_resources(), Duration::from_secs(1)) .await { - return Ok(resources); + Ok(resources) => Ok(resources), + Err(e) => { + error!( + "cannot get the node resources: {}. Returning the node information instead", + e + ); + let node_info = cli_state.get_node(node.node_name()).await?; + let identity = cli_state + .get_named_identity_by_identifier(&node_info.identifier()) + .await?; + NodeResources::empty(node_info, identity.name()).into_diagnostic() + } } - - let node_info = cli_state.get_node(node.node_name()).await?; - let identity = cli_state - .get_named_identity_by_identifier(&node_info.identifier()) - .await?; - NodeResources::empty(node_info, identity.name()).into_diagnostic() } diff --git a/implementations/rust/ockam/ockam_command/src/relay/delete.rs b/implementations/rust/ockam/ockam_command/src/relay/delete.rs index 49b9a28dcac..dcba5cb2d87 100644 --- a/implementations/rust/ockam/ockam_command/src/relay/delete.rs +++ b/implementations/rust/ockam/ockam_command/src/relay/delete.rs @@ -7,7 +7,7 @@ use crate::{docs, CommandGlobalOpts}; use ockam::Context; use ockam_api::address::extract_address_value; use ockam_api::colors::OckamColor; -use ockam_api::nodes::models::relay::RelayInfo; +use ockam_api::nodes::models::relay::RelayInfoList; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::terminal::{Terminal, TerminalStream}; use ockam_api::{color, fmt_ok}; @@ -92,11 +92,11 @@ impl DeleteCommandTui for DeleteTui { } async fn list_items_names(&self) -> miette::Result> { - let relays: Vec = self + let relays: RelayInfoList = self .node .ask(&self.ctx, Request::get("/node/relay")) .await?; - Ok(relays.into_iter().map(|i| i.name().to_string()).collect()) + Ok(relays.0.into_iter().map(|i| i.name().to_string()).collect()) } async fn delete_single(&self, relay_name: &str) -> miette::Result<()> { diff --git a/implementations/rust/ockam/ockam_command/src/relay/list.rs b/implementations/rust/ockam/ockam_command/src/relay/list.rs index d69eb23edd2..74f9596712b 100644 --- a/implementations/rust/ockam/ockam_command/src/relay/list.rs +++ b/implementations/rust/ockam/ockam_command/src/relay/list.rs @@ -3,7 +3,7 @@ use clap::Args; use ockam::Context; use ockam_api::address::extract_address_value; use ockam_api::colors::color_primary; -use ockam_api::nodes::models::relay::RelayInfo; +use ockam_api::nodes::models::relay::RelayInfoList; use ockam_api::nodes::BackgroundNodeClient; use ockam_core::api::Request; @@ -34,7 +34,7 @@ impl ListCommand { pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> { let node = BackgroundNodeClient::create(ctx, &opts.state, &self.to).await?; - let relays: Vec = { + let relays: RelayInfoList = { let pb = opts.terminal.spinner(); if let Some(pb) = pb { pb.set_message(format!( @@ -45,13 +45,13 @@ impl ListCommand { node.ask(ctx, Request::get("/node/relay")).await? }; let plain = opts.terminal.build_list( - &relays, + &relays.0, &format!("No Relays found on node {}", node.node_name()), )?; opts.terminal .stdout() .plain(plain) - .json_obj(relays)? + .json_obj(relays.0)? .write_line()?; Ok(()) } diff --git a/implementations/rust/ockam/ockam_command/src/relay/show.rs b/implementations/rust/ockam/ockam_command/src/relay/show.rs index 391d7fca66c..d56b42926eb 100644 --- a/implementations/rust/ockam/ockam_command/src/relay/show.rs +++ b/implementations/rust/ockam/ockam_command/src/relay/show.rs @@ -6,7 +6,7 @@ use miette::{miette, IntoDiagnostic}; use ockam::Context; use ockam_api::address::extract_address_value; -use ockam_api::nodes::models::relay::RelayInfo; +use ockam_api::nodes::models::relay::{RelayInfo, RelayInfoList}; use ockam_api::nodes::BackgroundNodeClient; use ockam_core::api::Request; use ockam_multiaddr::MultiAddr; @@ -94,11 +94,11 @@ impl ShowCommandTui for ShowTui { } async fn list_items_names(&self) -> miette::Result> { - let relays: Vec = self + let relays: RelayInfoList = self .node .ask(&self.ctx, Request::get("/node/relay")) .await?; - Ok(relays.into_iter().map(|i| i.name().to_string()).collect()) + Ok(relays.0.into_iter().map(|i| i.name().to_string()).collect()) } async fn show_single(&self, item_name: &str) -> miette::Result<()> { diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/list.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/list.rs index 00a014d72b9..37e22f91ce1 100644 --- a/implementations/rust/ockam/ockam_command/src/secure_channel/list.rs +++ b/implementations/rust/ockam/ockam_command/src/secure_channel/list.rs @@ -8,7 +8,7 @@ use tokio::try_join; use ockam::Context; use ockam_api::colors::OckamColor; -use ockam_api::nodes::models::secure_channel::ShowSecureChannelResponse; +use ockam_api::nodes::models::secure_channel::{SecureChannelList, ShowSecureChannelResponse}; use ockam_api::nodes::BackgroundNodeClient; use ockam_core::{route, Address, Result}; @@ -79,10 +79,10 @@ impl ListCommand { let is_finished: Mutex = Mutex::new(false); let get_secure_channel_identifiers = async { - let secure_channel_identifiers: Vec = + let secure_channel_identifiers: SecureChannelList = node.ask(ctx, api::list_secure_channels()).await?; *is_finished.lock().await = true; - Ok(secure_channel_identifiers) + Ok(secure_channel_identifiers.0) }; let output_messages = vec!["Retrieving secure channel identifiers...\n".to_string()]; diff --git a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/list.rs b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/list.rs index 0af4625e15a..3369be76397 100644 --- a/implementations/rust/ockam/ockam_command/src/secure_channel/listener/list.rs +++ b/implementations/rust/ockam/ockam_command/src/secure_channel/listener/list.rs @@ -4,7 +4,7 @@ use colorful::Colorful; use tokio::sync::Mutex; use tokio::try_join; -use ockam::identity::SecureChannelListener; +use ockam::identity::SecureChannelListenerList; use ockam::Context; use ockam_api::colors::OckamColor; use ockam_api::nodes::BackgroundNodeClient; @@ -41,10 +41,10 @@ impl ListCommand { let is_finished: Mutex = Mutex::new(false); let get_listeners = async { - let listeners: Vec = + let listeners: SecureChannelListenerList = node.ask(ctx, api::list_secure_channel_listener()).await?; *is_finished.lock().await = true; - Ok(listeners) + Ok(listeners.0) }; let output_messages = vec![format!( diff --git a/implementations/rust/ockam/ockam_command/src/service/list.rs b/implementations/rust/ockam/ockam_command/src/service/list.rs index 78ce7753c23..578c5717d44 100644 --- a/implementations/rust/ockam/ockam_command/src/service/list.rs +++ b/implementations/rust/ockam/ockam_command/src/service/list.rs @@ -6,7 +6,7 @@ use tokio::try_join; use ockam::Context; use ockam_api::colors::OckamColor; -use ockam_api::nodes::models::services::ServiceStatus; +use ockam_api::nodes::models::services::ServiceStatusList; use ockam_api::nodes::BackgroundNodeClient; use crate::node::NodeOpts; @@ -30,9 +30,9 @@ impl ListCommand { let is_finished: Mutex = Mutex::new(false); let get_services = async { - let services: Vec = node.ask(ctx, api::list_services()).await?; + let services: ServiceStatusList = node.ask(ctx, api::list_services()).await?; *is_finished.lock().await = true; - Ok(services) + Ok(services.0) }; let output_messages = vec![format!( diff --git a/implementations/rust/ockam/ockam_command/src/service/start.rs b/implementations/rust/ockam/ockam_command/src/service/start.rs index 10c0031bf70..5d4571d0cd7 100644 --- a/implementations/rust/ockam/ockam_command/src/service/start.rs +++ b/implementations/rust/ockam/ockam_command/src/service/start.rs @@ -1,7 +1,6 @@ use clap::{Args, Subcommand}; use colorful::Colorful; use miette::WrapErr; -use minicbor::Encode; use crate::{CommandGlobalOpts, Result}; use ockam::Context; @@ -10,6 +9,7 @@ use ockam_api::nodes::service::default_address::DefaultAddress; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::{fmt_ok, fmt_warn}; use ockam_core::api::Request; +use ockam_core::Message; use crate::node::NodeOpts; use crate::util::api; @@ -69,7 +69,7 @@ pub(crate) async fn start_service_impl( req: Request, ) -> Result<()> where - T: Encode<()>, + T: Message, { node.tell(ctx, req) .await diff --git a/implementations/rust/ockam/ockam_command/src/subscription.rs b/implementations/rust/ockam/ockam_command/src/subscription.rs index 35ba57ed6b4..02d271d3d5c 100644 --- a/implementations/rust/ockam/ockam_command/src/subscription.rs +++ b/implementations/rust/ockam/ockam_command/src/subscription.rs @@ -1,6 +1,6 @@ use clap::builder::NonEmptyStringValueParser; use clap::{Args, Subcommand}; -use miette::{miette, IntoDiagnostic}; +use miette::miette; use ockam::Context; use ockam_api::orchestrator::subscription::{SubscriptionLegacy, Subscriptions}; @@ -90,9 +90,7 @@ pub(crate) async fn get_subscription_by_id_or_space_id( (Some(subscription_id), _) => Ok(Some( controller .get_subscription(ctx, subscription_id.clone()) - .await - .and_then(|s| s.found()) - .into_diagnostic()? + .await? .ok_or_else(|| { miette!( "no subscription found for subscription id {}", @@ -103,9 +101,7 @@ pub(crate) async fn get_subscription_by_id_or_space_id( (None, Some(space_id)) => Ok(Some( controller .get_subscription_by_space_id(ctx, space_id.clone()) - .await - .and_then(|s| s.found()) - .into_diagnostic()? + .await? .ok_or_else(|| miette!("no subscription found for space {}", space_id))?, )), _ => Ok(None), diff --git a/implementations/rust/ockam/ockam_command/src/tcp/connection/list.rs b/implementations/rust/ockam/ockam_command/src/tcp/connection/list.rs index 35614d338b1..4f89415c6f1 100644 --- a/implementations/rust/ockam/ockam_command/src/tcp/connection/list.rs +++ b/implementations/rust/ockam/ockam_command/src/tcp/connection/list.rs @@ -4,7 +4,7 @@ use ockam_api::colors::OckamColor; use tokio::sync::Mutex; use tokio::try_join; -use ockam_api::nodes::models::transport::TransportStatus; +use ockam_api::nodes::models::transport::TransportStatusList; use ockam_api::nodes::BackgroundNodeClient; use ockam_core::api::Request; use ockam_node::Context; @@ -35,10 +35,10 @@ impl ListCommand { let is_finished: Mutex = Mutex::new(false); let get_transports = async { - let transports: Vec = + let transports: TransportStatusList = node.ask(ctx, Request::get("/node/tcp/connection")).await?; *is_finished.lock().await = true; - Ok(transports) + Ok(transports.0) }; let output_messages = vec![format!( diff --git a/implementations/rust/ockam/ockam_command/src/tcp/inlet/delete.rs b/implementations/rust/ockam/ockam_command/src/tcp/inlet/delete.rs index 9628007277a..6f502c26818 100644 --- a/implementations/rust/ockam/ockam_command/src/tcp/inlet/delete.rs +++ b/implementations/rust/ockam/ockam_command/src/tcp/inlet/delete.rs @@ -9,7 +9,7 @@ use crate::{docs, Command, CommandGlobalOpts}; use ockam::Context; use ockam_api::colors::color_primary; use ockam_api::fmt_ok; -use ockam_api::nodes::models::portal::InletStatus; +use ockam_api::nodes::models::portal::InletStatusList; use ockam_api::nodes::service::tcp_inlets::Inlets; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::terminal::{Terminal, TerminalStream}; @@ -97,11 +97,11 @@ impl DeleteCommandTui for DeleteTui { } async fn list_items_names(&self) -> miette::Result> { - let inlets: Vec = self + let inlets: InletStatusList = self .node .ask(&self.ctx, Request::get("/node/inlet")) .await?; - let names = inlets.into_iter().map(|i| i.alias).collect(); + let names = inlets.0.into_iter().map(|i| i.alias).collect(); Ok(names) } diff --git a/implementations/rust/ockam/ockam_command/src/tcp/inlet/list.rs b/implementations/rust/ockam/ockam_command/src/tcp/inlet/list.rs index 725c07c2731..602c7b30113 100644 --- a/implementations/rust/ockam/ockam_command/src/tcp/inlet/list.rs +++ b/implementations/rust/ockam/ockam_command/src/tcp/inlet/list.rs @@ -1,6 +1,6 @@ use clap::Args; -use ockam_api::nodes::models::portal::InletStatus; +use ockam_api::nodes::models::portal::InletStatusList; use ockam_api::nodes::BackgroundNodeClient; use ockam_core::api::Request; use ockam_node::Context; @@ -28,13 +28,14 @@ impl ListCommand { pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> { let node = BackgroundNodeClient::create(ctx, &opts.state, &self.node.at_node).await?; - let inlets: Vec = { + let inlets: InletStatusList = { let pb = opts.terminal.spinner(); if let Some(pb) = pb.as_ref() { pb.set_message(format!("Listing TCP Inlets on {}...", node.node_name())); } node.ask(ctx, Request::get("/node/inlet")).await? }; + let inlets = inlets.0; let plain = opts.terminal.build_list( &inlets, diff --git a/implementations/rust/ockam/ockam_command/src/tcp/inlet/show.rs b/implementations/rust/ockam/ockam_command/src/tcp/inlet/show.rs index 61d863f728d..e3b140f6deb 100644 --- a/implementations/rust/ockam/ockam_command/src/tcp/inlet/show.rs +++ b/implementations/rust/ockam/ockam_command/src/tcp/inlet/show.rs @@ -7,7 +7,7 @@ use console::Term; use miette::{miette, IntoDiagnostic}; use ockam::Context; use ockam_api::address::extract_address_value; -use ockam_api::nodes::models::portal::InletStatus; +use ockam_api::nodes::models::portal::{InletStatus, InletStatusList}; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::output::Output; use ockam_api::terminal::{Terminal, TerminalStream}; @@ -92,11 +92,12 @@ impl ShowCommandTui for ShowTui { } async fn list_items_names(&self) -> miette::Result> { - let inlets: Vec = self + let inlets: InletStatusList = self .node .ask(&self.ctx, Request::get("/node/inlet")) .await?; let items_names: Vec = inlets + .0 .into_iter() .map(|inlet| inlet.alias.to_string()) .collect(); diff --git a/implementations/rust/ockam/ockam_command/src/tcp/listener/list.rs b/implementations/rust/ockam/ockam_command/src/tcp/listener/list.rs index 83ef646cd08..727fd7716fd 100644 --- a/implementations/rust/ockam/ockam_command/src/tcp/listener/list.rs +++ b/implementations/rust/ockam/ockam_command/src/tcp/listener/list.rs @@ -5,7 +5,7 @@ use tokio::try_join; use ockam::Context; use ockam_api::colors::OckamColor; -use ockam_api::nodes::models::transport::TransportStatus; +use ockam_api::nodes::models::transport::TransportStatusList; use ockam_api::nodes::BackgroundNodeClient; use crate::node::NodeOpts; @@ -36,7 +36,7 @@ impl ListCommand { let is_finished: Mutex = Mutex::new(false); let get_transports = async { - let transports: Vec = node.ask(ctx, api::list_tcp_listeners()).await?; + let transports: TransportStatusList = node.ask(ctx, api::list_tcp_listeners()).await?; *is_finished.lock().await = true; Ok(transports) }; @@ -51,7 +51,7 @@ impl ListCommand { let (transports, _) = try_join!(get_transports, progress_output)?; let list = opts.terminal.build_list( - &transports, + &transports.0, &format!( "No TCP Listeners found on {}", node.node_name().color(OckamColor::PrimaryResource.color()) diff --git a/implementations/rust/ockam/ockam_command/src/tcp/outlet/delete.rs b/implementations/rust/ockam/ockam_command/src/tcp/outlet/delete.rs index 50c28b83301..894ef09393f 100644 --- a/implementations/rust/ockam/ockam_command/src/tcp/outlet/delete.rs +++ b/implementations/rust/ockam/ockam_command/src/tcp/outlet/delete.rs @@ -9,7 +9,7 @@ use crate::{docs, Command, CommandGlobalOpts}; use ockam::Context; use ockam_api::colors::color_primary; use ockam_api::fmt_ok; -use ockam_api::nodes::models::portal::OutletStatus; +use ockam_api::nodes::models::portal::OutletStatusList; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::terminal::{Terminal, TerminalStream}; use ockam_core::api::Request; @@ -102,11 +102,12 @@ impl DeleteCommandTui for DeleteTui { } async fn list_items_names(&self) -> miette::Result> { - let res: Vec = self + let res: OutletStatusList = self .node .ask(&self.ctx, Request::get("/node/outlet")) .await?; let items_names: Vec = res + .0 .iter() .map(|outlet| outlet.worker_addr.address().to_string()) .collect(); diff --git a/implementations/rust/ockam/ockam_command/src/tcp/outlet/list.rs b/implementations/rust/ockam/ockam_command/src/tcp/outlet/list.rs index cef9147ad29..d4ffe286528 100644 --- a/implementations/rust/ockam/ockam_command/src/tcp/outlet/list.rs +++ b/implementations/rust/ockam/ockam_command/src/tcp/outlet/list.rs @@ -7,7 +7,7 @@ use tokio::try_join; use crate::node::NodeOpts; use crate::{docs, CommandGlobalOpts}; -use ockam_api::nodes::models::portal::OutletStatus; +use ockam_api::nodes::models::portal::OutletStatusList; use ockam_api::nodes::BackgroundNodeClient; use ockam_core::api::Request; use ockam_node::Context; @@ -39,7 +39,7 @@ impl ListCommand { let is_finished: Mutex = Mutex::new(false); let send_req = async { - let res: Vec = node.ask(ctx, Request::get("/node/outlet")).await?; + let res: OutletStatusList = node.ask(ctx, Request::get("/node/outlet")).await?; *is_finished.lock().await = true; Ok(res) }; @@ -52,6 +52,7 @@ impl ListCommand { let progress_output = opts.terminal.loop_messages(&output_messages, &is_finished); let (outlets, _) = try_join!(send_req, progress_output)?; + let outlets = outlets.0; let list: String = { let empty_message = fmt_info!( diff --git a/implementations/rust/ockam/ockam_command/src/tcp/outlet/show.rs b/implementations/rust/ockam/ockam_command/src/tcp/outlet/show.rs index 3f18e5ace88..b63b5d1db5f 100644 --- a/implementations/rust/ockam/ockam_command/src/tcp/outlet/show.rs +++ b/implementations/rust/ockam/ockam_command/src/tcp/outlet/show.rs @@ -7,6 +7,7 @@ use miette::{miette, IntoDiagnostic}; use serde::Serialize; use ockam::Context; +use ockam_api::nodes::models::portal::OutletStatusList; use ockam_api::nodes::BackgroundNodeClient; use ockam_api::terminal::{Terminal, TerminalStream}; use ockam_api::{address::extract_address_value, nodes::models::portal::OutletStatus}; @@ -119,11 +120,12 @@ impl ShowCommandTui for ShowTui { } async fn list_items_names(&self) -> miette::Result> { - let outlets: Vec = self + let outlets: OutletStatusList = self .node .ask(&self.ctx, Request::get("/node/outlet")) .await?; let items_names: Vec = outlets + .0 .into_iter() .map(|outlet| outlet.worker_addr.address().to_string()) .collect(); diff --git a/implementations/rust/ockam/ockam_core/src/api.rs b/implementations/rust/ockam/ockam_core/src/api.rs index 7409c3e188d..f6cf96b9b23 100644 --- a/implementations/rust/ockam/ockam_core/src/api.rs +++ b/implementations/rust/ockam/ockam_core/src/api.rs @@ -15,10 +15,12 @@ use crate::compat::rand; use crate::compat::string::String; use crate::compat::vec::Vec; use crate::errcode::{Kind, Origin}; -use crate::Result; +use crate::{ + cbor_encode_preallocate, deserialize, serialize, Decodable, Encodable, Encoded, Message, Result, +}; /// A request header. -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, CborLen)] #[rustfmt::skip] #[cbor(map)] pub struct RequestHeader { @@ -54,7 +56,7 @@ impl RequestHeader { } /// The response header. -#[derive(Debug, Clone, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq, Eq)] #[rustfmt::skip] #[cbor(map)] pub struct ResponseHeader { @@ -77,35 +79,6 @@ impl ResponseHeader { pub fn is_ok(&self) -> bool { self.status.map(|s| s == Status::Ok).unwrap_or(false) } - - /// If the response is not successful and the response has a body - /// parse the response body as an error - pub fn parse_err_msg(&self, mut dec: Decoder) -> String { - match self.status() { - Some(status) if self.has_body() => { - let err = if matches!(dec.datatype(), Ok(Type::String)) { - dec.decode::() - .map(|msg| format!("Message: {msg}")) - .unwrap_or_default() - } else { - dec.decode::() - .map(|e| { - e.message() - .map(|msg| format!("Message: {msg}")) - .unwrap_or_default() - }) - .unwrap_or_default() - }; - format!( - "An error occurred while processing the request. Status code: {status}. {err}" - ) - } - Some(status) => { - format!("An error occurred while processing the request. Status code: {status}") - } - None => "No status code found in response".to_string(), - } - } } /// The Reply enum separates two possible cases when interpreting a Response @@ -208,7 +181,7 @@ impl Reply { pub struct Id(#[n(0)] u32); /// Request methods. -#[derive(Debug, Copy, Clone, Encode, Decode, CborLen)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Encode, Decode, CborLen)] #[rustfmt::skip] #[cbor(index_only)] pub enum Method { @@ -335,7 +308,7 @@ impl ResponseHeader { } /// An error type used in response bodies. -#[derive(Debug, Clone, Default, Encode, Decode, CborLen)] +#[derive(Debug, Clone, Default, Encode, Decode, CborLen, Message, PartialEq, Eq)] #[rustfmt::skip] #[cbor(map)] pub struct Error { @@ -350,6 +323,18 @@ pub struct Error { } +impl Encodable for Error { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for Error { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl Error { #[track_caller] pub fn new(path: &str) -> Self { @@ -516,7 +501,7 @@ impl<'a, const N: usize> Segments<'a, N> { } } -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Request { header: RequestHeader, body: Option, @@ -545,6 +530,10 @@ impl Request { pub fn into_parts(self) -> (RequestHeader, Option) { (self.header, self.body) } + + pub fn has_body(&self) -> bool { + self.header.has_body + } } impl Request { @@ -577,7 +566,7 @@ impl Request { } impl Request<()> { - pub fn body>(self, b: T) -> Request { + pub fn body(self, b: T) -> Request { let mut b = Request { header: self.header, body: Some(b), @@ -587,31 +576,73 @@ impl Request<()> { } } -impl> Request { - pub fn encode(&self, buf: W) -> Result<(), encode::Error> +impl Request { + fn encode_request(self, buf: W) -> Result<(), encode::Error> where W: Write, { let mut e = Encoder::new(buf); e.encode(&self.header)?; - if let Some(b) = &self.body { - e.encode(b)?; + if let Some(b) = self.body { + e.writer_mut() + .write_all(&::encode(b).map_err(encode::Error::message)?) + .map_err(|_| encode::Error::message("encoding error"))?; } Ok(()) } - pub fn to_vec(&self) -> Result, encode::Error< as Write>::Error>> { + fn into_vec(self) -> Result, encode::Error< as Write>::Error>> { let mut buf = Vec::new(); - self.encode(&mut buf)?; - + self.encode_request(&mut buf)?; Ok(buf) } } -#[derive(Debug)] +impl Encodable for Request { + /// This double serialization of requests with both + /// cbor and then serde_bare is not necessary and could be removed + fn encode(self) -> Result { + serialize(self.into_vec()?) + } +} + +impl Decodable for Request { + fn decode(e: &[u8]) -> Result { + let deserialized = deserialize::>(e)?; + let mut dec = Decoder::new(&deserialized); + let header: RequestHeader = dec.decode()?; + if header.has_body() { + let body = dec + .input() + .get(dec.position()..deserialized.len()) + .ok_or_else(|| { + crate::Error::new( + Origin::Api, + Kind::Internal, + format!( + "can't access the remaining input bytes: {}/{}", + dec.position(), + deserialized.len() + ), + ) + })?; + Ok(Request { + header, + body: Some(::decode(body)?), + }) + } else { + Ok(Request { header, body: None }) + } + } +} + +impl Message for Request {} + +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Response { header: ResponseHeader, body: Option, + error: Option, } impl Response { @@ -635,21 +666,173 @@ impl Response { &self.header } - pub fn into_parts(self) -> (ResponseHeader, Option) { - (self.header, self.body) + pub fn into_parts(self) -> (ResponseHeader, Option, Option) { + (self.header, self.body, self.error) } + /// Convenient wrapper to append the requests header to the response pub fn with_headers(self, req: &RequestHeader) -> Self { let id = req.id; self.re(id) } + + pub fn is_ok(&self) -> bool { + self.header.is_ok() + } + + pub fn has_body(&self) -> bool { + self.header.has_body() + } +} + +impl Response { + pub fn encode_response(self, buf: W) -> Result<(), encode::Error> + where + W: Write, + { + let mut e = Encoder::new(buf); + e.encode(&self.header)?; + if let Some(b) = self.body { + e.writer_mut() + .write_all(&::encode(b).map_err(encode::Error::message)?) + .map_err(|_| encode::Error::message("encoding error"))?; + } + Ok(()) + } + + fn into_vec(self) -> Result, encode::Error< as Write>::Error>> { + let mut buf = Vec::new(); + self.encode_response(&mut buf)?; + Ok(buf) + } + + pub fn encode_body(self) -> Result>> { + let (header, body, error_message) = self.into_parts(); + let r = if let Some(b) = body { + Response { + header, + body: Some(::encode(b)?), + error: error_message, + } + } else { + Response { + header, + body: None, + error: error_message, + } + }; + Ok(r) + } +} + +impl Encodable for Response { + fn encode(self) -> Result { + serialize(self.into_vec()?) + } +} + +impl Decodable for Response { + fn decode(e: &[u8]) -> Result { + let deserialized = deserialize::>(e)?; + let mut dec = Decoder::new(&deserialized); + let header: ResponseHeader = dec.decode()?; + if header.is_ok() { + if header.has_body() { + let body = dec + .input() + .get(dec.position()..deserialized.len()) + .ok_or_else(|| { + crate::Error::new( + Origin::Api, + Kind::Internal, + format!( + "can't access the remaining input bytes: {}/{}", + dec.position(), + deserialized.len() + ), + ) + })?; + Ok(Response { + header, + body: Some(::decode(body)?), + error: None, + }) + } else { + Ok(Response { + header, + body: None, + error: None, + }) + } + } else { + let error = if matches!(dec.datatype(), Ok(Type::String)) { + dec.decode::() + .map(|msg| Error::new_without_path().with_message(msg))? + } else { + dec.decode::()? + }; + + Ok(Response { + header, + body: None, + error: Some(error), + }) + } + } +} + +impl Message for Response {} + +impl Response> { + pub fn to_reply(self) -> Result> { + let (header, body, error) = self.into_parts(); + if header.is_ok() { + if let Some(body) = body { + match T::decode(body.as_slice()) { + Err(e) => Err(crate::Error::new( + Origin::Api, + Kind::Serialization, + format!("{e:?}"), + )), + Ok(r) => Ok(Reply::Successful(r)), + } + } else { + Err(crate::Error::new( + Origin::Api, + Kind::Serialization, + "expected a message body, got nothing".to_string(), + )) + } + } else if let Some(error) = error { + Ok(Reply::Failed(error, header.status())) + } else { + Err(crate::Error::new( + Origin::Api, + Kind::Serialization, + "expected an error message, got nothing".to_string(), + )) + } + } + + pub fn to_empty_reply(self, request_header: &RequestHeader) -> Result> { + let status = self.header().status(); + if !self.is_ok() { + Ok(Reply::Failed( + Error::from_failed_request(request_header, &self.parse_err_msg()), + status, + )) + } else { + Ok(Reply::Successful(())) + } + } } impl Response<()> { - pub fn body>(self, b: T) -> Response { + pub fn body(self, b: T) -> Response { let mut b = Response { header: self.header, body: Some(b), + error: None, }; b.header.has_body = true; b @@ -662,6 +845,7 @@ impl Response { Response { header: ResponseHeader::new(re, status, false), body: None, + error: None, } } @@ -758,109 +942,53 @@ impl Response { } } -impl Response { - /// Parse the response header and if it is ok - /// parse and decode the response body - pub fn parse_response_body(bytes: &[u8]) -> Result - where - T: for<'a> Decode<'a, ()>, - { - Self::parse_response_reply(bytes).and_then(|r| r.success()) - } - - /// Parse the response header and if it is ok - /// parse the response body - pub fn parse_response_reply(bytes: &[u8]) -> Result> - where - T: for<'a> Decode<'a, ()>, - { - let (response, mut decoder) = Self::parse_response_header(bytes)?; - if response.is_ok() { - // if the response is OK, try to decode the body as T - if response.has_body() { - match decoder.decode() { - Ok(t) => Ok(Reply::Successful(t)), - Err(e) => { - #[cfg(all(feature = "alloc", feature = "minicbor/half"))] - error!(%e, dec = %minicbor::display(bytes), hex = %hex::encode(bytes), "Failed to decode response"); - Err(crate::Error::new( - Origin::Api, - Kind::Serialization, - format!("Failed to decode response body: {}", e), - )) - } - } - // otherwise return a decoding error - } else { - Err(crate::Error::new( - Origin::Api, - Kind::Serialization, - "expected a message body, got nothing".to_string(), - )) - } - // if the status is not ok, try to read the response body as an error - } else { - Self::parse_error::(&mut decoder, response.status()) - } - } - - /// Parse the response header - pub fn parse_response_reply_with_empty_body(bytes: &[u8]) -> Result> { - let (response, mut decoder) = Self::parse_response_header(bytes)?; - if response.is_ok() { - Ok(Reply::Successful(())) - } else { - Self::parse_error(&mut decoder, response.status()) - } - } - - /// Parse the response header and return it + the Decoder to continue parsing if necessary - pub fn parse_response_header(bytes: &[u8]) -> Result<(ResponseHeader, Decoder)> { - #[cfg(all(feature = "alloc", feature = "minicbor/half"))] - trace! { - dec = %minicbor::display(bytes), - hex = %hex::encode(bytes), - "Received CBOR message" - }; - - let mut dec = Decoder::new(bytes); - let hdr = dec.decode::()?; - Ok((hdr, dec)) - } - - fn parse_error(decoder: &mut Decoder, status: Option) -> Result> { - let error = if matches!(decoder.datatype(), Ok(Type::String)) { - decoder - .decode::() - .map(|msg| Error::new_without_path().with_message(msg)) +impl Response> { + pub fn parse_error(self) -> Result> { + let status = self.header().status; + let body = self.body.unwrap_or_default(); + let error = if let Ok(msg) = ::decode(&body) { + Ok(Error::new_without_path().with_message(msg)) } else { - decoder.decode::() + ::decode(&body) }; match error { Ok(e) => Ok(Reply::Failed(e, status)), Err(e) => Err(crate::Error::new(Origin::Api, Kind::Serialization, e)), } } -} -impl> Response { - pub fn encode(&self, buf: W) -> Result<(), encode::Error> - where - W: Write, - { - let mut e = Encoder::new(buf); - e.encode(&self.header)?; - if let Some(b) = &self.body { - e.encode(b)?; + /// If the response is not successful and the response has a body + /// parse the response body as an error + pub fn parse_err_msg(self) -> String { + let status = self.header().status; + let has_body = self.has_body(); + + match status { + Some(status) if has_body => { + let body = self.body.unwrap_or_default(); + let error = if let Ok(msg) = ::decode(&body) { + Ok(format!("Message: {msg}")) + } else { + ::decode(&body).map(|msg| format!("Message: {msg}")) + }; + match error { + Ok(err) => { + format!( + "An error occurred while processing the request. Status code: {status}. {err}" + ) + } + Err(err) => { + let msg = format!("No error message could be found in response: {err}"); + error!(msg); + msg + } + } + } + Some(status) => { + format!("An error occurred while processing the request. Status code: {status}") + } + None => "No status code found in response".to_string(), } - Ok(()) - } - - pub fn to_vec(self) -> Result, encode::Error< as Write>::Error>> { - let mut buf = Vec::new(); - self.encode(&mut buf)?; - - Ok(buf) } } @@ -916,6 +1044,98 @@ mod tests { } } + #[test] + fn test_roundtrip_request() { + // round-trip a request with no body + let request = Request::post("path"); + assert_eq!( + Request::decode(&Request::encode(request.clone()).unwrap()).ok(), + Some(request) + ); + + // round-trip a request with a unit body + let request = Request::post("path").body(()); + assert_eq!( + Request::decode(&Request::encode(request.clone()).unwrap()).ok(), + Some(request) + ); + + // round-trip a request with an encodable body + let person = Person { + name: "me".into(), + age: 42, + }; + let request = Request::post("path").body(person.clone()); + assert_eq!( + Request::decode(&Request::encode(request.clone()).unwrap()).ok(), + Some(request) + ); + + // Decode only the header of a request + let request = Request::post("path").body(person.clone()); + let decoded: Request> = + Request::decode(&Request::encode(request.clone()).unwrap()).unwrap(); + let decoded_person = ::decode(&decoded.body.unwrap_or_default()).ok(); + assert_eq!(decoded_person, Some(person)); + } + + #[test] + fn test_roundtrip_response() { + // round-trip a response with no body + let response = Response::ok(); + assert_eq!( + Response::decode(&Response::encode(response.clone()).unwrap()).ok(), + Some(response) + ); + + // round-trip a response with a unit body + let response = Response::ok().body(()); + assert_eq!( + Response::decode(&Response::encode(response.clone()).unwrap()).ok(), + Some(response) + ); + + // round-trip a response with an encodable body + let person = Person { + name: "me".into(), + age: 42, + }; + let response = Response::ok().body(person.clone()); + assert_eq!( + Response::decode(&Response::encode(response.clone()).unwrap()).ok(), + Some(response) + ); + + // Decode only the header of a response + let request = Response::ok().body(person.clone()); + let decoded: Response> = + Response::decode(&Response::encode(request.clone()).unwrap()).unwrap(); + let decoded_person = ::decode(&decoded.body.unwrap_or_default()).ok(); + assert_eq!(decoded_person, Some(person)); + } + + /// HELPERS + + #[derive(Debug, Clone, Eq, PartialEq, Encode, Decode, CborLen, Message)] + struct Person { + #[n(1)] + name: String, + #[n(2)] + age: u8, + } + + impl Encodable for Person { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } + } + + impl Decodable for Person { + fn decode(encoded: &[u8]) -> Result { + Ok(minicbor::decode(encoded)?) + } + } + impl Arbitrary for RequestHeader { fn arbitrary(g: &mut Gen) -> Self { RequestHeader::new( diff --git a/implementations/rust/ockam/ockam_core/src/message.rs b/implementations/rust/ockam/ockam_core/src/message.rs index 9c965f5e01e..31f4af02956 100644 --- a/implementations/rust/ockam/ockam_core/src/message.rs +++ b/implementations/rust/ockam/ockam_core/src/message.rs @@ -73,35 +73,59 @@ pub trait Message: Encodable + Decodable + Send + 'static {} impl Message for () {} +impl Message for String {} + impl Message for Vec {} -impl Message for String {} +impl Encodable for Vec { + fn encode(self) -> Result { + Ok(self) + } +} -// Auto-implement message trait for types that _can_ be messages. -impl Encodable for T -where - T: Serialize, -{ +impl Decodable for Vec { + fn decode(e: &[u8]) -> Result { + Ok(e.to_vec()) + } +} + +impl Encodable for () { fn encode(self) -> Result { - // Serializing directly to allow better serialization - // inlining for a measurable performance improvement. - let mut vec = Vec::new(); - let mut serializer = Serializer::new(VecWrite::new(&mut vec)); - self.serialize(&mut serializer)?; - Ok(vec) + Ok(vec![]) } } -// Auto-implement message trait for types that _can_ be messages. -impl Decodable for T -where - T: DeserializeOwned, -{ - fn decode(encoded: &[u8]) -> Result { - Ok(serde_bare::from_slice(encoded)?) +impl Decodable for () { + fn decode(_e: &[u8]) -> Result { + Ok(()) + } +} + +impl Encodable for String { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for String { + fn decode(e: &[u8]) -> Result { + deserialize(e) } } +/// Serialize a type using serde_bare +pub fn serialize(t: T) -> Result { + let mut vec = Vec::new(); + let mut serializer = Serializer::new(VecWrite::new(&mut vec)); + t.serialize(&mut serializer)?; + Ok(vec) +} + +/// Serialize a type using serde_bare +pub fn deserialize(encoded: &[u8]) -> Result { + Ok(serde_bare::from_slice(encoded)?) +} + /// A message type that is not subject to any encoding or decoding. #[derive(Debug, Clone)] pub struct NeutralMessage(Vec); diff --git a/implementations/rust/ockam/ockam_core/src/routing/address.rs b/implementations/rust/ockam/ockam_core/src/routing/address.rs index ee48d2f1068..2f89a9f9683 100644 --- a/implementations/rust/ockam/ockam_core/src/routing/address.rs +++ b/implementations/rust/ockam/ockam_core/src/routing/address.rs @@ -3,7 +3,10 @@ use crate::compat::{ string::{String, ToString}, vec::Vec, }; -use crate::{AddressParseError, AddressParseErrorKind, Result, TransportType, LOCAL}; +use crate::{ + serialize, AddressParseError, AddressParseErrorKind, Encodable, Encoded, Result, TransportType, + LOCAL, +}; use core::fmt::{self, Debug, Display}; use core::ops::Deref; use core::str::from_utf8; @@ -46,6 +49,12 @@ impl AsRef
for Address { } } +impl Encodable for Address { + fn encode(self) -> Result { + serialize(self) + } +} + impl Address { /// Creates a new address from separate transport type and data parts. /// diff --git a/implementations/rust/ockam/ockam_core/src/routing/message/local_info.rs b/implementations/rust/ockam/ockam_core/src/routing/message/local_info.rs index 41535f9535c..9af3d0c2062 100644 --- a/implementations/rust/ockam/ockam_core/src/routing/message/local_info.rs +++ b/implementations/rust/ockam/ockam_core/src/routing/message/local_info.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::compat::string::String; use crate::compat::vec::Vec; -use crate::Message; +use crate::{deserialize, serialize, Decodable, Encodable, Encoded, Message}; /// Contains metadata that will only be routed locally within the /// local Ockam Node. @@ -32,3 +32,15 @@ impl LocalInfo { &self.data } } + +impl Encodable for LocalInfo { + fn encode(self) -> crate::Result { + serialize(self) + } +} + +impl Decodable for LocalInfo { + fn decode(e: &[u8]) -> crate::Result { + deserialize(e) + } +} diff --git a/implementations/rust/ockam/ockam_core/src/routing/message/local_message.rs b/implementations/rust/ockam/ockam_core/src/routing/message/local_message.rs index a37c3c97f0e..80d30d09175 100644 --- a/implementations/rust/ockam/ockam_core/src/routing/message/local_message.rs +++ b/implementations/rust/ockam/ockam_core/src/routing/message/local_message.rs @@ -1,6 +1,9 @@ #[cfg(feature = "std")] use crate::OpenTelemetryContext; -use crate::{compat::vec::Vec, route, Address, Message, Route, TransportMessage}; +use crate::{ + compat::vec::Vec, deserialize, route, serialize, Address, Decodable, Encodable, Encoded, + Message, Route, TransportMessage, +}; use crate::{LocalInfo, Result}; use cfg_if::cfg_if; @@ -261,6 +264,18 @@ impl Default for LocalMessage { } } +impl Encodable for LocalMessage { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for LocalMessage { + fn decode(e: &[u8]) -> Result { + deserialize(e) + } +} + impl LocalMessage { /// Create a new `LocalMessage` from the provided transport message and local information. fn make( diff --git a/implementations/rust/ockam/ockam_core/src/routing/route.rs b/implementations/rust/ockam/ockam_core/src/routing/route.rs index 1c2955fb0cb..c6f58275dd0 100644 --- a/implementations/rust/ockam/ockam_core/src/routing/route.rs +++ b/implementations/rust/ockam/ockam_core/src/routing/route.rs @@ -1,6 +1,6 @@ use crate::{ compat::{collections::VecDeque, string::String, vec::Vec}, - Address, Result, RouteError, TransportType, + serialize, Address, Encodable, Encoded, Result, RouteError, TransportType, }; use core::fmt::{self, Display}; use core::ops::{Add, AddAssign}; @@ -15,6 +15,12 @@ pub struct Route { #[n(0)] inner: VecDeque
, } +impl Encodable for Route { + fn encode(self) -> Result { + serialize(self) + } +} + impl AddAssign for Route { fn add_assign(&mut self, mut rhs: Self) { self.inner.append(&mut rhs.inner); diff --git a/implementations/rust/ockam/ockam_identity/src/identities/storage/attributes_entry.rs b/implementations/rust/ockam/ockam_identity/src/identities/storage/attributes_entry.rs index ae6860be261..3ee1fff31a5 100644 --- a/implementations/rust/ockam/ockam_identity/src/identities/storage/attributes_entry.rs +++ b/implementations/rust/ockam/ockam_identity/src/identities/storage/attributes_entry.rs @@ -6,12 +6,13 @@ use minicbor::{CborLen, Decode, Encode}; use ockam_core::compat::borrow::ToOwned; use ockam_core::compat::string::String; use ockam_core::compat::{collections::BTreeMap, vec::Vec}; -use ockam_core::Result; +use ockam_core::{cbor_encode_preallocate, Message}; +use ockam_core::{Decodable, Encodable, Encoded, Result}; use serde::ser::SerializeMap; use serde::{Deserialize, Serialize}; /// An entry on the AuthenticatedIdentities table. -#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Encode, Decode, CborLen, PartialEq, Eq, Serialize, Deserialize, Message)] #[rustfmt::skip] #[cbor(map)] pub struct AttributesEntry { @@ -23,6 +24,18 @@ pub struct AttributesEntry { #[n(4)] attested_by: Option, } +impl Encodable for AttributesEntry { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for AttributesEntry { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + fn serialize_attributes( attrs: &BTreeMap, Vec>, s: S, diff --git a/implementations/rust/ockam/ockam_identity/src/models/credential_and_purpose_key.rs b/implementations/rust/ockam/ockam_identity/src/models/credential_and_purpose_key.rs index e274f6faae4..e2f4744d90a 100644 --- a/implementations/rust/ockam/ockam_identity/src/models/credential_and_purpose_key.rs +++ b/implementations/rust/ockam/ockam_identity/src/models/credential_and_purpose_key.rs @@ -2,7 +2,7 @@ use minicbor::{CborLen, Decode, Encode}; use ockam_core::compat::string::String; use ockam_core::compat::vec::Vec; use ockam_core::errcode::{Kind, Origin}; -use ockam_core::{Error, Result}; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded, Error, Message, Result}; use crate::alloc::string::ToString; use crate::models::{Credential, CredentialData, PurposeKeyAttestation}; @@ -10,7 +10,7 @@ use crate::TimestampInSeconds; /// [`Credential`] and the corresponding [`PurposeKeyAttestation`] that was used to issue that /// [`Credential`] and will be used to verify it -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, CborLen)] +#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, CborLen, Message)] #[rustfmt::skip] pub struct CredentialAndPurposeKey { /// [`Credential`] @@ -20,6 +20,18 @@ pub struct CredentialAndPurposeKey { #[n(1)] pub purpose_key_attestation: PurposeKeyAttestation, } +impl Encodable for CredentialAndPurposeKey { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for CredentialAndPurposeKey { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl CredentialAndPurposeKey { /// Encode the credential as a hex String pub fn encode_as_string(&self) -> Result { @@ -28,7 +40,7 @@ impl CredentialAndPurposeKey { /// Encode the credential as a CBOR bytes pub fn encode_as_cbor_bytes(&self) -> Result> { - ockam_core::cbor_encode_preallocate(self) + cbor_encode_preallocate(self) } /// Decode the credential from bytes diff --git a/implementations/rust/ockam/ockam_identity/src/models/identifiers.rs b/implementations/rust/ockam/ockam_identity/src/models/identifiers.rs index 5f8df8d8e9b..260f9c0a100 100644 --- a/implementations/rust/ockam/ockam_identity/src/models/identifiers.rs +++ b/implementations/rust/ockam/ockam_identity/src/models/identifiers.rs @@ -1,7 +1,8 @@ +use crate::alloc::string::ToString; use core::fmt::{Debug, Formatter}; use minicbor::{CborLen, Decode, Encode}; - -use crate::alloc::string::ToString; +use ockam_core::compat::vec::Vec; +use ockam_core::{cbor_encode_preallocate, Decodable, Encodable, Encoded, Message}; /// Identifier length pub const IDENTIFIER_LEN: usize = 32; @@ -22,6 +23,23 @@ impl Debug for Identifier { } } +/// List of identifiers +#[derive(Clone, Eq, PartialEq, Encode, Decode, CborLen, Message)] +#[cbor(transparent)] +pub struct IdentifierList(#[n(0)] pub Vec); + +impl Encodable for IdentifierList { + fn encode(self) -> ockam_core::Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for IdentifierList { + fn decode(e: &[u8]) -> ockam_core::Result { + Ok(minicbor::decode(e)?) + } +} + /// Unique identifier for a [`super::Change`] /// Computed as SHA256 of the corresponding [`super::ChangeData`] CBOR binary #[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, CborLen)] diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channel/api.rs b/implementations/rust/ockam/ockam_identity/src/secure_channel/api.rs index a0daab91b6f..360c0754503 100644 --- a/implementations/rust/ockam/ockam_identity/src/secure_channel/api.rs +++ b/implementations/rust/ockam/ockam_identity/src/secure_channel/api.rs @@ -1,12 +1,24 @@ use ockam_core::compat::vec::Vec; -use ockam_core::Error; use ockam_core::Message; +use ockam_core::{deserialize, serialize, Decodable, Encodable, Encoded, Error}; use serde::{Deserialize, Serialize}; /// Request type for `EncryptorWorker` API Address #[derive(Serialize, Deserialize, Message)] pub struct EncryptionRequest(pub Vec); +impl Encodable for EncryptionRequest { + fn encode(self) -> ockam_core::Result { + Encodable::encode(self.0) + } +} + +impl Decodable for EncryptionRequest { + fn decode(v: &[u8]) -> ockam_core::Result { + Ok(EncryptionRequest(Decodable::decode(v)?)) + } +} + /// Response type for `EncryptorWorker` API Address #[derive(Serialize, Deserialize, Message)] pub enum EncryptionResponse { @@ -16,10 +28,32 @@ pub enum EncryptionResponse { Err(Error), } +impl Encodable for EncryptionResponse { + fn encode(self) -> ockam_core::Result { + serialize(self) + } +} + +impl Decodable for EncryptionResponse { + fn decode(v: &[u8]) -> ockam_core::Result { + deserialize(v) + } +} /// Request type for `Decryptor` API Address (the `Decryptor` is accessible through the `HandshakeWorker`) #[derive(Serialize, Deserialize, Message)] pub struct DecryptionRequest(pub Vec); +impl Encodable for DecryptionRequest { + fn encode(self) -> ockam_core::Result { + Encodable::encode(self.0) + } +} + +impl Decodable for DecryptionRequest { + fn decode(v: &[u8]) -> ockam_core::Result { + Ok(DecryptionRequest(Decodable::decode(v)?)) + } +} /// Response type for `Decryptor` API Address (the `Decryptor` is accessible through the `HandshakeWorker`) #[derive(Serialize, Deserialize, Message)] pub enum DecryptionResponse { @@ -28,3 +62,15 @@ pub enum DecryptionResponse { /// Error Err(Error), } + +impl Encodable for DecryptionResponse { + fn encode(self) -> ockam_core::Result { + serialize(self) + } +} + +impl Decodable for DecryptionResponse { + fn decode(v: &[u8]) -> ockam_core::Result { + deserialize(v) + } +} diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channels/common.rs b/implementations/rust/ockam/ockam_identity/src/secure_channels/common.rs index fab83ed28b6..139b7ef5a6c 100644 --- a/implementations/rust/ockam/ockam_identity/src/secure_channels/common.rs +++ b/implementations/rust/ockam/ockam_identity/src/secure_channels/common.rs @@ -4,8 +4,10 @@ use core::fmt; use core::fmt::Formatter; use minicbor::{CborLen, Decode, Encode}; use ockam_core::compat::sync::{Arc, RwLock}; +use ockam_core::compat::vec::Vec; use ockam_core::flow_control::{FlowControlId, FlowControls}; -use ockam_core::{Address, Result, Route}; +use ockam_core::{cbor_encode_preallocate, Message}; +use ockam_core::{Address, Decodable, Encodable, Encoded, Result, Route}; use serde::Serialize; /// Result of [`super::SecureChannels::create_secure_channel()`] call. @@ -125,7 +127,7 @@ impl SecureChannel { } /// Result of [`super::SecureChannels::create_secure_channel_listener()`] call. -#[derive(Debug, Clone, Encode, Decode, CborLen, Serialize)] +#[derive(Debug, Clone, Encode, Decode, CborLen, Serialize, Message)] #[rustfmt::skip] #[cbor(map)] pub struct SecureChannelListener { @@ -134,6 +136,18 @@ pub struct SecureChannelListener { #[n(3)] is_key_exchange_only: bool, } +impl Encodable for SecureChannelListener { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for SecureChannelListener { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} + impl fmt::Display for SecureChannelListener { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( @@ -173,3 +187,19 @@ impl SecureChannelListener { self.is_key_exchange_only } } + +/// List of [`SecureChannelListener`]s +#[derive(Encode, Decode, CborLen, Debug, Default, Clone, Message)] +pub struct SecureChannelListenerList(#[n(0)] pub Vec); + +impl Encodable for SecureChannelListenerList { + fn encode(self) -> Result { + cbor_encode_preallocate(self) + } +} + +impl Decodable for SecureChannelListenerList { + fn decode(e: &[u8]) -> Result { + Ok(minicbor::decode(e)?) + } +} diff --git a/implementations/rust/ockam/ockam_identity/src/secure_channels/secure_client.rs b/implementations/rust/ockam/ockam_identity/src/secure_channels/secure_client.rs index 541a7d19d9d..cd70f67afca 100644 --- a/implementations/rust/ockam/ockam_identity/src/secure_channels/secure_client.rs +++ b/implementations/rust/ockam/ockam_identity/src/secure_channels/secure_client.rs @@ -1,14 +1,11 @@ use crate::{CredentialRetrieverCreator, Identifier, SecureChannelOptions, TrustIdentifierPolicy}; -use minicbor::{Decode, Encode}; -use tracing::error; - use crate::{SecureChannel, SecureChannels}; use ockam_core::api::Reply::Successful; use ockam_core::api::{Error, Reply, Request, Response}; use ockam_core::compat::sync::Arc; use ockam_core::compat::time::Duration; use ockam_core::compat::vec::Vec; -use ockam_core::{self, route, Address, Result, Route}; +use ockam_core::{self, route, Address, Message, Result, Route}; use ockam_node::api::Client; use ockam_node::Context; use ockam_transport_core::Transport; @@ -161,20 +158,14 @@ impl SecureClient { req: Request, ) -> Result> where - T: Encode<()>, - R: for<'a> Decode<'a, ()>, + T: Message, + R: Message, { - match self + // TODO: we should return a Reply::Failed(timeout) error here + let response: Response> = self .request_with_timeout(ctx, api_service, req, self.request_timeout) - .await - { - Ok(bytes) => Response::parse_response_reply::(bytes.as_slice()), - Err(err) => { - // TODO: we should return a Reply::Failed(timeout) error here - error!("Error during SecureClient::ask to {} {}", api_service, err); - Err(err) - } - } + .await?; + response.to_reply() } /// Send a request of type T and don't expect a reply @@ -186,50 +177,52 @@ impl SecureClient { req: Request, ) -> Result> where - T: Encode<()>, + T: Message, { let request_header = req.header().clone(); - let bytes = self + let response: Response> = self .request_with_timeout(ctx, api_service, req, self.request_timeout) // TODO: we should return a Reply::Failed(timeout) error here .await?; - let (response, decoder) = Response::parse_response_header(bytes.as_slice())?; if response.is_ok() { Ok(Successful(())) } else { + let status = response.header().status(); Ok(Reply::Failed( - Error::from_failed_request(&request_header, &response.parse_err_msg(decoder)), - response.status(), + Error::from_failed_request(&request_header, &response.parse_err_msg()), + status, )) } } - /// Send a request of type T and expect an untyped reply + /// Send a request of type T and expect a response of type T /// See `ask` for more information - pub async fn request( + pub async fn request( &self, ctx: &Context, api_service: &str, req: Request, - ) -> Result> + ) -> Result> where - T: Encode<()>, + T: Message, + R: Message, { self.request_with_timeout(ctx, api_service, req, self.request_timeout) .await } - /// Send a request of type T and expect an untyped reply within a specific timeout + /// Send a request of type T and expect a response of type R within a specific timeout /// See `ask` for more information - pub async fn request_with_timeout( + pub async fn request_with_timeout( &self, ctx: &Context, api_service: &str, req: Request, timeout: Duration, - ) -> Result> + ) -> Result> where - T: Encode<()>, + T: Message, + R: Message, { let (secure_channel, transport_address) = self.create_secure_channel(ctx).await?; let route = route![secure_channel.clone(), api_service]; diff --git a/implementations/rust/ockam/ockam_identity/tests/credentials_refresh.rs b/implementations/rust/ockam/ockam_identity/tests/credentials_refresh.rs index 780dc25065b..e1d53d8e6f4 100644 --- a/implementations/rust/ockam/ockam_identity/tests/credentials_refresh.rs +++ b/implementations/rust/ockam/ockam_identity/tests/credentials_refresh.rs @@ -56,7 +56,7 @@ impl Worker for CredentialIssuer { ) .await?; - let response = Response::ok().body(credential).to_vec()?; + let response = Response::ok().body(credential); self.call_counter.fetch_add(1, Ordering::Relaxed); diff --git a/implementations/rust/ockam/ockam_macros/src/lib.rs b/implementations/rust/ockam/ockam_macros/src/lib.rs index 697cca8b4fd..eacabbcf186 100644 --- a/implementations/rust/ockam/ockam_macros/src/lib.rs +++ b/implementations/rust/ockam/ockam_macros/src/lib.rs @@ -62,6 +62,17 @@ pub fn try_clone_derive(input: TokenStream) -> TokenStream { /// pub struct MyStruct { /// a: u32, /// } +/// +/// impl Encodable for MyStruct { +/// fn encode(&self) -> Result{ +/// serialize(self) +/// } +/// } +/// impl Decodable for MyStruct { +/// fn decode(e: &[u8]) -> Result { +/// deserialize(e) +/// } +/// } /// ``` #[proc_macro_derive(Message)] pub fn message_derive(input: TokenStream) -> TokenStream { diff --git a/implementations/rust/ockam/ockam_node/src/api.rs b/implementations/rust/ockam/ockam_node/src/api.rs index baf8bd62c4f..f1921963c90 100644 --- a/implementations/rust/ockam/ockam_node/src/api.rs +++ b/implementations/rust/ockam/ockam_node/src/api.rs @@ -1,13 +1,11 @@ #![allow(missing_docs)] -use minicbor::{Decode, Encode}; - use crate::{Context, MessageSendReceiveOptions}; -use ockam_core::api::Reply::Successful; -use ockam_core::api::{Error, Reply, Request, Response}; +use ockam_core::api::{Reply, Request, Response}; +use ockam_core::compat::string::ToString; use ockam_core::compat::time::Duration; use ockam_core::compat::vec::Vec; -use ockam_core::{LocalInfo, Result, Route}; +use ockam_core::{LocalInfo, Message, Result, Route}; /// This struct provides some support for making requests to another node /// and receiving replies @@ -43,95 +41,70 @@ impl Client { /// if one is not interested in request failures. pub async fn ask(&self, ctx: &Context, req: Request) -> Result> where - T: Encode<()>, - R: for<'a> Decode<'a, ()>, + T: Message, + R: Message, { - let bytes: Vec = self.request_with_timeout(ctx, req, self.timeout).await?; - Response::parse_response_reply::(bytes.as_slice()) + let response: Response> = self.request_with_timeout(ctx, req, self.timeout).await?; + response.to_reply() } /// Send a request of type T and don't expect a reply /// See `ask` for more information pub async fn tell(&self, ctx: &Context, req: Request) -> Result> where - T: Encode<()>, + T: Message, { let request_header = req.header().clone(); - let bytes = self.request_with_timeout(ctx, req, self.timeout).await?; - let (response, decoder) = Response::parse_response_header(bytes.as_slice())?; - if !response.is_ok() { - Ok(Reply::Failed( - Error::from_failed_request(&request_header, &response.parse_err_msg(decoder)), - response.status(), - )) - } else { - Ok(Successful(())) - } + let response: Response> = self.request_with_timeout(ctx, req, self.timeout).await?; + response.to_empty_reply(&request_header) } /// Send a request of type T and expect an untyped reply /// See `ask` for more information - pub async fn request(&self, ctx: &Context, req: Request) -> Result> + pub async fn request(&self, ctx: &Context, req: Request) -> Result> where - T: Encode<()>, + T: Message, + R: Message, { self.request_with_timeout(ctx, req, self.timeout).await } /// Send a request of type T and expect an untyped reply within a specific timeout /// See `ask` for more information - pub async fn request_with_timeout( + pub async fn request_with_timeout( &self, ctx: &Context, req: Request, timeout: Option, - ) -> Result> + ) -> Result> where - T: Encode<()>, + T: Message, + R: Message, { let (response, _) = self.request_with_local_info(ctx, req, timeout).await?; Ok(response) } - /// Send a request of type T and expect an untyped reply within a specific timeout - /// Additionally provide any local information added to the received message - /// See `ask` for more information - pub async fn ask_with_local_info( - &self, - ctx: &Context, - req: Request, - timeout: Option, - ) -> Result<(Reply, Vec)> - where - T: Encode<()>, - R: for<'a> Decode<'a, ()>, - { - let (bytes, local_info) = self.request_with_local_info(ctx, req, timeout).await?; - let reply = Response::parse_response_reply::(bytes.as_slice())?; - Ok((reply, local_info)) - } - - /// Send a request of type T and expect an untyped reply within a specific timeout + /// Send a request of type T and expect a response within a specific timeout /// Additionally provide any local information added to the received message /// See `ask` for more information - async fn request_with_local_info( + async fn request_with_local_info( &self, ctx: &Context, req: Request, timeout: Option, - ) -> Result<(Vec, Vec)> + ) -> Result<(Response, Vec)> where - T: Encode<()>, + T: Message, + R: Message, { - let mut buf = Vec::new(); - - req.encode(&mut buf)?; + let request_header = req.header(); trace! { target: "ockam_api", - id = %req.header().id(), - method = ?req.header().method(), - path = %req.header().path(), - body = %req.header().has_body(), + id = %request_header.id(), + method = ?request_header.method(), + path = %request_header.path(), + body = %request_header.has_body(), "sending request" } let options = if let Some(t) = timeout { @@ -143,17 +116,17 @@ impl Client { // TODO: Check IdentityId is the same we sent message to? // TODO: Check response id matches request id? let resp = ctx - .send_and_receive_extended::>(self.route.clone(), buf, options) + .send_and_receive_extended(self.route.clone(), req, options) .await?; let local_info = resp.local_message().local_info().to_vec(); - let body = resp.into_body()?; + let body: Response = resp.into_body()?; + let response_header = body.header(); trace! { target: "ockam_api", - id = %req.header().id(), - method = ?req.header().method(), - path = %req.header().path(), - body = %req.header().has_body(), + id = %response_header.id(), + body = %response_header.has_body(), + status = %response_header.status().map(|s| s.to_string()).unwrap_or("no status".to_string()), "received response" } diff --git a/implementations/rust/ockam/ockam_node/src/context/send_message.rs b/implementations/rust/ockam/ockam_node/src/context/send_message.rs index 11ac6398407..89edccd4f8d 100644 --- a/implementations/rust/ockam/ockam_node/src/context/send_message.rs +++ b/implementations/rust/ockam/ockam_node/src/context/send_message.rs @@ -54,11 +54,12 @@ impl Context { /// [`new_detached`]: Self::new_detached /// [`send`]: Self::send /// [`receive`]: Self::receive - pub async fn send_and_receive(&self, route: impl Into, msg: impl Message) -> Result + pub async fn send_and_receive(&self, route: impl Into, msg: T) -> Result where - M: Message, + T: Message, + R: Message, { - self.send_and_receive_extended::(route, msg, MessageSendReceiveOptions::new()) + self.send_and_receive_extended::(route, msg, MessageSendReceiveOptions::new()) .await? .into_body() } @@ -72,14 +73,15 @@ impl Context { /// [`new_detached`]: Self::new_detached /// [`send`]: Self::send /// [`receive`]: Self::receive - pub async fn send_and_receive_extended( + pub async fn send_and_receive_extended( &self, route: impl Into, - msg: impl Message, + msg: T, options: MessageSendReceiveOptions, - ) -> Result> + ) -> Result> where - M: Message, + T: Message, + R: Message, { let route: Route = route.into(); @@ -111,7 +113,7 @@ impl Context { child_ctx.send(route, msg).await?; child_ctx - .receive_extended::( + .receive_extended::( MessageReceiveOptions::new().with_message_wait(options.message_wait), ) .await @@ -146,8 +148,10 @@ impl Context { /// [`RouteBuilder`]: ockam_core::RouteBuilder /// /// ```rust - /// # use {ockam_node::Context, ockam_core::Result}; - /// # async fn test(ctx: &mut Context) -> Result<()> { + /// # use {ockam_node::Context, ockam_core::Result}; /// # + /// use ockam_core::{deserialize, serialize, Decodable, Encodable, Encoded}; + /// + /// async fn test(ctx: &mut Context) -> Result<()> { /// use ockam_core::Message; /// use serde::{Serialize, Deserialize}; /// @@ -160,6 +164,18 @@ impl Context { /// } /// } /// + /// impl Encodable for MyMessage { + /// fn encode(self) -> Result { + /// Ok(serialize(self)?) + /// } + /// } + /// + /// impl Decodable for MyMessage { + /// fn decode(e: &[u8]) -> Result { + /// Ok(deserialize(e)?) + /// } + /// } + /// /// ctx.send("my-test-worker", MyMessage::new("Hello you there :)")).await?; /// Ok(()) /// # } @@ -167,7 +183,7 @@ impl Context { pub async fn send(&self, route: R, msg: M) -> Result<()> where R: Into, - M: Message + Send + 'static, + M: Message, { self.send_from_address(route.into(), msg, self.primary_address().clone()) .await @@ -183,7 +199,7 @@ impl Context { ) -> Result<()> where R: Into, - M: Message + Send + 'static, + M: Message, { self.send_from_address_impl( route.into(), @@ -215,7 +231,7 @@ impl Context { ) -> Result<()> where R: Into, - M: Message + Send + 'static, + M: Message, { self.send_from_address_impl(route.into(), msg, sending_address, Vec::new()) .await @@ -229,7 +245,7 @@ impl Context { local_info: Vec, ) -> Result<()> where - M: Message + Send + 'static, + M: Message, { // Check if the sender address exists if !self.mailboxes.contains(&sending_address) { diff --git a/implementations/rust/ockam/ockam_node/tests/tests.rs b/implementations/rust/ockam/ockam_node/tests/tests.rs index 46a04b319d7..c468faa9c0c 100644 --- a/implementations/rust/ockam/ockam_node/tests/tests.rs +++ b/implementations/rust/ockam/ockam_node/tests/tests.rs @@ -6,7 +6,10 @@ use ockam_core::compat::{ sync::Arc, }; use ockam_core::errcode::{Kind, Origin}; -use ockam_core::{async_trait, Address, AllowAll, Any, Decodable, DenyAll, Message}; +use ockam_core::{ + async_trait, deserialize, serialize, Address, AllowAll, Any, Decodable, DenyAll, Encodable, + Encoded, Message, +}; use ockam_core::{route, Processor, Result, Routed, Worker}; use ockam_node::compat::futures::FutureExt; use ockam_node::{Context, MessageReceiveOptions, NodeBuilder}; @@ -503,11 +506,35 @@ enum SendReceiveRequest { Connect(), } +impl Encodable for SendReceiveRequest { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for SendReceiveRequest { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} + #[derive(Serialize, Deserialize, Debug, Message)] enum SendReceiveResponse { Connect(Result<()>), } +impl Encodable for SendReceiveResponse { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for SendReceiveResponse { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} + /// Test the new method Context::send_and_receive(). /// See https://github.com/build-trust/ockam/issues/2628. #[ockam_macros::test] diff --git a/implementations/rust/ockam/ockam_transport_ble/src/router/mod.rs b/implementations/rust/ockam/ockam_transport_ble/src/router/mod.rs index 3ca8e8ce3fc..7d16a42ec0a 100644 --- a/implementations/rust/ockam/ockam_transport_ble/src/router/mod.rs +++ b/implementations/rust/ockam/ockam_transport_ble/src/router/mod.rs @@ -3,7 +3,7 @@ mod handle; use ockam_core::{ async_trait, compat::{boxed::Box, collections::BTreeMap, vec::Vec}, - AllowAll, Any, Mailbox, Mailboxes, + deserialize, serialize, AllowAll, Any, Encodable, Encoded, Mailbox, Mailboxes, }; use ockam_core::{Address, Decodable, LocalMessage, Message, Result, Routed, Worker}; use ockam_node::{Context, WorkerBuilder}; @@ -24,6 +24,18 @@ pub enum BleRouterMessage { }, } +impl Encodable for BleRouterMessage { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for BleRouterMessage { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} + /// A Bluetooth Low Energy address router and connection listener /// /// In order to create new BLE connection workers you need a router to diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/options.rs b/implementations/rust/ockam/ockam_transport_tcp/src/options.rs index b5cb49816ed..3a429d0cc89 100644 --- a/implementations/rust/ockam/ockam_transport_tcp/src/options.rs +++ b/implementations/rust/ockam/ockam_transport_tcp/src/options.rs @@ -80,7 +80,7 @@ impl TcpConnectionOptions { } /// Trust Options for a TCP listener -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TcpListenerOptions { pub(crate) flow_control_id: FlowControlId, } diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_message.rs b/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_message.rs index f6d869f664f..5ae69225766 100644 --- a/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_message.rs +++ b/implementations/rust/ockam/ockam_transport_tcp/src/portal/portal_message.rs @@ -1,6 +1,6 @@ use ockam_core::bare::{read_slice, write_slice}; use ockam_core::errcode::{Kind, Origin}; -use ockam_core::{Encodable, Encoded, Message, NeutralMessage}; +use ockam_core::{deserialize, serialize, Decodable, Encodable, Encoded, Message, NeutralMessage}; use serde::{Deserialize, Serialize}; use std::convert::TryInto; @@ -108,10 +108,22 @@ pub enum PortalInternalMessage { Disconnect, } +impl Encodable for PortalInternalMessage { + fn encode(self) -> ockam_core::Result { + serialize(self) + } +} + +impl Decodable for PortalInternalMessage { + fn decode(v: &[u8]) -> ockam_core::Result { + deserialize(v) + } +} + #[cfg(test)] mod test { use crate::PortalMessage; - use ockam_core::Message; + use ockam_core::{deserialize, serialize, Encoded, Message}; use ockam_core::{Decodable, Encodable}; use serde::{Deserialize, Serialize}; @@ -123,6 +135,18 @@ mod test { Payload(Vec), } + impl Encodable for PortalMessageV1 { + fn encode(self) -> ockam_core::Result { + serialize(self) + } + } + + impl Decodable for PortalMessageV1 { + fn decode(v: &[u8]) -> ockam_core::Result { + deserialize(v) + } + } + #[test] fn older_message_can_be_decoded() { let payload = "hello".as_bytes().to_vec(); diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs b/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs index 73b4922f8d6..053244c07fc 100644 --- a/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs +++ b/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs @@ -4,7 +4,8 @@ use ockam_core::flow_control::FlowControlId; use ockam_core::{ async_trait, compat::{net::SocketAddr, sync::Arc}, - AddressMetadata, AllowAll, AllowSourceAddress, DenyAll, LocalMessage, + deserialize, serialize, AddressMetadata, AllowAll, AllowSourceAddress, DenyAll, Encodable, + Encoded, LocalMessage, }; use ockam_core::{Any, Decodable, Mailbox, Mailboxes, Message, Result, Routed, Worker}; use ockam_node::{Context, WorkerBuilder, WorkerShutdownPriority}; @@ -40,6 +41,18 @@ pub(crate) struct TcpSendWorker { rx_should_be_stopped: bool, } +impl Encodable for TcpSendWorkerMsg { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for TcpSendWorkerMsg { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} + impl TcpSendWorker { /// Create a new `TcpSendWorker` fn new( diff --git a/implementations/rust/ockam/ockam_transport_tcp/tests/send_receive.rs b/implementations/rust/ockam/ockam_transport_tcp/tests/send_receive.rs index 8865d0613ee..f3c7aa06b47 100644 --- a/implementations/rust/ockam/ockam_transport_tcp/tests/send_receive.rs +++ b/implementations/rust/ockam/ockam_transport_tcp/tests/send_receive.rs @@ -30,7 +30,7 @@ async fn send_receive(ctx: &mut Context) -> Result<()> { let r = route![addr, "echoer"]; - let reply = ctx.send_and_receive::(r, msg.clone()).await?; + let reply: String = ctx.send_and_receive(r, msg.clone()).await?; assert_eq!(reply, msg, "Should receive the same message"); }; diff --git a/implementations/rust/ockam/ockam_transport_udp/src/puncture/rendezvous_service/client.rs b/implementations/rust/ockam/ockam_transport_udp/src/puncture/rendezvous_service/client.rs index 2f0ad53b69f..6ab127bc3e9 100644 --- a/implementations/rust/ockam/ockam_transport_udp/src/puncture/rendezvous_service/client.rs +++ b/implementations/rust/ockam/ockam_transport_udp/src/puncture/rendezvous_service/client.rs @@ -25,8 +25,8 @@ impl RendezvousClient { /// Query the Rendezvous service pub async fn get_my_address(&self, ctx: &Context) -> Result { - let res = ctx - .send_and_receive_extended::( + let res: RendezvousResponse = ctx + .send_and_receive_extended( self.rendezvous_route.clone(), RendezvousRequest::GetMyAddress, MessageSendReceiveOptions::new().with_timeout(QUICK_TIMEOUT), @@ -44,8 +44,8 @@ impl RendezvousClient { /// Query the Rendezvous service pub async fn ping(&self, ctx: &Context) -> Result<()> { - let res = ctx - .send_and_receive_extended::( + let res: RendezvousResponse = ctx + .send_and_receive_extended( self.rendezvous_route.clone(), RendezvousRequest::Ping, MessageSendReceiveOptions::new().with_timeout(QUICK_TIMEOUT), diff --git a/implementations/rust/ockam/ockam_transport_udp/tests/tests.rs b/implementations/rust/ockam/ockam_transport_udp/tests/tests.rs index 48ba6a2cd3a..8f515d2f39f 100644 --- a/implementations/rust/ockam/ockam_transport_udp/tests/tests.rs +++ b/implementations/rust/ockam/ockam_transport_udp/tests/tests.rs @@ -157,8 +157,8 @@ async fn send_from_same_client_port(ctx: &mut Context) -> Result<()> { (UDP, addr.to_string()), "echoer" ]; - let reply = ctx - .send_and_receive_extended::( + let reply: String = ctx + .send_and_receive_extended( r, msg.clone(), MessageSendReceiveOptions::new().with_timeout(TIMEOUT), @@ -206,8 +206,8 @@ async fn send_receive_arbitrary_udp_peer(ctx: &mut Context) -> Result<()> { (UDP, bind2.bind_address().to_string()), "echoer" ]; - let reply = ctx - .send_and_receive_extended::( + let reply: String = ctx + .send_and_receive_extended( r, msg.clone(), MessageSendReceiveOptions::new().with_timeout(TIMEOUT), @@ -222,8 +222,8 @@ async fn send_receive_arbitrary_udp_peer(ctx: &mut Context) -> Result<()> { (UDP, bind3.bind_address().to_string()), "echoer" ]; - let reply = ctx - .send_and_receive_extended::( + let reply: String = ctx + .send_and_receive_extended( r, msg.clone(), MessageSendReceiveOptions::new().with_timeout(TIMEOUT), @@ -270,8 +270,8 @@ async fn send_receive_one_known_udp_peer(ctx: &mut Context) -> Result<()> { .collect(); let r = route![bind2.sender_address().clone(), "echoer"]; - let reply = ctx - .send_and_receive_extended::( + let reply: String = ctx + .send_and_receive_extended( r, msg.clone(), MessageSendReceiveOptions::new().with_timeout(TIMEOUT), @@ -286,8 +286,8 @@ async fn send_receive_one_known_udp_peer(ctx: &mut Context) -> Result<()> { (UDP, bind2.bind_address().to_string()), "echoer" ]; - let reply = ctx - .send_and_receive_extended::( + let reply: String = ctx + .send_and_receive_extended( r, msg.clone(), MessageSendReceiveOptions::new().with_timeout(TIMEOUT), @@ -345,8 +345,8 @@ async fn send_receive_two_known_udp_peers(ctx: &mut Context) -> Result<()> { .collect(); let r = route![bind2.sender_address().clone(), "echoer"]; - let reply = ctx - .send_and_receive_extended::( + let reply: String = ctx + .send_and_receive_extended( r, msg.clone(), MessageSendReceiveOptions::new().with_timeout(TIMEOUT), @@ -357,8 +357,8 @@ async fn send_receive_two_known_udp_peers(ctx: &mut Context) -> Result<()> { assert_eq!(reply, msg, "Should receive the same message"); let r = route![bind1.sender_address().clone(), "echoer"]; - let reply = ctx - .send_and_receive_extended::( + let reply: String = ctx + .send_and_receive_extended( r, msg.clone(), MessageSendReceiveOptions::new().with_timeout(TIMEOUT), @@ -411,8 +411,8 @@ async fn send_receive_large_message(ctx: &mut Context) -> Result<()> { .collect(); let r = route![bind2.sender_address().clone(), "echoer"]; - let reply = ctx - .send_and_receive_extended::( + let reply: String = ctx + .send_and_receive_extended( r, msg.clone(), MessageSendReceiveOptions::new().with_timeout(TIMEOUT), diff --git a/implementations/rust/ockam/ockam_transport_uds/src/router/message.rs b/implementations/rust/ockam/ockam_transport_uds/src/router/message.rs index 09497ecd359..56c07849136 100644 --- a/implementations/rust/ockam/ockam_transport_uds/src/router/message.rs +++ b/implementations/rust/ockam/ockam_transport_uds/src/router/message.rs @@ -1,4 +1,4 @@ -use ockam_core::{Address, Message, Result}; +use ockam_core::{deserialize, serialize, Address, Decodable, Encodable, Encoded, Message, Result}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Message)] @@ -21,6 +21,18 @@ pub enum UdsRouterRequest { }, } +impl Encodable for UdsRouterRequest { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for UdsRouterRequest { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} + #[derive(Serialize, Deserialize, Debug, Message)] pub enum UdsRouterResponse { /// Response containing a result when attempting to register a new client @@ -32,3 +44,15 @@ pub enum UdsRouterResponse { /// Response containing a result when attempt to unregister Unregister(Result<()>), } + +impl Encodable for UdsRouterResponse { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for UdsRouterResponse { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} diff --git a/implementations/rust/ockam/ockam_transport_uds/src/workers/sender.rs b/implementations/rust/ockam/ockam_transport_uds/src/workers/sender.rs index eb1b5557dd9..f7505ecee27 100644 --- a/implementations/rust/ockam/ockam_transport_uds/src/workers/sender.rs +++ b/implementations/rust/ockam/ockam_transport_uds/src/workers/sender.rs @@ -1,8 +1,8 @@ use std::os::unix::net::SocketAddr; use ockam_core::{ - async_trait, compat::sync::Arc, Address, AllowAll, Any, Decodable, DenyAll, LocalMessage, - Mailbox, Mailboxes, Message, Result, Routed, Worker, + async_trait, compat::sync::Arc, deserialize, serialize, Address, AllowAll, Any, Decodable, + DenyAll, Encodable, Encoded, LocalMessage, Mailbox, Mailboxes, Message, Result, Routed, Worker, }; use ockam_node::{Context, WorkerBuilder}; use ockam_transport_core::{encode_transport_message, TransportError}; @@ -51,6 +51,18 @@ pub(crate) enum UdsSendWorkerMsg { ConnectionClosed, } +impl Encodable for UdsSendWorkerMsg { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for UdsSendWorkerMsg { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} + pub(crate) struct UdsSendWorker { router_handle: UdsRouterHandle, rx: Option, diff --git a/implementations/rust/ockam/ockam_transport_websocket/src/router/mod.rs b/implementations/rust/ockam/ockam_transport_websocket/src/router/mod.rs index d82319e5998..1562ca416c7 100644 --- a/implementations/rust/ockam/ockam_transport_websocket/src/router/mod.rs +++ b/implementations/rust/ockam/ockam_transport_websocket/src/router/mod.rs @@ -5,8 +5,8 @@ use std::sync::Arc; pub(crate) use handle::WebSocketRouterHandle; use ockam_core::{ - async_trait, Address, AllowAll, Any, Decodable, LocalMessage, Mailbox, Mailboxes, Message, - Result, Routed, Worker, + async_trait, deserialize, serialize, Address, AllowAll, Any, Decodable, Encodable, Encoded, + LocalMessage, Mailbox, Mailboxes, Message, Result, Routed, Worker, }; use ockam_node::{Context, WorkerBuilder}; use ockam_transport_core::TransportError; @@ -28,11 +28,35 @@ pub enum WebSocketRouterRequest { }, } +impl Encodable for WebSocketRouterRequest { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for WebSocketRouterRequest { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} + #[derive(Serialize, Deserialize, Debug, Message)] pub enum WebSocketRouterResponse { Register(Result<()>), } +impl Encodable for WebSocketRouterResponse { + fn encode(self) -> Result { + serialize(self) + } +} + +impl Decodable for WebSocketRouterResponse { + fn decode(v: &[u8]) -> Result { + deserialize(v) + } +} + /// A WebSocket address router and connection listener. /// /// In order to create new WebSocket connection workers you need a router to diff --git a/implementations/rust/ockam/ockam_transport_websocket/tests/send_receive.rs b/implementations/rust/ockam/ockam_transport_websocket/tests/send_receive.rs index 2f108b74343..f5f3000b012 100644 --- a/implementations/rust/ockam/ockam_transport_websocket/tests/send_receive.rs +++ b/implementations/rust/ockam/ockam_transport_websocket/tests/send_receive.rs @@ -19,7 +19,7 @@ async fn send_receive(ctx: &mut Context) -> Result<()> { .map(char::from) .collect(); let r = route![(WS, listener_address.to_string()), "echoer"]; - let reply = ctx.send_and_receive::(r, msg.clone()).await?; + let reply: String = ctx.send_and_receive(r, msg.clone()).await?; assert_eq!(reply, msg, "Should receive the same message"); };