Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: store ws client's current url #123

Merged
merged 1 commit into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions public/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ import './fade-scroll.js'
import './flash-message.js'
import './map-thumbnail.js'
import './notification.js'
import './navigation.js'
33 changes: 33 additions & 0 deletions public/js/navigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import htmx from './htmx.js'

/**
* @typedef WsSend
* @type {function}
* @param {string} message
*/

/**
* @typedef SocketWrapper
* @type {object}
* @property {WsSend} send
*/

/** @type {SocketWrapper} */
let socket

export function reportNavigation(/** @type {string} */ path) {
const msg = JSON.stringify({ navigated: path })
socket?.send(msg)
}

/**
* @param {{detail: {socketWrapper: SocketWrapper}}} event
*/
htmx.on('htmx:wsOpen', event => {
socket = event.detail.socketWrapper
reportNavigation(window.location.pathname)
})

htmx.on('htmx:pushedIntoHistory', ({ detail }) => {
reportNavigation(detail.path)
})
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default fp(
events.on('player:updated', ({ before, after }) => {
if (before.activeGame === undefined && after.activeGame !== undefined) {
app.gateway
.toPlayers(after.steamId)
.broadcast(async () => await GoToGame(after.activeGame!))
.to({ player: after.steamId })
.send(async () => await GoToGame(after.activeGame!))
}
})
},
Expand Down
54 changes: 39 additions & 15 deletions src/games/plugins/sync-clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,54 @@ import { GameScore } from '../views/html/game-score'
export default fp(async app => {
events.on('game:updated', async ({ before, after }) => {
if (before.state !== after.state) {
app.gateway.broadcast(async () => await GameStateIndicator({ game: after }))
app.gateway.broadcast(async actor => await ConnectInfo({ game: after, actor }))
app.gateway
.to({ url: `/games/${after.number}` })
.send(async () => await GameStateIndicator({ game: after }))
app.gateway
.to({ url: `/games/${after.number}` })
.send(async actor => await ConnectInfo({ game: after, actor }))

if ([GameState.launching, GameState.ended, GameState.interrupted].includes(after.state)) {
app.gateway.broadcast(async actor => await GameSlotList({ game: after, actor }))
app.gateway
.to({ url: `/games/${after.number}` })
.send(async actor => await GameSlotList({ game: after, actor }))
}
}

if (before.score?.blu !== after.score?.blu || before.score?.red !== after.score?.red) {
app.gateway.broadcast(async () => await GameScore({ game: after }))
app.gateway
.to({ url: `/games/${after.number}` })
.send(async () => await GameScore({ game: after }))
}

if (
before.connectString !== after.connectString ||
before.stvConnectString !== after.stvConnectString
) {
app.gateway.broadcast(async actor => await ConnectInfo({ game: after, actor }))
app.gateway
.to({ url: `/games/${after.number}` })
.send(async actor => await ConnectInfo({ game: after, actor }))
}

if (before.logsUrl !== after.logsUrl) {
app.gateway.broadcast(async () => await LogsLink({ game: after }))
app.gateway
.to({ url: `/games/${after.number}` })
.send(async () => await LogsLink({ game: after }))
}

if (before.demoUrl !== after.demoUrl) {
app.gateway.broadcast(async () => await DemoLink({ game: after }))
app.gateway
.to({ url: `/games/${after.number}` })
.send(async () => await DemoLink({ game: after }))
}

if (before.events.length < after.events.length) {
const n = before.events.length - after.events.length
const newEvents = after.events.slice(n)
for (const event of newEvents) {
app.gateway.broadcast(async () => await GameEventList.append({ game: after, event }))
app.gateway
.to({ url: `/games/${after.number}` })
.send(async () => await GameEventList.append({ game: after, event }))
}
}

Expand All @@ -62,8 +78,9 @@ export default fp(async app => {

if (beforeSlot.shouldJoinBy !== slot.shouldJoinBy) {
app.gateway
.toPlayers(slot.player)
.broadcast(async actor => await ConnectInfo({ game: after, actor }))
.to({ url: `/games/${after.number}` })
.to({ player: slot.player })
.send(async actor => await ConnectInfo({ game: after, actor }))
}
}),
)
Expand All @@ -76,9 +93,9 @@ export default fp(async app => {

events.on(
'game:updated',
whenGameEnds(async () => {
whenGameEnds(async ({ after }) => {
const cmp = await GamesLink()
app.gateway.broadcast(() => cmp)
app.gateway.to({ url: `/games/${after.number}` }).send(() => cmp)
}),
)

Expand All @@ -92,7 +109,10 @@ export default fp(async app => {
connectionStatus: playerConnectionStatus,
}),
)
app.gateway.toPlayers(player).broadcast(async actor => await ConnectInfo({ game, actor }))
app.gateway
.to({ url: `/games/${game.number}` })
.to({ player })
.send(async actor => await ConnectInfo({ game, actor }))
}),
)

Expand All @@ -102,11 +122,15 @@ export default fp(async app => {
throw new Error(`no such game slot: ${game.number} ${replacee}`)
}

app.gateway.broadcast(async actor => await GameSlot({ game, slot, actor }))
app.gateway
.to({ url: `/games/${game.number}` })
.send(async actor => await GameSlot({ game, slot, actor }))
})

events.on('game:playerReplaced', ({ game }) => {
// fixme refresh only one slot
app.gateway.broadcast(async actor => await GameSlotList({ game, actor }))
app.gateway
.to({ url: `/games/${game.number}` })
.send(async actor => await GameSlotList({ game, actor }))
})
})
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { nanoid } from 'nanoid'
import type { GameNumber } from '../../../database/models/game.model'
import { environment } from '../../../environment'

export function GoToGame(number: GameNumber) {
const id = nanoid()
return (
<div id="notify-container" hx-swap-oob="beforeend">
<script type="module" id={id}>{`
import htmx from '/js/htmx.js';
const path = '${environment.WEBSITE_URL}/games/${number}';
import { reportNavigation } from '/js/navigation.js';
const path = '/games/${number}';
htmx.ajax('get', path).then(() => {
history.pushState({}, '', path);
reportNavigation(path);
});
document.getElementById('${id}').remove();
`}</script>
Expand Down
4 changes: 0 additions & 4 deletions src/players/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import fp from 'fastify-plugin'
import { bySteamId } from './by-steam-id'
import { getPlayerGameCountOnClasses } from './get-player-game-count-on-classes'
import { update } from './update'
import { resolve } from 'node:path'

export const players = {
bySteamId,
Expand All @@ -12,9 +11,6 @@ export const players = {

export default fp(
async app => {
await app.register((await import('@fastify/autoload')).default, {
dir: resolve(import.meta.dirname, 'plugins'),
})
await app.register((await import('./routes')).default)
},
{ name: 'players' },
Expand Down
26 changes: 11 additions & 15 deletions src/queue/plugins/gateway-listeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default fp(
async function refreshTakenSlots(actor: SteamId64) {
const slots = await collections.queueSlots.find({ player: { $ne: null } }).toArray()
const cmps = await Promise.all(slots.map(async slot => await QueueSlot({ slot, actor })))
app.gateway.toPlayers(actor).broadcast(() => cmps)
app.gateway.to({ player: actor }).send(() => cmps)
}

app.gateway.on('queue:join', async (socket, slotId) => {
Expand All @@ -31,10 +31,10 @@ export default fp(

try {
const slots = await join(slotId, socket.player.steamId)
app.gateway.toPlayers(socket.player.steamId).broadcast(async () => await MapVote.enable())
app.gateway.to({ player: socket.player.steamId }).send(async () => await MapVote.enable())
app.gateway
.toPlayers(socket.player.steamId)
.broadcast(async () => await PreReadyUpButton.enable())
.to({ player: socket.player.steamId })
.send(async () => await PreReadyUpButton.enable())

if (slots.find(s => s.canMakeFriendsWith?.length)) {
await refreshTakenSlots(socket.player.steamId)
Expand All @@ -51,14 +51,10 @@ export default fp(

try {
const slot = await leave(socket.player.steamId)
app.gateway.toPlayers(socket.player.steamId).broadcast(async () => await MapVote.disable())
app.gateway.to({ player: socket.player.steamId }).send(async () => await MapVote.disable())
app.gateway
.toPlayers(socket.player.steamId)
.broadcast(async () => await PreReadyUpButton.disable())

app.gateway
.toPlayers(socket.player.steamId)
.broadcast(async actor => await MapVote({ actor }))
.to({ player: socket.player.steamId })
.send(async () => await PreReadyUpButton.disable())

if (slot.canMakeFriendsWith?.length) {
await refreshTakenSlots(socket.player.steamId)
Expand All @@ -67,7 +63,7 @@ export default fp(
const queueState = await getState()
if (queueState === QueueState.ready) {
const close = await ReadyUpDialog.close()
app.gateway.toPlayers(socket.player.steamId).broadcast(() => close)
app.gateway.to({ player: socket.player.steamId }).send(() => close)
}
} catch (error) {
logger.error(error)
Expand All @@ -81,7 +77,7 @@ export default fp(

try {
const [, close] = await Promise.all([readyUp(socket.player.steamId), ReadyUpDialog.close()])
app.gateway.toPlayers(socket.player.steamId).broadcast(() => close)
app.gateway.to({ player: socket.player.steamId }).send(() => close)
} catch (error) {
logger.error(error)
}
Expand All @@ -95,8 +91,8 @@ export default fp(
try {
await voteMap(socket.player.steamId, map)
app.gateway
.toPlayers(socket.player.steamId)
.broadcast(async actor => await MapVote({ actor }))
.to({ player: socket.player.steamId })
.send(async actor => await MapVote({ actor }))
} catch (error) {
logger.error(error)
}
Expand Down
54 changes: 29 additions & 25 deletions src/queue/plugins/sync-clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ export default fp(
async function syncAllSlots(...players: SteamId64[]) {
const slots = await collections.queueSlots.find().toArray()
slots.forEach(async slot => {
app.gateway.toPlayers(...players).broadcast(async actor => await QueueSlot({ slot, actor }))
app.gateway.to({ players }).send(async actor => await QueueSlot({ slot, actor }))
})
}

app.gateway.on('connected', async socket => {
app.gateway.on('ready', async socket => {
if (socket.currentUrl !== '/') {
return
}

const slots = await collections.queueSlots.find().toArray()
slots.forEach(async slot => {
socket.send(await QueueSlot({ slot, actor: socket.player?.steamId }))
Expand Down Expand Up @@ -62,14 +66,14 @@ export default fp(
safe(async ({ before, after }) => {
if (before.activeGame !== after.activeGame) {
const cmp = await RunningGameSnackbar({ gameNumber: after.activeGame })
app.gateway.toPlayers(after.steamId).broadcast(() => cmp)
app.gateway.to({ players: [after.steamId] }).send(() => cmp)
await syncAllSlots(after.steamId)
}

if (before.preReadyUntil !== after.preReadyUntil) {
app.gateway
.toPlayers(after.steamId)
.broadcast(async actor => await PreReadyUpButton({ actor }))
.to({ players: [after.steamId] })
.send(async actor => await PreReadyUpButton({ actor }))
}
}),
)
Expand Down Expand Up @@ -107,7 +111,7 @@ export default fp(
.filter(Boolean) as SteamId64[]

const show = await ReadyUpDialog.show()
app.gateway.toPlayers(...players).broadcast(() => show)
app.gateway.to({ players }).send(() => show)
}
}),
)
Expand All @@ -133,29 +137,29 @@ export default fp(
if (!slot) {
return
}
const actors = await collections.queueSlots
.find({ 'canMakeFriendsWith.0': { $exists: true }, player: { $ne: null } })
.toArray()
app.gateway
.toPlayers(...actors.map(a => a.player!))
.broadcast(async actor => await QueueSlot({ slot, actor }))
const players = (
await collections.queueSlots
.find({ 'canMakeFriendsWith.0': { $exists: true }, player: { $ne: null } })
.toArray()
).map(({ player }) => player!)
app.gateway.to({ players }).send(async actor => await QueueSlot({ slot, actor }))
}),
)

events.on(
'queue/friendship:updated',
safe(async ({ target }) => {
const actors = await collections.queueSlots
.find({ 'canMakeFriendsWith.0': { $exists: true }, player: { $ne: null } })
.toArray()
const players = (
await collections.queueSlots
.find({ 'canMakeFriendsWith.0': { $exists: true }, player: { $ne: null } })
.toArray()
).map(({ player }) => player!)

const slots = await collections.queueSlots
.find({ player: { $in: [target.before, target.after] } })
.toArray()
slots.forEach(slot => {
app.gateway
.toPlayers(...actors.map(a => a.player!))
.broadcast(async actor => await QueueSlot({ slot, actor }))
app.gateway.to({ players }).send(async actor => await QueueSlot({ slot, actor }))
})
}),
)
Expand All @@ -167,12 +171,12 @@ export default fp(
if (!slot) {
return
}
const actors = await collections.queueSlots
.find({ 'canMakeFriendsWith.0': { $exists: true }, player: { $ne: null } })
.toArray()
app.gateway
.toPlayers(...actors.map(a => a.player!))
.broadcast(async actor => await QueueSlot({ slot, actor }))
const players = (
await collections.queueSlots
.find({ 'canMakeFriendsWith.0': { $exists: true }, player: { $ne: null } })
.toArray()
).map(({ player }) => player!)
app.gateway.to({ players }).send(async actor => await QueueSlot({ slot, actor }))
}),
)

Expand All @@ -193,7 +197,7 @@ export default fp(

const refreshBanAlerts = async (player: SteamId64) => {
const cmp = await BanAlerts({ actor: player })
app.gateway.toPlayers(player).broadcast(() => cmp)
app.gateway.to({ players: [player] }).send(() => cmp)

setImmediate(async () => {
await syncAllSlots(player)
Expand Down
Loading
Loading