*/ public function getDiscoveredServices(): array { $out = []; foreach ($this->discoverMysql() as $row) { $out[] = $row; } foreach ($this->discoverCacheFrontends() as $row) { $out[] = $row; } foreach ($this->discoverSessionRedis() as $row) { $out[] = $row; } foreach ($this->discoverAmqp() as $row) { $out[] = $row; } foreach ($this->discoverHttpCacheHosts() as $row) { $out[] = $row; } foreach ($this->discoverCatalogSearch() as $row) { $out[] = $row; } return $out; } /** * @return array{host: string, port: int}|null */ public function resolveService(string $serviceKey): ?array { foreach ($this->getDiscoveredServices() as $row) { if ($row['service_key'] === $serviceKey) { return ['host' => $row['host'], 'port' => $row['port']]; } } return null; } /** * @return list */ private function discoverMysql(): array { $conn = $this->deploymentConfig->get('db/connection/default'); if (!\is_array($conn)) { return []; } $host = trim((string) ($conn['host'] ?? '')); if ($host === '') { return []; } $port = $this->parsePort($conn['port'] ?? null) ?? 3306; return [[ 'service_key' => self::MYSQL_DEFAULT_KEY, 'label' => sprintf('MySQL (db/connection/default) — %s:%d', $host, $port), 'host' => $host, 'port' => $port, ]]; } /** * @return list */ private function discoverCacheFrontends(): array { $cache = $this->deploymentConfig->get('cache'); if (!\is_array($cache)) { return []; } $frontends = $cache['frontend'] ?? null; if (!\is_array($frontends)) { return []; } $out = []; foreach ($frontends as $name => $frontend) { if (!\is_array($frontend)) { continue; } $backend = (string) ($frontend['backend'] ?? ''); if ($backend === '' || stripos($backend, 'Redis') === false) { continue; } $opts = $frontend['backend_options'] ?? null; if (!\is_array($opts)) { continue; } $host = trim((string) ($opts['server'] ?? '')); $port = $this->parsePort($opts['port'] ?? null); if ($host === '' || $port === null) { continue; } $safeName = preg_replace('/[^a-zA-Z0-9_\-]/', '_', (string) $name) ?: 'frontend'; $key = 'cache_frontend_' . $safeName; $out[] = [ 'service_key' => $key, 'label' => sprintf('Redis cache (%s) — %s:%d', (string) $name, $host, $port), 'host' => $host, 'port' => $port, ]; } return $out; } /** * @return list */ private function discoverSessionRedis(): array { $session = $this->deploymentConfig->get('session'); if (!\is_array($session)) { return []; } if (strtolower((string) ($session['save'] ?? '')) !== 'redis') { return []; } $redis = $session['redis'] ?? null; if (!\is_array($redis)) { return []; } $host = trim((string) ($redis['host'] ?? '')); $port = $this->parsePort($redis['port'] ?? null); if ($host === '' || $port === null) { return []; } return [[ 'service_key' => self::SESSION_REDIS_KEY, 'label' => sprintf('Redis (sessions) — %s:%d', $host, $port), 'host' => $host, 'port' => $port, ]]; } /** * @return list */ private function discoverAmqp(): array { $queue = $this->deploymentConfig->get('queue'); if (!\is_array($queue)) { return []; } $amqp = $queue['amqp'] ?? null; if (!\is_array($amqp)) { return []; } $host = trim((string) ($amqp['host'] ?? '')); $port = $this->parsePort($amqp['port'] ?? null); if ($host === '' || $port === null) { return []; } return [[ 'service_key' => self::QUEUE_AMQP_KEY, 'label' => sprintf('RabbitMQ (AMQP) — %s:%d', $host, $port), 'host' => $host, 'port' => $port, ]]; } /** * @return list */ private function discoverHttpCacheHosts(): array { $hosts = $this->deploymentConfig->get('http_cache_hosts'); if (!\is_array($hosts)) { return []; } $out = []; foreach ($hosts as $i => $entry) { if (!\is_array($entry)) { continue; } $host = trim((string) ($entry['host'] ?? '')); $port = $this->parsePort($entry['port'] ?? null); if ($host === '' || $port === null) { continue; } $key = 'http_cache_' . $i; $out[] = [ 'service_key' => $key, 'label' => sprintf('HTTP cache host — %s:%d', $host, $port), 'host' => $host, 'port' => $port, ]; } return $out; } /** * Elasticsearch / OpenSearch from catalog/search in env when present. * * @return list */ private function discoverCatalogSearch(): array { $catalog = $this->deploymentConfig->get('catalog'); if (!\is_array($catalog)) { return []; } $search = $catalog['search'] ?? null; if (!\is_array($search)) { return []; } $candidates = [ [ 'key' => 'catalog_search_elasticsearch7', 'host' => 'elasticsearch7_server_hostname', 'port' => 'elasticsearch7_server_port', 'label' => 'Elasticsearch 7', ], [ 'key' => 'catalog_search_elasticsearch8', 'host' => 'elasticsearch8_server_hostname', 'port' => 'elasticsearch8_server_port', 'label' => 'Elasticsearch 8', ], [ 'key' => 'catalog_search_opensearch', 'host' => 'opensearch_server_hostname', 'port' => 'opensearch_server_port', 'label' => 'OpenSearch', ], ]; $out = []; foreach ($candidates as $c) { $host = trim((string) ($search[$c['host']] ?? '')); $port = $this->parsePort($search[$c['port']] ?? null); if ($host === '' || $port === null) { continue; } $out[] = [ 'service_key' => $c['key'], 'label' => sprintf('%s — %s:%d', $c['label'], $host, $port), 'host' => $host, 'port' => $port, ]; } return $out; } private function parsePort(mixed $value): ?int { if ($value === null || $value === '') { return null; } $n = (int) $value; return ($n >= 1 && $n <= 65535) ? $n : null; } }