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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
pub mod configuration;
mod network;

// extern for macro.
pub extern crate anyhow;
pub extern crate async_trait;
pub extern crate tokio;
pub extern crate tokio_util;
pub extern crate tcp_handler;
#[cfg(feature = "serde")]
pub extern crate serde;

use std::net::SocketAddr;
use anyhow::Result;
use async_trait::async_trait;
use tcp_handler::common::AesCipher;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use crate::network::start_server;

pub use network::{send, recv};

#[async_trait]
pub trait FuncHandler<R, W>: Send where R: AsyncReadExt + Unpin + Send, W: AsyncWriteExt + Unpin + Send {
    async fn handle(&self, receiver: &mut R, sender: &mut W, cipher: AesCipher, addr: SocketAddr, version: &str) -> Result<AesCipher>;
}

#[macro_export]
macro_rules! func_handler {
    ($vi: vis $name: ident, |$receiver: ident, $sender: ident, $cipher: ident, $addr: ident, $version: ident| $block: expr) => {
        $vi struct $name;
        #[$crate::async_trait::async_trait]
        impl<R: $crate::tokio::io::AsyncReadExt + Unpin + Send, W: $crate::tokio::io::AsyncWriteExt + Unpin + Send> $crate::FuncHandler<R, W> for $name {
            async fn handle(&self, $receiver: &mut R, $sender: &mut W, $cipher: $crate::tcp_handler::common::AesCipher, $addr: std::net::SocketAddr, $version: &str) -> $crate::anyhow::Result<$crate::tcp_handler::common::AesCipher> {
                $block
            }
        }
    };
}

#[async_trait]
pub trait Server {
    fn get_identifier(&self) -> &'static str;

    /// # Example
    /// ```ignore
    /// version == env!("CARGO_PKG_VERSION")
    /// ```
    fn check_version(&self, version: &str) -> bool;

    fn get_function<R, W>(&self, func: &str) -> Option<Box<dyn FuncHandler<R, W>>>
        where R: AsyncReadExt + Unpin + Send, W: AsyncWriteExt + Unpin + Send;

    async fn start(&'static self) -> Result<()> {
        start_server(self).await
    }
}

#[cfg(test)]
mod tests {
    use anyhow::Result;
    use env_logger::Target;
    use tcp_client::client_base::ClientBase;
    use tcp_client::configuration::{Configuration as ClientConfiguration, set_config as set_client_config};
    use tcp_client::quickly_connect;
    use tcp_client::mutable_cipher::MutableCipher;
    use tcp_handler::common::AesCipher;
    use tokio::io::{AsyncReadExt, AsyncWriteExt};
    use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
    use tokio::net::TcpStream;
    use tokio::spawn;
    use crate::{FuncHandler, Server};
    use crate::configuration::{Configuration as ServerConfiguration, set_config as set_server_config};

    struct TestServer;

    impl Server for TestServer {
        fn get_identifier(&self) -> &'static str {
            "tester"
        }

        fn check_version(&self, version: &str) -> bool {
            version == env!("CARGO_PKG_VERSION")
        }

        fn get_function<R, W>(&self, func: &str) -> Option<Box<dyn FuncHandler<R, W>>> where R: AsyncReadExt + Unpin + Send, W: AsyncWriteExt + Unpin + Send {
            if func == "test" {
                func_handler!(TestHandler, |_receiver, _sender, cipher, _addr, _version| {
                    Ok(cipher)
                });
                Some(Box::new(TestHandler))
            } else {
                None
            }
        }
    }

    struct TestClient(OwnedReadHalf, OwnedWriteHalf, MutableCipher);

    impl From<(TcpStream, AesCipher)> for TestClient {
        fn from(value: (TcpStream, AesCipher)) -> Self {
            let (receiver, sender) = value.0.into_split();
            Self(receiver, sender, MutableCipher::new(value.1))
        }
    }

    impl ClientBase<OwnedReadHalf, OwnedWriteHalf> for TestClient {
        fn get_receiver<'a>(&'a mut self) -> (&'a mut OwnedReadHalf, &MutableCipher) {
            (&mut self.0, &self.2)
        }

        fn get_sender<'a>(&'a mut self) -> (&'a mut OwnedWriteHalf, &MutableCipher) {
            (&mut self.1, &self.2)
        }
    }

    static TEST_SERVER: TestServer = TestServer;

    #[tokio::test]
    async fn test() -> Result<()> {
        env_logger::builder().parse_filters("trace").target(Target::Stderr).try_init()?;
        set_server_config(ServerConfiguration {
            addr: "localhost:25565".to_string(),
            connect_sec: 5,
            idle_sec: 3,
        });
        set_client_config(ClientConfiguration {
            connect_sec: 5,
            idle_sec: 3,
        });

        let server = spawn(TEST_SERVER.start());
        let mut client: TestClient = quickly_connect("tester", env!("CARGO_PKG_VERSION"), "localhost:25565").await?;

        client.check_func("test").await?;

        server.abort();
        Ok(())
    }
}