mod common_api;
mod lynn_client_config;
use std::{net::ToSocketAddrs, time::Duration};
use common_api::{spawn_check_heart, spawn_handle};
use lynn_client_config::{LynnClientConfig, LynnClientConfigBuilder};
use tokio::{net::TcpStream, sync::mpsc, task::JoinHandle, time};
use tracing::{error, info, warn, Level};
use tracing_subscriber::fmt;
use crate::lynn_tcp_dependents::{HandlerResult, InputBufVO};
pub mod client_config {
pub use super::lynn_client_config::LynnClientConfig;
pub use super::lynn_client_config::LynnClientConfigBuilder;
}
#[cfg(feature = "client")]
pub struct LynnClient<'a> {
lynn_client_config: LynnClientConfig<'a>,
connection_join_handle: Option<JoinHandle<()>>,
tx_write: Option<mpsc::Sender<HandlerResult>>,
rx_read: Option<mpsc::Receiver<InputBufVO>>,
}
impl<'a> LynnClient<'a> {
pub async fn new_with_config(lynn_client_config: LynnClientConfig<'a>) -> Self {
let client = Self {
lynn_client_config,
connection_join_handle: None,
tx_write: None,
rx_read: None,
};
client
}
#[deprecated(since = "1.1.7", note = "use `new_with_addr` instead")]
pub async fn new_with_ipv4(server_ipv4: &'a str) -> Self {
let client = Self {
lynn_client_config: LynnClientConfigBuilder::new()
.with_server_ipv4(server_ipv4)
.build(),
connection_join_handle: None,
tx_write: None,
rx_read: None,
};
client
}
pub async fn new_with_addr<T>(server_addr: T) -> Self
where
T: ToSocketAddrs,
{
let client = Self {
lynn_client_config: LynnClientConfigBuilder::new()
.with_server_addr(server_addr)
.build(),
connection_join_handle: None,
tx_write: None,
rx_read: None,
};
client
}
pub async fn start(mut self: Self) -> Self {
match self.run().await {
Ok(_) => self,
Err(e) => {
error!("{}", e);
self
}
}
}
async fn run(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let retry_count = 3;
let timeout = Duration::from_secs(3);
let ip_v4 = self.lynn_client_config.get_server_ipv4().to_string();
let channel_size = self
.lynn_client_config
.get_client_single_channel_size()
.clone();
let message_header_mark = self.lynn_client_config.get_message_header_mark().clone();
let message_tail_mark = self.lynn_client_config.get_message_tail_mark().clone();
for _ in 0..retry_count {
match time::timeout(timeout, TcpStream::connect(ip_v4.clone())).await {
Ok(stream) => {
if let Ok(stream) = stream {
let (tx_write, rx_read, join_handle) = spawn_handle(
stream,
channel_size,
message_header_mark,
message_tail_mark,
);
self.tx_write = Some(tx_write);
self.rx_read = Some(rx_read);
self.connection_join_handle = Some(join_handle);
self.check_heart().await;
info!(
"Client - [Main-LynnClient] connection to [server_ipv4:{}] success!!! ",
{ ip_v4 }
);
return Ok(());
} else if let Err(e) = stream {
warn!(
"connect to server failed - TcpStream e: {:?}",
e.to_string()
);
continue;
}
}
Err(e) => {
warn!("connect to server failed - timeout e: {:?}", e.to_string());
continue;
}
}
}
Err("connect to server failed".into())
}
#[cfg(feature = "client")]
pub fn log_server(&self) {
let subscriber = fmt::Subscriber::builder()
.with_max_level(Level::INFO)
.finish();
match tracing::subscriber::set_global_default(subscriber) {
Ok(_) => {
info!("Client - [log server] start sucess!!!")
}
Err(e) => {
warn!("set_global_default failed - e: {:?}", e.to_string())
}
}
}
pub async fn get_receive_data(&mut self) -> Option<InputBufVO> {
self.rx_read.as_mut().unwrap().recv().await
}
pub async fn get_sender(&mut self) -> Option<mpsc::Sender<HandlerResult>> {
self.tx_write.clone()
}
pub async fn send_data(
&mut self,
handler_result: HandlerResult,
) -> Result<(), Box<dyn std::error::Error>> {
match &self.tx_write {
Some(sender) => {
if let Err(e) = sender.send(handler_result).await {
error!("send to server failed - e: {:?}", e);
Err(e.into())
} else {
Ok(())
}
}
None => Err("tx_write is None , No linked server".into()),
}
}
pub(crate) async fn check_heart(&mut self) {
let interval_time = self
.lynn_client_config
.get_server_check_heart_interval()
.clone();
if let Some(sender) = self.get_sender().await {
spawn_check_heart(interval_time, sender);
} else {
warn!("Client - [check heart] start failed!!!");
}
}
}