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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
//! This crate contains demo applications for CoAP on Rust //! //! All demos use the ecosystem around the [coap-message] crate. They come in two variations: //! //! * "applications" contain code that would typically be the high-level code that executes //! business logic. //! //! They are a mix of standalone resource implementations, collections thereof into a //! whole-server handler, and possibly client code. //! //! They reside in the `src/` directory, and are available as library modules. This allows //! integrating them into other demo code, eg. into examples of a coap-message implementation. //! //! * "examples" are the stand-alone executable binaries using various backends. //! //! They pick suitable applications, and wrap them with a CoAP implementation of choice into a //! program that can be run with `cargo run --example X`. //! //! Currently, the examples in this crate show the use of: //! //! * [coap-lite](https://crates.io/crates/coap-lite), //! a building block for CoAP-over-UDP libraries, running directly on a socket in the example. //! //! * [the coap crate](https://crates.io/crates/coap), //! which provides a full implementation, and can interface with coap-message by virtue of //! using coap-lite as a backend. //! //! * [embedded-nal-minimal-coapserver](https://crates.io/crates/embedded-nal-minimal-coapserver), //! which implements CoAP-over-UDP on the Embedded Network Abstraction Layer //! and processes messages through the [coap_handler] types. //! For the example, it uses a std implementation of embedded-nal. //! //! Examples that need larger ecosystem support and can not simply be launched natively by `cargo //! run --example` are not included here, but show (maybe even better) what the coap-message //! ecosystem is capable of providing: //! //! * [verdigris](https://crates.io/crates/verdigris) //! is an implementation of CoAP that runs in the web browser and uses CoAP-over-WebSockets. //! It includes the demo applications in its color server sub-application, where they can be //! accessed through a proxying Resource Directory. //! //! * [RIOT](https://riot-os.org/) is an embedded operating system for the Internet of Things. //! In the [examples of its Rust bindings](https://gitlab.com/etonomy/riot-examples/), //! the `coap_through_embeddednal` application runs the no_std part of the demo applications //! using the same embedded-nal-minimal-coapserver crate as the local example, //! but using RIOT's sockets instead of POSIX sockets. //! //! Usage //! ----- //! //! The examples are all configured to run a selection of the applications; which they are depends //! on the selected features. //! //! For minimal operation, run the examples as //! //! ```sh //! $ cargo +nightly run --example EXNAME --features example-EXNAME //! ``` //! //! where `EXNAME` is substituted with any of the examples -- currently `coaplite`, `coap_crate` or //! `std_embedded_nal_minicoapserver`. //! //! To explore all features, just run with //! //! ```sh //! $ cargo +nightly run --example EXNAME --all-features //! ``` //! //! which, for example, adds access to a system [::log]. //! //! All the same can be accessed, for example, by using [aiocoap-client]: //! //! ```sh //! $ aiocoap-client coap://localhost/.well-known/core //! </>; ct="0"; title="Landing page", //! </time>; ct="0"; title="Clock", //! </cbor/1>; ct="60", //! </cbor/2>; ct="60", //! </cbor>; ct="60", //! </message/warning>; title="POST warning texts here", //! </message/info>; title="POST info texts here" //! //! $ aiocoap-client coap://localhost/cbor //! {'hidden': False, 'number': 32, 'label': 'Hello', 'list': [1, 2, 3]} //! ``` //! //! [coap-message]: https://crates.io/crates/coap-message //! [aiocoap-client]: https://aiocoap.readthedocs.io/en/latest/installation.html #![no_std] #![feature(type_alias_impl_trait)] #[cfg(feature = "std")] extern crate std; #[cfg(feature = "alloc")] extern crate alloc; #[cfg(feature = "alloc")] pub mod cbor; pub mod helloworld; #[cfg(feature = "with-log")] pub mod log; #[cfg(not(feature = "with-log"))] pub mod log { /// A never-ish type that allows having a single full_application_tree function independent of /// whether things are built with-log or without. pub enum Log {} } /// Build a handler that contains all the demo applications /// /// Note that no log::Log is created because that needs to be global, created-only-once and /// available as early in the application start-up as possible as per the log crate's design; you'd /// have to pass one in if you want to view the log through CoAP. /// /// The resources /message/info and /message/warn for creating log messages will /// be available independently thereof as long as the with-log feature is active. pub fn full_application_tree( main_log: Option<&'static crate::log::Log> ) -> FullHandler { #[cfg(feature = "with-log")] use crate::log::*; #[cfg(feature = "alloc")] use cbor::*; use helloworld::*; #[cfg(feature = "std")] let shared_cbor: std::sync::Arc<std::sync::Mutex<MyCBOR>> = Default::default(); use coap_handler_implementations::{new_dispatcher, HandlerBuilder, SimpleCBORWrapper}; let handler = new_dispatcher() .at( &[".well-known", "core"], // TBD: Build this string from cfg to not advertise 4.04'ing resources coap_handler_implementations::TypedStaticResponse { payload: b"</>;ct=0;title=\"Landing page\",\ </time>;ct=0;title=\"Clock\",\ </poem>;sz=1339,\ </cbor/1>;ct=60,\ </cbor/2>;ct=60,\ </cbor>;ct=60,\ </message/warn>;title=\"POST warning texts here\",\ </message/info>;title=\"POST info texts here\"\ </log>;title=\"Most recent log messages\"\ ", contentformat: &[40], }, ) .at(&[], WELCOME) .at(&["time"], TIME) .at(&["poem"], POEM); #[cfg(feature = "std")] let handler = handler .at( &["cbor", "1"], SimpleCBORWrapper::new(TryingThroughMutex(shared_cbor.clone())), ) .at( &["cbor", "2"], SimpleCBORWrapper::new(TryingThroughMutex(shared_cbor.clone())), ); #[cfg(feature = "alloc")] let handler = handler.at( &["cbor"], SimpleCBORWrapper::<MyCBOR>::new(Default::default()), ); #[cfg(feature = "with-log")] let handler = handler .at(&["message", "warn"], LogMessagePostHandler::new_warn()) .at(&["message", "info"], LogMessagePostHandler::new_info()) .at( &["log"], main_log.map(|m| coap_handler_implementations::SimpleRendered(&*m)), ); #[cfg(not(feature = "with-log"))] let _ = main_log; // Discarding what's sure to be None (because Ok can never be) handler } pub type FullHandler = impl coap_handler::Handler;