mirror of
https://github.com/ershisan99/www.git
synced 2026-01-05 21:02:08 +00:00
update stream card, update leaderboards on match finished webhook
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { discord_router } from '@/server/api/routers/discord'
|
||||
import { history_router } from '@/server/api/routers/history'
|
||||
import { leaderboard_router } from '@/server/api/routers/leaderboard'
|
||||
import { playerStateRouter } from '@/server/api/routers/player-state'
|
||||
import { createCallerFactory, createTRPCRouter } from '@/server/api/trpc'
|
||||
|
||||
/**
|
||||
@@ -12,6 +13,7 @@ export const appRouter = createTRPCRouter({
|
||||
history: history_router,
|
||||
discord: discord_router,
|
||||
leaderboard: leaderboard_router,
|
||||
playerState: playerStateRouter,
|
||||
})
|
||||
|
||||
// export type definition of API
|
||||
|
||||
50
src/server/api/routers/player-state.ts
Normal file
50
src/server/api/routers/player-state.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { createEventIterator, globalEmitter } from '@/lib/events'
|
||||
import { redis } from '@/server/redis'
|
||||
import { tracked } from '@trpc/server'
|
||||
import { z } from 'zod'
|
||||
import { createTRPCRouter, publicProcedure } from '../trpc'
|
||||
|
||||
export type PlayerState = {
|
||||
status: 'idle' | 'queuing' | 'in_game'
|
||||
queueStartTime?: number
|
||||
currentMatch?: {
|
||||
opponentId: string
|
||||
startTime: number
|
||||
}
|
||||
}
|
||||
|
||||
const PLAYER_STATE_KEY = (userId: string) => `player:${userId}:state`
|
||||
|
||||
export const playerStateRouter = createTRPCRouter({
|
||||
getState: publicProcedure
|
||||
.input(z.string())
|
||||
.query(async ({ input: userId }) => {
|
||||
const state = await redis.get(PLAYER_STATE_KEY(userId))
|
||||
return state ? (JSON.parse(state) as PlayerState) : null
|
||||
}),
|
||||
onStateChange: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
userId: z.string(),
|
||||
lastEventId: z.string().optional(),
|
||||
})
|
||||
)
|
||||
.subscription(async function* ({ input, ctx, signal }) {
|
||||
const iterator = createEventIterator<PlayerState>(
|
||||
globalEmitter,
|
||||
`state-change:${input.userId}`,
|
||||
{ signal: signal }
|
||||
)
|
||||
|
||||
// get initial state
|
||||
const initialState = await redis.get(PLAYER_STATE_KEY(input.userId))
|
||||
if (initialState) {
|
||||
yield tracked('initial', JSON.parse(initialState) as PlayerState)
|
||||
}
|
||||
|
||||
// listen for updates
|
||||
for await (const [state] of iterator) {
|
||||
yield tracked(Date.now().toString(), state)
|
||||
}
|
||||
}),
|
||||
})
|
||||
@@ -2,3 +2,5 @@ import { env } from '@/env'
|
||||
import { Redis } from 'ioredis'
|
||||
|
||||
export const redis = new Redis(env.REDIS_URL)
|
||||
|
||||
export const PLAYER_STATE_KEY = (userId: string) => `player:${userId}:state`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redis } from '../redis'
|
||||
import { neatqueue_service } from './neatqueue.service'
|
||||
import { type LeaderboardEntry, neatqueue_service } from './neatqueue.service'
|
||||
|
||||
export class LeaderboardService {
|
||||
private getZSetKey(channel_id: string) {
|
||||
@@ -56,23 +56,19 @@ export class LeaderboardService {
|
||||
|
||||
async getUserRank(channel_id: string, user_id: string) {
|
||||
try {
|
||||
const zsetKey = this.getZSetKey(channel_id)
|
||||
const rank = await redis.zrevrank(zsetKey, user_id)
|
||||
|
||||
if (rank === null) return null
|
||||
|
||||
const userData = await redis.hgetall(this.getUserKey(user_id, channel_id))
|
||||
if (!userData) return null
|
||||
|
||||
return {
|
||||
rank: rank + 1,
|
||||
...userData,
|
||||
mmr: Number(userData.mmr),
|
||||
streak: userData.streak,
|
||||
}
|
||||
} as unknown as LeaderboardEntry
|
||||
} catch (error) {
|
||||
console.error('Error getting user rank:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const leaderboardService = new LeaderboardService()
|
||||
|
||||
Reference in New Issue
Block a user