diff --git a/Cargo.lock b/Cargo.lock index b61563c40..fe5597925 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -449,7 +449,6 @@ dependencies = [ "coap-scroll-ring-server", "coapcore", "embassy-executor", - "embassy-futures", "embassy-net", "embassy-time", "embedded-io-async", @@ -598,6 +597,9 @@ dependencies = [ "coap-message-implementations", "coap-message-utils", "coap-numbers", + "embassy-futures", + "embedded-nal-async", + "embedded-nal-coap", "heapless 0.8.0", "hexlit", "lakers", @@ -605,6 +607,7 @@ dependencies = [ "liboscore", "liboscore-msgbackend", "minicbor 0.23.0", + "rand_core", ] [[package]] diff --git a/examples/coap/Cargo.toml b/examples/coap/Cargo.toml index 6db682ec5..b6dc44ca3 100644 --- a/examples/coap/Cargo.toml +++ b/examples/coap/Cargo.toml @@ -28,7 +28,6 @@ smoltcp = { version = "0.11", default-features = false } embedded-nal-coap = "0.1.0-alpha.2" coap-request = "0.2.0-alpha.2" coap-message = "0.3.2" -embassy-futures = "0.1.1" coap-message-demos = { version = "0.4.0", default-features = false } coap-request-implementations = "0.1.0-alpha.4" lakers = { version = "0.6.0", default-features = false } diff --git a/examples/coap/src/main.rs b/examples/coap/src/main.rs index 201a9806d..c7ec871ad 100644 --- a/examples/coap/src/main.rs +++ b/examples/coap/src/main.rs @@ -107,57 +107,48 @@ where println!("Server is ready."); - let coap = embedded_nal_coap::CoAPShared::<3>::new(); - let (client, server) = coap.split(); - - // going with an embassy_futures join instead of an async_std::task::spawn b/c CoAPShared is not - // Sync, and async_std expects to work in multiple threads - embassy_futures::join::join( - async { - server - .run(&mut sock, &mut handler, &mut riot_rs::random::fast_rng()) - .await - .expect("UDP error") - }, - run_client_operations(client), - ) - .await; + // FIXME: We may want to have a very slim wrapper around this for riot-rs that provides our RNG + // … or maybe less slim and it handles the sock creation as well. + let mut rng = riot_rs::random::fast_rng(); + coapcore::coap_task(&mut sock, &mut handler, &mut rng, Client).await; } -/// In parallel to server operation, this function performs some operations as a client. -/// -/// This doubles as an experimentation ground for the client side of embedded_nal_coap and -/// coap-request in general. -async fn run_client_operations( - client: embedded_nal_coap::CoAPRuntimeClient<'_, N>, -) { - // shame - let demoserver = "10.42.0.1:1234".parse().unwrap(); - - use coap_request::Stack; - println!("Sending GET to {}...", demoserver); - let response = client - .to(demoserver) - .request( - coap_request_implementations::Code::get() - .with_path("/other/separate") +struct Client; + +impl coapcore::ClientRunner<3> for Client { + /// In parallel to server operation, this function performs some operations as a client. + /// + /// This doubles as an experimentation ground for the client side of embedded_nal_coap and + /// coap-request in general. + async fn run(self, client: embedded_nal_coap::CoAPRuntimeClient<'_, 3>) { + // shame + let demoserver = "10.42.0.1:1234".parse().unwrap(); + + use coap_request::Stack; + println!("Sending GET to {}...", demoserver); + let response = client + .to(demoserver) + .request( + coap_request_implementations::Code::get() + .with_path("/other/separate") + .processing_response_payload_through(|p| { + println!("Got payload {:?}", p); + }), + ) + .await; + println!("Response {:?}", response); + + let req = coap_request_implementations::Code::post().with_path("/uppercase"); + + println!("Sending POST..."); + let mut response = client.to(demoserver); + let response = response.request( + req.with_request_payload_slice(b"Set time to 1955-11-05") .processing_response_payload_through(|p| { - println!("Got payload {:?}", p); + println!("Uppercase is {}", core::str::from_utf8(p).unwrap()) }), - ) - .await; - println!("Response {:?}", response); - - let req = coap_request_implementations::Code::post().with_path("/uppercase"); - - println!("Sending POST..."); - let mut response = client.to(demoserver); - let response = response.request( - req.with_request_payload_slice(b"Set time to 1955-11-05") - .processing_response_payload_through(|p| { - println!("Uppercase is {}", core::str::from_utf8(p).unwrap()) - }), - ); - let response = response.await; - println!("Response {:?}", response); + ); + let response = response.await; + println!("Response {:?}", response); + } } diff --git a/src/lib/coapcore/Cargo.toml b/src/lib/coapcore/Cargo.toml index 3b7f3a113..1fbd868bf 100644 --- a/src/lib/coapcore/Cargo.toml +++ b/src/lib/coapcore/Cargo.toml @@ -14,7 +14,14 @@ description = "A CoAP stack for embedded devices with built-in OSCORE/EDHOC supp # public coap-handler = "0.2.0" coap-message = "0.3.2" +# public because we take a credential lakers = { version = "0.6.0", default-features = false } +# public because the callback provides a type from there +embedded-nal-coap = "0.1.0-alpha.2" +# public because we take a socket +embedded-nal-async = "0.7" +# public because we take a RngCor +rand_core = "0.6.4" # private arrayvec = { version = "0.7.4", default-features = false } @@ -29,3 +36,4 @@ liboscore-msgbackend = { git = "https://gitlab.com/oscore/liboscore/", features ], rev = "e7a4ecd037cbb9c7f085047fec5896f4bdc68d50" } minicbor = "0.23.0" heapless = "0.8.0" +embassy-futures = "0.1.1" diff --git a/src/lib/coapcore/src/lib.rs b/src/lib/coapcore/src/lib.rs index 049a19300..0b0470546 100644 --- a/src/lib/coapcore/src/lib.rs +++ b/src/lib/coapcore/src/lib.rs @@ -5,11 +5,9 @@ //! the application as an `embedded-nal` socket, and processes CoAP along with its security //! components OSCORE and EDHOC before passing on authorized requests to the application. //! -//! The crate is under heavy development: Its API is in flux, and so far it does not yet provide -//! the CoAP server itself, but merely a middleware. (Providing the full CoAP will be a requirement -//! for at least as long as the OSCORE component is tightly coupled to a particular implementation -//! of [`coap-message`]). +//! The crate is under heavy development. #![no_std] +#![feature(lint_reasons)] // Might warrant a standalone crate at some point // @@ -17,3 +15,39 @@ // anyway) pub mod oluru; pub mod seccontext; + +// This is a trait because I haven't managed to work out any lifetimes for a single client +// callback; tried +// pub async fn coap_task( +// sock: &mut impl embedded_nal_async::UnconnectedUdp, +// handler: &mut impl coap_handler::Handler, +// rng: &mut impl rand_core::RngCore, +// run_client_operations: ClientOps, +// ) where +// for<'a> ClientOps: Fn(embedded_nal_coap::CoAPRuntimeClient<'a, 3>) -> ClientFuture, +// ClientFuture: core::future::Future, +// { +// which typechecks on its own, but won't take a static async fn (or closure that returns an async +// block) as input. +pub trait ClientRunner { + #[allow(async_fn_in_trait, reason = "We explicitly expect this to not be send")] + async fn run(self, client: embedded_nal_coap::CoAPRuntimeClient<'_, N>); +} + +pub async fn coap_task( + sock: &mut impl embedded_nal_async::UnconnectedUdp, + handler: &mut impl coap_handler::Handler, + rng: &mut impl rand_core::RngCore, + client_runner: impl ClientRunner, +) { + let coap = embedded_nal_coap::CoAPShared::::new(); + let (client, server) = coap.split(); + + // going with an embassy_futures join instead of an async_std::task::spawn b/c CoAPShared is not + // Sync, and async_std expects to work in multiple threads + embassy_futures::join::join( + async { server.run(sock, handler, rng).await.expect("UDP error") }, + client_runner.run(client), + ) + .await; +}