Skip to content
This repository has been archived by the owner on Aug 28, 2023. It is now read-only.

romshark/webwire-go-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


WebWire

WebWire for Go
An asynchronous duplex messaging library

Travis CI: build status Coveralls: Test Coverage GoReportCard CodeBeat: Status CodeClimate: Maintainability
Licence: MIT GoDoc

OpenCollective


webwire-go-client provides a client implementation for the open-source webwire protocol.

Table of Contents

Installation

Choose any stable release from the available release tags and copy the source code into your project's vendor directory: $YOURPROJECT/vendor/github.com/qbeon/webwire-go-client.

Dep

If you're using dep, just use dep ensure to add a specific version of webwire-go-client including all its transitive dependencies to your project: dep ensure -add github.com/qbeon/[email protected].

Go Get

You can also use go get: go get github.com/qbeon/webwire-go-client but beware that this will fetch the latest commit of the master branch which is currently not yet considered a stable release branch. It's therefore recommended to use dep instead.

Contribution

Contribution of any kind is always welcome and appreciated, check out our Contribution Guidelines for more information!

Maintainers

Maintainer Role Specialization
Roman Sharkov Core Maintainer Dev (Go, JavaScript)
Daniil Trishkin CI Maintainer DevOps

WebWire Binary Protocol

WebWire is built for speed and portability implementing an open source binary protocol (see here for further details).

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,
// this will block the goroutine until either a reply is received
// or the default timeout triggers (if there is one)
reply, err := client.Request(
	context.Background(), // No cancelation, default timeout
	nil,                  // No name
	wwr.Payload{
		Data: []byte("sudo rm -rf /"), // Binary request payload
	},
)
defer reply.Close() // Close the reply
if err != nil {
	// Oh oh, the request failed for some reason!
}
reply.PayloadUtf8() // Here we go!

Requests will respect cancelable contexts and deadlines

cancelableCtx, cancel := context.WithCancel(context.Background())
defer cancel()
timedCtx, cancelTimed := context.WithTimeout(cancelableCtx, 1*time.Second)
defer cancelTimed()

// Send a cancelable request to the server with a 1 second deadline
// will block the goroutine for 1 second at max
reply, err := client.Request(timedCtx, nil, wwr.Payload{
	Encoding: wwr.EncodingUtf8,
	Data:     []byte("hurry up!"),
})
defer reply.Close()

// Investigate errors manually...
switch err.(type) {
case wwr.ErrCanceled:
	// Request was prematurely canceled by the sender
case wwr.ErrDeadlineExceeded:
	// Request timed out, server didn't manage to reply
	// within the user-specified context deadline
case wwr.TimeoutErr:
	// Request timed out, server didn't manage to reply
	// within the specified default request timeout duration
case nil:
	// Replied successfully
}

// ... or check for a timeout error the easier way:
if err != nil {
	if wwr.IsTimeoutErr(err) {
		// Timed out due to deadline excess or default timeout
	} else {
		// Unexpected error
	}
}

reply // Just in time!

Client-side Signals

Individual clients can send signals to the server. Signals are one-way messages guaranteed to arrive, though they're not guaranteed to be processed like requests are. In cases such as when the server is being shut down, incoming signals are ignored by the server and dropped while requests will acknowledge the failure.

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

Server-side Signals

The server also can send signals to individual connected clients.

OnSignal implements the wwrclt.Implementation interface
func (c *ClientImplementation) OnSignal(msg wwr.Message) {
  // A server-side signal was received
  msg.PayloadEncoding() // Signal payload encoding
  msg.Payload()         // Signal payload data
}

Namespaces

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

reply, err := client.Request(
	context.Background(),
	[]byte("request name"),
	wwr.Payload{},
)
OnSignal implements the wwrclt.Implementation interface
func (c *ClientImplementation) OnSignal(msg wwr.Message) {
	switch msg.Name() {
	case "event A":
		// handle signal A
	case "event B":
		// handle signal 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 a way to authenticate a connection.

OnSessionCreated implements the wwrclt.Implementation interface
func (c *ClientImplementation) OnSessionCreated(newSession *wwr.Session) {
	// A session was created on this connection
}

OnDisconnected implements the wwrclt.Implementation interface
func (c *ClientImplementation) OnDisconnected() {
	// The session of this connection was closed
	// by either the client, or the server
}

Automatic Session Restoration

The client will automatically try to restore the previously opened session during connection establishment when getting disconnected without explicitly closing the session before.

// Will automatically restore the previous session if there was any
err := client.Connect()

The session can also be restored manually given its key assuming the server didn't yet delete it. Session restoration will fail and return an error if the provided key doesn't correspond to any active session on the server or else if there's another active session already assigned to this client.

err := client.RestoreSession([]byte("yoursessionkeygoeshere"))

Automatic Connection Maintenance

The WebWire client maintains the connection fully automatically to guarantee maximum connection uptime. It will automatically reconnect in the background whenever the connection is lost.

The only things to remember are:

  • Client API methods such as client.Request and client.RestoreSession will timeout if the server is unavailable for the entire duration of the specified timeout and thus the client fails to reconnect.
  • client.Signal will immediately return a ErrDisconnected error if there's no connection at the time the signal was sent.

This feature is entirely optional and can be disabled at will which will cause client.Request and client.RestoreSession to immediately return a ErrDisconnected error when there's no connection at the time the request is made.

Security

If the webwire server is using a TLS protected transport implementation the client can establish a secure connection to prevent man-in-the-middle attacks as well as to verify the identity of the server. To connect the client to a webwire server that's using a TLS protected transport implementation such as webwire-go-gorilla over TLS the appropriate transport implementation needs to be used:

connection, err := wwrclt.NewClient(
	clientImplementation,
	wwrclt.Options{/*...*/},
	&wwrgorilla.ClientTransport{
		ServerAddress: serverAddr,
		Dialer:        gorillaws.Dialer{
			TLSClientConfig: &tls.Config{},
		},
	},
)

© 2018 Roman Sharkov [email protected]

About

A webwire-go client implementation

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages