pub struct WebsocketFrameEncoder { /* private fields */ }
Expand description
A low-level WebSocket frames decoder.
It lets to prepare frame headers and transform (mask) frame payloads when needed.
It does not validate that you supplied correct amount of payload bytes after headers or that headers make sense.
Example usage:
use std::io::Write;
use tungstenite::{protocol::Role, Message};
use websocket_sans_io::{FrameInfo, Opcode};
fn main() {
let (tunstenite_end, mut sansio_end) = pipe::bipipe();
std::thread::spawn(move || {
let mut frame_encoder = websocket_sans_io::WebsocketFrameEncoder::new();
let mut hello = *b"Hello, world\n";
let header = frame_encoder.start_frame(&FrameInfo {
opcode: Opcode::Text,
payload_length: hello.len() as websocket_sans_io::PayloadLength,
mask: Some(1234u32.to_be_bytes()),
fin: true,
reserved: 0,
});
sansio_end.write_all(&header[..]).unwrap();
frame_encoder.transform_frame_payload(&mut hello[..]);
sansio_end.write_all(&hello[..]).unwrap();
});
let mut tunstenite =
tungstenite::protocol::WebSocket::from_raw_socket(tunstenite_end, Role::Server, None);
let msg = tunstenite.read().unwrap();
assert_eq!(msg, Message::Text("Hello, world\n".to_owned()));
}
Implementations§
Source§impl WebsocketFrameEncoder
impl WebsocketFrameEncoder
Sourcepub const fn new() -> WebsocketFrameEncoder
pub const fn new() -> WebsocketFrameEncoder
Create new instance of WebsocketFrameEncoder
Sourcepub fn start_frame(&mut self, frame_info: &FrameInfo) -> ArrayVec<[u8; 14]>
pub fn start_frame(&mut self, frame_info: &FrameInfo) -> ArrayVec<[u8; 14]>
Serialize given frame header as bytes. You should write all those bytes to the socket before starting to write payload contant (if any).
You can repeat the calls to start_frame
to re-serialize the header of the same frame
if you haven’t yet called transform_frame_payload
for that frame.
It does not validate the frame in any way and can allow you
to do nonsensial things such as starting conversation with Continuation
frame
or getting next frame header when current frame’s payload is not completely written.
Use masked frames when you are client and unmasked frames when you are server.
Writing frame header with nonzero frame_info.payload_length
means you are obligated to
write this number of bytes before writing any new frame.
If you have large or unknown size of a WebSocket message, use frames with fin=false
and
crate::Opcode::Continuation
frames with smaller payload lengths each.
This also allows to interrupt the data transmissing to send a crate::Opcode::Ping
or reply with a crate::Opcode::Pong
.
Sourcepub fn transform_frame_payload(&mut self, data: &mut [u8])
pub fn transform_frame_payload(&mut self, data: &mut [u8])
Prepare this memory chunk to be transfitted to the socket as a part of WebSocket frame payload.
Call this after start_frame
.
Chunks transformed by this method should be written to the socket in the same order as they
are supplied to transform_frame_payload
.
If you do not want to transmit the tranformed chunk or some of its trailing part, you can
rollback the encoder state with WebsocketFrameEncoder::rollback_payload_transform
.
Sourcepub fn rollback_payload_transform(&mut self, n_bytes: usize)
pub fn rollback_payload_transform(&mut self, n_bytes: usize)
Undo transformation of this number of bytes.
Example:
use std::io::Write;
use tungstenite::{protocol::Role, Message};
use websocket_sans_io::{FrameInfo, Opcode};
fn main() {
let (tunstenite_end, mut sansio_end) = pipe::bipipe();
std::thread::spawn(move || {
let mut frame_encoder = websocket_sans_io::WebsocketFrameEncoder::new();
let mut hello = *b"Hello, world\n";
let header = frame_encoder.start_frame(&FrameInfo {
opcode: Opcode::Text,
payload_length: hello.len() as websocket_sans_io::PayloadLength,
mask: Some(1234567890u32.to_be_bytes()),
fin: true,
reserved: 0,
});
sansio_end.write_all(&header[..]).unwrap();
frame_encoder.transform_frame_payload(&mut hello[..]);
// Let's pretend we only can write 7 bytes here, then
// we need to forget the buffer and reconstruct it later.
sansio_end.write_all(&hello[0..7]).unwrap();
frame_encoder.rollback_payload_transform(hello.len() - 7);
#[allow(dropping_copy_types)]
drop(hello);
// Now we returned and want to finish the writing.
let mut hello_remembered = *b"Hello, world\n";
let remaining_part = &mut hello_remembered[7..];
frame_encoder.transform_frame_payload(remaining_part);
sansio_end.write_all(&remaining_part[..]).unwrap();
});
let mut tunstenite =
tungstenite::protocol::WebSocket::from_raw_socket(tunstenite_end, Role::Server, None);
let msg = tunstenite.read().unwrap();
assert_eq!(msg, Message::Text("Hello, world\n".to_owned()));
}
Sourcepub const fn transform_needed(&self) -> bool
pub const fn transform_needed(&self) -> bool
Check if you can skip transform_frame_payload
and just transfer payload as is.
Trait Implementations§
Source§impl Clone for WebsocketFrameEncoder
impl Clone for WebsocketFrameEncoder
Source§fn clone(&self) -> WebsocketFrameEncoder
fn clone(&self) -> WebsocketFrameEncoder
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more