Skip to content

Commit 0bafb31

Browse files
authored
Reduced websocket latency (#73)
* Reduced websocket latency * Windows fix
1 parent a7056a1 commit 0bafb31

File tree

6 files changed

+49
-29
lines changed

6 files changed

+49
-29
lines changed

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
- rust: stable
2525
can-fail: false
2626
- rust: nightly
27-
can-fail: true
27+
can-fail: false
2828
steps:
2929
- name: Checkout Repository
3030
uses: actions/checkout@v1

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## Release 0.12.2
4+
- Reduced *WebSocket* latency.
5+
36
## Release 0.12.1
47
- *WebSocket* now can returns when send correctly a `SendStatus::MaxPacketSizeExceeded` instead of `ResourceNotFound` if the packet size is exceeded.
58
- *UDP* has increases the packet size when send.

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "message-io"
3-
version = "0.12.1"
3+
version = "0.12.2"
44
authors = ["lemunozm <[email protected]>"]
55
edition = "2018"
66
readme = "README.md"

src/adapters/ws.rs

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -110,30 +110,37 @@ impl Remote for RemoteResource {
110110
// "emulates" full duplex for the websocket case locking here and not outside the loop.
111111
let mut state = self.state.lock().expect(OTHER_THREAD_ERR);
112112
match state.deref_mut() {
113-
RemoteState::WebSocket(web_socket) => {
114-
match web_socket.read_message() {
115-
Ok(message) => match message {
116-
Message::Binary(data) => {
117-
// We can not call process_data while the socket is blocked.
118-
// The user could lock it again if sends from the callback.
119-
drop(state);
120-
process_data(&data);
113+
RemoteState::WebSocket(web_socket) => match web_socket.read_message() {
114+
Ok(message) => match message {
115+
Message::Binary(data) => {
116+
// As an optimization.
117+
// Fast check to know if there is more data to avoid call
118+
// WebSocket::read_message() again.
119+
// TODO: investigate why this code doesn't work in windows.
120+
// Seems like windows consume the `WouldBlock` notification
121+
// at peek() when it happens, and the poll never wakes it again.
122+
#[cfg(not(target_os = "windows"))]
123+
let _peek_result = web_socket.get_ref().peek(&mut [0; 0]);
124+
125+
// We can not call process_data while the socket is blocked.
126+
// The user could lock it again if sends from the callback.
127+
drop(state);
128+
process_data(&data);
129+
130+
#[cfg(not(target_os = "windows"))]
131+
if let Err(err) = _peek_result {
132+
break Self::io_error_to_read_status(&err)
121133
}
122-
Message::Close(_) => break ReadStatus::Disconnected,
123-
_ => continue,
124-
},
125-
Err(Error::Io(ref err)) if err.kind() == ErrorKind::WouldBlock => {
126-
break ReadStatus::WaitNextEvent
127-
}
128-
Err(Error::Io(ref err)) if err.kind() == ErrorKind::ConnectionReset => {
129-
break ReadStatus::Disconnected
130-
}
131-
Err(err) => {
132-
log::error!("WS receive error: {}", err);
133-
break ReadStatus::Disconnected // should not happen
134134
}
135+
Message::Close(_) => break ReadStatus::Disconnected,
136+
_ => continue,
137+
},
138+
Err(Error::Io(ref err)) => break Self::io_error_to_read_status(err),
139+
Err(err) => {
140+
log::error!("WS receive error: {}", err);
141+
break ReadStatus::Disconnected // should not happen
135142
}
136-
}
143+
},
137144
RemoteState::Handshake(handshake) => {
138145
let current_handshake = handshake.take().unwrap();
139146
match current_handshake.mid_handshake.handshake() {
@@ -191,6 +198,19 @@ impl RemoteResource {
191198
}
192199
}
193200
}
201+
202+
fn io_error_to_read_status(err: &io::Error) -> ReadStatus {
203+
if err.kind() == io::ErrorKind::WouldBlock {
204+
ReadStatus::WaitNextEvent
205+
}
206+
else if err.kind() == io::ErrorKind::ConnectionReset {
207+
ReadStatus::Disconnected
208+
}
209+
else {
210+
log::error!("WS receive error: {}", err);
211+
ReadStatus::Disconnected // should not happen
212+
}
213+
}
194214
}
195215

196216
pub(crate) struct LocalResource {

tests/integration.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const SMALL_MESSAGE: &'static str = "Integration test message";
1717
const BIG_MESSAGE_SIZE: usize = 1024 * 1024 * 8; // 8MB
1818

1919
lazy_static::lazy_static! {
20-
pub static ref TIMEOUT: Duration = Duration::from_secs(30);
20+
pub static ref TIMEOUT: Duration = Duration::from_secs(60);
2121
}
2222

2323
// Common error messages
@@ -179,10 +179,7 @@ fn start_burst_receiver(
179179

180180
let mut count = 0;
181181
listener.for_each(move |event| match event {
182-
NodeEvent::Signal(_) => std::panic::catch_unwind(|| {
183-
panic!("{}", TIMEOUT_EVENT_RECV_ERR);
184-
})
185-
.unwrap(),
182+
NodeEvent::Signal(_) => panic!("{}", TIMEOUT_EVENT_RECV_ERR),
186183
NodeEvent::Network(net_event) => match net_event {
187184
NetEvent::Message(_, data) => {
188185
let expected_message = format!("{}: {}", SMALL_MESSAGE, count);

0 commit comments

Comments
 (0)