diff --git a/backend/classes/HistoryFile.js b/backend/classes/HistoryFile.js new file mode 100644 index 0000000..999ecd0 --- /dev/null +++ b/backend/classes/HistoryFile.js @@ -0,0 +1,82 @@ +import path from 'path'; +import fs from 'fs'; + +export default class HistoryFile { + constructor(fileName) { + this.path = path.join(process.cwd(), fileName); + this.history = []; + this.load(); + } + + /** + * Writes history to file + * @returns {boolean} true if successful, false otherwise + */ + writeToFile() { + try { + fs.writeFileSync(this.path, JSON.stringify(this.history)); + return true; + } catch (err) { + console.error(`Failed to write data to history file: ${err.message}`); + return false; + } + } + + /** + * Reads history file, and returns it as JSON + * @returns {array} + */ + readFromFile() { + try { + const raw = fs.readFileSync(this.path, 'utf-8'); + return JSON.parse(raw); + } catch (err) { + console.warn(`Failed at reading history, using empty history: ${err.message}`); + return []; + } + } + + /** + * Loads history file, if it exists + * If not, creates empty file + */ + load() { + if (fs.existsSync(this.path)) { + // Read file, and update this.history + const data = this.readFromFile(); + this.history = data; + } else { + // Create empty history file, if doesn't exist + this.writeToFile(); + } + } + + /** + * Saves most recent 15 entries to history file + */ + save() { + // If there's more than 15 entries, we need to save only most recent 15 ones + if (this.history.length > 15) { + this.history = this.history.slice(this.history.length - 15); + } + + // Write to history file + this.writeToFile(); + } + + /** + * Appends new entry to history file + * Returns most recent entry + * @param {number} number + * @returns {object} + */ + append(number) { + const data = { number, timestamp: Date.now() }; + // Push new entry to history + this.history.push(data); + // Save history file, and keep only 15 entries + this.save(); + // Return most recent entry + return data; + } +} diff --git a/backend/data.json b/backend/data.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/backend/data.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/backend/index.js b/backend/index.js index a705d0a..8667437 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,8 +1,15 @@ -const WebSocket = require('ws'); +import { WebSocketServer } from 'ws'; +import HistoryFile from './classes/HistoryFile.js'; -const wss = new WebSocket.Server({ port: 8080 }); +// Define WebSocket server +const wss = new WebSocketServer({ port: 8080 }); +// Define History file class +// For managing data state beyond restart +const history = new HistoryFile('data.json'); wss.on('connection', (ws) => { + // On successful connection, we send history data to the client + // After that, we procceed sending data update every 10 seconds console.log('Client connected'); ws.on('message', (message) => { diff --git a/backend/package.json b/backend/package.json index b6970fa..4584854 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,7 @@ { "name": "backend", "version": "1.0.0", + "type": "module", "main": "index.js", "scripts": { "dev": "nodemon index.js", diff --git a/backend/utils/random.js b/backend/utils/random.js new file mode 100644 index 0000000..4e6776f --- /dev/null +++ b/backend/utils/random.js @@ -0,0 +1,33 @@ +/** + * Generates a random integer between min and max (inclusive) + * @param {number} min + * @param {number} max + * @returns {number} + */ +export function randomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +/** + * Generates a random number based on previous number, and provided range + * Also taking into account global provided min and max values + * @param {number} previousNumber + * @param {number} range (0 - 1) + * @param {number} min + * @param {number} max + * @returns {number} + */ +export function randomInRange(previousNumber, range, min, max) { + // Decides on min max range for the next number + // based on range, and previous number + const integerRange = previousNumber * range; // +- 0.3 -> 30% + // Calculate min, and check if its less that global min (eg. 0) + let newMin = previousNumber - integerRange; + if (newMin < min) newMin = min; // sets to global min, for example 0 + + // calculate max, and check if number is above the global set max (eg. 100) + let newMax = previousNumber + integerRange; + if (newMax > max) newMax = max; // sets to global max, for example 100 + + return Math.floor(randomInt(newMin, newMax)); +}