Skip to content

Commit

Permalink
refactor(coap): Move server/client mechanism from example into coapcore
Browse files Browse the repository at this point in the history
  • Loading branch information
chrysn committed Jul 2, 2024
1 parent 0ce6630 commit 05817f3
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 55 deletions.
5 changes: 4 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion examples/coap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
89 changes: 40 additions & 49 deletions examples/coap/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<const N: usize>(
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);
}
}
8 changes: 8 additions & 0 deletions src/lib/coapcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand All @@ -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"
42 changes: 38 additions & 4 deletions src/lib/coapcore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,49 @@
//! 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
//
// This is pub only to make the doctests run (but the crate's pub-ness needs a major overhaul
// 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<ClientOps, ClientFuture>(
// 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<Output = ()>,
// {
// 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<const N: usize> {
#[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<const N: usize>(
sock: &mut impl embedded_nal_async::UnconnectedUdp,
handler: &mut impl coap_handler::Handler,
rng: &mut impl rand_core::RngCore,
client_runner: impl ClientRunner<N>,
) {
let coap = embedded_nal_coap::CoAPShared::<N>::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;
}

0 comments on commit 05817f3

Please sign in to comment.