Documentation
¶
Overview ¶
Package engineio implements the Engine.IO v4 protocol codec — the transport framing layer that Socket.IO is built on. It encodes and decodes the small set of Engine.IO packets and the polling "payload" that batches several packets into a single HTTP body. Engine.IO is the lower half of the Node.js Socket.IO stack: it establishes and keeps alive a logical connection over an interchangeable transport (HTTP long-polling first, then an upgrade to WebSocket) and provides ordered, heartbeat-monitored delivery of opaque messages. This package is the Go equivalent of that layer's parser/encoder.
The wire format is deliberately tiny. A string packet is a single ASCII digit type prefix followed by the packet data — for example "4hello" is a MESSAGE ("4") carrying "hello", "2probe" is a PING with data "probe", and "0{...}" is the OPEN handshake carrying JSON. The seven packet types (Open, Close, Ping, Pong, Message, Upgrade, Noop) are modeled by PacketType and its constants. Encode and Decode convert between a Packet and this string form; that string is exactly what travels inside a WebSocket text frame.
Use this package when you need to speak the transport layer directly rather than the higher-level Socket.IO event API: the socketio server uses it to frame outbound messages and to interpret inbound transport packets, and the client package uses it to read the OPEN handshake and answer heartbeats. Most application code never imports engineio directly — it is a building block — but it is exported so alternative transports or tooling can reuse the codec.
For HTTP long-polling, several packets are batched into one response body using EncodePayload/DecodePayload, which join packets with the Engine.IO v4 record separator (ASCII 0x1e). Binary data is handled two ways: over WebSocket a binary MESSAGE rides in a native binary frame (its Binary field is set and Encode falls back to a base64 "b"-prefixed string only when forced into a text context), while in a polling payload a binary packet is always serialized as "b" + standard-base64. NewMessage and NewOpen are convenience constructors for the two packet types callers build most often.
The codec is pure and stateless: functions do not retain the byte slices they return, hold no locks, and perform no I/O, so they are safe to call concurrently. Decode and DecodePayload validate their input and return ErrEmptyPacket or a descriptive error for malformed data rather than panicking. This is a focused implementation of Engine.IO v4 (Protocol == 4) covering exactly what Socket.IO v5 needs; it is not a general transport manager and does not itself open sockets, schedule pings, or negotiate upgrades — those responsibilities live in the socketio and client packages.
Example ¶
Example demonstrates the Engine.IO codec end to end. It first builds a MESSAGE packet with NewMessage and renders it to the wire form with Encode, showing the single-digit type prefix ("4") in front of the data. It then parses a wire string back into a Packet with Decode and prints the decoded type (via PacketType.String) and data. Finally it batches an OPEN handshake packet and a MESSAGE packet into a single HTTP long-polling body with EncodePayload, whose parts are joined by the Engine.IO v4 record separator (shown here as the \x1e escape). The reader should take away that Encode/Decode handle one packet and EncodePayload/DecodePayload handle the batched polling form, and that the wire format is a compact, human-readable string.
package main
import (
"fmt"
"github.com/malcolmston/socketio/engineio"
)
func main() {
// Encode a single MESSAGE packet to its wire form.
fmt.Println(engineio.NewMessage("hello").Encode())
// Decode a wire string back into a Packet.
p, _ := engineio.Decode("4hello")
fmt.Printf("%s %q\n", p.Type, p.Data)
// Batch several packets into one polling payload.
payload := engineio.EncodePayload([]engineio.Packet{
engineio.NewOpen(`{"sid":"abc"}`),
engineio.NewMessage("hi"),
})
fmt.Printf("%q\n", payload)
}
Output: 4hello message "hello" "0{\"sid\":\"abc\"}\x1e4hi"
Index ¶
- Constants
- Variables
- func EncodeCloseFrame(code CloseCode, reason string) []byte
- func EncodePayload(packets []Packet) string
- type CloseCode
- type Packet
- func Decode(s string) (Packet, error)
- func DecodePayload(payload string) ([]Packet, error)
- func NewBinaryMessage(data []byte) Packet
- func NewClose() Packet
- func NewMessage(data string) Packet
- func NewNoop() Packet
- func NewOpen(handshakeJSON string) Packet
- func NewPing(data string) Packet
- func NewPong(data string) Packet
- func NewUpgrade() Packet
- type PacketType
Examples ¶
Constants ¶
const Protocol = 4
Protocol is the Engine.IO protocol revision implemented here.
Variables ¶
var ErrEmptyPacket = errors.New("engineio: empty packet")
ErrEmptyPacket is returned when decoding an empty packet string.
var ErrInvalidCloseFrame = errors.New("engineio: invalid close frame payload")
ErrInvalidCloseFrame indicates a close-frame payload that is neither empty nor a valid two-byte-code (optionally UTF-8 reason) body.
Functions ¶
func EncodeCloseFrame ¶ added in v0.3.0
EncodeCloseFrame builds the payload of a WebSocket close frame: the two-byte big-endian status code followed by the UTF-8 reason. Pass an empty reason for a code-only frame.
func EncodePayload ¶
EncodePayload joins packets into a single polling payload, separated by the record separator.
Types ¶
type CloseCode ¶ added in v0.3.0
type CloseCode uint16
CloseCode is a WebSocket close status code (RFC 6455 §7.4). Engine.IO runs its WebSocket transport over RFC 6455 frames, so a close frame's two-byte status code — and any UTF-8 reason that follows it — is the signal that carries why a transport shut down. These helpers encode and decode that payload without pulling in a third-party WebSocket library.
const ( // CloseNormalClosure (1000) indicates a normal closure: the purpose for // which the connection was established has been fulfilled. CloseNormalClosure CloseCode = 1000 // CloseGoingAway (1001) indicates an endpoint is going away, e.g. a server // shutting down or a browser navigating away from a page. CloseGoingAway CloseCode = 1001 // CloseProtocolError (1002) indicates termination due to a protocol error. CloseProtocolError CloseCode = 1002 // CloseUnsupportedData (1003) indicates receipt of a data type the endpoint // cannot accept (e.g. binary where only text is understood). CloseUnsupportedData CloseCode = 1003 // CloseNoStatusReceived (1005) is a reserved pseudo-code meaning no status // code was present in the close frame. It must not be sent on the wire. CloseNoStatusReceived CloseCode = 1005 // CloseAbnormalClosure (1006) is a reserved pseudo-code meaning the // connection closed without a close frame. It must not be sent on the wire. CloseAbnormalClosure CloseCode = 1006 // CloseInvalidFramePayloadData (1007) indicates a message contained data // inconsistent with its type (e.g. non-UTF-8 in a text message). CloseInvalidFramePayloadData CloseCode = 1007 // ClosePolicyViolation (1008) indicates a message violated the endpoint's // policy. ClosePolicyViolation CloseCode = 1008 // CloseMessageTooBig (1009) indicates a message was too big to process — // the code Engine.IO uses when maxHttpBufferSize is exceeded. CloseMessageTooBig CloseCode = 1009 // CloseMandatoryExtension (1010) indicates the client expected the server // to negotiate an extension that it did not. CloseMandatoryExtension CloseCode = 1010 // CloseInternalServerErr (1011) indicates the server hit an unexpected // condition that prevented it from fulfilling the request. CloseInternalServerErr CloseCode = 1011 // CloseServiceRestart (1012) indicates the server is restarting. CloseServiceRestart CloseCode = 1012 // CloseTryAgainLater (1013) indicates the server is overloaded and the // client should retry after a delay. CloseTryAgainLater CloseCode = 1013 // CloseTLSHandshake (1015) is a reserved pseudo-code meaning the TLS // handshake failed. It must not be sent on the wire. CloseTLSHandshake CloseCode = 1015 )
RFC 6455 §7.4.1 registered close codes, plus the pseudo-codes reserved for applications that never appear on the wire.
func DecodeCloseFrame ¶ added in v0.3.0
DecodeCloseFrame parses a WebSocket close-frame payload into its status code and reason. An empty payload decodes to CloseNoStatusReceived with an empty reason (per RFC 6455, a close frame may omit the status code). A one-byte payload is invalid and returns ErrInvalidCloseFrame.
type Packet ¶
type Packet struct {
// Type is the Engine.IO packet type (Open, Message, Ping, ...).
Type PacketType
// Data is the textual payload for string packets.
Data string
// Binary holds raw bytes for binary packets; when non-nil the packet is
// encoded with a "b" prefix + base64 in polling payloads.
Binary []byte
}
Packet is a single Engine.IO packet.
func DecodePayload ¶
DecodePayload splits a polling payload into its constituent packets.
func NewBinaryMessage ¶ added in v0.3.0
NewBinaryMessage builds a MESSAGE packet carrying raw binary data. In a polling payload it is serialized as "b" + base64; over WebSocket it rides in a native binary frame.
func NewClose ¶ added in v0.3.0
func NewClose() Packet
NewClose builds a CLOSE packet, which requests that the transport be closed.
func NewMessage ¶
NewMessage builds a MESSAGE packet with string data.
func NewNoop ¶ added in v0.3.0
func NewNoop() Packet
NewNoop builds a NOOP packet, which does nothing and is used to cleanly terminate a pending long-polling request when the transport upgrades.
func NewPing ¶ added in v0.3.0
NewPing builds a PING packet. Engine.IO v4 servers send PING with an empty payload for the heartbeat; the "probe" data ("2probe") is used during a transport upgrade.
func NewPong ¶ added in v0.3.0
NewPong builds a PONG packet answering a PING, echoing its data (an empty string for a heartbeat pong, "probe" for the upgrade handshake).
func NewUpgrade ¶ added in v0.3.0
func NewUpgrade() Packet
NewUpgrade builds an UPGRADE packet, sent by the client to complete a polling-to-WebSocket transport upgrade.
type PacketType ¶
type PacketType byte
PacketType identifies an Engine.IO packet.
const ( // Open is sent by the server on connection with the handshake data. Open PacketType = iota // Close requests the transport be closed. Close // Ping is part of the heartbeat (server -> client in EIO4). Ping // Pong answers a Ping. Pong // Message carries an application payload (a Socket.IO packet). Message // Upgrade signals a transport upgrade (polling -> websocket). Upgrade // Noop does nothing; used to cleanly terminate a polling request. Noop )
func (PacketType) String ¶
func (t PacketType) String() string
String returns the lowercase Engine.IO name of the packet type (e.g. "message", "ping"), or "unknown" for an unrecognized value.