ipfs document storage for etica - works on etica network/currencys
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

50 lines
1.7 KiB

// backend/metrics.js (ESM)
// Mount with: import registerMetrics from './metrics.js'; registerMetrics(app, { query: sql });
export default function registerMetrics(app, db) {
if (!app || !db || typeof db.query !== 'function') {
throw new Error('metrics: app and a {query(sql, [params])} db are required');
}
let cache = { at: 0, data: null };
const CACHE_MS = 5_000; // front-end polls at 10–60 min; 5s is fine here
app.get('/api/metrics', async (_req, res) => {
try {
const now = Date.now();
if (cache.data && (now - cache.at) < CACHE_MS) {
res.setHeader('Cache-Control', 'no-store');
return res.json(cache.data);
}
// Users = distinct payer addresses who have at least one successful upload (cid not null)
const u = await db.query(`
SELECT COUNT(DISTINCT lower(address))::bigint AS users
FROM public.payments
WHERE address IS NOT NULL AND address <> '' AND cid IS NOT NULL
`);
// Uploads + total bytes = only rows with a CID
const p = await db.query(`
SELECT
COUNT(*)::bigint AS uploads,
COALESCE(SUM(size_bytes), 0)::bigint AS bytes
FROM public.payments
WHERE cid IS NOT NULL
`);
const payload = {
users: Number(u.rows?.[0]?.users ?? 0),
uploads: Number(p.rows?.[0]?.uploads?? 0),
bytes: Number(p.rows?.[0]?.bytes ?? 0),
};
cache = { at: now, data: payload };
res.setHeader('Cache-Control', 'no-store');
res.json(payload);
} catch (err) {
console.error('metrics route error:', err);
res.status(500).json({ ok:false, error:'metrics_failed' });
}
});
}