1 //! Service discovery 2 //! 3 //! This module provides the [`Change`] enum, which indicates the arrival or departure of a service 4 //! from a collection of similar services. Most implementations should use the [`Discover`] trait 5 //! in their bounds to indicate that they can handle services coming and going. [`Discover`] itself 6 //! is primarily a convenience wrapper around [`TryStream<Ok = Change>`][`TryStream`]. 7 //! 8 //! Every discovered service is assigned an identifier that is distinct among the currently active 9 //! services. If that service later goes away, a [`Change::Remove`] is yielded with that service's 10 //! identifier. From that point forward, the identifier may be re-used. 11 //! 12 //! # Examples 13 //! 14 //! ```rust 15 //! use futures_util::{future::poll_fn, pin_mut}; 16 //! use tower::discover::{Change, Discover}; 17 //! async fn services_monitor<D: Discover>(services: D) { 18 //! pin_mut!(services); 19 //! while let Some(Ok(change)) = poll_fn(|cx| services.as_mut().poll_discover(cx)).await { 20 //! match change { 21 //! Change::Insert(key, svc) => { 22 //! // a new service with identifier `key` was discovered 23 //! # let _ = (key, svc); 24 //! } 25 //! Change::Remove(key) => { 26 //! // the service with identifier `key` has gone away 27 //! # let _ = (key); 28 //! } 29 //! } 30 //! } 31 //! } 32 //! ``` 33 //! 34 //! [`TryStream`]: https://docs.rs/futures/latest/futures/stream/trait.TryStream.html 35 36 mod error; 37 mod list; 38 39 pub use self::list::ServiceList; 40 41 use crate::sealed::Sealed; 42 use futures_core::TryStream; 43 use std::{ 44 pin::Pin, 45 task::{Context, Poll}, 46 }; 47 48 /// A dynamically changing set of related services. 49 /// 50 /// As new services arrive and old services are retired, 51 /// [`Change`]s are returned which provide unique identifiers 52 /// for the services. 53 /// 54 /// See the module documentation for more details. 55 pub trait Discover: Sealed<Change<(), ()>> { 56 /// A unique identifier for each active service. 57 /// 58 /// An identifier can be re-used once a [`Change::Remove`] has been yielded for its service. 59 type Key: Eq; 60 61 /// The type of [`Service`] yielded by this [`Discover`]. 62 /// 63 /// [`Service`]: crate::Service 64 type Service; 65 66 /// Error produced during discovery 67 type Error; 68 69 /// Yields the next discovery change set. poll_discover( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll<Option<Result<Change<Self::Key, Self::Service>, Self::Error>>>70 fn poll_discover( 71 self: Pin<&mut Self>, 72 cx: &mut Context<'_>, 73 ) -> Poll<Option<Result<Change<Self::Key, Self::Service>, Self::Error>>>; 74 } 75 76 impl<K, S, E, D: ?Sized> Sealed<Change<(), ()>> for D 77 where 78 D: TryStream<Ok = Change<K, S>, Error = E>, 79 K: Eq, 80 { 81 } 82 83 impl<K, S, E, D: ?Sized> Discover for D 84 where 85 D: TryStream<Ok = Change<K, S>, Error = E>, 86 K: Eq, 87 { 88 type Key = K; 89 type Service = S; 90 type Error = E; 91 poll_discover( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll<Option<Result<D::Ok, D::Error>>>92 fn poll_discover( 93 self: Pin<&mut Self>, 94 cx: &mut Context<'_>, 95 ) -> Poll<Option<Result<D::Ok, D::Error>>> { 96 TryStream::try_poll_next(self, cx) 97 } 98 } 99 100 /// A change in the service set. 101 #[derive(Debug)] 102 pub enum Change<K, V> { 103 /// A new service identified by key `K` was identified. 104 Insert(K, V), 105 /// The service identified by key `K` disappeared. 106 Remove(K), 107 } 108