use std::sync::Arc;
use futures::Future;
use futures::stream::Stream;
use error::Error;
use combinators::{FrozenSubscriber, NullResolver, NullHostResolver};
use {Name, Address, IpList};
/// Resolves a hostname into a list of IpAddresses
///
/// This is usually equivalent of the resolving A or AAAA record. This
/// kind of resolution is used in two cases:
///
/// 1. If user specified port of the service explicitly (`example.org:1234`)
/// 2. When there is known default port like `80` for http
///
/// Note: akin to A records this method returns plain list of addresses so
/// it can't use a backup addresses and weights. So this should be used for
/// simple cases and full blown `Resolve` trait (i.e. SRV records) for
/// more complex ones.
pub trait HostResolve {
/// A future returned from `resolve()`
type HostFuture: Future<Item=IpList, Error=Error>;
/// Resolve a name to an address once
fn resolve_host(&self, name: &Name) -> Self::HostFuture;
/// Create a subscriber that resolves once using this resolver
/// and never updates a stream
///
/// This is mostly useful for tests
fn frozen_host_subscriber(self) -> FrozenSubscriber<Self>
where Self: Sized
{
FrozenSubscriber { resolver: self }
}
/// Create a thing that implements Resolve+HostResolve but returns
/// `NameNotFound` on `resolve`
///
/// This is needed to add resolver that can only resolve hostnames to
/// the router.
fn null_service_resolver(self) -> NullResolver<Self>
where Self: Sized
{
NullResolver { resolver: self }
}
}
/// Resolves a name of the service in to a set of addresses
///
/// This is commonly done using SRV records, but can also be done
/// as a wrapper around resolver by resolving a host and adding a
/// default value (see `HostResolve::with_default_port`.
pub trait Resolve {
/// A future returned from `resolve()`
type Future: Future<Item=Address, Error=Error>;
/// Resolve a name to an address once
fn resolve(&self, name: &Name) -> Self::Future;
/// Create a subscriber that resolves once using this resolver
/// and never updates a stream
///
/// This is mostly useful for tests
fn frozen_subscriber(self) -> FrozenSubscriber<Self>
where Self: Resolve + Sized
{
FrozenSubscriber { resolver: self }
}
/// Create a subscriber that resolves once using this resolver
/// and never updates a stream
///
/// This is mostly useful for tests
fn frozen_service_subscriber(self) -> FrozenSubscriber<Self>
where Self: Sized
{
FrozenSubscriber { resolver: self }
}
/// Create a thing that implements Resolve+HostResolve but returns
/// `NameNotFound` on `resolve_host`
///
/// This is needed to add resolver that can only resolve services to
/// the router.
fn null_host_resolver(self) -> NullHostResolver<Self>
where Self: Sized
{
NullHostResolver { resolver: self }
}
}
/// A resolver that allows to subscribe on the host name and receive updates
///
pub trait HostSubscribe {
/// An error type returned by a stream
///
/// This is usually either ``abstract_ns::Error`` or ``Void``, showing
/// whether error can actually occur, but can be any other error at your
/// convenience.
///
/// Note: this is an associated type so that connection pool
/// implementations could accept `SubscribeHost<Error=Void>` as there are
/// no reason to shutdown pool if there is a temporary error in name
/// resolution (and all errors should be considered temporary as
/// user can even fix invalid name by fixing configuration file while
/// connection pool is operating).
type HostError: Into<Error>;
/// A stream returned from `subscribe()`
type HostStream: Stream<Item=IpList, Error=Self::HostError>;
/// Resolve a name and subscribe to the updates
///
/// Note: errors returned by a stream are considered fatal but temporary.
/// I.e. stream can't be used after an error, but user might subscribe
/// again after a short interval.
///
/// For efficiency it might be useful to attempt name resolution few
/// times if the error is temporary before returning an error, but
/// on network resolver fatal errors (or subsequent temporary ones)
/// should be returned so middleware and routers can failover to other
/// sources and put errors to log.
fn subscribe_host(&self, name: &Name) -> Self::HostStream;
}
/// A resolver that allows to subscribe on the service name
/// and receive updates
pub trait Subscribe {
/// An error type returned by a stream
///
/// This is usually either ``abstract_ns::Error`` or ``Void``, showing
/// whether error can actually occur, but can be any other error at your
/// convenience.
///
/// Note: this is an associated type so that connection pool
/// implementations could accept `SubscribeHost<Error=Void>` as there are
/// no reason to shutdown pool if there is a temporary error in name
/// resolution (and all errors should be considered temporary as
/// user can even fix invalid name by fixing configuration file while
/// connection pool is operating).
type Error: Into<Error>;
/// A stream returned from `subscribe()`
type Stream: Stream<Item=Address, Error=Self::Error>;
/// Resolve a name and subscribe to the updates
///
/// Note: errors returned by a stream are considered fatal but temporary.
/// I.e. stream can't be used after an error, but user might subscribe
/// again after a short interval.
///
/// For efficiency it might be useful to attempt name resolution few
/// times if the error is temporary before returning an error, but
/// on network resolver fatal errors (or subsequent temporary ones)
/// should be returned so middleware and routers can failover to other
/// sources and put errors to log.
fn subscribe(&self, name: &Name) -> Self::Stream;
}
impl<T: Resolve> Resolve for Arc<T> {
type Future = T::Future;
fn resolve(&self, name: &Name) -> Self::Future {
(**self).resolve(name)
}
}
impl<T: HostResolve> HostResolve for Arc<T> {
type HostFuture = T::HostFuture;
fn resolve_host(&self, name: &Name) -> Self::HostFuture {
(**self).resolve_host(name)
}
}
impl<T: Subscribe> Subscribe for Arc<T> {
type Error = T::Error;
type Stream = T::Stream;
fn subscribe(&self, name: &Name) -> Self::Stream {
(**self).subscribe(name)
}
}
impl<T: HostSubscribe> HostSubscribe for Arc<T> {
type HostError = T::HostError;
type HostStream = T::HostStream;
fn subscribe_host(&self, name: &Name) -> Self::HostStream {
(**self).subscribe_host(name)
}
}