2023-10-27 15:54:11 +01:00
|
|
|
import { Point } from "@influxdata/influxdb-client";
|
2023-10-27 16:30:30 +01:00
|
|
|
import axios from "axios";
|
2023-10-27 15:54:11 +01:00
|
|
|
import { w3cwebsocket as WebsocketClient } from "websocket";
|
|
|
|
import { InfluxWriteAPI } from "..";
|
|
|
|
import { connectMongo } from "../db/mongo";
|
|
|
|
import { LeaderboardSchema } from "../db/schemas/leaderboard";
|
2023-10-30 15:01:08 +00:00
|
|
|
import { Score } from "../db/schemas/score";
|
2023-10-30 15:45:35 +00:00
|
|
|
import { Headsets } from "../headsets";
|
|
|
|
import { normalizedRegionName } from "../utils/regionUtils";
|
2023-10-27 15:54:11 +01:00
|
|
|
|
|
|
|
async function update() {
|
2023-10-27 16:30:30 +01:00
|
|
|
const response = await axios.get("https://scoresaber.com/api/players/count");
|
|
|
|
const count = response.data;
|
2023-10-27 15:54:11 +01:00
|
|
|
|
|
|
|
const point = new Point("scoresaber")
|
|
|
|
.tag("type", "player_count")
|
|
|
|
.intField("value", parseInt(count))
|
|
|
|
.timestamp(new Date());
|
|
|
|
InfluxWriteAPI.writePoint(point);
|
|
|
|
|
|
|
|
console.log(`Updated player count to ${count}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function connectWebsocket() {
|
|
|
|
await connectMongo();
|
|
|
|
const leaderboard = await LeaderboardSchema.findOne({ _id: "scoresaber" });
|
|
|
|
if (!leaderboard) {
|
|
|
|
await LeaderboardSchema.create({ _id: "scoresaber", totalPlays: 0 });
|
|
|
|
}
|
|
|
|
let totalScores = leaderboard?.totalPlays || 0;
|
2023-10-30 15:27:10 +00:00
|
|
|
let totalCountries = leaderboard?.countries || {};
|
|
|
|
let totalHeadsets = leaderboard?.headsets || {};
|
2023-10-27 15:54:11 +01:00
|
|
|
|
|
|
|
const socket = new WebsocketClient("wss://scoresaber.com/ws");
|
|
|
|
socket.onopen = () => {
|
|
|
|
console.log("Connected to websocket");
|
|
|
|
};
|
|
|
|
|
|
|
|
socket.onclose = () => {
|
|
|
|
console.log("Disconnected from websocket");
|
|
|
|
setTimeout(connectWebsocket, 5000);
|
|
|
|
};
|
|
|
|
|
|
|
|
socket.onerror = (error) => {
|
|
|
|
console.error("Websocket error:", error);
|
|
|
|
};
|
|
|
|
|
2023-10-30 15:01:08 +00:00
|
|
|
socket.onmessage = async (message) => {
|
2023-10-27 15:54:11 +01:00
|
|
|
const data = message.data;
|
|
|
|
let json;
|
|
|
|
try {
|
|
|
|
json = JSON.parse(data.toString());
|
|
|
|
} catch (e) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const commandName = json.commandName;
|
|
|
|
const commandData = json.commandData;
|
|
|
|
if (commandName == "score") {
|
2023-10-30 15:01:08 +00:00
|
|
|
const { score, leaderboard } = commandData;
|
2023-10-27 15:54:11 +01:00
|
|
|
totalScores++;
|
2023-10-30 15:01:08 +00:00
|
|
|
|
|
|
|
const {
|
|
|
|
id,
|
|
|
|
hmd,
|
|
|
|
baseScore,
|
|
|
|
missedNotes,
|
|
|
|
badCuts,
|
|
|
|
leaderboardPlayerInfo: player,
|
|
|
|
pp,
|
|
|
|
} = score;
|
|
|
|
const { maxScore, stars, id: leaderboardId } = leaderboard;
|
2023-10-30 15:49:06 +00:00
|
|
|
await Score.deleteOne({ _id: id }); // Delete the score if it already exists
|
2023-10-30 15:01:08 +00:00
|
|
|
|
|
|
|
const data: any = {
|
|
|
|
_id: id,
|
|
|
|
player: {
|
|
|
|
id: player.id,
|
|
|
|
},
|
|
|
|
mistakes: {
|
|
|
|
badCuts: badCuts,
|
|
|
|
missed: missedNotes,
|
|
|
|
},
|
|
|
|
rank: score.rank,
|
|
|
|
maxCombo: score.maxCombo,
|
|
|
|
leaderboardId: leaderboardId,
|
|
|
|
};
|
|
|
|
if (maxScore) {
|
|
|
|
data.acc = ((baseScore / maxScore) * 100).toFixed(2);
|
|
|
|
}
|
|
|
|
if (pp && stars > 0) {
|
|
|
|
data.pp = pp;
|
|
|
|
data.stars = stars;
|
|
|
|
}
|
|
|
|
|
2023-10-30 15:49:06 +00:00
|
|
|
Score.create(data); // Create the score
|
2023-10-30 16:08:47 +00:00
|
|
|
|
|
|
|
const hmdName =
|
|
|
|
Headsets.find((h) => h.id.includes(hmd))?.name || "Unknown";
|
|
|
|
const countryId = normalizedRegionName(player.country) || "Unknown";
|
2023-10-30 15:27:10 +00:00
|
|
|
totalCountries[countryId] = (totalCountries[countryId] || 0) + 1;
|
2023-10-30 16:08:47 +00:00
|
|
|
totalHeadsets[hmdName] = (totalHeadsets[hmdName] || 0) + 1;
|
|
|
|
|
2023-10-30 15:49:06 +00:00
|
|
|
// Update the leaderboard data in the database
|
2023-10-30 15:27:10 +00:00
|
|
|
await LeaderboardSchema.updateOne(
|
|
|
|
{ _id: "scoresaber" },
|
|
|
|
{
|
|
|
|
$set: {
|
|
|
|
totalPlays: totalScores,
|
|
|
|
countries: totalCountries,
|
|
|
|
headsets: totalHeadsets,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
).exec();
|
2023-10-30 15:01:08 +00:00
|
|
|
|
2023-10-30 15:49:06 +00:00
|
|
|
// Write the metrics data to influx
|
2023-10-30 15:27:10 +00:00
|
|
|
InfluxWriteAPI.writePoint(
|
|
|
|
new Point("scoresaber")
|
|
|
|
.tag("type", "score_count")
|
|
|
|
.intField("value", totalScores)
|
|
|
|
.timestamp(new Date())
|
|
|
|
);
|
|
|
|
InfluxWriteAPI.writePoint(
|
|
|
|
new Point("scoresaber")
|
|
|
|
.tag("type", "headsets")
|
2023-10-30 16:08:47 +00:00
|
|
|
.tag("hmd", hmdName)
|
|
|
|
.intField("value", totalHeadsets[hmdName])
|
2023-10-30 15:27:10 +00:00
|
|
|
.timestamp(new Date())
|
|
|
|
);
|
|
|
|
InfluxWriteAPI.writePoint(
|
|
|
|
new Point("scoresaber")
|
|
|
|
.tag("type", "countries")
|
|
|
|
.tag("country", countryId)
|
|
|
|
.intField("value", totalCountries[countryId])
|
|
|
|
.timestamp(new Date())
|
|
|
|
);
|
2023-10-27 15:54:11 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-10-30 15:01:08 +00:00
|
|
|
async function updateAverages() {
|
|
|
|
const before = new Date().getTime();
|
|
|
|
Score.find({}).then((scores) => {
|
|
|
|
// create an average for all data for all scores
|
|
|
|
const average = {
|
|
|
|
acc: 0,
|
|
|
|
pp: 0,
|
|
|
|
stars: 0,
|
|
|
|
mistakes: {
|
|
|
|
badCuts: 0,
|
|
|
|
missed: 0,
|
|
|
|
},
|
|
|
|
rank: 0,
|
|
|
|
maxCombo: 0,
|
|
|
|
};
|
|
|
|
scores.forEach((score) => {
|
|
|
|
if (score.acc) {
|
|
|
|
average.acc += score.acc;
|
|
|
|
}
|
|
|
|
if (score.pp) {
|
|
|
|
average.pp += score.pp;
|
|
|
|
}
|
|
|
|
if (score.stars) {
|
|
|
|
average.stars += score.stars;
|
|
|
|
}
|
|
|
|
if (score.mistakes) {
|
|
|
|
average.mistakes.badCuts += score.mistakes.badCuts;
|
|
|
|
average.mistakes.missed += score.mistakes.missed;
|
|
|
|
}
|
|
|
|
if (score.rank) {
|
|
|
|
average.rank += score.rank;
|
|
|
|
}
|
|
|
|
if (score.maxCombo) {
|
|
|
|
average.maxCombo += score.maxCombo;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
average.acc /= scores.length;
|
|
|
|
average.pp /= scores.length;
|
|
|
|
average.stars /= scores.length;
|
|
|
|
average.mistakes.badCuts /= scores.length;
|
|
|
|
average.mistakes.missed /= scores.length;
|
|
|
|
average.rank /= scores.length;
|
|
|
|
average.maxCombo /= scores.length;
|
|
|
|
|
|
|
|
// create the point and write it to influx
|
|
|
|
const point = new Point("scoresaber")
|
|
|
|
.tag("type", "average")
|
|
|
|
.timestamp(new Date());
|
2023-10-30 15:03:29 +00:00
|
|
|
|
|
|
|
if (average.acc) {
|
|
|
|
point.floatField("acc", average.acc);
|
|
|
|
}
|
|
|
|
if (average.pp) {
|
|
|
|
point.floatField("pp", average.pp);
|
|
|
|
}
|
|
|
|
if (average.stars) {
|
|
|
|
point.floatField("stars", average.stars);
|
|
|
|
}
|
|
|
|
if (average.mistakes) {
|
2023-10-30 15:05:28 +00:00
|
|
|
point.intField(
|
|
|
|
"badCuts",
|
|
|
|
isNaN(average.mistakes.badCuts) ? 0 : average.mistakes.badCuts
|
|
|
|
);
|
|
|
|
point.intField(
|
|
|
|
"missed",
|
|
|
|
isNaN(average.mistakes.missed) ? 0 : average.mistakes.missed
|
|
|
|
);
|
2023-10-30 15:03:29 +00:00
|
|
|
}
|
|
|
|
if (average.rank) {
|
|
|
|
point.intField("rank", average.rank);
|
|
|
|
}
|
|
|
|
if (average.maxCombo) {
|
|
|
|
point.intField("maxCombo", average.maxCombo);
|
|
|
|
}
|
2023-10-30 15:01:08 +00:00
|
|
|
InfluxWriteAPI.writePoint(point);
|
|
|
|
console.log(`Updated averages in ${new Date().getTime() - before}ms`);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-10-27 15:54:11 +01:00
|
|
|
update();
|
2023-10-30 15:01:08 +00:00
|
|
|
updateAverages();
|
2023-10-27 15:54:11 +01:00
|
|
|
connectWebsocket();
|
|
|
|
setInterval(update, 60_000); // 1 minute
|
2023-10-30 15:01:08 +00:00
|
|
|
setInterval(updateAverages, 60_000 * 5); // 5 minutes
|