I Want To Heal 2 build v1.0.5 code
This commit is contained in:
@@ -19,6 +19,10 @@ const port = Number(process.env.PORT ?? 4173)
|
||||
const pool = createPool()
|
||||
const sessionCookieName = 'iwanttoheal2_session'
|
||||
const sessionLifetimeSeconds = 60 * 60 * 24 * 30
|
||||
const arenaQueue = new Map()
|
||||
const arenaMatches = new Map()
|
||||
const arenaQueueTtlMs = 15 * 1000
|
||||
const arenaMatchTtlMs = 60 * 60 * 1000
|
||||
|
||||
const corsOrigins = new Set(
|
||||
(process.env.CORS_ORIGINS ?? '')
|
||||
@@ -144,6 +148,10 @@ async function handleApi(request, response, url) {
|
||||
if (!user) return
|
||||
const body = await readJson(request)
|
||||
const mode = String(body?.mode ?? 'action-healer')
|
||||
if (mode === 'arenas') {
|
||||
sendJson(response, 200, joinArenaQueue(user))
|
||||
return
|
||||
}
|
||||
const rating = Number(body?.rating ?? 1000)
|
||||
const queued = await pool.query(
|
||||
`
|
||||
@@ -159,6 +167,14 @@ async function handleApi(request, response, url) {
|
||||
return
|
||||
}
|
||||
|
||||
const arenaQueueTicket = url.pathname.match(/^\/api\/pvp\/queue\/([A-Za-z0-9_-]+)$/)
|
||||
if (request.method === 'GET' && arenaQueueTicket) {
|
||||
const user = await requireUser(request, response)
|
||||
if (!user) return
|
||||
sendJson(response, 200, checkArenaQueue(user, arenaQueueTicket[1]))
|
||||
return
|
||||
}
|
||||
|
||||
if (request.method === 'DELETE' && url.pathname === '/api/pvp/queue') {
|
||||
const user = await requireUser(request, response)
|
||||
if (!user) return
|
||||
@@ -168,9 +184,127 @@ async function handleApi(request, response, url) {
|
||||
return
|
||||
}
|
||||
|
||||
if (request.method === 'DELETE' && arenaQueueTicket) {
|
||||
const user = await requireUser(request, response)
|
||||
if (!user) return
|
||||
cancelArenaQueue(user, arenaQueueTicket[1])
|
||||
sendJson(response, 200, { ok: true })
|
||||
return
|
||||
}
|
||||
|
||||
sendJson(response, 404, { error: 'not_found' })
|
||||
}
|
||||
|
||||
function cleanupArenaMemory(now = Date.now()) {
|
||||
for (const [ticketId, ticket] of arenaQueue.entries()) {
|
||||
if (now - ticket.updatedAt > arenaQueueTtlMs) arenaQueue.delete(ticketId)
|
||||
}
|
||||
for (const [matchId, match] of arenaMatches.entries()) {
|
||||
if (now - match.updatedAt > arenaMatchTtlMs) arenaMatches.delete(matchId)
|
||||
}
|
||||
}
|
||||
|
||||
function arenaPlayerInfo(user) {
|
||||
return {
|
||||
accountId: user.id,
|
||||
displayName: user.display_name ?? user.username ?? 'Arena Player',
|
||||
username: user.username ?? user.auth_subject,
|
||||
}
|
||||
}
|
||||
|
||||
function arenaSnapshot(match) {
|
||||
return {
|
||||
id: match.id,
|
||||
mode: 'arenas',
|
||||
createdAt: match.createdAt,
|
||||
players: match.players,
|
||||
updatedAt: match.updatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
function createArenaMatch(players, now = Date.now()) {
|
||||
const match = {
|
||||
id: randomBytes(12).toString('base64url'),
|
||||
players,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}
|
||||
arenaMatches.set(match.id, match)
|
||||
return match
|
||||
}
|
||||
|
||||
function joinArenaQueue(user) {
|
||||
const now = Date.now()
|
||||
cleanupArenaMemory(now)
|
||||
const existingTicket = [...arenaQueue.values()].find((ticket) => ticket.accountId === user.id)
|
||||
if (existingTicket?.matchId) {
|
||||
const match = arenaMatches.get(existingTicket.matchId)
|
||||
if (match) {
|
||||
const side = match.players.a.accountId === user.id ? 'a' : 'b'
|
||||
return { ticketId: existingTicket.id, status: 'matched', side, match: arenaSnapshot(match) }
|
||||
}
|
||||
}
|
||||
|
||||
const opponent = [...arenaQueue.values()]
|
||||
.filter((ticket) => !ticket.matchId && ticket.accountId !== user.id)
|
||||
.sort((left, right) => left.createdAt - right.createdAt)[0]
|
||||
const player = arenaPlayerInfo(user)
|
||||
if (opponent) {
|
||||
const match = createArenaMatch({
|
||||
a: { side: 'a', ...opponent.player },
|
||||
b: { side: 'b', ...player },
|
||||
}, now)
|
||||
opponent.matchId = match.id
|
||||
opponent.updatedAt = now
|
||||
const ticketId = randomBytes(12).toString('base64url')
|
||||
arenaQueue.set(ticketId, {
|
||||
id: ticketId,
|
||||
accountId: user.id,
|
||||
player,
|
||||
matchId: match.id,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
return { ticketId, status: 'matched', side: 'b', match: arenaSnapshot(match) }
|
||||
}
|
||||
|
||||
if (existingTicket) {
|
||||
existingTicket.updatedAt = now
|
||||
return { ticketId: existingTicket.id, status: 'waiting' }
|
||||
}
|
||||
|
||||
const ticketId = randomBytes(12).toString('base64url')
|
||||
arenaQueue.set(ticketId, {
|
||||
id: ticketId,
|
||||
accountId: user.id,
|
||||
player,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
return { ticketId, status: 'waiting' }
|
||||
}
|
||||
|
||||
function checkArenaQueue(user, ticketId) {
|
||||
cleanupArenaMemory()
|
||||
const ticket = arenaQueue.get(ticketId)
|
||||
if (!ticket || ticket.accountId !== user.id) {
|
||||
const error = new Error('Arena queue ticket not found.')
|
||||
error.status = 404
|
||||
throw error
|
||||
}
|
||||
ticket.updatedAt = Date.now()
|
||||
if (!ticket.matchId) return { ticketId, status: 'waiting' }
|
||||
const match = arenaMatches.get(ticket.matchId)
|
||||
if (!match) return { ticketId, status: 'waiting' }
|
||||
const side = match.players.a.accountId === user.id ? 'a' : 'b'
|
||||
return { ticketId, status: 'matched', side, match: arenaSnapshot(match) }
|
||||
}
|
||||
|
||||
function cancelArenaQueue(user, ticketId) {
|
||||
const ticket = arenaQueue.get(ticketId)
|
||||
if (ticket && ticket.accountId === user.id && !ticket.matchId) arenaQueue.delete(ticketId)
|
||||
}
|
||||
|
||||
async function handleAuthApi(request, response, url) {
|
||||
if (!url.pathname.startsWith('/api/auth/')) return false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user