mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-02 06:46:18 +08:00
72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
import { ref } from 'vue'
|
|
|
|
const PORTS = [8765, 8766, 8767, 8768, 8769, 8770]
|
|
const HEALTH_TIMEOUT_MS = 1200
|
|
const RECHECK_MS = 15_000
|
|
const LOCAL_TIMEOUT_MS = 8000
|
|
|
|
export async function postWithLocalFallback(
|
|
localUrl: string | null,
|
|
body: any,
|
|
cloudPost: () => Promise<any>,
|
|
): Promise<any> {
|
|
if (localUrl) {
|
|
const ctrl = new AbortController()
|
|
const timeout = setTimeout(() => ctrl.abort(), LOCAL_TIMEOUT_MS)
|
|
try {
|
|
const response = await fetch(localUrl, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
signal: ctrl.signal,
|
|
})
|
|
if (response.ok) return await response.json()
|
|
} catch {
|
|
// Local Bridge is unavailable: continue with the existing cloud path.
|
|
} finally {
|
|
clearTimeout(timeout)
|
|
}
|
|
}
|
|
return cloudPost()
|
|
}
|
|
|
|
export async function probeLocalSpeech(ports: number[] = PORTS): Promise<string | null> {
|
|
for (const port of ports) {
|
|
const base = `http://127.0.0.1:${port}`
|
|
try {
|
|
const ctrl = new AbortController()
|
|
const timeout = setTimeout(() => ctrl.abort(), HEALTH_TIMEOUT_MS)
|
|
const response = await fetch(`${base}/health`, { signal: ctrl.signal })
|
|
clearTimeout(timeout)
|
|
if (!response.ok) continue
|
|
const body = await response.json()
|
|
if (body?.ok && body?.ready) return base
|
|
} catch {
|
|
// Port closed/refused: probe the next one.
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
const localBase = ref<string | null>(null)
|
|
let started = false
|
|
|
|
export function useLocalSpeechBridge() {
|
|
const refresh = async () => {
|
|
localBase.value = await probeLocalSpeech()
|
|
}
|
|
|
|
if (typeof window !== 'undefined' && !started) {
|
|
started = true
|
|
void refresh()
|
|
setInterval(() => void refresh(), RECHECK_MS)
|
|
}
|
|
|
|
return {
|
|
localBase,
|
|
/** Absolute endpoint URL, or null while no ready local Bridge is found. */
|
|
localUrl: (path: string) => (localBase.value ? localBase.value + path : null),
|
|
refresh,
|
|
}
|
|
}
|