openvibers/openvibe.media Commits

App stats: hours archived answer every window (it was an un-awaited function, so the JSON said hours: {}), and each window carries pw, the seven days before the last seven (#197)

OP OpenVibers committed 17 days ago · 49f82b8a93 · 2 files, +48 −11

Changes

ddiff --git a/server/db/database.js b/server/db/database.js
iindex b649672..c72b642 100644
---- a/server/db/database.js
++++ b/server/db/database.js
@@@ -324,11 +324,17 @@ async function latestVodThumbsByManagedStreams(appId, managedStreamIds) {
/** Aggregate per-app media stats for the owning app's dashboards/heroes. */
async function getAppStats(appId) {
const c = async (sql, p = []) => { try { return (await get(sql, p))?.n || 0; } catch { return 0; } };
-- const win = async (sql, extraParams = []) => ({
-- d: await c(sql, [...extraParams, '-1 day']),
-- w: await c(sql, [...extraParams, '-7 days']),
-- m: await c(sql, [...extraParams, '-30 days']),
-- });
++ // Rolling day/week/month figures, and `pw`: the seven days before the last seven, so a reader can say whether
++ // this week beat the last one.
++ const win = async (agg, base, scale = 1) => {
++ const q = async (where, params) => Math.round((await c(`SELECT ${agg} n ${base} AND ${where}`, [appId, ...params])) / scale);
++ return {
++ d: await q("created_at >= datetime('now', ?)", ['-1 day']),
++ w: await q("created_at >= datetime('now', ?)", ['-7 days']),
++ m: await q("created_at >= datetime('now', ?)", ['-30 days']),
++ pw: await q("created_at >= datetime('now', ?) AND created_at < datetime('now', ?)", ['-14 days', '-7 days']),
++ };
++ };
const vodBase = "FROM vods WHERE app_id = ? AND is_public = 1 AND COALESCE(is_recording,0) = 0 AND COALESCE(clips_only,0) = 0";
const clipBase = "FROM clips WHERE app_id = ? AND COALESCE(is_public,1) = 1";
return {
@@@ -336,12 +342,10 @@ async function getAppStats(appId) {
clips: await c(`SELECT COUNT(*) n ${clipBase}`, [appId]),
durationSeconds: await c(`SELECT COALESCE(SUM(duration_seconds),0) n ${vodBase}`, [appId]),
recent: {
-- vods: await win(`SELECT COUNT(*) n ${vodBase} AND created_at >= datetime('now', ?)`, [appId]),
-- clips: await win(`SELECT COUNT(*) n ${clipBase} AND created_at >= datetime('now', ?)`, [appId]),
-- hours: (async () => {
-- const w = await win(`SELECT COALESCE(SUM(duration_seconds),0) n ${vodBase} AND created_at >= datetime('now', ?)`, [appId]);
-- return { d: Math.round(w.d / 3600), w: Math.round(w.w / 3600), m: Math.round(w.m / 3600) };
-- })(),
++ vods: await win('COUNT(*)', vodBase),
++ clips: await win('COUNT(*)', clipBase),
++ // Hours archived. This was an un-awaited async function, so the stats answered `hours: {}`.
++ hours: await win('COALESCE(SUM(duration_seconds),0)', vodBase, 3600),
},
};
}
ddiff --git a/test/app-stats.test.js b/test/app-stats.test.js
nnew file mode 100644
iindex 0000000..dd3f2df
---- /dev/null
++++ b/test/app-stats.test.js
@@@ -0,0 +1,33 @@
++'use strict';
++// An app's stats (GET /api/v1/:app/stats, db.getAppStats): the home page counters and their rolling windows. Hours
++// archived over a window used to be an un-awaited async function, so the JSON answered `hours: {}` and Live's
++// "Hours archived" never showed a change; each window also carries `pw`, the seven days before the last seven.
++const assert = require('assert');
++const fs = require('fs');
++const os = require('os');
++const path = require('path');
++
++(async () => {
++ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ov-media-app-stats-'));
++ const dir = (n) => { const d = path.join(tmp, n); fs.mkdirSync(d, { recursive: true }); return d; };
++ Object.assign(process.env, {
++ VOD_PATH: dir('vods'), CLIPS_PATH: dir('clips'), FILES_PATH: dir('files'), THUMBNAILS_PATH: dir('thumbnails'),
++ PASTES_PATH: dir('pastes'), OBJECTS_PATH: dir('objects'), MEDIA_PUBLIC_URL: 'https://media.test',
++ });
++ const db = require('../server/db/database');
++ const d = db.getDb();
++ const V = d.prepare(`INSERT INTO vods (id, app_id, file_path, file_size, duration_seconds, visibility, is_public, storage_provider, created_at) OVERRIDING SYSTEM VALUE
++ VALUES (?, 'live', ?, 100, ?, 'public', 1, 'local', datetime('now', ?))`);
++ // Two hours today, three hours ten days ago, one an hour long 40 days ago.
++ await V.run(9101, '/x/9101.webm', 7200, '-1 hours');
++ await V.run(9102, '/x/9102.webm', 10800, '-10 days');
++ await V.run(9103, '/x/9103.webm', 3600, '-40 days');
++
++ const s = JSON.parse(JSON.stringify(await db.getAppStats('live')));
++ assert.strictEqual(Number(s.vods), 3);
++ assert.deepStrictEqual(s.recent.hours, { d: 2, w: 2, m: 5, pw: 3 }, 'hours archived answer every window, as numbers');
++ assert.deepStrictEqual(s.recent.vods, { d: 1, w: 1, m: 2, pw: 1 });
++ assert.deepStrictEqual(s.recent.clips, { d: 0, w: 0, m: 0, pw: 0 });
++ console.log(' ✓ an app\'s stats answer hours archived per window, and the week before');
++ process.exit(0);
++})().catch((err) => { console.error(err); process.exit(1); });