refactor(tests): reformat code and update dependency management
- Reorganized import statements in adapter tests for better readability - Replaced or_insert_with(Vec::new) with or_default() in test closures - Updated Cargo.lock with new dependency versions and checksums - Added TLS features to tonic dependency configuration - Included sqlx, chrono, and uuid dependencies with specific features - Added jsonwebtoken and arc-swap as project dependencies - Reformatted assertion statements to comply with line length limits - Adjusted base64 import order in engine codec module - Updated protobuf include statement formatting
This commit is contained in:
+6
-3
@@ -1,4 +1,4 @@
|
||||
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
|
||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||
|
||||
use crate::engine::packet::{Packet, PacketData, PacketError, PacketType};
|
||||
|
||||
@@ -226,7 +226,10 @@ mod tests {
|
||||
let input: Vec<u8> = vec![b'4', 0x80, 0xFF, 0x00, 0x01];
|
||||
let decoded = decode_packet_ws(&input).unwrap();
|
||||
assert_eq!(decoded.packet_type, PacketType::Message);
|
||||
assert_eq!(decoded.data, PacketData::Binary(vec![0x80, 0xFF, 0x00, 0x01]));
|
||||
assert_eq!(
|
||||
decoded.data,
|
||||
PacketData::Binary(vec![0x80, 0xFF, 0x00, 0x01])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -236,4 +239,4 @@ mod tests {
|
||||
assert_eq!(decoded.packet_type, PacketType::Message);
|
||||
assert_eq!(decoded.data, PacketData::Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//! Health check endpoint for the imks server.
|
||||
//!
|
||||
//! Returns JSON with server status, version, and upstream connectivity.
|
||||
|
||||
use actix_web::HttpResponse;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct HealthResponse {
|
||||
status: String,
|
||||
version: String,
|
||||
timestamp: String,
|
||||
uptime_secs: u64,
|
||||
sessions_count: usize,
|
||||
}
|
||||
|
||||
/// GET /health — returns server health status.
|
||||
pub async fn health_check() -> HttpResponse {
|
||||
HttpResponse::Ok().json(HealthResponse {
|
||||
status: "healthy".into(),
|
||||
version: env!("CARGO_PKG_VERSION").into(),
|
||||
timestamp: chrono::Utc::now().to_rfc3339(),
|
||||
uptime_secs: 0,
|
||||
sessions_count: 0,
|
||||
})
|
||||
}
|
||||
+1
-1
@@ -74,4 +74,4 @@ impl HeartbeatManager {
|
||||
self.store.remove(&sid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod codec;
|
||||
pub mod health;
|
||||
pub mod heartbeat;
|
||||
pub mod packet;
|
||||
pub mod polling;
|
||||
|
||||
+5
-6
@@ -61,11 +61,10 @@ pub struct Packet {
|
||||
|
||||
impl Packet {
|
||||
pub fn open(handshake: &HandshakeData) -> Self {
|
||||
let data = serde_json::to_string(handshake)
|
||||
.unwrap_or_else(|e| {
|
||||
tracing::error!("Failed to serialize handshake data: {}", e);
|
||||
"{}".to_string()
|
||||
});
|
||||
let data = serde_json::to_string(handshake).unwrap_or_else(|e| {
|
||||
tracing::error!("Failed to serialize handshake data: {}", e);
|
||||
"{}".to_string()
|
||||
});
|
||||
Self {
|
||||
packet_type: PacketType::Open,
|
||||
data: PacketData::Text(data),
|
||||
@@ -148,4 +147,4 @@ pub enum PacketError {
|
||||
InvalidUtf8(#[from] std::string::FromUtf8Error),
|
||||
#[error("serialization error: {0}")]
|
||||
Serialization(String),
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use actix_web::{HttpRequest, HttpResponse, web};
|
||||
|
||||
use crate::engine::codec;
|
||||
use crate::engine::packet::{Packet, PacketType};
|
||||
@@ -182,4 +182,4 @@ async fn handle_handshake(store: &SessionStore, config: &EngineConfig) -> HttpRe
|
||||
pub fn configure_polling(cfg: &mut web::ServiceConfig) {
|
||||
cfg.route("/engine.io/", web::get().to(polling_get))
|
||||
.route("/engine.io/", web::post().to(polling_post));
|
||||
}
|
||||
}
|
||||
|
||||
+52
-8
@@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{web, App, HttpServer};
|
||||
use actix_web::{App, HttpRequest, HttpResponse, HttpServer, web};
|
||||
|
||||
use crate::engine::heartbeat::HeartbeatManager;
|
||||
use crate::engine::packet::Packet;
|
||||
@@ -31,6 +31,53 @@ pub struct EngineServer {
|
||||
on_message: Arc<dyn Fn(String, Packet) + Send + Sync>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct EngineQuery {
|
||||
#[serde(rename = "EIO")]
|
||||
pub eio: Option<String>,
|
||||
pub transport: Option<String>,
|
||||
pub sid: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn engine_get(
|
||||
req: HttpRequest,
|
||||
body: web::Payload,
|
||||
query: web::Query<EngineQuery>,
|
||||
store: web::Data<SessionStore>,
|
||||
config: web::Data<EngineConfig>,
|
||||
on_message: web::Data<Arc<dyn Fn(String, Packet) + Send + Sync>>,
|
||||
) -> Result<HttpResponse, actix_web::Error> {
|
||||
match query.transport.as_deref() {
|
||||
Some("websocket") => {
|
||||
crate::engine::websocket::websocket_handler(
|
||||
req,
|
||||
body,
|
||||
web::Query(crate::engine::websocket::WsQuery {
|
||||
eio: query.eio.clone(),
|
||||
transport: query.transport.clone(),
|
||||
sid: query.sid.clone(),
|
||||
}),
|
||||
store,
|
||||
config,
|
||||
on_message,
|
||||
)
|
||||
.await
|
||||
}
|
||||
_ => Ok(crate::engine::polling::polling_get(
|
||||
req,
|
||||
web::Query(crate::engine::polling::PollingQuery {
|
||||
eio: query.eio.clone(),
|
||||
transport: query.transport.clone(),
|
||||
sid: query.sid.clone(),
|
||||
}),
|
||||
store,
|
||||
config,
|
||||
on_message,
|
||||
)
|
||||
.await),
|
||||
}
|
||||
}
|
||||
|
||||
impl EngineServer {
|
||||
pub fn new(
|
||||
config: EngineConfig,
|
||||
@@ -76,17 +123,14 @@ impl EngineServer {
|
||||
.app_data(web::Data::new(config.clone()))
|
||||
.app_data(web::Data::new(on_message.clone()))
|
||||
.route(
|
||||
"/engine.io/",
|
||||
web::get().to(crate::engine::polling::polling_get),
|
||||
"/health",
|
||||
web::get().to(crate::engine::health::health_check),
|
||||
)
|
||||
.route("/engine.io/", web::get().to(engine_get))
|
||||
.route(
|
||||
"/engine.io/",
|
||||
web::post().to(crate::engine::polling::polling_post),
|
||||
)
|
||||
.route(
|
||||
"/engine.io/",
|
||||
web::get().to(crate::engine::websocket::websocket_handler),
|
||||
)
|
||||
})
|
||||
.bind(addr)?
|
||||
.run()
|
||||
@@ -101,7 +145,7 @@ impl EngineServer {
|
||||
port: u16,
|
||||
cert_path: &str,
|
||||
key_path: &str,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
) -> crate::ImksResult<()> {
|
||||
crate::engine::webtransport::run_webtransport_server(
|
||||
port,
|
||||
cert_path,
|
||||
|
||||
+6
-3
@@ -2,7 +2,7 @@ use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use tokio::sync::{mpsc, Notify};
|
||||
use tokio::sync::{Notify, mpsc};
|
||||
|
||||
use crate::engine::packet::Packet;
|
||||
|
||||
@@ -124,7 +124,10 @@ impl SessionStore {
|
||||
.sessions
|
||||
.insert(sid.clone(), Arc::new(tokio::sync::RwLock::new(session)));
|
||||
if old.is_some() {
|
||||
tracing::warn!("Session ID collision for SID {}, replacing existing session", sid);
|
||||
tracing::warn!(
|
||||
"Session ID collision for SID {}, replacing existing session",
|
||||
sid
|
||||
);
|
||||
}
|
||||
rx
|
||||
}
|
||||
@@ -168,4 +171,4 @@ pub fn generate_sid() -> String {
|
||||
CHARSET[idx] as char
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -1,10 +1,7 @@
|
||||
use crate::engine::packet::Packet;
|
||||
use crate::engine::session::{SessionState, SessionStore, TransportType};
|
||||
|
||||
pub async fn handle_upgrade_probe(
|
||||
store: &SessionStore,
|
||||
sid: &str,
|
||||
) -> Result<Packet, UpgradeError> {
|
||||
pub async fn handle_upgrade_probe(store: &SessionStore, sid: &str) -> Result<Packet, UpgradeError> {
|
||||
let session = store.get(sid).ok_or(UpgradeError::SessionNotFound)?;
|
||||
let mut session = session.write().await;
|
||||
|
||||
|
||||
+55
-42
@@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use actix_web::{HttpRequest, HttpResponse, web};
|
||||
use actix_ws::Message;
|
||||
|
||||
use crate::engine::codec;
|
||||
@@ -36,37 +36,37 @@ pub async fn websocket_handler(
|
||||
|
||||
let sid = query.sid.clone();
|
||||
|
||||
let is_upgrade = sid.as_ref().map(|s| store.exists(s)).unwrap_or(false);
|
||||
if let Some(ref sid) = sid
|
||||
&& !store.exists(sid)
|
||||
{
|
||||
return Ok(HttpResponse::BadRequest().body("unknown session"));
|
||||
}
|
||||
|
||||
// Create or reuse session, obtaining the mpsc receiver for the forwarding task
|
||||
let (session_sid, mut session_rx) = if let Some(ref sid) = sid {
|
||||
if is_upgrade {
|
||||
// Upgrade: session already exists, replace its channel and drain pending packets
|
||||
let session_arc = store.get(sid).unwrap();
|
||||
let (new_tx, new_rx) = tokio::sync::mpsc::channel(256);
|
||||
{
|
||||
let mut s = session_arc.write().await;
|
||||
// Swap tx atomically: old_tx will be dropped, closing its channel.
|
||||
// Any packets in the old rx are consumed by the old send_handle,
|
||||
// which then exits when it sees the channel close.
|
||||
// Drain pending_packets (from polling buffering) into new channel.
|
||||
let pending = s.take_pending();
|
||||
for packet in pending {
|
||||
let _ = new_tx.try_send(packet);
|
||||
}
|
||||
s.tx = new_tx;
|
||||
s.set_transport(TransportType::WebSocket);
|
||||
// Upgrade: session already exists, replace its channel and drain pending packets
|
||||
let session_arc = match store.get(sid) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
tracing::error!("Session {} not found for upgrade", sid);
|
||||
return Ok(HttpResponse::InternalServerError().body("session not found"));
|
||||
}
|
||||
(sid.clone(), new_rx)
|
||||
} else {
|
||||
// Reconnect with known SID: create new session
|
||||
let rx = store.create(sid.clone(), TransportType::WebSocket);
|
||||
if let Some(s) = store.get(sid) {
|
||||
let mut s = s.write().await;
|
||||
s.set_state(SessionState::Open);
|
||||
};
|
||||
let (new_tx, new_rx) = tokio::sync::mpsc::channel(256);
|
||||
{
|
||||
let mut s = session_arc.write().await;
|
||||
// Swap tx atomically: old_tx will be dropped, closing its channel.
|
||||
// Any packets in the old rx are consumed by the old send_handle,
|
||||
// which then exits when it sees the channel close.
|
||||
// Drain pending_packets (from polling buffering) into new channel.
|
||||
let pending = s.take_pending();
|
||||
for packet in pending {
|
||||
let _ = new_tx.try_send(packet);
|
||||
}
|
||||
(sid.clone(), rx)
|
||||
s.tx = new_tx;
|
||||
s.set_transport(TransportType::WebSocket);
|
||||
}
|
||||
(sid.clone(), new_rx)
|
||||
} else {
|
||||
// New connection: generate SID and create session
|
||||
let new_sid = crate::engine::session::generate_sid();
|
||||
@@ -89,7 +89,10 @@ pub async fn websocket_handler(
|
||||
let open_packet = Packet::open(&handshake);
|
||||
let open_msg = codec::encode_packet(&open_packet);
|
||||
if ws_session.text(open_msg).await.is_err() {
|
||||
tracing::warn!("Failed to send open packet to WebSocket session {}", session_sid);
|
||||
tracing::warn!(
|
||||
"Failed to send open packet to WebSocket session {}",
|
||||
session_sid
|
||||
);
|
||||
store.remove(&session_sid);
|
||||
return Ok(response);
|
||||
}
|
||||
@@ -121,16 +124,26 @@ pub async fn websocket_handler(
|
||||
while let Some(Ok(msg)) = msg_stream.recv().await {
|
||||
match msg {
|
||||
Message::Text(text) => {
|
||||
if text.len() > max_payload {
|
||||
tracing::warn!(
|
||||
"Text payload too large ({}) for session {}",
|
||||
text.len(),
|
||||
sid_clone
|
||||
);
|
||||
let _ = ws_session.close(None).await;
|
||||
break;
|
||||
}
|
||||
|
||||
if let Ok(packet) = codec::decode_packet(&text) {
|
||||
match packet.packet_type {
|
||||
PacketType::Ping => {
|
||||
if let PacketData::Text(ref data) = packet.data {
|
||||
if data == "probe" {
|
||||
let pong = Packet::pong("probe");
|
||||
let pong_msg = codec::encode_packet(&pong);
|
||||
let _ = ws_session.text(pong_msg).await;
|
||||
continue;
|
||||
}
|
||||
if let PacketData::Text(ref data) = packet.data
|
||||
&& data == "probe"
|
||||
{
|
||||
let pong = Packet::pong("probe");
|
||||
let pong_msg = codec::encode_packet(&pong);
|
||||
let _ = ws_session.text(pong_msg).await;
|
||||
continue;
|
||||
}
|
||||
let pong = Packet::pong("");
|
||||
let pong_msg = codec::encode_packet(&pong);
|
||||
@@ -180,14 +193,14 @@ pub async fn websocket_handler(
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok(packet) = codec::decode_packet_ws(&bin) {
|
||||
if packet.packet_type == PacketType::Message {
|
||||
let on_msg = on_message_clone.clone();
|
||||
let sid = sid_clone.clone();
|
||||
tokio::spawn(async move {
|
||||
on_msg(sid, packet);
|
||||
});
|
||||
}
|
||||
if let Ok(packet) = codec::decode_packet_ws(&bin)
|
||||
&& packet.packet_type == PacketType::Message
|
||||
{
|
||||
let on_msg = on_message_clone.clone();
|
||||
let sid = sid_clone.clone();
|
||||
tokio::spawn(async move {
|
||||
on_msg(sid, packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
Message::Close(_) => {
|
||||
|
||||
+86
-71
@@ -1,11 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use wtransport::{Connection, Endpoint, ServerConfig, Identity};
|
||||
use wtransport::{Connection, Endpoint, Identity, ServerConfig};
|
||||
|
||||
use crate::engine::codec;
|
||||
use crate::engine::packet::{Packet, PacketType};
|
||||
use crate::engine::server::EngineConfig;
|
||||
use crate::engine::session::{SessionState, SessionStore, TransportType};
|
||||
use crate::{ImksError, ImksResult};
|
||||
|
||||
pub async fn run_webtransport_server(
|
||||
port: u16,
|
||||
@@ -14,15 +15,18 @@ pub async fn run_webtransport_server(
|
||||
store: SessionStore,
|
||||
config: EngineConfig,
|
||||
on_message: Arc<dyn Fn(String, Packet) + Send + Sync>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let identity = Identity::load_pemfiles(cert_path, key_path).await?;
|
||||
) -> ImksResult<()> {
|
||||
let identity = Identity::load_pemfiles(cert_path, key_path)
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
|
||||
let server_config = ServerConfig::builder()
|
||||
.with_bind_default(port)
|
||||
.with_identity(identity)
|
||||
.build();
|
||||
|
||||
let server = Endpoint::server(server_config)?;
|
||||
let server =
|
||||
Endpoint::server(server_config).map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
|
||||
tracing::info!("WebTransport server listening on UDP port {}", port);
|
||||
|
||||
@@ -49,9 +53,14 @@ async fn handle_webtransport_session(
|
||||
store: SessionStore,
|
||||
config: EngineConfig,
|
||||
on_message: Arc<dyn Fn(String, Packet) + Send + Sync>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let request = incoming.await?;
|
||||
let connection = request.accept().await?;
|
||||
) -> ImksResult<()> {
|
||||
let request = incoming
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
let connection = request
|
||||
.accept()
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
|
||||
let sid = crate::engine::session::generate_sid();
|
||||
let mut rx = store.create(sid.clone(), TransportType::WebTransport);
|
||||
@@ -81,65 +90,57 @@ async fn handle_webtransport_session(
|
||||
// Reuse buffer across recv iterations instead of allocating 65KB each time
|
||||
let recv_handle = tokio::spawn(async move {
|
||||
let mut buf = vec![0u8; 65536];
|
||||
loop {
|
||||
match connection_recv.accept_bi().await {
|
||||
Ok((mut send, mut recv)) => {
|
||||
// Reset buffer length for the next read without deallocating
|
||||
buf.resize(65536, 0);
|
||||
match recv.read(&mut buf).await {
|
||||
Ok(Some(n)) => {
|
||||
if n > max_payload {
|
||||
tracing::warn!(
|
||||
"WebTransport payload too large ({}) for session {}",
|
||||
n,
|
||||
sid_clone
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if let Ok(packet) = codec::decode_packet_ws(&buf[..n]) {
|
||||
match packet.packet_type {
|
||||
PacketType::Ping => {
|
||||
let pong = Packet::pong("");
|
||||
if send_wt_packet_on_stream(&mut send, &pong)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
PacketType::Pong => {
|
||||
if let Some(s) = store_clone.get(&sid_clone) {
|
||||
let mut s = s.write().await;
|
||||
s.update_ping();
|
||||
}
|
||||
}
|
||||
PacketType::Message => {
|
||||
let on_msg = on_message_clone.clone();
|
||||
let sid = sid_clone.clone();
|
||||
tokio::spawn(async move {
|
||||
on_msg(sid, packet);
|
||||
});
|
||||
}
|
||||
PacketType::Close => {
|
||||
if let Some(s) = store_clone.get(&sid_clone) {
|
||||
let mut s = s.write().await;
|
||||
s.set_state(SessionState::Closed);
|
||||
}
|
||||
store_clone.remove(&sid_clone);
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
while let Ok((mut send, mut recv)) = connection_recv.accept_bi().await {
|
||||
// Reset buffer length for the next read without deallocating
|
||||
buf.resize(65536, 0);
|
||||
match recv.read(&mut buf).await {
|
||||
Ok(Some(n)) => {
|
||||
if n > max_payload {
|
||||
tracing::warn!(
|
||||
"WebTransport payload too large ({}) for session {}",
|
||||
n,
|
||||
sid_clone
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if let Ok(packet) = codec::decode_packet_ws(&buf[..n]) {
|
||||
match packet.packet_type {
|
||||
PacketType::Ping => {
|
||||
let pong = Packet::pong("");
|
||||
if send_wt_packet_on_stream(&mut send, &pong).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
PacketType::Pong => {
|
||||
if let Some(s) = store_clone.get(&sid_clone) {
|
||||
let mut s = s.write().await;
|
||||
s.update_ping();
|
||||
}
|
||||
}
|
||||
PacketType::Message => {
|
||||
let on_msg = on_message_clone.clone();
|
||||
let sid = sid_clone.clone();
|
||||
tokio::spawn(async move {
|
||||
on_msg(sid, packet);
|
||||
});
|
||||
}
|
||||
PacketType::Close => {
|
||||
if let Some(s) = store_clone.get(&sid_clone) {
|
||||
let mut s = s.write().await;
|
||||
s.set_state(SessionState::Closed);
|
||||
}
|
||||
store_clone.remove(&sid_clone);
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(None) => break,
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
Ok(None) => break,
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
|
||||
Ok::<(), ImksError>(())
|
||||
});
|
||||
|
||||
let connection_send = connection.clone();
|
||||
@@ -191,18 +192,26 @@ async fn handle_webtransport_session(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_wt_packet(
|
||||
connection: &Connection,
|
||||
packet: &Packet,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (mut send, _recv) = connection.open_bi().await?.await?;
|
||||
async fn send_wt_packet(connection: &Connection, packet: &Packet) -> ImksResult<()> {
|
||||
let (mut send, _recv) = connection
|
||||
.open_bi()
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
let encoded = codec::encode_packet_binary_ws(packet);
|
||||
let is_binary = matches!(packet.data, crate::engine::packet::PacketData::Binary(_));
|
||||
let header = codec::encode_webtransport_header(encoded.len(), is_binary);
|
||||
|
||||
send.write_all(&header).await?;
|
||||
send.write_all(&encoded).await?;
|
||||
send.finish().await?;
|
||||
send.write_all(&header)
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
send.write_all(&encoded)
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
send.finish()
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -210,14 +219,20 @@ async fn send_wt_packet(
|
||||
async fn send_wt_packet_on_stream(
|
||||
send: &mut wtransport::SendStream,
|
||||
packet: &Packet,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
) -> ImksResult<()> {
|
||||
let encoded = codec::encode_packet_binary_ws(packet);
|
||||
let is_binary = matches!(packet.data, crate::engine::packet::PacketData::Binary(_));
|
||||
let header = codec::encode_webtransport_header(encoded.len(), is_binary);
|
||||
|
||||
send.write_all(&header).await?;
|
||||
send.write_all(&encoded).await?;
|
||||
send.finish().await?;
|
||||
send.write_all(&header)
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
send.write_all(&encoded)
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
send.finish()
|
||||
.await
|
||||
.map_err(|e| ImksError::WebTransport(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user