134 lines
4.5 KiB
TypeScript
134 lines
4.5 KiB
TypeScript
import { database, Character, Game, Pick, App, roleNames } from './db'
|
|
import { Op, QueryTypes } from 'sequelize'
|
|
|
|
const serverGameStatsQuery =
|
|
'SELECT ' +
|
|
'COUNT(*) as TotalGames, ' +
|
|
'SUM(CASE WHEN status = "Complete" THEN 1 ELSE 0 END) as Complete, ' +
|
|
'SUM(CASE WHEN status = "Postponed" THEN 1 ELSE 0 END) as Postponed, ' +
|
|
'SUM(CASE WHEN status = "Pending" THEN 1 ELSE 0 END) as Pending, ' +
|
|
'SUM(CASE WHEN event = "TRUE" THEN 1 ELSE 0 END) as Events, ' +
|
|
'SUM(CASE WHEN fix = "TRUE" THEN 1 ELSE 0 END) as Fixes, ' +
|
|
'SUM(payoutEB) as TotalEB, ' +
|
|
'SUM(payoutIP) as TotalIP, ' +
|
|
'SUM(payoutEB) / SUM(CASE WHEN status = "Complete" THEN 1 ELSE 0 END) as AverageEB, ' +
|
|
'SUM(payoutIP) / SUM(CASE WHEN status = "Complete" THEN 1 ELSE 0 END) as AverageIP ' +
|
|
'FROM Games WHERE postdate BETWEEN :startSeconds AND :endSeconds'
|
|
|
|
const startingYear = 2023
|
|
|
|
function getMonthNumber(monthId: number): number {
|
|
return monthId % 12
|
|
}
|
|
|
|
function getYearNumber(monthId: number): number {
|
|
return Math.floor(monthId / 12 + startingYear)
|
|
}
|
|
|
|
function monthIdToStartSeconds(monthId: number): number {
|
|
if (monthId != -1) {
|
|
const yearNumber = getYearNumber(monthId)
|
|
const monthNumber = getMonthNumber(monthId)
|
|
return new Date(yearNumber, monthNumber, 1).getTime() / 1000
|
|
}
|
|
return 0
|
|
}
|
|
|
|
function monthIdToEndSeconds(monthId: number): number {
|
|
if (monthId != -1) {
|
|
const yearNumber = getYearNumber(monthId)
|
|
const monthNumber = getMonthNumber(monthId)
|
|
return new Date(yearNumber, monthNumber + 1, -1).getTime() / 1000
|
|
}
|
|
return Number.MAX_SAFE_INTEGER
|
|
}
|
|
|
|
export function addRushStatsApis(app, jsonParser, memcache) {
|
|
app.post('/api/serverstats/gamestats', jsonParser, async (req, res) => {
|
|
const monthId = req.body.monthId
|
|
let startSeconds = monthIdToStartSeconds(monthId)
|
|
let endSeconds = monthIdToEndSeconds(monthId)
|
|
|
|
let cachedResponse = await memcache.get('gamestats' + req.body.monthId)
|
|
|
|
if (!cachedResponse) {
|
|
console.log('cache miss')
|
|
const serverGameStats = await database.query(serverGameStatsQuery, {
|
|
type: QueryTypes.SELECT,
|
|
replacements: {
|
|
startSeconds,
|
|
endSeconds
|
|
}
|
|
})
|
|
|
|
await memcache.set('gamestats' + req.body.monthId, serverGameStats[0])
|
|
res.send(serverGameStats[0])
|
|
} else {
|
|
console.log('cache hit')
|
|
res.send(cachedResponse)
|
|
}
|
|
})
|
|
|
|
app.post('/api/serverstats/rolestats', jsonParser, async (req, res) => {
|
|
const monthId = req.body.monthId
|
|
let startSeconds = monthIdToStartSeconds(monthId)
|
|
let endSeconds = monthIdToEndSeconds(monthId)
|
|
|
|
let cachedResponse = await memcache.get('rolestats' + req.body.monthId)
|
|
|
|
if (!cachedResponse) {
|
|
const games = await Game.findAll({
|
|
include: [
|
|
{ model: Character, as: 'characterPickedForGame' },
|
|
{ model: Character, as: 'characterAppliedForGame' }
|
|
],
|
|
where: { postdate: { [Op.between]: [startSeconds, endSeconds] } }
|
|
})
|
|
|
|
// count active roles
|
|
let activeCharacters = new Map()
|
|
let pickedCharacterCount = new Map()
|
|
let appedCharacterCount = new Map()
|
|
|
|
games.forEach((game, gameNum) => {
|
|
const picks = game.dataValues.characterPickedForGame
|
|
const appls = game.dataValues.characterAppliedForGame
|
|
|
|
picks.forEach((character, characterNum) => {
|
|
const role = character.dataValues.role
|
|
// Count role application
|
|
pickedCharacterCount.set(role, (pickedCharacterCount.get(role) || 0) + 1)
|
|
})
|
|
|
|
appls.forEach((character, characterNum) => {
|
|
const role = character.dataValues.role
|
|
const charId = character.dataValues.id
|
|
// Add apllied characters to active list
|
|
if (!activeCharacters.has(role)) {
|
|
activeCharacters.set(role, new Set())
|
|
}
|
|
activeCharacters.get(role).add(charId)
|
|
// Count role application
|
|
appedCharacterCount.set(role, (appedCharacterCount.get(role) || 0) + 1)
|
|
})
|
|
})
|
|
|
|
const result = {}
|
|
|
|
roleNames.forEach((roleName) => {
|
|
result[roleName] = {
|
|
apps: appedCharacterCount.get(roleName) || 0,
|
|
picks: pickedCharacterCount.get(roleName) || 0,
|
|
active: activeCharacters.has(roleName) ? activeCharacters.get(roleName).size : 0
|
|
}
|
|
})
|
|
|
|
await memcache.set('rolestats' + req.body.monthId, result)
|
|
res.send(result)
|
|
} else {
|
|
console.log('cache hit')
|
|
res.send(cachedResponse)
|
|
}
|
|
})
|
|
}
|