Documentation
¶
Overview ¶
Package events owns the gateway's outbound webhook surface: the event names, the signed envelope, and delivery to configured endpoints with bounded retry. Nothing pushes until configuration names an endpoint, and a payload carries identifiers and states only — never a provider credential, gateway key material, or prompt and response content.
Index ¶
Constants ¶
const ( // TypeBudgetExhausted fires when a budget refuses a request: the // window's spend or token meter is spent and the caller drew a 402. TypeBudgetExhausted = "budget.exhausted" // TypeJobCompleted fires once when an asynchronous job produced its // asset. TypeJobCompleted = "job.completed" // TypeJobFailed fires once when an asynchronous job ended without an // asset. TypeJobFailed = "job.failed" // TypeJobCancelled fires once when a job's owner stopped it. TypeJobCancelled = "job.cancelled" // TypeProviderHealthChanged fires when a provider's status-page // indicator moved: an incident opened, worsened, or cleared. TypeProviderHealthChanged = "provider.health.changed" // TypeKeyCreated fires when the admin surface issues a gateway API // key. The payload names the key; it never carries the token. TypeKeyCreated = "key.created" // TypeKeyDeleted fires when the admin surface revokes a gateway API // key. TypeKeyDeleted = "key.deleted" )
Event type names. Each follows concept.verb, the naming the audit trail's actions use, so an operator reads one vocabulary across both surfaces.
const SignatureHeader = "X-Starport-Signature"
SignatureHeader carries the delivery's HMAC so a receiver can prove the body came from this gateway and arrived unchanged.
#nosec G101 -- An HTTP header name, not a credential.
Variables ¶
This section is empty.
Functions ¶
func RedactEndpoint ¶
RedactEndpoint strips the userinfo and the query from a receiver URL. A receiver often authenticates through a token in either place, and the admin surface shows where deliveries go, not how they authenticate. A value that does not parse as a URL redacts to its scheme and host portion only.
func Sign ¶
Sign computes the header value for one delivery body: "sha256=" and the lowercase hex HMAC-SHA256 of the body under the shared secret.
func TypeForJobState ¶
TypeForJobState maps a terminal job state onto its event name. The job seam reports states without naming events, so the mapping lives here with the rest of the vocabulary. An unknown state maps to TypeJobFailed: a receiver told nothing about an ended job is worse than one told the conservative verdict.
Types ¶
type Dispatcher ¶
type Dispatcher struct {
// contains filtered or unexported fields
}
Dispatcher delivers each emitted event to every configured endpoint, signed, from its own goroutine. An emit never blocks the caller: the emit sites sit on the request path and the poller's pass, and a webhook receiver must not be able to slow either.
A nil *Dispatcher emits nothing, so every emit site holds one unconditionally. That is the unconfigured deployment: no endpoint, no outbound push.
func NewDispatcher ¶
func NewDispatcher(endpoints []string, secret string, options Options) *Dispatcher
NewDispatcher builds a dispatcher for the configured endpoints. It returns nil when endpoints is empty: webhooks stay off until configuration names a receiver.
func (*Dispatcher) Close ¶
func (d *Dispatcher) Close(ctx context.Context) error
Close delivers what is already queued and stops the worker. The context bounds the wait.
func (*Dispatcher) Emit ¶
func (d *Dispatcher) Emit(eventType string, data map[string]string)
Emit queues one event for delivery and returns immediately. A full queue or a closed dispatcher drops the event and counts a dead letter.
func (*Dispatcher) Stats ¶
func (d *Dispatcher) Stats() Stats
Stats reports the delivery state. A nil dispatcher is the unconfigured deployment and reports no endpoints and nothing queued.
type Event ¶
type Event struct {
// ID names this event. A receiver deduplicates redeliveries on it.
ID string `json:"id"`
// Type is one of the Type constants above.
Type string `json:"type"`
// Time is when the gateway observed the fact, RFC 3339 UTC.
Time string `json:"time"`
// Data is the typed payload: identifiers, scopes, and states.
Data map[string]string `json:"data"`
}
Event is the envelope one delivery carries, encoded as one JSON object. Data holds short identifier and state strings only.
type Options ¶
type Options struct {
// MaxPending bounds the undelivered queue. An emit against a full
// queue drops the event and OnDeadLetter counts it.
MaxPending int
// OnDeadLetter observes every event that will never deliver: dropped
// at a full queue, or spent through every attempt at an endpoint.
// Nil observes nothing.
OnDeadLetter func(count int)
// Now replaces the clock. A test states its own times.
Now func() time.Time
}
Options tune a dispatcher. The zero value selects the defaults.
type Stats ¶
type Stats struct {
// Endpoints lists the configured receivers, redacted.
Endpoints []string
// QueueDepth counts the events waiting for delivery.
QueueDepth int
// QueueCapacity is the pending bound the queue drops at.
QueueCapacity int
// DeadLetters counts every event that will never deliver since start.
DeadLetters int64
}
Stats is the delivery state the admin surface reports. Endpoints carries each receiver with its credentials and query removed, so the summary never repeats a secret a receiver URL embeds.