Compare commits
2 Commits
28acbce1ac
...
fbbf677667
Author | SHA1 | Date | |
---|---|---|---|
fbbf677667 | |||
e3630699bd |
2
app.json
2
app.json
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "Sample node.js express app",
|
"name": "beatsaber-metrics-tracker",
|
||||||
"repository": "https://git.fascinated.cc/Fascinated/beatsaber-metrics-tracker",
|
"repository": "https://git.fascinated.cc/Fascinated/beatsaber-metrics-tracker",
|
||||||
"healthchecks": {}
|
"healthchecks": {}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import { INFLUXDB_BUCKET, InfluxQueryAPI } from "../index";
|
import { INFLUXDB_BUCKET, InfluxQueryAPI } from "../index";
|
||||||
|
import { formatString } from "../utils/stringUtils";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
// Query to get the player count history for tge last 24 hours in 1 hour intervals
|
// Query to get the player count history for tge last 24 hours in 1 hour intervals
|
||||||
const getPlayerHistoryQuery = `from(bucket: "${INFLUXDB_BUCKET}")
|
const getPlayerHistoryQuery = `from(bucket: "${INFLUXDB_BUCKET}")
|
||||||
|> range(start: -24h)
|
|> range(start: {})
|
||||||
|> filter(fn: (r) => r["_measurement"] == "scoresaber")
|
|> filter(fn: (r) => r["_measurement"] == "scoresaber")
|
||||||
|> filter(fn: (r) => r["_field"] == "value")
|
|> filter(fn: (r) => r["_field"] == "value")
|
||||||
|> filter(fn: (r) => r["type"] == "player_count")
|
|> filter(fn: (r) => r["type"] == "player_count")
|
||||||
@ -20,7 +21,18 @@ app.get("/", (req, res) => {
|
|||||||
|
|
||||||
app.get("/analytics", async (req, res) => {
|
app.get("/analytics", async (req, res) => {
|
||||||
const before = new Date().getTime();
|
const before = new Date().getTime();
|
||||||
const rows = await InfluxQueryAPI.collectRows(getPlayerHistoryQuery);
|
|
||||||
|
const timeQuery = req.query.time || "24h";
|
||||||
|
const timeInMs = parseTimeToMilliseconds(timeQuery.toString());
|
||||||
|
if (timeInMs > 30 * 24 * 60 * 60 * 1000) {
|
||||||
|
return res.status(400).json({
|
||||||
|
error: "Time range too large. Max time range is 30 days.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = await InfluxQueryAPI.collectRows(
|
||||||
|
formatString(getPlayerHistoryQuery, false, timeQuery)
|
||||||
|
);
|
||||||
let history = rows.map((row: any) => ({
|
let history = rows.map((row: any) => ({
|
||||||
time: row._time,
|
time: row._time,
|
||||||
value: row._value !== null ? row._value.toFixed(0) : null,
|
value: row._value !== null ? row._value.toFixed(0) : null,
|
||||||
|
26
src/utils/stringUtils.ts
Normal file
26
src/utils/stringUtils.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Formats a string with the given arguments.
|
||||||
|
*
|
||||||
|
* @param str the string to check
|
||||||
|
* @param uriEncodeStrings whether to uri encode the strings
|
||||||
|
* @param args the arguments to replace
|
||||||
|
* @returns the formatted string
|
||||||
|
*/
|
||||||
|
export function formatString(
|
||||||
|
str: string,
|
||||||
|
uriEncodeStrings: boolean,
|
||||||
|
...args: any[]
|
||||||
|
): string {
|
||||||
|
return str.replace(/{}/g, (match) => {
|
||||||
|
// If there are no arguments, return the match
|
||||||
|
if (args.length === 0) {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, return the next argument
|
||||||
|
if (uriEncodeStrings) {
|
||||||
|
return encodeURIComponent(String(args.shift()));
|
||||||
|
}
|
||||||
|
return String(args.shift());
|
||||||
|
});
|
||||||
|
}
|
40
src/utils/timeUtils.ts
Normal file
40
src/utils/timeUtils.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Parses a time string to milliseconds.
|
||||||
|
*
|
||||||
|
* @param time the time to parse
|
||||||
|
* @returns the time in milliseconds
|
||||||
|
*/
|
||||||
|
function parseTimeToMilliseconds(time: string) {
|
||||||
|
// Regular expression to match the numeric value and unit
|
||||||
|
const regex = /^(\d+)([smhdwMy])$/;
|
||||||
|
|
||||||
|
const match = time.match(regex);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(
|
||||||
|
"Invalid time format. Example valid formats: 1s, 5m, 2h, 3d, 1w, 2M, 1y"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = parseInt(match[1]);
|
||||||
|
const unit = match[2];
|
||||||
|
|
||||||
|
switch (unit) {
|
||||||
|
case "s":
|
||||||
|
return value * 1000; // seconds to milliseconds
|
||||||
|
case "m":
|
||||||
|
return value * 60 * 1000; // minutes to milliseconds
|
||||||
|
case "h":
|
||||||
|
return value * 60 * 60 * 1000; // hours to milliseconds
|
||||||
|
case "d":
|
||||||
|
return value * 24 * 60 * 60 * 1000; // days to milliseconds
|
||||||
|
case "w":
|
||||||
|
return value * 7 * 24 * 60 * 60 * 1000; // weeks to milliseconds
|
||||||
|
case "M":
|
||||||
|
return value * 30 * 24 * 60 * 60 * 1000; // months (approximate) to milliseconds
|
||||||
|
case "y":
|
||||||
|
return value * 365 * 24 * 60 * 60 * 1000; // years (approximate) to milliseconds
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid time unit. Use one of: s, m, h, d, w, M, y");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user