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#[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}