Skip to content

Commit 37b48b4

Browse files
Cleanup the game even if deleting the peer fails (#46)
* Cleanup the game even if deleting the peer fails * Make it more clear that gameSession is always null after stopping * Improve error handling and toasts
1 parent 61fc79c commit 37b48b4

File tree

7 files changed

+62
-48
lines changed

7 files changed

+62
-48
lines changed
Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import type { RoomId } from '@fishjam-cloud/js-server-sdk';
1+
import {
2+
RoomNotFoundException,
3+
type RoomId,
4+
} from '@fishjam-cloud/js-server-sdk';
25
import { TRPCError } from '@trpc/server';
36
import { GameRoomFullError } from '../domain/errors.js';
47
import { GameRoom } from '../game/room.js';
@@ -9,30 +12,34 @@ import { publicProcedure } from '../trpc.js';
912
export const createPeer = publicProcedure
1013
.input(createPeerInputSchema)
1114
.mutation(async ({ ctx, input }) => {
12-
const room = await ctx.fishjam.getRoom(input.roomId as RoomId);
13-
if (!room) {
14-
throw new Error(`Room with id ${input.roomId} does not exist`);
15-
}
15+
try {
16+
const room = await ctx.fishjam.getRoom(input.roomId as RoomId);
1617

17-
let gameRoom = roomService.getGameRoom(room.id);
18-
if (!gameRoom) {
19-
gameRoom = new GameRoom(ctx.fishjam, ctx.notifierService, room.id);
20-
roomService.setGameRoom(room.id, gameRoom);
21-
}
18+
let gameRoom = roomService.getGameRoom(room.id);
19+
if (!gameRoom) {
20+
gameRoom = new GameRoom(ctx.fishjam, ctx.notifierService, room.id);
21+
roomService.setGameRoom(room.id, gameRoom);
22+
}
2223

23-
try {
2424
const { peer, peerToken } = await gameRoom.addPlayer(input.name);
2525
return {
2626
peer,
2727
token: peerToken,
2828
};
29-
} catch (error) {
30-
if (error instanceof GameRoomFullError) {
29+
} catch (e) {
30+
if (e instanceof RoomNotFoundException) {
31+
console.warn(`Room ${input.roomId} not found`);
32+
throw new TRPCError({
33+
code: 'NOT_FOUND',
34+
message: `Room does not exist`,
35+
});
36+
}
37+
if (e instanceof GameRoomFullError) {
3138
throw new TRPCError({
32-
code: 'BAD_REQUEST',
33-
message: error.message,
39+
code: 'CONFLICT',
40+
message: e.message,
3441
});
3542
}
36-
throw error;
43+
throw e;
3744
}
3845
});

deep-sea-stories/packages/backend/src/game/room.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -200,28 +200,28 @@ export class GameRoom {
200200
this.gameTimeoutId = null;
201201
}
202202

203-
if (this.gameSession) {
204-
await this.gameSession.stopGame(wait);
205-
try {
203+
try {
204+
if (this.gameSession) {
205+
await this.gameSession.stopGame(wait);
206206
await this.fishjamClient.deletePeer(
207207
this.roomId,
208208
this.gameSession.agentId,
209209
);
210-
this.gameSession = null;
211-
} catch (e) {
212-
if (!(e instanceof PeerNotFoundException)) throw e;
213210
}
211+
} catch (e) {
212+
if (!(e instanceof PeerNotFoundException)) throw e;
213+
} finally {
214+
this.gameSession = null;
215+
this.story = undefined;
216+
217+
this.notifierService.emitNotification(this.roomId, {
218+
type: 'gameEnded' as const,
219+
timestamp: Date.now(),
220+
});
221+
222+
this.gameStarted = false;
223+
console.log(`Stopped game for room ${this.roomId}`);
214224
}
215-
216-
this.story = undefined;
217-
218-
this.notifierService.emitNotification(this.roomId, {
219-
type: 'gameEnded' as const,
220-
timestamp: Date.now(),
221-
});
222-
223-
this.gameStarted = false;
224-
console.log(`Stopped game for room ${this.roomId}`);
225225
}
226226

227227
private async createFishjamAgent() {

deep-sea-stories/packages/web/src/components/AgentModeToggle.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { EarOff, Headphones } from 'lucide-react';
1+
import { Check, CircleX, EarOff, Headphones } from 'lucide-react';
22
import { type FC, useEffect, useState } from 'react';
3-
import { toast } from 'sonner';
43
import { useTRPCClient } from '@/contexts/trpc';
54
import { useAgentEvents } from '@/hooks/useAgentEvents';
65
import { Button } from './ui/button';
6+
import { toast } from './ui/sonner';
77

88
type AgentModeToggleProps = {
99
roomId: string;
@@ -40,10 +40,11 @@ const AgentModeToggle: FC<AgentModeToggleProps> = ({ roomId }) => {
4040
muted: !isAiMuted,
4141
});
4242

43-
toast.success(!isAiMuted ? 'Agent deafened' : 'Agent listening');
43+
toast(!isAiMuted ? 'Agent deafened' : 'Agent listening', Check);
4444
} catch (error) {
45-
console.error('Failed to toggle AI mode:', error);
46-
toast.error('Failed to toggle mode');
45+
console.error(error);
46+
const verb = isAiMuted ? 'undeafen' : 'deafen';
47+
toast(`Failed to ${verb} agent`, CircleX);
4748
} finally {
4849
setIsMutating(false);
4950
}

deep-sea-stories/packages/web/src/components/StorySelectionPanel.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { StoryData } from '@deep-sea-stories/common';
2-
import { Check } from 'lucide-react';
2+
import { Check, X } from 'lucide-react';
33
import type { FC } from 'react';
44
import { useEffect, useState } from 'react';
55
import { useTRPCClient } from '@/contexts/trpc';
@@ -38,7 +38,7 @@ const StorySelectionPanel: FC<StorySelectionPanelProps> = ({
3838
setStories(fetchedStories);
3939
} catch (error) {
4040
console.error('Failed to fetch stories:', error);
41-
toast('Failed to load stories', Check);
41+
toast('Failed to load stories', X);
4242
} finally {
4343
setIsLoadingStories(false);
4444
}
@@ -63,7 +63,7 @@ const StorySelectionPanel: FC<StorySelectionPanelProps> = ({
6363
} catch (error) {
6464
const errorMessage =
6565
error instanceof Error ? error.message : 'Failed to select story';
66-
toast(`Error: ${errorMessage}`, Check);
66+
toast(errorMessage, X);
6767
} finally {
6868
setIsStarting(false);
6969
}

deep-sea-stories/packages/web/src/components/ui/sonner.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const Toaster = ({ ...props }: ToasterProps) => {
3333
toastOptions={{
3434
classNames: {
3535
toast:
36-
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
36+
'group toast group-[.toaster]:text-foreground group-[.toaster]:border-border w-full items-center justify-center flex group-[.toaster]:shadow-lg',
3737
description: 'group-[.toast]:text-muted-foreground',
3838
actionButton:
3939
'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',

deep-sea-stories/packages/web/src/views/HomeView.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Footer from '@/components/Footer';
44
import TitleBar from '@/components/TitleBar';
55
import { Button } from '@/components/ui/button';
66
import { useTRPCClient } from '@/contexts/trpc';
7+
import { toast } from '@/components/ui/sonner';
8+
import { CircleX } from 'lucide-react';
79

810
export default function HomeView() {
911
const navigate = useNavigate();
@@ -16,7 +18,8 @@ export default function HomeView() {
1618
const room = await trpcClient.createRoom.mutate();
1719
navigate(`/${room.id}`);
1820
} catch (error) {
19-
console.error('Failed to create room:', error);
21+
toast('Failed to create room', CircleX);
22+
console.error(error);
2023
} finally {
2124
setIsLoading(false);
2225
}

deep-sea-stories/packages/web/src/views/JoinView.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
useInitializeDevices,
55
useMicrophone,
66
} from '@fishjam-cloud/react-client';
7-
import { Camera, Mic, User } from 'lucide-react';
7+
import { Camera, CircleX, Mic, User } from 'lucide-react';
88
import type { FC } from 'react';
99
import { useCallback, useEffect, useRef, useState } from 'react';
1010
import { DeviceSelect } from '@/components/DeviceSelect';
@@ -66,13 +66,16 @@ const JoinView: FC<JoinViewProps> = ({ roomId }) => {
6666
peerMetadata: { name },
6767
});
6868
} catch (error) {
69-
if (
70-
error instanceof TRPCClientError &&
71-
error.data?.code === 'BAD_REQUEST'
72-
) {
69+
if (!(error instanceof TRPCClientError)) {
70+
console.error(error);
71+
return;
72+
}
73+
74+
if (error.data?.code === 'BAD_REQUEST') {
7375
toast(error.message, User);
76+
} else {
77+
toast(error.message, CircleX);
7478
}
75-
console.error(error);
7679
}
7780
}, [trpcClient, roomId, joinRoom, name]);
7881

0 commit comments

Comments
 (0)