import msgpack from '@msgpack/msgpack' import fs from 'fs' import { execMany } from './helper.js' import { sqlite } from './init.js' /** * This module parses the msgpack provided by DDNet... * @module db/decodeMsgpack */ export function decodeMsgpack() { const data = fs.readFileSync('players.msgpack') const decoded = msgpack.decodeMulti(data, { wrap: true }) const order = ['categories', 'maps', 'totalPoints', 'pointsRanks', 'pointsThisWeek', 'pointsThisMonth', 'teamRankPoints', 'rankPoints', 'serverRanks'] let final = {} let i = 0 for (const part of decoded) { final[order[i]] = part ++i } return final } /** * This generates rankings for each map... * @module db/processRankings */ export function processRankings() { const maps = sqlite.prepare(`SELECT map FROM maps`); for (const map of maps.iterate()) sqlite .prepare(` INSERT INTO rankings ( map, name, time, timestamp, rank, server ) SELECT map, name, time, timestamp, rank, server FROM ( SELECT rank() OVER w AS rank, map, timestamp, NAME, min(time) AS time, server FROM race WHERE map = ? GROUP BY NAME window w AS (ORDER BY time) ) AS a ORDER BY rank `) .run(map.Map) } /** * This generates teamrankings for each map... * @module db/processTeamRankings */ export function processTeamRankings() { const maps = sqlite.prepare(`SELECT map FROM maps`); for (const map of maps.iterate()) sqlite .prepare(` INSERT INTO teamrankings ( name, map, id, time, timestamp, server, teamrank ) SELECT DISTINCT(r.NAME), r.map, r.id, r.time, r.timestamp, Substring(n.server, 1, 3), dense_rank() OVER w AS rank FROM (( SELECT DISTINCT id FROM teamrace WHERE map = ? ORDER BY time) AS l ) LEFT JOIN teamrace AS r ON l.id = r.id INNER JOIN race AS n ON r.map = n.map AND r.NAME = n.NAME AND r.time = n.time window w AS (ORDER BY r.time) `) .run(map.Map) } /** * This inserts all types of points into a table... * @module db/processAllPoints */ export function processAllPoints() { const msgpack = decodeMsgpack() const types = { points: msgpack.pointsRanks, pointsThisWeek: msgpack.pointsThisWeek, pointsThisMonth: msgpack.pointsThisMonth, pointsTeam: msgpack.teamRankPoints, pointsRank: msgpack.rankPoints, } /* Generate tables */ sqlite.exec(` CREATE TABLE IF NOT EXISTS "points" ( "type" varchar(16) NOT NULL, "rank" INTEGER NOT NULL, "name" varchar(16) NOT NULL, "points" INTEGER NOT NULL ); `) /* Insert data */ for(const type in types) { let rank = 1 for (const entry of types[type]) { sqlite .prepare(` INSERT INTO "points" ( type, rank, name, points ) VALUES (?, ?, ?, ?) `) .run( type, rank, entry[0], entry[1] ) ++rank } } /* Generate indexes */ execMany([ `CREATE INDEX IF NOT EXISTS "idx_points_type" ON "points" ("type")`, `CREATE INDEX IF NOT EXISTS "Idx_points_rank" on "points" ("rank")`, `CREATE INDEX IF NOT EXISTS "Idx_points_name" on "points" ("name")` ]) } export default { processAllPoints, processRankings, processTeamRankings }