128ddcb4df
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.
75 lines
1.6 KiB
ObjectPascal
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.
|