Files
fpc-events/CHANGELOG.md
T
kenjreno 128ddcb4df v0.1.0: thread-safe pub/sub event bus
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.
2026-05-05 18:13:10 -07:00

4.0 KiB
Raw Permalink Blame History

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.