Address PR comments on RoomForm
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
<script lang="ts">
|
||||
import {get} from "svelte/store"
|
||||
import type {Snippet} from "svelte"
|
||||
import {assoc, append, nth, type Maybe, uniqBy} from "@welshman/lib"
|
||||
import type {RoomMeta} from "@welshman/util"
|
||||
import {makeRoomMeta} from "@welshman/util"
|
||||
import {getTag, makeRoomMeta} from "@welshman/util"
|
||||
import {waitForThunkError, createRoom, editRoom, joinRoom} from "@welshman/app"
|
||||
import StickerSmileSquare from "@assets/icons/sticker-smile-square.svg?dataurl"
|
||||
import Hashtag from "@assets/icons/hashtag.svg?dataurl"
|
||||
@@ -15,14 +17,14 @@
|
||||
import ModalBody from "@lib/components/ModalBody.svelte"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {uploadFile} from "@app/core/commands"
|
||||
import {checkRelayHasLivekit} from "@app/voice"
|
||||
import {deriveHasLivekit} from "@app/core/state"
|
||||
|
||||
type RoomMode = "text" | "voice" | "both"
|
||||
|
||||
const getRoomModeFromEvent = (event?: {tags?: string[][]}): RoomMode => {
|
||||
const getRoomModeFromEvent = (event: Maybe<{tags: Maybe<string[][]>}>): RoomMode => {
|
||||
const tags = event?.tags ?? []
|
||||
const hasLivekit = tags.some(t => t[0] === "livekit")
|
||||
const hasNoText = tags.some(t => t[0] === "no-text")
|
||||
const hasLivekit = !!getTag("livekit", tags)
|
||||
const hasNoText = !!getTag("no-text", tags)
|
||||
if (hasLivekit && hasNoText) return "voice"
|
||||
if (hasLivekit) return "both"
|
||||
return "text"
|
||||
@@ -30,8 +32,9 @@
|
||||
|
||||
const buildTagsWithRoomMode = (existingTags: string[][], roomMode: RoomMode): string[][] => {
|
||||
const filtered = existingTags.filter(t => t[0] !== "livekit" && t[0] !== "no-text")
|
||||
if (roomMode === "both") return [...filtered, ["livekit"]]
|
||||
if (roomMode === "voice") return [...filtered, ["livekit"], ["no-text"]]
|
||||
if (roomMode === "both") return uniqBy(nth(0), append(["livekit"], filtered))
|
||||
if (roomMode === "voice")
|
||||
return uniqBy(nth(0), append(["no-text"], append(["livekit"], filtered)))
|
||||
return filtered
|
||||
}
|
||||
|
||||
@@ -47,23 +50,12 @@
|
||||
|
||||
const values = $state(initialValues)
|
||||
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 relayHasLivekit = deriveHasLivekit(url)
|
||||
|
||||
const submit = async () => {
|
||||
const room = $state.snapshot(values)
|
||||
|
||||
if ((roomMode === "voice" || roomMode === "both") && !relayHasLivekit) {
|
||||
if ((roomMode === "voice" || roomMode === "both") && !get(relayHasLivekit)) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "This relay does not support voice rooms.",
|
||||
@@ -84,16 +76,17 @@
|
||||
room.pictureMeta = result.tags
|
||||
}
|
||||
|
||||
const existingTags = room.event?.tags ?? []
|
||||
const tags = buildTagsWithRoomMode(existingTags, roomMode)
|
||||
room.event = room.event ? {...room.event, tags} : ({tags} as RoomMeta["event"])
|
||||
|
||||
const createMessage = await waitForThunkError(createRoom(url, room))
|
||||
|
||||
if (createMessage && !createMessage.includes("already")) {
|
||||
return pushToast({theme: "error", message: createMessage})
|
||||
}
|
||||
|
||||
if (room.event && get(relayHasLivekit)) {
|
||||
const existingTags = room.event.tags ?? []
|
||||
const tags = buildTagsWithRoomMode(existingTags, roomMode)
|
||||
room.event = assoc("tags", tags)(room.event) as RoomMeta["event"]
|
||||
}
|
||||
const editMessage = await waitForThunkError(editRoom(url, room))
|
||||
|
||||
if (editMessage) {
|
||||
@@ -207,22 +200,23 @@
|
||||
</label>
|
||||
{/snippet}
|
||||
</FieldInline>
|
||||
<FieldInline>
|
||||
{#snippet label()}
|
||||
<p>Room type</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<select class="select select-bordered w-full" bind:value={roomMode} aria-label="Room type">
|
||||
<option value="text">Text only</option>
|
||||
<option value="both" disabled={relayHasLivekit === false}>
|
||||
Text and voice{relayHasLivekit === false ? " (not setup)" : ""}
|
||||
</option>
|
||||
<option value="voice" disabled={relayHasLivekit === false}>
|
||||
Voice only{relayHasLivekit === false ? " (not setup)" : ""}
|
||||
</option>
|
||||
</select>
|
||||
{/snippet}
|
||||
</FieldInline>
|
||||
{#if $relayHasLivekit}
|
||||
<FieldInline>
|
||||
{#snippet label()}
|
||||
<p>Room type</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<select
|
||||
class="select select-bordered w-full"
|
||||
bind:value={roomMode}
|
||||
aria-label="Room type">
|
||||
<option value="text">Text only</option>
|
||||
<option value="both">Text and voice</option>
|
||||
<option value="voice">Voice only</option>
|
||||
</select>
|
||||
{/snippet}
|
||||
</FieldInline>
|
||||
{/if}
|
||||
<strong class="md:hidden">Permissions</strong>
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="checkbox" class="checkbox" bind:checked={values.isRestricted} />
|
||||
|
||||
@@ -146,6 +146,7 @@ import {
|
||||
displayProfileByPubkey,
|
||||
getProfile,
|
||||
} from "@welshman/app"
|
||||
import {checkRelayHasLivekit} from "$lib/livekit"
|
||||
import {readFeed} from "@lib/feeds"
|
||||
|
||||
export const fromCsv = (s: string) => (s || "").split(",").filter(identity)
|
||||
@@ -1197,6 +1198,12 @@ export const deriveSupportedMethods = simpleCache(([url]: [string]) => {
|
||||
})
|
||||
})
|
||||
|
||||
export const deriveHasLivekit = simpleCache(([url]: [string]) =>
|
||||
readable<boolean | undefined>(undefined, set => {
|
||||
checkRelayHasLivekit(url).then(has => set(has))
|
||||
}),
|
||||
)
|
||||
|
||||
export const deriveTimeout = (timeout: number) => {
|
||||
const store = writable<boolean>(false)
|
||||
|
||||
|
||||
+3
-21
@@ -8,31 +8,13 @@ import {derived, get, writable} from "svelte/store"
|
||||
import {now} from "@welshman/lib"
|
||||
import {makeEvent, getTagValue} from "@welshman/util"
|
||||
import {signer, publishThunk} from "@welshman/app"
|
||||
import {getLivekitEndpoint} from "$lib/livekit"
|
||||
import {deriveEventsForUrl} from "@app/core/state"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
export {checkRelayHasLivekit} from "$lib/livekit"
|
||||
|
||||
const PRESENCE_INTERVAL_MS = 60_000
|
||||
const PRESENCE_EXPIRY_S = 300
|
||||
@@ -53,7 +35,7 @@ const fetchLivekitToken = async (
|
||||
groupId: string,
|
||||
signal?: AbortSignal,
|
||||
): Promise<{server_url: string; participant_token: string}> => {
|
||||
const endpoint = livekitEndpoint(url, groupId)
|
||||
const endpoint = getLivekitEndpoint(url, groupId)
|
||||
|
||||
const $signer = signer.get()
|
||||
if (!$signer) throw new Error("No signer available")
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
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 {
|
||||
// Zooid returns 401 when livekit is configured and 404 if it is not.
|
||||
const response = await fetch(endpoint)
|
||||
return response.status === 401
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export const getLivekitEndpoint = (url: string, groupId: string) => livekitEndpoint(url, groupId)
|
||||
Reference in New Issue
Block a user