Documentation ¶
Overview ¶
Package signalr provides the client side implementation of the WebSocket portion of the SignalR protocol.
First things first: this was almost entirely written using https://blog.3d-logic.com/2015/03/29/signalr-on-the-wire-an-informal-description-of-the-signalr-protocol/ as a reference guide. It is an excellent technical write-up. Many thanks to Pawel Kadluczka for writing that and sharing it with the public. If you want deep-dive technical details of how this all works, read that blog. I won't try to replicate it here.
At a high level, the WebSocket portion of SignalR goes through the following steps:
- negotiate: use HTTP/HTTPS to get connection info for how to connect to the websocket endpoint
- connect: attempt to connect to the websocket endpoint
- start: make the WebSocket connection usable by SignalR connections
See the provided examples for how to use this library.
Example (Basic) ¶
This example shows the most basic way to start a websocket connection.
package main import ( "log" "github.com/carterjones/signalr" ) func main() { // Prepare a SignalR client. c := signalr.New( "fake-server.definitely-not-real", "1.5", "/signalr", `[{"name":"awesomehub"}]`, nil, ) // Define message and error handlers. msgHandler := func(msg signalr.Message) { log.Println(msg) } panicIfErr := func(err error) { if err != nil { log.Panic(err) } } // Start the connection. err := c.Run(msgHandler, panicIfErr) panicIfErr(err) // Wait indefinitely. select {} }
Output:
Example (Complex) ¶
This example shows how to manually perform each of the initialization steps.
package main import ( "log" "github.com/carterjones/signalr" ) func main() { // Prepare a SignalR client. c := signalr.New( "fake-server.definitely-not-real", "1.5", "/signalr", `[{"name":"awesomehub"}]`, map[string]string{"custom-key": "custom-value"}, ) // Perform any optional modifications to the client here. Read the docs for // all the available options that are exposed via public fields. // Define message and error handlers. msgHandler := func(msg signalr.Message) { log.Println(msg) } panicIfErr := func(err error) { if err != nil { log.Panic(err) } } // Manually perform the initialization routine. err := c.Negotiate() panicIfErr(err) conn, err := c.Connect() panicIfErr(err) err = c.Start(conn) panicIfErr(err) // Begin the message reading loop. go c.ReadMessages(msgHandler, panicIfErr) // Wait indefinitely. select {} }
Output:
Index ¶
- func TestCompleteHandler(w http.ResponseWriter, r *http.Request)
- func TestConnect(w http.ResponseWriter, r *http.Request)
- func TestNegotiate(w http.ResponseWriter, r *http.Request)
- func TestReconnect(w http.ResponseWriter, r *http.Request)
- func TestStart(w http.ResponseWriter, r *http.Request)
- type Client
- func (c *Client) Close()
- func (c *Client) Conn() WebsocketConn
- func (c *Client) Connect() (*websocket.Conn, error)
- func (c *Client) Negotiate() error
- func (c *Client) ReadMessages(msgHandler MsgHandler, errHandler ErrHandler)
- func (c *Client) Reconnect() (*websocket.Conn, error)
- func (c *Client) Run(msgHandler MsgHandler, errHandler ErrHandler) error
- func (c *Client) Send(m hubs.ClientMsg) error
- func (c *Client) SetConn(conn WebsocketConn)
- func (c *Client) Start(conn WebsocketConn) error
- type ErrHandler
- type Message
- type MsgHandler
- type SafeString
- type Scheme
- type WebsocketConn
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func TestCompleteHandler ¶ added in v0.1.4
func TestCompleteHandler(w http.ResponseWriter, r *http.Request)
TestCompleteHandler combines the negotiate, connect, reconnect, and start handlers found in this package into one complete response handler.
func TestConnect ¶ added in v0.1.4
func TestConnect(w http.ResponseWriter, r *http.Request)
TestConnect provides a sample "/connect" handling function.
If an error occurs while upgrading the websocket, it will panic.
func TestNegotiate ¶ added in v0.1.4
func TestNegotiate(w http.ResponseWriter, r *http.Request)
TestNegotiate provides a sample "/negotiate" handling function.
If an error occurs while writing the response data, it will panic.
func TestReconnect ¶ added in v0.1.4
func TestReconnect(w http.ResponseWriter, r *http.Request)
TestReconnect provides a sample "/reconnect" handling function. It simply calls TestConnect.
Types ¶
type Client ¶
type Client struct { // The host providing the SignalR service. Host string // The relative path where the SignalR service is provided. Endpoint string // The websockets protocol version. Protocol string // Connection data passed to the service's websocket. ConnectionData string // User-defined custom parameters passed with each request to the server. Params map[string]string // The HTTPClient used to initialize the websocket connection. HTTPClient *http.Client // An optional setting to provide a non-default TLS configuration to use // when connecting to the websocket. TLSClientConfig *tls.Config // Either HTTPS or HTTP. Scheme Scheme // The maximum number of times to re-attempt a negotiation. MaxNegotiateRetries int // The maximum number of times to re-attempt a connection. MaxConnectRetries int // The maximum number of times to re-attempt a reconnection. MaxReconnectRetries int // The maximum number of times to re-attempt a start command. MaxStartRetries int // The time to wait before retrying, in the event that an error occurs // when contacting the SignalR service. RetryWaitDuration time.Duration // The maximum amount of time to spend retrying a reconnect attempt. MaxReconnectAttemptDuration time.Duration // This is the connection token set during the negotiate phase of the // protocol and used to uniquely identify the connection to the server // in all subsequent phases of the connection. ConnectionToken string // This is the ID of the connection. It is set during the negotiate // phase and then ignored by all subsequent steps. ConnectionID string // The groups token that is used during reconnect attempts. // // This is an example groups token: // yUcSohHrAZGEwK62B4Ao0WYac82p5yeRvHHInBgVmSK7jX++ym3kIgDy466yW/gRPp2l3Py8G45mRLJ9FslB3sKfsDPUNWL1b54cvjaSXCUo0znzyACxrN2Y0kNLR59h7hb6PgOSfy3Z2R5CUSVm5LZg6jg= GroupsToken SafeString // The message ID that is used during reconnect attempts. // // This is an example message ID: d-8B839DC3-C,0|aaZe,0|aaZf,2|C1,2A801 MessageID SafeString // Header values that should be applied to all HTTP requests. Headers map[string]string // This value is not part of the SignalR protocol. If this value is set, // it will be used in debug messages. CustomID string // contains filtered or unexported fields }
Client represents a SignlR client. It manages connections so that the caller doesn't have to.
func (*Client) Close ¶
func (c *Client) Close()
Close sends a signal to the loop reading WebSocket messages to indicate that the loop should terminate.
func (*Client) Conn ¶
func (c *Client) Conn() WebsocketConn
Conn returns the underlying websocket connection.
func (*Client) Negotiate ¶
Negotiate implements the negotiate step of the SignalR connection sequence.
func (*Client) ReadMessages ¶
func (c *Client) ReadMessages(msgHandler MsgHandler, errHandler ErrHandler)
ReadMessages processes WebSocket messages from the underlying websocket connection.
func (*Client) Reconnect ¶
Reconnect implements the reconnect step of the SignalR connection sequence.
func (*Client) Run ¶
func (c *Client) Run(msgHandler MsgHandler, errHandler ErrHandler) error
Run connects to the host and performs the websocket initialization routines that are part of the SignalR specification.
Example ¶
package main import ( "log" "github.com/carterjones/signalr" ) func main() { // Prepare a SignalR client. c := signalr.New( "fake-server.definitely-not-real", "1.5", "/signalr", `[{"name":"awesomehub"}]`, nil, ) // Define handlers. msgHandler := func(msg signalr.Message) { log.Println(msg) } panicIfErr := func(err error) { if err != nil { log.Panic(err) } } // Start the connection. err := c.Run(msgHandler, panicIfErr) if err != nil { log.Panic(err) } // Wait indefinitely. select {} }
Output:
func (*Client) SetConn ¶
func (c *Client) SetConn(conn WebsocketConn)
SetConn changes the underlying websocket connection to the specified connection. This is done using a mutex to wait until existing read operations have completed.
func (*Client) Start ¶
func (c *Client) Start(conn WebsocketConn) error
Start implements the start step of the SignalR connection sequence.
type Message ¶
type Message struct { // message id, present for all non-KeepAlive messages C string // an array containing actual data M []hubs.ClientMsg // indicates that the transport was initialized (a.k.a. init message) S int // groups token – an encrypted string representing group membership G string // other miscellaneous variables that sometimes are sent by the server I string E string R json.RawMessage H json.RawMessage // could be bool or string depending on a message type D json.RawMessage T json.RawMessage }
Message represents a message sent from the server to the persistent websocket connection.
type SafeString ¶ added in v0.2.3
type SafeString struct {
// contains filtered or unexported fields
}
SafeString is a thread-safe string.
func (*SafeString) Get ¶ added in v0.2.3
func (s *SafeString) Get() string
Get returns the string value.
func (*SafeString) Set ¶ added in v0.2.3
func (s *SafeString) Set(str string)
Set sets the string value.
type Scheme ¶
type Scheme string
Scheme represents a type of transport scheme. For the purposes of this project, we only provide constants for schemes relevant to HTTP and websockets.
type WebsocketConn ¶
type WebsocketConn interface { // ReadMessage is modeled after the function defined at // https://godoc.org/github.com/gorilla/websocket#Conn.ReadMessage // // At a high level, it reads messages and returns: // - the type of message read // - the bytes that were read // - any errors encountered during reading the message ReadMessage() (messageType int, p []byte, err error) // WriteJSON is modeled after the function defined at // https://godoc.org/github.com/gorilla/websocket#Conn.WriteJSON // // At a high level, it writes a structure to the underlying websocket and // returns any error that was encountered during the write operation. WriteJSON(v interface{}) error }
WebsocketConn is a combination of MessageReader and JSONWriter. It is used to provide an interface to objects that can read from and write to a websocket connection.