Files
job-search/internal/websocket/messages.go
T
bwilliams 465358609a Naming, layout and comments: descriptive full-word names, one item per line in wrapped calls and literals, and doc comments on exported names
Short and single-letter names in application code become full words (tests
keep theirs). Wrapped calls, signatures and composite literals put one item
per line, and one-line function bodies are expanded. Exported names and
groups of constants get doc comments, and comments refer to the renamed
identifiers.
2026-10-15 16:12:56 +01:00

73 lines
2.3 KiB
Go

// Package websocket implements the hub that pushes messages to connected
// clients: WebSocket clients upgraded by Hub.ServeHTTP (the /ws endpoint) and
// plain TCP clients run by Hub.ServeTCP, which send the same messages as
// newline-delimited JSON (see tcp.go). Package tcpserver runs a TCP server
// for those clients.
//
// Every message is a JSON Envelope: a WebSocket text frame, or one line on
// TCP.
//
// Client -> server:
//
// {"type":"ping","id":"1"}
// {"type":"echo","id":"2","payload":{...}}
//
// Server -> client:
//
// {"type":"welcome","payload":{"clientId":"..."}}
// {"type":"pong","id":"1","payload":{"time":"..."}}
// {"type":"echo","id":"2","payload":{...}}
// {"type":"error","id":"3","error":"..."}
// {"type":"item.created","payload":{...}}
//
// Any other type from a client gets an "unknown message type" error. The last
// message is one sent by Hub.Push: its type is the pushed message type.
package websocket
import "encoding/json"
// Envelope is the wire format for every message in both directions.
type Envelope struct {
Type string `json:"type"`
ID string `json:"id,omitempty"`
Payload json.RawMessage `json:"payload,omitempty"`
Error string `json:"error,omitempty"`
}
// Envelope types. TypeEvent, TypeRequest and TypeAck are reserved: nothing
// sends or handles them yet.
const (
// TypeWelcome is sent to a client when it connects, with its client ID.
TypeWelcome = "welcome"
// TypePing asks the server for a TypePong.
TypePing = "ping"
// TypePong answers a TypePing, with the server's time.
TypePong = "pong"
// TypeEcho is sent back to the client with the same ID and payload.
TypeEcho = "echo"
// TypeEvent is reserved for events pushed to clients.
TypeEvent = "event"
// TypeRequest is reserved for requests from clients.
TypeRequest = "request"
// TypeAck is reserved for acknowledging a request.
TypeAck = "ack"
// TypeError reports an error, with the ID of the message it answers.
TypeError = "error"
)
// mustRaw returns value as raw JSON: value itself if it is already
// json.RawMessage, nil if value is nil or can't be marshalled.
func mustRaw(value any) json.RawMessage {
if value == nil {
return nil
}
if raw, ok := value.(json.RawMessage); ok {
return raw
}
encoded, err := json.Marshal(value)
if err != nil {
return nil
}
return encoded
}