add time range support

This commit is contained in:
Lee 2023-10-27 16:13:51 +01:00
parent be7d32f7f2
commit e3630699bd
4 changed files with 81 additions and 3 deletions

@ -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

@ -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

@ -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");
}
}