gun

package
v0.0.0-...-0096207 Latest Latest
Warning

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

Go to latest
Published: Feb 26, 2019 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package gun is an implementation of the Gun distributed graph database in Go. See https://gun.eco for more information on the Gun distributed graph database.

For common use, create a Gun instance via New, use Scoped to arrive at the desired field, then use Fetch to get/listen to values and/or Put to write values. A simple example is in the README at https://github.com/cretz/esgopeta.

WARNING: This is an early proof-of-concept alpha version. Many pieces are not implemented or don't work.

Index

Constants

View Source
const DefaultOldestAllowedStorageValue = 7 * (60 * time.Minute)

DefaultOldestAllowedStorageValue is the default NewStorageInMem expiration.

View Source
const DefaultPeerSleepOnError = 30 * time.Second

DefaultPeerSleepOnError is the default amount of time that an errored reconnectable peer will wait until trying to reconnect.

Variables

View Source
var ErrLookupOnTopLevel = errors.New("Cannot do put/lookup on top level")

ErrLookupOnTopLevel occurs when a put or remote fetch is attempted on a top-level field.

View Source
var ErrNotObject = errors.New("Scoped value not an object")

ErrNotObject occurs when a put or a fetch is attempted as a child of an existing, non-relation value.

View Source
var ErrStorageNotFound = errors.New("Not found")

ErrStorageNotFound is returned by Storage.Get and sometimes Storage.Put when the field doesn't exist.

View Source
var PeerURLSchemes map[string]func(context.Context, *url.URL) (PeerConn, error)

PeerURLSchemes is the map that maps URL schemes to factory functions to create the connection. Currently "http" and "https" simply defer to "ws" and "wss" respectively. "ws" and "wss" use DialPeerConnWebSocket.

Functions

func DefaultSoulGen

func DefaultSoulGen() string

DefaultSoulGen is the default soul generator. It uses the current time in MS as the first part of the string. However if that MS was already used in this process, the a guaranteed-process-unique-nano-level time is added to the first part. The second part is a random string.

Types

type Config

type Config struct {
	// PeerURLs is the initial set of peer URLs to connect to. This can be empty
	// to not connect to any peers.
	PeerURLs []string
	// Servers is the set of local servers to listen for new peers on. This can
	// be empty to not run any server.
	Servers []Server
	// Storage is the backend storage to locally store data. If not present, a
	// NewStorageInMem is created with a value expiration of
	// DefaultOldestAllowedStorageValue.
	Storage Storage
	// SoulGen is a generator for new soul values. If not present,
	// DefaultSoulGen is used.
	SoulGen func() string
	// PeerErrorHandler is called on every error from or concerning a peer. Not
	// required.
	PeerErrorHandler func(*ErrPeer)
	// PeerSleepOnError is the amount of time we will consider a reconnectable
	// peer "bad" on error before attempting reconnect. If 0 (i.e. not set),
	// DefaultPeerSleepOnError is used.
	PeerSleepOnError time.Duration
	// MyPeerID is the identifier given for this peer to whoever asks. If empty
	// it is set to a random string
	MyPeerID string
	// Tracking is how seen values are updated when they are seen on the wire.
	// When set to TrackingNothing, no seen values will be updated. When set to
	// TrackingRequested (the default), only values that are already in storage
	// will be updated when seen. When set to TrackingEverything, all values
	// seen on the wire will be stored.
	Tracking Tracking
}

Config is the configuration for a Gun instance.

type ConflictResolution

type ConflictResolution int

ConflictResolution is how to handle two values for the same field.

const (
	// ConflictResolutionNeverSeenUpdate occurs when there is no existing value.
	// It means an update should always occur.
	ConflictResolutionNeverSeenUpdate ConflictResolution = iota
	// ConflictResolutionTooFutureDeferred occurs when the update is after our
	// current machine state. It means the update should be deferred.
	ConflictResolutionTooFutureDeferred
	// ConflictResolutionOlderHistorical occurs when the update happened before
	// the existing value's last update. It means it can be noted, but the
	// update should be discarded.
	ConflictResolutionOlderHistorical
	// ConflictResolutionNewerUpdate occurs when the update happened after last
	// update but is not beyond ur current machine state. It means the update
	// should overwrite.
	ConflictResolutionNewerUpdate
	// ConflictResolutionSameKeep occurs when the update happened at the same
	// time and it is lexically not the one chosen. It means the update should
	// be discarded.
	ConflictResolutionSameKeep
	// ConflictResolutionSameUpdate occurs when the update happened at the same
	// time and it is lexically the one chosen. It means the update should
	// overwrite.
	ConflictResolutionSameUpdate
)

func ConflictResolve

func ConflictResolve(existingVal Value, existingState State, newVal Value, newState State, sysState State) ConflictResolution

ConflictResolve checks the existing val/state, new val/state, and the current machine state to choose what to do with the update. Note, the existing val should always exist meaning it will never return ConflictResolutionNeverSeenUpdate.

func (ConflictResolution) IsImmediateUpdate

func (c ConflictResolution) IsImmediateUpdate() bool

IsImmediateUpdate returns true for ConflictResolutionNeverSeenUpdate, ConflictResolutionNewerUpdate, and ConflictResolutionSameUpdate

type ErrPeer

type ErrPeer struct {
	// Err is the error.
	Err error
	// Peer is the peer the error relates to.
	Peer *Peer
}

ErrPeer is an error specific to a peer.

func (*ErrPeer) Error

func (e *ErrPeer) Error() string

type FetchResult

type FetchResult struct {
	// Err is any error on fetch, local or remote. This can be a context error
	// if the fetch's context completes. This is nil on successful fetch.
	//
	// This may be ErrLookupOnTopLevel for a remote fetch of a top-level field.
	// This may be ErrNotObject if the field is a child of a non-relation value.
	Err error
	// Field is the name of the field that was fetched. It is a convenience
	// value for the scope's field this was originally called on.
	Field string
	// Value is the fetched value. This will be nil if Err is not nil. This will
	// also be nil if a peer said the value does not exist. This will also be
	// nil if the value exists but is nil. Use ValueExists to distinguish
	// between the last two cases.
	Value Value
	// State is the conflict state of the value. It may be 0 for errors. It may
	// also be 0 if this is a top-level field.
	State State
	// ValueExists is true if there is no error and the fetched value, nil or
	// not, does exist.
	ValueExists bool
	// Peer is the peer this result is for. This is nil for results from local
	// storage. This may be nil on error.
	Peer *Peer
}

FetchResult is a result of a fetch.

type Gun

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

Gun is the main client/server instance for the database.

func New

func New(ctx context.Context, config Config) (*Gun, error)

New creates a new Gun instance for the given config. The given context is used for all peer connection reconnects now/later, all server servings, and peer message handling. Therefore it should be kept available at least until Close. Callers must still call Close on complete, the completion of the context does not automatically do it.

This returns nil with an error on any initial peer connection failure (and cleans up any other peers temporarily connected to).

func (*Gun) Close

func (g *Gun) Close() error

Close stops all peers and servers and closes the underlying storage.

func (*Gun) Scoped

func (g *Gun) Scoped(ctx context.Context, field string, children ...string) *Scoped

Scoped returns a scoped instance to the given field and children for reading and writing. This is the equivalent of calling the Gun JS API "get" function (sans callback) for each field/child.

type Message

type Message struct {
	Ack  string             `json:"@,omitempty"`
	ID   string             `json:"#,omitempty"`
	To   string             `json:"><,omitempty"`
	Hash json.Number        `json:"##,omitempty"`
	How  string             `json:"how,omitempty"`
	Get  *MessageGetRequest `json:"get,omitempty"`
	Put  map[string]*Node   `json:"put,omitempty"`
	DAM  string             `json:"dam,omitempty"`
	PID  string             `json:"pid,omitempty"`
	OK   int                `json:"ok,omitempty"`
	Err  string             `json:"err,omitempty"`
}

Message is the JSON-encodable message that Gun peers send to each other.

type MessageGetRequest

type MessageGetRequest struct {
	Soul  string `json:"#,omitempty"`
	Field string `json:".,omitempty"`
}

MessageGetRequest is the format for Message.Get.

type Metadata

type Metadata struct {
	// Soul is the unique identifier of this node.
	Soul string `json:"#,omitempty"`
	// State is the conflict state value for each node field.
	State map[string]State `json:">,omitempty"`
}

Metadata is the soul of a node and the state of its values.

type Node

type Node struct {
	// Metadata is the metadata for this node.
	Metadata
	// Values is the set of values (including null) keyed by the field name.
	Values map[string]Value
}

Node is a JSON-encodable representation of a Gun node which is a set of scalar values by name and metadata about those values.

func (*Node) MarshalJSON

func (n *Node) MarshalJSON() ([]byte, error)

MarshalJSON implements encoding/json.Marshaler for Node.

func (*Node) UnmarshalJSON

func (n *Node) UnmarshalJSON(b []byte) error

UnmarshalJSON implements encoding/json.Unmarshaler for Node.

type Peer

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

Peer is a known peer to Gun. It has a single connection. Some peers are "reconnectable" which means due to failure, they may be in a "bad" state awaiting reconnection.

func (*Peer) Close

func (p *Peer) Close() error

Close closes the peer and the connection is connected.

func (*Peer) Closed

func (p *Peer) Closed() bool

Closed is whether the peer is closed.

func (*Peer) Conn

func (p *Peer) Conn() PeerConn

Conn is the underlying PeerConn. This can be nil if the peer is currently "bad" or closed.

func (*Peer) ID

func (p *Peer) ID() string

ID is the identifier of the peer as given by the peer. It is empty if the peer wasn't asked for or didn't give an ID.

func (*Peer) Name

func (p *Peer) Name() string

Name is the name of the peer which is usually the URL.

func (*Peer) String

func (p *Peer) String() string

String is a string representation of the peer including whether it's connected.

type PeerConn

type PeerConn interface {
	// Send sends the given message (and maybe others) to the peer. The context
	// governs just this send.
	Send(ctx context.Context, msg *Message, moreMsgs ...*Message) error
	// Receive waits for the next message (or set of messages if sent at once)
	// from a peer. The context can be used to control a timeout.
	Receive(ctx context.Context) ([]*Message, error)
	// RemoteURL is the URL this peer is connected via.
	RemoteURL() string
	// Close closes this connection.
	Close() error
}

PeerConn is a single peer connection.

func NewPeerConn

func NewPeerConn(ctx context.Context, peerURL string) (PeerConn, error)

NewPeerConn connects to a peer for the given URL.

type PeerConnWebSocket

type PeerConnWebSocket struct {
	Underlying *websocket.Conn
	WriteLock  sync.Mutex
}

PeerConnWebSocket implements PeerConn for a websocket connection.

func DialPeerConnWebSocket

func DialPeerConnWebSocket(ctx context.Context, peerURL *url.URL) (*PeerConnWebSocket, error)

DialPeerConnWebSocket opens a peer websocket connection.

func NewPeerConnWebSocket

func NewPeerConnWebSocket(underlying *websocket.Conn) *PeerConnWebSocket

NewPeerConnWebSocket wraps an existing websocket connection.

func (*PeerConnWebSocket) Close

func (p *PeerConnWebSocket) Close() error

Close implements PeerConn.Close.

func (*PeerConnWebSocket) Receive

func (p *PeerConnWebSocket) Receive(ctx context.Context) ([]*Message, error)

Receive implements PeerConn.Receive.

func (*PeerConnWebSocket) RemoteURL

func (p *PeerConnWebSocket) RemoteURL() string

RemoteURL implements PeerConn.RemoteURL.

func (*PeerConnWebSocket) Send

func (p *PeerConnWebSocket) Send(ctx context.Context, msg *Message, moreMsgs ...*Message) error

Send implements PeerConn.Send.

type PutOption

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

PutOption is the base interface for all options that can be passed to Put.

var PutOptionFailWithoutParent PutOption = putOptionFailWithoutParent{}

PutOptionFailWithoutParent makes Put fail if it would need to lazily create parent relations.

var PutOptionStoreLocalOnly PutOption = putOptionStoreLocalOnly{}

PutOptionStoreLocalOnly makes Put only store locally and then be done.

type PutResult

type PutResult struct {
	// Err is any error on put, local or remote. This can be a context error
	// if the put's context completes. This is nil on successful put.
	//
	// This may be ErrLookupOnTopLevel for a remote fetch of a top-level field.
	// This may be ErrNotObject if the field is a child of a non-relation value.
	Err error
	// Field is the name of the field that was put. It is a convenience value
	// for the scope's field this was originally called on.
	Field string
	// Peer is the peer this result is for. This is nil for results from local
	// storage. This may be nil on error.
	Peer *Peer
}

PutResult is either an acknowledgement or an error for a put.

type Scoped

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

Scoped is a contextual, namespaced field to read or write.

func (*Scoped) Fetch

func (s *Scoped) Fetch(ctx context.Context) <-chan *FetchResult

Fetch fetches and listens for updates on the field and sends them to the resulting channel. This will error if called for a top-level field. The resulting channel is closed on Gun close, context completion, or when FetchDone is called with it. Users should ensure one of the three happen in a reasonable timeframe to stop listening and prevent leaks. This is a shortcut for FetchOneLocal (but doesn't send to channel if doesn't exist) followed by FetchRemote.

This is the equivalent of the Gun JS API "on" function.

func (*Scoped) FetchDone

func (s *Scoped) FetchDone(ch <-chan *FetchResult) bool

FetchDone is called with a channel returned from Fetch or FetchRemote to stop listening and close the channel. It returns true if it actually stopped listening or false if it wasn't listening.

func (*Scoped) FetchOne

func (s *Scoped) FetchOne(ctx context.Context) *FetchResult

FetchOne fetches a single result, trying local first. It is a shortcut for calling FetchOneLocal and if it doesn't exist falling back to FetchOneRemote. This should not be called on a top-level field. The context can be used to timeout the wait.

This is the equivalent of the Gun JS API "once" function.

func (*Scoped) FetchOneLocal

func (s *Scoped) FetchOneLocal(ctx context.Context) *FetchResult

FetchOneLocal gets a local value from storage. For top-level fields, it simply returns the field name as a relation.

func (*Scoped) FetchOneRemote

func (s *Scoped) FetchOneRemote(ctx context.Context) *FetchResult

FetchOneRemote fetches a single result from the first peer that responds. It will not look in storage first. This will error if called for a top-level field. This is a shortcut for calling FetchRemote, waiting for a single value, then calling FetchDone. The context can be used to timeout the wait.

func (*Scoped) FetchRemote

func (s *Scoped) FetchRemote(ctx context.Context) <-chan *FetchResult

FetchRemote fetches and listens for updates on a field only from peers, not via storage. This will error if called for a top-level field. The resulting channel is closed on Gun close, context completion, or when FetchDone is called with it. Users should ensure one of the three happen in a reasonable timeframe to stop listening and prevent leaks.

func (*Scoped) Put

func (s *Scoped) Put(ctx context.Context, val Value, opts ...PutOption) <-chan *PutResult

Put puts a value on the field in local storage. It also sends the put to all peers unless the PutOptionStoreLocalOnly option is present. Each acknowledgement or error will be sent to the resulting channel. Unless the PutOptionFailWithoutParent option is present, this will lazily create all parent relations that do not already exist. This will error if called for a top-level field. The resulting channel is closed on Gun close, context completion, or when PutDone is called with it. Users should ensure one of the three happen in a reasonable timeframe to stop listening for acks and prevent leaks.

This is the equivalent of the Gun JS API "put" function.

func (*Scoped) PutDone

func (s *Scoped) PutDone(ch <-chan *PutResult) bool

PutDone is called with a channel returned from Put to stop listening for acks and close the channel. It returns true if it actually stopped listening or false if it wasn't listening.

func (*Scoped) Scoped

func (s *Scoped) Scoped(ctx context.Context, field string, children ...string) *Scoped

Scoped returns a scoped instance to the given field and children for reading and writing. This is the equivalent of calling the Gun JS API "get" function (sans callback) for each field/child.

func (*Scoped) Soul

func (s *Scoped) Soul(ctx context.Context) (string, error)

Soul returns the current soul of this value relation. It returns a cached value if called before. Otherwise, it does a FetchOne to get the value and return its soul if a relation. If any parent is not a relation or this value exists and is not a relation, ErrNotObject is returned. If this field doesn't exist yet, an empty string is returned with no error. Otherwise, the soul of the relation is returned. The context can be used to timeout the fetch.

type Server

type Server interface {
	// Serve is called by Gun to start the server. It should not return until
	// an error occurs or Close is called.
	Serve() error
	// Accept is called to wait for the next peer connection or if an error
	// occurs while trying.
	Accept() (PeerConn, error)
	// Close is called by Gun to stop and close this server.
	Close() error
}

Server is the interface implemented by servers.

func NewServerWebSocket

func NewServerWebSocket(server *http.Server, upgrader *websocket.Upgrader) Server

NewServerWebSocket creates a new Server for the given HTTP server and given upgrader.

type State

type State float64 // TODO: what if larger?

State represents the conflict state of this value. It is usually the Unix time in milliseconds.

func StateFromTime

func StateFromTime(t time.Time) State

StateFromTime converts a time to a State (i.e. converts to Unix ms).

func StateNow

func StateNow() State

StateNow is the current machine state (i.e. current Unix time in ms).

type Storage

type Storage interface {
	// Get obtains the value (which can be nil) and state from storage for the
	// given field. If the field does not exist, this errors with
	// ErrStorageNotFound.
	Get(ctx context.Context, parentSoul, field string) (Value, State, error)
	// Put sets the value (which can be nil) and state in storage for the given
	// field if the conflict resolution says it should (see ConflictResolve). It
	// also returns the conflict resolution. If onlyIfExists is true and the
	// field does not exist, this errors with ErrStorageNotFound. Otherwise, if
	// the resulting resolution is an immediate update, it is done. If the
	// resulting resolution is deferred for the future, it is scheduled for then
	// but is not even attempted if context is completed or storage is closed.
	Put(ctx context.Context, parentSoul, field string, val Value, state State, onlyIfExists bool) (ConflictResolution, error)
	// Close closes this storage and disallows future gets or puts.
	Close() error
}

Storage is the interface that storage adapters must implement.

func NewStorageInMem

func NewStorageInMem(oldestAllowed time.Duration) Storage

NewStorageInMem creates an in-memory storage that automatically purges values that are older than the given oldestAllowed. If oldestAllowed is 0, it keeps all values forever.

type Tracking

type Tracking int

Tracking is what to do when a value update is seen on the wire.

const (
	// TrackingRequested means any value we have already stored will be updated
	// when seen.
	TrackingRequested Tracking = iota
	// TrackingNothing means no values will be updated.
	TrackingNothing
	// TrackingEverything means every value update is stored.
	TrackingEverything
)

type Value

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

Value is the common interface implemented by all possible Gun values. The possible values of Value are nil and instances of ValueNumber, ValueString, ValueBool, and ValueRelation. They can all be marshaled into JSON.

func ValueDecodeJSON

func ValueDecodeJSON(token json.Token, dec *json.Decoder) (Value, error)

ValueDecodeJSON decodes a single Value from JSON. For the given JSON decoder and last read token, this decodes a Value. The decoder needs to have ran UseNumber. Unrecognized values are errors.

type ValueBool

type ValueBool bool

ValueBool is a representation of a bool Value.

type ValueNumber

type ValueNumber string

ValueNumber is a representation of a number Value. It is typed as a string similar to how encoding/json.Number works since it can overflow numeric types.

func (ValueNumber) Float64

func (v ValueNumber) Float64() (float64, error)

Float64 returns the number as a float64.

func (ValueNumber) Int64

func (v ValueNumber) Int64() (int64, error)

Int64 returns the number as an int64.

func (ValueNumber) String

func (v ValueNumber) String() string

type ValueRelation

type ValueRelation string

ValueRelation is a representation of a relation Value. The value is the soul of the linked node. It has a custom JSON encoding.

func (ValueRelation) MarshalJSON

func (v ValueRelation) MarshalJSON() ([]byte, error)

MarshalJSON implements encoding/json.Marshaler fr ValueRelation.

func (ValueRelation) String

func (v ValueRelation) String() string

type ValueString

type ValueString string

ValueString is a representation of a string Value.

func (ValueString) String

func (v ValueString) String() string

Jump to

Keyboard shortcuts

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