Maintain local ⭤ remote in sync with automatic AT Protocol parity for Laravel (alpha & unstable)
1<?php
2
3namespace SocialDept\AtpParity\Commands;
4
5use Illuminate\Console\Command;
6use SocialDept\AtpParity\Discovery\DiscoveryService;
7
8use function Laravel\Prompts\error;
9use function Laravel\Prompts\info;
10use function Laravel\Prompts\note;
11
12class DiscoverCommand extends Command
13{
14 protected $signature = 'parity:discover
15 {collection : The collection NSID to discover (e.g., app.bsky.feed.post)}
16 {--limit= : Maximum number of DIDs to discover}
17 {--import : Import records for discovered DIDs}
18 {--output= : Output DIDs to file (one per line)}
19 {--count : Only count DIDs without listing them}';
20
21 protected $description = 'Discover DIDs with records in a specific collection';
22
23 public function handle(DiscoveryService $service): int
24 {
25 $collection = $this->argument('collection');
26 $limit = $this->option('limit') ? (int) $this->option('limit') : null;
27
28 if ($this->option('count')) {
29 return $this->handleCount($service, $collection);
30 }
31
32 if ($this->option('import')) {
33 return $this->handleDiscoverAndImport($service, $collection, $limit);
34 }
35
36 return $this->handleDiscover($service, $collection, $limit);
37 }
38
39 protected function handleCount(DiscoveryService $service, string $collection): int
40 {
41 info("Counting DIDs with records in {$collection}...");
42
43 $count = $service->count($collection);
44
45 info("Found {$count} DIDs");
46
47 return self::SUCCESS;
48 }
49
50 protected function handleDiscover(DiscoveryService $service, string $collection, ?int $limit): int
51 {
52 $limitDisplay = $limit ? " (limit: {$limit})" : '';
53 info("Discovering DIDs with records in {$collection}{$limitDisplay}...");
54
55 $result = $service->discover($collection, $limit);
56
57 if ($result->isFailed()) {
58 error("Discovery failed: {$result->error}");
59
60 return self::FAILURE;
61 }
62
63 if ($result->total === 0) {
64 note('No DIDs found');
65
66 return self::SUCCESS;
67 }
68
69 // Output to file if requested
70 if ($output = $this->option('output')) {
71 file_put_contents($output, implode("\n", $result->dids)."\n");
72 info("Found {$result->total} DIDs, written to {$output}");
73
74 if ($result->isIncomplete()) {
75 note('Results may be incomplete due to limit');
76 }
77
78 return self::SUCCESS;
79 }
80
81 // Output to console
82 foreach ($result->dids as $did) {
83 $this->line($did);
84 }
85
86 info("Found {$result->total} DIDs");
87
88 if ($result->isIncomplete()) {
89 note('Results may be incomplete due to limit');
90 }
91
92 return self::SUCCESS;
93 }
94
95 protected function handleDiscoverAndImport(DiscoveryService $service, string $collection, ?int $limit): int
96 {
97 $limitDisplay = $limit ? " (limit: {$limit})" : '';
98 info("Discovering and importing DIDs with records in {$collection}{$limitDisplay}...");
99
100 $result = $service->discoverAndImport(
101 $collection,
102 $limit,
103 function (string $did, int $count) {
104 note("[{$count}] Importing {$did}");
105 }
106 );
107
108 if ($result->isFailed()) {
109 error("Discovery failed: {$result->error}");
110
111 return self::FAILURE;
112 }
113
114 info("Imported records for {$result->total} DIDs");
115
116 if ($result->isIncomplete()) {
117 note('Results may be incomplete due to limit');
118 }
119
120 return self::SUCCESS;
121 }
122}