Verbatim port of Fastway-Server's TFWEventBus from fw_plugin_host.pas
per feedback_copy_dont_reinterpret.md. Adjustments limited to:
- Type renames (TFW* -> T*).
- uses clause: drop fw_log; add log.types from fpc-log so the
optional Logger property uses the canonical ecosystem-wide
TLogProc shape, matching every other fpc-* library.
- Per-handler exception logging now calls Logger with
Level=llError, Category='events', and includes the source
plugin (ASourcePlugin parameter) in the message text so the
canonical signature stays meaningful.
Behaviours preserved verbatim: APluginName bulk-Unsubscribe key,
wildcard '*' subscriber, OnBroadcast external-listener tap,
snapshot-iterate-outside-lock pattern, per-handler exception
isolation, TCriticalSection.
docs/DEVELOPER_GUIDE.md added covering threading, payload
ownership, recursive Fire, OnBroadcast, logger plumbing, and
the relationship between fpc-events (ecosystem-wide pub/sub)
and per-library typed observer callbacks (bp.events / cm.events
pattern).
Tests: 44 assertions across 14 scenarios pass on x86_64-linux.
Pre-tag -vh audit on src/ev.bus.pas reports zero hints/warnings.
97 lines
4.0 KiB
Markdown
97 lines
4.0 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to fpc-events are recorded here. Every release
|
||
tag (`vX.Y.Z`) points at the commit that bumped `EVENTS_VERSION`
|
||
in `src/events.version.pas`. Downstream consumers should pin
|
||
by tag, not commit hash.
|
||
|
||
Semver intent:
|
||
- **major** — breaks callers (API removal, signature change)
|
||
- **minor** — additive features
|
||
- **patch** — bug fixes, internal cleanups
|
||
|
||
## 0.1.0 — 2026-05-05
|
||
|
||
Initial release. Verbatim port of Fastway-Server's `TFWEventBus`
|
||
class from `fw_plugin_host.pas` per `feedback_copy_dont_reinterpret.md`.
|
||
|
||
### Added
|
||
|
||
- `events.bus.TEventBus` — thread-safe publish/subscribe registry
|
||
(port of `TFWEventBus`, lines 188-203 + 1626-1753 of canonical
|
||
`fw_plugin_host.pas`). Public surface:
|
||
- `constructor Create` / `destructor Destroy`
|
||
- `procedure Subscribe(const APluginName, AEventType: string; ACallback: TEventCallback)`
|
||
- `procedure Unsubscribe(const APluginName: string)`
|
||
- `procedure UnsubscribeCallback(ACallback: TEventCallback)`
|
||
- `procedure Fire(const ASourcePlugin, AEventType: string; AData: TJSONObject)`
|
||
- `function GetSubscriptionCount: Integer`
|
||
- `property OnBroadcast: TEventBroadcast`
|
||
- `property Logger: log.types.TLogProc` (new — fpc-* ecosystem
|
||
logger shape from fpc-log, replaces canonical's
|
||
`fw_log.Log.Error(...)` calls)
|
||
- `events.bus.TEventCallback`, `TEventBroadcast`,
|
||
`TEventSubscription` types (renamed from canonical `TFW*`).
|
||
- `events.version` unit with `EVENTS_VERSION_MAJOR/MINOR/PATCH/STRING`.
|
||
- `docs/DEVELOPER_GUIDE.md` — full developer guide covering
|
||
threading, payload ownership, recursive Fire, OnBroadcast,
|
||
logger plumbing, and the relationship between fpc-events
|
||
and per-library typed callbacks.
|
||
|
||
### Adjustments from canonical (the only behaviour-preserving changes)
|
||
|
||
| Canonical | fpc-events |
|
||
|----------------------------|------------------------|
|
||
| `TFWEventBus` | `TEventBus` |
|
||
| `TFWEventCallback` | `TEventCallback` |
|
||
| `TFWEventBroadcast` | `TEventBroadcast` |
|
||
| `TFWEventSubscription` | `TEventSubscription` |
|
||
|
||
- **`uses` clause:** dropped `fw_log`. Added `log.types` (from
|
||
fpc-log) for the canonical ecosystem-wide logger shape. The
|
||
exception-handler logging path that called
|
||
`fw_log.Log.Error(...)` now calls the optional
|
||
`Logger: log.types.TLogProc` if assigned with
|
||
`Level=llError`, `Category='events'`, and the formatted
|
||
message; silently swallows otherwise.
|
||
|
||
### Behaviours preserved verbatim (because they LOOK Fastway-specific
|
||
but aren't, per the handoff)
|
||
|
||
- `APluginName` parameter on `Subscribe` and `Unsubscribe`-by-name
|
||
bulk removal. Consumers without plugin semantics pass `''` and
|
||
use `UnsubscribeCallback`.
|
||
- Wildcard `'*'` event type.
|
||
- `OnBroadcast` external-listener tap, fired once per `Fire`.
|
||
- Snapshot-iterate-outside-lock pattern (re/un-subscribe and
|
||
recursive `Fire` from inside a callback are safe).
|
||
- Per-handler exception isolation (try/except inside the iteration,
|
||
not outside).
|
||
- `TCriticalSection` (not `TMonitor` / `TRWLock`).
|
||
- No deduplication on `Subscribe`.
|
||
- Subscription order = insertion order.
|
||
|
||
### Notes for downstream consumers
|
||
|
||
- The `Fire` callback signature carries `ASourcePlugin` as
|
||
passthrough metadata. Fastway used it for provenance tagging at
|
||
the call site; new consumers can pass `''`.
|
||
- `AData` lifetime: the caller of `Fire` retains ownership.
|
||
Subscribers must not free it.
|
||
|
||
### Tests
|
||
|
||
- `tests/test_bus.pas` — 44 assertions across 14 scenarios:
|
||
basic delivery, subscription order, wildcard, type filtering,
|
||
bulk Unsubscribe by plugin, UnsubscribeCallback by method
|
||
pointer, unsubscribe-from-callback, subscribe-from-callback
|
||
(snapshot semantics), recursive Fire, handler exception
|
||
isolation, broadcast tap, broadcast exception isolation,
|
||
threaded publishers (4 producer threads × 1000 events), and
|
||
GetSubscriptionCount add/remove.
|
||
|
||
### Examples
|
||
|
||
- `examples/pubsub.pas` — minimal demo with a typed listener,
|
||
wildcard audit subscriber, and bulk `Unsubscribe`.
|