silk.http.websocket_server.
WebSocket messages on the server side, over a channel from an accepted handshake.
When to use#
After withUpgrade of silk.http.websocket_upgrade accepts a handshake, it lends you the channel.
Call withServer with it. In the callback, call readEvent in a loop, and answer with
writeText or writeBinary.
Details#
Each readEvent reads one complete frame and checks it before it returns:
TextandBinarywrite the payload to your buffer. Text is valid UTF-8.Pingis answered with aPongbeforereadEventreturns.PeerClosemeans that the client sent Close. The server answered with Close and closed the channel.
To close from the server, call sendClose, then finishClose to wait for the Close of the
client. Client frames must be masked. Server frames are not masked. The channel is closed when
the callback of withServer ends.
When a client frame breaks a rule, the session fails, and later calls fail with
PreviousFailure. Unless the deadline has passed, the server first sends Close with a code:
1002 for a protocol error, 1003 for fragmentation, 1007 for bad UTF-8, and 1009 for a message
that is too large for the limits or the buffer. With no deadline, it allows that Close one
second.
Errors#
WebSocketError tells the rule, limit, state, or transport error.
Gotchas#
Fragmented messages, extensions, and compression are not supported. A fragmented message fails the session.
If a message is larger than your buffer, the session fails with
BufferTooSmall. Give a buffer ofmaxMessageBytes.
Examples#
Answer one message#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.io.buffered_duplex { BufferedDuplex }
import silk.io.buffered_input { BufferError }
import silk.io.byte_duplex { ByteDuplex }
import silk.collections.bytes { Bytes }
import silk.core.effect { Effect }
import silk.http.body { Limits as BodyLimits }
import silk.http.head { Limits as HeadLimits }
import silk.http.headers { Headers, Limits as ValueLimits }
import silk.http.server {
Connection,
ConnectionHandler,
Limits as ServerLimits,
Request,
ServerError,
withConnection,
withRequest
}
import silk.collections.list { List }
import silk.io.memory_byte_duplex {
MemoryByteDuplex,
MemoryReadEvent,
MemoryWriteAction,
MemoryWriteEvent
}
import silk.system.monotonic_clock { MonotonicClock }
import silk.core.option { Option }
import silk.core.result { Result }
import silk.system.system_clock { Instant, SystemClock }
import silk.num.u64
import silk.num.usize
import silk.http.websocket_server as WebSocketServer {
Event,
Limits as SocketLimits,
ServerWebSocket,
WebSocketError
}
import silk.http.websocket_upgrade {
Decision,
DecisionHandler,
Limits,
Offer,
Outcome,
UpgradeError,
withUpgrade
}
struct FixedClock {}
impl MonotonicClock for FixedClock {
effect fn now(self: &mut Self) -> Instant {
return SystemClock.make(0, 0)
}
effect fn getResolution(self: &mut Self) -> u64 {
return u64.toU64(1)
}
effect fn waitUntil(self: &mut Self, when: Instant) -> () {
drop when
return ()
}
effect fn waitFor(self: &mut Self, duration: u64) -> () {
drop duration
return ()
}
}
fn valueLimits() -> ValueLimits {
return ValueLimits {
maxMethodBytes: 32,
maxTargetBytes: 128,
maxNameBytes: 64,
maxValueBytes: 256,
maxFields: 12,
maxFieldBytes: 512,
maxOwnedBytes: 2048,
}
}
fn serverLimits() -> ServerLimits {
return ServerLimits {
head: HeadLimits {
maxHeadBytes: 1024,
maxStartLineBytes: 256,
maxFieldLineBytes: 256,
maxOwnedBytes: 2048,
values: valueLimits(),
},
body: BodyLimits {
maxWireBytes: 1024,
maxPayloadBytes: 512,
maxChunkBytes: 64,
maxChunks: 8,
maxChunkLineBytes: 64,
maxExtensionBytes: 128,
maxTrailerBytes: 256,
maxTrailerFields: 4,
maxOwnedBytes: 2048,
trailerValues: valueLimits(),
},
values: valueLimits(),
readCapacity: 256,
writeCapacity: 256,
maxRequestsPerConnection: 1,
maxInformationalResponses: 2,
maxDiscardWireBytes: u64.toU64(256),
shutdownDrainBytes: 16,
}
}
// Accepts each handshake, with no subprotocol.
struct AcceptAll {}
impl DecisionHandler<UpgradeError ? &mut MonotonicClock> for AcceptAll {
effect<'call> fn decide<'call, 'head: 'call>(
handler: &'call Self,
offer: &'call Offer<'head>
) -> Decision<'call>
! UpgradeError
? &mut MonotonicClock {
return Decision.Accept {
protocol: Option<string<'call>>.none(),
headers: Option<Headers<'call>>.none(),
extensions: false,
}
}
}
// Reads one text message, answers it, then reads the close of the client.
effect<'call> fn chat<'call, 'channel: 'call, 'transport: 'channel>(
socket: &'call mut ServerWebSocket<'channel, 'transport, MemoryByteDuplex>,
) -> i32
! WebSocketError
? &mut MonotonicClock {
let mut message: [u8; 64] = [0; 64]
match move run WebSocketServer.readEvent(&mut socket.*, &mut message, Option<Instant>.none()) {
Event.Text { count } => {
if count != 2 || message[0] != 72 {
return 1
}
}
_ => {
return 1
}
}
run WebSocketServer.writeText(&mut socket.*, "Hello", Option<Instant>.none())
// `PeerClose` means that the reply Close was sent and the channel is closed.
return match move run WebSocketServer.readEvent(
&mut socket.*,
&mut message,
Option<Instant>.none()
) {
Event.PeerClose { data: _ } => 0
_ => 1
}
}
effect<'call> fn useChannel<'call, 'transport: 'call>(
channel: &'call mut BufferedDuplex<'transport, MemoryByteDuplex>,
) -> i32
! WebSocketError
? &mut MonotonicClock {
return run WebSocketServer.withServer(move channel, SocketLimits.defaults(), chat)
}
effect<'call> fn handleRequest<
'call,
'request: 'call,
'connection: 'request,
'transport: 'connection
>(request: &'call mut Request<'request, 'connection, 'transport, MemoryByteDuplex>) -> i32
! UpgradeError | WebSocketError | ServerError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock {
let outcome = run withUpgrade<i32, UpgradeError, WebSocketError>(
move request,
Limits.defaults(),
Option<Instant>.none(),
AcceptAll {},
useChannel,
)
return match move outcome {
Outcome.Upgraded { value } => value
Outcome.Rejected { status: _ } => 1
}
}
struct Handler {}
impl ConnectionHandler<
MemoryByteDuplex,
i32,
UpgradeError | WebSocketError | ServerError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock
> for Handler {
effect<'call> fn handle<'call, 'connection: 'call, 'transport: 'connection>(
handler: Self,
connection: &'call mut Connection<'connection, 'transport, MemoryByteDuplex>,
) -> i32
! UpgradeError | WebSocketError | ServerError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock where
&'transport mut MemoryByteDuplex provides &ByteDuplex from &mut ByteDuplex
| &mut MonotonicClock {
drop handler
return match run withRequest(&mut connection.*, Option<Instant>.none(), handleRequest) {
Option.Some { value } => value
Option.None => 1
}
}
}
effect fn program() -> i32
! UpgradeError | WebSocketError | ServerError | BufferError | OutOfMemoryError
? &mut Allocator | &mut MonotonicClock {
let handshake = run Bytes.copy(
b"GET /chat HTTP/1.1\r\nHost: example.test\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n"
)
// A masked text frame "Hi" and a masked Close with code 1000. The mask is zero.
let frames: [u8; 16] = [129, 130, 0, 0, 0, 0, 72, 105, 136, 130, 0, 0, 0, 0, 3, 232]
let client = run Bytes.copy(&frames)
let mut reads = List<MemoryReadEvent>.make()
run List.append(
&mut reads,
MemoryReadEvent.Data { readyAt: SystemClock.make(0, 0), bytes: move handshake }
)
run List.append(
&mut reads,
MemoryReadEvent.Data { readyAt: SystemClock.make(0, 0), bytes: move client }
)
let mut writes = List<MemoryWriteEvent>.make()
let mut index = usize.ZERO
while index < 4 {
run List.append(
&mut writes,
MemoryWriteEvent {
readyAt: SystemClock.make(0, 0),
action: MemoryWriteAction.Accept { count: 512 }
},
)
index = index + usize.ONE
}
let mut transport = run MemoryByteDuplex.make(
move reads,
move writes,
512,
64,
Option<i32>.none()
)
let code = run withConnection(&mut transport, serverLimits(), Handler {})
if code != 0 {
return code
}
// The output ends with the text frame "Hello" and the reply Close.
let expected: [u8; 11] = [129, 5, 72, 101, 108, 108, 111, 136, 2, 3, 232]
let sent = transport.outbound()
if sent.length < 11 {
return 1
}
let start = sent.length - 11
let mut at = usize.ZERO
while at < 11 {
if sent[start + at] != expected[at] {
return 1
}
at = at + usize.ONE
}
return 0
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
let mut allocator = Allocator.systemAllocatorProvider()
let mut clock = FixedClock {}
return run Effect.catchAll(program(), failed) |> Effect.provideMut<MonotonicClock>(&mut clock)
|> Effect.provideMut<Allocator>(&mut allocator)
}Import as WebSocketServer with import silk.http.websocket_server as WebSocketServer.
Public declarations: 25.
Limits#
pub struct LimitsThe limits of a session. All are more than zero.
Field maxMessageBytes#
pub maxMessageBytes: usizeThe maximum payload of one Text or Binary message.
Field maxCloseFrames#
pub maxCloseFrames: usizeThe maximum number of client frames that one finishClose call reads.
Field maxCloseBytes#
pub maxCloseBytes: usizeThe maximum number of client bytes, with frame headers, that one finishClose call reads.
Implementation Copy for Limits#
impl Copy for LimitsImplementation Limits#
impl LimitsAssociated function defaults#
pub fn defaults() -> LimitsReturns the default limits: 65536-byte messages, 32 close frames, and 65536 close bytes.
Associated function make#
pub fn make(
maxMessageBytes: usize,
maxCloseFrames: usize,
maxCloseBytes: usize,
) -> Result<Limits, WebSocketError>Returns limits with these values.
Errors#
InvalidLimits if a value is zero.
LimitKind#
pub enum LimitKindThe limit that is not valid.
MessageBytes#
MessageBytesmaxMessageBytes is zero.
CloseFrames#
CloseFramesmaxCloseFrames is zero.
CloseBytes#
CloseBytesmaxCloseBytes is zero.
Arithmetic#
ArithmeticA size does not fit in its type.
Implementation Debug for LimitKind#
impl Debug for LimitKindOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as MessageBytes.
State#
pub enum StateThe state of a session.
Open#
OpenMessages can be read and written.
CloseSent#
CloseSentThe server sent Close, and waits for the Close of the client. finishClose reads until it
arrives.
Closed#
ClosedBoth sides sent Close, and the channel is closed.
Failed#
FailedAn error ended the session. All later frame operations fail.
Implementation Debug for State#
impl Debug for StateOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Open.
Operation#
pub enum OperationThe operation that failed.
ReadEvent#
ReadEventWriteText#
WriteTextWriteBinary#
WriteBinaryWritePing#
WritePingWritePong#
WritePongSendClose#
SendCloseFinishClose#
FinishCloseImplementation Debug for Operation#
impl Debug for OperationOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as ReadEvent.
ProtocolReason#
pub enum ProtocolReasonThe frame rule that failed. The server sends Close with code 1002.
MaskRequired#
MaskRequiredA client frame is not masked.
Rsv#
RsvA reserved bit is set.
ReservedOpcode#
ReservedOpcodeThe opcode is reserved.
NonMinimalLength#
NonMinimalLengthThe length uses more bytes than necessary.
LengthHighBit#
LengthHighBitThe highest bit of a 64-bit length is set.
ControlTooLarge#
ControlTooLargeA control frame has more than 125 bytes.
ControlFragmented#
ControlFragmentedA control frame is not final.
ClosePayloadLength#
ClosePayloadLengthA Close frame has a payload of exactly one byte.
CloseCode#
CloseCodeA Close frame has a code that is not allowed.
Implementation Debug for ProtocolReason#
impl Debug for ProtocolReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as MaskRequired.
Utf8Component#
pub enum Utf8ComponentThe text that is not valid UTF-8.
Text#
TextA Text message.
CloseReason#
CloseReasonThe reason of a Close frame.
Implementation Debug for Utf8Component#
impl Debug for Utf8ComponentOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Text.
CloseDataReason#
pub enum CloseDataReasonThe rule of CloseData.make that failed.
Code#
CodeThe code is not allowed in a server Close.
ReasonTooLarge#
ReasonTooLargeThe reason has more than 123 bytes.
Implementation Debug for CloseDataReason#
impl Debug for CloseDataReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Code.
CloseLimitKind#
pub enum CloseLimitKindThe finishClose limit that was exceeded.
Frames#
FramesmaxCloseFrames.
Bytes#
BytesmaxCloseBytes.
Implementation Debug for CloseLimitKind#
impl Debug for CloseLimitKindOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Frames.
Failure#
pub enum FailureThe kind of the first error of a failed session. Later calls return it in PreviousFailure.
Protocol#
ProtocolA client frame broke a protocol rule.
Fragmentation#
FragmentationThe client sent a fragmented message.
Utf8#
Utf8Text or a Close reason was not valid UTF-8.
MessageLimit#
MessageLimitA message was larger than maxMessageBytes.
BufferCapacity#
BufferCapacityA message was larger than the buffer of the caller.
CloseLimit#
CloseLimitA finishClose limit was exceeded.
Truncated#
TruncatedThe input ended in the middle of a frame.
Transport#
TransportA read, write, or close failed.
Implementation Debug for Failure#
impl Debug for FailureOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Protocol.
WebSocketError#
pub union WebSocketErrorThe error of a WebSocket operation: the rule, limit, state, or transport error.
Details#
When a client frame breaks a rule, the session fails, and later calls fail with
PreviousFailure. Unless the deadline has passed, the server first sends Close with a code:
1002 for a protocol error, 1003 for fragmentation, 1007 for bad UTF-8, and 1009 for a message
that is too large for the limits or the buffer. With no deadline, it allows that Close one
second.
InvalidLimits#
InvalidLimitsA limit is zero.
Field kind#
pub kind: LimitKindThe limit.
InvalidState#
InvalidStateThe operation is not allowed in the current state.
Field operation#
pub operation: OperationThe operation.
Field state#
pub state: StateThe current state.
PreviousFailure#
PreviousFailureAn earlier error ended the session.
Field failure#
pub failure: FailureThe kind of the earlier error.
BufferTooSmall#
BufferTooSmallA valid message does not fit in the buffer. The message is not read, and the session fails.
Field required#
pub required: usizeThe size of the message.
Field capacity#
pub capacity: usizeThe size of the buffer.
MessageTooLarge#
MessageTooLargeA message is larger than maxMessageBytes.
Field length#
pub length: u64The length of the message.
Field allowed#
pub allowed: usizeThe value of maxMessageBytes.
UnsupportedFragmentation#
UnsupportedFragmentationThe client sent a fragmented message, which is not supported.
ProtocolError#
ProtocolErrorA client frame broke a rule of RFC 6455.
Field reason#
pub reason: ProtocolReasonThe rule.
InvalidCloseData#
InvalidCloseDataThe Close data is not valid for a server.
Field reason#
pub reason: CloseDataReasonThe rule.
InvalidUtf8#
InvalidUtf8Text is not valid UTF-8.
Field component#
pub component: Utf8ComponentThe text that failed.
CloseLimitExceeded#
CloseLimitExceededA finishClose limit was exceeded.
Field kind#
pub kind: CloseLimitKindThe limit.
Field allowed#
pub allowed: usizeThe value of the limit.
Truncated#
TruncatedThe input ended in the middle of a frame.
Buffer#
BufferA buffered read, write, or flush failed.
Field operation#
pub operation: OperationThe operation.
Field frameAccepted#
pub frameAccepted: usizeThe bytes of the frame that were accepted before the error.
Field error#
pub error: BufferErrorThe buffer error.
Transport#
TransportClosing the channel failed.
Field operation#
pub operation: OperationThe operation.
Field error#
pub error: ByteIoErrorThe transport error.
Implementation Debug for WebSocketError#
impl Debug for WebSocketErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as InvalidLimits { ... }.
ControlPayload#
pub struct ControlPayloadThe payload of a Ping or Pong, at most 125 bytes.
Implementation ControlPayload#
impl ControlPayloadMethod asSlice#
pub fn asSlice<'payload>(self: &'payload Self) -> &'payload [u8]Returns the payload bytes.
CloseReason#
pub struct CloseReasonThe reason of a Close frame: valid UTF-8, at most 123 bytes.
Implementation CloseReason#
impl CloseReasonMethod asSlice#
pub fn asSlice<'reason>(self: &'reason Self) -> &'reason [u8]Returns the reason bytes.
CloseData#
pub struct CloseDataThe code and reason of a server Close frame. Make it with CloseData.make.
Implementation CloseData#
impl CloseDataAssociated function make#
pub fn make(code: u16, reason: &[u8]) -> Result<CloseData, WebSocketError>Returns Close data with code and a copy of reason.
Errors#
InvalidCloseDatawithCodeifcodeis not allowed. Allowed codes are 1000 through 1003, 1007 through 1014 except 1010, and 3000 through 4999.InvalidCloseDatawithReasonTooLargeifreasonhas more than 123 bytes.InvalidUtf8ifreasonis not valid UTF-8.
Method code#
pub fn code(self: &Self) -> u16Returns the code.
Method reason#
pub fn reason<'data>(self: &'data Self) -> &'data CloseReasonReturns the reason.
PeerCloseData#
pub union PeerCloseDataThe code and reason in the Close of the client.
Absent#
AbsentThe Close had no payload.
Present#
PresentThe Close had a code and a reason.
Field code#
pub code: u16The code.
Field reason#
pub reason: CloseReasonThe reason. It can be empty.
Event#
pub union EventA frame from the client, from readEvent.
Text#
TextA Text message. The first count bytes of the buffer hold it, and they are valid UTF-8.
Field count#
pub count: usizeThe length of the message.
Binary#
BinaryA Binary message. The first count bytes of the buffer hold it.
Field count#
pub count: usizeThe length of the message.
Ping#
PingA Ping. The Pong answer was already sent.
Field payload#
pub payload: ControlPayloadThe payload.
Pong#
PongA Pong.
Field payload#
pub payload: ControlPayloadThe payload.
PeerClose#
PeerCloseThe client sent Close. The server answered with Close, and the channel is closed.
Field data#
pub data: PeerCloseDataThe code and reason of the client.
ServerWebSocket#
pub struct ServerWebSocket<'channel, 'transport, P>A WebSocket session. withServer lends it to a callback, and it cannot escape the callback.
state#
pub fn state<'channel, 'transport, P>(
socket: &ServerWebSocket<'channel, 'transport, P>,
) -> StateReturns the state of the session. It does no I/O.
readEvent#
pub effect fn readEvent<'channel, 'transport, P>(
socket: &mut ServerWebSocket<'channel, 'transport, P>,
output: &mut [u8],
deadline: Option<Instant>,
) -> Event
! WebSocketError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex,
&'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockReads one frame from the client, and returns it as an Event.
Details#
Text and Binary payloads are written to the start of output. If the call fails after it wrote
part of output, those bytes are not valid. A Ping is answered with a Pong before the call
returns. A Close is answered with a Close, and the channel is closed.
Errors#
BufferTooSmallif a message does not fit inoutput. The message is not read.MessageTooLarge,ProtocolError,UnsupportedFragmentation, orInvalidUtf8for a bad frame.InvalidStateif the session is not open. All of these fail the session.
writeText#
pub effect fn writeText<'message, 'channel, 'transport, P>(
socket: &mut ServerWebSocket<'channel, 'transport, P>,
message: string<'message>,
deadline: Option<Instant>,
) -> ()
! WebSocketError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex,
&'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends message as one Text frame, and flushes it.
writeBinary#
pub effect fn writeBinary<'message, 'channel, 'transport, P>(
socket: &mut ServerWebSocket<'channel, 'transport, P>,
message: &'message [u8],
deadline: Option<Instant>,
) -> ()
! WebSocketError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex,
&'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends message as one Binary frame, and flushes it.
writePing#
pub effect fn writePing<'message, 'channel, 'transport, P>(
socket: &mut ServerWebSocket<'channel, 'transport, P>,
message: &'message [u8],
deadline: Option<Instant>,
) -> ()
! WebSocketError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex,
&'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends a Ping with message, and flushes it. message has at most 125 bytes.
writePong#
pub effect fn writePong<'message, 'channel, 'transport, P>(
socket: &mut ServerWebSocket<'channel, 'transport, P>,
message: &'message [u8],
deadline: Option<Instant>,
) -> ()
! WebSocketError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex,
&'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends a Pong with message, and flushes it. message has at most 125 bytes.
sendClose#
pub effect fn sendClose<'close, 'channel, 'transport, P>(
socket: &mut ServerWebSocket<'channel, 'transport, P>,
data: Option<&'close CloseData>,
deadline: Option<Instant>,
) -> ()
! WebSocketError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex,
&'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockSends a Close frame, and flushes it. The state becomes CloseSent.
Details#
data gives the code and reason. With None, the Close has no payload. If the state is already
CloseSent or Closed, it does nothing.
finishClose#
pub effect fn finishClose<'channel, 'transport, P>(
socket: &mut ServerWebSocket<'channel, 'transport, P>,
deadline: Instant,
) -> ()
! WebSocketError
? &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex,
&'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClockReads frames from the client until its Close arrives, then closes the channel.
Details#
Call it after sendClose. Data frames are checked and dropped. A Ping is still answered.
deadline applies to all reads and writes. The reads are limited by maxCloseFrames and
maxCloseBytes, with frame headers.
Errors#
InvalidStateif the state isOpen.CloseLimitExceededif a limit is reached before the Close of the client.
withServer#
pub effect fn withServer<
'callback,
'channel,
'transport: 'channel,
A,
E,
?R,
P,
>(
channel: &'channel mut BufferedDuplex<'transport, P>,
limits: Limits,
use: for<'call, 'channelView: 'call, 'transportView: 'channelView> once fn<'callback>(
&'call mut ServerWebSocket<'channelView, 'transportView, P>,
) -> once Effect<'call; A ! E ? R>,
) -> A
! E | WebSocketError
? R | &mut MonotonicClock
where &'transport mut P provides &ByteDuplex from &mut ByteDuplex,
&'transport mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock,
R in Without<R, ByteDuplex>Starts a WebSocket session on channel, and lends it to use.
When to use#
After withUpgrade of silk.http.websocket_upgrade accepts a handshake, it lends you the channel.
Call withServer with it. In the callback, call readEvent in a loop, and answer with
writeText or writeBinary. To close from the server, call sendClose, then
finishClose.
Details#
Client frames must be masked. Server frames are not masked. /// channel comes from
silk.http.websocket_upgrade. The limits are checked before any I/O. The channel is closed when
use returns, fails, or is cancelled.
Errors#
InvalidLimitsif a limit is zero.The error of
use.
Gotchas#
Fragmented messages, extensions, and compression are not supported. A fragmented message fails the session.
Category: HTTP.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.