docs(modules): rewrite cabana, wire, towel, festival, compass, backpack READMEs
This commit is contained in:
@@ -1,3 +1,84 @@
|
||||
# festival
|
||||
|
||||
`festival` is the framework event bus, supporting collection and handler registration for application events. `backpack` and example plugins import it during boot; create a bus with `festival.New` in `bus.go`.
|
||||
Typed, synchronous event bus with listener priorities, payload collection and stop-when-handled dispatch.
|
||||
|
||||
`import "git.golem15.com/golem15/summercms/modules/festival"`
|
||||
|
||||
## Overview
|
||||
|
||||
`festival` is the SummerCMS counterpart of WinterCMS's `Event::listen` and `Event::fire`, the mechanism plugins use to extend each other without direct calls. Events are routed by their Go type rather than by a string name, so a listener registered for `*PostPublished` receives exactly that type, and a payload mismatch is a compile error. Each application owns one bus: [backpack](../backpack/README.md) creates it in `backpack.New` and exposes it as `backpack.App.Events`, and plugins register listeners from their Boot step.
|
||||
|
||||
## Features
|
||||
|
||||
- Listener registration with `festival.Bus.Listen` (priority 0) and `festival.Bus.ListenPriority`. Higher priorities run first; listeners with equal priority run in registration order. Every listener carries the ID of the plugin that owns it.
|
||||
- Three dispatch modes, all synchronous on the caller's goroutine:
|
||||
- `festival.Bus.Fire` runs every listener and returns the joined errors of all that failed (`errors.Join`).
|
||||
- `festival.Bus.Collect` runs every listener and, after each one, merges the event's `festival.Collectable.Collected` map into a single payload (later keys win). It returns the payload gathered so far together with the joined errors.
|
||||
- `festival.Bus.UntilHandled` stops at the first error or as soon as the event's `festival.Handleable.IsHandled` reports true, and returns whether the event was handled (WinterCMS's halting fire).
|
||||
- Panic isolation: a panicking listener is recovered and reported as an error that names its owner plugin, so one faulty plugin cannot take down the dispatch.
|
||||
- Safe for concurrent use: registration is locked and dispatch works on a snapshot of the listener list.
|
||||
- Value and pointer types are distinct event types; events that listeners modify (for `Collect` and `UntilHandled`) are usually pointers.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package blog
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/festival"
|
||||
)
|
||||
|
||||
// PostPublished is fired after a post goes live. Listeners add payload
|
||||
// entries and may mark the event handled.
|
||||
type PostPublished struct {
|
||||
PostID uint
|
||||
payload map[string]any
|
||||
handled bool
|
||||
}
|
||||
|
||||
func (e *PostPublished) Collected() map[string]any { return e.payload }
|
||||
func (e *PostPublished) IsHandled() bool { return e.handled }
|
||||
|
||||
func publish(ctx context.Context, bus *festival.Bus) (map[string]any, error) {
|
||||
bus.ListenPriority("acme.search", 10, func(ctx context.Context, e *PostPublished) error {
|
||||
if e.payload == nil {
|
||||
e.payload = map[string]any{}
|
||||
}
|
||||
e.payload["indexed"] = true
|
||||
return nil
|
||||
})
|
||||
return bus.Collect(ctx, &PostPublished{PostID: 42})
|
||||
}
|
||||
```
|
||||
|
||||
The event type is inferred from the listener's parameter, so this listener only receives `*PostPublished` events. In a plugin, the bus is `app.Events` on the `backpack.App` passed to Boot; `festival.New` is for tests and standalone use.
|
||||
|
||||
## API reference
|
||||
|
||||
| Identifier | Description |
|
||||
|------------|-------------|
|
||||
| `festival.Bus` | Application-owned, type-keyed event dispatcher. |
|
||||
| `festival.New` | Returns an empty bus. |
|
||||
| `festival.Bus.Listen` | Registers a listener for event type T at priority 0. |
|
||||
| `festival.Bus.ListenPriority` | Registers a listener for event type T at an explicit priority. |
|
||||
| `festival.Bus.Fire` | Runs every listener and joins their errors. |
|
||||
| `festival.Bus.Collect` | Runs every listener and merges the event's collected payload. |
|
||||
| `festival.Bus.UntilHandled` | Runs listeners until one handles the event or fails. |
|
||||
| `festival.Collectable` | Implemented by events that expose a mergeable payload for `Collect`. |
|
||||
| `festival.Handleable` | Implemented by events that can stop `UntilHandled`. |
|
||||
|
||||
## Dependencies
|
||||
|
||||
- SummerCMS modules: none.
|
||||
- Third-party: none.
|
||||
- Standard library: `context`, `errors`, `fmt`, `reflect`, `sort`, `sync`.
|
||||
|
||||
## Testing
|
||||
|
||||
```sh
|
||||
go test ./modules/festival/...
|
||||
```
|
||||
|
||||
The tests use in-process listeners and need no external services.
|
||||
|
||||
Reference in New Issue
Block a user