Categorygithub.com/qbeon/webwire-go
modulepackage
0.1.0-alpha1
Repository: https://github.com/qbeon/webwire-go.git
Documentation: pkg.go.dev

# README

License: MIT Build Status Go Report Card Donate

WebWire for Golang

WebWire is a high-level asynchronous duplex messaging library built on top of WebSockets and an open source binary message protocol with builtin support for UTF8 and UTF16 encoding. The webwire-go library provides both a client and a server implementation for the Go programming language. An official JavaScript client implementation is also available. WebWire provides a compact set of useful features that are not available and/or cumbersome to implement on raw WebSockets such as Request-Reply, Sessions, Thread-safety etc.

WebWire Binary Protocol

WebWire is built for speed and portability implementing an open source binary protocol. Protocol Subset Diagram

The first byte defines the type of the message. Requests and replies contain an incremental 8-byte identifier that must be unique in the context of the senders' session. A 0 to 255 bytes long 7-bit ASCII encoded name is contained in the header of a signal or request message. A header-padding byte is applied in case of UTF16 payload encoding to properly align the payload sequence. Fraudulent messages are recognized by analyzing the message length, out-of-range memory access attacks are therefore prevented.

Examples

Features

Request-Reply

Clients can initiate multiple simultaneous requests and receive replies asynchronously. Requests are multiplexed through the connection similar to HTTP2 pipelining.

// Send a request to the server, will block the goroutine until replied
reply, err := client.Request("", wwr.Payload{Data: []byte("sudo rm -rf /")})
if err != nil {
  // Oh oh, request failed for some reason!
}
reply // Here we go!

Timed requests will timeout and return an error if the server doesn't manage to reply within the specified time frame.

// Send a request to the server, will block the goroutine for 200ms at max
reply, err := client.TimedRequest("", wwr.Payload{Data: []byte("hurry up!")}, 200*time.Millisecond)
if err != nil {
  // Probably timed out!
}
reply // Just in time!

Client-side Signals

Individual clients can send signals to the server. Signals are one-way messages guaranteed to arrive not requiring any reply though.

// Send signal to server
err := client.Signal("eventA", wwr.Payload{Data: []byte("something")})

Server-side Signals

The server also can send signals to individual connected clients.

func onRequest(ctx context.Context) (wwr.Payload, *wwr.Error) {
  msg := ctx.Value(wwr.Msg).(wwr.Message)
  // Send a signal to the client before replying to the request
  msg.Client.Signal("", wwr.Payload{Data: []byte("ping!")})
  return wwr.Payload{}, nil
}

Namespaces

Different kinds of requests and signals can be differentiated using the builtin namespacing feature.

func onRequest(ctx context.Context) (wwr.Payload, *wwr.Error) {
  msg := ctx.Value(wwr.Msg).(wwr.Message)
  switch msg.Name {
  case "auth":
    // Authentication request
  case "query":
    // Query request
  }
  return wwr.Payload{}, nil
}
func onSignal(ctx context.Context) {
  msg := ctx.Value(wwr.Msg).(wwr.Message)
  switch msg.Name {
  case "event A":
    // handle event A
  case "event B":
    // handle event B
  }
}

Sessions

Individual connections can get sessions assigned to identify them. The state of the session is automagically synchronized between the client and the server. WebWire doesn't enforce any kind of authentication technique though, it just provides you a way to authenticate a connection. WebWire also doesn't enforce any kind of session storage, it's up to the user to implement any kind of volatile or persistent session storage, be it a database or a simple map.

func onRequest(ctx context.Context) (wwr.Payload, *wwr.Error) {
  msg := ctx.Value(wwr.Msg).(wwr.Message)
  client := msg.Client
  // Verify credentials
  if string(msg.Payload.Data) != "secret:pass" {
    return wwr.Payload{}, wwr.Error {
      Code: "WRONG_CREDENTIALS",
      Message: "Incorrect username or password, try again"
    }
  }
  // Create session, will automatically synchronize to the client
  err := client.CreateSession(/*arbitrary data*/); err != nil {
    return wwr.Payload{}, wwr.Error {
      Code: "INTERNAL_ERROR",
      Message: "Couldn't create session for some reason"
    }
  }
  client.Session // return wwr.Payload{}, nil
}

Thread Safety

It's safe to use both the session agents (those that are provided by the server through messages) and the client concurrently from multiple goroutines, the library automatically synchronizes concurrent operations.

Hooks

Various hooks provide the ability to asynchronously react to different kinds of events and control the behavior of both the client and the server.

Server-side Hooks

  • OnOptions
  • OnClientConnected
  • OnClientDisconnected
  • OnSignal
  • OnRequest
  • OnSessionCreated
  • OnSessionLookup
  • OnSessionClosed

Client-side Hooks

  • OnServerSignal
  • OnSessionCreated
  • OnSessionClosed

© 2018 Roman Sharkov [email protected]

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Functions

GenerateSessionKey returns a URL-safe, base64 encoded securely generated random string.
NewEmptyRequestMessage composes a new request message consisting only of the type and identifier and returns its binary representation.
NewNamelessRequestMessage composes a new nameless (initially without a name) request message and returns its binary representation.
NewReplyMessage composes a new reply message and returns its binary representation.
NewRequestMessage composes a new named request message and returns its binary representation.
NewServer creates a new WebWire server instance.
NewSession generates a new session object generating a cryptographically random secure key.
NewSignalMessage composes a new named signal message and returns its binary representation.
SetupServer sets up a new headed WebWire server with an HTTP server hosting it.

# Constants

EncodingBinary represents unencoded binary data.
EncodingUtf16 represents UTF16 encoding.
EncodingUtf8 represents UTF8 encoding.
Msg identifies the message object stored in the handler context.
MsgCloseSession is sent by the client and represents a request for the destruction of the currently active session.
MsgErrorReply is sent by the server and represents an error-reply to a previously sent request.
MsgMinLenCloseSession represents the minimum session destruction request message length.
MsgMinLenErrorReply represents the minimum error reply message length.
MsgMinLenReply represents the minimum binary/UTF8 encoded reply message length.
MsgMinLenReplyUtf16 represents the minimum UTF16 encoded reply message length.
MsgMinLenRequest represents the minimum binary/UTF8 encoded request message length.
MsgMinLenRequestUtf16 represents the minimum UTF16 encoded request message length.
MsgMinLenRestoreSession represents the minimum session restoration request message length.
MsgMinLenSessionClosed represents the minimum session creation notification message length.
MsgMinLenSessionCreated represents the minimum session creation notification message length.
MsgMinLenSignal represents the minimum binary/UTF8 encoded signal message length.
MsgMinLenSignalUtf16 represents the minimum UTF16 encoded signal message length.
MsgReplyBinary represents a reply with a binary payload.
MsgReplyUtf16 represents a reply with a UTF16 encoded payload.
MsgReplyUtf8 represents a reply with a UTF8 encoded payload.
MsgRequestBinary represents a request with binary payload.
MsgRequestUtf16 represents a request with a UTF16 encoded payload.
MsgRequestUtf8 represents a request with a UTF8 encoded payload.
MsgRestoreSession is sent by the client to request session restoration.
MsgSessionClosed is sent by the server to notify the client about the session destruction.
MsgSessionCreated is sent by the server to notify the client about the session creation.
MsgSignalBinary represents a signal with binary payload.
MsgSignalUtf16 represents a signal with UTF16 encoded payload.
MsgSignalUtf8 represents a signal with UTF8 encoded payload.

# Structs

Client represents a client connected to the server.
Error represents an error returned in case of a wrong request.
Hooks represents all callback hook functions.
Message represents a WebWire protocol message.
Options represents the options for a headed server setup.
Payload represents an encoded message payload.
Server represents a headless WebWire server instance, where headless means there's no HTTP server that's hosting it.
Session represents a session object.

# Type aliases

ContextKey represents the identifiers of objects passed to the handlers context.
PayloadEncoding represents the type of encoding of the message payload.