|
| 1 | +import { protectedRoute, withMiddleware } from '../../../lib/routing/router' |
| 2 | +import { loadGame } from '../../../middleware/game-middleware' |
| 3 | +import { endOfDay, startOfDay } from 'date-fns' |
| 4 | +import { formatDateForClickHouse } from '../../../lib/clickhouse/formatDateTime' |
| 5 | +import { withResponseCache } from '../../../lib/perf/responseCache' |
| 6 | +import { HEADLINES_CACHE_TTL_MS } from './common' |
| 7 | +import { dateRangeSchema } from '../../../lib/validation/dateRangeSchema' |
| 8 | + |
| 9 | +export const averageSessionDurationRoute = protectedRoute({ |
| 10 | + method: 'get', |
| 11 | + path: '/average_session_duration', |
| 12 | + schema: () => ({ |
| 13 | + query: dateRangeSchema |
| 14 | + }), |
| 15 | + middleware: withMiddleware(loadGame), |
| 16 | + handler: async (ctx) => { |
| 17 | + const { startDate: startDateQuery, endDate: endDateQuery } = ctx.state.validated.query |
| 18 | + const game = ctx.state.game |
| 19 | + const includeDevData = ctx.state.includeDevData |
| 20 | + const clickhouse = ctx.clickhouse |
| 21 | + |
| 22 | + return withResponseCache({ |
| 23 | + key: `average-session-duration-${game.id}-${includeDevData}-${startDateQuery}-${endDateQuery}`, |
| 24 | + ttl: HEADLINES_CACHE_TTL_MS / 1000 |
| 25 | + }, async () => { |
| 26 | + const startDate = formatDateForClickHouse(startOfDay(new Date(startDateQuery))) |
| 27 | + const endDate = formatDateForClickHouse(endOfDay(new Date(endDateQuery))) |
| 28 | + |
| 29 | + let query = ` |
| 30 | + SELECT avg(dateDiff('seconds', started_at, ended_at)) AS averageDuration |
| 31 | + FROM player_sessions |
| 32 | + WHERE started_at BETWEEN '${startDate}' AND '${endDate}' |
| 33 | + AND ended_at IS NOT NULL |
| 34 | + AND game_id = ${game.id} |
| 35 | + ` |
| 36 | + |
| 37 | + if (!includeDevData) { |
| 38 | + query += ' AND dev_build = false' |
| 39 | + } |
| 40 | + |
| 41 | + const result = await clickhouse.query({ |
| 42 | + query, |
| 43 | + format: 'JSONEachRow' |
| 44 | + }).then((res) => res.json<{ averageDuration: number }>()) |
| 45 | + |
| 46 | + const seconds = result[0].averageDuration |
| 47 | + |
| 48 | + return { |
| 49 | + status: 200, |
| 50 | + body: { |
| 51 | + hours: Math.floor(seconds / 3600), |
| 52 | + minutes: Math.floor((seconds % 3600) / 60), |
| 53 | + seconds: seconds % 60 |
| 54 | + } |
| 55 | + } |
| 56 | + }) |
| 57 | + } |
| 58 | +}) |
0 commit comments