signalr

package module
v0.6.2 Latest Latest
Warning

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

Go to latest
Published: Apr 8, 2023 License: MIT Imports: 27 Imported by: 23

README

SignalR

Actions Status codecov PkgGoDev

SignalR is an open-source library that simplifies adding real-time web functionality to apps. Real-time web functionality enables server-side code to push content to clients instantly.

Historically it was tied to ASP.NET Core but the protocol is open and implementable in any language.

This repository contains an implementation of a SignalR server and a SignalR client in go. The implementation is based on the work of David Fowler at https://github.com/davidfowl/signalr-ports. Client and server support transport over WebSockets, Server Sent Events and raw TCP. Protocol encoding in JSON and MessagePack is fully supported.

Install

With a correctly configured Go toolchain:

go get -u github.com/philippseith/signalr

Getting Started

SignalR uses a signalr.HubInterface instance to anchor the connection on the server and a javascript HubConnection object to anchor the connection on the client.

Server side
Implement the HubInterface

The easiest way to implement the signalr.HubInterface in your project is to declare your own type and embed signalr.Hub which implements that interface and will take care of all the signalr plumbing. You can call your custom type anything you want so long as it implements the signalr.HubInterface interface.

package main

import "github.com/philippseith/signalr"

type AppHub struct {
    signalr.Hub
}

Add functions with your custom hub type as a receiver.

func (h *AppHub) SendChatMessage(message string) {
    h.Clients().All().Send("chatMessageReceived", message)
}

These functions must be public so that they can be seen by the signalr server package but can be invoked client-side as lowercase message names. We'll explain setting up the client side in a moment, but as a preview, here's an example of calling our AppHub.SendChatMessage(...) method from the client:

    // javascript snippet invoking that AppHub.Send method from the client
    connection.invoke('sendChatMessage', val);

The signalr.HubInterface contains a pair of methods you can implement to handle connection and disconnection events. signalr.Hub contains empty implementations of them to satisfy the interface, but you can "override" those defaults by implementing your own functions with your custom hub type as a receiver:

func (c *chat) OnConnected(connectionID string) {
    fmt.Printf("%s connected\n", connectionID)
}

func (c *chat) OnDisconnected(connectionID string) {
   fmt.Printf("%s disconnected\n", connectionID)
}
Serve with http.ServeMux
import (
    "net/http"
	
    "github.com/philippseith/signalr"
)

func runHTTPServer() {
    address := 'localhost:8080'
    
    // create an instance of your hub
    hub := AppHub{}
	
    // build a signalr.Server using your hub
    // and any server options you may need
    server, _ := signalr.NewServer(context.TODO(),
        signalr.SimpleHubFactory(hub)
        signalr.KeepAliveInterval(2*time.Second),
        signalr.Logger(kitlog.NewLogfmtLogger(os.Stderr), true))
    )
    
    // create a new http.ServerMux to handle your app's http requests
    router := http.NewServeMux()
    
    // ask the signalr server to map it's server
    // api routes to your custom baseurl
    server.MapHTTP(signalr.WithHTTPServeMux(router), "/chat")

    // in addition to mapping the signalr routes
    // your mux will need to serve the static files
    // which make up your client-side app, including
    // the signalr javascript files. here is an example
    // of doing that using a local `public` package
    // which was created with the go:embed directive
    // 
    // fmt.Printf("Serving static content from the embedded filesystem\n")
    // router.Handle("/", http.FileServer(http.FS(public.FS)))
    
    // bind your mux to a given address and start handling requests
    fmt.Printf("Listening for websocket connections on http://%s\n", address)
    if err := http.ListenAndServe(address, router); err != nil {
        log.Fatal("ListenAndServe:", err)
    }
}
Client side: JavaScript/TypeScript
Grab copies of the signalr scripts

Microsoft has published the client-side libraries as a node package with embedded typescript annotations: @microsoft/signalr.

You can install @microsoft/signalr through any node package manager:

package manager command
npm npm install @microsoft/signalr@latest
yarn yarn add @microsoft/signalr@latest
LibMan libman install @microsoft/signalr@latest -p unpkg -d wwwroot/js/signalr --files dist/browser/signalr.js --files dist/browser/signalr.min.js --files dist/browser/signalr.map.js
none you can download the version we are using in our chatsample from here (the minified version is here)
Use a HubConnection to connect to your server Hub

How you format your client UI is going to depend on your application use case but here is a simple example. It illustrates the basic steps of connecting to your server hub:

  1. import the signalr.js library (or signalr.min.js);

  2. create a connection object using the HubConnectionBuilder;

  3. bind events

    • UI event handlers can use connection.invoke(targetMethod, payload) to send invoke functions on the server hub;
    • connection event handlers can react to the messages sent from the server hub;
  4. start your connection

<html>
<body>
    <!-- you may want the content you send to be dynamic -->
    <input type="text" id="message" />
    
    <!-- you may need a trigger to initiate the send -->
    <input type="button" value="Send" id="send" />
    
    <!-- you may want some container to display received messages -->
    <ul id="messages">
    </ul>

    <!-- 1. you need to import the signalr script which provides
            the HubConnectionBuilder and handles the connection
            plumbing.
    -->
    <script src="js/signalr.js"></script>
    <script>
    (async function () {
        // 2. use the signalr.HubConnectionBuilder to build a hub connection
        //    and point it at the baseurl which you configured in your mux
        const connection = new signalR.HubConnectionBuilder()
                .withUrl('/chat')
                .build();

        // 3. bind events:
        //    - UI events can invoke (i.e. dispatch to) functions on the server hub
        document.getElementById('send').addEventListener('click', sendClicked);
        //    - connection events can handle messages received from the server hub
        connection.on('chatMessageReceived', onChatMessageReceived);

        // 4. call start to initiate the connection and start streaming events
        //    between your server hub and your client connection
        connection.start();
        
        // that's it! your server and client should be able to communicate
        // through the signalr.Hub <--> connection pipeline managed by the
        // signalr package and client-side library.
        
        // --------------------------------------------------------------------
       
        // example UI event handler
        function sendClicked() {
            // prepare your target payload
            const msg = document.getElementById('message').value;
            if (msg) {
                // call invoke on your connection object to dispatch
                // messages to the server hub with two arguments:
                // -  target: name of the hub func to invoke
                // - payload: the message body
                // 
                const target = 'sendChatMessage';
                connection.invoke(target, msg);
            }
        }

        // example server event handler
        function onChatMessageReceived(payload) {
            // the payload is whatever was passed to the inner
            // clients' `Send(...)` method in your server-side
            // hub function.
           
            const li = document.createElement('li');
            li.innerText = payload;
            document.getElementById('messages').appendChild(li);
        }
    })();
    </script>
</body>
</html>
Client side: go

To handle callbacks from the server, create a receiver class which gets the server callbacks mapped to its methods:

type receiver struct {
	signalr.Hub
}

func (c *receiver) Receive(msg string) {
	fmt.Println(msg)
}

Receive gets called when the server does something like this:

hub.Clients().Caller().Send("receive", message)

The client itself might be used like that:

// Create a Connection (with timeout for the negotiation process)
creationCtx, _ := context.WithTimeout(ctx, 2 * time.Second)
conn, err := signalr.NewHTTPConnection(creationCtx, address)
if err != nil {
    return err
}
// Create the client and set a receiver for callbacks from the server
client, err := signalr.NewClient(ctx,
	signalr.WithConnection(conn),
	signalr.WithReceiver(receiver))
if err != nil {
    return err
}
// Start the client loop
c.Start()
// Do some client work
ch := <-c.Invoke("update", data)
// ch gets the result of the update operation

Debugging

Server, Client and the protocol implementations are able to log most of their operations. The logging option is disabled by default in all tests. To configure logging, edit the testLogConf.json file:

{
  "Enabled": false,
  "Debug": false
}
  • If Enabled is set to true, the logging will be enabled. The tests will log to os.Stderr.
  • If Debug ist set to true, the logging will be more detailed.

Documentation

Overview

Package signalr contains a SignalR client and a SignalR server. Both support the transport types Websockets and Server-Sent Events and the transfer formats Text (JSON) and Binary (MessagePack).

Basics

The SignalR Protocol is a protocol for two-way RPC over any stream- or message-based transport. Either party in the connection may invoke procedures on the other party, and procedures can return zero or more results or an error. Typically, SignalR connections are HTTP-based, but it is dead simple to implement a signalr.Connection on any transport that supports io.Reader and io.Writer.

Client

A Client can be used in client side code to access server methods. From an existing connection, it can be created with NewClient().

  // NewClient with raw TCP connection and MessagePack encoding
  conn, err := net.Dial("tcp", "example.com:6502")
  client := NewClient(ctx,
			WithConnection(NewNetConnection(ctx, conn)),
			TransferFormat("Binary),
			WithReceiver(receiver))

  client.Start()

A special case is NewHTTPClient(), which creates a Client from a server address and negotiates with the server which kind of connection (Websockets, Server-Sent Events) will be used.

  // Configurable HTTP connection
  conn, err := NewHTTPConnection(ctx, "http://example.com/hub", WithHTTPHeaders(..))
  // Client with JSON encoding
  client, err := NewClient(ctx,
			WithConnection(conn),
			TransferFormat("Text"),
			WithReceiver(receiver))

  client.Start()

The object which will receive server callbacks is passed to NewClient() by using the WithReceiver option. After calling client.Start(), the client is ready to call server methods or to receive callbacks.

Server

A Server provides the public methods of a server side class over signalr to the client. Such a server side class is called a hub and must implement HubInterface. It is reasonable to derive your hubs from the Hub struct type, which already implements HubInterface. Servers for arbitrary connection types can be created with NewServer().

// Typical server with log level debug to Stderr
server, err := NewServer(ctx, SimpleHubFactory(hub), Logger(log.NewLogfmtLogger(os.Stderr), true))

To serve a connection, call server.Serve(connection) in a goroutine. Serve ends when the connection is closed or the servers context is canceled.

// Serving over TCP, accepting client who use MessagePack or JSON
addr, _ := net.ResolveTCPAddr("tcp", "localhost:6502")
listener, _ := net.ListenTCP("tcp", addr)
tcpConn, _ := listener.Accept()
go server.Serve(NewNetConnection(conn))

To serve a HTTP connection, use server.MapHTTP(), which connects the server with a path in an http.ServeMux. The server then automatically negotiates which kind of connection (Websockets, Server-Sent Events) will be used.

// build a signalr.Server using your hub
// and any server options you may need
server, _ := signalr.NewServer(ctx,
    signalr.SimpleHubFactory(&AppHub{})
    signalr.KeepAliveInterval(2*time.Second),
    signalr.Logger(kitlog.NewLogfmtLogger(os.Stderr), true))
)

// create a new http.ServerMux to handle your app's http requests
router := http.NewServeMux()

// ask the signalr server to map it's server
// api routes to your custom baseurl
server.MapHTTP(signalr.WithHTTPServeMux(router), "/hub")

// in addition to mapping the signalr routes
// your mux will need to serve the static files
// which make up your client-side app, including
// the signalr javascript files. here is an example
// of doing that using a local `public` package
// which was created with the go:embed directive
//
// fmt.Printf("Serving static content from the embedded filesystem\n")
// router.Handle("/", http.FileServer(http.FS(public.FS)))

// bind your mux to a given address and start handling requests
fmt.Printf("Listening for websocket connections on http://%s\n", address)
if err := http.ListenAndServe(address, router); err != nil {
    log.Fatal("ListenAndServe:", err)
}

Supported method signatures

The SignalR protocol constrains the signature of hub or receiver methods that can be used over SignalR. All methods with serializable types as parameters and return types are supported. Methods with multiple return values are not generally supported, but returning one or no value and an optional error is supported.

// Simple signatures for hub/receiver methods
func (mh *MathHub) Divide(a, b float64) (float64, error) // error on division by zero
func (ah *AlgoHub) Sort(values []string) []string
func (ah *AlgoHub) FindKey(value []string, dict map[int][]string) (int, error) // error on not found
func (receiver *View) DisplayServerValue(value interface{}) // will work for every serializable value

Methods which return a single sending channel (<-chan), and optionally an error, are used to initiate callee side streaming. The caller will receive the contents of the channel as stream. When the returned channel is closed, the stream will be completed.

// Streaming methods
func (n *Netflix) Stream(show string, season, episode int) (<-chan []byte, error) // error on password shared

Methods with one or multiple receiving channels (chan<-) as parameters are used as receivers for caller side streaming. The caller invokes this method and pushes one or multiple streams to the callee. The method should end when all channels are closed. A channel is closed by the server when the assigned stream is completed. The methods which return a channel are not supported.

// Caller side streaming
func (mh *MathHub) MultiplyAndSum(a, b chan<- float64) float64

In most cases, the caller will be the client and the callee the server. But the vice versa case is also possible.

Index

Constants

This section is empty.

Variables

View Source
var ErrClosedPipe = errors.New("io: read/write on closed pipe")

ErrClosedPipe is the error used for read or write operations on a closed pipe.

View Source
var ErrUnableToConnect = errors.New("neither WithConnection nor WithConnector option was given")

Functions

func AllowOriginPatterns added in v0.4.0

func AllowOriginPatterns(origins []string) func(Party) error

AllowOriginPatterns lists the host patterns for authorized origins which is used for avoid same origin strategy. See https://pkg.go.dev/nhooyr.io/websocket#AcceptOptions

func ChanReceiveTimeout

func ChanReceiveTimeout(timeout time.Duration) func(Party) error

ChanReceiveTimeout is the timeout for processing stream items from the client, after StreamBufferCapacity was reached If the hub method is not able to process a stream item during the timeout duration, the server will send a completion with error. Default is 5 seconds.

func CtxPipe added in v0.2.2

func CtxPipe(ctx context.Context) (*PipeReader, *PipeWriter)

CtxPipe creates a synchronous in-memory pipe. It can be used to connect code expecting an io.Reader with code expecting an io.Writer.

By canceling the context, Read and Write can be canceled

Reads and Writes on the pipe are matched one to one except when multiple Reads are needed to consume a single Write. That is, each Write to the PipeWriter blocks until it has satisfied one or more Reads from the PipeReader that fully consume the written data. The data is copied directly from the Write to the corresponding Read (or Reads); there is no internal buffering.

It is safe to call Read and Write in parallel with each other or with Close. Parallel calls to Read and parallel calls to Write are also safe: the individual calls will be gated sequentially.

func EnableDetailedErrors

func EnableDetailedErrors(enable bool) func(Party) error

EnableDetailedErrors If true, detailed exception messages are returned to the other Party when an exception is thrown in a Hub method. The default is false, as these exception messages can contain sensitive information.

func HTTPTransports

func HTTPTransports(transports ...string) func(Party) error

HTTPTransports sets the list of available transports for http connections. Allowed transports are "WebSockets", "ServerSentEvents". Default is both transports are available.

func HandshakeTimeout

func HandshakeTimeout(timeout time.Duration) func(Party) error

HandshakeTimeout is the interval if the other Party doesn't send an initial handshake message within, the connection is closed. This is an advanced setting that should only be modified if handshake timeout errors are occurring due to severe network latency. For more detail on the handshake process, see https://github.com/dotnet/aspnetcore/blob/master/src/SignalR/docs/specs/HubProtocol.md

func HubFactory

func HubFactory(factory func() HubInterface) func(Party) error

HubFactory sets the function which returns the hub instance for every hub method invocation The function might create a new hub instance on every invocation. If hub instances should be created and initialized by a DI framework, the frameworks' factory method can be called here.

func InsecureSkipVerify added in v0.4.0

func InsecureSkipVerify(skip bool) func(Party) error

InsecureSkipVerify disables Accepts origin verification behaviour which is used to avoid same origin strategy. See https://pkg.go.dev/nhooyr.io/websocket#AcceptOptions

func KeepAliveInterval

func KeepAliveInterval(interval time.Duration) func(Party) error

KeepAliveInterval is the interval if the Party hasn't sent a message within, a ping message is sent automatically to keep the connection open. When changing KeepAliveInterval, change the Timeout setting on the other Party. The recommended Timeout value is double the KeepAliveInterval value. Default is 15 seconds.

func Logger

func Logger(logger StructuredLogger, debug bool) func(Party) error

Logger sets the logger used by the Party to log info events. If debug is true, debug log event are generated, too

func MaximumReceiveMessageSize

func MaximumReceiveMessageSize(sizeInBytes uint) func(Party) error

MaximumReceiveMessageSize is the maximum size in bytes of a single incoming hub message. Default is 32768 bytes (32KB)

func ReadWriteWithContext added in v0.5.0

func ReadWriteWithContext(ctx context.Context, doRW func() (int, error), unblockRW func()) (int, error)

ReadWriteWithContext is a wrapper to make blocking io.Writer / io.Reader cancelable. It can be used to implement cancellation of connections. ReadWriteWithContext will return when either the Read/Write operation has ended or ctx has been canceled.

doRW func() (int, error)

doRW should contain the Read/Write operation.

unblockRW func()

unblockRW should contain the operation to unblock the Read/Write operation. If there is no way to unblock the operation, one goroutine will leak when ctx is canceled. As the standard use case when ReadWriteWithContext is canceled is the cancellation of a connection this leak will be problematic on heavily used servers with uncommon connection types. Luckily, the standard connection types for ServerSentEvents, Websockets and common net.Conn connections can be unblocked.

func SimpleHubFactory

func SimpleHubFactory(hubProto HubInterface) func(Party) error

SimpleHubFactory sets a HubFactory which creates a new hub with the underlying type of hubProto on each hub method invocation.

func StreamBufferCapacity

func StreamBufferCapacity(capacity uint) func(Party) error

StreamBufferCapacity is the maximum number of items that can be buffered for client upload streams. If this limit is reached, the processing of invocations is blocked until the server processes stream items. Default is 10.

func TimeoutInterval

func TimeoutInterval(timeout time.Duration) func(Party) error

TimeoutInterval is the interval one Party will consider the other Party disconnected if it hasn't received a message (including keep-alive) in it. The recommended value is double the KeepAliveInterval value. Default is 30 seconds.

func TransferFormat

func TransferFormat(format string) func(Party) error

TransferFormat sets the transfer format used on the transport. Allowed values are "Text" and "Binary"

func UseHub

func UseHub(hub HubInterface) func(Party) error

UseHub sets the hub instance used by the server

func WithBackoff added in v0.6.1

func WithBackoff(backoffFactory func() backoff.BackOff) func(party Party) error

WithBackoff sets the backoff.BackOff used for repeated connection attempts in the client. See https://pkg.go.dev/github.com/cenkalti/backoff for configuration options. If the option is not set, backoff.NewExponentialBackOff() without any further configuration will be used.

func WithConnection added in v0.5.0

func WithConnection(connection Connection) func(party Party) error

WithConnection sets the Connection of the Client

func WithConnector added in v0.6.0

func WithConnector(connectionFactory func() (Connection, error)) func(Party) error

WithConnector allows the Client to establish a connection using the Connection build by the connectionFactory. It is also used for auto reconnect if the connection is lost.

func WithHTTPClient added in v0.5.0

func WithHTTPClient(client Doer) func(*httpConnection) error

WithHTTPClient sets the http client used to connect to the signalR server. The client is only used for http requests. It is not used for the websocket connection.

func WithHTTPHeaders added in v0.5.0

func WithHTTPHeaders(headers func() http.Header) func(*httpConnection) error

WithHTTPHeaders sets the function for providing request headers for HTTP and websocket requests

func WithHTTPServeMux added in v0.5.0

func WithHTTPServeMux(serveMux *http.ServeMux) func() MappableRouter

WithHTTPServeMux is a MappableRouter factory for MapHTTP which converts a http.ServeMux to a MappableRouter. For factories for other routers, see github.com/philippseith/signalr/router

func WithReceiver added in v0.5.0

func WithReceiver(receiver interface{}) func(Party) error

WithReceiver sets the object which will receive server side calls to client methods (e.g. callbacks)

Types

type Client

type Client interface {
	Party
	Start()
	State() ClientState
	ObserveStateChanged(chan ClientState) context.CancelFunc
	Err() error
	WaitForState(ctx context.Context, waitFor ClientState) <-chan error
	Invoke(method string, arguments ...interface{}) <-chan InvokeResult
	Send(method string, arguments ...interface{}) <-chan error
	PullStream(method string, arguments ...interface{}) <-chan InvokeResult
	PushStreams(method string, arguments ...interface{}) <-chan InvokeResult
}

Client is the signalR connection used on the client side.

Start()

Start starts the client loop. After starting the client, the interaction with a server can be started. The client loop will run until the server closes the connection. If WithConnector is used, Start will start a new loop. To end the loop from the client side, the context passed to NewClient has to be canceled.

State() ClientState

State returns the current client state. When WithConnector is set and the server allows reconnection, the client switches to ClientConnecting and tries to reach ClientConnected after the last connection has ended.

ObserveStateChanged(chan ClientState) context.CancelFunc

ObserveStateChanged pushes a new item != nil to the channel when State has changed. The returned CancelFunc ends the observation and closes the channel.

Err() error

Err returns the last error occurred while running the client. When the client goes to ClientConnecting, Err is set to nil.

WaitForState(ctx context.Context, waitFor ClientState) <-chan error

WaitForState returns a channel for waiting on the Client to reach a specific ClientState. The channel either returns an error if ctx or the client has been canceled. or nil if the ClientState waitFor was reached.

Invoke(method string, arguments ...interface{}) <-chan InvokeResult

Invoke invokes a method on the server and returns a channel wich will return the InvokeResult. When failing, InvokeResult.Error contains the client side error.

Send(method string, arguments ...interface{}) <-chan error

Send invokes a method on the server but does not return a result from the server but only a channel, which might contain a client side error occurred while sending.

PullStream(method string, arguments ...interface{}) <-chan InvokeResult

PullStream invokes a streaming method on the server and returns a channel which delivers the stream items. For more info about Streaming see https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/HubProtocol.md#streaming

PushStreams(method string, arguments ...interface{}) <-chan error

PushStreams pushes all items received from its arguments of type channel to the server (Upload Streaming). PushStreams does not support server methods that return a channel. For more info about Upload Streaming see https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/docs/specs/HubProtocol.md#upload-streaming

func NewClient

func NewClient(ctx context.Context, options ...func(Party) error) (Client, error)

NewClient builds a new Client. When ctx is canceled, the client loop and a possible auto reconnect loop are ended.

type ClientProxy

type ClientProxy interface {
	Send(target string, args ...interface{})
}

ClientProxy allows the hub to send messages to one or more of its clients

type ClientState added in v0.5.0

type ClientState int

ClientState is the state of the client.

const (
	ClientCreated ClientState = iota
	ClientConnecting
	ClientConnected
	ClientClosed
)

Client states

ClientCreated

The Client has been created and is not started yet.

ClientConnecting

The Client has been started and is negotiating the connection.

ClientConnected

The Client has successfully negotiated the connection and can send and receive messages.

ClientClosed

The Client is not able to send and receive messages anymore and has to be started again to be able to.

type Connection

type Connection interface {
	io.Reader
	io.Writer
	Context() context.Context
	ConnectionID() string
	SetConnectionID(id string)
}

Connection describes a connection between signalR client and server

func NewHTTPConnection added in v0.3.0

func NewHTTPConnection(ctx context.Context, address string, options ...func(*httpConnection) error) (Connection, error)

NewHTTPConnection creates a signalR HTTP Connection for usage with a Client. ctx can be used to cancel the SignalR negotiation during the creation of the Connection but not the Connection itself.

func NewNetConnection

func NewNetConnection(ctx context.Context, conn net.Conn) Connection

NewNetConnection wraps net.Conn into a Connection

type ConnectionBase

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

ConnectionBase is a baseclass for implementers of the Connection interface.

func NewConnectionBase added in v0.5.0

func NewConnectionBase(ctx context.Context, connectionID string) *ConnectionBase

NewConnectionBase creates a new ConnectionBase

func (*ConnectionBase) ConnectionID

func (cb *ConnectionBase) ConnectionID() string

ConnectionID is the ID of the connection.

func (*ConnectionBase) Context

func (cb *ConnectionBase) Context() context.Context

Context can be used to wait for cancellation of the Connection

func (*ConnectionBase) SetConnectionID

func (cb *ConnectionBase) SetConnectionID(id string)

SetConnectionID sets the ConnectionID

type ConnectionWithTransferMode

type ConnectionWithTransferMode interface {
	TransferMode() TransferMode
	SetTransferMode(transferMode TransferMode)
}

ConnectionWithTransferMode is a Connection with TransferMode (e.g. Websocket)

type Doer added in v0.3.0

type Doer interface {
	Do(req *http.Request) (*http.Response, error)
}

Doer is the *http.Client interface

type GroupManager

type GroupManager interface {
	AddToGroup(groupName string, connectionID string)
	RemoveFromGroup(groupName string, connectionID string)
}

GroupManager manages the client groups of the hub

type Hub

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

Hub is a base class for hubs

func (*Hub) Abort

func (h *Hub) Abort()

Abort aborts the current connection

func (*Hub) Clients

func (h *Hub) Clients() HubClients

Clients returns the clients of this hub

func (*Hub) ConnectionID

func (h *Hub) ConnectionID() string

ConnectionID gets the ID of the current connection

func (*Hub) Context added in v0.2.0

func (h *Hub) Context() context.Context

Context is the context.Context of the current connection

func (*Hub) Groups

func (h *Hub) Groups() GroupManager

Groups returns the client groups of this hub

func (*Hub) Initialize

func (h *Hub) Initialize(ctx HubContext)

Initialize initializes a hub with a HubContext

func (*Hub) Items

func (h *Hub) Items() *sync.Map

Items returns the items for this connection

func (*Hub) Logger

func (h *Hub) Logger() (info StructuredLogger, dbg StructuredLogger)

Logger returns the loggers used in this server. By this, derived hubs can use the same loggers as the server.

func (*Hub) OnConnected

func (h *Hub) OnConnected(string)

OnConnected is called when the hub is connected

func (*Hub) OnDisconnected

func (h *Hub) OnDisconnected(string)

OnDisconnected is called when the hub is disconnected

type HubClients

type HubClients interface {
	All() ClientProxy
	Caller() ClientProxy
	Client(connectionID string) ClientProxy
	Group(groupName string) ClientProxy
}

HubClients gives the hub access to various client groups All() gets a ClientProxy that can be used to invoke methods on all clients connected to the hub Caller() gets a ClientProxy that can be used to invoke methods of the current calling client Client() gets a ClientProxy that can be used to invoke methods on the specified client connection Group() gets a ClientProxy that can be used to invoke methods on all connections in the specified group

type HubContext

type HubContext interface {
	Clients() HubClients
	Groups() GroupManager
	Items() *sync.Map
	ConnectionID() string
	Context() context.Context
	Abort()
	Logger() (info StructuredLogger, dbg StructuredLogger)
}

HubContext is a context abstraction for a hub Clients gets a HubClients that can be used to invoke methods on clients connected to the hub Groups gets a GroupManager that can be used to add and remove connections to named groups Items holds key/value pairs scoped to the hubs connection ConnectionID gets the ID of the current connection Abort aborts the current connection Logger returns the logger used in this server

type HubInterface

type HubInterface interface {
	Initialize(hubContext HubContext)
	OnConnected(connectionID string)
	OnDisconnected(connectionID string)
}

HubInterface is a hubs interface

type HubLifetimeManager

type HubLifetimeManager interface {
	OnConnected(conn hubConnection)
	OnDisconnected(conn hubConnection)
	InvokeAll(target string, args []interface{})
	InvokeClient(connectionID string, target string, args []interface{})
	InvokeGroup(groupName string, target string, args []interface{})
	AddToGroup(groupName, connectionID string)
	RemoveFromGroup(groupName, connectionID string)
}

HubLifetimeManager is a lifetime manager abstraction for hub instances OnConnected() is called when a connection is started OnDisconnected() is called when a connection is finished InvokeAll() sends an invocation message to all hub connections InvokeClient() sends an invocation message to a specified hub connection InvokeGroup() sends an invocation message to a specified group of hub connections AddToGroup() adds a connection to the specified group RemoveFromGroup() removes a connection from the specified group

type InvokeResult

type InvokeResult struct {
	Value interface{}
	Error error
}

InvokeResult is the combined value/error result for async invocations. Used as channel type.

type MappableRouter

type MappableRouter interface {
	HandleFunc(string, func(w http.ResponseWriter, r *http.Request))
	Handle(string, http.Handler)
}

MappableRouter encapsulates the methods used by server.MapHTTP to configure the handlers required by the signalr protocol. this abstraction removes the explicit binding to http.ServerMux and allows use of any mux which implements those basic Handle and HandleFunc methods.

type Party

type Party interface {
	// contains filtered or unexported methods
}

Party is the common base of Server and Client. The Party methods are only used internally, but the interface is public to allow using Options on Party as parameters for external functions

type PipeReader added in v0.2.2

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

A PipeReader is the read half of a pipe.

func (*PipeReader) Close added in v0.2.2

func (r *PipeReader) Close() error

Close closes the reader; subsequent writes to the write half of the pipe will return the error ErrClosedPipe.

func (*PipeReader) CloseWithError added in v0.2.2

func (r *PipeReader) CloseWithError(err error) error

CloseWithError closes the reader; subsequent writes to the write half of the pipe will return the error err.

CloseWithError never overwrites the previous error if it exists and always returns nil.

func (*PipeReader) Read added in v0.2.2

func (r *PipeReader) Read(data []byte) (n int, err error)

Read implements the standard Read interface: it reads data from the pipe, blocking until a writer arrives or the write end is closed. If the write end is closed with an error, that error is returned as err; otherwise err is EOF.

type PipeWriter added in v0.2.2

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

A PipeWriter is the write half of a pipe.

func (*PipeWriter) Close added in v0.2.2

func (w *PipeWriter) Close() error

Close closes the writer; subsequent reads from the read half of the pipe will return no bytes and EOF.

func (*PipeWriter) CloseWithError added in v0.2.2

func (w *PipeWriter) CloseWithError(err error) error

CloseWithError closes the writer; subsequent reads from the read half of the pipe will return no bytes and the error err, or EOF if err is nil.

CloseWithError never overwrites the previous error if it exists and always returns nil.

func (*PipeWriter) Write added in v0.2.2

func (w *PipeWriter) Write(data []byte) (n int, err error)

Write implements the standard Write interface: it writes data to the pipe, blocking until one or more readers have consumed all the data or the read end is closed. If the read end is closed with an error, that err is returned as err; otherwise err is ErrClosedPipe.

type RWJobResult added in v0.5.0

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

RWJobResult can be used to send the result of an io.Writer / io.Reader operation over a channel. Use it for special connection types, where ReadWriteWithContext does not fit all needs.

type Receiver

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

Receiver is a base class for receivers in the client. It implements ReceiverInterface

func (*Receiver) Init added in v0.5.0

func (ch *Receiver) Init(client Client)

Init is used by the Client to connect the receiver to the server.

func (*Receiver) Server added in v0.5.0

func (ch *Receiver) Server() Client

Server can be used inside receiver methods to call Client methods,

type ReceiverInterface added in v0.5.0

type ReceiverInterface interface {
	Init(Client)
	Server() Client
}

ReceiverInterface allows receivers to interact with the server directly from the receiver methods

Init(Client)

Init is used by the Client to connect the receiver to the server.

Server() Client

Server can be used inside receiver methods to call Client methods, e.g. Client.Send, Client.Invoke, Client.PullStream and Client.PushStreams

type Server

type Server interface {
	Party
	MapHTTP(routerFactory func() MappableRouter, path string)
	Serve(conn Connection) error
	HubClients() HubClients
	// contains filtered or unexported methods
}

Server is a SignalR server for one type of hub.

MapHTTP(mux *http.ServeMux, path string)

maps the servers' hub to a path on a http.ServeMux.

Serve(conn Connection)

serves the hub of the server on one connection. The same server might serve different connections in parallel. Serve does not return until the connection is closed or the servers' context is canceled.

HubClients() allows to call all HubClients of the server from server-side, non-hub code. Note that HubClients.Caller() returns nil, because there is no real caller which can be reached over a HubConnection.

func NewServer

func NewServer(ctx context.Context, options ...func(Party) error) (Server, error)

NewServer creates a new server for one type of hub. The hub type is set by one of the options UseHub, HubFactory or SimpleHubFactory

type StructuredLogger

type StructuredLogger interface {
	Log(keyVals ...interface{}) error
}

StructuredLogger is the simplest logging interface for structured logging. See github.com/go-kit/log

type TransferMode

type TransferMode int

TransferMode is either TextTransferMode or BinaryTransferMode

const (
	// TextTransferMode is for UTF-8 encoded text messages like JSON.
	TextTransferMode TransferMode = iota + 1
	// BinaryTransferMode is for binary messages like MessagePack.
	BinaryTransferMode
)

MessageType constants.

Directories

Path Synopsis
mux module
router module

Jump to

Keyboard shortcuts

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