mirror of
https://github.com/array-in-a-matrix/matrix-word-counter.git
synced 2025-04-02 11:11:49 -04:00
137 lines
3.3 KiB
JavaScript
137 lines
3.3 KiB
JavaScript
import fs from "node:fs";
|
|
import { Module } from "node:module";
|
|
|
|
class WordCount {
|
|
constructor() {
|
|
const a = fs.readdirSync("./db");
|
|
|
|
//make sure dir exists
|
|
if (!a.some((b) => b === "count")) {
|
|
//if not, make the folder for it
|
|
fs.mkdirSync("./db/count");
|
|
}
|
|
const roomJSONlist = fs.readdirSync("./db/count");
|
|
|
|
//map to store everything in
|
|
this.perRoom = new Map();
|
|
this.writePromise = new Map();
|
|
this.writeQueued = new Map();
|
|
this.statsString = new Map();
|
|
|
|
//every stored room
|
|
for (const obj of roomJSONlist) {
|
|
//read and parse file
|
|
let roomFile;
|
|
|
|
try {
|
|
roomFile = fs.readFileSync(`./db/count/${obj}`);
|
|
} catch (e) {
|
|
console.log(`error reading file ${obj}, it may be a dir\n${e}`);
|
|
return;
|
|
}
|
|
|
|
const rm = JSON.parse(roomFile);
|
|
|
|
//get room id from the file name
|
|
const roomID = obj.substring(0, obj.length - 5);
|
|
|
|
//create a submap for the room
|
|
const roomMap = new Map();
|
|
this.perRoom.set(roomID, roomMap);
|
|
|
|
//each word is a key to a set of stats per user
|
|
const wordsSaved = Object.keys(rm);
|
|
for (const word of wordsSaved) {
|
|
//get the set of stats for that word
|
|
const stats = rm[word];
|
|
const users = Object.keys(stats);
|
|
|
|
//create a map for each word to store each user
|
|
const wordMap = new Map();
|
|
wordMap.set(word, wordMap);
|
|
|
|
//process each user
|
|
for (const user of users) {
|
|
//remaining bit to parce should just be an int to plop in
|
|
const userUsage = stats[user];
|
|
|
|
//if not a number its invalid data
|
|
if (Number.isNaN(userUsage)) return;
|
|
|
|
wordMap.set(user, userUsage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async addToUser(room, word, user, amount) {
|
|
if (!this.perRoom.has(room)) this.perRoom.set(room, new Map());
|
|
|
|
let stats = this.perRoom.get(room).get(word);
|
|
|
|
if (!stats) {
|
|
stats = new Map();
|
|
|
|
this.perRoom.get(room).set(word, stats);
|
|
}
|
|
|
|
let current = stats.get(user);
|
|
|
|
//if undefined set it to 0 just to make sure i dont footgun myself
|
|
if (!current) current = 0;
|
|
|
|
//set new value
|
|
stats.set(user, current + amount);
|
|
|
|
this.queueWrite(room);
|
|
}
|
|
|
|
async queueWrite(room) {
|
|
//the data is being global, if theres a scheduled write queued already
|
|
//the data will be written already so we can just toss any other queued
|
|
//for that room
|
|
if (this.writeQueued.get(room)) return;
|
|
|
|
//get the last write to await
|
|
const currentWritePromise = this.writePromise.get(room);
|
|
|
|
if (currentWritePromise) {
|
|
//say we already have one right after this
|
|
this.writeQueued.set(room, true);
|
|
|
|
//prevent racey writes
|
|
await currentWritePromise;
|
|
}
|
|
|
|
//save the promise to prevent racey writes
|
|
this.writePromise.set(room, this.write(room));
|
|
|
|
//no longer queueing
|
|
this.writeQueued.delete(room);
|
|
}
|
|
|
|
async write(room) {
|
|
const statsMap = this.perRoom.get(room);
|
|
|
|
const words = Array.from(statsMap.keys());
|
|
|
|
const statsObjMap = new Map();
|
|
|
|
for (const word of words) {
|
|
statsObjMap.set(word, Object.fromEntries(statsMap.get(word).entries()));
|
|
}
|
|
|
|
const statsObj = Object.fromEntries(statsObjMap.entries());
|
|
|
|
const statsString = JSON.stringify(statsObj, null, 2);
|
|
|
|
const oldStatsString = this.statsString.get(room);
|
|
|
|
//if its the same as what was already written no need to write
|
|
if (oldStatsString === statsString) return;
|
|
|
|
fs.writeFileSync(`./db/count/${room}.json`, statsString);
|
|
}
|
|
}
|
|
|
|
export { WordCount };
|