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.
5.0 KiB
fpc-events — API reference
Every callable the library exposes, with parameters, return values,
and runnable examples. See architecture.md
for the big picture and DEVELOPER_GUIDE.md
for the consumer-oriented walkthrough.
Contents
Quick start
uses
Classes, SysUtils, fpjson,
log.types,
events.bus;
var
Bus: TEventBus;
Data: TJSONObject;
begin
Bus := TEventBus.Create;
try
Bus.Subscribe('demo', 'user.login', @MyHandler);
Data := TJSONObject.Create;
try
Data.Add('username', 'alice');
Bus.Fire('auth', 'user.login', Data);
finally
Data.Free;
end;
finally
Bus.Free;
end;
end.
Types
type
TEventCallback = procedure(const AEventType: string;
AData: TJSONObject) of object;
TEventBroadcast = procedure(const AEventType: string;
AData: TJSONObject) of object;
TEventSubscription = record
PluginName: string;
EventType: string;
Callback: TEventCallback;
end;
The optional Logger property is typed as log.types.TLogProc
(from fpc-log) — the canonical ecosystem-wide logger shape.
TEventBus
Constructed with the parameterless Create constructor:
Bus := TEventBus.Create;
try
...
finally
Bus.Free;
end;
Thread-safe via a single TCriticalSection. The Free call
releases the subscription array and the lock; outstanding
subscribers' method pointers are released but their targets
(the consumer's class instances) are never freed by the bus.
TEventBus.Subscribe
procedure Subscribe(const APluginName, AEventType: string;
ACallback: TEventCallback);
Register ACallback for events whose type equals AEventType,
or for every event when AEventType = '*'. APluginName is
a free-form group key used by Unsubscribe;
pass '' if your consumer doesn't need bulk removal.
Subscribe does NOT deduplicate — registering the same callback
twice produces two entries.
TEventBus.Unsubscribe
procedure Unsubscribe(const APluginName: string);
Remove every subscription whose PluginName matches
APluginName (case-insensitive). Use this when a logical
subsystem owns N subscriptions and is shutting down.
TEventBus.UnsubscribeCallback
procedure UnsubscribeCallback(ACallback: TEventCallback);
Remove every subscription whose method pointer (Code+Data)
matches ACallback. Use this for per-handler removal.
TEventBus.Fire
procedure Fire(const ASourcePlugin, AEventType: string;
AData: TJSONObject);
Deliver (AEventType, AData) to every subscriber whose
EventType equals AEventType or '*', then invoke
OnBroadcast once if assigned. ASourcePlugin is metadata —
included in handler-error log messages but not used for
delivery routing.
AData ownership stays with the caller. Subscribers may read
fields and copy values out, but must not call AData.Free.
If a subscriber callback raises, the exception is caught,
forwarded to the Logger (with Level=llError,
Category='events'), and delivery continues to the next
subscriber. Same for OnBroadcast.
TEventBus.GetSubscriptionCount
function GetSubscriptionCount: Integer;
Number of registered subscriptions. Acquires the lock; safe to call from any thread.
TEventBus.OnBroadcast
property OnBroadcast: TEventBroadcast read FOnBroadcast write FOnBroadcast;
Single nullable callback fired after subscriber delivery on
every Fire call. Originally used by Fastway-Server to
forward every event to web-admin WebSocket clients.
A nil OnBroadcast (the default) means no broadcast.
TEventBus.Logger
property Logger: TLogProc read FLogger write FLogger;
Optional logger for handler-exception messages. TLogProc is
defined in log.types (fpc-log) — the same logger shape used
by every other fpc-* library.
When a subscriber callback or the OnBroadcast tap raises:
Logger(llError, 'events', 'Handler error in <plugin> for <type> (from <src>): <msg>')- (
OnBroadcasterrors omit the plugin field.)
If Logger is nil (the default), exceptions are silently
swallowed.
Version constants
In events.version:
const
EVENTS_VERSION_MAJOR = 0;
EVENTS_VERSION_MINOR = 1;
EVENTS_VERSION_PATCH = 0;
EVENTS_VERSION_STRING = '0.1.0';
Bumped together with the git tag. Pin downstream consumers by tag, not commit hash.