Lifecycle
The WebSocket life cycle begins when the client tries to establish the connection and ends when it is closed definitely.
GOX manages the handshake, connection, disconnection and reconnection. The client and server can register handlers to react to these changes.
socket.When("handshake", func(ctx *gox.Context) bool {
return socket.Handshake.Origin() == "https://example.com"
})
socket.When("connect", func(isReconnect bool) {
socket.Emit("welcome", isReconnect)
})
socket.When("disconnect", func(details gox.WSDisconnectReason) {
log.Printf("Conexión cerrada: %d", details.Code)
})
socket.When("error", func(err gox.GoxSocketError) {
log.Printf("Error WebSocket: %s", err.Message)
}) socket.when("connect", isReconnect => {
console.log("Conectado", { isReconnect })
})
socket.when("disconnect", details => {
console.log("Desconectado", details)
})
socket.when("error", error => {
console.error(error)
}) Both APIs describe the same communication, although each environment receives the information corresponding to its side of the connection.
See Socket to know the API of the server used during these stages. To learn how to create and configure the connection from JavaScript or TypeScript, see Client.
Events
| Event | Server | Client | Description |
|---|---|---|---|
handshake | Yes | No. | Authorizes or rejects the connection before the upgrade. |
connect | Yes | Yes | It indicates that the connection is available. |
disconnect | Yes | Yes | Describe the connection closure. |
error | Yes | Yes | It reports an operating or protocol error. |
handshake only exists on the server because it uses the HTTP context that started the connection.
Other events can be observed from both sides by When() in Go and when() in JavaScript.
Handshake
Handshake is the first stage of the connection.
The server can record the event handshake to authorize or reject the client before completing the upgrade to WebSocket:
socket.When("handshake", func(ctx *gox.Context) bool {
return socket.Handshake.Origin() == "https://example.com"
}) The handler receives the original HTTP context and must return a boolean value:
trueAccept the connection.falseHe rejects the connection.
If the event is not recorded, GOX automatically applies its default validation of the same origin.
The context makes it possible to consult information necessary to make the decision:
socket.When("handshake", func(ctx *gox.Context) bool {
return ctx.Session.Has("userID")
}) During this stage, the socket has not yet been registered and socket.ID() return an empty string.
If the handshake is rejected, the server responds with 403 Forbidden and does not run connectThe client first gets a mistake. HANDSHAKE_FAILED and then the event disconnectThe connection remains closed and GOX does not try to reconnect it automatically.
socket.when("error", error => {
if (error.code === "HANDSHAKE_FAILED") {
console.log("El handshake fue rechazado o no pudo completarse")
}
}) The browser does not allow for a certain distinction between deliberate rejection and other problems that prevent the handshake from being completed.
Do not keep the context received after completion of the handler. To subsequently access the initial request data, use socket.Handshake.
Connect
The event connect is run when the connection is available.
Servidor:
socket.When("connect", func(isReconnect bool) {
socket.Emit("welcome", "George", isReconnect)
}) Cliente:
socket.when("connect", isReconnect => {
console.log("Conectado", { isReconnect })
}) The argument isReconnect indicates how the connection was established:
| Value | Description |
|---|---|
false | It's the client's initial connection. |
true | The connection was established by a reconnection. |
From connect, the server can already use socket.ID(), issue events, consult other sockets and work with groups or channels.
socket.When("connect", func(isReconnect bool) {
log.Printf("Socket conectado: %s", socket.ID())
}) The client can use isReconnect to avoid repeating operations that only correspond to the initial connection:
socket.when("connect", isReconnect => {
if (!isReconnect) {
initializeApplication()
}
}) Recording connect replace the previous handler of that event.
Disconnect
The event disconnect It runs when the connection ends.
Servidor:
socket.When("disconnect", func(details gox.WSDisconnectReason) {
log.Printf("Socket cerrado: %d", details.Code)
}) Cliente:
socket.when("disconnect", details => {
console.log(details.code)
console.log(details.reason)
console.log(details.willReconnect)
}) The information received describes the cause of the closure:
| Go | JavaScript | Description |
|---|---|---|
Code | code | Code of closure. |
Reason | reason | Description associated with the code. |
Clean | clean | It indicates whether the transport correctly completed the closure. |
Initiator | initiator | It indicates who started or caused the closure. |
WillReconnect | willReconnect | It indicates whether the client will try to reconnect. |
initiator may contain:
| Value | Description |
|---|---|
"client" | The client requested the disconnection. |
"server" | The server closed the connection. |
"unknown" | It was not possible to determine the initiator, usually due to an interruption of transport. |
The server can close the connection by Disconnect():
socket.Disconnect(gox.WSClosePermanent) The client can close it by disconnect():
import { Socket, WSCloseCode } from "@gox/websocket"
const socket = new Socket()
socket.disconnect(WSCloseCode.NORMAL) A direct call to socket.disconnect() disable the automatic reconnection for that socket.
Reconnection
The automatic reconnection is default-active in the client.
GOX tries to recover the connection when the closing code represents a recoverable interruption. The wait gradually increases between attempts to reach the set limit.
const socket = new Socket({
reconnect: {
enabled: true,
delay: 1000,
maxDelay: 30000,
attempts: 5
}
}) | Option | Default value | Description |
|---|---|---|
enabled | true | It activates the automatic reconnection. |
delay | 1000 | Initial wait in milliseconds. |
maxDelay | 30000 | Wait a minute between attempts. |
attempts | 0 | Maximum number of attempts. 0 It doesn't set a limit. |
It can also be completely deactivated:
const socket = new Socket({
reconnect: false
}) When a reconnection occurs:
- The client retains the same instance of
Socket. - The handlers registered by
when()andon()are preserved. - The existing channels try to join again.
- The server creates a new instance of
gox.Socket. - The new connection receives another identifier.
- The session can be held if it remains valid.
connectreceivesisReconnectwith the valuetrue.
The previous connection is over. For this reason, the new socket of the server does not retain its groups or the state stored only in the previous instance.
To keep information between connections, use the session or other persistent storage. Sessions to know their storage, persistence and life cycle.
Close codes
GOX provides shared codes between Go and JavaScript.
| Go | JavaScript | Code | Reconecta |
|---|---|---|---|
WSCloseNormal | WSCloseCode.NORMAL | 1000 | No. |
WSCloseGoingAway | WSCloseCode.GOING_AWAY | 1001 | Yes |
WSCloseProtocol | WSCloseCode.PROTOCOL | 1002 | No. |
WSCloseUnsupported | WSCloseCode.UNSUPPORTED | 1003 | No. |
WSCloseAbnormal | WSCloseCode.ABNORMAL | 1006 | Yes |
WSCloseInvalidData | WSCloseCode.INVALID_DATA | 1007 | No. |
WSClosePolicy | WSCloseCode.POLICY | 1008 | No. |
WSCloseMessageLarge | WSCloseCode.MESSAGE_LARGE | 1009 | No. |
WSCloseInternal | WSCloseCode.INTERNAL | 1011 | Yes |
WSCloseRestart | WSCloseCode.RESTART | 1012 | Yes |
WSCloseTryLater | WSCloseCode.TRY_LATER | 1013 | Yes |
WSClosePermanent | WSCloseCode.PERMANENT | 4000 | No. |
WSCloseReconnect | WSCloseCode.RECONNECT | 4001 | Yes |
WSCloseSessionExpired | WSCloseCode.SESSION_EXPIRED | 4002 | No. |
WSCloseSessionDestroyed | WSCloseCode.SESSION_DESTROYED | 4003 | No. |
WSCloseDefault and WSCloseCode.DEFAULT They are equivalent to normal closure.
Use WSCloseReconnect when the server needs to close the current connection and ask the client to establish a new one:
socket.Disconnect(gox.WSCloseReconnect) Use WSClosePermanent when the connection must not be automatically recovered:
socket.Disconnect(gox.WSClosePermanent) The codes reserved for sessions are normally administered by GOX when a session expires or is destroyed.
The reconnection also depends on the client's configuration and the number of attempts available. A recoverable code does not guarantee a reconnection if it was disabled or reached its limit.
Error
The event error reports operational problems without assuming that the connection is over.
Servidor:
socket.When("error", func(err gox.GoxSocketError) {
log.Printf("%s: %s", err.Code, err.Message)
}) Cliente:
socket.when("error", error => {
console.error({
code: error.code,
phase: error.phase,
event: error.event,
retryable: error.retryable,
message: error.message
})
}) An error contains the following main information:
| Go | JavaScript | Description |
|---|---|---|
Code | code | Stable error identifier. |
Message | message | Description of the problem. |
Phase | phase | Stage at which it happened. |
Event | event | Related event, when appropriate. |
Retryable | retryable | It indicates whether the operation can be recovered. |
The main phases are:
| Phase | Description |
|---|---|
handshake | Authorization or initial establishment. |
connection | Creation or registration of the connection. |
transport | Reading, writing or interruption of transport. |
handler | Running a handler. |
protocol | Codification, packages or protocol status. |
binding | Linking arguments to the client. |
session | Persistence, activity or expiry of the session. |
The event error and the event disconnect perform different functions:
errordescribes a problem.disconnectconfirms the connection's over.
An error can occur without closing the socket. disconnect or state to determine the status of the connection.
Sequence
An accepted initial connection follows this order:
- The client creates a
Socket. - GOX starts the HTTP handshake.
- The server runs
Index. - The server runs
handshake, if it was registered. - GOX accepts and records the connection.
- The server runs
connect. - The client runs
connect. - The client and the server exchange events.
- The connection is over.
- The client and the server run
disconnect.
If the closure allows to reconnect, the client expects and starts a new attempt. The server creates another socket and events connect receive isReconnect with the value true.
Best practices
- Search the life cycle handlers before starting to exchange events.
- Use
handshaketo authorize the connection before the upgrade. - Do not use
socket.ID()duringIndexorhandshake. - Check.
isReconnectbefore repeating exclusive tasks of the initial connection. - Store the recoverable status in the session or in persistent storage.
- Always handle the event
error. - Use
disconnectto confirm that the connection is over. - Select a closing code that correctly represents the cause.
- Use
WSCloseReconnectonly when the client has to recover the connection. - Use
WSClosePermanentwhere there should be no automatic reconnection. - Do not keep the HTTP context received by
handshake.