Voice Room Membership Error #106
@@ -5,7 +5,6 @@
|
||||
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
||||
import RoomImage from "@app/components/RoomImage.svelte"
|
||||
import RoomName from "@app/components/RoomName.svelte"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {makeRoomPath} from "@app/util/routes"
|
||||
import {
|
||||
deriveVoiceParticipants,
|
||||
@@ -42,12 +41,7 @@
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await joinVoiceRoom(url, h)
|
||||
} catch (e) {
|
||||
console.error("Failed to join voice room", e)
|
||||
pushToast({theme: "error", message: "Failed to join voice room"})
|
||||
}
|
||||
await joinVoiceRoom(url, h)
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
|
||||
+23
-4
@@ -9,7 +9,7 @@ import type {TrustedEvent} from "@welshman/util"
|
||||
import {makeHttpAuth, makeHttpAuthHeader, getTags} from "@welshman/util"
|
||||
import {signer} from "@welshman/app"
|
||||
import {getLivekitEndpoint} from "$lib/livekit"
|
||||
import {AbortError, whenAborted, whenTimeout} from "$lib/util"
|
||||
import {AbortError, TimeoutError, whenAborted, whenTimeout} from "$lib/util"
|
||||
import {deriveLatestEventForUrl} from "@app/core/state"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
|
||||
@@ -17,6 +17,24 @@ export const LIVEKIT_PARTICIPANTS = 39004
|
||||
|
||||
export {checkRelayHasLivekit} from "$lib/livekit"
|
||||
|
||||
export class VoiceJoinMembershipError extends Error {
|
||||
constructor() {
|
||||
super("Failed to join voice room: you must be a member.")
|
||||
this.name = "VoiceJoinMembershipError"
|
||||
}
|
||||
}
|
||||
|
||||
const handleJoinError = (e: unknown) => {
|
||||
if (e instanceof AbortError) return
|
||||
console.error("Failed to join voice room", e)
|
||||
let message = "Failed to join voice room"
|
||||
if (e instanceof VoiceJoinMembershipError) message = e.message
|
||||
else if (e instanceof TimeoutError)
|
||||
message = "Connection timed out. Please check your network and try again."
|
||||
else if (e instanceof Error && e.message === "No signer available") message = e.message
|
||||
pushToast({theme: "error", message})
|
||||
}
|
||||
|
|
||||
|
||||
export type VoiceSession = {
|
||||
url: string
|
||||
h: string
|
||||
@@ -95,6 +113,7 @@ const fetchLivekitToken = async (
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text()
|
||||
if (response.status === 403) throw new VoiceJoinMembershipError()
|
||||
throw new Error(`Token request failed (${response.status}): ${text}`)
|
||||
}
|
||||
|
||||
@@ -243,8 +262,7 @@ export const joinVoiceRoom = async (url: string, h: string): Promise<void> => {
|
||||
playJoinSound()
|
||||
} catch (e) {
|
||||
if (isActive()) voiceState.set("disconnected")
|
||||
if (e instanceof AbortError) return
|
||||
throw e
|
||||
handleJoinError(e)
|
||||
} finally {
|
||||
if (isActive()) joinAbortController = undefined
|
||||
}
|
||||
@@ -266,7 +284,8 @@ export const leaveVoiceRoom = async () => {
|
||||
|
||||
export const rejoinVoiceRoom = () => {
|
||||
const target = get(currentVoiceRoom)
|
||||
if (target) joinVoiceRoom(target.url, target.h)
|
||||
if (!target) return
|
||||
void joinVoiceRoom(target.url, target.h)
|
||||
}
|
||||
|
||||
export const toggleMute = async () => {
|
||||
|
||||
Reference in New Issue
Block a user
I think this should probably go in the component as it was before. Otherwise, LGTM
It's not as simple as moving it back to the component here because by calling
handleJoinError()fromjoinVoice()I stealth-fixed another bug which was that we weren't doing the full error handling flow onrejoinVoiceRoom().rejoinVoiceRoom()is called fromVoiceWidgetandjoinVoiceRoom()is called fromVoiceRoomItem, so the helperhandleJoinError()needs to be available in both. If I move its definition into to one of those components then it needs to be imported in the other one which doesn't seem right.Are you cool with importing helpers from one component to another? Or should I create a new util class for this function? Or leave in in voice.ts? Or something else?
Yeah, occasionally I do export component helpers. As long as there's some kind of a dependency on the other component I think it's ok. The thing I want to avoid is mixing application logic and presentation layers.