Check if livekit is configured on the relay during room creation/edit
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
import ModalBody from "@lib/components/ModalBody.svelte"
|
import ModalBody from "@lib/components/ModalBody.svelte"
|
||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
import {uploadFile} from "@app/core/commands"
|
import {uploadFile} from "@app/core/commands"
|
||||||
|
import {checkRelayHasLivekit} from "@app/voice"
|
||||||
|
|
||||||
type RoomMode = "text" | "voice" | "both"
|
type RoomMode = "text" | "voice" | "both"
|
||||||
|
|
||||||
@@ -46,10 +47,29 @@
|
|||||||
|
|
||||||
const values = $state(initialValues)
|
const values = $state(initialValues)
|
||||||
let roomMode = $state<RoomMode>(getRoomModeFromEvent(initialValues.event))
|
let roomMode = $state<RoomMode>(getRoomModeFromEvent(initialValues.event))
|
||||||
|
let relayHasLivekit = $state<boolean | undefined>(undefined)
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
const u = url
|
||||||
|
let cancelled = false
|
||||||
|
checkRelayHasLivekit(u).then(has => {
|
||||||
|
if (!cancelled) relayHasLivekit = has
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
cancelled = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
const room = $state.snapshot(values)
|
const room = $state.snapshot(values)
|
||||||
|
|
||||||
|
if ((roomMode === "voice" || roomMode === "both") && !relayHasLivekit) {
|
||||||
|
return pushToast({
|
||||||
|
theme: "error",
|
||||||
|
message: "This relay does not support voice rooms.",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (imageFile) {
|
if (imageFile) {
|
||||||
const {error, result} = await uploadFile(imageFile, {
|
const {error, result} = await uploadFile(imageFile, {
|
||||||
maxWidth: 256,
|
maxWidth: 256,
|
||||||
@@ -211,8 +231,12 @@
|
|||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<select class="select select-bordered w-full" bind:value={roomMode} aria-label="Room type">
|
<select class="select select-bordered w-full" bind:value={roomMode} aria-label="Room type">
|
||||||
<option value="text">Text only</option>
|
<option value="text">Text only</option>
|
||||||
<option value="both">Text and voice</option>
|
<option value="both" disabled={relayHasLivekit === false}>
|
||||||
<option value="voice">Voice only</option>
|
Text and voice{relayHasLivekit === false ? " (not setup)" : ""}
|
||||||
|
</option>
|
||||||
|
<option value="voice" disabled={relayHasLivekit === false}>
|
||||||
|
Voice only{relayHasLivekit === false ? " (not setup)" : ""}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FieldInline>
|
</FieldInline>
|
||||||
|
|||||||
+26
-5
@@ -1,3 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Voice rooms via LiveKit. Note: Voice does not work on localhost in Firefox
|
||||||
|
* (ICE candidate gathering fails). Use Chrome or test from deployed HTTPS.
|
||||||
|
*/
|
||||||
import {DisconnectReason, Room, RoomEvent, Track} from "livekit-client"
|
import {DisconnectReason, Room, RoomEvent, Track} from "livekit-client"
|
||||||
import {getToken} from "nostr-tools/nip98"
|
import {getToken} from "nostr-tools/nip98"
|
||||||
import {derived, get, writable} from "svelte/store"
|
import {derived, get, writable} from "svelte/store"
|
||||||
@@ -9,6 +13,27 @@ import {pushToast} from "@app/util/toast"
|
|||||||
|
|
||||||
export const ROOM_PRESENCE = 10312
|
export const ROOM_PRESENCE = 10312
|
||||||
|
|
||||||
|
const livekitEndpoint = (url: string, groupId: string) => {
|
||||||
|
const httpUrl = url
|
||||||
|
.replace(/^wss:\/\//, "https://")
|
||||||
|
.replace(/^ws:\/\//, "http://")
|
||||||
|
.replace(/\/$/, "")
|
||||||
|
return `${httpUrl}/.well-known/nip29/livekit/${groupId}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const checkRelayHasLivekit = async (url: string): Promise<boolean> => {
|
||||||
|
const endpoint = livekitEndpoint(url, "nop")
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Currently we are hitting the API with no auth because zooid returns a 401 livekit
|
||||||
|
// is configured and 404 if it is not. But we need a standardized solution in the NIP.
|
||||||
|
const response = await fetch(endpoint)
|
||||||
|
return response.status === 401
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const PRESENCE_INTERVAL_MS = 60_000
|
const PRESENCE_INTERVAL_MS = 60_000
|
||||||
const PRESENCE_EXPIRY_S = 300
|
const PRESENCE_EXPIRY_S = 300
|
||||||
|
|
||||||
@@ -26,11 +51,7 @@ const fetchLivekitToken = async (
|
|||||||
groupId: string,
|
groupId: string,
|
||||||
signal?: AbortSignal,
|
signal?: AbortSignal,
|
||||||
): Promise<{server_url: string; participant_token: string}> => {
|
): Promise<{server_url: string; participant_token: string}> => {
|
||||||
const httpUrl = url
|
const endpoint = livekitEndpoint(url, groupId)
|
||||||
.replace(/^wss:\/\//, "https://")
|
|
||||||
.replace(/^ws:\/\//, "http://")
|
|
||||||
.replace(/\/$/, "")
|
|
||||||
const endpoint = `${httpUrl}/.well-known/nip29/livekit/${groupId}`
|
|
||||||
|
|
||||||
const $signer = signer.get()
|
const $signer = signer.get()
|
||||||
if (!$signer) throw new Error("No signer available")
|
if (!$signer) throw new Error("No signer available")
|
||||||
|
|||||||
Reference in New Issue
Block a user