fix: clean up fight event listeners after completion (BUG-12)
Move fightEvents.cleanup(fightId) to finally block to ensure cleanup runs even if post-fight operations (bets, payouts) fail. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
0f606cc991
commit
0f95cbf881
@@ -555,61 +555,63 @@ async function executeFightRounds(fightId: string, botA: BotRecord, botB: BotRec
|
||||
potSats: mode === 'ranked' ? 42 : 0,
|
||||
})
|
||||
|
||||
// Publish notable results to Nostr
|
||||
if (winnerId) {
|
||||
const winner = winnerId === botA.id ? botA : botB
|
||||
const loser = winnerId === botA.id ? botB : botA
|
||||
const isUpset = loser.eloRating - winner.eloRating > 150
|
||||
const isKO = (winnerId === botA.id && hpB <= 0) || (winnerId === botB.id && hpA <= 0)
|
||||
publishFightResult({
|
||||
fightId, winnerName: winner.name, loserName: loser.name, winnerId,
|
||||
winnerElo: newWinnerEloFinal, loserElo: newLoserEloFinal,
|
||||
winnerEloChange, loserEloChange,
|
||||
isPerfect: !!isPerfect, isKO, isUpset,
|
||||
totalRounds: lastRound, arena: arena.name,
|
||||
}).catch(err => console.warn('[nostr] publish failed:', err))
|
||||
}
|
||||
|
||||
// Settle bets
|
||||
try {
|
||||
const settlements = await settleBets(fightId, winnerId)
|
||||
for (const s of settlements) {
|
||||
db.update(schema.bets).set({
|
||||
status: s.won ? 'won' : winnerId ? 'lost' : 'refunded',
|
||||
payoutSats: s.payoutSats,
|
||||
payoutToken: s.payoutToken,
|
||||
settledAt: new Date().toISOString(),
|
||||
}).where(eq(schema.bets.id, s.betId)).run()
|
||||
// Publish notable results to Nostr
|
||||
if (winnerId) {
|
||||
const winner = winnerId === botA.id ? botA : botB
|
||||
const loser = winnerId === botA.id ? botB : botA
|
||||
const isUpset = loser.eloRating - winner.eloRating > 150
|
||||
const isKO = (winnerId === botA.id && hpB <= 0) || (winnerId === botB.id && hpA <= 0)
|
||||
publishFightResult({
|
||||
fightId, winnerName: winner.name, loserName: loser.name, winnerId,
|
||||
winnerElo: newWinnerEloFinal, loserElo: newLoserEloFinal,
|
||||
winnerEloChange, loserEloChange,
|
||||
isPerfect: !!isPerfect, isKO, isUpset,
|
||||
totalRounds: lastRound, arena: arena.name,
|
||||
}).catch(err => console.warn('[nostr] publish failed:', err))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`[betting] settlement failed for fight ${fightId}:`, err)
|
||||
}
|
||||
|
||||
// Ranked fight payout
|
||||
if (mode === 'ranked') {
|
||||
// Dev mode: always pay the human bot (not mock), regardless of win/loss
|
||||
const devMode = process.env.NODE_ENV !== 'production'
|
||||
const isMockA = botA.webhookUrl.startsWith('http://mock.local')
|
||||
const isMockB = botB.webhookUrl.startsWith('http://mock.local')
|
||||
const humanBotId = devMode ? (isMockA ? botB.id : isMockB ? botA.id : winnerId) : winnerId
|
||||
// Settle bets
|
||||
try {
|
||||
const settlements = await settleBets(fightId, winnerId)
|
||||
for (const s of settlements) {
|
||||
db.update(schema.bets).set({
|
||||
status: s.won ? 'won' : winnerId ? 'lost' : 'refunded',
|
||||
payoutSats: s.payoutSats,
|
||||
payoutToken: s.payoutToken,
|
||||
settledAt: new Date().toISOString(),
|
||||
}).where(eq(schema.bets.id, s.betId)).run()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`[betting] settlement failed for fight ${fightId}:`, err)
|
||||
}
|
||||
|
||||
if (humanBotId) {
|
||||
payWinner(fightId, humanBotId).catch(err => {
|
||||
console.error(`[payments] payout failed for fight ${fightId}:`, err)
|
||||
})
|
||||
} else if (!winnerId) {
|
||||
// Draw — refund both entry fees
|
||||
const entryPayments = await db.select().from(schema.payments)
|
||||
.where(sql`${schema.payments.fightId} = ${fightId} AND ${schema.payments.direction} = 'in' AND ${schema.payments.status} = 'confirmed'`)
|
||||
for (const payment of entryPayments) {
|
||||
refundEntry(payment.id).catch(err => {
|
||||
console.error(`[payments] draw refund failed for ${payment.id}:`, err)
|
||||
// Ranked fight payout
|
||||
if (mode === 'ranked') {
|
||||
// Dev mode: always pay the human bot (not mock), regardless of win/loss
|
||||
const devMode = process.env.NODE_ENV !== 'production'
|
||||
const isMockA = botA.webhookUrl.startsWith('http://mock.local')
|
||||
const isMockB = botB.webhookUrl.startsWith('http://mock.local')
|
||||
const humanBotId = devMode ? (isMockA ? botB.id : isMockB ? botA.id : winnerId) : winnerId
|
||||
|
||||
if (humanBotId) {
|
||||
payWinner(fightId, humanBotId).catch(err => {
|
||||
console.error(`[payments] payout failed for fight ${fightId}:`, err)
|
||||
})
|
||||
} else if (!winnerId) {
|
||||
// Draw — refund both entry fees
|
||||
const entryPayments = await db.select().from(schema.payments)
|
||||
.where(sql`${schema.payments.fightId} = ${fightId} AND ${schema.payments.direction} = 'in' AND ${schema.payments.status} = 'confirmed'`)
|
||||
for (const payment of entryPayments) {
|
||||
refundEntry(payment.id).catch(err => {
|
||||
console.error(`[payments] draw refund failed for ${payment.id}:`, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fightEvents.cleanup(fightId)
|
||||
}
|
||||
|
||||
fightEvents.cleanup(fightId)
|
||||
}
|
||||
|
||||
export async function runFight(botAId: string, botBId: string, mode: 'free' | 'ranked' = 'free'): Promise<string> {
|
||||
|
||||
Reference in New Issue
Block a user