tcp_client/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![forbid(unsafe_code)]
4#![warn(missing_docs)]
5
6pub mod config;
7pub mod errors;
8
9pub extern crate bytes;
10pub extern crate tcp_handler;
11
12/// The main macro provided by this crate.
13///
14/// # Example
15/// ```rust,no_run
16/// use tcp_client::define_client;
17/// use tcp_client::errors::Result;
18///
19/// define_client!(pub CommonMyClient, MyClient, "MyTcpApplication");
20///
21/// impl MyClient {
22///     // define your method here.
23///     // example:
24///     async fn my_method(&mut self) -> Result<()> {
25///         self.check_func("my_method").await?;
26///         // ...
27///         Ok(())
28///     }
29/// }
30///
31/// #[tokio::main]
32/// async fn main() {
33///     let mut client = MyClient::connect("127.0.0.1:1234").await.unwrap();
34///     // use client.
35///     // example:
36///     client.my_method().await.unwrap();
37/// }
38/// ```
39#[macro_export]
40macro_rules! define_client {
41    ($vis: vis $client: ident, $tcp_client: ident, $identifier: literal) => {
42        define_client!(compress_encrypt, $vis $client, $tcp_client, $identifier);
43    };
44    (raw, $vis: vis $client: ident, $tcp_client: ident, $identifier: literal) => {
45        define_client!(@@define raw, TcpClientHandlerRaw, $vis $client, $tcp_client, $identifier);
46    };
47    (compress, $vis: vis $client: ident, $tcp_client: ident, $identifier: literal) => {
48        define_client!(@@define compress, TcpClientHandlerCompress, $vis $client, $tcp_client, $identifier);
49    };
50    (encrypt, $vis: vis $client: ident, $tcp_client: ident, $identifier: literal) => {
51        define_client!(@@define encrypt, TcpClientHandlerEncrypt, $vis $client, $tcp_client, $identifier);
52    };
53    (compress_encrypt, $vis: vis $client: ident, $tcp_client: ident, $identifier: literal) => {
54        define_client!(@@define compress_encrypt, TcpClientHandlerCompressEncrypt, $vis $client, $tcp_client, $identifier);
55    };
56
57    (@@define $protocol: ident, $inner: ident, $vis: vis $client: ident, $tcp_client: ident, $identifier: literal) => {
58        #[derive(Debug)]
59        $vis struct $client<R: ::tokio::io::AsyncRead + ::core::marker::Unpin, W: ::tokio::io::AsyncWrite + ::core::marker::Unpin> {
60            identifier: &'static str,
61            version: &'static str,
62            inner: ::tcp_handler::streams::$protocol::$inner<R, W>,
63        }
64        #[allow(dead_code)]
65        impl<R: ::tokio::io::AsyncRead + ::core::marker::Unpin, W: ::tokio::io::AsyncWrite + ::core::marker::Unpin> $client<R, W> {
66            $vis async fn new(reader: R, writer: W) -> $crate::errors::Result<Self> {
67                let identifier = $identifier;
68                let version = env!("CARGO_PKG_VERSION");
69                let future = ::tcp_handler::streams::$protocol::$inner::new(reader, writer, identifier, version);
70                let timeout = $crate::config::get_connect_timeout();
71                let inner = ::tokio::time::timeout(timeout, future).await
72                    .map_err(|_| $crate::errors::Error::Timeout(true, timeout))??;
73                Ok(Self { identifier, version, inner })
74            }
75        }
76        #[allow(dead_code)]
77        impl<R: ::tokio::io::AsyncRead + ::core::marker::Unpin, W: ::tokio::io::AsyncWrite + ::core::marker::Unpin> $client<R, W> {
78            #[inline]
79            $vis fn get_identifier(&self) -> &'static str {
80                &self.identifier
81            }
82
83            #[inline]
84            $vis fn get_version(&self) -> &'static str {
85                &self.version
86            }
87
88            #[inline]
89            $vis async fn send<B: ::bytes::Buf>(&mut self, message: &mut B) -> $crate::errors::Result<()> {
90                self.inner.send(message).await.map_err(|e| e.into())
91            }
92
93            #[inline]
94            $vis async fn recv(&mut self) -> $crate::errors::Result<::bytes::BytesMut> {
95                let future = self.inner.recv();
96                let timeout = $crate::config::get_receive_timeout();
97                ::tokio::time::timeout(timeout, future).await
98                    .map_err(|_| $crate::errors::Error::Timeout(false, timeout))?
99                    .map_err(|e| e.into())
100            }
101
102            #[inline]
103            $vis async fn send_recv<B: ::bytes::Buf>(&mut self, message: &mut B) -> $crate::errors::Result<::bytes::BytesMut> {
104                self.send(message).await?;
105                self.recv().await
106            }
107
108            $vis async fn check_func(&mut self, func: &str) -> $crate::errors::Result<()> {
109                use ::bytes::{Buf, BufMut};
110                use ::variable_len_reader::{VariableReader, VariableWriter};
111                let mut writer = ::bytes::BytesMut::new().writer();
112                writer.write_string(func)?;
113                let mut reader = self.send_recv(&mut writer.into_inner()).await?.reader();
114                if reader.read_bool()? {
115                    Ok(())
116                } else {
117                    Err($crate::errors::Error::ServerDenied)
118                }
119            }
120        }
121        $vis type $tcp_client = $client<::tokio::io::BufReader<::tokio::net::tcp::OwnedReadHalf>, ::tokio::io::BufWriter<::tokio::net::tcp::OwnedWriteHalf>>;
122        #[allow(dead_code)]
123        impl $tcp_client {
124            $vis async fn connect<A: ::tokio::net::ToSocketAddrs>(addr: A) -> $crate::errors::Result<Self> {
125                let identifier = $identifier;
126                let version = env!("CARGO_PKG_VERSION");
127                let future = ::tcp_handler::streams::$protocol::$inner::connect(addr, identifier, version);
128                let timeout = $crate::config::get_connect_timeout();
129                let inner = ::tokio::time::timeout(timeout, future).await
130                    .map_err(|_| $crate::errors::Error::Timeout(true, timeout))??;
131                Ok(Self { identifier, version, inner })
132            }
133        }
134    };
135}
136
137#[cfg(test)]
138mod tests {
139    define_client!(DefaultClient, TcpDefaultClient, "DefaultClient");
140
141    define_client!(raw, RawClient, TcpRawClient, "RawClient");
142    define_client!(compress, CompressClient, TcpCompressClient, "CompressClient");
143    define_client!(encrypt, EncryptClient, TcpEncryptClient, "EncryptClient");
144    define_client!(compress_encrypt, CompressEncryptClient, TcpCompressEncryptClient, "CompressEncryptClient");
145}