2018-11-03 17:09:14 +01:00
|
|
|
use std::collections::HashMap;
|
2020-12-29 00:44:53 +01:00
|
|
|
use std::future::Future;
|
|
|
|
use std::{fmt, io};
|
2018-11-03 17:09:14 +01:00
|
|
|
|
2019-12-02 06:30:27 +01:00
|
|
|
use actix_rt::net::TcpStream;
|
2020-12-27 05:28:00 +01:00
|
|
|
use actix_service::{
|
|
|
|
fn_service, IntoServiceFactory as IntoBaseServiceFactory,
|
|
|
|
ServiceFactory as BaseServiceFactory,
|
|
|
|
};
|
2019-12-02 17:30:09 +01:00
|
|
|
use actix_utils::counter::CounterGuard;
|
2020-12-29 00:44:53 +01:00
|
|
|
use futures_core::future::LocalBoxFuture;
|
2018-12-06 23:04:42 +01:00
|
|
|
use log::error;
|
2018-11-03 17:09:14 +01:00
|
|
|
|
2020-12-29 00:44:53 +01:00
|
|
|
use crate::builder::bind_addr;
|
|
|
|
use crate::service::{BoxedServerService, InternalServiceFactory, StreamService};
|
|
|
|
use crate::socket::{MioStream, MioTcpListener, StdSocketAddr, StdTcpListener, ToSocketAddrs};
|
|
|
|
use crate::{ready, Token};
|
2018-11-03 17:09:14 +01:00
|
|
|
|
|
|
|
pub struct ServiceConfig {
|
2020-12-29 00:44:53 +01:00
|
|
|
pub(crate) services: Vec<(String, MioTcpListener)>,
|
2019-07-18 13:05:40 +02:00
|
|
|
pub(crate) apply: Option<Box<dyn ServiceRuntimeConfiguration>>,
|
2018-12-12 23:16:16 +01:00
|
|
|
pub(crate) threads: usize,
|
2020-12-29 00:44:53 +01:00
|
|
|
pub(crate) backlog: u32,
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ServiceConfig {
|
2020-12-29 00:44:53 +01:00
|
|
|
pub(super) fn new(threads: usize, backlog: u32) -> ServiceConfig {
|
2018-11-03 17:09:14 +01:00
|
|
|
ServiceConfig {
|
2018-12-12 23:16:16 +01:00
|
|
|
threads,
|
2019-03-11 20:01:55 +01:00
|
|
|
backlog,
|
2018-11-03 17:09:14 +01:00
|
|
|
services: Vec::new(),
|
2018-12-12 23:16:16 +01:00
|
|
|
apply: None,
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-12 23:16:16 +01:00
|
|
|
/// Set number of workers to start.
|
|
|
|
///
|
|
|
|
/// By default server uses number of available logical cpu as workers
|
|
|
|
/// count.
|
|
|
|
pub fn workers(&mut self, num: usize) {
|
|
|
|
self.threads = num;
|
|
|
|
}
|
|
|
|
|
2018-11-03 17:09:14 +01:00
|
|
|
/// Add new service to server
|
|
|
|
pub fn bind<U, N: AsRef<str>>(&mut self, name: N, addr: U) -> io::Result<&mut Self>
|
|
|
|
where
|
2020-12-29 00:44:53 +01:00
|
|
|
U: ToSocketAddrs,
|
2018-11-03 17:09:14 +01:00
|
|
|
{
|
2019-03-11 20:01:55 +01:00
|
|
|
let sockets = bind_addr(addr, self.backlog)?;
|
2018-11-03 17:09:14 +01:00
|
|
|
|
|
|
|
for lst in sockets {
|
2020-12-29 00:44:53 +01:00
|
|
|
self._listen(name.as_ref(), lst);
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add new service to server
|
2020-12-29 00:44:53 +01:00
|
|
|
pub fn listen<N: AsRef<str>>(&mut self, name: N, lst: StdTcpListener) -> &mut Self {
|
|
|
|
self._listen(name, MioTcpListener::from_std(lst))
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
2018-12-12 23:16:16 +01:00
|
|
|
/// Register service configuration function. This function get called
|
|
|
|
/// during worker runtime configuration. It get executed in worker thread.
|
|
|
|
pub fn apply<F>(&mut self, f: F) -> io::Result<()>
|
2018-11-03 17:09:14 +01:00
|
|
|
where
|
|
|
|
F: Fn(&mut ServiceRuntime) + Send + Clone + 'static,
|
|
|
|
{
|
2018-12-12 23:16:16 +01:00
|
|
|
self.apply = Some(Box::new(f));
|
2018-11-03 17:09:14 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
2020-12-29 00:44:53 +01:00
|
|
|
|
|
|
|
fn _listen<N: AsRef<str>>(&mut self, name: N, lst: MioTcpListener) -> &mut Self {
|
|
|
|
if self.apply.is_none() {
|
|
|
|
self.apply = Some(Box::new(not_configured));
|
|
|
|
}
|
|
|
|
self.services.push((name.as_ref().to_string(), lst));
|
|
|
|
self
|
|
|
|
}
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) struct ConfiguredService {
|
2019-07-18 13:05:40 +02:00
|
|
|
rt: Box<dyn ServiceRuntimeConfiguration>,
|
2020-12-29 00:44:53 +01:00
|
|
|
names: HashMap<Token, (String, StdSocketAddr)>,
|
2019-12-04 16:34:48 +01:00
|
|
|
topics: HashMap<String, Token>,
|
|
|
|
services: Vec<Token>,
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ConfiguredService {
|
2019-07-18 13:05:40 +02:00
|
|
|
pub(super) fn new(rt: Box<dyn ServiceRuntimeConfiguration>) -> Self {
|
2018-11-03 17:09:14 +01:00
|
|
|
ConfiguredService {
|
|
|
|
rt,
|
|
|
|
names: HashMap::new(),
|
2019-12-04 16:34:48 +01:00
|
|
|
topics: HashMap::new(),
|
|
|
|
services: Vec::new(),
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-29 00:44:53 +01:00
|
|
|
pub(super) fn stream(&mut self, token: Token, name: String, addr: StdSocketAddr) {
|
2019-03-12 22:14:21 +01:00
|
|
|
self.names.insert(token, (name.clone(), addr));
|
2020-01-28 12:27:33 +01:00
|
|
|
self.topics.insert(name, token);
|
2019-12-04 16:34:48 +01:00
|
|
|
self.services.push(token);
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InternalServiceFactory for ConfiguredService {
|
|
|
|
fn name(&self, token: Token) -> &str {
|
2019-03-12 22:14:21 +01:00
|
|
|
&self.names[&token].0
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
2019-07-18 13:05:40 +02:00
|
|
|
fn clone_factory(&self) -> Box<dyn InternalServiceFactory> {
|
2018-11-03 17:09:14 +01:00
|
|
|
Box::new(Self {
|
|
|
|
rt: self.rt.clone(),
|
|
|
|
names: self.names.clone(),
|
2019-12-04 16:34:48 +01:00
|
|
|
topics: self.topics.clone(),
|
2018-11-03 17:09:14 +01:00
|
|
|
services: self.services.clone(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-11-14 13:38:24 +01:00
|
|
|
fn create(&self) -> LocalBoxFuture<'static, Result<Vec<(Token, BoxedServerService)>, ()>> {
|
2018-11-03 17:09:14 +01:00
|
|
|
// configure services
|
2019-12-04 16:34:48 +01:00
|
|
|
let mut rt = ServiceRuntime::new(self.topics.clone());
|
2018-11-03 17:09:14 +01:00
|
|
|
self.rt.configure(&mut rt);
|
|
|
|
rt.validate();
|
2019-12-04 16:34:48 +01:00
|
|
|
let mut names = self.names.clone();
|
|
|
|
let tokens = self.services.clone();
|
2018-11-03 17:09:14 +01:00
|
|
|
|
2019-11-14 13:38:24 +01:00
|
|
|
// construct services
|
2020-12-29 00:44:53 +01:00
|
|
|
Box::pin(async move {
|
2019-12-04 16:34:48 +01:00
|
|
|
let mut services = rt.services;
|
2019-11-14 13:38:24 +01:00
|
|
|
// TODO: Proper error handling here
|
|
|
|
for f in rt.onstart.into_iter() {
|
|
|
|
f.await;
|
2019-03-15 04:48:58 +01:00
|
|
|
}
|
2019-11-14 13:38:24 +01:00
|
|
|
let mut res = vec![];
|
2019-12-04 16:34:48 +01:00
|
|
|
for token in tokens {
|
|
|
|
if let Some(srv) = services.remove(&token) {
|
|
|
|
let newserv = srv.new_service(());
|
|
|
|
match newserv.await {
|
|
|
|
Ok(serv) => {
|
|
|
|
res.push((token, serv));
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
error!("Can not construct service");
|
|
|
|
return Err(());
|
|
|
|
}
|
2019-11-14 13:38:24 +01:00
|
|
|
}
|
2019-12-04 16:34:48 +01:00
|
|
|
} else {
|
|
|
|
let name = names.remove(&token).unwrap().0;
|
|
|
|
res.push((
|
|
|
|
token,
|
2020-12-27 05:28:00 +01:00
|
|
|
Box::new(StreamService::new(fn_service(move |_: TcpStream| {
|
|
|
|
error!("Service {:?} is not configured", name);
|
2020-12-29 00:44:53 +01:00
|
|
|
ready::<Result<_, ()>>(Ok(()))
|
2020-12-27 05:28:00 +01:00
|
|
|
}))),
|
2019-12-04 16:34:48 +01:00
|
|
|
));
|
2019-11-14 13:38:24 +01:00
|
|
|
};
|
|
|
|
}
|
2020-09-06 11:41:42 +02:00
|
|
|
Ok(res)
|
2020-12-29 00:44:53 +01:00
|
|
|
})
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) trait ServiceRuntimeConfiguration: Send {
|
2019-07-18 13:05:40 +02:00
|
|
|
fn clone(&self) -> Box<dyn ServiceRuntimeConfiguration>;
|
2018-11-03 17:09:14 +01:00
|
|
|
|
2018-12-06 23:04:42 +01:00
|
|
|
fn configure(&self, rt: &mut ServiceRuntime);
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<F> ServiceRuntimeConfiguration for F
|
|
|
|
where
|
|
|
|
F: Fn(&mut ServiceRuntime) + Send + Clone + 'static,
|
|
|
|
{
|
2019-07-18 13:05:40 +02:00
|
|
|
fn clone(&self) -> Box<dyn ServiceRuntimeConfiguration> {
|
2018-11-03 17:09:14 +01:00
|
|
|
Box::new(self.clone())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn configure(&self, rt: &mut ServiceRuntime) {
|
|
|
|
(self)(rt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn not_configured(_: &mut ServiceRuntime) {
|
|
|
|
error!("Service is not configured");
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ServiceRuntime {
|
|
|
|
names: HashMap<String, Token>,
|
|
|
|
services: HashMap<Token, BoxedNewService>,
|
2019-11-14 13:38:24 +01:00
|
|
|
onstart: Vec<LocalBoxFuture<'static, ()>>,
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ServiceRuntime {
|
|
|
|
fn new(names: HashMap<String, Token>) -> Self {
|
|
|
|
ServiceRuntime {
|
|
|
|
names,
|
|
|
|
services: HashMap::new(),
|
2019-03-15 04:09:34 +01:00
|
|
|
onstart: Vec::new(),
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn validate(&self) {
|
|
|
|
for (name, token) in &self.names {
|
|
|
|
if !self.services.contains_key(&token) {
|
|
|
|
error!("Service {:?} is not configured", name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-15 04:09:34 +01:00
|
|
|
/// Register service.
|
|
|
|
///
|
|
|
|
/// Name of the service must be registered during configuration stage with
|
|
|
|
/// *ServiceConfig::bind()* or *ServiceConfig::listen()* methods.
|
2018-11-03 17:09:14 +01:00
|
|
|
pub fn service<T, F>(&mut self, name: &str, service: F)
|
|
|
|
where
|
2020-12-27 05:28:00 +01:00
|
|
|
F: IntoBaseServiceFactory<T, TcpStream>,
|
|
|
|
T: BaseServiceFactory<TcpStream, Config = ()> + 'static,
|
2018-11-03 17:09:14 +01:00
|
|
|
T::Future: 'static,
|
|
|
|
T::Service: 'static,
|
|
|
|
T::InitError: fmt::Debug,
|
|
|
|
{
|
|
|
|
// let name = name.to_owned();
|
|
|
|
if let Some(token) = self.names.get(name) {
|
|
|
|
self.services.insert(
|
2020-04-20 01:02:08 +02:00
|
|
|
*token,
|
2018-11-03 17:09:14 +01:00
|
|
|
Box::new(ServiceFactory {
|
2019-11-14 13:38:24 +01:00
|
|
|
inner: service.into_factory(),
|
2018-11-03 17:09:14 +01:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
panic!("Unknown service: {:?}", name);
|
|
|
|
}
|
|
|
|
}
|
2019-03-15 04:09:34 +01:00
|
|
|
|
|
|
|
/// Execute future before services initialization.
|
2019-03-15 04:23:49 +01:00
|
|
|
pub fn on_start<F>(&mut self, fut: F)
|
2019-03-15 04:09:34 +01:00
|
|
|
where
|
2019-11-14 13:38:24 +01:00
|
|
|
F: Future<Output = ()> + 'static,
|
2019-03-15 04:09:34 +01:00
|
|
|
{
|
2020-12-29 00:44:53 +01:00
|
|
|
self.onstart.push(Box::pin(fut))
|
2019-03-15 04:09:34 +01:00
|
|
|
}
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type BoxedNewService = Box<
|
2020-12-27 05:28:00 +01:00
|
|
|
dyn BaseServiceFactory<
|
2020-12-29 00:44:53 +01:00
|
|
|
(Option<CounterGuard>, MioStream),
|
2018-11-03 17:09:14 +01:00
|
|
|
Response = (),
|
|
|
|
Error = (),
|
|
|
|
InitError = (),
|
2019-12-02 06:30:27 +01:00
|
|
|
Config = (),
|
2018-11-03 17:09:14 +01:00
|
|
|
Service = BoxedServerService,
|
2019-11-14 13:38:24 +01:00
|
|
|
Future = LocalBoxFuture<'static, Result<BoxedServerService, ()>>,
|
2018-11-03 17:09:14 +01:00
|
|
|
>,
|
|
|
|
>;
|
|
|
|
|
|
|
|
struct ServiceFactory<T> {
|
|
|
|
inner: T,
|
|
|
|
}
|
|
|
|
|
2020-12-29 00:44:53 +01:00
|
|
|
impl<T> BaseServiceFactory<(Option<CounterGuard>, MioStream)> for ServiceFactory<T>
|
2018-11-03 17:09:14 +01:00
|
|
|
where
|
2020-12-27 05:28:00 +01:00
|
|
|
T: BaseServiceFactory<TcpStream, Config = ()>,
|
2018-11-03 17:09:14 +01:00
|
|
|
T::Future: 'static,
|
|
|
|
T::Service: 'static,
|
|
|
|
T::Error: 'static,
|
|
|
|
T::InitError: fmt::Debug + 'static,
|
|
|
|
{
|
|
|
|
type Response = ();
|
|
|
|
type Error = ();
|
2019-12-02 06:30:27 +01:00
|
|
|
type Config = ();
|
2018-11-03 17:09:14 +01:00
|
|
|
type Service = BoxedServerService;
|
2020-12-13 01:46:32 +01:00
|
|
|
type InitError = ();
|
2019-11-14 13:38:24 +01:00
|
|
|
type Future = LocalBoxFuture<'static, Result<BoxedServerService, ()>>;
|
2018-11-03 17:09:14 +01:00
|
|
|
|
2019-12-02 16:27:48 +01:00
|
|
|
fn new_service(&self, _: ()) -> Self::Future {
|
|
|
|
let fut = self.inner.new_service(());
|
2020-12-29 00:44:53 +01:00
|
|
|
Box::pin(async move {
|
2020-09-06 11:41:42 +02:00
|
|
|
match fut.await {
|
2019-11-14 13:38:24 +01:00
|
|
|
Ok(s) => Ok(Box::new(StreamService::new(s)) as BoxedServerService),
|
|
|
|
Err(e) => {
|
|
|
|
error!("Can not construct service: {:?}", e);
|
|
|
|
Err(())
|
|
|
|
}
|
2020-09-06 11:41:42 +02:00
|
|
|
}
|
2020-12-29 00:44:53 +01:00
|
|
|
})
|
2018-11-03 17:09:14 +01:00
|
|
|
}
|
|
|
|
}
|