const pull = require('../server/node_modules/pull-stream'); const { getConfig } = require('../configs/config-manager.js'); const logLimit = getConfig().ssbLogStream?.limit || 5000; const VALID_GAMES = new Set([ 'cocoland', 'ecoinflow', 'neoninfiltrator', 'spaceinvaders', 'arkanoid', 'pingpong', 'asteroids', 'tiktaktoe', 'flipflop', '8ball', 'artillery', 'labyrinth', 'cocoman', 'tetris' ]); module.exports = ({ cooler }) => { let ssb; const openSsb = async () => { if (!ssb) ssb = await cooler.open(); return ssb; }; async function readAll(ssbClient) { return new Promise((resolve, reject) => { pull( ssbClient.createLogStream({ limit: logLimit }), pull.collect((err, results) => (err ? reject(err) : resolve(results))) ); }); } return { async submitScore(game, score) { if (!VALID_GAMES.has(game)) throw new Error('invalid game'); const n = Number(score); if (!Number.isFinite(n) || n < 0 || n > 9999999) throw new Error('invalid score'); const ssbClient = await openSsb(); return new Promise((resolve, reject) => { ssbClient.publish({ type: 'gameScore', game, score: Math.round(n) }, (err, msg) => { if (err) reject(err); else resolve(msg); }); }); }, async getHallOfFame() { const ssbClient = await openSsb(); const messages = await readAll(ssbClient); const best = {}; for (const m of messages) { const c = m.value && m.value.content; if (!c || c.type !== 'gameScore') continue; if (!VALID_GAMES.has(c.game)) continue; const author = m.value.author; const score = Number(c.score); if (!Number.isFinite(score) || score < 0) continue; const key = `${c.game}:${author}`; if (!best[key] || score > best[key].score) { best[key] = { author, score, game: c.game, ts: m.value.timestamp || 0 }; } } const hall = {}; for (const game of VALID_GAMES) hall[game] = []; for (const entry of Object.values(best)) { if (hall[entry.game]) hall[entry.game].push(entry); } for (const game of VALID_GAMES) { hall[game] = hall[game].sort((a, b) => b.score - a.score).slice(0, 10); } return hall; } }; };