coap_handler/handler.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
/// A minimal stateless testing CoAP server interface.
use coap_message::{MinimalWritableMessage, MutableWritableMessage, ReadableMessage};
pub trait Request {
// I think this will require coap-message to `impl ReadableMessage for &T where T:
// ReadableMessage`, but we can do that.
fn request(&self) -> impl ReadableMessage;
fn done(
self,
) -> impl PausedOperation<ResponseMessage = Self::ResponseMessage, ResponseDone = Self::ResponseDone>;
type ResponseMessage: MutableWritableMessage;
type ResponseDone;
}
pub trait PausedOperation {
type ResponseMessage: MutableWritableMessage;
type ResponseDone;
async fn respond(
self,
expected_length: usize,
) -> impl Response<ResponseMessage = Self::ResponseMessage, Done = Self::ResponseDone>;
}
pub trait Response {
type Done;
// It'd be tempting to add a lifetime to ResponseMessage, but that doesn't really give us
// anything:
// While we could return an arbitrarily lifetime'd impl Self::ResponseMessage in response, that
// lifetime is still given by the caller. If an implementor needs a lifetime, it can be part of
// the Self type and thus already in the ResponseMessage of Request, PausedOperation and
// Response.
// (Plus we can't carry a generic -> impl Response<for<'a> ResponsMessage<'a> =
// Self::ResponseMessage<'a>> around, so we'd need to carry all the ResponseMessage's
// individual associated types hoping they don't depend on that lifetime).
type ResponseMessage: MutableWritableMessage;
// This typically owns whatever is given out as a mutable response (but sticking with &mut so
// it's not a use-once thing, as long as ResponseMessage does not follow a type state pattern
// -- that can be added in parallel anyway.)
fn response(&mut self) -> &mut Self::ResponseMessage;
// While we have MutableWritableMessage style building, this may check whether a code was set.
// On the long run with a type state pattern writable message, handing that back can produce
// the same result without runtime checks.
fn done(self) -> Self::Done;
}
/// A CoAP request handler. This gets called by a CoAP server implementation that the handler is
/// assigned to. The server processes the [.handle()][Self::handle] async method. As part of
/// building a successful response, the handler takes the passed [Request] object, reads from
/// it, turns it into a [Response] and writes into that response.
///
/// Response building is inherently fallible (the stack may not support some options), and other
/// errors can just as well occur during extraction (for example checking for unprocessed critical
/// options). Returning an error is not only an ergonomically easy step, it also allows the error
/// writer to start over fresh: There is currently no trait method in [`coap_message`] that
/// describes how that would be done, but the CoAP implementation knows the concrete type and can
/// use its methods directly.
pub trait Handler {
type Error<M: MinimalWritableMessage>: core::fmt::Debug
+ coap_message::error::RenderableOnMinimal;
/// Processes an incoming request and build a response.
///
/// Implementations that do not have anything to await in their application logic still have at
/// least one await point: the call to the async Request::response method.
///
/// CoAP servers may be implemented with limited buffer space. It is therefore recommended that
/// long awaits (ideally, any awaits) are run between the call to [`Request::done()`] (at
/// which point the CoAP server can start reusing the receive buffer) and the subsequent call
/// to [`.respond()`][PausedOperation::respond] during which the server waits for a send
/// buffer to be ready.
async fn handle<R: Request>(
&mut self,
request: R,
) -> Result<<R as Request>::ResponseDone, Self::Error<<R as Request>::ResponseMessage>>;
}