#[cfg(not(target_arch = "wasm32"))]
use crate::client::HybridClient;
#[cfg(target_arch = "wasm32")]
use crate::client::WebSocketClient;
use crate::client::builder::{BaseClientBuilderConfig, ClientWrapper};
use crate::common::MessageParser;
use crate::common::config_types::{HeartbeatAppState, HeartbeatConfig};
use crate::common::error::Result;
use crate::common::message::{
ArcMessageMiddleware, ArcMessageProcessor, MessageContext, MessagePipeline, MessageProcessor,
};
use crate::common::protocol::Frame;
use crate::common::protocol::flare::core::commands::command::Type as CommandType;
use crate::transport::events::{ConnectionEvent, ConnectionObserver};
use async_trait::async_trait;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{debug, error, info, warn};
#[async_trait]
pub trait MessageListener: Send + Sync {
async fn on_message(&self, frame: &Frame) -> Result<Option<Frame>> {
let _ = frame;
Ok(None)
}
async fn on_connect(&self) -> Result<()> {
Ok(())
}
async fn on_disconnect(&self, reason: Option<&str>) -> Result<()> {
let _ = reason;
Ok(())
}
async fn on_error(&self, error: &str) -> Result<()> {
let _ = error;
Ok(())
}
}
pub struct FlareClientBuilder {
base: BaseClientBuilderConfig,
listener: Option<Arc<dyn MessageListener>>,
middlewares: Vec<ArcMessageMiddleware>,
processors: Vec<ArcMessageProcessor>,
observers: Vec<Arc<dyn ConnectionObserver>>,
}
impl FlareClientBuilder {
pub fn new(server_url: impl Into<String>) -> Self {
Self {
base: BaseClientBuilderConfig::new(server_url),
listener: None,
middlewares: Vec::new(),
processors: Vec::new(),
observers: Vec::new(),
}
}
pub fn with_listener(mut self, listener: Arc<dyn MessageListener>) -> Self {
self.listener = Some(listener);
self
}
pub fn with_middleware(mut self, middleware: ArcMessageMiddleware) -> Self {
self.middlewares.push(middleware);
self
}
pub fn with_processor(mut self, processor: ArcMessageProcessor) -> Self {
self.processors.push(processor);
self
}
pub fn with_observer(mut self, observer: Arc<dyn ConnectionObserver>) -> Self {
self.observers.push(observer);
self
}
pub fn with_protocol(
mut self,
protocol: crate::common::config_types::TransportProtocol,
) -> Self {
self.base = self.base.with_protocol(protocol);
self
}
pub fn with_protocol_race(
mut self,
protocols: Vec<crate::common::config_types::TransportProtocol>,
) -> Self {
self.base = self.base.with_protocol_race(protocols);
self
}
pub fn with_protocol_url(
mut self,
protocol: crate::common::config_types::TransportProtocol,
url: String,
) -> Self {
self.base = self.base.with_protocol_url(protocol, url);
self
}
pub fn with_user_id(mut self, user_id: String) -> Self {
self.base = self.base.with_user_id(user_id);
self
}
pub fn with_format(mut self, format: crate::common::protocol::SerializationFormat) -> Self {
self.base = self.base.with_format(format);
self
}
pub fn with_compression(
mut self,
compression: crate::common::compression::CompressionAlgorithm,
) -> Self {
self.base = self.base.with_compression(compression);
self
}
pub fn force_format(mut self, format: crate::common::protocol::SerializationFormat) -> Self {
self.base = self.base.force_format(format);
self
}
pub fn force_compression(
mut self,
compression: crate::common::compression::CompressionAlgorithm,
) -> Self {
self.base = self.base.force_compression(compression);
self
}
pub fn with_device_info(mut self, device_info: crate::common::device::DeviceInfo) -> Self {
self.base = self.base.with_device_info(device_info);
self
}
pub fn with_heartbeat(
mut self,
heartbeat: crate::common::config_types::HeartbeatConfig,
) -> Self {
self.base = self.base.with_heartbeat(heartbeat);
self
}
pub fn with_tls(mut self, tls: crate::common::config_types::TlsConfig) -> Self {
self.base = self.base.with_tls(tls);
self
}
pub fn with_connect_timeout(mut self, timeout: std::time::Duration) -> Self {
self.base = self.base.with_connect_timeout(timeout);
self
}
pub fn with_race_timeout(mut self, timeout: std::time::Duration) -> Self {
self.base = self.base.with_race_timeout(timeout);
self
}
pub fn with_reconnect_interval(mut self, interval: std::time::Duration) -> Self {
self.base = self.base.with_reconnect_interval(interval);
self
}
pub fn with_max_reconnect_attempts(mut self, attempts: Option<u32>) -> Self {
self.base = self.base.with_max_reconnect_attempts(attempts);
self
}
pub fn with_token(mut self, token: String) -> Self {
self.base = self.base.with_token(token);
self
}
pub fn enable_router(mut self) -> Self {
self.base = self.base.enable_router();
self
}
pub async fn build_with_race(self) -> Result<FlareClient> {
let listener = self.listener.ok_or_else(|| {
crate::common::error::FlareError::protocol_error(
"MessageListener is required".to_string(),
)
})?;
use crate::common::message::parser::PRE_NEGOTIATION_PARSER;
#[cfg(target_arch = "wasm32")]
let client = WebSocketClient::connect_with_config(self.base.config.clone()).await?;
let pipeline = Arc::new(Mutex::new(MessagePipeline::new(
PRE_NEGOTIATION_PARSER.clone(),
)));
for middleware in self.middlewares {
pipeline.lock().await.add_middleware(middleware).await;
}
let listener_processor = Arc::new(ListenerProcessor {
listener: listener.clone(),
});
pipeline
.lock()
.await
.add_processor(listener_processor)
.await;
for processor in self.processors {
pipeline.lock().await.add_processor(processor).await;
}
#[cfg(not(target_arch = "wasm32"))]
let client = HybridClient::connect_with_race(self.base.config.clone()).await?;
let wrapper = ClientWrapper::new(client);
let observer = Arc::new(FlareObserver {
pipeline: pipeline.clone(),
listener: listener.clone(),
});
let observer_clone = observer.clone();
wrapper.add_observer(observer_clone).await;
for observer in self.observers {
wrapper.add_observer(observer).await;
}
wrapper
.wait_for_negotiation(std::time::Duration::from_secs(10))
.await?;
let parser = wrapper.parser_snapshot().await;
pipeline.lock().await.update_parser(parser).await;
Ok(FlareClient {
wrapper,
pipeline,
listener,
})
}
}
#[derive(Clone)]
pub struct FlareClient {
wrapper: ClientWrapper,
#[allow(dead_code)] pipeline: Arc<Mutex<MessagePipeline>>,
#[allow(dead_code)] listener: Arc<dyn MessageListener>,
}
impl FlareClient {
pub async fn send_frame(&self, frame: &Frame) -> Result<()> {
self.wrapper.send_frame(frame).await
}
pub async fn send_frame_and_wait(
&self,
frame: &Frame,
timeout: std::time::Duration,
) -> Result<Frame> {
self.wrapper.send_frame_and_wait(frame, timeout).await
}
#[cfg(not(target_arch = "wasm32"))]
pub fn is_connected(&self) -> bool {
crate::client::runtime::run_client_async(self.is_connected_async())
}
pub async fn is_connected_async(&self) -> bool {
self.wrapper.is_connected_async().await
}
pub async fn disconnect(self) -> Result<()> {
self.wrapper.disconnect().await
}
#[cfg(not(target_arch = "wasm32"))]
pub fn connection_id(&self) -> Option<String> {
crate::client::runtime::run_client_async(self.connection_id_async())
}
pub async fn connection_id_async(&self) -> Option<String> {
self.wrapper.connection_id_async().await
}
pub async fn parser_snapshot(&self) -> MessageParser {
self.wrapper.parser_snapshot().await
}
pub fn active_protocol(&self) -> crate::common::config_types::TransportProtocol {
self.wrapper.active_protocol()
}
pub async fn update_heartbeat_config(&self, config: HeartbeatConfig) {
self.wrapper.update_heartbeat_config(config).await;
}
pub async fn set_heartbeat_app_state(&self, state: HeartbeatAppState) {
self.wrapper.set_heartbeat_app_state(state).await;
}
pub async fn set_heartbeat_nat_timeout(&self, timeout: Option<std::time::Duration>) {
self.wrapper.set_heartbeat_nat_timeout(timeout).await;
}
pub async fn heartbeat_effective_interval(&self) -> std::time::Duration {
self.wrapper.heartbeat_effective_interval().await
}
pub async fn update_parser(&self, parser: MessageParser) {
let mut pipeline = self.pipeline.lock().await;
*pipeline = MessagePipeline::new(parser);
}
pub async fn add_observer(&self, observer: Arc<dyn ConnectionObserver>) {
self.wrapper.add_observer(observer).await;
}
}
struct FlareObserver {
pipeline: Arc<Mutex<MessagePipeline>>,
listener: Arc<dyn MessageListener>,
}
impl ConnectionObserver for FlareObserver {
fn on_event(&self, event: &ConnectionEvent) {
match event {
ConnectionEvent::Connected => {
info!("[FlareClient] ✅ 已连接");
let listener = self.listener.clone();
crate::client::runtime::spawn_client_task(async move {
if let Err(e) = listener.on_connect().await {
error!("[FlareClient] on_connect 失败: {}", e);
}
});
}
ConnectionEvent::Disconnected(reason) => {
let reason_arc: Arc<str> = Arc::from(reason.as_str());
info!("[FlareClient] ❌ 连接断开: {}", reason_arc);
let listener = self.listener.clone();
crate::client::runtime::spawn_client_task(async move {
if let Err(e) = listener.on_disconnect(Some(&reason_arc)).await {
error!("[FlareClient] on_disconnect 失败: {}", e);
}
});
}
ConnectionEvent::Error(err) => {
let err_str = format!("{:?}", err);
let is_race_error = err_str.contains("Connection reset without closing handshake")
|| (err_str.contains("ConnectionFailed")
&& err_str.contains("WebSocket protocol error"));
let is_connection_lost = err_str.contains("connection lost")
|| err_str.contains("connection closed")
|| err_str.contains("Connection reset");
if is_race_error {
debug!(
"[FlareClient] 协议竞速:未选中协议连接已关闭(这是正常的,协议竞速会选择最快的协议)"
);
} else if is_connection_lost {
warn!("[FlareClient] 连接丢失: {:?}", err);
info!("[FlareClient] 💡 底层客户端将自动尝试重连(如果配置了重连)");
let listener = self.listener.clone();
let err_str_arc: Arc<str> = Arc::from(err_str.as_str());
crate::client::runtime::spawn_client_task(async move {
if let Err(e) = listener.on_error(&err_str_arc).await {
error!("[FlareClient] on_error 失败: {}", e);
}
});
} else {
warn!("[FlareClient] 连接错误: {:?}", err);
let listener = self.listener.clone();
let err_str_arc: Arc<str> = Arc::from(err_str.as_str());
crate::client::runtime::spawn_client_task(async move {
if let Err(e) = listener.on_error(&err_str_arc).await {
error!("[FlareClient] on_error 失败: {}", e);
}
});
}
}
ConnectionEvent::Message(data) => {
use crate::common::message::parser::PRE_NEGOTIATION_PARSER;
use crate::common::protocol::flare::core::commands::system_command::Type as SysType;
let pipeline = self.pipeline.clone();
let data = data.clone();
crate::client::runtime::spawn_client_task(async move {
if let Ok(frame) = PRE_NEGOTIATION_PARSER.parse(&data)
&& let Some(cmd) = &frame.command
&& let Some(CommandType::System(sys_cmd)) = &cmd.r#type
&& sys_cmd.r#type == SysType::ConnectAck as i32
{
let format =
crate::common::protocol::SerializationFormat::try_from(sys_cmd.format)
.unwrap_or(crate::common::protocol::SerializationFormat::Json);
let compression =
crate::common::compression::CompressionAlgorithm::from_str(
&sys_cmd.compression,
)
.unwrap_or(crate::common::compression::CompressionAlgorithm::None);
let encryption = crate::common::encryption::EncryptionAlgorithm::from_str(
&sys_cmd.encryption,
)
.unwrap_or(crate::common::encryption::EncryptionAlgorithm::None);
{
let compression_clone = compression.clone();
let encryption_clone = encryption.clone();
let pipeline_guard = pipeline.lock().await;
let new_parser =
crate::common::MessageParser::new(format, compression, encryption);
pipeline_guard.update_parser(new_parser).await;
debug!(
"[FlareObserver] ✅ 已更新 MessagePipeline 的 parser: format={:?}, compression={:?}, encryption={:?}",
format, compression_clone, encryption_clone
);
}
let pipeline_guard = pipeline.lock().await;
match pipeline_guard.process_frame(&frame, None).await {
Ok(Some(_response_data)) => {
debug!(
"[FlareClient] 消息管道返回响应,但客户端无法自动发送,需要用户手动处理"
);
}
Ok(None) => {
debug!("[FlareClient] CONNECT_ACK 处理完成,无需响应");
}
Err(e) => {
error!("[FlareClient] CONNECT_ACK 处理失败: {}", e);
}
}
return;
}
let pipeline = pipeline.lock().await;
match pipeline.process_raw(&data, None).await {
Ok(Some(_response_data)) => {
debug!(
"[FlareClient] 消息管道返回响应,但客户端无法自动发送,需要用户手动处理"
);
}
Ok(None) => {
debug!("[FlareClient] 消息处理完成,无需响应");
}
Err(e) => {
error!("[FlareClient] 消息管道处理失败: {}", e);
}
}
});
}
}
}
}
struct ListenerProcessor {
listener: Arc<dyn MessageListener>,
}
#[async_trait]
impl MessageProcessor for ListenerProcessor {
async fn process(&self, ctx: &MessageContext) -> Result<Option<Frame>> {
self.listener.on_message(&ctx.frame).await
}
fn name(&self) -> &str {
"ListenerProcessor"
}
}