KI-AGENT: Asterisk-Statusprüfung robuster machen

This commit is contained in:
2026-05-20 22:24:13 +02:00
parent 10f03e151d
commit 655a78392b
2 changed files with 76 additions and 33 deletions

View File

@@ -11,6 +11,17 @@ const telephonyEnabled = () =>
const asteriskHttpStatusUrl = () => const asteriskHttpStatusUrl = () =>
process.env.TELEPHONY_ASTERISK_HTTP_URL || "http://asterisk-dev:8088/ws" process.env.TELEPHONY_ASTERISK_HTTP_URL || "http://asterisk-dev:8088/ws"
const asteriskHttpStatusUrls = () => {
const configuredUrl = asteriskHttpStatusUrl()
return Array.from(new Set([
configuredUrl,
"http://asterisk-dev:8088/ws",
"http://host.docker.internal:8088/ws",
`http://127.0.0.1:${process.env.TELEPHONY_DEV_WS_PORT || "8088"}/ws`,
`http://localhost:${process.env.TELEPHONY_DEV_WS_PORT || "8088"}/ws`,
]))
}
const publicAsteriskWsUrl = () => const publicAsteriskWsUrl = () =>
process.env.TELEPHONY_ASTERISK_WS_URL || `ws://localhost:${process.env.TELEPHONY_DEV_WS_PORT || "8088"}/ws` process.env.TELEPHONY_ASTERISK_WS_URL || `ws://localhost:${process.env.TELEPHONY_DEV_WS_PORT || "8088"}/ws`
@@ -54,40 +65,52 @@ export default async function telephonyRoutes(server: FastifyInstance) {
server.get("/telephony/status", async () => { server.get("/telephony/status", async () => {
const enabled = telephonyEnabled() const enabled = telephonyEnabled()
const url = asteriskHttpStatusUrl() const urls = asteriskHttpStatusUrls()
if (!enabled) { let lastError: any = null
return { const attempts = []
enabled,
provider: "asterisk", for (const url of urls) {
reachable: false, try {
statusUrl: url, const response = await fetchWithTimeout(url)
message: "Telefonie ist nicht aktiviert.", attempts.push({
url,
reachable: true,
statusCode: response.status,
})
return {
enabled,
provider: "asterisk",
reachable: true,
statusCode: response.status,
statusUrl: url,
attempts,
message: enabled
? (response.ok ? "Asterisk ist erreichbar." : `Asterisk-HTTP ist erreichbar (HTTP ${response.status}).`)
: "Asterisk ist erreichbar, Telefonie ist aber noch nicht aktiviert.",
}
} catch (error: any) {
lastError = error
attempts.push({
url,
reachable: false,
message: error?.name === "AbortError"
? "Abgelaufen"
: (error?.message || "Nicht erreichbar"),
})
} }
} }
try { return {
const response = await fetchWithTimeout(url) enabled,
return { provider: "asterisk",
enabled, reachable: false,
provider: "asterisk", statusUrl: urls[0],
reachable: true, attempts,
statusCode: response.status, message: lastError?.name === "AbortError"
statusUrl: url, ? "Asterisk-Statusabfrage ist abgelaufen."
message: response.ok : (lastError?.message || "Asterisk ist nicht erreichbar."),
? "Asterisk ist erreichbar."
: `Asterisk-HTTP ist erreichbar (HTTP ${response.status}).`,
}
} catch (error: any) {
return {
enabled,
provider: "asterisk",
reachable: false,
statusUrl: url,
message: error?.name === "AbortError"
? "Asterisk-Statusabfrage ist abgelaufen."
: (error?.message || "Asterisk ist nicht erreichbar."),
}
} }
}) })
} }

View File

@@ -11,13 +11,15 @@ const websocketResult = ref(null)
const lastUpdated = ref(null) const lastUpdated = ref(null)
const statusColor = computed(() => { const statusColor = computed(() => {
if (status.value?.reachable) return "success"
if (!status.value?.enabled) return "warning" if (!status.value?.enabled) return "warning"
return status.value?.reachable ? "success" : "error" return "error"
}) })
const statusIcon = computed(() => { const statusIcon = computed(() => {
if (status.value?.reachable) return "i-heroicons-signal"
if (!status.value?.enabled) return "i-heroicons-pause-circle" if (!status.value?.enabled) return "i-heroicons-pause-circle"
return status.value?.reachable ? "i-heroicons-signal" : "i-heroicons-signal-slash" return "i-heroicons-signal-slash"
}) })
const websocketColor = computed(() => { const websocketColor = computed(() => {
@@ -174,7 +176,7 @@ onMounted(loadTelephony)
<span class="text-sm font-medium text-gray-700">Status</span> <span class="text-sm font-medium text-gray-700">Status</span>
</div> </div>
<p class="mt-3 text-lg font-semibold text-gray-950"> <p class="mt-3 text-lg font-semibold text-gray-950">
{{ status?.enabled ? (status?.reachable ? "Erreichbar" : "Nicht erreichbar") : "Deaktiviert" }} {{ status?.reachable ? "Erreichbar" : (status?.enabled ? "Nicht erreichbar" : "Deaktiviert") }}
</p> </p>
</div> </div>
@@ -206,6 +208,24 @@ onMounted(loadTelephony)
:title="status?.message || 'Telefonie wird geladen'" :title="status?.message || 'Telefonie wird geladen'"
:description="status?.statusUrl || 'Noch keine Status-URL geladen.'" :description="status?.statusUrl || 'Noch keine Status-URL geladen.'"
/> />
<div v-if="status?.attempts?.length" class="mt-4 rounded-lg border border-gray-200 bg-gray-50 p-3">
<p class="text-xs font-medium uppercase tracking-wide text-gray-500">
Geprüfte Status-Ziele
</p>
<div class="mt-2 grid gap-2">
<div
v-for="attempt in status.attempts"
:key="attempt.url"
class="flex items-center justify-between gap-3 text-sm"
>
<span class="break-all font-mono text-gray-700">{{ attempt.url }}</span>
<UBadge :color="attempt.reachable ? 'success' : 'neutral'" variant="soft">
{{ attempt.reachable ? `HTTP ${attempt.statusCode}` : "offline" }}
</UBadge>
</div>
</div>
</div>
</UCard> </UCard>
<UCard> <UCard>