feature: add support for services to use a path
This commit is contained in:
@@ -15,7 +15,11 @@ export function generateMarkdownTable(nodes: Node<NodeData>[]): string {
|
||||
.map((n) => {
|
||||
const d = n.data
|
||||
const services = d.services?.length
|
||||
? d.services.map((s) => `${s.service_name}:${s.port}`).join(', ')
|
||||
? d.services.map((s) => {
|
||||
const port = s.port != null ? `:${s.port}` : ''
|
||||
const path = s.path?.trim() ? s.path.trim() : ''
|
||||
return `${s.service_name}${port}${path}`
|
||||
}).join(', ')
|
||||
: EMPTY
|
||||
return [
|
||||
cell(d.label),
|
||||
|
||||
@@ -20,15 +20,82 @@ const NON_HTTP_PORTS = new Set([
|
||||
27017, 27018, // MongoDB
|
||||
])
|
||||
|
||||
function splitFirstHost(host: string): string {
|
||||
return host.split(',')[0]?.trim() ?? ''
|
||||
}
|
||||
|
||||
function parsePort(port: string): number | undefined {
|
||||
if (!/^\d+$/.test(port)) return undefined
|
||||
const parsed = Number.parseInt(port, 10)
|
||||
return parsed >= 1 && parsed <= 65535 ? parsed : undefined
|
||||
}
|
||||
|
||||
function parseHostParts(host: string): { protocol?: 'http' | 'https'; hostname: string; port?: number } | null {
|
||||
const firstHost = splitFirstHost(host)
|
||||
if (!firstHost) return null
|
||||
|
||||
if (firstHost.startsWith('http://') || firstHost.startsWith('https://')) {
|
||||
const url = new URL(firstHost)
|
||||
return {
|
||||
protocol: url.protocol === 'https:' ? 'https' : 'http',
|
||||
hostname: url.hostname,
|
||||
port: parsePort(url.port),
|
||||
}
|
||||
}
|
||||
|
||||
if (firstHost.startsWith('[')) {
|
||||
const bracketIndex = firstHost.indexOf(']')
|
||||
if (bracketIndex === -1) return { hostname: firstHost }
|
||||
const hostname = firstHost.slice(1, bracketIndex)
|
||||
const remainder = firstHost.slice(bracketIndex + 1)
|
||||
return {
|
||||
hostname,
|
||||
port: remainder.startsWith(':') ? parsePort(remainder.slice(1)) : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
const colonCount = (firstHost.match(/:/g) ?? []).length
|
||||
if (colonCount === 1) {
|
||||
const [hostname, rawPort] = firstHost.split(':')
|
||||
const parsedPort = parsePort(rawPort)
|
||||
if (hostname && parsedPort != null) {
|
||||
return { hostname, port: parsedPort }
|
||||
}
|
||||
}
|
||||
|
||||
return { hostname: firstHost }
|
||||
}
|
||||
|
||||
function normalizePath(path?: string): string {
|
||||
const trimmed = path?.trim()
|
||||
if (!trimmed) return ''
|
||||
if (trimmed === '/') return '/'
|
||||
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`
|
||||
}
|
||||
|
||||
function formatHostname(hostname: string): string {
|
||||
return hostname.includes(':') && !hostname.startsWith('[') ? `[${hostname}]` : hostname
|
||||
}
|
||||
|
||||
export function getServiceUrl(svc: ServiceInfo, host?: string): string | null {
|
||||
if (!host) return null
|
||||
if (svc.port === 22) return null // SSH — no browser
|
||||
if (svc.protocol === 'udp') return null // UDP — not HTTP
|
||||
if (NON_HTTP_PORTS.has(svc.port)) return null
|
||||
|
||||
const parts = parseHostParts(host)
|
||||
if (!parts?.hostname) return null
|
||||
|
||||
const effectivePort = svc.port ?? parts.port
|
||||
if (effectivePort === 22) return null // SSH — no browser
|
||||
if (effectivePort != null && NON_HTTP_PORTS.has(effectivePort)) return null
|
||||
|
||||
const name = svc.service_name.toLowerCase()
|
||||
const isHttps =
|
||||
const protocol = parts.protocol ?? (
|
||||
name.includes('https') || name.includes('ssl') || name.includes('tls') ||
|
||||
svc.port === 443 || svc.port === 8443
|
||||
return `${isHttps ? 'https' : 'http'}://${host}:${svc.port}`
|
||||
effectivePort === 443 || effectivePort === 8443
|
||||
? 'https'
|
||||
: 'http'
|
||||
)
|
||||
const base = `${protocol}://${formatHostname(parts.hostname)}`
|
||||
const port = effectivePort != null ? `:${effectivePort}` : ''
|
||||
return `${base}${port}${normalizePath(svc.path)}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user