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
use mio::{net::TcpListener, Events, Interest, Poll, Token};

use crate::{
    connection_acceptor::ConnectionAcceptor, connection_server::ConnectionServer, interrupted,
    Result, ServerConnector,
};

pub struct Server {
    poll: Poll,
    events: Events,
    services: Vec<ConnectionAcceptor>,
}

impl Server {
    pub fn new() -> Result<Self> {
        let poll = Poll::new()?;
        let events = Events::with_capacity(1024);
        log::trace!("new server");

        Ok(Self {
            poll,
            events,
            services: Default::default(),
        })
    }

    /// listener must be configured non_blocking
    pub fn register_service_listener<Connector: ServerConnector>(
        &mut self,
        listener: std::net::TcpListener,
        server_state: Connector,
    ) -> Result<ConnectionServer<Connector>> {
        let token = Token(self.services.len());
        log::trace!("new service listener index {} on {listener:?}", token.0);

        let mut listener = TcpListener::from_std(listener);
        self.poll.registry().register(
            &mut listener,
            token,
            Interest::READABLE.add(Interest::WRITABLE),
        )?;
        let (acceptor, server) = ConnectionServer::new(server_state, listener)?;

        self.services.push(acceptor);

        Ok(server)
    }

    /// Dedicate a thread to your connection frontend.
    pub fn serve(self) -> Result<()> {
        let Self {
            mut poll,
            mut events,
            services,
        } = self;
        log::trace!("serving frontend");
        loop {
            if let Err(e) = poll.poll(&mut events, None) {
                if interrupted(&e) {
                    log::trace!("interrupted");
                    continue;
                }
                log::error!("failed {e:?}");
                return Err(e.into());
            }

            for event in events.iter() {
                let service_index = event.token().0;
                log::trace!("new connection for service {service_index}");
                services[service_index].accept()?;
            }
        }
    }
}