glomp/frame
Encode and decode STOMP frames yourself, without any sockets. The client
in glomp uses this module, so most users never need it. You can use this
if you are writing your own STOMP transport, or a broker!
Types
A STOMP command.
pub type Command {
Connect
Stomp
Send
Subscribe
Unsubscribe
Ack
Nack
Begin
Commit
Abort
Disconnect
Connected
Message
Receipt
ServerError
}
Constructors
-
Connect -
StompAnother name for CONNECT, added in STOMP 1.2.
-
Send -
Subscribe -
Unsubscribe -
Ack -
Nack -
Begin -
Commit -
Abort -
Disconnect -
Connected -
Message -
Receipt -
ServerErrorThe ERROR command, which a broker sends when something went wrong.
An error from turning bytes into a frame. After any of these errors the decoder cannot find where the next frame starts, so the stream has to be closed.
pub type DecodeError {
UnknownCommand(command: String)
HeadNotUtf8
MalformedHeader(line: String)
UndefinedEscape(sequence: String)
InvalidContentLength(value: String)
MissingTerminator
HeadTooLarge(limit: Int)
BodyTooLarge(limit: Int)
}
Constructors
-
UnknownCommand(command: String)The first line is not a known STOMP command.
-
HeadNotUtf8The command or headers are not UTF-8.
-
MalformedHeader(line: String)A header line is missing its colon or its name.
-
UndefinedEscape(sequence: String)A header uses an escape that STOMP does not define. The valid escapes are
\n,\cand\\, plus\rin 1.2. -
InvalidContentLength(value: String)The
content-lengthheader is not a valid number of bytes. -
MissingTerminatorThe body does not end with a NUL byte.
-
HeadTooLarge(limit: Int) -
BodyTooLarge(limit: Int)
A decoder turns bytes from the network into frames. It holds the bytes that have arrived and how far it got through the next frame.
Create one with decoder. Pass it bytes with feed, then call next
until it returns Incomplete:
let decoder = frame.decoder(frame.default_limits) |> frame.feed(bytes)
case frame.next(decoder) {
Ok(frame.Decoded(frame:, decoder:)) -> use_frame(frame, decoder)
Ok(frame.Incomplete(decoder:)) -> wait_for_more_bytes(decoder)
Error(error) -> close_the_connection(error)
}
Each step returns a new Decoder, so always keep the latest one. After
a DecodeError, the decoder cannot read any more of the stream.
pub opaque type Decoder
A frame, which is one unit of STOMP: a command, some headers and a body.
Its headers are unescaped and kept in the order they were sent.
pub type Frame {
Frame(
command: Command,
headers: List(#(String, String)),
body: BitArray,
)
}
Constructors
-
Frame( command: Command, headers: List(#(String, String)), body: BitArray, )
pub type Limits {
Limits(max_head_bytes: Int, max_body_bytes: Int)
}
Constructors
-
Limits(max_head_bytes: Int, max_body_bytes: Int)
What next gives back. It is either a frame, or a sign that more bytes
are needed.
Both variants carry the updated Decoder. Use it for the next call to
feed or next.
pub type Step {
Decoded(frame: Frame, decoder: Decoder)
Incomplete(decoder: Decoder)
}
Constructors
-
A frame. Call
nextagain to get the one after it. -
Incomplete(decoder: Decoder)The buffer does not hold a whole frame yet. Call
feedwith more bytes.
Values
pub fn command_to_string(command: Command) -> String
Get the command’s name on the transport, such as "SEND".
pub fn decoder(limits: Limits) -> Decoder
Create a decoder that reads STOMP 1.2. Change it with set_version.
pub const default_limits: Limits
The default limits, which allow 64 KiB of headers and a 100 MiB body.
pub fn encode(frame: Frame, version: Version) -> BitArray
Encode a frame.
Headers are escaped for version. CONNECT and CONNECTED headers are
written as they are, because STOMP 1.0 brokers expect that.
Only the headers you give are written. A NUL byte marks the end of a
frame, so a body that contains one needs content-length. The reader
then knows how far to read.
pub fn header(frame: Frame, name: String) -> Result(String, Nil)
Get the first header called name.
pub fn next(decoder: Decoder) -> Result(Step, DecodeError)
Take the next frame from the buffer. It skips heart-beats.