*/ public function getAllTunnelStatuses(): array { return $this->tunnelStatus->getAllTunnelStatuses(); } /** * @return list> */ public function listTunnelsFromRegistry(): array { return $this->tunnelRegistry->listTunnels(); } public function hasAnyNginxPendingReload(): bool { return $this->tunnelRegistry->anyTunnelHasNginxPendingReload(); } /** * Preset ports shown first in Admin (443 is typical for Holesail + HTTPS upstream). * * @return list */ public function getLocalPortPresetValues(): array { return [443, 80, 8080]; } /** * Initial Add-tunnel UI: preset key '443'|'80'|'8080'|'custom' and optional custom port when not a preset. * * @return array{preset: string, custom_port: int} */ public function getInitialLocalPortUiState(): array { $presets = $this->getLocalPortPresetValues(); $default = 443; foreach ($presets as $p) { if ($p === $default) { return ['preset' => (string) $p, 'custom_port' => $default]; } } return ['preset' => 'custom', 'custom_port' => $default]; } public function getDefaultHolesailSecure(): bool { return (bool) $this->scopeConfig->getValue(self::XML_MODE); } /** * @return list */ public function getWebsiteOptions(): array { $options = []; foreach ($this->storeManager->getWebsites() as $website) { $options[] = [ 'value' => (string) $website->getId(), 'label' => $website->getName() . ' (' . $website->getCode() . ')', ]; } return $options; } /** * JSON map: websiteId string => list of {id, name} */ public function getStoreGroupsByWebsiteJson(): string { $map = []; foreach ($this->storeManager->getWebsites() as $website) { $wid = (string) $website->getId(); $map[$wid] = []; foreach ($website->getGroups() as $group) { $map[$wid][] = [ 'id' => (string) $group->getId(), 'name' => $group->getName() . ' (' . $group->getCode() . ')', ]; } } return $this->json->serialize($map); } /** * @deprecated */ public function getTunnelStoreState(): ?array { return $this->tunnelStoreProvisioner->getPersistedState(); } public function getTunnelStoreCodeConstant(): string { return TunnelStoreProvisioner::STORE_CODE; } /** * Strip scheme for display so Admin shows hostname-only; persisted URLs stay full in state. */ public function getTunnelHostDisplay(?string $baseUrl): string { if ($baseUrl === null || $baseUrl === '') { return ''; } $parts = parse_url($baseUrl); if ($parts === false || empty($parts['host'])) { return $baseUrl; } $out = $parts['host']; if (!empty($parts['port'])) { $out .= ':' . $parts['port']; } if (!empty($parts['path']) && $parts['path'] !== '/' && $parts['path'] !== '') { $out .= rtrim($parts['path'], '/'); } return $out; } public function getStatusUrl(): string { return $this->getUrl('*/*/status'); } public function getIndexUrl(): string { return $this->getUrl('*/*/index'); } public function getLogtailUrl(): string { return $this->getUrl('*/*/logtail'); } public function getFormKey(): string { return $this->formKey->getFormKey(); } public function getLogFilePathForTunnel(string $tunnelId): string { return $this->tunnelStatus->getLogFilePath($tunnelId); } /** * @return string[] */ public function getRecentLogLinesForTunnel(string $tunnelId): array { $path = $this->tunnelStatus->getLogFilePath($tunnelId); if (!\is_readable($path)) { return []; } $size = filesize($path); if ($size === false || $size === 0) { return []; } $fp = fopen($path, 'rb'); if ($fp === false) { return []; } $start = max(0, $size - self::LOG_TAIL_BYTES); fseek($fp, $start); if ($start > 0) { fgets($fp); } $chunk = stream_get_contents($fp) ?: ''; fclose($fp); $lines = preg_split('/\R/', $chunk) ?: []; $lines = array_values(array_filter($lines, static fn ($l) => $l !== '')); if (\count($lines) > self::LOG_TAIL_LINES) { $lines = \array_slice($lines, -self::LOG_TAIL_LINES); } return $lines; } }