2023-10-09 19:03:31 +00:00
|
|
|
import { hoursToMilliseconds, isSameDay, minutesToMilliseconds } from "date-fns";
|
2023-10-21 10:40:42 +00:00
|
|
|
import { UTCDateMini } from "date-fns/utc";
|
2023-11-20 00:33:38 +00:00
|
|
|
import { Static, t } from "elysia";
|
2023-10-15 19:13:38 +00:00
|
|
|
import { info } from "std/log/mod.ts";
|
2023-10-09 19:03:31 +00:00
|
|
|
import { db } from "./db.ts";
|
|
|
|
import { generationStore } from "./generationStore.ts";
|
2023-11-20 00:33:38 +00:00
|
|
|
import { kvMemoize } from "../utils/kvMemoize.ts";
|
2023-10-09 19:03:31 +00:00
|
|
|
|
2023-11-20 00:33:38 +00:00
|
|
|
export const dailyStatsSchema = t.Object({
|
|
|
|
userIds: t.Array(t.Number()),
|
|
|
|
imageCount: t.Number(),
|
|
|
|
stepCount: t.Number(),
|
|
|
|
pixelCount: t.Number(),
|
|
|
|
pixelStepCount: t.Number(),
|
|
|
|
timestamp: t.Number(),
|
|
|
|
});
|
2023-10-09 19:03:31 +00:00
|
|
|
|
2023-11-20 00:33:38 +00:00
|
|
|
export type DailyStats = Static<typeof dailyStatsSchema>;
|
2023-10-09 19:03:31 +00:00
|
|
|
|
|
|
|
export const getDailyStats = kvMemoize(
|
|
|
|
db,
|
|
|
|
["dailyStats"],
|
|
|
|
async (year: number, month: number, day: number): Promise<DailyStats> => {
|
|
|
|
const userIdSet = new Set<number>();
|
|
|
|
let imageCount = 0;
|
2023-10-13 11:47:57 +00:00
|
|
|
let stepCount = 0;
|
2023-10-09 19:03:31 +00:00
|
|
|
let pixelCount = 0;
|
2023-10-13 11:47:57 +00:00
|
|
|
let pixelStepCount = 0;
|
2023-10-09 19:03:31 +00:00
|
|
|
|
|
|
|
const after = new Date(Date.UTC(year, month - 1, day));
|
|
|
|
const before = new Date(Date.UTC(year, month - 1, day + 1));
|
|
|
|
|
2023-10-15 19:13:38 +00:00
|
|
|
info(`Calculating daily stats for ${year}-${month}-${day}`);
|
2023-10-09 19:03:31 +00:00
|
|
|
|
|
|
|
for await (
|
|
|
|
const generation of generationStore.listAll({ after, before })
|
|
|
|
) {
|
|
|
|
userIdSet.add(generation.value.from.id);
|
|
|
|
imageCount++;
|
2023-10-13 11:47:57 +00:00
|
|
|
stepCount += generation.value.info?.steps ?? 0;
|
2023-10-09 19:03:31 +00:00
|
|
|
pixelCount += (generation.value.info?.width ?? 0) * (generation.value.info?.height ?? 0);
|
2023-10-13 11:47:57 +00:00
|
|
|
pixelStepCount += (generation.value.info?.width ?? 0) *
|
|
|
|
(generation.value.info?.height ?? 0) *
|
|
|
|
(generation.value.info?.steps ?? 0);
|
2023-10-09 19:03:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
userIds: [...userIdSet],
|
|
|
|
imageCount,
|
2023-10-13 11:47:57 +00:00
|
|
|
stepCount,
|
2023-10-09 19:03:31 +00:00
|
|
|
pixelCount,
|
2023-10-13 11:47:57 +00:00
|
|
|
pixelStepCount,
|
2023-10-09 19:03:31 +00:00
|
|
|
timestamp: Date.now(),
|
|
|
|
};
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// expire in 1 minute if was calculated on the same day, otherwise 7-14 days.
|
|
|
|
expireIn: (result, year, month, day) => {
|
|
|
|
const requestDate = new UTCDateMini(year, month - 1, day);
|
|
|
|
const calculatedDate = new UTCDateMini(result.timestamp);
|
|
|
|
return isSameDay(requestDate, calculatedDate)
|
|
|
|
? minutesToMilliseconds(1)
|
|
|
|
: hoursToMilliseconds(24 * 7 + Math.random() * 24 * 7);
|
|
|
|
},
|
|
|
|
// should cache if the stats are non-zero
|
|
|
|
shouldCache: (result) =>
|
|
|
|
result.userIds.length > 0 || result.imageCount > 0 || result.pixelCount > 0,
|
|
|
|
},
|
|
|
|
);
|