Springcleaning
This commit is contained in:
parent
c5427e0ee3
commit
ca617d50d3
24
api/api.js
24
api/api.js
|
@ -1,24 +0,0 @@
|
||||||
import { Router } from 'express'
|
|
||||||
import finishApi from './finishes.js'
|
|
||||||
import mapApi from './maps.js'
|
|
||||||
import playerApi from './players.js'
|
|
||||||
|
|
||||||
const api = Router()
|
|
||||||
|
|
||||||
api.get(
|
|
||||||
'/',
|
|
||||||
(req, res) => res.json({
|
|
||||||
success: true,
|
|
||||||
response: "You connected to DDStats API! :D"
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
api.use('/finishes', finishApi)
|
|
||||||
api.use('/maps', mapApi)
|
|
||||||
api.use('/players', playerApi)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module is the entrypoint for the API.
|
|
||||||
* @module api/api
|
|
||||||
*/
|
|
||||||
export default api
|
|
|
@ -1,57 +0,0 @@
|
||||||
import { Router } from 'express'
|
|
||||||
import Finish from '../schemas/Finish.js'
|
|
||||||
|
|
||||||
const finishApi = Router()
|
|
||||||
|
|
||||||
finishApi.get(
|
|
||||||
'/count',
|
|
||||||
(req, res) => {
|
|
||||||
Finish.find({}).count().then(
|
|
||||||
finishAmount => {
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: finishAmount
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
finishApi.get(
|
|
||||||
'/find',
|
|
||||||
async (req, res) => {
|
|
||||||
if (!req.query.player && !req.query.map)
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "Please provide either a player or map!"
|
|
||||||
})
|
|
||||||
|
|
||||||
const player = req.query.player
|
|
||||||
const map = req.query.map
|
|
||||||
const sort = req.query.sort ?? 'date'
|
|
||||||
const order = req.query.order === "desc" ? -1 : 1
|
|
||||||
|
|
||||||
Finish.find({ player: player ?? /\w/, map: map ?? /\w/ }).sort([[sort, order]]).then(
|
|
||||||
finishes => {
|
|
||||||
if (!finishes[0])
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "No maps found!"
|
|
||||||
})
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: {
|
|
||||||
finishes
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module handles all API actions related to maps.
|
|
||||||
* @module api/finishes
|
|
||||||
*/
|
|
||||||
export default finishApi
|
|
115
api/maps.js
115
api/maps.js
|
@ -1,115 +0,0 @@
|
||||||
import { Router } from 'express'
|
|
||||||
import Level from '../schemas/Level.js'
|
|
||||||
|
|
||||||
const mapApi = Router()
|
|
||||||
|
|
||||||
mapApi.get(
|
|
||||||
'/count',
|
|
||||||
(req, res) => {
|
|
||||||
Level.find({}).count().then(
|
|
||||||
mapAmount => {
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: mapAmount
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
mapApi.get(
|
|
||||||
'/get/:map',
|
|
||||||
(req, res) => {
|
|
||||||
Level.findOne({ name: req.params.map }).then(
|
|
||||||
map => {
|
|
||||||
if (!map)
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "No map found!"
|
|
||||||
})
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: map
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
mapApi.get(
|
|
||||||
'/getAll',
|
|
||||||
(req, res) => {
|
|
||||||
Level.find({}).then(
|
|
||||||
maps => {
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: maps
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
mapApi.get(
|
|
||||||
'/category/:category',
|
|
||||||
(req, res) => {
|
|
||||||
Level.find({ category: req.params.category }).then(
|
|
||||||
maps => {
|
|
||||||
if (!maps[0])
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "Invalid category name!"
|
|
||||||
})
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: maps
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
mapApi.get(
|
|
||||||
'/search',
|
|
||||||
async (req, res) => {
|
|
||||||
if (!req.query.q)
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "No query ('host/path?q=query') provided!"
|
|
||||||
})
|
|
||||||
|
|
||||||
const name = req.query.q
|
|
||||||
const sort = req.query.sort ?? 'name'
|
|
||||||
const order = req.query.order === "desc" ? -1 : 1
|
|
||||||
const page = req.query.page ?? 1
|
|
||||||
const filter = req.query.byMapper ? { mapper: { $regex: name, $options: 'i' }} : { name: { $regex: name, $options: 'i' }}
|
|
||||||
const pageCount = Math.ceil((await Level.find({ name: { $regex: name, $options: 'i' }}).count()) / 20)
|
|
||||||
|
|
||||||
Level.find(filter).sort([[sort, order]]).limit(20).skip((page - 1) * 20).then(
|
|
||||||
maps => {
|
|
||||||
if (!maps[0])
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "No maps found!"
|
|
||||||
})
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: {
|
|
||||||
pageCount,
|
|
||||||
maps
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module handles all API actions related to maps.
|
|
||||||
* @module api/maps
|
|
||||||
*/
|
|
||||||
export default mapApi
|
|
|
@ -1,80 +0,0 @@
|
||||||
import { Router } from 'express'
|
|
||||||
import Player from '../schemas/Player.js'
|
|
||||||
|
|
||||||
|
|
||||||
const playerApi = Router()
|
|
||||||
|
|
||||||
playerApi.get(
|
|
||||||
'/count',
|
|
||||||
(req, res) => {
|
|
||||||
Player.count({}).then(
|
|
||||||
playerAmount => {
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: playerAmount
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
playerApi.get(
|
|
||||||
'/get/:player',
|
|
||||||
(req, res) => {
|
|
||||||
Player.findOne({ name: req.params.player }).then(
|
|
||||||
player => {
|
|
||||||
if (!player)
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "No player found!"
|
|
||||||
})
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: player
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
playerApi.get(
|
|
||||||
'/search',
|
|
||||||
async (req, res) => {
|
|
||||||
if (!req.query.q)
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "No query ('host/path?q=query') provided!"
|
|
||||||
})
|
|
||||||
|
|
||||||
const name = req.query.q
|
|
||||||
const sort = req.query.sort ?? 'name'
|
|
||||||
const order = req.query.order === "desc" ? -1 : 1
|
|
||||||
const page = req.query.page ?? 1
|
|
||||||
const pageCount = Math.ceil((await Player.find({ name: { $regex: name, $options: 'i' }}).count()) / 20)
|
|
||||||
|
|
||||||
Player.find({ name: { $regex: name, $options: 'i' }}).sort([[sort, order]]).limit(20).skip((page - 1) * 20).then(
|
|
||||||
players => {
|
|
||||||
if (!players[0])
|
|
||||||
return res.json({
|
|
||||||
success: false,
|
|
||||||
response: "No players found!"
|
|
||||||
})
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
response: {
|
|
||||||
pageCount,
|
|
||||||
players
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module handles all API actions related to players.
|
|
||||||
* @module api/players
|
|
||||||
*/
|
|
||||||
export default playerApi
|
|
14
index.js
14
index.js
|
@ -8,11 +8,7 @@ import express from 'express'
|
||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
import njk from 'nunjucks'
|
import njk from 'nunjucks'
|
||||||
|
|
||||||
import sqlite2mongo from './libs/database/sqlite2mongo.js'
|
|
||||||
import databaseInit from './libs/database/init.js'
|
|
||||||
import initLog from './libs/utils/log.js'
|
import initLog from './libs/utils/log.js'
|
||||||
|
|
||||||
import api from './api/api.js'
|
|
||||||
import routes from './routes/routes.js'
|
import routes from './routes/routes.js'
|
||||||
|
|
||||||
import { initWorkers } from './libs/utils/multithread.js'
|
import { initWorkers } from './libs/utils/multithread.js'
|
||||||
|
@ -22,15 +18,6 @@ const log = initLog("[ MAIN ]")
|
||||||
// Read the .env file
|
// Read the .env file
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
// await databaseInit()
|
|
||||||
|
|
||||||
initWorkers(process.env.THREADS ?? 4)
|
|
||||||
|
|
||||||
if (process.env.LOAD_DB === "true")
|
|
||||||
await sqlite2mongo()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const Server = express()
|
const Server = express()
|
||||||
|
|
||||||
njk.configure(
|
njk.configure(
|
||||||
|
@ -45,6 +32,5 @@ njk.configure(
|
||||||
|
|
||||||
Server.use('/', routes)
|
Server.use('/', routes)
|
||||||
Server.use('/assets', express.static('static'))
|
Server.use('/assets', express.static('static'))
|
||||||
Server.use('/api', api)
|
|
||||||
|
|
||||||
Server.listen(process.env.PORT ?? 12345, () => log(`Server started and listening on port ${process.env.PORT}.`))
|
Server.listen(process.env.PORT ?? 12345, () => log(`Server started and listening on port ${process.env.PORT}.`))
|
|
@ -1,22 +0,0 @@
|
||||||
import initLog from '../utils/log.js'
|
|
||||||
import { checkForFinishes, checkForMaps, checkForPlayers } from './sqlite2mongo/checks.js'
|
|
||||||
import postTasks from './sqlite2mongo/postTasks.js'
|
|
||||||
|
|
||||||
const log = initLog("sqlite2mongo")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function handles the sqlite database provided by DDNet and
|
|
||||||
* migrates the data to mongodb.
|
|
||||||
* @module libs/database/sqlite2mongo
|
|
||||||
*/
|
|
||||||
async function sqlite2mongo() {
|
|
||||||
log("Checking for additions to 'ddnet.sqlite'...")
|
|
||||||
|
|
||||||
await checkForMaps()
|
|
||||||
await checkForPlayers()
|
|
||||||
await checkForFinishes()
|
|
||||||
|
|
||||||
await postTasks()
|
|
||||||
}
|
|
||||||
|
|
||||||
export default sqlite2mongo
|
|
|
@ -1,126 +0,0 @@
|
||||||
import { sqlite } from "../init.js"
|
|
||||||
import Level from '../../../schemas/Level.js'
|
|
||||||
import Player from '../../../schemas/Player.js'
|
|
||||||
import Finish from '../../../schemas/Finish.js'
|
|
||||||
import initLog from '../../utils/log.js'
|
|
||||||
|
|
||||||
|
|
||||||
const log = initLog("sqlite2mongo")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This for new maps from the sqlite db. If any are found it adds them to mongodb.
|
|
||||||
* @module libs/database/sqlite2mongo/checks
|
|
||||||
*/
|
|
||||||
export async function checkForMaps() {
|
|
||||||
log("Checking for new maps...")
|
|
||||||
|
|
||||||
const latestMap = await Level.findOne({}).sort({ "release": "desc" })
|
|
||||||
const date = latestMap ? latestMap.release.toISOString().replace(/[TZ]/g, " ").replace(/\.[0-9\s]+/, "") : undefined
|
|
||||||
const newMapsAmount = (await sqlite.get(`SELECT count(Map) FROM maps ${date ? `WHERE Timestamp > datetime('${date}')` : ''} ORDER BY Timestamp`))['count(Map)']
|
|
||||||
log(`Found ${newMapsAmount} new maps!`)
|
|
||||||
|
|
||||||
let addedMaps = 0
|
|
||||||
await sqlite.each(
|
|
||||||
`SELECT Map, Server, Points, Stars, Mapper, Timestamp FROM maps ${date ? `WHERE Timestamp > datetime('${date}')` : ''} ORDER BY Timestamp`,
|
|
||||||
[],
|
|
||||||
(err, map) => {
|
|
||||||
if (err) return log(err)
|
|
||||||
|
|
||||||
Level.create({
|
|
||||||
name: map.Map,
|
|
||||||
mapper: map.Mapper,
|
|
||||||
release: map.Timestamp === '0000-00-00 00:00:00' ? new Date('January 1, 1970 00:00:00 UTC') : new Date(`${map.Timestamp}+00:00`),
|
|
||||||
category: map.Server,
|
|
||||||
rating: map.Stars,
|
|
||||||
awardPoints: map.Points
|
|
||||||
}).then(() => {
|
|
||||||
++addedMaps
|
|
||||||
log(`Added map ${addedMaps}/${newMapsAmount} -> ${map.Map}`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This checks for new players in the sqlite db. If any are found it adds them to mongodb.
|
|
||||||
* @module libs/database/sqlite2mongo/checks
|
|
||||||
*/
|
|
||||||
export async function checkForPlayers() {
|
|
||||||
log("Checking for new players...")
|
|
||||||
|
|
||||||
const latestPlayer = await Player.findOne({}).sort({ "firstFinish": "desc" })
|
|
||||||
const date = latestPlayer ? latestPlayer.firstFinish.toISOString().replace(/[TZ]/g, " ").replace(/\.[0-9\s]+/, "") : undefined
|
|
||||||
const newPlayerAmount = (await sqlite.get(`select count(Name) FROM (SELECT Name, Timestamp FROM (SELECT Name, Timestamp FROM (SELECT * FROM race ORDER BY Timestamp ASC, Name ASC) GROUP BY Name) ${date ? `WHERE Timestamp > datetime('${date}')` : ''} ORDER BY Timestamp ASC)`))['count(Name)']
|
|
||||||
if (newPlayerAmount === 0) return log("No new players found...")
|
|
||||||
|
|
||||||
// Create a temporary table to prevent re-running CPU-intensive queries.
|
|
||||||
log(`Found ${newPlayerAmount} new players!`)
|
|
||||||
log("Importing new players...")
|
|
||||||
await sqlite.exec("DROP TABLE IF EXISTS temp")
|
|
||||||
await sqlite.exec("CREATE TABLE temp(Name varchar(128) NOT NULL, Timestamp timestamp NOT NULL)")
|
|
||||||
await sqlite.exec(`INSERT INTO TEMP (Name, Timestamp) SELECT Name, Timestamp FROM (SELECT Name, Timestamp FROM (SELECT Name, Timestamp FROM (SELECT * FROM race ORDER BY Timestamp ASC, Name ASC) GROUP BY Name) ${date ? `WHERE Timestamp > datetime('${date}')` : ''} ORDER BY Timestamp ASC)`)
|
|
||||||
log("Imported new players into 'temp'!")
|
|
||||||
|
|
||||||
let addedPlayers = 0
|
|
||||||
let offset = -1
|
|
||||||
while (offset < newPlayerAmount) {
|
|
||||||
await sqlite.each(
|
|
||||||
`SELECT Name, Timestamp FROM temp LIMIT 10000 OFFSET ${offset + 1}`,
|
|
||||||
[],
|
|
||||||
async (err, player) => {
|
|
||||||
if (err) return log(err)
|
|
||||||
if (addedPlayers >= newPlayerAmount) return {}
|
|
||||||
|
|
||||||
Player.create({
|
|
||||||
name: player.Name,
|
|
||||||
firstFinish: player.Timestamp === '0000-00-00 00:00:00' ? new Date('January 1, 1970 00:00:00 UTC') : new Date(`${player.Timestamp}+00:00`)
|
|
||||||
}).then(() => {
|
|
||||||
++addedPlayers
|
|
||||||
log(`Added player ${addedPlayers}/${newPlayerAmount} -> ${player.Name}`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
offset += 10000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This checks for new finishes in the sqlite db. If any are found it adds them to mongodb.
|
|
||||||
* @module libs/database/sqlite2mongo/checks
|
|
||||||
*/
|
|
||||||
export async function checkForFinishes() {
|
|
||||||
log("Checking for new finishes...")
|
|
||||||
|
|
||||||
const latestFinish = await Finish.findOne({}).sort({ "date": "desc" })
|
|
||||||
const date = latestFinish ? latestFinish.date.toISOString().replace(/[TZ]/g, " ").replace(/\.[0-9\s]+/, "") : undefined
|
|
||||||
const newFinishAmount = (await sqlite.get(`SELECT count(Name) FROM race ${date ? `WHERE Timestamp > datetime('${date}')` : ''}`))['count(Name)']
|
|
||||||
if (newFinishAmount === 0) return log("No new finishes found...")
|
|
||||||
|
|
||||||
log(`Found ${newFinishAmount} new finishes!`)
|
|
||||||
|
|
||||||
let addedFinishes = 0
|
|
||||||
let offset = -1
|
|
||||||
while (offset < newFinishAmount) {
|
|
||||||
await sqlite.each(
|
|
||||||
`SELECT * FROM race ${date ? `WHERE Timestamp > datetime('${date}')` : ''} ORDER BY Timestamp LIMIT 5000 OFFSET ${offset + 1}`,
|
|
||||||
[],
|
|
||||||
async (err, finish) => {
|
|
||||||
if (err) return log(err)
|
|
||||||
if (addedFinishes >= newFinishAmount) return {}
|
|
||||||
|
|
||||||
Finish.create({
|
|
||||||
map: finish.Map,
|
|
||||||
time: finish.Time,
|
|
||||||
date: finish.Timestamp === '0000-00-00 00:00:00' ? new Date('January 1, 1970 00:00:00 UTC') : new Date(`${finish.Timestamp}+00:00`),
|
|
||||||
serverLocation: finish.Server ?? '',
|
|
||||||
player: finish.Name
|
|
||||||
}).then(() => {
|
|
||||||
++addedFinishes
|
|
||||||
log(`Added finish ${addedFinishes}/${newFinishAmount} -> At ${finish.Timestamp} «${finish.Name}» completed «${finish.Map}» in ${finish.Time} s`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
offset += 5000
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
import fs from 'fs'
|
|
||||||
import msgpack from '@msgpack/msgpack'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module parses the msgpack provided by DDNet...
|
|
||||||
* @module libs/database/sqlite2mongo/decodeMsgpack
|
|
||||||
*/
|
|
||||||
export default 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
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,125 +0,0 @@
|
||||||
import Level from '../../../schemas/Level.js'
|
|
||||||
import Player from '../../../schemas/Player.js'
|
|
||||||
import initLog from '../../utils/log.js'
|
|
||||||
import decodeMsgpack from './decodeMsgpack.js'
|
|
||||||
import { spread } from '../../utils/multithread.js'
|
|
||||||
|
|
||||||
const log = initLog("sqlite2mongo")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This handles some post-tasks that run after the initial checks.
|
|
||||||
* @module libs/database/sqlite2mongo/postTasks
|
|
||||||
*/
|
|
||||||
export default async function postTasks() {
|
|
||||||
log("Post tasks...")
|
|
||||||
|
|
||||||
log("Loading cached info from DDNet...")
|
|
||||||
const cache = decodeMsgpack()
|
|
||||||
|
|
||||||
log("Adding total amounts of finishes to maps...")
|
|
||||||
const totalMaps = await Level.find({}).count()
|
|
||||||
let processedMaps = 0
|
|
||||||
for (const category in cache.maps) {
|
|
||||||
for (const map of cache.maps[category]) {
|
|
||||||
Level.findOneAndUpdate(
|
|
||||||
{ name: map[0] },
|
|
||||||
{ totalFinishes: map[2] }
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
++processedMaps
|
|
||||||
log(`Processed map ${processedMaps}/${totalMaps} -> «${map[0]}» [${category}] with ${map[2]} finishes!`)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log("Reseting weekly and monthly points...")
|
|
||||||
await Player.updateMany({}, { pointsThisWeek: 0, pointsThisMonth: 0 })
|
|
||||||
log("Done!")
|
|
||||||
|
|
||||||
log("Processing points for players...")
|
|
||||||
const totalPlayers = await Player.find({}).count()
|
|
||||||
let processedPlayerPoints = 0
|
|
||||||
for (const entry of cache.pointsRanks) {
|
|
||||||
spread(
|
|
||||||
'./playerPoints.js',
|
|
||||||
{
|
|
||||||
name: entry[0],
|
|
||||||
points: entry[1]
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
++processedPlayerPoints
|
|
||||||
log(`Processed player ${processedPlayerPoints}/${totalPlayers} -> «${entry[0]}» has ${entry[1]} points!`)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
log("Processing rank points for players...")
|
|
||||||
let processedPlayerRankPoints = 0
|
|
||||||
for (const entry of cache.rankPoints) {
|
|
||||||
spread(
|
|
||||||
'./playerRankPoints.js',
|
|
||||||
{
|
|
||||||
name: entry[0],
|
|
||||||
rankPoints: entry[1]
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
++processedPlayerRankPoints
|
|
||||||
log(`Processed player ${processedPlayerRankPoints}/${cache.rankPoints.length} -> «${entry[0]}» has ${entry[1]} rank points!`)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
log("Processing team points for players...")
|
|
||||||
let processedTeamPoints = 0
|
|
||||||
for (const entry in cache.teamRankPoints) {
|
|
||||||
spread(
|
|
||||||
'./playerTeamPoints.js',
|
|
||||||
{
|
|
||||||
name: entry[0],
|
|
||||||
teamPoints: entry[1]
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
++processedTeamPoints
|
|
||||||
log(`Processed player ${processedTeamPoints}/${cache.teamRankPoints.length} -> «${entry[0]}» has ${entry[1]} team points!`)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
log("Processing players' points for the last week...")
|
|
||||||
let processedPlayerPointsWeek = 0
|
|
||||||
for (const entry of cache.pointsThisWeek) {
|
|
||||||
spread(
|
|
||||||
'./playerWeekPoints.js',
|
|
||||||
{
|
|
||||||
name: entry[0],
|
|
||||||
pointsThisWeek: entry[1]
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
++processedPlayerPointsWeek
|
|
||||||
log(`Processed player ${processedPlayerPointsWeek}/${cache.pointsThisWeek.length} -> «${entry[0]}» got ${entry[1]} points this week!`)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
log("Processing players' points for the last month...")
|
|
||||||
let processedPlayerPointsMonth = 0
|
|
||||||
for (const entry of cache.pointsThisMonth) {
|
|
||||||
spread(
|
|
||||||
'./playerMonthPoints.js',
|
|
||||||
{
|
|
||||||
name: entry[0],
|
|
||||||
pointsThisMonth: entry[1]
|
|
||||||
}
|
|
||||||
).then(
|
|
||||||
() => {
|
|
||||||
++processedPlayerPointsMonth
|
|
||||||
log(`Processed player ${processedPlayerPointsMonth}/${cache.pointsThisMonth.length} -> «${entry[0]}» got ${entry[1]} points this month!`)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
import { randomUUID } from 'crypto'
|
|
||||||
import { SHARE_ENV, Worker } from 'worker_threads'
|
|
||||||
import initLog from './log.js'
|
|
||||||
|
|
||||||
const log = initLog("Worker Setup")
|
|
||||||
|
|
||||||
let workerFarm = []
|
|
||||||
let workerReady = []
|
|
||||||
let scheduledJobs = []
|
|
||||||
|
|
||||||
function scheduler() {
|
|
||||||
if (scheduledJobs.length === 0) return
|
|
||||||
|
|
||||||
const readyIndex = workerReady.indexOf(true)
|
|
||||||
if (readyIndex === -1) return
|
|
||||||
|
|
||||||
workerReady[readyIndex] = false
|
|
||||||
const worker = workerFarm[readyIndex]
|
|
||||||
|
|
||||||
const job = scheduledJobs.shift()
|
|
||||||
|
|
||||||
worker.postMessage({
|
|
||||||
type: 'runScript',
|
|
||||||
script: job.script,
|
|
||||||
data: job.data,
|
|
||||||
id: job.jobID
|
|
||||||
})
|
|
||||||
|
|
||||||
const messageHandler = message => {
|
|
||||||
if (message.id === job.jobID) {
|
|
||||||
workerReady[readyIndex] = true
|
|
||||||
worker.removeListener(
|
|
||||||
'message',
|
|
||||||
messageHandler
|
|
||||||
)
|
|
||||||
return job.callback(message.result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
worker.on(
|
|
||||||
'message',
|
|
||||||
messageHandler
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initWorkers(threads) {
|
|
||||||
for (let i = 0; i < threads; ++i) {
|
|
||||||
workerFarm.push(new Worker('./libs/utils/multithread/genericWorker.js', { env: SHARE_ENV }))
|
|
||||||
|
|
||||||
const worker = workerFarm[i]
|
|
||||||
worker.postMessage({
|
|
||||||
type: 'initWorker',
|
|
||||||
name: `Worker ${parseInt(i) + 1}`
|
|
||||||
})
|
|
||||||
|
|
||||||
workerReady[i] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
log(`Initialised ${threads} workers!`)
|
|
||||||
|
|
||||||
setInterval(
|
|
||||||
scheduler,
|
|
||||||
process.env.SCHEDULE_TIME ?? 50
|
|
||||||
)
|
|
||||||
|
|
||||||
log(`Initialised the scheduler!`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function spread(script, data) {
|
|
||||||
return new Promise(
|
|
||||||
async (resolve, reject) => {
|
|
||||||
const jobID = randomUUID()
|
|
||||||
|
|
||||||
scheduledJobs.push({
|
|
||||||
script,
|
|
||||||
data,
|
|
||||||
jobID,
|
|
||||||
callback: result => {
|
|
||||||
resolve(result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
import initLog from '../log.js'
|
|
||||||
|
|
||||||
const log = initLog('Fibonacci')
|
|
||||||
|
|
||||||
export function main(data) {
|
|
||||||
return new Promise(
|
|
||||||
(resolve, reject) => {
|
|
||||||
let nums = [1, 1]
|
|
||||||
|
|
||||||
for (let i = 0; i < 44; i++) {
|
|
||||||
nums.push(nums[nums.length - 2] + nums[nums.length - 1])
|
|
||||||
}
|
|
||||||
|
|
||||||
let primes = []
|
|
||||||
for (const num of nums) {
|
|
||||||
let isPrime = true
|
|
||||||
for (let i = 2; i < num / 2; ++i) {
|
|
||||||
if (num % i === 0)
|
|
||||||
isPrime = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPrime)
|
|
||||||
primes.push(num)
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(primes)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { workerData, parentPort } from 'worker_threads'
|
|
||||||
import initLog from '../log.js'
|
|
||||||
|
|
||||||
let runScript = ''
|
|
||||||
let myName = ''
|
|
||||||
|
|
||||||
let log = initLog(myName)
|
|
||||||
|
|
||||||
parentPort.on(
|
|
||||||
'message',
|
|
||||||
async message => {
|
|
||||||
switch (message.type) {
|
|
||||||
case 'initWorker':
|
|
||||||
myName = message.name
|
|
||||||
log = initLog(myName)
|
|
||||||
process.env.DEBUG && log(`Started new thread -> «${myName}»`)
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'runScript':
|
|
||||||
runScript = message.script
|
|
||||||
process.env.DEBUG && log(`Running script -> «${runScript}»`)
|
|
||||||
|
|
||||||
import(runScript).then(
|
|
||||||
script => script.main(message.data).then(
|
|
||||||
result => {
|
|
||||||
parentPort.postMessage({ result, id: message.id })
|
|
||||||
process.env.DEBUG && log(`Script done -> «${runScript}»`)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
log(`Invalid message -> ${message.type ?? 'No message type provided!'}`)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -1,11 +0,0 @@
|
||||||
import mongoose from 'mongoose'
|
|
||||||
|
|
||||||
export async function connectMongoose() {
|
|
||||||
await mongoose.connect(
|
|
||||||
process.env.MONGO_URI,
|
|
||||||
{
|
|
||||||
useNewUrlParser: true,
|
|
||||||
useUnifiedTopology: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import Player from '../../../schemas/Player.js'
|
|
||||||
import { connectMongoose } from './mongoForWorkes.js'
|
|
||||||
|
|
||||||
connectMongoose()
|
|
||||||
|
|
||||||
export function main(data) {
|
|
||||||
return new Promise(
|
|
||||||
(resolve, reject) => {
|
|
||||||
Player.findOneAndUpdate(
|
|
||||||
{ name: data.name },
|
|
||||||
{ rankPoints: data.pointsThisMonth }
|
|
||||||
).then(
|
|
||||||
() => resolve()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import Player from '../../../schemas/Player.js'
|
|
||||||
import { connectMongoose } from './mongoForWorkes.js'
|
|
||||||
|
|
||||||
connectMongoose()
|
|
||||||
|
|
||||||
export function main(data) {
|
|
||||||
return new Promise(
|
|
||||||
(resolve, reject) => {
|
|
||||||
Player.findOneAndUpdate(
|
|
||||||
{ name: data.name },
|
|
||||||
{ points: data.points }
|
|
||||||
).then(
|
|
||||||
() => resolve()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import Player from '../../../schemas/Player.js'
|
|
||||||
import { connectMongoose } from './mongoForWorkes.js'
|
|
||||||
|
|
||||||
connectMongoose()
|
|
||||||
|
|
||||||
export function main(data) {
|
|
||||||
return new Promise(
|
|
||||||
(resolve, reject) => {
|
|
||||||
Player.findOneAndUpdate(
|
|
||||||
{ name: data.name },
|
|
||||||
{ rankPoints: data.rankPoints }
|
|
||||||
).then(
|
|
||||||
() => resolve()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import Player from '../../../schemas/Player.js'
|
|
||||||
import { connectMongoose } from './mongoForWorkes.js'
|
|
||||||
|
|
||||||
connectMongoose()
|
|
||||||
|
|
||||||
export function main(data) {
|
|
||||||
return new Promise(
|
|
||||||
(resolve, reject) => {
|
|
||||||
Player.findOneAndUpdate(
|
|
||||||
{ name: data.name },
|
|
||||||
{ teamPoints: data.teamPoints }
|
|
||||||
).then(
|
|
||||||
() => resolve()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import Player from '../../../schemas/Player.js'
|
|
||||||
import { connectMongoose } from './mongoForWorkes.js'
|
|
||||||
|
|
||||||
connectMongoose()
|
|
||||||
|
|
||||||
export function main(data) {
|
|
||||||
return new Promise(
|
|
||||||
(resolve, reject) => {
|
|
||||||
Player.findOneAndUpdate(
|
|
||||||
{ name: data.name },
|
|
||||||
{ pointsThisWeek: data.pointsThisWeek }
|
|
||||||
).then(
|
|
||||||
() => resolve()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import mongoose from 'mongoose'
|
|
||||||
|
|
||||||
const Finish = new mongoose.Schema({
|
|
||||||
map: String,
|
|
||||||
time: Number,
|
|
||||||
date: Date,
|
|
||||||
serverLocation: String,
|
|
||||||
player: String
|
|
||||||
})
|
|
||||||
|
|
||||||
Finish.index({ player: 1, map: 1 })
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This cotains the mongoose 'Finish' model.
|
|
||||||
* @module schemas/Finish
|
|
||||||
*/
|
|
||||||
export default mongoose.model("Finish", Finish)
|
|
|
@ -1,17 +0,0 @@
|
||||||
import mongoose from 'mongoose'
|
|
||||||
|
|
||||||
const Level = new mongoose.Schema({
|
|
||||||
name: String,
|
|
||||||
mapper: String,
|
|
||||||
release: Date,
|
|
||||||
category: String,
|
|
||||||
rating: Number,
|
|
||||||
awardPoints: Number,
|
|
||||||
totalFinishes: Number
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This cotains the mongoose 'Level' (maps) model.
|
|
||||||
* @module schemas/Level
|
|
||||||
*/
|
|
||||||
export default mongoose.model("Level", Level)
|
|
|
@ -1,19 +0,0 @@
|
||||||
import mongoose from 'mongoose'
|
|
||||||
|
|
||||||
const Player = new mongoose.Schema({
|
|
||||||
name: String,
|
|
||||||
points: Number,
|
|
||||||
rankPoints: Number,
|
|
||||||
teamPoints: Number,
|
|
||||||
pointsThisWeek: Number,
|
|
||||||
pointsThisMonth: Number,
|
|
||||||
firstFinish: Date
|
|
||||||
})
|
|
||||||
|
|
||||||
Player.index({ name: 1 })
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This cotains the mongoose 'Player' model.
|
|
||||||
* @module schemas/Player
|
|
||||||
*/
|
|
||||||
export default mongoose.model("Player", Player)
|
|
|
@ -1,15 +0,0 @@
|
||||||
import mongoose from 'mongoose'
|
|
||||||
|
|
||||||
const TeamFinish = new mongoose.Schema({
|
|
||||||
map: String,
|
|
||||||
time: Number,
|
|
||||||
date: Date,
|
|
||||||
serverLocation: String,
|
|
||||||
players: [ String ]
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This cotains the mongoose 'TeamFinish' model.
|
|
||||||
* @module schemas/TeamFinish
|
|
||||||
*/
|
|
||||||
export default mongoose.model("TeamFinish", TeamFinish)
|
|
|
@ -1,67 +0,0 @@
|
||||||
import { initWorkers, spread } from '../libs/utils/multithread.js'
|
|
||||||
import Player from '../schemas/Player.js'
|
|
||||||
import decodeMsgpack from '../libs/database/sqlite2mongo/decodeMsgpack.js'
|
|
||||||
import initLog from '../libs/utils/log.js'
|
|
||||||
|
|
||||||
const log = initLog("Fib. Test")
|
|
||||||
|
|
||||||
initWorkers(3)
|
|
||||||
|
|
||||||
const jobs = 10
|
|
||||||
let completed = 0
|
|
||||||
for (let i = 0; i < jobs; ++i) {
|
|
||||||
spread(
|
|
||||||
'./fibonacci.js',
|
|
||||||
{}
|
|
||||||
).then(
|
|
||||||
result => {
|
|
||||||
++completed
|
|
||||||
log(`Completed job ${completed}/${jobs} -> ${result}`)
|
|
||||||
|
|
||||||
if (completed === jobs) process.exit(0)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default async function() {
|
|
||||||
const cache = decodeMsgpack()
|
|
||||||
|
|
||||||
await Player.updateMany(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
pointsThisWeek: 0,
|
|
||||||
pointsThisMonth: 0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let processedPlayers = 0
|
|
||||||
const totalPlayers = cache.pointsRanks.length
|
|
||||||
const rawDbFunc = (name, points) => new Promise((resolve, reject) => Player.findOneAndUpdate({ name: name }, { points: points }).then(() => resolve()))
|
|
||||||
for (const entry of cache.pointsRanks) {
|
|
||||||
let data = new SharedArrayBuffer(1024 * 10)
|
|
||||||
// let data = new Array(buffer)
|
|
||||||
|
|
||||||
data[0] = 0
|
|
||||||
data[1] = entry[0]
|
|
||||||
data[2] = entry[1]
|
|
||||||
|
|
||||||
spread(
|
|
||||||
'./db.test.js',
|
|
||||||
data
|
|
||||||
).then(
|
|
||||||
result => {
|
|
||||||
console.log(data[0])
|
|
||||||
++processedPlayers
|
|
||||||
log(`Process player ${processedPlayers}/${totalPlayers} -> «${entry[0]}» with ${entry[1]} points!`)
|
|
||||||
|
|
||||||
if (processedPlayers === totalPlayers)
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user