Skip to content

Commit

Permalink
refactor: switch from websocket to api and sse endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
zAlweNy26 committed Jan 8, 2025
1 parent 2f80363 commit 17348c3
Show file tree
Hide file tree
Showing 15 changed files with 203 additions and 197 deletions.
78 changes: 0 additions & 78 deletions app/composables/peer.ts

This file was deleted.

51 changes: 29 additions & 22 deletions app/pages/board.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
<script lang="ts" setup>
import smorfiaLivornese from 'assets/livornese.json'
import smorfiaNapoletana from 'assets/napoletana.json'
import smorfiaPiemontese from 'assets/piemontese.json'
import smorfiaRomana from 'assets/romana.json'
import smorfiaTrapanese from 'assets/trapanese.json'
import livornese from 'assets/livornese.json'
import napoletana from 'assets/napoletana.json'
import piemontese from 'assets/piemontese.json'
import romana from 'assets/romana.json'
import trapanese from 'assets/trapanese.json'
import Dinero from 'dinero.js'
import { randomUUID } from 'uncrypto'
const gameId = useRouteQuery('id', randomUUID().split('-')[0]!)
const smirks = { napoletana, trapanese, romana, piemontese, livornese }
const { sendExtraction } = usePeer(gameId, 'host')
const { copy } = useClipboard()
const { data: gameId } = useFetch('/api/game/create', {
method: 'POST',
lazy: true,
transform: data => data.gameId!,
default: () => '',
})
const smirks = {
napoletana: smorfiaNapoletana,
trapanese: smorfiaTrapanese,
romana: smorfiaRomana,
piemontese: smorfiaPiemontese,
livornese: smorfiaLivornese,
}
const router = useRouter()
onMounted(() => {
router.push({ query: { id: gameId.value } })
})
const cards = Array.from({ length: 6 }).map((_, i) => {
let up = -5
Expand All @@ -30,7 +31,7 @@ const cards = Array.from({ length: 6 }).map((_, i) => {
})
const { currentLocale } = storeToRefs(useSettingsStore())
const { copy } = useClipboard()
const extractedNumbers = ref<number[]>([]), autoAnnounce = ref(false), currentNumber = ref<number>()
const totalPrize = ref(0.1), smirk = ref<keyof typeof smirks>(), speakText = ref<string>('')
Expand Down Expand Up @@ -95,12 +96,18 @@ function speechText() {
setTimeout(() => speak(), 250)
}
function extractNumber() {
async function extractNumber() {
const random = useSample([...remainingNumbers.value])
if (!random) return
currentNumber.value = random
extractedNumbers.value.push(random)
sendExtraction(random)
const { extractions } = await $fetch('/api/game/extract', {
method: 'POST',
body: {
gameId: gameId.value,
number: random,
},
})
extractedNumbers.value = extractions
}
</script>

Expand Down Expand Up @@ -155,8 +162,8 @@ function extractNumber() {
size="xl" highlight :aria-label="$t('board.smirk')" :items="smirkOptions" />
<NuSwitch v-model="autoAnnounce" :disabled="!smirk" size="xl" :label="$t('board.announcer')"
uncheckedIcon="i-tabler-x" checkedIcon="i-tabler-check" defaultValue />
<NuButton icon="i-tabler-numbers" :disabled="remaining === 0 || !smirk" size="xl"
:label="$t('board.draw')" @click="extractNumber()" />
<NuButton icon="i-tabler-numbers" :disabled="remaining === 0 || !smirk" size="xl" loadingAuto
:label="$t('board.draw')" @click="extractNumber" />
<NuCard v-if="currentSmirk" :ui="{ body: 'inline-flex items-center justify-center gap-4 !px-4 !py-2' }">
<span class="font-bold">{{ currentSmirk.number }}</span>
<div>
Expand Down
32 changes: 31 additions & 1 deletion app/pages/cards.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,37 @@ definePageMeta({
})
const gameId = useRouteQuery<string>('id')
const { extractions } = usePeer(gameId, 'client')
const { t } = useI18n(), toast = useToast()
const extractions = ref<number[]>([])
const { data, error } = useEventSource(() => `/game?id=${gameId.value}`)
watchImmediate(error, (err) => {
if (err) {
navigateTo({ path: '/', query: {} }, { redirectCode: 302 })
toast.add({
title: t('game.error.title'),
description: t('game.error.description'),
color: 'error',
})
}
})
watch(data, (val) => {
if (val === null) return
let content: number[]
try {
content = JSON.parse(val)
}
catch (error) {
console.error(error)
console.error('Failed to parse WebSocket data:', data)
return
}
extractions.value = content
})
const lastExtractions = computed(() => extractions.value.slice(-5))
Expand Down
18 changes: 16 additions & 2 deletions app/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
<script lang="ts" setup>
const { title } = useAppConfig()
const { t } = useI18n(), toast = useToast()
const gameId = ref('')
async function checkGame(cards: number) {
const { found } = await $fetch('/api/game/join', { query: { id: gameId.value } })
if (!found) {
toast.add({
title: t('game.error.title'),
description: t('game.error.description'),
color: 'error',
})
return
}
await navigateTo({ name: 'cards', query: { id: gameId.value, n: cards } })
}
</script>

<template>
Expand All @@ -26,8 +41,7 @@ const gameId = ref('')
:ui="{ leadingIcon: 'text-[var(--ui-primary)]' }" />
</NuFormField>
<NuButton v-for="n in 6" :key="n" :disabled="gameId.length !== 8" :variant="gameId.length !== 8 ? 'outline' : 'solid'"
:label="$t('cards.quantity', [n], n)" block size="xl"
:to="$localePath({ name: 'cards', query: { id: gameId, n } })" />
:label="$t('cards.quantity', [n], n)" block size="xl" @click="checkGame(n)" />
</template>
</NuModal>
</div>
Expand Down
Binary file modified bun.lockb
Binary file not shown.
4 changes: 0 additions & 4 deletions i18n/locales/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,6 @@
"game": {
"title": "{0} - {1} remaining numbers",
"id": "Game ID",
"end": {
"title": "Game ended",
"description": "The game was terminated by the player who created it."
},
"error": {
"title": "Game not found",
"description": "The game you are trying to access does not exist."
Expand Down
4 changes: 0 additions & 4 deletions i18n/locales/it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@
"id": "ID partita",
"title": "{0} - {1} numeri rimanenti",
"description": "Condividi questo ID con i tuoi amici per permettere loro di partecipare a questa partita!",
"end": {
"title": "Partita terminata",
"description": "La partita è stata terminata dal giocatore che l'ha creata."
},
"error": {
"title": "Partita non trovata",
"description": "La partita a cui stai cercando di accedere non esiste."
Expand Down
6 changes: 0 additions & 6 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
export default defineNuxtConfig({
devtools: { enabled: true },

nitro: {
experimental: {
websocket: true,
},
},

modules: [
'nuxt-lodash',
'@nuxthub/core',
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"nuxt-lodash": "2.5.3",
"pinia": "^2.3.0",
"uncrypto": "^0.1.3",
"unenv": "^1.10.0"
"unenv": "^1.10.0",
"zod": "^3.24.1"
},
"devDependencies": {
"@antfu/eslint-config": "^3.12.2",
Expand Down
19 changes: 19 additions & 0 deletions server/api/game/create.post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { randomUUID } from 'uncrypto'

export default defineEventHandler(async () => {
const [id, ...hostId] = randomUUID().split('-')

const game = await setGame(id, {
id,
extractions: [],
clients: [],
host: [id, ...hostId].join('-'),
})

console.info(`[Game: ${game.id}] Host ${game.host} created game`)
console.info(`Active games: ${await getActiveGames()}`)

return {
gameId: id,
}
})
28 changes: 28 additions & 0 deletions server/api/game/extract.post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { z } from 'zod'

const extractionSchema = z.object({
gameId: z.string().length(8),
number: z.number().min(1).max(90),
})

export default defineEventHandler(async (event) => {
const { gameId, number } = await readValidatedBody(event, body => extractionSchema.parse(body))

const game = await getGame(gameId)

if (!game) {
throw createError({
statusCode: 400,
statusMessage: 'Game not found',
})
}

game.extractions.push(number)
await setGame(gameId, game)

console.info(`[Game: ${gameId}] Host ${game.host} extracted number ${number}`)

return {
extractions: game.extractions,
}
})
15 changes: 15 additions & 0 deletions server/api/game/join.get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { z } from 'zod'

const checkSchema = z.object({
id: z.string().length(8),
})

export default defineEventHandler(async (event) => {
const { id } = await getValidatedQuery(event, body => checkSchema.parse(body))

const game = await getGame(id)

return {
found: !!game,
}
})
Loading

0 comments on commit 17348c3

Please sign in to comment.