websocket

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 1, 2019 License: BSD-3-Clause Imports: 21 Imported by: 4

Documentation

Overview

Package websocket provide the websocket library for server and client. [1][2]

The websocket server is implemented with epoll [3], which means it's only run on Linux.

Constraints

Routing is handled by proxy layer (e.g. HAProxy).

References

[1] https://tools.ietf.org/html/rfc6455

[2] https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers

[3] http://man7.org/linux/man-pages/man7/epoll.7.html

Index

Constants

View Source
const (
	ConnStateClosed ConnState = 0
	ConnStateOpen             = 1 << iota
	ConnStateConnected
	ConnStateError
)

List of socket connection status.

View Source
const (
	OpCodeCont  = 0x0
	OpCodeText  = 0x1
	OpCodeBin   = 0x2
	OpCodeClose = 0x8
	OpCodePing  = 0x9
	OpCodePong  = 0xA
)

List of valid operation code in frame.

View Source
const (
	FrameSmallPayload  = 125
	FrameMediumPayload = 126
	FrameLargePayload  = 127
)

List of frame length.

View Source
const (
	FrameIsFinished = 0x80
	FrameIsMasked   = 0x80
)

List of frame FIN and MASK values.

Variables

View Source
var (
	// StatusNormal (1000) indicates a normal closure, meaning that the
	// purpose for which the connection was established has been
	// fulfilled.
	StatusNormal = []byte{0x03, 0xE8} //nolint: gochecknoglobals

	// StatusGone (1001) indicates that an endpoint is "going away", such
	// as a server going down or a browser having navigated away from a
	// page.
	StatusGone = []byte{0x03, 0xE9} //nolint: gochecknoglobals

	// StatusBadRequest (1002) indicates that an endpoint is terminating
	// the connection due to a protocol error.
	StatusBadRequest = []byte{0x03, 0xEA} //nolint: gochecknoglobals

	// StatusUnsupportedType (1003) indicates that an endpoint is
	// terminating the connection because it has received a type of data
	// it cannot accept (e.g., an endpoint that understands only text data
	// MAY send this if it receives a binary message).
	StatusUnsupportedType = []byte{0x03, 0xEB} //nolint: gochecknoglobals

	// StatusInvalidData (1007) indicates that an endpoint is terminating
	// the connection because it has received data within a message that
	// was not consistent with the type of the message (e.g., non-UTF-8
	// [RFC3629] data within a text message).
	StatusInvalidData = []byte{0x03, 0xEF} //nolint: gochecknoglobals

	// StatusForbidden (1008) indicates that an endpoint is terminating
	// the connection because it has received a message that violates its
	// policy.  This is a generic status code that can be returned when
	// there is no other more suitable status code (e.g., 1003 or 1009) or
	// if there is a need to hide specific details about the policy.
	StatusForbidden = []byte{0x03, 0xF0} //nolint: gochecknoglobals

	// StatusRequestEntityTooLarge (1009) indicates that an endpoint is
	// terminating the connection because it has received a message that
	// is too big for it to process.
	StatusRequestEntityTooLarge = []byte{0x03, 0xF1} //nolint: gochecknoglobals

	// StatusBadGateway (1010) indicates that an endpoint (client) is
	// terminating the connection because it has expected the server to
	// negotiate one or more extension, but the server didn't return them
	// in the response message of the WebSocket handshake.  The list of
	// extensions that are needed SHOULD appear in the /reason/ part of
	// the Close frame.  Note that this status code is not used by the
	// server, because it can fail the WebSocket handshake instead.
	StatusBadGateway = []byte{0x03, 0xF2} //nolint: gochecknoglobals

	// StatusInternalError or 1011 indicates that a server is terminating
	// the connection because it encountered an unexpected condition that
	// prevented it from fulfilling the request.
	StatusInternalError = []byte{0x03, 0xF3} //nolint: gochecknoglobals
)

List of close code in network byte order. The name of status is mimicking the "net/http" status code.

Endpoints MAY use the following pre-defined status codes when sending a Close frame.

Status code 1004-1006, and 1015 is reserved and MUST NOT be used on Close payload.

See RFC6455 7.4.1-P45 for more information.

View Source
var (
	ControlFrameClose         = []byte{FrameIsFinished | OpCodeClose, 0x00} //nolint: gochecknoglobals
	ControlFrameCloseWithCode = []byte{FrameIsFinished | OpCodeClose, 0x02} //nolint: gochecknoglobals
	ControlFramePing          = []byte{FrameIsFinished | OpCodePing, 0x00}  //nolint: gochecknoglobals
	ControlFramePong          = []byte{FrameIsFinished | OpCodePong, 0x00}  //nolint: gochecknoglobals
)

List of unmasked control frames, MUST used only by server.

View Source
var (
	ErrBadRequest                = errors.New("bad request")
	ErrRequestLength             = errors.New("bad request: length is less than minimum")
	ErrRequestHeaderLength       = errors.New("bad request: header length is less than minimum")
	ErrInvalidHTTPMethod         = errors.New("invalid HTTP method")
	ErrInvalidHTTPVersion        = errors.New("invalid HTTP version")
	ErrInvalidHeaderUpgrade      = errors.New("invalid Upgrade header")
	ErrInvalidHeaderFormat       = errors.New("invalid Header format")
	ErrInvalidHeaderHost         = errors.New("invalid Host header")
	ErrInvalidHeaderWSKey        = errors.New("invalid Sec-Websocket-Key header")
	ErrInvalidHeaderWSVersion    = errors.New("invalid Sec-Websocket-Version header")
	ErrInvalidHeaderWSExtensions = errors.New("invalid Sec-Websocket-Extensions header")
	ErrInvalidHeaderWSProtocol   = errors.New("invalid Sec-Websocket-Protocol header")
	ErrInvalidHeaderConn         = errors.New("invalid Connection header")
	ErrMissingRequiredHeader     = errors.New("missing required headers")
	ErrUnsupportedWSVersion      = errors.New("unsupported Sec-WebSocket-Version")
)

List of errors.

View Source
var (
	ErrRouteInvMethod = errors.New("invalid method")
	ErrRouteInvTarget = errors.New("invalid target")
	ErrRouteDupParam  = errors.New("duplicate parameter on route")
)

List of route error values.

Functions

func GenerateHandshakeAccept

func GenerateHandshakeAccept(key []byte) string

GenerateHandshakeAccept generate server accept key by concatenating key, defined in step 4 in Section 4.2.2, with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this concatenated value to obtain a 20-byte value and base64-encoding (see Section 4 of [RFC4648]) this 20-byte hash.

func GenerateHandshakeKey

func GenerateHandshakeKey() (key []byte)

GenerateHandshakeKey randomly selected 16-byte value that has been base64-encoded (see Section 4 of [RFC4648]).

func GetConnectAddr

func GetConnectAddr(u *url.URL) (addr string)

GetConnectAddr return "host:port" from value in URL. By default, if no port is given, it will set to 80.

func Recv

func Recv(fd int) (packet []byte, err error)

Recv read all content from file descriptor into slice of bytes.

On success it will return buffer from pool. Caller must put the buffer back to the pool.

On fail it will return nil buffer and error.

func Send

func Send(fd int, packet []byte) (err error)

Send the packet through web socket file descriptor `fd`.

func SendFrame

func SendFrame(fd int, f *Frame, randomMask bool) (err error)

SendFrame by packing websocket frame first and write into it.

Types

type Client

type Client struct {
	State ConnState
	URL   *url.URL

	IsTLS bool
	// contains filtered or unexported fields
}

Client for websocket.

func NewClient

func NewClient(endpoint string, headers http.Header) (cl *Client, err error)

NewClient create a new client connection to websocket server with a handshake.

The endpoint use the following format,

  1. WebSocket URIs

    This specification defines two URI schemes, using the ABNF syntax defined in RFC 5234 [RFC5234], and terminology and ABNF productions defined by the URI specification RFC 3986 [RFC3986].

    ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ] wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

    ...

    The port component is OPTIONAL; the default for "ws" is port 80, while the default for "wss" is port 443.

func (*Client) Handshake

func (cl *Client) Handshake(path, origin, proto, ext string, headers http.Header) (err error)

Handshake send the websocket opening handshake.

RFC6455 P17-P19
1.   The handshake MUST be a valid HTTP request as specified by
     [RFC2616].

2.   The method of the request MUST be GET, and the HTTP version MUST
     be at least 1.1.

     For example, if the WebSocket URI is "ws://example.com/chat",
     the first line sent should be "GET /chat HTTP/1.1".

3.   The "Request-URI" part of the request MUST match the /resource
     name/ defined in Section 3 (a relative URI) or be an absolute
     http/https URI that, when parsed, has a /resource name/, /host/,
     and /port/ that match the corresponding ws/wss URI.

4.   The request MUST contain a |Host| header field whose value
     contains /host/ plus optionally ":" followed by /port/ (when not
     using the default port).

5.   The request MUST contain an |Upgrade| header field whose value
     MUST include the "websocket" keyword.

6.   The request MUST contain a |Connection| header field whose value
     MUST include the "Upgrade" token.

7.   The request MUST include a header field with the name
     |Sec-WebSocket-Key|.  The value of this header field MUST be a
     nonce consisting of a randomly selected 16-byte value that has
     been base64-encoded (see Section 4 of [RFC4648]).  The nonce
     MUST be selected randomly for each connection.

     NOTE: As an example, if the randomly selected value was the
     sequence of bytes 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
     0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10, the value of the header
     field would be "AQIDBAUGBwgJCgsMDQ4PEC=="

8.   The request MUST include a header field with the name |Origin|
     [RFC6454] if the request is coming from a browser client.  If
     the connection is from a non-browser client, the request MAY
     include this header field if the semantics of that client match
     the use-case described here for browser clients.  The value of
     this header field is the ASCII serialization of origin of the
     context in which the code establishing the connection is
     running.  See [RFC6454] for the details of how this header field
     value is constructed.

     As an example, if code downloaded from www.example.com attempts
     to establish a connection to ww2.example.com, the value of the
     header field would be "http://www.example.com".

9.   The request MUST include a header field with the name
     |Sec-WebSocket-Version|.  The value of this header field MUST be
     13.

     NOTE: Although draft versions of this document (-09, -10, -11,
     and -12) were posted (they were mostly comprised of editorial
     changes and clarifications and not changes to the wire
     protocol), values 9, 10, 11, and 12 were not used as valid
     values for Sec-WebSocket-Version.  These values were reserved in
     the IANA registry but were not and will not be used.

10.  The request MAY include a header field with the name
     |Sec-WebSocket-Protocol|.  If present, this value indicates one
     or more comma-separated subprotocol the client wishes to speak,
     ordered by preference.  The elements that comprise this value
     MUST be non-empty strings with characters in the range U+0021 to
     U+007E not including separator characters as defined in
     [RFC2616] and MUST all be unique strings.  The ABNF for the
     value of this header field is 1#token, where the definitions of
     constructs and rules are as given in [RFC2616].

11.  The request MAY include a header field with the name
     |Sec-WebSocket-Extensions|.  If present, this value indicates
     the protocol-level extension(s) the client wishes to speak.  The
     interpretation and format of this header field is described in
     Section 9.1.

12.  The request MAY include any other header fields, for example,
     cookies [RFC6265] and/or authentication-related header fields
     such as the |Authorization| header field [RFC2616], which are
     processed according to documents that define them.

func (*Client) Open

func (cl *Client) Open(addr string) (err error)

Open TCP connection to websocket server address in "host:port" format. If client "IsTLS" field is true, the connection is opened with TLS protocol and the remote name MUST have a valid certificate.

func (*Client) ParseURI

func (cl *Client) ParseURI(endpoint string) (serverAddr string, err error)

ParseURI of websocket connection scheme from "endpoint" and set client URL and TLS status to true if scheme is "wss://".

On success it will set and return server address that can be used on Open().

On fail it will return empty server address and error.

func (*Client) Reconnect

func (cl *Client) Reconnect() (err error)

Reconnect to server using previous address and handshake parameters.

func (*Client) Recv

func (cl *Client) Recv() (packet []byte, err error)

Recv message from server.

func (*Client) Send

func (cl *Client) Send(ctx context.Context, req []byte, handler ClientRecvHandler) (err error)

Send message to server.

type ClientRecvHandler

type ClientRecvHandler func(ctx context.Context, resp []byte) (err error)

ClientRecvHandler define a custom callback type for handling response from request.

type ConnState

type ConnState int

ConnState represent socket connection status.

type ContextKey

type ContextKey uint64

ContextKey define a type for context.

const (
	CtxKeyExternalJWT ContextKey = 1 << iota
	CtxKeyInternalJWT
	CtxKeyUID
)

List of valid context key.

type Frame

type Frame struct {
	Fin    byte
	Opcode byte
	Masked byte

	Payload []byte
	// contains filtered or unexported fields
}

Frame represent a websocket data protocol.

5.2 Base Framing Protocol

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-------+-+-------------+-------------------------------+
  |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
  |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
  |N|V|V|V|       |S|             |   (if payload len==126/127)   |
  | |1|2|3|       |K|             |                               |
  +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
  |     Extended payload length continued, if payload len == 127  |
  + - - - - - - - - - - - - - - - +-------------------------------+
  |                               |Masking-key, if MASK set to 1  |
  +-------------------------------+-------------------------------+
  | Masking-key (continued)       |          Payload Data         |
  +-------------------------------- - - - - - - - - - - - - - - - +
  :                     Payload Data continued ...                :
  + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
  |                     Payload Data continued ...                |
  +---------------------------------------------------------------+

Mask:  1 bit

   Defines whether the "Payload data" is masked.  If set to 1, a
   masking key is present in masking-key, and this is used to unmask
   the "Payload data" as per Section 5.3.  All frames sent from
   client to server have this bit set to 1.

Payload length:  7 bits, 7+16 bits, or 7+64 bits

   The length of the "Payload data", in bytes: if 0-125, that is the
   payload length.  If 126, the following 2 bytes interpreted as a
   16-bit unsigned integer are the payload length.  If 127, the
   following 8 bytes interpreted as a 64-bit unsigned integer (the
   most significant bit MUST be 0) are the payload length.  Multibyte
   length quantities are expressed in network byte order.  Note that
   in all cases, the minimal number of bytes MUST be used to encode
   the length, for example, the length of a 124-byte-long string
   can't be encoded as the sequence 126, 0, 124.  The payload length
   is the length of the "Extension data" + the length of the
   "Application data".  The length of the "Extension data" may be
   zero, in which case the payload length is the length of the
   "Application data".

Masking-key:  0 or 4 bytes

   All frames sent from the client to the server are masked by a
   32-bit value that is contained within the frame.  This field is
   present if the mask bit is set to 1 and is absent if the mask bit
   is set to 0.  See Section 5.3 for further information on client-
   to-server masking.

Payload data:  (x+y) bytes

   The "Payload data" is defined as "Extension data" concatenated
   with "Application data".

Extension data:  x bytes

   The "Extension data" is 0 bytes unless an extension has been
   negotiated.  Any extension MUST specify the length of the
   "Extension data", or how that length may be calculated, and how
   the extension use MUST be negotiated during the opening handshake.
   If present, the "Extension data" is included in the total payload
   length.

Application data:  y bytes

   Arbitrary "Application data", taking up the remainder of the frame
   after any "Extension data".  The length of the "Application data"
   is equal to the payload length minus the length of the "Extension
   data".

func Unpack

func Unpack(in []byte) (fs []*Frame)

Unpack websocket data protocol from raw bytes to one or more frames.

On success it will return one or more frames. On fail it will return zero frame.

func (*Frame) Pack

func (f *Frame) Pack(randomMask bool) (out []byte)

Pack websocket Frame into packet that can be sent through network.

Caller must set frame fields Fin, Opcode, Masked, and Payload.

Frame payload len will be set based on length of payload.

Frame maskKey will be set randomly only if Masked is set and randomMask parameter is true.

RFC6455 5.1-P27
A server MUST NOT mask any frames that it sends to the client.

type HandlerAuthFn

type HandlerAuthFn func(req *Handshake) (ctx context.Context, err error)

HandlerAuthFn callback type to handle authentication request.

type HandlerClientFn

type HandlerClientFn func(ctx context.Context, conn int)

HandlerClientFn callback type to handle client request.

type HandlerFn

type HandlerFn func(conn int, req *Frame)

HandlerFn callback type to handle handshake request.

type Handshake

type Handshake struct {
	URI        []byte
	Host       []byte
	Key        []byte
	Extensions []byte
	Protocol   []byte
	Header     http.Header
	// contains filtered or unexported fields
}

Handshake contains the websocket HTTP handshake request.

func (*Handshake) Parse

func (h *Handshake) Parse(req []byte) (err error)

Parse HTTP request.

RFC6455 4.1-P17-19

1.   The handshake MUST be a valid HTTP request as specified by
     [RFC2616].

2.   The method of the request MUST be GET, and the HTTP version MUST
     be at least 1.1.

     For example, if the WebSocket URI is "ws://example.com/chat",
     the first line sent should be "GET /chat HTTP/1.1".

3.   The "Request-URI" part of the request MUST match the /resource
     name/ defined in Section 3 (a relative URI) or be an absolute
     http/https URI that, when parsed, has a /resource name/, /host/,
     and /port/ that match the corresponding ws/wss URI.

4.   The request MUST contain a |Host| header field whose value
     contains /host/ plus optionally ":" followed by /port/ (when not
     using the default port).

5.   The request MUST contain an |Upgrade| header field whose value
     MUST include the "websocket" keyword.

6.   The request MUST contain a |Connection| header field whose value
     MUST include the "Upgrade" token.

7.   The request MUST include a header field with the name
     |Sec-WebSocket-Key|.  The value of this header field MUST be a
     nonce consisting of a randomly selected 16-byte value that has
     been base64-encoded (see Section 4 of [RFC4648]).  The nonce
     MUST be selected randomly for each connection.

     NOTE: As an example, if the randomly selected value was the
     sequence of bytes 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
     0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10, the value of the header
     field would be "AQIDBAUGBwgJCgsMDQ4PEC=="

     ...
     The |Sec-WebSocket-Key| header field MUST NOT appear more than once
     in an HTTP request.

8.   The request MUST include a header field with the name |Origin|
     [RFC6454] if the request is coming from a browser client.  If
     the connection is from a non-browser client, the request MAY
     include this header field if the semantics of that client match
     the use-case described here for browser clients.  The value of
     this header field is the ASCII serialization of origin of the
     context in which the code establishing the connection is
     running.  See [RFC6454] for the details of how this header field
     value is constructed.

     As an example, if code downloaded from www.example.com attempts
     to establish a connection to ww2.example.com, the value of the
     header field would be "http://www.example.com".

9.   The request MUST include a header field with the name
     |Sec-WebSocket-Version|.  The value of this header field MUST be
     13.

     NOTE: Although draft versions of this document (-09, -10, -11,
     and -12) were posted (they were mostly comprised of editorial
     changes and clarifications and not changes to the wire
     protocol), values 9, 10, 11, and 12 were not used as valid
     values for Sec-WebSocket-Version.  These values were reserved in
     the IANA registry but were not and will not be used.

10.  The request MAY include a header field with the name
     |Sec-WebSocket-Protocol|.  If present, this value indicates one
     or more comma-separated subprotocol the client wishes to speak,
     ordered by preference.  The elements that comprise this value
     MUST be non-empty strings with characters in the range U+0021 to
     U+007E not including separator characters as defined in
     [RFC2616] and MUST all be unique strings.  The ABNF for the
     value of this header field is 1#token, where the definitions of
     constructs and rules are as given in [RFC2616].

11.  The request MAY include a header field with the name
     |Sec-WebSocket-Extensions|.  If present, this value indicates
     the protocol-level extension(s) the client wishes to speak.  The
     interpretation and format of this header field is described in
     Section 9.1.

12.  The request MAY include any other header fields, for example,
     cookies [RFC6265] and/or authentication-related header fields
     such as the |Authorization| header field [RFC2616], which are
     processed according to documents that define them.

Based on above requirements, the minimum handshake header is,

GET / HTTP/1.1\r\n			(16 bytes)
Host: a.com\r\n				(13 bytes)
Upgrade: websocket\r\n			(20 bytes)
Connection: Upgrade\r\n			(21 bytes)
Sec-Websocket-Key: (24 chars)\r\n	(45 bytes)
Sec-Websocket-Version: 13\r\n		(27 bytes)
\r\n					(2 bytes)

If we count all characters, the minimum bytes would be: 144 bytes. Of course one can send request with long URI "/chat?query=<512 chars>" without headers and the length will be greater than 144 bytes.

The minimum length of request without HTTP line is: 144 - 16 = 128 bytes.

func (*Handshake) Reset

func (h *Handshake) Reset(req []byte)

Reset all handshake values to zero or empty.

type Request

type Request struct {
	//
	// Id is unique between request to differentiate multiple request
	// since each request is asynchronous.  Client can use incremental
	// value or, the recommended way, using Unix timestamp with
	// millisecond.
	//
	ID uint64 `json:"id"`

	// Method is equal to HTTP method.
	Method string `json:"method"`

	// Target is equal to HTTP request RequestURI, e.g. "/path?query".
	Target string `json:"target"`

	// Body is equal to HTTP body on POST/PUT.
	Body string `json:"body"`

	// Path is Target without query.
	Path string `json:"-"`

	// Params are parameters as key-value in Target path that has been
	// parsed.
	Params targetParam `json:"-"`

	// Query is Target query.
	Query url.Values `json:"-"`
}

Request define text payload format for client requesting resource on server.

Example of request format,

{
	"id": 1512459721269,
	"method": "GET",
	"target": "/v1/auth/login",
	"body": "{ \"token\": \"xxx.yyy.zzz\" }"
}

func (*Request) Reset

func (req *Request) Reset()

Reset all field's value to zero or empty.

type Response

type Response struct {
	ID      uint64 `json:"id"`
	Code    int32  `json:"code"`
	Message string `json:"message"`
	Body    string `json:"body"`
}

Response contains the data that server send to client as a reply from Request or as broadcast from client subscription.

If response type is a reply from Request, the ID from Request will be copied to the Response, and `code` and `message` field values are equal with HTTP response code and message.

Example of response format for replying request,

{
	id: 1512459721269,
	code:  200,
	message: "",
	body: ""
}

If response type is broadcast the ID and code MUST be 0, and the `message` field will contain the name of subscription. For example, when recipient of message read the message, server will publish a notification response as,

{
	id: 0,
	code:  0,
	message: "message.read",
	body: "{ \"id\": ... }"
}

func (*Response) Reset

func (res *Response) Reset()

Reset all field's value to zero or empty.

type RouteHandler

type RouteHandler func(ctx context.Context, req *Request, res *Response)

RouteHandler is a function that will be called when registered method and target match with request.

type Server

type Server struct {
	HandleText         HandlerFn
	HandleBin          HandlerFn
	HandleClose        HandlerFn
	HandlePing         HandlerFn
	HandleAuth         HandlerAuthFn
	HandleClientAdd    HandlerClientFn
	HandleClientRemove HandlerClientFn
	// contains filtered or unexported fields
}

Server for websocket.

func NewServer

func NewServer(port int) (serv *Server, err error)

NewServer will create new web-socket server that listen on port number.

func (*Server) RegisterTextHandler

func (serv *Server) RegisterTextHandler(method, target string, handler RouteHandler) (err error)

RegisterTextHandler register specific function to be called by server when request opcode is text, and method and target matched with Request.

func (*Server) SendResponse

func (serv *Server) SendResponse(conn int, res *Response) (err error)

SendResponse to client.

func (*Server) Start

func (serv *Server) Start()

Start accepting incoming connection from clients.

type UserSockets

type UserSockets struct {
	sync.Map
}

UserSockets define a mapping between user ID (uint64) and list of their connections ([]int)

Each user may have more than one connection (e.g. from Android, iOS, web, etc). By knowing which connections that user have, implementor of websocket server can broadcast a message.

func (*UserSockets) Add

func (us *UserSockets) Add(uid uint64, conn int)

Add new socket connection to user ID only if the socket is not already exist.

func (*UserSockets) Remove

func (us *UserSockets) Remove(uid uint64, conn int)

Remove socket from list of user's connection.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL