games_model.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. const pull = require('../server/node_modules/pull-stream');
  2. const { getConfig } = require('../configs/config-manager.js');
  3. const logLimit = getConfig().ssbLogStream?.limit || 5000;
  4. const VALID_GAMES = new Set([
  5. 'cocoland', 'ecoinflow', 'neoninfiltrator', 'spaceinvaders', 'arkanoid', 'pingpong',
  6. 'asteroids', 'tiktaktoe', 'flipflop',
  7. '8ball', 'artillery', 'labyrinth', 'cocoman', 'tetris'
  8. ]);
  9. module.exports = ({ cooler }) => {
  10. let ssb;
  11. const openSsb = async () => {
  12. if (!ssb) ssb = await cooler.open();
  13. return ssb;
  14. };
  15. async function readAll(ssbClient) {
  16. return new Promise((resolve, reject) => {
  17. pull(
  18. ssbClient.createLogStream({ limit: logLimit }),
  19. pull.collect((err, results) => (err ? reject(err) : resolve(results)))
  20. );
  21. });
  22. }
  23. return {
  24. async submitScore(game, score) {
  25. if (!VALID_GAMES.has(game)) throw new Error('invalid game');
  26. const n = Number(score);
  27. if (!Number.isFinite(n) || n < 0 || n > 9999999) throw new Error('invalid score');
  28. const ssbClient = await openSsb();
  29. return new Promise((resolve, reject) => {
  30. ssbClient.publish({ type: 'gameScore', game, score: Math.round(n) }, (err, msg) => {
  31. if (err) reject(err); else resolve(msg);
  32. });
  33. });
  34. },
  35. async getHallOfFame() {
  36. const ssbClient = await openSsb();
  37. const messages = await readAll(ssbClient);
  38. const best = {};
  39. for (const m of messages) {
  40. const c = m.value && m.value.content;
  41. if (!c || c.type !== 'gameScore') continue;
  42. if (!VALID_GAMES.has(c.game)) continue;
  43. const author = m.value.author;
  44. const score = Number(c.score);
  45. if (!Number.isFinite(score) || score < 0) continue;
  46. const key = `${c.game}:${author}`;
  47. if (!best[key] || score > best[key].score) {
  48. best[key] = { author, score, game: c.game, ts: m.value.timestamp || 0 };
  49. }
  50. }
  51. const hall = {};
  52. for (const game of VALID_GAMES) hall[game] = [];
  53. for (const entry of Object.values(best)) {
  54. if (hall[entry.game]) hall[entry.game].push(entry);
  55. }
  56. for (const game of VALID_GAMES) {
  57. hall[game] = hall[game].sort((a, b) => b.score - a.score).slice(0, 10);
  58. }
  59. return hall;
  60. }
  61. };
  62. };