awareness

package
v1.0.36 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package awareness implements bounded, ephemeral presence state for a collaboration group.

Awareness is deliberately separate from durable CRDT state: it must never be checkpointed, included in a replica.Frontier, or used as an authorization decision. Each actor owns a monotonically increasing clock. A removal keeps its clock as an in-memory tombstone so a delayed older update cannot bring a disconnected actor back online.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidOptions = errors.New("awareness: invalid options")
	ErrInvalidActor   = errors.New("awareness: invalid actor")
	ErrInvalidState   = errors.New("awareness: invalid state")
	ErrInvalidUpdate  = errors.New("awareness: invalid update")
	ErrResourceLimit  = errors.New("awareness: resource limit exceeded")
	ErrStateConflict  = errors.New("awareness: conflicting update clock")
	ErrClockExhausted = errors.New("awareness: actor clock exhausted")
	ErrOfflineActor   = errors.New("awareness: actor has no online state")
)
View Source
var (
	// ErrNilCallback reports a nil local awareness callback.
	ErrNilCallback = errors.New("awareness: nil callback")
	// ErrSubscriptionLimit reports that local application observation exceeded
	// the Store's configured resource bound.
	ErrSubscriptionLimit = errors.New("awareness: subscription limit exceeded")
	// ErrNilContext reports an expiry loop without an explicit owner lifecycle.
	ErrNilContext = errors.New("awareness: nil context")
	// ErrInvalidExpiryInterval reports a non-positive expiry scheduling interval.
	ErrInvalidExpiryInterval = errors.New("awareness: invalid expiry interval")
)

Functions

This section is empty.

Types

type Callback added in v1.0.25

type Callback func(Event)

Callback receives one Event after Store releases its internal lock. It may call Store methods, but must treat Event and every nested byte slice as immutable. A callback panic stops only that subscription.

type Event added in v1.0.25

type Event struct {
	Version   uint64
	Origin    Origin
	Update    Update
	Active    []Update
	Coalesced uint64
}

Event is one immutable UI snapshot of ephemeral presence. Update is empty for Initial and Expired events; Active is sorted by actor. Every subscriber for one revision receives the same immutable snapshot, avoiding an observer-count multiplier for large presence lists. A slow subscription may skip superseded versions, in which case Coalesced reports how many pending events were replaced.

type ExpiryLoop added in v1.0.25

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

ExpiryLoop is one caller-owned expiry scheduler. Done closes after its context is cancelled; cancelling a parent application context is the only shutdown mechanism, so a Store never retains an unbounded background task.

func (*ExpiryLoop) Done added in v1.0.25

func (loop *ExpiryLoop) Done() <-chan struct{}

Done closes once the expiry scheduler has stopped. It is already closed for a nil loop, matching Subscription's lifecycle behavior.

type Options

type Options struct {
	MaxActors     int
	MaxActorBytes int
	MaxStateBytes int
	// MaxSubscribers bounds local UI observers. It has no wire effect and
	// defaults to 1,024 when omitted from an otherwise valid Options value.
	MaxSubscribers int
	Timeout        time.Duration
}

Options sets the resource and liveness boundaries for one awareness group. MaxStateBytes covers a single JSON object, not the aggregate application session. Timeout is evaluated by ActiveAt; applications should publish a strictly newer heartbeat before it elapses.

func DefaultOptions

func DefaultOptions() Options

DefaultOptions returns conservative limits for UI presence such as names, colours, selections, and small cursor metadata.

type Origin added in v1.0.25

type Origin uint8

Origin identifies why a local presence observer received a new snapshot. It is process-local UI metadata and must never be transmitted or persisted.

const (
	// Initial is the state atomically captured when Subscribe is registered.
	Initial Origin = iota
	// Local is an update created through Set or Remove.
	Local
	// Remote is a newer update successfully accepted through Apply.
	Remote
	// Expired is a liveness transition made explicit by Expire.
	Expired
)

type Store

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

Store accepts locally created and remotely received updates. It is safe for concurrent UI, timer, and transport goroutines. Its state is intentionally process-local and must not be persisted with CRDT data.

func NewStore

func NewStore(options Options) (*Store, error)

NewStore constructs an empty bounded awareness store.

func (*Store) ActiveAt

func (store *Store) ActiveAt(now time.Time) []Update

ActiveAt returns sorted, owned copies of the currently live presence states. Offline tombstones remain retained internally until the application drops the whole ephemeral Store, preventing old packets from reviving an actor.

func (*Store) Apply

func (store *Store) Apply(update Update, now time.Time) (changed bool, err error)

Apply installs a newer remote update. Duplicates and stale updates are harmless and return changed=false. A different payload at an equal clock is rejected so arrival order cannot determine a user's displayed presence.

func (*Store) Expire added in v1.0.25

func (store *Store) Expire(now time.Time) bool

Expire records liveness transitions which have passed Timeout and publishes one latest presence snapshot when any state becomes inactive. It deliberately does not create a wire update or erase the actor's clock tombstone. A later, strictly newer heartbeat can make the actor active again. Applications call it from their own scheduler so the Store never owns an unbounded timer or goroutine lifetime.

func (*Store) Heartbeat added in v1.0.25

func (store *Store) Heartbeat(actor string, now time.Time) (Update, error)

Heartbeat creates and installs the next online update without re-parsing an unchanged state object. Call it only for an actor owned by this local application; transports must still authorize that actor before relaying the returned update. A removed or unknown actor must use Set to establish its state again.

func (*Store) Options

func (store *Store) Options() Options

Options returns the immutable store configuration.

func (*Store) Remove

func (store *Store) Remove(actor string, now time.Time) (Update, error)

Remove creates and installs the next removal update for actor. It is useful on a graceful disconnect; abrupt disconnects are handled by ActiveAt's TTL.

func (*Store) Set

func (store *Store) Set(actor string, state []byte, now time.Time) (Update, error)

Set creates and installs the next online update for actor. The caller should publish the returned update and periodically call Set again as a heartbeat.

func (*Store) StartExpiry added in v1.0.25

func (store *Store) StartExpiry(ctx context.Context, interval time.Duration) (*ExpiryLoop, error)

StartExpiry runs Expire immediately and then at interval until ctx is cancelled. It only makes local liveness transitions observable: it never sends a removal, mutates a CRDT, or deletes retained actor clocks. Use an interval no greater than Options.Timeout when the UI must reflect expiry promptly.

func (*Store) Subscribe added in v1.0.25

func (store *Store) Subscribe(callback Callback) (*Subscription, error)

Subscribe atomically queues the current active snapshot and then later updates. It uses the current wall clock; deterministic simulations should use SubscribeAt with their simulated time.

func (*Store) SubscribeAt added in v1.0.25

func (store *Store) SubscribeAt(now time.Time, callback Callback) (*Subscription, error)

SubscribeAt is Subscribe with an explicit liveness time. It prevents a UI from missing a presence update between its initial read and registration.

type Subscription added in v1.0.25

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

Subscription is one bounded latest-state mailbox. Unsubscribe is idempotent; Done closes after an in-flight callback returns.

func (*Subscription) Done added in v1.0.25

func (subscription *Subscription) Done() <-chan struct{}

Done closes when callback delivery has stopped.

func (*Subscription) Unsubscribe added in v1.0.25

func (subscription *Subscription) Unsubscribe()

Unsubscribe stops this callback without waiting for one already in progress.

type Update

type Update struct {
	Actor string
	Clock uint64
	State []byte
}

Update is one actor's complete ephemeral state at Clock. A nil State is a removal. State is an opaque canonical JSON object so the owning application can define fields without making presence a durable document schema.

func Normalize

func Normalize(update Update, options Options) (Update, error)

Normalize returns a copied update whose online JSON state has a deterministic representation. It reserves nil for a removal and rejects every other JSON top-level value, keeping presence fields namespaced beneath an object.

func UnmarshalUpdate

func UnmarshalUpdate(data []byte, options Options) (Update, error)

UnmarshalUpdate decodes one exact, bounded awareness-v1 update. It performs all limits and JSON validation before allocating retained state.

func (Update) MarshalBinary

func (update Update) MarshalBinary() ([]byte, error)

MarshalBinary serializes a self-contained awareness-v1 update using bounded canonical varints. It authenticates nothing; transports must authorize the actor against their authenticated peer before relaying it.

func (Update) MarshalBinaryWithOptions

func (update Update) MarshalBinaryWithOptions(options Options) ([]byte, error)

MarshalBinaryWithOptions serializes update after validating and canonicalizing its actor and optional JSON object.

func (Update) Online

func (update Update) Online() bool

Online reports whether update carries a presence object rather than a removal tombstone.

Jump to

Keyboard shortcuts

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