signalr: github.com/carterjones/signalr Index | Examples | Files | Directories

package signalr

import "github.com/carterjones/signalr"

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.

This example shows the most basic way to start a websocket connection.

Code:

// 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 {}

This example shows how to manually perform each of the initialization steps.

Code:

// 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 {}

Index

Examples

Package Files

doc.go signalr.go testing.go

func TestCompleteHandler Uses

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 Uses

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 Uses

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 Uses

func TestReconnect(w http.ResponseWriter, r *http.Request)

TestReconnect provides a sample "/reconnect" handling function. It simply calls TestConnect.

func TestStart Uses

func TestStart(w http.ResponseWriter, r *http.Request)

TestStart provides a sample "/start" handling function.

If an error occurs while writing the response data, it will panic.

type Client Uses

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:
    // nolint:lll
    // 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 New Uses

func New(host, protocol, endpoint, connectionData string, params map[string]string) *Client

New creates and initializes a SignalR client.

func (*Client) Close Uses

func (c *Client) Close()

Close sends a signal to the loop reading WebSocket messages to indicate that the loop should terminate.

func (*Client) Conn Uses

func (c *Client) Conn() WebsocketConn

Conn returns the underlying websocket connection.

func (*Client) Connect Uses

func (c *Client) Connect() (*websocket.Conn, error)

Connect implements the connect step of the SignalR connection sequence.

func (*Client) Negotiate Uses

func (c *Client) Negotiate() error

Negotiate implements the negotiate step of the SignalR connection sequence.

func (*Client) ReadMessages Uses

func (c *Client) ReadMessages(msgHandler MsgHandler, errHandler ErrHandler)

ReadMessages processes WebSocket messages from the underlying websocket connection.

func (*Client) Reconnect Uses

func (c *Client) Reconnect() (*websocket.Conn, error)

Reconnect implements the reconnect step of the SignalR connection sequence.

func (*Client) Run Uses

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.

Code:

// 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 {}

func (*Client) Send Uses

func (c *Client) Send(m hubs.ClientMsg) error

Send sends a message to the websocket connection.

func (*Client) SetConn Uses

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 Uses

func (c *Client) Start(conn WebsocketConn) error

Start implements the start step of the SignalR connection sequence.

type ErrHandler Uses

type ErrHandler func(err error)

ErrHandler processes an error.

type Message Uses

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 MsgHandler Uses

type MsgHandler func(msg Message)

MsgHandler processes a Message.

type SafeString Uses

type SafeString struct {
    // contains filtered or unexported fields
}

SafeString is a thread-safe string.

func (*SafeString) Get Uses

func (s *SafeString) Get() string

Get returns the string value.

func (*SafeString) Set Uses

func (s *SafeString) Set(str string)

Set sets the string value.

type Scheme Uses

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.

const (
    // HTTPS is the literal string, "https".
    HTTPS Scheme = "https"

    // HTTP is the literal string, "http".
    HTTP Scheme = "http"

    // WSS is the literal string, "wss".
    WSS Scheme = "wss"

    // WS is the literal string, "ws".
    WS  Scheme = "ws"
)

type WebsocketConn Uses

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.

Directories

PathSynopsis
hubsPackage hubs provides functionality used by the SignalR Hubs API.

Package signalr imports 20 packages (graph) and is imported by 1 packages. Updated 2019-03-20. Refresh now. Tools for package owners.