service

package module
v0.18.0 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2019 License: BSD-3-Clause Imports: 19 Imported by: 5

README

service Latest Tag Build Status Go Report Card GoDoc

The robµlab service library is a convenience wrapper for easy microservice creation.


How to add to your project?

Run this in your project

$ burrow get github.com/embeddedenterprises/service

and use the library in your sourcecode like this.

package main

import (
	"os"

	"github.com/EmbeddedEnterprises/service"
	"github.com/gammazero/nexus/client"
	"github.com/op/go-logging"
)

func main() {
	srv := service.New(service.Config{
		Name:          "example",
		Serialization: client.MSGPACK,
		Version:       "0.1.0",
		Description:   "Simple example microservice from the documentation.",
	})
	srv.Connect()

	// register and subscribe here

	srv.Run()
	os.Exit(service.ExitSuccess)
}

Running the examples

Simple example

First you have to start a WAMP router in the background (i.e. crossbar.io or nexus):

$ docker run -p 127.0.0.1:8080:8080 --name crossbar --rm crossbario/crossbar:latest

The you can run the example service like this:

$ burrow run --example simple -- -b ws://localhost:8080/ws -r realm1
Authentication example

First you have to start a WAMP router configured with authentication in the background:

$ docker run -p 127.0.0.1:8080:8080 \
    --mount type=bind,source=$(pwd)/example/auth/crossbar.json,target=/node/.crossbar/config.json \
    --name crossbar --rm crossbario/crossbar:latest

Then you can run the auth example like this:

$ burrow run --example auth -- -b ws://localhost:8080/ws -u WRONG
# Should yield 'no such principal with authid WRONG'

$ burrow run --example auth -- -b ws://localhost:8080/ws -u CORRECT
# Should yield 'authentication failed'

$ burrow run --example auth -- -b ws://localhost:8080/ws -u CORRECT -p CORRECT
# Should work just like the 'simple' example.

The service library supports several authentication modes:

  • Anonymous (i.e. no username and password is specified), the client is authenticated using other features, like remote-ip or some specific socket
  • Ticket (normal username and password)
  • TLS Client Auth, which provides encryption and authentication utilizing a PKI.

Documentation

Index

Examples

Constants

View Source
const (
	// ExitSuccess indicates that the service terminated without an error.
	ExitSuccess int = iota

	// ExitArgument indicates that the service terminated early as an argument was missing or malformed.
	ExitArgument

	// ExitService indicates that the service implementation ran into an unhandled error and could not be recovered.
	ExitService

	// ExitConnect indicates that the service failed to connect to the broker.
	ExitConnect

	// ExitRegistration indicates that the service failed to register or subscribe for a given topic or method.
	ExitRegistration
)
View Source
const BinaryDataExtension byte = 42

BinaryDataExtension is the extension number used to correctly encode raw binary data in msgpack. This is required because most msgpack implementations don't distinguish between strings and byte arrays, but JSON does, which leads to invalid utf-8 characters in JSON strings. This extension allows us to pass binary messages from a msgpack client to a JSON client.

View Source
const EnvBrokerURL string = "SERVICE_BROKER_URL"

EnvBrokerURL defines the environment variable name for the broker url definition.

View Source
const EnvConnectTimeout string = "SERVICE_CONNECT_TIMEOUT"

EnvConnectTimeout defines the environment variable name for the connect timeout definition.

View Source
const EnvLogFormat string = "SERVICE_LOGFORMAT"

EnvLogFormat defines the environment variable name for the logging format string definition.

View Source
const EnvPassword string = "SERVICE_PASSWORD"

EnvPassword defines the environment variable name for the password the service is using to authenticate on the broker.

View Source
const EnvPingEnabled string = "SERVICE_ENABLE_PING"

EnvPingEnabled defines the environment variable name for the flag indicating whether server ping should be enabled

View Source
const EnvPingEndpoint string = "SERVICE_PING_ENDPOINT"

EnvPingEndpoint defines the environment variable name for the ping procedure to call

View Source
const EnvPingInterval string = "SERVICE_PING_INTERVAL"

EnvPingInterval defines the environment variable name for the ping interval definition

View Source
const EnvRealm string = "SERVICE_REALM"

EnvRealm defines the environment variable name for the realm definition.

View Source
const EnvTLSClientCertFile string = "TLS_CLIENT_CERT"

EnvTLSClientCertFile defines the environment variable name for the TLS client certificate public key to present to the router.

View Source
const EnvTLSClientKeyFile string = "TLS_CLIENT_KEY"

EnvTLSClientKeyFile defines the environment variable name for the TLS client certificate private key to present to the router.

View Source
const EnvTLSServerCertFile string = "TLS_SERVER_CERT"

EnvTLSServerCertFile defines the environment variable name for the TLS server certificate public key to verify the server certificate against.

View Source
const EnvUsername string = "SERVICE_USERNAME"

EnvUsername defines the environment variable name for the username the service is using to authenticate on the broker.

View Source
const Version string = "0.18.0"

Version defines the git tag this code is built with

Variables

This section is empty.

Functions

func FunctionTimeout added in v0.17.3

func FunctionTimeout(fn func() error, timeout time.Duration) error

FunctionTimeout implements a high-level timeout for functions

func IsRPCError added in v0.13.0

func IsRPCError(err error) bool

IsRPCError checks whether the given error is a wamp RPC error

func IsSpecificRPCError added in v0.13.0

func IsSpecificRPCError(err error, uri wamp.URI) bool

IsSpecificRPCError checks whether the given error is a wamp RPC error witch the expected error URI

func ReturnEmpty added in v0.12.0

func ReturnEmpty() *client.InvokeResult

ReturnEmpty constructs an empty wamp response, the equivalent of void. Its primary use is to save boilerplate code.

func ReturnError added in v0.12.0

func ReturnError(uri string) *client.InvokeResult

ReturnError constructs a wamp response which contains an error with the specified URI. Its primary use is to save boilerplate code.

func ReturnValue added in v0.12.0

func ReturnValue(value interface{}) *client.InvokeResult

ReturnValue constructs a wamp response which contains just one arbitrary value. Its primary use is to save boilerplate code.

Types

type CallerID added in v0.15.0

type CallerID struct {
	Session  wamp.ID  `call:"caller" publish:"publisher"`
	Username string   `call:"caller_authid" publish:"publisher_authid"`
	Role     []string `call:"caller_authrole" publish:"publisher_authrole"`
}

CallerID represents a caller of a wamp RPC invocation

func ParseCallerID added in v0.15.0

func ParseCallerID(details wamp.Dict) (*CallerID, error)

ParseCallerID extracts caller information from the details dictionary of a wamp RPC invocation

func ParsePublisherID added in v0.17.0

func ParsePublisherID(details wamp.Dict) (*CallerID, error)

ParsePublisherID extracts caller information from the details dictionary of a wamp publication

func (*CallerID) HasAnyRole added in v0.15.0

func (c *CallerID) HasAnyRole(test []string) bool

HasAnyRole checks whether the caller object has any of the specified roles

type Config

type Config struct {
	Name          string
	Version       string
	Description   string
	Serialization serialize.Serialization
}

Config is a structure describing the service. It is used to describe the service when running with --version or --help. Values passed in the config structure can't be overridden at runtime.

type Error

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

Error is the holder of an inner error and a translated `ErrorKind`. Instances may be created with `NewError` or `NewErrorFrom`.

func NewError

func NewError(kind ErrorKind) *Error

NewError creates a new error from a given error kind.

func NewErrorFrom

func NewErrorFrom(kind ErrorKind, inner error) *Error

NewErrorFrom translates an inner to a given error kind and holds the inner error.

func (*Error) Error

func (e *Error) Error() string

type ErrorKind

type ErrorKind int

ErrorKind describes the type of an error that occurred during the execution of the microservice. It can be used as a basic set of errors that are used by implementors of this service library.

const (
	// ErrorBadArgument indicates that a given argument does not meet its requirements.
	ErrorBadArgument ErrorKind = iota

	// ErrorNotAvailable indicates that a requested resource is not available.
	ErrorNotAvailable

	// ErrorNotEnoughData indicates that the provided data is not enough.
	ErrorNotEnoughData

	// ErrorUnexpectedData indicates that the provided data is in an unexpected format.
	ErrorUnexpectedData

	// ErrorTooMuchData indicates that the provided data is too much.
	ErrorTooMuchData

	// ErrorOutOfRange indicates that a given index is out of range.
	ErrorOutOfRange

	// ErrorTimedOut indicates that a request has timed out.
	ErrorTimedOut

	// ErrorPermissionDenied indicates that the access to a resource was denied.
	ErrorPermissionDenied

	// ErrorNotFound indicates that a given resource could not be found.
	ErrorNotFound

	// ErrorUnreachableLineReached indicates that this code should not be reached as it is not implemented.
	ErrorUnreachableLineReached

	// ErrorThisWorksOnMyMachine indicates that this code needs complicated state to work. Contact your
	// system administrator for details.
	ErrorThisWorksOnMyMachine

	// ErrorItsNotABugItsAFeature indicates that the current behavior is intended. If you did not expect this to
	// happen, contact your system administrator.
	ErrorItsNotABugItsAFeature

	// ErrorAKittenDies indicates that something was nil...
	ErrorAKittenDies
)

type EventSubscription added in v0.9.0

type EventSubscription struct {
	Handler client.EventHandler
	Options wamp.Dict
}

EventSubscription holds a tuple of a `client.EventHandler` and an options map that can be used in the `SubscribeAll` function to subcribe to multiple topics at once.

type HandlerRegistration added in v0.8.0

type HandlerRegistration struct {
	Handler client.InvocationHandler
	Options wamp.Dict
}

HandlerRegistration holds a tuple of a `client.InvocationHandler` and an options map that can be used in the `RegisterAll` function to register multiple method handlers at once.

type RegistrationError added in v0.8.0

type RegistrationError struct {
	ProcedureName string
	Inner         error
}

RegistrationError describes an error that occurred during the registration of a remote procedure call. The struct holds the inner error and the procedure name that failed to register.

type Service

type Service struct {
	Logger *logging.Logger
	Client *client.Client
	// contains filtered or unexported fields
}

Service is a struct that holds all state that is needed to run the service. An instance of this struct is the main object that is used to communicate with the broker backend. Use the `New` function to create a service instance. The instance will give you access to the `Logger` and `Client` object.

func New

func New(defaultConfig Config) *Service

New creates a new service instance from the provided default configuration. The configuration can be overridden with command line arguments or environment variables.

You can look in the `examples` of the source repository for a more detailed example.

This function can exit the program early when

1. A version print was requested by the command line interface.

2. An error occurred while parsing the command line arguments.

3. An internal error occurrs that cannot be recovered.

Example
package main

import (
	"os"

	"github.com/EmbeddedEnterprises/service"
	"github.com/gammazero/nexus/client"
)

func main() {
	srv := service.New(service.Config{
		Name:          "example",
		Serialization: client.MSGPACK,
		Version:       "0.1.0",
		Description:   "Simple example microservice from the documentation.",
	})
	srv.Connect()

	// register and subscribe here

	srv.Run()
	os.Exit(service.ExitSuccess)
}
Output:

func (*Service) Connect

func (srv *Service) Connect()

Connect establishes a connection with the broker and must be called before `Run`!

This function may exit the program early when

1. Logger creation failed.

2. The client failed to join the realm.

func (*Service) RegisterAll added in v0.8.0

func (srv *Service) RegisterAll(procedures map[string]HandlerRegistration) *RegistrationError

RegisterAll can be used to register multiple remote procedure calls at once.

Example
package main

import (
	"context"
	"os"

	"github.com/EmbeddedEnterprises/service"
	"github.com/gammazero/nexus/client"
	"github.com/gammazero/nexus/wamp"
)

func dummyRegistration(_ context.Context, _ wamp.List, _, _ wamp.Dict) *client.InvokeResult {
	return service.ReturnEmpty()
}

func main() {
	srv := service.New(service.Config{
		Name:          "example",
		Serialization: client.MSGPACK,
		Version:       "0.1.0",
		Description:   "Simple example microservice from the documentation.",
	})
	srv.Connect()

	options := wamp.Dict{}
	procedures := map[string]service.HandlerRegistration{
		"example.get_magic":     {Handler: dummyRegistration, Options: options},
		"example.do_stuff":      {Handler: dummyRegistration, Options: options},
		"example.set_something": {Handler: dummyRegistration, Options: options},
	}
	if err := srv.RegisterAll(procedures); err != nil {
		srv.Logger.Criticalf(
			"Failed to register procedure '%s' in broker: %s",
			err.ProcedureName,
			err,
		)
		os.Exit(service.ExitRegistration)
	}

	srv.Run()
	os.Exit(service.ExitSuccess)
}
Output:

func (*Service) Run

func (srv *Service) Run()

Run starts the microservice. This function blocks until the user interrupts the process with a SIGINT. It can be considered as the main loop of the service. This function may be only called once.

This function can exit the program early when

1. The client failed to leave the realm.

2. The client connection failed to close.

func (*Service) SubscribeAll added in v0.8.0

func (srv *Service) SubscribeAll(events map[string]EventSubscription) *SubscriptionError

SubscribeAll can be used to subscribe to multiple topics at once.

Example
package main

import (
	"os"

	"github.com/EmbeddedEnterprises/service"
	"github.com/gammazero/nexus/client"
	"github.com/gammazero/nexus/wamp"
)

func dummySubscription(_ wamp.List, _, _ wamp.Dict) {
}

func main() {
	srv := service.New(service.Config{
		Name:          "example",
		Serialization: client.MSGPACK,
		Version:       "0.1.0",
		Description:   "Simple example microservice from the documentation.",
	})
	srv.Connect()

	options := wamp.Dict{}
	events := map[string]service.EventSubscription{
		"example.goo_happened": {Handler: dummySubscription, Options: options},
		"example.gesus_joined": {Handler: dummySubscription, Options: options},
		"example.no_more_mate": {Handler: dummySubscription, Options: options},
	}
	if err := srv.SubscribeAll(events); err != nil {
		srv.Logger.Criticalf(
			"Failed to subscribe to topic '%s' in broker: %s",
			err.Topic,
			err,
		)
		os.Exit(service.ExitRegistration)
	}

	srv.Run()
	os.Exit(service.ExitSuccess)
}
Output:

type SubscriptionError added in v0.9.0

type SubscriptionError struct {
	Topic string
	Inner error
}

SubscriptionError describes an error that occurred during the subscription on a topic. The struct holds the inner error and the topic name that failed to subscribe.

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

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