async_coap/remote_endpoint.rs
1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16use super::*;
17use crate::UriBuf;
18
19/// An object that represents a remote CoAP endpoint with a default, overridable path.
20///
21/// # Example
22///
23/// ```
24/// # #![feature(async_await)]
25/// #
26/// # use std::sync::Arc;
27/// # use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt};
28/// # use async_coap::prelude::*;
29/// # use async_coap::datagram::{DatagramLocalEndpoint,AllowStdUdpSocket};
30/// #
31/// # // Create our asynchronous socket. In this case, it is just an
32/// # // (inefficient) wrapper around the standard rust `UdpSocket`,
33/// # // but that is quite adequate in this case.
34/// # let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed");
35/// #
36/// # // Create a new local endpoint from the socket we just created,
37/// # // wrapping it in a `Arc<>` to ensure it can live long enough.
38/// # let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket));
39/// #
40/// # // Create a local execution pool for running our local endpoint.
41/// # let mut pool = LocalPool::new();
42/// #
43/// # // Add our local endpoint to the pool, so that it
44/// # // can receive packets.
45/// # pool.spawner().spawn_local(local_endpoint
46/// # .clone()
47/// # .receive_loop_arc(null_receiver!())
48/// # .map(|err| panic!("Receive loop terminated: {}", err))
49/// # );
50/// #
51/// # let future = async move {
52/// // Create a remote endpoint instance to represent the
53/// // device we wish to interact with.
54/// let remote_endpoint = local_endpoint
55/// .remote_endpoint_from_uri(uri!("coap://coap.me"))
56/// .unwrap(); // Will only fail if the URI scheme or authority is unrecognizable
57///
58/// // Create a future that sends a request to a specific path
59/// // on the remote endpoint, collecting any blocks in the response
60/// // and returning `Ok(OwnedImmutableMessage)` upon success.
61/// let future = remote_endpoint.send_to(
62/// rel_ref!("large"),
63/// CoapRequest::get() // This is a CoAP GET request
64/// .accept(ContentFormat::TEXT_PLAIN_UTF8) // We only want plaintext
65/// .block2(Some(Default::default())) // Enable block2 processing
66/// .emit_successful_collected_response() // Collect all blocks into a single message
67/// );
68///
69/// // Wait for the final result and print it.
70/// println!("result: {:?}", future.await.unwrap());
71/// # };
72/// #
73/// # pool.run_until(future);
74/// ```
75///
76pub trait RemoteEndpoint {
77 /// The `SocketAddr` type to use with this local endpoint. This is usually
78 /// simply `std::net::SocketAddr`, but may be different in some cases (like for CoAP-SMS
79 /// endpoints).
80 type SocketAddr: SocketAddrExt;
81
82 /// Type used by closure that is passed into `send()`, representing the context for the
83 /// response.
84 type InboundContext: InboundContext<SocketAddr = Self::SocketAddr>;
85
86 /// Returns a [`UriBuf`] describing the underlying destination of this remote endpoint.
87 fn uri(&self) -> UriBuf;
88
89 /// Returns a string slice containing the scheme for this `RemoteEndpoint`.
90 fn scheme(&self) -> &'static str;
91
92 /// Prevents this remote endpoint from including a `Uri-Host` option.
93 fn remove_host_option(&mut self);
94
95 /// Creates a clone of this `RemoteEndpoint` with a different relative path.
96 fn clone_using_rel_ref(&self, uri: &RelRef) -> Self;
97
98 /// Uses `send_desc` to send a request to the endpoint and path described by this
99 /// `RemoteEndpoint` instance.
100 fn send<'a, R, SD>(&'a self, send_desc: SD) -> BoxFuture<'_, Result<R, Error>>
101 where
102 SD: SendDesc<Self::InboundContext, R> + 'a,
103 R: Send + 'a;
104
105 /// Uses `send_desc` to send a request to the given relative path on the endpoint described
106 /// by this `RemoteEndpoint` instance.
107 fn send_to<'a, R, SD, UF>(&'a self, path: UF, send_desc: SD) -> BoxFuture<'_, Result<R, Error>>
108 where
109 SD: SendDesc<Self::InboundContext, R> + 'a,
110 R: Send + 'a,
111 UF: AsRef<RelRef>;
112}
113
114/// Extension trait which implements additional helper methods.
115pub trait RemoteEndpointExt: RemoteEndpoint {
116 /// Sends an application-level ping to to one or more addresses specified by `dest`.
117 /// The first response received causes the future to emit `Ok(())`.
118 fn ping(&self) -> BoxFuture<'_, Result<(), Error>> {
119 self.send(Ping::new())
120 }
121
122 /// Analogous to [`LocalEndpointExt::send_as_stream`], except using this `RemoteEndpoint` for
123 /// the destination SocketAddr and path.
124 fn send_as_stream<'a, R, SD>(&'a self, send_desc: SD) -> SendAsStream<'a, R>
125 where
126 SD: SendDesc<Self::InboundContext, R> + 'a,
127 R: Send + 'a,
128 {
129 let (sender, receiver) = futures::channel::mpsc::channel::<Result<R, Error>>(10);
130
131 SendAsStream {
132 receiver,
133 send_future: self.send(SendAsStreamDesc::new(send_desc, sender)),
134 }
135 }
136
137 /// Analogous to [`LocalEndpointExt::send_as_stream`], except using this `RemoteEndpoint` for
138 /// the destination SocketAddr and using a path relative to this `RemoteEndpoint`.
139 fn send_to_as_stream<'a, R, SD, UF>(&'a self, path: UF, send_desc: SD) -> SendAsStream<'a, R>
140 where
141 SD: SendDesc<Self::InboundContext, R> + 'a,
142 R: Send + 'a,
143 UF: AsRef<RelRef>,
144 {
145 let (sender, receiver) = futures::channel::mpsc::channel::<Result<R, Error>>(10);
146
147 SendAsStream {
148 receiver,
149 send_future: self.send_to(path, SendAsStreamDesc::new(send_desc, sender)),
150 }
151 }
152}
153
154/// Blanket implementation of `RemoteEndpointExt` for all `RemoteEndpoint` instances.
155impl<T: RemoteEndpoint> RemoteEndpointExt for T {}