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,
|
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 {
|
try {
|
||||||
const settlements = await settleBets(fightId, winnerId)
|
// Publish notable results to Nostr
|
||||||
for (const s of settlements) {
|
if (winnerId) {
|
||||||
db.update(schema.bets).set({
|
const winner = winnerId === botA.id ? botA : botB
|
||||||
status: s.won ? 'won' : winnerId ? 'lost' : 'refunded',
|
const loser = winnerId === botA.id ? botB : botA
|
||||||
payoutSats: s.payoutSats,
|
const isUpset = loser.eloRating - winner.eloRating > 150
|
||||||
payoutToken: s.payoutToken,
|
const isKO = (winnerId === botA.id && hpB <= 0) || (winnerId === botB.id && hpA <= 0)
|
||||||
settledAt: new Date().toISOString(),
|
publishFightResult({
|
||||||
}).where(eq(schema.bets.id, s.betId)).run()
|
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
|
// Settle bets
|
||||||
if (mode === 'ranked') {
|
try {
|
||||||
// Dev mode: always pay the human bot (not mock), regardless of win/loss
|
const settlements = await settleBets(fightId, winnerId)
|
||||||
const devMode = process.env.NODE_ENV !== 'production'
|
for (const s of settlements) {
|
||||||
const isMockA = botA.webhookUrl.startsWith('http://mock.local')
|
db.update(schema.bets).set({
|
||||||
const isMockB = botB.webhookUrl.startsWith('http://mock.local')
|
status: s.won ? 'won' : winnerId ? 'lost' : 'refunded',
|
||||||
const humanBotId = devMode ? (isMockA ? botB.id : isMockB ? botA.id : winnerId) : winnerId
|
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) {
|
// Ranked fight payout
|
||||||
payWinner(fightId, humanBotId).catch(err => {
|
if (mode === 'ranked') {
|
||||||
console.error(`[payments] payout failed for fight ${fightId}:`, err)
|
// Dev mode: always pay the human bot (not mock), regardless of win/loss
|
||||||
})
|
const devMode = process.env.NODE_ENV !== 'production'
|
||||||
} else if (!winnerId) {
|
const isMockA = botA.webhookUrl.startsWith('http://mock.local')
|
||||||
// Draw — refund both entry fees
|
const isMockB = botB.webhookUrl.startsWith('http://mock.local')
|
||||||
const entryPayments = await db.select().from(schema.payments)
|
const humanBotId = devMode ? (isMockA ? botB.id : isMockB ? botA.id : winnerId) : winnerId
|
||||||
.where(sql`${schema.payments.fightId} = ${fightId} AND ${schema.payments.direction} = 'in' AND ${schema.payments.status} = 'confirmed'`)
|
|
||||||
for (const payment of entryPayments) {
|
if (humanBotId) {
|
||||||
refundEntry(payment.id).catch(err => {
|
payWinner(fightId, humanBotId).catch(err => {
|
||||||
console.error(`[payments] draw refund failed for ${payment.id}:`, 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> {
|
export async function runFight(botAId: string, botBId: string, mode: 'free' | 'ranked' = 'free'): Promise<string> {
|
||||||
|
|||||||
Reference in New Issue
Block a user