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
// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // use super::*; use crate::UriBuf; /// An object that represents a remote CoAP endpoint with a default, overridable path. /// /// # Example /// /// ``` /// # #![feature(async_await)] /// # /// # use std::sync::Arc; /// # use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt}; /// # use async_coap::prelude::*; /// # use async_coap::datagram::{DatagramLocalEndpoint,AllowStdUdpSocket}; /// # /// # // Create our asynchronous socket. In this case, it is just an /// # // (inefficient) wrapper around the standard rust `UdpSocket`, /// # // but that is quite adequate in this case. /// # let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed"); /// # /// # // Create a new local endpoint from the socket we just created, /// # // wrapping it in a `Arc<>` to ensure it can live long enough. /// # let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket)); /// # /// # // Create a local execution pool for running our local endpoint. /// # let mut pool = LocalPool::new(); /// # /// # // Add our local endpoint to the pool, so that it /// # // can receive packets. /// # pool.spawner().spawn_local(local_endpoint /// # .clone() /// # .receive_loop_arc(null_receiver!()) /// # .map(|err| panic!("Receive loop terminated: {}", err)) /// # ); /// # /// # let future = async move { /// // Create a remote endpoint instance to represent the /// // device we wish to interact with. /// let remote_endpoint = local_endpoint /// .remote_endpoint_from_uri(uri!("coap://coap.me")) /// .unwrap(); // Will only fail if the URI scheme or authority is unrecognizable /// /// // Create a future that sends a request to a specific path /// // on the remote endpoint, collecting any blocks in the response /// // and returning `Ok(OwnedImmutableMessage)` upon success. /// let future = remote_endpoint.send_to( /// rel_ref!("large"), /// CoapRequest::get() // This is a CoAP GET request /// .accept(ContentFormat::TEXT_PLAIN_UTF8) // We only want plaintext /// .block2(Some(Default::default())) // Enable block2 processing /// .emit_successful_collected_response() // Collect all blocks into a single message /// ); /// /// // Wait for the final result and print it. /// println!("result: {:?}", future.await.unwrap()); /// # }; /// # /// # pool.run_until(future); /// ``` /// pub trait RemoteEndpoint { /// The `SocketAddr` type to use with this local endpoint. This is usually /// simply `std::net::SocketAddr`, but may be different in some cases (like for CoAP-SMS /// endpoints). type SocketAddr: SocketAddrExt; /// Type used by closure that is passed into `send()`, representing the context for the /// response. type InboundContext: InboundContext<SocketAddr = Self::SocketAddr>; /// Returns a [`UriBuf`] describing the underlying destination of this remote endpoint. fn uri(&self) -> UriBuf; /// Returns a string slice containing the scheme for this `RemoteEndpoint`. fn scheme(&self) -> &'static str; /// Prevents this remote endpoint from including a `Uri-Host` option. fn remove_host_option(&mut self); /// Creates a clone of this `RemoteEndpoint` with a different relative path. fn clone_using_rel_ref(&self, uri: &RelRef) -> Self; /// Uses `send_desc` to send a request to the endpoint and path described by this /// `RemoteEndpoint` instance. fn send<'a, R, SD>(&'a self, send_desc: SD) -> BoxFuture<'_, Result<R, Error>> where SD: SendDesc<Self::InboundContext, R> + 'a, R: Send + 'a; /// Uses `send_desc` to send a request to the given relative path on the endpoint described /// by this `RemoteEndpoint` instance. fn send_to<'a, R, SD, UF>(&'a self, path: UF, send_desc: SD) -> BoxFuture<'_, Result<R, Error>> where SD: SendDesc<Self::InboundContext, R> + 'a, R: Send + 'a, UF: AsRef<RelRef>; } /// Extension trait which implements additional helper methods. pub trait RemoteEndpointExt: RemoteEndpoint { /// Sends an application-level ping to to one or more addresses specified by `dest`. /// The first response received causes the future to emit `Ok(())`. fn ping(&self) -> BoxFuture<'_, Result<(), Error>> { self.send(Ping::new()) } /// Analogous to [`LocalEndpointExt::send_as_stream`], except using this `RemoteEndpoint` for /// the destination SocketAddr and path. fn send_as_stream<'a, R, SD>(&'a self, send_desc: SD) -> SendAsStream<'a, R> where SD: SendDesc<Self::InboundContext, R> + 'a, R: Send + 'a, { let (sender, receiver) = futures::channel::mpsc::channel::<Result<R, Error>>(10); SendAsStream { receiver, send_future: self.send(SendAsStreamDesc::new(send_desc, sender)), } } /// Analogous to [`LocalEndpointExt::send_as_stream`], except using this `RemoteEndpoint` for /// the destination SocketAddr and using a path relative to this `RemoteEndpoint`. fn send_to_as_stream<'a, R, SD, UF>(&'a self, path: UF, send_desc: SD) -> SendAsStream<'a, R> where SD: SendDesc<Self::InboundContext, R> + 'a, R: Send + 'a, UF: AsRef<RelRef>, { let (sender, receiver) = futures::channel::mpsc::channel::<Result<R, Error>>(10); SendAsStream { receiver, send_future: self.send_to(path, SendAsStreamDesc::new(send_desc, sender)), } } } /// Blanket implementation of `RemoteEndpointExt` for all `RemoteEndpoint` instances. impl<T: RemoteEndpoint> RemoteEndpointExt for T {}