feature/23-voice-room/poc #93
@@ -17,13 +17,18 @@
|
||||
|
||||
const participants = deriveVoiceParticipants(url, h)
|
||||
const isActive = $derived($currentVoiceSession?.url === url && $currentVoiceSession?.h === h)
|
||||
let isJoining = $state(false)
|
||||
|
||||
const handleClick = async () => {
|
||||
if (isJoining) return
|
||||
isJoining = true
|
||||
try {
|
||||
await joinVoiceRoom(url, h)
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : String(e)
|
||||
pushToast({theme: "error", message: `Failed to join voice room: ${message}`})
|
||||
} finally {
|
||||
isJoining = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +40,15 @@
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<SecondaryNavItem onclick={handleClick} class={isActive ? "!bg-base-100 !text-base-content" : ""}>
|
||||
<Icon icon={Volume} size={4} class="opacity-70" />
|
||||
<SecondaryNavItem
|
||||
onclick={handleClick}
|
||||
disabled={isJoining}
|
||||
|
hodlbod marked this conversation as resolved
Outdated
|
||||
class={isActive ? "!bg-base-100 !text-base-content" : ""}>
|
||||
{#if isJoining}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
{:else}
|
||||
<Icon icon={Volume} size={4} class="opacity-70" />
|
||||
{/if}
|
||||
|
hodlbod marked this conversation as resolved
Outdated
hodlbod
commented
Why do the bots do this? I have seen this cause bugs more than once. Just do Why do the bots do this? I have seen this cause bugs more than once. Just do `e.message || String(e)`. Or, better yet, actually design the error types and don't put anything that gets thrown in a message to the user. Just tell them "Failed to join voice room" and log it if it's not an error we know what to do with.
mplorentz
commented
I am cleaning this up but I want to fully understand you. Can you explain how this causes bugs? As a non-javascript guy this doesn't look pretty but makes sense to me because I understand the current code risks showing raw error messages to the user (which doesn't bother me actually as long as it has a nice prefix like "Failed to join voice room"). Is there something worse that I am missing? I am cleaning this up but I want to fully understand you. Can you explain how this causes bugs? As a non-javascript guy this doesn't look pretty but makes sense to me because `e` could literally be any type and there is no way to write a catch block for a specific type, so it seems reasonably defensive to check the type before just grabbing the `message` property off of whatever might have been thrown. Or in the case where some library throws a String it seems reasonable to surface that.
I understand the current code risks showing raw error messages to the user (which doesn't bother me actually as long as it has a nice prefix like "Failed to join voice room"). Is there something worse that I am missing?
mplorentz
commented
Idk maybe it is stupid to think that some library would throw some random object with a Idk maybe it is stupid to think that some library would throw some random object with a `message` property, but anything seems possible when `node_modules` are involved 😓
mplorentz
commented
Oh interesting, Oh interesting, `e.message || String(e)` actually gives a typescript error: `'e' is of type 'unknown'.`. But AI found the `errorMessage()` function from `@lib/util` so I'll use that.
hodlbod
commented
The problem is when a pojo with a message gets thrown or rejected, which means the object gets cast to a string, which fails to show the message. This is the case when you probably actually want to show the message to the user, whereas showing an error's message is almost always confusing. Errors being completely untyped are a huge flaw in typescript, so I like to save throws for truly exceptional cases (https://effect.website/ does this more formally, and I think it's a good idea), in which case you want to log and recover if you can, and resolve/return everything else (even errors that are deferred to the caller). But I'm certainly not consistent about this.
The problem is when a pojo with a message gets thrown or rejected, which means the object gets cast to a string, which fails to show the message. This is the case when you probably actually want to show the message to the user, whereas showing an error's message is almost always confusing. Errors being completely untyped are a huge flaw in typescript, so I like to save throws for truly exceptional cases (https://effect.website/ does this more formally, and I think it's a good idea), in which case you want to log and recover if you can, and resolve/return everything else (even errors that are deferred to the caller). But I'm certainly not consistent about this.
`errorMessage` was introduced by an LLM too (via Tyson), I don't really believe in it either. I think we should just avoid propagating thrown errors to the user (I don't like the "Failed to do x: [technical jargon]" pattern. It helps to debug some, but not really in that many cases.
|
||||
<RoomName {url} {h} />
|
||||
</SecondaryNavItem>
|
||||
{#if $participants.length > 0}
|
||||
|
||||
[nit] in situations like this, I like to overload the controller as the isJoining boolean and just check whether joinAbortController is undefined. One fewer variable to keep track of