Build Reactive Signals for Bluesky's AT Protocol Firehose in Laravel
1<?php
2
3namespace SocialDept\AtpSignals;
4
5use Illuminate\Support\ServiceProvider;
6use SocialDept\AtpSignals\Commands\ConsumeCommand;
7use SocialDept\AtpSignals\Commands\InstallCommand;
8use SocialDept\AtpSignals\Commands\ListSignalsCommand;
9use SocialDept\AtpSignals\Commands\MakeSignalCommand;
10use SocialDept\AtpSignals\Commands\TestSignalCommand;
11use SocialDept\AtpSignals\Contracts\CursorStore;
12use SocialDept\AtpSignals\Services\EventDispatcher;
13use SocialDept\AtpSignals\Services\FirehoseConsumer;
14use SocialDept\AtpSignals\Services\JetstreamConsumer;
15use SocialDept\AtpSignals\Services\SignalManager;
16use SocialDept\AtpSignals\Services\SignalRegistry;
17use SocialDept\AtpSignals\Storage\DatabaseCursorStore;
18use SocialDept\AtpSignals\Storage\FileCursorStore;
19use SocialDept\AtpSignals\Storage\RedisCursorStore;
20
21class SignalServiceProvider extends ServiceProvider
22{
23 public function register(): void
24 {
25 $this->mergeConfigFrom(__DIR__.'/../config/signal.php', 'signal');
26
27 // Register cursor store
28 $this->app->singleton(CursorStore::class, function ($app) {
29 return match (config('signal.cursor_storage')) {
30 'redis' => new RedisCursorStore(),
31 'file' => new FileCursorStore(),
32 default => new DatabaseCursorStore(),
33 };
34 });
35
36 // Register signal registry
37 $this->app->singleton(SignalRegistry::class, function ($app) {
38 $registry = new SignalRegistry();
39
40 // Register configured signals
41 foreach (config('signal.signals', []) as $signal) {
42 $registry->register($signal);
43 }
44
45 return $registry;
46 });
47
48 // Register event dispatcher
49 $this->app->singleton(EventDispatcher::class, function ($app) {
50 return new EventDispatcher($app->make(SignalRegistry::class));
51 });
52
53 // Register Jetstream consumer
54 $this->app->singleton(JetstreamConsumer::class, function ($app) {
55 return new JetstreamConsumer(
56 $app->make(CursorStore::class),
57 $app->make(SignalRegistry::class),
58 $app->make(EventDispatcher::class),
59 );
60 });
61
62 // Register Firehose consumer
63 $this->app->singleton(FirehoseConsumer::class, function ($app) {
64 return new FirehoseConsumer(
65 $app->make(CursorStore::class),
66 $app->make(SignalRegistry::class),
67 $app->make(EventDispatcher::class),
68 );
69 });
70
71 // Register Signal manager
72 $this->app->singleton(SignalManager::class, function ($app) {
73 return new SignalManager(
74 $app->make(FirehoseConsumer::class),
75 $app->make(JetstreamConsumer::class),
76 );
77 });
78 }
79
80 public function boot(): void
81 {
82 if ($this->app->runningInConsole()) {
83 // Publish config
84 $this->publishes([
85 __DIR__.'/../config/signal.php' => config_path('signal.php'),
86 ], 'signal-config');
87
88 // Publish migrations
89 $this->publishes([
90 __DIR__.'/../database/migrations' => database_path('migrations'),
91 ], 'signal-migrations');
92
93 // Register commands
94 $this->commands([
95 InstallCommand::class,
96 ConsumeCommand::class,
97 ListSignalsCommand::class,
98 MakeSignalCommand::class,
99 TestSignalCommand::class,
100 ]);
101 }
102
103 // Load migrations
104 $this->loadMigrationsFrom(__DIR__.'/../database/migrations');
105 }
106}