Build Reactive Signals for Bluesky's AT Protocol Firehose in Laravel
1<?php
2
3namespace SocialDept\AtpSignals\Commands;
4
5use Illuminate\Console\Command;
6use InvalidArgumentException;
7use SocialDept\AtpSignals\Events\CommitEvent;
8use SocialDept\AtpSignals\Events\SignalEvent;
9
10class TestSignalCommand extends Command
11{
12 protected $signature = 'signal:test
13 {signal : The Signal class name}
14 {--sample=commit : The type of sample event to use}';
15
16 protected $description = 'Test a Signal with sample data';
17
18 public function handle(): int
19 {
20 $signalClass = $this->resolveSignalClass();
21
22 if ($signalClass === null) {
23 return self::FAILURE;
24 }
25
26 $signal = app($signalClass);
27
28 $this->displayTestHeader($signalClass);
29
30 $event = $this->createAndDisplaySampleEvent();
31
32 return $this->executeSignal($signal, $event);
33 }
34
35 private function resolveSignalClass(): ?string
36 {
37 $signalClass = $this->argument('signal');
38
39 if (! class_exists($signalClass)) {
40 $signalClass = 'App\\Signals\\'.$signalClass;
41 }
42
43 if (! class_exists($signalClass)) {
44 $this->error("Signal class not found: {$signalClass}");
45
46 return null;
47 }
48
49 return $signalClass;
50 }
51
52 private function displayTestHeader(string $signalClass): void
53 {
54 $this->info("Testing signal: {$signalClass}");
55 $this->newLine();
56 }
57
58 private function createAndDisplaySampleEvent(): SignalEvent
59 {
60 $event = $this->createSampleEvent($this->option('sample'));
61
62 $this->info('Sample event created:');
63 $this->line(json_encode($event->toArray(), JSON_PRETTY_PRINT));
64 $this->newLine();
65
66 return $event;
67 }
68
69 private function executeSignal(object $signal, SignalEvent $event): int
70 {
71 try {
72 if ($signal->shouldHandle($event)) {
73 $this->info('Calling signal->handle()...');
74 $signal->handle($event);
75 $this->info('✓ Signal executed successfully');
76 } else {
77 $this->warn('Signal->shouldHandle() returned false');
78 }
79 } catch (\Exception $e) {
80 $this->error('Error executing signal: '.$e->getMessage());
81
82 return self::FAILURE;
83 }
84
85 return self::SUCCESS;
86 }
87
88 protected function createSampleEvent(string $type): SignalEvent
89 {
90 return match ($type) {
91 'commit' => new SignalEvent(
92 did: 'did:plc:sample123456789',
93 timeUs: time() * 1000000,
94 kind: 'commit',
95 commit: new CommitEvent(
96 rev: 'sample-rev',
97 operation: 'create',
98 collection: 'app.bsky.feed.post',
99 rkey: 'sample-rkey',
100 record: (object) [
101 'text' => 'This is a sample post for testing',
102 'createdAt' => now()->toIso8601String(),
103 ],
104 cid: 'sample-cid',
105 ),
106 ),
107 default => throw new InvalidArgumentException("Unknown sample type: {$type}"),
108 };
109 }
110}