spvchannels

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Mar 17, 2022 License: ISC Imports: 12 Imported by: 3

README

go-spvchannels

Release Go Go

Report codecov Go Sponsor Donate Mergify Status


Go SPV Channels is a golang implementation of the SPV Channels Server.

The library implement all rest api endpoints served in SPV Channels Server and the websocket client to listen new message notifications in real time.

Table of Contents

Installation

go get github.com/libsv/go-spvchannels

Run tests

Run unit test

go clean -testcache && go test -v ./...

To run integration tests, make sure you have docker-compose up -d on your local machine, then run

go clean -testcache && go test  -race -v -tags=integration ./...

Setup Local SPV Channels server

Creating SSL key for secure connection

Following the tutorial in the SPV Channels Server, we first create the certificate using openssl:

terminal $> openssl req -x509 -out localhost.crt -keyout localhost.key -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -extensions EXT -config <( printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
terminal $> openssl pkcs12 -export -out devkey.pfx -inkey localhost.key -in localhost.crt # use devkey as password

That will create the devkey.pfx with password devkey. We then write a docker-compose.yml file following the tutorial.

Launch local SPV Channels Server :
docker-compose up -d
Create an account

We then need to create a SPV Channels account on the server

docker exec spvchannels ./SPVChannels.API.Rest -createaccount spvchannels_dev dev dev
Usage with swagger

The SPV Channels Server run by docker-compose.yml listen on localhost:5010. We can start playing with the endpoints using swagger, i.e in browser, open https://localhost:5010/swagger/index.html

From this page, there are a link /swagger/v1/swagger.json to export swagger file

Usage with Postman

Interacting with browser might have some difficulty related to adding certificate to the system. It might be easier to use Postman to interact as Postman has a easy possibility to disable SSL certificate check to ease development propose.

From Postman, import the file devconfig/postman.json and set the environment config as follow

VARIABLE INITIAL VALUE
URL_PORT localhost:5010
ACCOUNT 1
USERNAME dev
PASSWORD dev

These environment variable are used as template to populate values in the postman.json file. There are a few more environment variable to define (look into the json file) that will depend to the endpoint and value created during the experience:

VARIABLE INITIAL VALUE
CHANNEL_ID .. to define ..
TOKEN_ID .. to define ..
TOKEN_VALUE .. to define ..
MSG_SEQUENCE .. to define ..
NOTIFY_TOKEN .. to define ..

License

License

Documentation

Overview

Package spvchannels is an golang implementation of the spv channel client.

It implement all the rest api endpoints and the weboscket client to listen to notifications from channel in real time.

Using the combination of the notification websocket and the rest api to pull unread message, users can have a real time message channel.

SPV Channel BRFC

https://github.com/bitcoin-sv-specs/brfc-spvchannels

SPV Channel server

https://github.com/bitcoin-sv/spvchannels-reference

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ChannelCreateReply

type ChannelCreateReply struct {
	ID           string    `json:"id"`
	Href         string    `json:"href"`
	PublicRead   bool      `json:"public_read"`
	PublicWrite  bool      `json:"public_write"`
	Sequenced    bool      `json:"sequenced"`
	Locked       bool      `json:"locked"`
	Head         int       `json:"head"`
	Retention    Retention `json:"retention"`
	AccessTokens []struct {
		ID          string `json:"id"`
		Token       string `json:"token"`
		Description string `json:"description"`
		CanRead     bool   `json:"can_read"`
		CanWrite    bool   `json:"can_write"`
	} `json:"access_tokens"`
}

ChannelCreateReply hold data for create channel reply It contains the new channel id, it's properties and the first default created token to allow authentification the communication on this channel

type ChannelCreateRequest

type ChannelCreateRequest struct {
	AccountID   int64     `json:"accountid"`
	PublicRead  bool      `json:"public_read"`
	PublicWrite bool      `json:"public_write"`
	Sequenced   bool      `json:"sequenced"`
	Retention   Retention `json:"retention"`
}

ChannelCreateRequest hold data for create channel request The request should contain the account id, and optionally some channel properties to be initialised.

type ChannelDeleteRequest

type ChannelDeleteRequest struct {
	AccountID int64  `json:"accountid"`
	ChannelID string `json:"channelid"`
}

ChannelDeleteRequest hold data for delete channel request The request contains the account and channel identification

type ChannelReply

type ChannelReply struct {
	ID          string `json:"id"`
	Href        string `json:"href"`
	PublicRead  bool   `json:"public_read"`
	PublicWrite bool   `json:"public_write"`
	Sequenced   bool   `json:"sequenced"`
	Locked      bool   `json:"locked"`
	Head        int    `json:"head"`
	Retention   struct {
		MinAgeDays int  `json:"min_age_days"`
		MaxAgeDays int  `json:"max_age_days"`
		AutoPrune  bool `json:"auto_prune"`
	} `json:"retention"`
	AccessTokens []struct {
		ID          string `json:"id"`
		Token       string `json:"token"`
		Description string `json:"description"`
		CanRead     bool   `json:"can_read"`
		CanWrite    bool   `json:"can_write"`
	} `json:"access_tokens"`
}

ChannelReply hold data for get channel reply

type ChannelRequest

type ChannelRequest struct {
	AccountID int64  `json:"accountid"`
	ChannelID string `json:"channelid"`
}

ChannelRequest hold data for get channel request

type ChannelUpdateReply

type ChannelUpdateReply struct {
	PublicRead  bool `json:"public_read"`
	PublicWrite bool `json:"public_write"`
	Locked      bool `json:"locked"`
}

ChannelUpdateReply hold data for update channel reply If successful, the reply contains the confirmed updated properties

type ChannelUpdateRequest

type ChannelUpdateRequest struct {
	AccountID   int64  `json:"accountid"`
	ChannelID   string `json:"channelid"`
	PublicRead  bool   `json:"public_read"`
	PublicWrite bool   `json:"public_write"`
	Locked      bool   `json:"locked"`
}

ChannelUpdateRequest hold data for update channel request. The request contains the account and channel identification, And the properties values to be updated. These properties defines common permission for the channel

type ChannelsReply

type ChannelsReply struct {
	Channels []struct {
		ID           string    `json:"id"`
		Href         string    `json:"href"`
		PublicRead   bool      `json:"public_read"`
		PublicWrite  bool      `json:"public_write"`
		Sequenced    bool      `json:"sequenced"`
		Locked       bool      `json:"locked"`
		Head         int       `json:"head"`
		Retention    Retention `json:"retention"`
		AccessTokens []struct {
			ID          string `json:"id"`
			Token       string `json:"token"`
			Description string `json:"description"`
			CanRead     bool   `json:"can_read"`
			CanWrite    bool   `json:"can_write"`
		} `json:"access_tokens"`
	} `json:"channels"`
}

ChannelsReply hold data for get channels reply. It is a list of channel's detail

type ChannelsRequest

type ChannelsRequest struct {
	AccountID int64 `json:"accountid"`
}

ChannelsRequest hold data for get channels request for a particular account

type Client

type Client struct {
	HTTPClient HTTPClient
	// contains filtered or unexported fields
}

Client hold rest api configuration and http connection

func NewClient

func NewClient(opts ...SPVConfigFunc) *Client

NewClient create a new rest api client by providing functional config settings

Example of usage :

client := spv.NewClient(
	spv.WithBaseURL("localhost:5010"),
	spv.WithVersion("v1"),
	spv.WithUser("dev"),
	spv.WithPassword("dev"),
	spv.WithInsecure(),
)

The full list of functional settings for a rest client are :

To disable the TSL certificate check ( used in dev only )

WithInsecure()

To set the base url of the server

WithBaseURL(url string)

To set the version string of the rest api

WithVersion(v string)

To set the user's name for basic authentification

WithUser(userName string)

To set the user's password for the basic authentification

WithPassword(p string)

To set the brearer token authentification (this will ignore the basic authentification if set)

WithToken(t string)

func (*Client) Channel

func (c *Client) Channel(ctx context.Context, r ChannelRequest) (*ChannelReply, error)

Channel get single channel's detail for a particular account

func (*Client) ChannelCreate

func (c *Client) ChannelCreate(ctx context.Context, r ChannelCreateRequest) (*ChannelCreateReply, error)

ChannelCreate create a new channel for a particular account

func (*Client) ChannelDelete

func (c *Client) ChannelDelete(ctx context.Context, r ChannelDeleteRequest) error

ChannelDelete delete the channel a particular channel. It return nothing, which is a 204 http code (No Content)

func (*Client) ChannelUpdate

func (c *Client) ChannelUpdate(ctx context.Context, r ChannelUpdateRequest) (*ChannelUpdateReply, error)

ChannelUpdate update the channel's properties.

func (*Client) Channels

func (c *Client) Channels(ctx context.Context, r ChannelsRequest) (*ChannelsReply, error)

Channels get the list of channels with detail for a particular account

func (*Client) MessageDelete

func (c *Client) MessageDelete(ctx context.Context, r MessageDeleteRequest) error

MessageDelete delete a message

The request should use bearer token authentification method. The token is provided by the TokenCreate endpoint

func (*Client) MessageHead

func (c *Client) MessageHead(ctx context.Context, r MessageHeadRequest) error

MessageHead send HEAD message request. It request the max sequence for a particular channel

The request should use bearer token authentification method. The token is provided by the TokenCreate endpoint

func (*Client) MessageMark

func (c *Client) MessageMark(ctx context.Context, r MessageMarkRequest) error

MessageMark mark a message

The request should use bearer token authentification method. The token is provided by the TokenCreate endpoint

func (*Client) MessageWrite

func (c *Client) MessageWrite(ctx context.Context, r MessageWriteRequest) (*MessageWriteReply, error)

MessageWrite write a message to a particular channel

The request should use bearer token authentification method. The token is provided by the TokenCreate endpoint

func (*Client) Messages

func (c *Client) Messages(ctx context.Context, r MessagesRequest) (MessagesReply, error)

Messages get messages list. It can query read/unread messages.

The request should use bearer token authentification method. The token is provided by the TokenCreate endpoint

func (*Client) Token

func (c *Client) Token(ctx context.Context, r TokenRequest) (*TokenReply, error)

Token get the token's detail.

func (*Client) TokenCreate

func (c *Client) TokenCreate(ctx context.Context, r TokenCreateRequest) (*TokenCreateReply, error)

TokenCreate create a new token for a particular account and channel

It is typically used when and admin/orchestrator need to create a communication channel for a group of 2 or more peers.

He then create a channel and a list of token, then give the tokens to each peers so they can communicate through the channel

func (*Client) TokenDelete

func (c *Client) TokenDelete(ctx context.Context, r TokenDeleteRequest) error

TokenDelete delete a particular token

It is typically used when an admin create a temporary communication capability for a particular user on a channel,

After the user has finished he usage of the channel, the admin then delete the token

func (*Client) Tokens

func (c *Client) Tokens(ctx context.Context, r TokensRequest) (*TokensReply, error)

Tokens get the list of tokens. It return a full list of tokens for a particular account id and channel id

type ErrWSClose

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

ErrWSClose can be returned by a NotificationHandlerFunc to instruct the socket client that we are finished processing messages and to close.

This could be emitted as a result of a server sending a message with a payload of 'close stream' or equivalent.

type ErrorHandlerFunc

type ErrorHandlerFunc func(err error)

ErrorHandlerFunc is a callback to handle the error after processing the message

err : the error to handle

type HTTPClient

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

HTTPClient is the interface for http client.

type MessageDeleteRequest

type MessageDeleteRequest struct {
	ChannelID string `json:"channelid"`
	Sequence  int64  `json:"sequence"`
}

MessageDeleteRequest hold data for delete message request A particular message is identified by its sequence number and the channel id in which it belong to

type MessageHeadRequest

type MessageHeadRequest struct {
	ChannelID string `json:"channelid"`
}

MessageHeadRequest hold data for HEAD message request It request the max sequence for a particular channel

type MessageMarkRequest

type MessageMarkRequest struct {
	ChannelID string `json:"channelid"`
	Sequence  int64  `json:"sequence"`
	Older     bool   `json:"older"`
	Read      bool   `json:"read"`
}

MessageMarkRequest hold data for mark message request

A particular message is identified by its sequence number and the channel id in which it belong to

type MessageWriteReply

type MessageWriteReply struct {
	Sequence    int64  `json:"sequence"`
	Received    string `json:"received"`
	ContentType string `json:"content_type"`
	Payload     string `json:"payload"`
}

MessageWriteReply hold data for write message reply It contains the id of the message in the database, the received timestamp, the content type, and the base64 encoding of the message content

type MessageWriteRequest

type MessageWriteRequest struct {
	ChannelID string `json:"channelid"`
	Message   string `json:"message"`
}

MessageWriteRequest hold data for write message request

type MessagesReply

type MessagesReply []MessageWriteReply

MessagesReply hold data for get messages reply

type MessagesRequest

type MessagesRequest struct {
	ChannelID string `json:"channelid"`
	UnRead    bool   `json:"unread"`
}

MessagesRequest hold data for get messages request

type MockClient

type MockClient struct {
	MockDo func(req *http.Request) (*http.Response, error)
}

MockClient mocks the http client.

func (*MockClient) Do

func (m *MockClient) Do(req *http.Request) (*http.Response, error)

Do implement the mock of Do method for http client interface

type NotificationHandlerFunc

type NotificationHandlerFunc = func(ctx context.Context, t int, msg []byte, err error) error

NotificationHandlerFunc is a callback to process websocket messages

ctx : the handling context
t   : message type
msg : message content
err : message error

type Retention

type Retention struct {
	MinAgeDays int  `json:"min_age_days"`
	MaxAgeDays int  `json:"max_age_days"`
	AutoPrune  bool `json:"auto_prune"`
}

Retention the data retention policy of a channel.

type SPVConfigFunc

type SPVConfigFunc func(c *spvConfig)

SPVConfigFunc set the rest api configuration

func WithBaseURL

func WithBaseURL(url string) SPVConfigFunc

WithBaseURL provide base url (domain:port) for the rest api

func WithChannelID

func WithChannelID(id string) SPVConfigFunc

WithChannelID provide channel id for websocket notification

func WithErrorHandler

func WithErrorHandler(e ErrorHandlerFunc) SPVConfigFunc

WithErrorHandler can be provided with a function used to handle errors when processing Socket message callbacks.

Here you could log the errors, send to another system to drop them etc.

func WithInsecure

func WithInsecure() SPVConfigFunc

WithInsecure skip the TLS check (for dev only)

func WithNoTLS

func WithNoTLS() SPVConfigFunc

WithNoTLS use http and ws in place of https and wss (for dev only)

func WithPassword

func WithPassword(p string) SPVConfigFunc

WithPassword provide password for rest basic authentification

func WithPath added in v0.0.2

func WithPath(path string) SPVConfigFunc

WithPath provide a path on the hosting service (/peerchannels)

func WithToken

func WithToken(t string) SPVConfigFunc

WithToken provide token for rest token bearer authentification

func WithUser

func WithUser(userName string) SPVConfigFunc

WithUser provide username for rest basic authentification

func WithVersion

func WithVersion(v string) SPVConfigFunc

WithVersion provide version string for the rest api

func WithWebsocketCallBack

func WithWebsocketCallBack(f NotificationHandlerFunc) SPVConfigFunc

WithWebsocketCallBack provide the callback function to process notification messages

type TokenCreateReply

type TokenCreateReply struct {
	ID          string `json:"id"`
	Token       string `json:"token"`
	Description string `json:"description"`
	CanRead     bool   `json:"can_read"`
	CanWrite    bool   `json:"can_write"`
}

TokenCreateReply hold data for create token reply It hold the id and value of the new token, and some of the token's properties

type TokenCreateRequest

type TokenCreateRequest struct {
	AccountID   int64  `json:"accountid"`
	ChannelID   string `json:"channelid"`
	Description string `json:"description"`
	CanRead     bool   `json:"can_read"`
	CanWrite    bool   `json:"can_write"`
}

TokenCreateRequest hold data for create token request The request should contains existing account and channel id, with optionally some description and permission properties attached to the token

type TokenDeleteRequest

type TokenDeleteRequest struct {
	AccountID int64  `json:"accountid"`
	ChannelID string `json:"channelid"`
	TokenID   string `json:"tokenid"`
}

TokenDeleteRequest hold data for delete token request A token belong to a particular channel, which again belong to a particular account. To identify a token, it needs to provide account id, channel id, and token id

type TokenReply

type TokenReply struct {
	ID          string `json:"id"`
	Token       string `json:"token"`
	Description string `json:"description"`
	CanRead     bool   `json:"can_read"`
	CanWrite    bool   `json:"can_write"`
}

TokenReply hold data for get token reply The reply contains

- token id (a number which is uniquely identified in the database) - token value, which will be used for authentification to read/write messages on the channel - some permission properties attached to the token

type TokenRequest

type TokenRequest struct {
	AccountID int64  `json:"accountid"`
	ChannelID string `json:"channelid"`
	TokenID   string `json:"tokenid"`
}

TokenRequest hold data for get token request A token belong to a particular channel, which again belong to a particular account. To identify a token, it needs to provide account id, channel id, and token id

type TokensReply

type TokensReply []TokenReply

TokensReply hold data for get tokens reply. It is a list of detail for tokens

type TokensRequest

type TokensRequest struct {
	AccountID int64  `json:"accountid"`
	ChannelID string `json:"channelid"`
}

TokensRequest hold data for get tokens request The request contains the account id and channel id.

type WSClient

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

WSClient is the structure holding the

  • websocket configuration
  • websocket connection
  • number of received notifications

func NewWSClient

func NewWSClient(opts ...SPVConfigFunc) (*WSClient, error)

NewWSClient create a new connected websocket client by providing fuctional config settings. After being created (connected), the websocket client is ready to listen to new messages

Example of usage :

ws := spv.NewWSClient(
	spv.WithBaseURL("localhost:5010"),
	spv.WithVersion("v1"),
	spv.WithChannelID(channelid),
	spv.WithToken(tok),
	spv.WithInsecure(),
	spv.WithWebsocketCallBack(PullUnreadMessages),
)

The full list of functional settings for a websocket client are :

To disable the TSL certificate check ( used in dev only )

WithInsecure()

To set the base url of the server

WithBaseURL(url string)

To set the version string of the server

WithVersion(v string)

To set channel to be notified

WithChannelID(channelid string)

To set the token that allow the socket connection

WithToken(tok string)

To specify a callback function to process the notification

WithWebsocketCallBack(p PullUnreadMessages)

func (*WSClient) Close

func (c *WSClient) Close()

Close stops reading any notification and closes the websocket Usually it is called from a separate goroutine

func (*WSClient) Run

func (c *WSClient) Run()

Run establishes the connection and start listening the notification stream process the notification if a callback is provided

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

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