Skip to main content

trillium_testing/runtimeless/
server.rs

1use super::SERVERS;
2use crate::{RuntimelessRuntime, TestTransport};
3use async_channel::Receiver;
4use std::io::{Error, Result};
5use trillium::Info;
6use trillium_server_common::Server;
7use url::Url;
8
9/// A [`Server`] for testing that does not depend on any runtime
10#[derive(Debug)]
11pub struct RuntimelessServer {
12    host: String,
13    port: u16,
14    channel: Receiver<TestTransport>,
15}
16
17impl RuntimelessServer {
18    /// returns whether there are any currently registered servers
19    pub fn is_empty() -> bool {
20        SERVERS.is_empty()
21    }
22
23    /// returns the number of currently registered servers
24    pub fn len() -> usize {
25        SERVERS.len()
26    }
27}
28
29impl Server for RuntimelessServer {
30    type Runtime = RuntimelessRuntime;
31    type Transport = TestTransport;
32    type UdpTransport = ();
33
34    fn runtime() -> Self::Runtime {
35        RuntimelessRuntime::default()
36    }
37
38    async fn accept(&mut self) -> Result<Self::Transport> {
39        self.channel.recv().await.map_err(Error::other)
40    }
41
42    fn from_host_and_port(host: &str, mut port: u16) -> Self {
43        if port == 0 {
44            loop {
45                port = fastrand::u16(..);
46                if !SERVERS.contains_key(&(host.to_string(), port)) {
47                    break;
48                }
49            }
50        }
51
52        let entry = SERVERS
53            .entry((host.to_string(), port))
54            .or_insert_with(async_channel::unbounded);
55
56        let (_, channel) = entry.value();
57
58        Self {
59            host: host.to_string(),
60            channel: channel.clone(),
61            port,
62        }
63    }
64
65    async fn clean_up(self) {
66        SERVERS.remove(&(self.host, self.port));
67    }
68
69    fn init(&self, info: &mut Info) {
70        info.insert_shared_state(
71            Url::parse(&format!("http://{}:{}", &self.host, self.port)).unwrap(),
72        );
73    }
74}