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/ChronosX88/go-gun.
WARNING: This is an early proof-of-concept alpha version. Many pieces are not implemented or don't work.
Index ¶
- Constants
- Variables
- func DefaultSoulGen() string
- type Config
- type ConflictResolution
- type ErrPeer
- type FetchResult
- type Gun
- type Message
- type MessageGetRequest
- type Metadata
- type Node
- type Peer
- type PeerConn
- type PeerConnWebSocket
- type PutOption
- type PutResult
- type Scoped
- func (s *Scoped) Fetch(ctx context.Context) <-chan *FetchResult
- func (s *Scoped) FetchDone(ch <-chan *FetchResult) bool
- func (s *Scoped) FetchOne(ctx context.Context) *FetchResult
- func (s *Scoped) FetchOneLocal(ctx context.Context) *FetchResult
- func (s *Scoped) FetchOneRemote(ctx context.Context) *FetchResult
- func (s *Scoped) FetchRemote(ctx context.Context) <-chan *FetchResult
- func (s *Scoped) Put(ctx context.Context, val Value, opts ...PutOption) <-chan *PutResult
- func (s *Scoped) PutDone(ch <-chan *PutResult) bool
- func (s *Scoped) Scoped(ctx context.Context, field string, children ...string) *Scoped
- func (s *Scoped) Soul(ctx context.Context) (string, error)
- type Server
- type State
- type Storage
- type Tracking
- type Value
- type ValueBool
- type ValueNumber
- type ValueRelation
- type ValueString
Constants ¶
const DefaultOldestAllowedStorageValue = 7 * (60 * time.Minute)
DefaultOldestAllowedStorageValue is the default NewStorageInMem expiration.
const DefaultPeerSleepOnError = 30 * time.Second
DefaultPeerSleepOnError is the default amount of time that an errored reconnectable peer will wait until trying to reconnect.
Variables ¶
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.
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.
var ErrStorageNotFound = errors.New("Not found")
ErrStorageNotFound is returned by Storage.Get and sometimes Storage.Put when the field doesn't exist.
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.
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 ¶
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).
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 ¶
MarshalJSON implements encoding/json.Marshaler for Node.
func (*Node) UnmarshalJSON ¶
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) Conn ¶
Conn is the underlying PeerConn. This can be nil if the peer is currently "bad" or closed.
func (*Peer) ID ¶
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.
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.
type PeerConnWebSocket ¶
PeerConnWebSocket implements PeerConn for a websocket connection.
func DialPeerConnWebSocket ¶
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.
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 ¶
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 ¶
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 ¶
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 ¶
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.
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 ¶
StateFromTime converts a time to a State (i.e. converts to Unix 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 ¶
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 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.
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