From 2aaa108521f530e427c7245ead3df2473f28aa09 Mon Sep 17 00:00:00 2001 From: furo Date: Thu, 4 Nov 2021 15:40:12 +0100 Subject: [PATCH] Started working on functions for the UI --- api/finishes.js | 40 +++++ api/maps.js | 74 +++++---- api/players.js | 32 ++-- index.js | 2 +- libs/database/generate.js | 52 +++++- libs/database/init.js | 3 + libs/database/tasks.js | 61 ++++++- libs/database/wrapper.js | 335 ++++++++++++++++++++++++++++++++++++++ math-func.so | Bin 0 -> 86392 bytes 9 files changed, 530 insertions(+), 69 deletions(-) create mode 100644 libs/database/wrapper.js create mode 100755 math-func.so diff --git a/api/finishes.js b/api/finishes.js index 1fd68f6..f339806 100644 --- a/api/finishes.js +++ b/api/finishes.js @@ -1,5 +1,6 @@ import { Router } from 'express' import { sqlite } from '../libs/database/init.js' +import wrapper from '../libs/database/wrapper.js' const finishApi = Router() @@ -16,4 +17,43 @@ finishApi.get( } ) +finishApi.get( + '/finishedMaps/:player', + (req, res) => { + /* Check if player exists */ + if(!wrapper.playerExists(req.params.player)) { + return res.json({ + success: false, + response: "No such player!" + }) + } + const finishes = wrapper.finishedMaps(req.params.player) + + return res.json({ + success: true, + response: finishes, + }) + } +) + +finishApi.get( + '/unfinishedMaps/:player', + (req, res) => { + /* Check if player exists */ + if(!wrapper.playerExists(req.params.player)) { + return res.json({ + success: false, + response: "No such player!" + }) + } + const finishes = wrapper.unfinishedMaps(req.params.player) + + return res.json({ + success: true, + response: finishes, + }) + } +) + + export default finishApi \ No newline at end of file diff --git a/api/maps.js b/api/maps.js index 851ff06..d2ebceb 100644 --- a/api/maps.js +++ b/api/maps.js @@ -1,5 +1,6 @@ import { Router } from 'express' import { sqlite } from '../libs/database/init.js' +import wrapper, { map } from '../libs/database/wrapper.js' const mapApi = Router() @@ -18,37 +19,17 @@ mapApi.get( mapApi.get( '/get/:map', (req, res) => { - let map = req.params.map - /* Check if map exists */ - const check = sqlite.prepare(`SELECT map FROM maps WHERE map = ?`).get(map) - if (!check) { + if(!wrapper.mapExists(req.params.map)) { return res.json({ success: false, - response: "No map found!", + response: "No such map!" }) } - const info = sqlite.prepare(`SELECT * FROM maps WHERE map = ?`).get(map) - - /* TODO: Generate a table with this as a cache */ - const avgTime = sqlite.prepare(`SELECT avg(time) AS 'averageTime' FROM race WHERE map = ?`).get(map) - const total = sqlite.prepare(`SELECT COUNT(*) AS 'total' FROM race WHERE map = ?`).get(map) - const unique = sqlite.prepare(`SELECT COUNT(distinct(player)) AS 'unique' FROM race WHERE map = ?`).get(map) - const teams = sqlite.prepare(`SELECT COUNT(distinct(id)) AS 'teams' FROM teamrace WHERE map = ?`).get(map) return res.json({ success: true, - response: { - info, - - /* TODO Get median time*/ - averageTime: avgTime.averageTime, - finishes: { - unique: unique.unique, - total: total.total, - teams: teams.teams, - } - } + response: map(req.params.map) }) } ) @@ -56,11 +37,9 @@ mapApi.get( mapApi.get( '/getAll', (req, res) => { - const allMaps = sqlite.prepare(`SELECT * FROM maps`).all() - return res.json({ success: true, - response: allMaps, + response: wrapper.allMaps() }) } ) @@ -68,22 +47,53 @@ mapApi.get( mapApi.get( '/category/:category', (req, res) => { - let category = req.params.category - /* Check if category exists */ - const check = sqlite.prepare(`SELECT category FROM maps WHERE category = ? LIMIT 1`).get(category) - if (!check) { + if (!wrapper.categoryExists(req.params.category)) { return res.json({ success: false, response: "Invalid category name!", }) } - const allMaps = sqlite.prepare(`SELECT * FROM maps WHERE category = ?`).all(category) + return res.json({ + success: true, + response: wrapper.mapCategory(req.params.category) + }) + } +) + +mapApi.get( + '/leaderboard/race/:map', + (req, res) => { + /* Check if map exists */ + if (!wrapper.mapExists(req.params.map)) { + return res.json({ + success: false, + response: "No such map!", + }) + } return res.json({ success: true, - response: allMaps, + response: wrapper.leaderboardRace(req.params.map, 1, 20) + }) + } +) + +mapApi.get( + '/leaderboard/teamrace/:map', + (req, res) => { + /* Check if map exists */ + if (!wrapper.mapExists(req.params.map)) { + return res.json({ + success: false, + response: "No such map!", + }) + } + + return res.json({ + success: true, + response: wrapper.leaderboardTeamrace(req.params.map, 1, 20) }) } ) diff --git a/api/players.js b/api/players.js index d8d7f4d..6bf13cf 100644 --- a/api/players.js +++ b/api/players.js @@ -1,32 +1,24 @@ import { Router } from 'express' -import { sqlite } from '../libs/database/init.js' -import searcher from '../libs/database/searcher.js' +import wrapper from '../libs/database/wrapper.js' const playerApi = Router() - playerApi.get( '/get/:player', async (req, res) => { - searcher( - 'points', - 'player', - req.params.player, - undefined, - false, - "get", - 0 - ).then( - player => res.json({ - success: true, - response: player - }) - ).catch( - error => res.json({ + /* Check if player exists */ + if(!wrapper.playerExists(req.params.player)) { + return res.json({ success: false, - response: error + response: "No such player!" }) - ) + } + const data = wrapper.player(req.params.player) + + return res.json({ + success: true, + response: data + }) } ) diff --git a/index.js b/index.js index 3f6b3e2..4983417 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,7 @@ import api from './api/api.js' import { generateDB } from './libs/database/generate.js' import { dbInit } from './libs/database/init.js' import { downloadEssentialData } from './libs/download/dowload.js' - +import tasks from './libs/database/tasks.js' loadEnv() diff --git a/libs/database/generate.js b/libs/database/generate.js index b9c5f69..0293681 100644 --- a/libs/database/generate.js +++ b/libs/database/generate.js @@ -43,11 +43,6 @@ export function generateDB() { `ALTER TABLE maps RENAME COLUMN Timestamp TO release` ]) } - log("Generating map index...") - execMany([ - `CREATE INDEX IF NOT EXISTS "idx_maps_map" ON "maps" ("map")`, - `CREATE INDEX IF NOT EXISTS "idx_maps_category" ON "maps" ("category")` - ]) log("Generating race index...") execMany([ @@ -62,12 +57,15 @@ export function generateDB() { log("Creating rankings table...") sqlite.exec(` CREATE TABLE IF NOT EXISTS "rankings" ( + "category" varchar(32) NOT NULL, + "points" integer NOT NULL DEFAULT 0, "map" varchar(128) NOT NULL, "player" varchar(16) NOT NULL, "time" float NOT NULL DEFAULT 0, "date" timestamp NOT NULL DEFAULT current_timestamp, "server" char(4) NOT NULL DEFAULT '', - "rank" INTEGER NOT NULL + "rank" INTEGER NOT NULL, + "finishes" INTEGER NOT NULL DEFAULT 0 ) `) @@ -78,7 +76,9 @@ export function generateDB() { execMany([ `CREATE INDEX IF NOT EXISTS "idx_rankings_map" ON "rankings" ("map")`, `CREATE INDEX IF NOT EXISTS "idx_rankings_rank" ON "rankings" ("rank")`, - `CREATE INDEX IF NOT EXISTS "idx_rankings_player" ON "rankings" ("player")` + `CREATE INDEX IF NOT EXISTS "idx_rankings_player" ON "rankings" ("player")`, + `CREATE INDEX IF NOT EXISTS "idx_rankings_finishes" ON "rankings" ("finishes")`, + `CREATE INDEX IF NOT EXISTS "idx_rankings_mapRank" ON "rankings" ("map", "rank")` ]) log("Generating teamrace index...") @@ -91,6 +91,8 @@ export function generateDB() { log("Creating teamrankings table...") sqlite.exec(` CREATE TABLE IF NOT EXISTS "teamrankings" ( + "category" varchar(32) NOT NULL, + "points" integer NOT NULL DEFAULT 0, "map" varchar(128) NOT NULL, "id" varbinary(16) NOT NULL, "player" varchar(16) NOT NULL, @@ -108,7 +110,9 @@ export function generateDB() { execMany([ `CREATE INDEX IF NOT EXISTS "idx_teamrankings_map" ON "teamrankings" ("map")`, `CREATE INDEX IF NOT EXISTS "idx_teamrankings_rank" ON "teamrankings" ("teamrank")`, - `CREATE INDEX IF NOT EXISTS "idx_teamrankings_player" ON "teamrankings" ("player")` + `CREATE INDEX IF NOT EXISTS "idx_teamrankings_player" ON "teamrankings" ("player")`, + `CREATE INDEX IF NOT EXISTS "idx_teamrankings_playerCategoryMap" ON "teamrankings" ("player", "category", "map")`, + `CREATE INDEX IF NOT EXISTS "idx_teamrankings_mapTeamrank" ON "teamrankings" ("map", "teamrank")` ]) log("Generating graphRecordCache...") @@ -131,6 +135,38 @@ export function generateDB() { log("Inserting points to DB...") tasks.processAllPoints() + log("Generating a new maps table...") + /* Rename the old one as we wanna use that name for the new one*/ + sqlite.exec(`ALTER TABLE maps RENAME TO oldmaps`) + + sqlite.exec(` + CREATE TABLE IF NOT EXISTS "maps" ( + "map" varchar(128) NOT NULL, + "category" varchar(32) NOT NULL, + "points" integer NOT NULL DEFAULT 0, + "stars" integer NOT NULL DEFAULT 0, + "mapper" char(128) NOT NULL, + "release" timestamp NOT NULL DEFAULT current_timestamp, + + "avgTime" FLOAT NOT NULL DEFAULT 0, + "medianTime" FLOAT NOT NULL DEFAULT 0, + "topTime" FLOAT NOT NULL DEFAULT 0, + "topTeamTime" FLOAT NOT NULL DEFAULT 0, + "finishesUnique" INTEGER NOT NULL DEFAULT 0, + "finishesTotal" INTEGER NOT NULL DEFAULT 0, + "finishesTeam" INTEGER NOT NULL DEFAULT 0 + ) + `) + tasks.processMaps() + + log("Generating map index...") + execMany([ + `CREATE INDEX IF NOT EXISTS "idx_maps_map" ON "maps" ("map")`, + `CREATE INDEX IF NOT EXISTS "idx_maps_category" ON "maps" ("category")` + `CREATE INDEX IF NOT EXISTS "idx_maps_categoryMap" ON "maps" ("category", "map")` + ]) + + skinDB.exec(` CREATE TABLE IF NOT EXISTS "skindata" ( "timestamp" INTEGER NOT NULL, diff --git a/libs/database/init.js b/libs/database/init.js index 281f7be..84f2098 100644 --- a/libs/database/init.js +++ b/libs/database/init.js @@ -24,6 +24,9 @@ export function dbInit() { /* Unsafe mode */ sqlite.unsafeMode() + /* Load external extensions */ + sqlite.loadExtension('./math-func.so') + log("Loaded in 'ddnet.sqlite'!") log("Loaded in 'skindata.sqlite'!") } diff --git a/libs/database/tasks.js b/libs/database/tasks.js index c91bc6a..71e6e2f 100644 --- a/libs/database/tasks.js +++ b/libs/database/tasks.js @@ -7,26 +7,28 @@ import { sqlite } from './init.js' * @module libs/database/processRankings */ export function processRankings() { - const maps = sqlite.prepare(`SELECT map FROM maps`) + const maps = sqlite.prepare(`SELECT * FROM maps`) for (const map of maps.iterate()) sqlite .prepare(` INSERT INTO rankings ( - map, player, time, date, rank, server + map, category, points, player, time, date, rank, server, finishes ) - SELECT map, player, time, date, rank, server + SELECT a.map, b.category, b.points, a.player, a.time, a.date, a.rank, a.server, a.finishes FROM ( SELECT rank() OVER w AS rank, map, date, player, min(time) AS time, - server - FROM race + server, + COUNT(*) AS finishes + FROM race as a WHERE map = ? GROUP BY player window w AS (ORDER BY time) ) AS a + JOIN maps as b ON a.map = b.map ORDER BY rank `) .run(map.map) @@ -44,12 +46,13 @@ export function processTeamRankings() { .prepare(` INSERT INTO teamrankings ( - player, map, id, time, date, server, teamrank + player, map, id, time, date, server, teamrank, category, points ) SELECT DISTINCT(r.player), r.map, r.id, r.time, r.date, Substring(n.server, 1, 3), - dense_rank() OVER w AS rank + dense_rank() OVER w AS rank, + a.category, a.points FROM (( SELECT DISTINCT id FROM teamrace @@ -61,7 +64,9 @@ export function processTeamRankings() { INNER JOIN race AS n ON r.map = n.map AND r.player = n.player - AND r.time = n.time window w AS (ORDER BY r.time) + AND r.time = n.time + JOIN maps as a + ON r.map = a.map window w AS (ORDER BY r.time) `) .run(map.map) } @@ -99,6 +104,45 @@ export function processTimeGraph() { } } +/** + * This generates a fancy map table containing more data such total finishes, median time. + * @module libs/database/processMaps + */ +export function processMaps() { + const maps = sqlite.prepare(`SELECT map FROM oldmaps`) + const finishes = sqlite.prepare(`SELECT * FROM race WHERE map = ? ORDER BY date`) + + for (const map of maps.iterate()) { + const info = sqlite.prepare(`SELECT * FROM oldmaps WHERE map = ?`).get(map.map) + + const avgTime = sqlite.prepare(`SELECT avg(time) AS avgTime FROM race WHERE map = ?`).get(map.map)?.avgTime ?? -1 + const medianTime = sqlite.prepare(`SELECT median(time) as medianTime FROM race WHERE map = ?`).get(map.map)?.medianTime ?? -1 + + const teams = sqlite.prepare(`SELECT COUNT(distinct(id)) AS 'teams' FROM teamrace WHERE map = ?`).get(map.map)?.teams ?? -1 + const topTeamTime = sqlite.prepare(`SELECT time as topTeamTime FROM teamrankings WHERE map = ? ORDER BY Time ASC LIMIT 1`).get(map.map)?.topTeamTime ?? -1 + + const topTime = sqlite.prepare(`SELECT time as topTime FROM rankings WHERE map = ? ORDER BY Time ASC LIMIT 1`).get(map.map)?.topTime ?? -1 + + + const total = sqlite.prepare(`SELECT COUNT(*) AS 'total' FROM race WHERE map = ?`).get(map.map)?.total ?? -1 + const unique = sqlite.prepare(`SELECT COUNT(distinct(player)) AS 'unique' FROM race WHERE map = ?`).get(map.map)?.unique ?? -1 + + + sqlite.prepare(` + INSERT INTO "maps" + ( + map, category, points, stars, mapper, release, + avgTime, medianTime, topTime, topTeamTime, + finishesUnique, finishesTotal, finishesTeam + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `).run( + info.map, info.category, info.points, info.stars, info.mapper, info.release, + avgTime, medianTime, topTime, topTeamTime, + unique, total, teams, + ) + } +} + /** * This inserts all types of points into a table... * @module db/processAllPoints @@ -160,5 +204,6 @@ export default { processAllPoints, processRankings, processTeamRankings, + processMaps, processTimeGraph } \ No newline at end of file diff --git a/libs/database/wrapper.js b/libs/database/wrapper.js new file mode 100644 index 0000000..06c2cce --- /dev/null +++ b/libs/database/wrapper.js @@ -0,0 +1,335 @@ +import { sqlite } from './init.js' + +/** + * This function checks if a player exists + * + * @param {string} player The player to check + + * @returns {boolean} Returns a boolean + */ +export function playerExists(player) { + const exists = sqlite.prepare(`SELECT * FROM points WHERE player = ? LIMIT 1`).get(player) + + if(exists) + return true + else + return false +} + +/** + * This function checks if a map exists + * + * @param {string} player The map to check + + * @returns {boolean} Returns a boolean + */ +export function mapExists(map) { + const exists = sqlite.prepare(`SELECT * FROM maps WHERE map = ? LIMIT 1`).get(map) + + if(exists) + return true + else + return false +} + +/** + * This function checks if a map category exists + * + * @param {string} player The category to check + + * @returns {boolean} Returns a boolean + */ + export function categoryExists(category) { + const exists = sqlite.prepare(`SELECT category FROM maps WHERE category = ? LIMIT 1`).get(category) + + if(exists) + return true + else + return false +} + +/** + * This function returns all data pertaining a certain player + * + * @param {string} player The player to fetch + + * @returns {object} An object containing the players data + */ +export function player(player) { + /* Misc */ + const firstFinish = sqlite.prepare(`SELECT map, time, date, server FROM race WHERE player = ? ORDER BY date ASC LIMIT 1`).get(player) + + /* Points */ + let points = {} + let rank = {} + + const pointsData = sqlite.prepare(`SELECT * FROM points WHERE player = ?`) + + for (const pointsType of pointsData.iterate(player)) { + rank[pointsType.type] = pointsType.rank + } + for (const pointsType of pointsData.iterate(player)) { + points[pointsType.type] = pointsType.points + } + + return { + player, + firstFinish, + points, + rank, + } +} + +/** + * This function returns all data pertaining a certain map + * + * @param {string} map The map to fetch + + * @returns {object} An object containing map data + */ +export function map(map) { + const a = sqlite.prepare(` + SELECT * FROM maps WHERE map = ? + `).get(map) + + return prettyifyMap(a) +} + +export function mapCategory(category) { + let output = [] + const maps = sqlite.prepare(` + SELECT * FROM maps WHERE category = ?`).all(category) + + for(const map of maps) { + output.push(prettyifyMap(map)) + } + return output +} + +/** + * This function returns all data pertaining to all maps + + * @returns {array} An array contaning all map objects + */ +export function allMaps() { + let output = [] + const maps = sqlite.prepare(` + SELECT * FROM maps`).all() + + for(const map of maps) { + output.push(prettyifyMap(map)) + } + return output +} + +/** + * This function returns all data pertaining a certain map + * + * @param {string} map The map to fetch + + * @returns {object} An object containing map data + */ + export function prettyifyMap(a) { + let output + + output = { + map: a.map, + category: a.category, + points: a.points, + stars: a.stars, + release: a.release, + mappers: a.mapper.split(" & "), + + times: { + average: a.avgTime, + median: a.medianTime, + topTime: a.topTime, + topTimeTeam: (a.topTeamTime != -1) ? a.topTeamTime : undefined, + }, + finishes: { + total: a.finishesTotal, + team: a.finishesTeam, + unique: a.finishesUnique, + } + } + + return output +} + +/** + * This function returns the race leaderboard for a map + * + * @param {string} map The map to check + * @param {number} start At which rank the leaderboard should begin + * @param {number} end At which rank the leaderboard should end + + * @returns {array} An array containing the leaderboard + */ +export function leaderboardRace(map, start, end) { + const leaderboard = sqlite.prepare(` + SELECT rank, time, date, player, server FROM rankings WHERE map = ? AND rank >= ? AND rank <= ?`) + .all(map, start, end) + + return leaderboard +} + +/** + * This function returns the teamrace leaderboard for a map + * + * @param {string} map The map to check + * @param {number} start At which rank the leaderboard should begin + * @param {number} end At which rank the leaderboard should end + + * @returns {array} An array containing the leaderboard + */ + export function leaderboardTeamrace(map, start, end) { + // TODO: Optimize array creation of players + let leaderboard = [] + + const a = sqlite.prepare(` + SELECT teamrank, time, date, player, server FROM teamrankings WHERE map = ? AND teamrank >= ? AND teamrank <= ? GROUP BY teamrank`) + + for(const teamrank of a.iterate(map, start, end)) { + let players = [] + const b = sqlite.prepare(`SELECT player FROM teamrankings WHERE map = ? AND teamrank = ?`) + + for(const player of b.iterate(map, teamrank.teamrank)) { + players.push(player.player) + } + leaderboard.push({ + teamrank: teamrank.teamrank, + time: teamrank.time, + date: teamrank.date, + server: teamrank.server, + players: players, + }) + } + return leaderboard +} + +/** + * This function returns the points leaderboard for a specific type + * (points, pointsRank, pointsTeam, pointsThisWeek, pointsThisMonth) + * + * @param {string} type Which type of points to fetch + * @param {number} start At which rank the leaderboard should begin + * @param {number} end At which rank the leaderboard should end + + * @returns {array} An array containing the leaderboard + */ +export function leaderboardPoints(map, start, end) { + const leaderboard = sqlite.prepare(` + SELECT rank, player, points FROM points WHERE type = ? AND rank >= ? AND rank <= ? ORDER BY rank`) + .all(type, start, end) + + return leaderboard +} + +/** + * This function returns all finished maps by a specific player + * togheter with their respective rank, teamrank, amount of finishes. + * Finishes are grouped by map category (Novice, Brutal) + * + * @param {string} player The player to check + + * @returns {object} An object containing all finishes grouped by category + */ +export function finishedMaps(player) { + const finishesStmt = sqlite.prepare( + ` + SELECT a.map, + a.category, + a.points, + a.rank, + b.teamrank, + a.finishes + FROM rankings AS a + LEFT OUTER JOIN teamrankings AS b + ON a.player = b.player + AND a.category = b.category + AND a.map = b.map + WHERE a.player = ? + `) + + let finishes = { + Novice: [], + Moderate: [], + Brutal: [], + Insane: [], + Dummy: [], + DDmaX: [], + Oldschool: [], + Solo: [], + Race: [], + Fun: [] + } + for (const finish of finishesStmt.iterate(player)) { + finishes[finish.category].push(finish) + } + + return finishes +} + +/** + * This function returns all unfinished maps by a specific player + * togheter with category, points, finishTotal and medianTime. + * Maps are grouped by the map category (Novice, Brutal) + * + * @param {string} player The player to check + + * @returns {object} An object containing all unfinished maps + */ + export function unfinishedMaps(player) { + const maps = sqlite.prepare( + ` + SELECT a.map, + a.category, + a.points, + b.finishesTotal, + b.medianTime + FROM (SELECT category, + map, + points + FROM maps + WHERE map NOT IN (SELECT map + FROM rankings + WHERE player = ? )) AS a + JOIN maps AS b + ON a.category = b.category + AND a.map = b.map + ORDER BY b.category ASC; + `) + + let unfinished = { + Novice: [], + Moderate: [], + Brutal: [], + Insane: [], + Dummy: [], + DDmaX: [], + Oldschool: [], + Solo: [], + Race: [], + Fun: [] + } + for (const map of maps.iterate(player)) { + unfinished[map.category].push(map) + } + + return unfinished +} + +export default { + playerExists, + finishedMaps, + unfinishedMaps, + player, + + map, + mapCategory, + allMaps, + mapExists, + leaderboardRace, + leaderboardTeamrace, + categoryExists, +} \ No newline at end of file diff --git a/math-func.so b/math-func.so new file mode 100755 index 0000000000000000000000000000000000000000..3a3fc0bc664b1814517cbe9422e90bbe0a5c4897 GIT binary patch literal 86392 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