Voice Room Membership Error #106

Merged
hodlbod merged 2 commits from bugfix/voice-room-membership-error into dev 2026-03-27 17:45:42 +00:00
2 changed files with 24 additions and 11 deletions
Showing only changes of commit 56d386cb6b - Show all commits
+1 -7
View File
@@ -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
View File
@@ -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})
}
Outdated
Review

I think this should probably go in the component as it was before. Otherwise, LGTM

I think this should probably go in the component as it was before. Otherwise, LGTM
Outdated
Review

It's not as simple as moving it back to the component here because by calling handleJoinError() from joinVoice() I stealth-fixed another bug which was that we weren't doing the full error handling flow on rejoinVoiceRoom(). rejoinVoiceRoom() is called from VoiceWidget and joinVoiceRoom() is called from VoiceRoomItem, so the helper handleJoinError() 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?

It's not as simple as moving it back to the component here because by calling `handleJoinError()` from `joinVoice()` I stealth-fixed another bug which was that we weren't doing the full error handling flow on `rejoinVoiceRoom()`. `rejoinVoiceRoom()` is called from `VoiceWidget` and `joinVoiceRoom()` is called from `VoiceRoomItem`, so the helper `handleJoinError()` 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?
Outdated
Review

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.

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.
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 () => {