Files
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

75 lines
1.6 KiB
ObjectPascal

{ pubsub -- minimal "subscribe in one place, fire in another" demo.
Build:
bash build.sh
/opt/fpcup/fpc/bin/x86_64-linux/fpc -O2 -Sh \
-Fusrc -FUbuild -FEbuild -obuild/pubsub examples/pubsub.pas
Run:
./build/pubsub }
program pubsub;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}cthreads,{$ENDIF}
Classes, SysUtils, fpjson, events.bus;
type
TListener = class
public
procedure HandleLogin(const AEventType: string; AData: TJSONObject);
procedure HandleAny(const AEventType: string; AData: TJSONObject);
end;
procedure TListener.HandleLogin(const AEventType: string; AData: TJSONObject);
begin
Writeln('login listener: user=', AData.Get('username', '?'));
end;
procedure TListener.HandleAny(const AEventType: string; AData: TJSONObject);
begin
Writeln('audit log: type=', AEventType);
end;
var
Bus: TEventBus;
L: TListener;
Data: TJSONObject;
begin
Bus := TEventBus.Create;
L := TListener.Create;
try
{ Subscribe to a specific event. }
Bus.Subscribe('demo', 'user.login', @L.HandleLogin);
{ Subscribe to every event. }
Bus.Subscribe('audit', '*', @L.HandleAny);
Data := TJSONObject.Create;
try
Data.Add('username', 'alice');
Bus.Fire('auth', 'user.login', Data);
finally
Data.Free;
end;
Data := TJSONObject.Create;
try
Data.Add('node', 1);
Bus.Fire('telnet', 'session.start', Data);
finally
Data.Free;
end;
{ Bulk Unsubscribe by group key. }
Bus.Unsubscribe('audit');
Writeln('after Unsubscribe(audit), count=', Bus.GetSubscriptionCount);
finally
L.Free;
Bus.Free;
end;
end.