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
use crate::{Result, Error, FirePit};
use crate::util::PinnedFuture;
use crate::fire::{self, Wood};

use std::future;
use std::sync::Arc;
use std::net::SocketAddr;
use std::task::{Poll, Context};
use std::convert::Infallible;
use std::result::Result as StdResult;

use types::body::BodyHttp;

use hyper::Response;
use hyper::service::Service;
use hyper::server::conn::{AddrIncoming, AddrStream};


pub type HyperRequest = hyper::Request<hyper::Body>;

// todo replace this function once hyper-util is ready
pub(crate) struct Server {
	listener: hyper::Server<AddrIncoming, MakeFireService>
}

impl Server {
	pub(crate) async fn bind(
		addr: SocketAddr,
		wood: Arc<Wood>
	) -> Result<Self> {
		let listener = hyper::Server::try_bind(&addr)
			.map_err(Error::from_server_error)?
			.serve(MakeFireService { wood });
		Ok(Self { listener })
	}

	pub fn local_addr(&self) -> Result<SocketAddr> {
		Ok(self.listener.local_addr())
	}

	pub async fn serve(self) -> Result<()> {
		self.listener.await.map_err(Error::from_server_error)
	}
}

/// A `tower::Service` to be used with the `hyper::Server`
pub struct MakeFireService {
	pub(crate) wood: Arc<Wood>
}

impl MakeFireService {
	pub fn pit(&self) -> FirePit {
		FirePit { wood: self.wood.clone() }
	}

	pub fn make(&self, address: SocketAddr) -> FireService {
		FireService { wood: self.wood.clone(), address }
	}
}

impl<'a> Service<&'a AddrStream> for MakeFireService {
	type Response = FireService;
	type Error = Infallible;
	type Future = future::Ready<StdResult<FireService, Infallible>>;

	fn poll_ready(
		&mut self,
		_: &mut Context
	) -> Poll<StdResult<(), Infallible>> {
		Poll::Ready(Ok(()))
	}

	fn call(&mut self, addr_stream: &'a AddrStream) -> Self::Future {
		let address = addr_stream.remote_addr();
		future::ready(Ok(FireService {
			wood: self.wood.clone(),
			address
		}))
	}
}

pub struct FireService {
	wood: Arc<Wood>,
	address: SocketAddr
}

impl Service<HyperRequest> for FireService {
	type Response = Response<BodyHttp>;
	type Error = Infallible;
	type Future = PinnedFuture<'static, StdResult<Self::Response, Self::Error>>;

	fn poll_ready(
		&mut self,
		_: &mut Context
	) -> Poll<StdResult<(), Infallible>> {
		Poll::Ready(Ok(()))
	}

	fn call(&mut self, req: HyperRequest) -> Self::Future {
		let wood = self.wood.clone();
		let address = self.address;
		PinnedFuture::new(async move {
			fire::route_hyper(&wood, req, address).await
		})
	}
}