Lines 100.00% 55 / 55
Methods 100.00% 7 / 7
Classes 100.00% 1 / 1
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 takeSnapshot 100.00% 12 / 12 100.00% 1 / 1 1
 buildDaemonInfo 100.00% 9 / 9 100.00% 1 / 1 2
 buildBrokerStats 100.00% 7 / 7 100.00% 1 / 1 1
 buildRegistrationInfo 100.00% 8 / 8 100.00% 1 / 1 1
 buildDeployStatus 100.00% 10 / 10 100.00% 1 / 1 3
 buildComponentStatus 100.00% 8 / 8 100.00% 1 / 1 1
30final readonly class SnapshotAssembler implements SnapshotSource
31{
32    public function __construct(
33        private HaSession $session,
34        private StewartVersion $stewartVersion,
35        private DaemonStartTime $startTime,
36        private ConnectionTracker $connection,
37        private WorkerSlotRegistry $slots,
38        private HaCallSlots $callSlots,
39        private SubscriptionRegistry $registry,
40        private DeployState $deployState,
41        private ComponentTracker $componentTracker,
42        private ExposeConfig $expose,
43        private WorkerStatusBuilder $workerStatuses,
44        private AppStatusBuilder $appStatuses,
45        private StoreHealthBuilder $storeHealth,
46        private Clock $clock,
47    ) {}
48
49    public function takeSnapshot(): RuntimeSnapshot
50    {
51        return new RuntimeSnapshot(
52            takenAt: $this->clock->getNow(),
53            daemon: $this->buildDaemonInfo(),
54            connection: $this->connection->state,
55            broker: $this->buildBrokerStats(),
56            workers: $this->workerStatuses->buildWorkerStatuses(),
57            apps: $this->appStatuses->buildAppStatuses(),
58            subscriptions: array_map($this->buildRegistrationInfo(...), $this->registry->listSubscriptions()),
59            store: $this->storeHealth->buildStoreHealth(),
60            deploy: $this->buildDeployStatus(),
61            component: $this->buildComponentStatus(),
62        );
63    }
64
65    private function buildDaemonInfo(): DaemonInfo
66    {
67        return new DaemonInfo(
68            pid: getmypid() ?: 0,
69            startedAt: $this->startTime->getStartedAt(),
70            memoryBytes: memory_get_usage(true),
71            version: $this->stewartVersion->value,
72            timeZone: $this->session->getTimeZone()->getName(),
73            entities: $this->session->countEntities(),
74            haVersion: $this->session->getHaVersion(),
75        );
76    }
77
78    private function buildBrokerStats(): BrokerStats
79    {
80        return new BrokerStats(
81            workers: $this->slots->countSpawnedSlots(),
82            liveWorkers: $this->slots->countLiveWorkers(),
83            inFlightServiceCalls: $this->callSlots->inFlight,
84            refusedServiceCalls: $this->callSlots->refusedCalls,
85            routing: $this->registry->getRoutingStats(),
86        );
87    }
88
89    private function buildRegistrationInfo(BrokerSubscription $subscription): RegistrationInfo
90    {
91        return new RegistrationInfo(
92            subscriptionId: $subscription->subscriptionId->value,
93            workerId: $subscription->workerId->value,
94            appId: $subscription->scope->wireValue(),
95            kind: $subscription->kind,
96            selector: $subscription->selector->toCanonicalKey(),
97            exact: $subscription->selector->findExactPattern() !== null,
98        );
99    }
100
101    private function buildDeployStatus(): ?DeployStatus
102    {
103        $commit = $this->deployState->findRunningCommit();
104
105        if ($commit === null) {
106            return null;
107        }
108
109        $failure = $this->deployState->findLastFailure();
110
111        return new DeployStatus(
112            commit: $commit->value,
113            lastPolledAt: $this->deployState->findLastPolledAt(),
114            failures: $this->deployState->countFailures(),
115            lastFailure: $failure === null ? null : new DeployFailure($failure->commit->value, $failure->reason, $failure->failedAt),
116        );
117    }
118
119    private function buildComponentStatus(): ComponentStatus
120    {
121        $detection = $this->componentTracker->detection;
122
123        return new ComponentStatus(
124            state: $detection->state,
125            since: $detection->since,
126            instance: $this->expose->instance->value,
127            version: $detection->version?->componentVersion,
128            protocol: $detection->version?->protocol,
129        );
130    }
131}