docs(modules): rewrite cabana, wire, towel, festival, compass, backpack READMEs

This commit is contained in:
Jakub Zych
2026-09-28 15:43:23 +02:00
parent cc584e906e
commit 1bd34948a9
6 changed files with 574 additions and 6 deletions

View File

@@ -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.