hook

package
v1.4.2 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package hook says whether an identity is hooked in: the one record, in the bus Redis, of the role an identity hooked in as, which pushes that role needs, and which of them are live and proven now (docs/SPEC-HOOK.md; the machine is tla/Hook.tla). Every tool that sends, reads or takes work as an identity asks Gate first and acts only on a yes; a no carries the breadcrumb, the exact command lines that hook the identity in.

The record's truth lives in Redis alone. A push is live while its holder, the process that receives that push, renews a lease key with a TTL; a dead holder's lease expires on its own and the gate refuses. A push is proven while a proof key with a TTL stands: a session answered the challenge its hook printed, or a daemon holder proved its own round trip. This package is its own module, with the Redis client its one dependency, so every tool that gates (nova-tools and nova-sprint alike) reads the same record.

Index

Constants

View Source
const (
	// LeaseTTL is how long a push stays live after its holder last renewed it.
	LeaseTTL = 90 * time.Second
	// RenewEvery is how often a holder renews: three renewals inside one lease.
	RenewEvery = 30 * time.Second
	// ChallengeEvery is how often a session's hook asks it again.
	ChallengeEvery = 30 * time.Minute
	// AnswerBound is how long a challenge waits for its answer.
	AnswerBound = 5 * time.Minute
	// ProofTTL is how long a proof stands: a challenge's cadence and twice its
	// answer's bound, so a proof answered at the last moment of one challenge's
	// bound outlives the whole bound of the next (a session answering every
	// challenge inside its bound is never unproven between them).
	ProofTTL = ChallengeEvery + 2*AnswerBound
	// BeatEvery is the server's pass interval, not its challenge cadence
	// (tla/HookBeat.tla, Pass).
	BeatEvery = time.Minute
	// BusyQuietAfter applies to a friend with ready or working sprint cards.
	BusyQuietAfter = 5 * time.Minute
	// QuietAfter applies to an idle friend or comms name.
	QuietAfter = 10 * time.Minute
	// CoordinatorEvery is the coordinator's quiet window.
	CoordinatorEvery = 30 * time.Minute
	// DownAfter is silence required in addition to an outstanding challenge
	// past AnswerBound before the server unhooks a name (tla/HookBeat.tla).
	DownAfter = 5 * time.Minute
)

The clocks of the record (docs/SPEC-HOOK.md, the clocks; tla/Hook.tla).

View Source
const (

	// NamesKey is the set of every name that ever hooked in.
	NamesKey = prefix + "names"
	// ServeKey is the heartbeat server's own stamp: a hash of at, every, by.
	ServeKey = prefix + "serve"
	// EventsKey is the capped stream of the heartbeat's unhooks, one entry each.
	EventsKey = prefix + "events"
	// EventsMax caps EventsKey (approximately, MAXLEN ~).
	EventsMax = 10000
)

The keys (docs/SPEC-HOOK.md, the key layout), all in the bus Redis.

View Source
const (
	StateNone     = "none"     // no record: never hooked in
	StateUnhooked = "unhooked" // unhooked by nova-hook unhook
	StateExpired  = "expired"  // hooked, and no push of the role is live
	StatePartial  = "partial"  // hooked, some pushes of the role live and some not
	StateLive     = "live"     // hooked, every push live, not every one proven
	StateProven   = "proven"   // hooked, every push live and proven: the gate's one yes

	PushDown   = "down"   // no live lease: its holder is not running
	PushArmed  = "armed"  // a live lease and no proof
	PushProven = "proven" // a live lease and a proof
)

The record's states and a push's (docs/SPEC-HOOK.md, the states).

View Source
const (
	BeatLeft       = 0 // not hooked, no bus push, or challenged already this interval
	BeatChallenged = 1 // a fresh challenge is set: deliver its nonce
	BeatUnhooked   = 2 // a miss with no answer for down-after: unhooked
)

What one heartbeat pass did to one name.

View Source
const (
	ToCoordinator = "coordinator"
	ToRest        = "rest"
)

The audiences a pass tells, each marked told on its own (Store.Told): the coordinator, who gets the judgment, and the rest of the live names.

View Source
const (
	NeverRanReason = "hook server never ran"
	StaleReason    = "hook server stale"
	NoAnswerReason = "no answer to a heartbeat challenge within the window"
)

Why a hooked record reads down although its state says otherwise: up needs evidence, a heartbeat server passing and the name's own answer.

View Source
const JudgmentsKey = prefix + "judgments"

JudgmentsKey holds the heartbeat's open judgments: a hash of message id to the judgment (JSON), each open until one of its recipients answers it (the bus's answers record, nova-bus send --re <id>), re-pushed as OVERDUE at most once past its due (tla/HookBeat.tla, Judge).

View Source
const RecentMax = 64

RecentMax bounds the challenges a name's record keeps for its proof window (the record's recent): a pass keeps the ones the down-after window can hold at one pass per nine tenths of an interval, never more than this.

View Source
const StateDown = "down"

StateDown is a proven record that reads down at this read (Served.Down: no answer within the window, or no server), the state nova-hook friends shows as down; every other state is the record's own.

Variables

View Source
var (
	ErrNoChallenge = errors.New("no challenge stands for this name: its hook has not asked one, or it lapsed past its bound; read the hook's stream for the next HOOK CHALLENGE")
	ErrWrongNonce  = errors.New("the nonce is not the one the challenge asked, nor one the heartbeat issued to this name in this epoch within its down-after window and not yet answered; copy it from the newest HOOK CHALLENGE line of the hook's stream")
	ErrExpired     = errors.New("the heartbeat challenge is past its interval and its window: it counts as missed; answer the next one, which the heartbeat server sends within the interval")
)

The refusals of Answer, by the script's code.

View Source
var Audiences = []string{ToCoordinator, ToRest}

Audiences is every audience, in the order the pass reply carries them.

View Source
var Challenged = map[Role][]Push{Coordinator: {Bus}, Friend: {Bus}, Comms: {Bus}}

Challenged is the pushes a heartbeat challenge names for each role a session answers in: the bus push. The sprint push is the seat hook's own (nova-sprint run), and a member's or reader's loop has no session: neither is challenged.

View Source
var ErrNotHooked = errors.New("the record is not hooked under this epoch: it was unhooked, or hooked again since")

ErrNotHooked is what Renew, Prove and Challenge answer when the record is not hooked under the holder's epoch: unhooked, or hooked again since.

View Source
var ErrOtherRole = errors.New("the record is hooked as another role")

ErrOtherRole is Arm's answer for a record hooked as another role: a holder never takes a record over; only a fresh arm (nova-hook hook, asked by the identity itself) does.

View Source
var Pushes = []Push{Bus, Sprint, Work}

Pushes is every push, in the order the record's keys list them.

Roles is every role, in the order help lists them.

Functions

func AgentLabel

func AgentLabel(name string, r Role) string

AgentLabel is the service that runs a friend's lanes: her daemon (com.nova.friend-<name>).

func Breadcrumb(name string, role Role, need []Push, st Status) (string, []string)

Breadcrumb is the remedy and the lines that say who holds each push and how to see and end the hook, each runnable as printed (docs/SPEC-HOOK.md, the breadcrumb). With a role, the remedy is the command that hooks name in as it. With no role known the breadcrumb never guesses one: the remedy is to look (nova-hook status), and the lines offer every role that carries need, comms first, then friend, then coordinator.

func ChallengeKey

func ChallengeKey(name string) string

ChallengeKey is name's outstanding challenge: a hash of epoch, sum, pushes, with a TTL.

func DeliveryKey

func DeliveryKey(name string) string

DeliveryKey holds the private pending challenge payload until bus delivery is confirmed (tla/HookBeat.tla, delivery obligation).

func DeliveryOnce

func DeliveryOnce(name string, epoch int64, nonce string) string

DeliveryOnce is the bus once-key of this challenge, stable across retries.

func DownReason

func DownReason(downAfter time.Duration, misses int) string

DownReason is the reason a heartbeat unhook records: no answer for downAfter, and the challenges missed in a row by then.

func HeldBy

func HeldBy(name string, r Role, p Push) string

HeldBy is who holds push p of a role for name: the service or the command that runs it, each line runnable as printed on this machine.

func HookCommand

func HookCommand(name string, r Role) string

HookCommand is the line that hooks name in as role.

func LiveKey

func LiveKey(name string, p Push) string

LiveKey is the lease of name's push: a string with a TTL its holder renews.

func ProofKey

func ProofKey(name string, p Push) string

ProofKey is the proof of name's push: a string with a TTL.

func PushOnce

func PushOnce(name string, epoch int64, state string, gen int64) string

PushOnce is the once-key of a name's gen-th push, naming its epoch and the state it pushes (tla/HookBeat.tla, NeverPushedTwice): the count makes a flap back to a state in the same epoch a push of its own.

func PushState

func PushState(st Status) string

PushState is the state of st a friend-status push names: the record's state, or down for a proven one the heartbeat's evidence does not stand behind.

func RecordKey

func RecordKey(name string) string

RecordKey is name's record: a hash of role, state, epoch, armed, unhooked, by.

func RestartCommand

func RestartCommand(goos, label string) string

RestartCommand is the line that restarts the service label on goos, runnable as printed: launchctl in the user's gui domain on darwin, systemctl --user elsewhere (pkg/units.Load names the services the same way).

func Sum

func Sum(nonce string) string

Sum is the challenge's form of a nonce: what the store keeps in its place.

Types

type Beat

type Beat struct {
	Name   string
	Did    int    // BeatLeft, BeatChallenged or BeatUnhooked
	Nonce  string // pending payload; the private outbox retains it until delivery
	Misses int
	Epoch  int64
	// DownAfter is the pass's down-after: the silence that unhooks.
	DownAfter time.Duration
}

Beat is one name's outcome of a heartbeat pass.

func (Beat) Reason

func (b Beat) Reason() string

Reason is why an unhooked beat unhooked its name, as the record and the event say it.

type Holder

type Holder struct {
	Store  Store
	Name   string
	Role   Role
	Pushes []Push // the pushes this process holds: some or all of the role's
	By     string // who holds them, as the lease shows it
	// contains filtered or unexported fields
}

Holder holds some pushes of one identity for a long-running process (a friend daemon, a member loop): it hooks in at start, renews each push it holds every RenewEvery, proves or unproves each as its owner's own round trip says, and answers the gate, so the process acts only while the record says proven (docs/SPEC-HOOK.md, holders; tla/Hook.tla, Arm, Renew and ProveDaemon).

func (*Holder) Beat

func (h *Holder) Beat(ctx context.Context, proven map[Push]bool) error

Beat renews each push the holder holds and proves the ones proven names, unproving the rest. When the record moved since, the holder rejoins only a record hooked as its own role again, and re-arms only a record that is gone (none: lost, or flushed, under a running holder: its start would arm it, so its beat does); after an unhook, or a hook as another role, it answers ErrNotHooked and holds nothing until someone hooks the identity in as its role again, so an unhook stands.

func (*Holder) Epoch

func (h *Holder) Epoch() int64

Epoch is the record's epoch the holder writes under, 0 before Start.

func (*Holder) Gate

func (h *Holder) Gate(ctx context.Context, need ...Push) error

Gate is the gate for the holder's identity: nil when every push of its role is live and proven, else the refusal or the store's error (fail closed).

func (*Holder) Start

func (h *Holder) Start(ctx context.Context) error

Start hooks the identity in as the holder's role and renews every push it holds once: the process's start is its hook. It joins a record hooked as its role, and arms one only where there is no record at all. A record hooked as another role is ErrOtherRole and an unhooked one ErrNotHooked, each left as it is: a holder never undoes the identity's word, so an unhook stands across the holder's restart until someone hooks the identity in again (nova-hook hook, which arms fresh).

type Judgment

type Judgment struct {
	ID      string    `json:"id"`
	To      []string  `json:"to"`
	Subject string    `json:"subject"`
	Due     time.Time `json:"due"`
	Overdue bool      `json:"overdue"` // re-pushed once already: never again
}

Judgment is one open judgment: the bus message that raised it.

func (Judgment) OverdueMark

func (j Judgment) OverdueMark() (once, field, value string, err error)

OverdueMark is j's re-push's once-key and the mark that records it re-pushed (a field of JudgmentsKey), written with the re-push in one step, so it is re-pushed at most once.

type Passed

type Passed struct {
	Taken    bool     // false: another pass (another server's) was taken inside nine tenths of the interval; nothing was done
	Beats    []Beat   // one per name, in the order asked
	Unhooked []string // every name unhooked now, sorted
	Coord    string   // the coordinator now: the first hooked name of that role, "" for none
	Live     []string // every hooked name of a challenged role: who hears a broadcast
	Was      map[string]Told
}

Passed is what one heartbeat pass did and found.

func (Passed) Changed

func (p Passed) Changed(audience string) bool

Changed is whether an audience has anything to be told.

func (Passed) Diff

func (p Passed) Diff(audience string) (down, back []string, was string)

Diff is what an audience has not been told: the names down and back since, and the coordinator it was told.

func (Passed) Telling

func (p Passed) Telling(audience string) (once string, marks []ToldMark)

Telling is what an audience's message for p carries so that the message and its told mark are one write (tla/HookBeat.tla, NeverToldTwice and EveryTransitionToldAtLeastOnce): the once-key of this telling, the audience's generation, which a later send under it finds and writes nothing; and the marks: what it was told, and the next generation.

type Proof

type Proof struct {
	Proven int // the pushes proven
	// Back is which challenge the nonce matched: 0 the newest the heartbeat
	// issued (or the standing challenge), k the one k challenges before it.
	Back int
	// Issued is when the heartbeat issued the matched challenge, by the
	// store's TIME; zero for a challenge the record's recent does not hold
	// (a bootstrap's).
	Issued time.Time
}

Proof is what an answer proved and which challenge it matched.

type Push

type Push string

Push is one stream of notifications an identity must be hooked into.

const (
	Bus    Push = "bus"    // the identity's bus stream (bus2:to:<name>), pushed into its session
	Sprint Push = "sprint" // the sprint server's judgments and pushes to the coordinator
	Work   Push = "work"   // the work the sprint deals the identity
)

The pushes (docs/SPEC-HOOK.md, roles and pushes).

func PushesOf

func PushesOf(r Role) []Push

PushesOf is the pushes role needs, nil for no role.

type PushRead

type PushRead struct {
	Live, Proof         string
	LiveLeft, ProofLeft time.Duration
}

PushRead is one push's keys as one read found them: the lease and the proof values ("" for none) and their remaining TTLs.

type PushStatus

type PushStatus struct {
	Push      Push
	State     string // PushDown, PushArmed, PushProven
	By        string // the lease's holder, "" when down
	LiveLeft  time.Duration
	ProofLeft time.Duration
}

PushStatus is one push of a role, judged.

type Pushed

type Pushed struct {
	State string
	Gen   int64
}

Pushed is what was last pushed for one name: its state and how many pushes went.

type Refusal

type Refusal struct {
	Status Status
	Why    string   // one line: what is not live
	Hook   string   // the command that hooks in, the remedy
	Lines  []string // the rest of the breadcrumb, one runnable line each
}

Refusal is the gate's no: the identity is not hooked in for the act. It carries the status it judged and the breadcrumb, the exact command lines that hook the identity in, runnable as printed.

func (*Refusal) Error

func (r *Refusal) Error() string

type Role

type Role string

Role is what an identity hooks in as; it names the pushes it needs.

const (
	Coordinator Role = "coordinator" // the seat: the bus and the sprint
	Friend      Role = "friend"      // a friend working the sprint: the bus and its work
	Comms       Role = "comms"       // a friend on the bus that takes no sprint work
	Member      Role = "member"      // a machine's member loop: its work
	Reader      Role = "reader"      // a machine's reader loop: its reads
)

The roles (docs/SPEC-HOOK.md, roles and pushes).

func ParseRole

func ParseRole(s string) (Role, error)

ParseRole is the role s names, or why it is none.

type Served

type Served struct {
	At, Now time.Time
	Every   time.Duration
	// DownAfter is the server's down-after (nova-hook serve --down-after):
	// the window a name's last answer must fall in to read up. A row from a
	// server that writes none reads as two intervals, that server's own rule.
	DownAfter time.Duration
	OK        bool
}

Served is the heartbeat server's stamp as the store holds it: when it last passed and its interval, with the store's now; ok false when no server ever passed.

func (Served) Down

func (sv Served) Down(st Status) string

Down is the shared reader rule (tla/HookBeat.tla, ActivityUp): a missing or stale server is down. A challenged role needs an initial nonce answer; afterward a delivered expired challenge with old activity reads down. The independent reader backstop also bounds silence when delivery is lost; quiet eligibility alone never changes reader status. The separate proof lease gate remains mandatory.

func (Served) Stale

func (sv Served) Stale() bool

Stale is whether the heartbeat server gives no evidence at this read: it never passed, or not for more than two of its intervals by the store's TIME.

func (Served) Window

func (sv Served) Window() time.Duration

Window is how old a name's last answer may be and the name read up: the server's down-after, or two intervals for a row that carries none.

type Status

type Status struct {
	Name         string
	Role         Role
	State        string // StateNone .. StateProven
	Epoch        int64
	Armed        time.Time     // when the record was last hooked, zero when never
	Unhooked     time.Time     // when it was unhooked, zero when it is not
	Reason       string        // why it was unhooked, when the heartbeat did it ("no answer in 5m0s (5 challenges missed)")
	BeatAt       time.Time     // when the heartbeat server last challenged it, zero when never
	ActivityAt   time.Time     // latest explicit model bus send, at store TIME
	PendingSent  bool          // the bus committed this challenge, not merely prepared it
	PendingUntil time.Time     // outstanding server challenge deadline, even after its key expires
	QuietAfter   time.Duration // policy selected from the authoritative sprint row at the last pass
	AnswerAt     time.Time     // when the session last answered a challenge, zero when never
	// Down is why the record reads down at this read whatever its state says
	// (Served.Down: no server, a stale one, or no answer), "" when the evidence
	// stands. No reader trusts the last written state then, and the gate refuses.
	Down   string
	Misses int // challenges in a row left unanswered
	Pushes []PushStatus
}

Status is one identity's record, judged at the store's now.

func Judge

func Judge(name string, rec map[string]string, reads []PushRead) Status

Judge is the status a record and its pushes' reads say: the state machine, a pure function (tla/Hook.tla, GateOK). rec is the record hash (empty: no record); reads holds one PushRead per push of Pushes, in that order. A lease or proof whose epoch is not the record's counts for nothing.

func (Status) Gate

func (st Status) Gate(w Want) *Refusal

Gate is nil when st lets w act: the record is hooked, every push of its role is live and proven, its role carries every push w needs, and it is one of w.Roles when w names any. Otherwise it is the Refusal with its breadcrumb (tla/Hook.tla, Gate and GateMeansHooked).

func (Status) LastActivity

func (st Status) LastActivity() time.Time

LastActivity is actual model activity or the initial arm, never a holder's lease renewal (tla/HookBeat.tla, lastActivity).

func (Status) QuietWindow

func (st Status) QuietWindow() time.Duration

QuietWindow is the policy selected by the last pass, or the role's default.

func (Status) Words

func (st Status) Words() string

Words is the status as one line's words: state, role, epoch and each push.

type Store

type Store struct {
	C redis.Cmdable
	// Timeout, when set, bounds each round trip on its own, inside the
	// caller's context: a long-running holder's beat makes several, and one
	// slow call never spends the next one's time.
	Timeout time.Duration
}

Store is the record over one Redis client: the bus Redis. Every verb is one round trip, a script or a pipeline (docs/SPEC-HOOK.md, the verbs).

func (Store) Answer

func (s Store) Answer(ctx context.Context, name, nonce, by string) (int, error)

Answer answers name's challenge with nonce: every push it named whose lease is live is proven for ProofTTL. It answers how many were proven.

func (Store) AnswerProof

func (s Store) AnswerProof(ctx context.Context, name, nonce, by string) (Proof, error)

AnswerProof answers name's challenge with nonce (answerLua): the newest challenge or any the heartbeat issued to name in its epoch within the down-after window and not yet spent (tla/HookBeat.tla, AnswerIssued and ProofNamesIssuedInWindow). The answer counts at the time of the proof. A refusal of another nonce names the server's window.

func (Store) Answered

func (s Store) Answered(ctx context.Context, j Judgment) (bool, error)

Answered says whether any of j's recipients replied to it: the bus's answers record (bus2:answers:<name>, field the id replied to), in one round trip.

func (Store) Arm

func (s Store) Arm(ctx context.Context, name string, role Role, by string, fresh bool) (epoch int64, joined bool, err error)

Arm hooks name in as role. Not fresh (a holder's start), it joins a record already hooked as that role at its epoch (joined true) and arms only where there is no record at all; a record hooked as another role is ErrOtherRole and an unhooked one ErrNotHooked, each left as it is, so neither a holder's start nor its restart ever undoes the identity's word. Fresh (nova-hook hook, the identity's own word) always starts a new epoch. by is who armed it, as the record shows it.

func (Store) Baseline

func (s Store) Baseline(ctx context.Context, states map[string]string) error

Baseline writes the states of the first pass as pushed, with no message: a server row with no pushed mark would else push every name at once. A mark already there stays (HSETNX).

func (Store) Challenge

func (s Store) Challenge(ctx context.Context, name string, role Role, epoch int64, pushes []Push, nonce string) (created bool, err error)

Challenge bootstraps a challenge for pushes under epoch and role (tla/HookBeat.tla, Bootstrap). It returns false without writing if a challenge stands or the heartbeat owns this epoch, including after Answer. Only a created challenge's nonce is delivered; a skipped client waits for the heartbeat's next delivery. A bootstrap lasts AnswerBound.

func (Store) Close

func (s Store) Close(ctx context.Context, j Judgment) error

Close ends an answered judgment, and logs it.

func (Store) Delivered

func (s Store) Delivered(ctx context.Context, beat Beat) error

Delivered confirms the bus accepted a challenge, without extending its deadline.

func (Store) Gate

func (s Store) Gate(ctx context.Context, w Want) error

Gate reads w.Name's record and says whether w may act: nil, a *Refusal with the breadcrumb, or an error of the store. Fail closed: a caller acts only on nil; a store that does not answer is a refusal of its own, never a pass.

func (Store) HookAs

func (s Store) HookAs(ctx context.Context, name string, role Role, by string) (epoch int64, joined bool, err error)

HookAs is the identity's own word, nova-hook hook: it joins a record hooked as role at its epoch (joined true); otherwise (no record, an unhooked one, one hooked as another role, which it takes over) it starts a new epoch.

func (Store) Judgments

func (s Store) Judgments(ctx context.Context) ([]Judgment, time.Time, error)

Judgments is every open judgment and the store's now, in one round trip.

func (Store) Lost

func (s Store) Lost(ctx context.Context, name string, from, until time.Time) error

Lost is a client's report of an episode it could not reach the server: from and until by its own clock, logged once on hook:events when it reaches the server again.

func (Store) Names

func (s Store) Names(ctx context.Context) ([]string, error)

Names is every name that ever hooked in, sorted.

func (Store) OpenJudgment

func (s Store) OpenJudgment(ctx context.Context, j Judgment, within time.Duration) error

OpenJudgment records j (its ID the message's) as open, due within of the store's now.

func (Store) Pass

func (s Store) Pass(ctx context.Context, names []string, every, downAfter time.Duration, nonce func() string, by string, busy ...string) (Passed, error)

Pass applies the silence/proof-renewal rule in one store round trip (tla/HookBeat.tla, Pass). busy names come from the authoritative sprint ready/working rows; omitted names use the idle policy. Beats with a nonce require delivery, including retry of a prepared but undelivered nonce.

func (Store) PlanPass

func (s Store) PlanPass(ctx context.Context, names []string, every, downAfter time.Duration, by string, busy ...string) (Passed, error)

PlanPass is what Pass would do now, from the same script, writing nothing (nova-hook serve --dry-run): the same Passed, with no nonce on any beat, as no challenge is set. A plan of a pass inside another's interval is not taken.

func (Store) Prove

func (s Store) Prove(ctx context.Context, name string, role Role, p Push, epoch int64, how string) error

Prove writes the proof of name's push p under epoch and role for ProofTTL: a daemon holder's own proof of its round trip. ErrNotHooked when the record is not hooked at that epoch as that role; an error naming the lease when p is not live.

func (Store) Pushed

func (s Store) Pushed(ctx context.Context) (map[string]Pushed, bool, error)

Pushed reads what was last pushed for each name, and whether any push or baseline was ever written (false: the first pass of a fresh row).

func (Store) Read

func (s Store) Read(ctx context.Context, names ...string) ([]Status, time.Time, error)

Read is each name's status at the store's now, in one round trip (a pipeline: the record, each push's lease and proof with their TTLs, the TIME).

func (Store) Renew

func (s Store) Renew(ctx context.Context, name string, role Role, p Push, epoch int64, by string) error

Renew renews the lease of name's push p under epoch and role for LeaseTTL; ErrNotHooked when the record is not hooked at that epoch as that role.

func (Store) Sent

func (s Store) Sent(ctx context.Context, once string) (bool, error)

Sent says whether a once-key's send went: the key stands.

func (Store) Serve

func (s Store) Serve(ctx context.Context) (Served, error)

Serve reads the heartbeat server's stamp and the store's TIME, in one round trip.

func (Store) Told

func (s Store) Told(ctx context.Context, p Passed, audience string) error

Told marks an audience told what p found when there is no one to send to.

func (Store) Unhook

func (s Store) Unhook(ctx context.Context, name string) (was string, err error)

Unhook unhooks name: was is StateNone when there was no record, StateUnhooked when it was unhooked already, else "hooked".

func (Store) Unprove

func (s Store) Unprove(ctx context.Context, name string, role Role, p Push, epoch int64) error

Unprove clears the proof of name's push p under epoch and role: its holder's session stopped answering, so the push is armed and no longer proven.

type Told

type Told struct {
	Unhooked []string
	Coord    string
	Gen      int64
}

Told is what an audience was last told: the unhooked set and the coordinator, and the generation of that telling.

type ToldMark

type ToldMark struct{ Field, Value string }

ToldMark is one field of the server row (ServeKey) an audience's message writes in its own atomic step.

func PushMark

func PushMark(name, state string, gen int64) ToldMark

PushMark is the server-row mark a push of state, the gen-th, writes in the same atomic step as its message.

type Want

type Want struct {
	Name string
	Need []Push
	// Roles, when set, are the only roles the act is for: a record hooked as
	// another role is refused even when that role carries every push Need
	// names (a friend daemon arming the seat's name as friend opens none of the
	// coordinator's verbs). Empty: any role that carries Need.
	Roles []Role
	Role  Role
}

Want is what a gate asks of an identity: its name, the pushes the act needs, the roles the act is for, and the role the caller would hook in as when the record names none (the breadcrumb's role; "" offers every role that carries the pushes, and the remedy is to look first).

Directories

Path Synopsis
Package hooktest is the test rig of the hook record: a hook.Store over a miniredis reached through net.Pipe, so no TCP connection is made (the cleanup fails a test whose fake took one), on a clock that moves only when a test moves it.
Package hooktest is the test rig of the hook record: a hook.Store over a miniredis reached through net.Pipe, so no TCP connection is made (the cleanup fails a test whose fake took one), on a clock that moves only when a test moves it.

Jump to

Keyboard shortcuts

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