diff --git a/src/canvasesDesc.js b/src/canvasesDesc.js index a2f94d5..176d630 100644 --- a/src/canvasesDesc.js +++ b/src/canvasesDesc.js @@ -4,6 +4,7 @@ * */ +import assetWatcher from './core/fsWatcher'; import canvases from './core/canvases'; import ttag from './core/ttag'; @@ -58,16 +59,21 @@ function getCanvases(t) { return localizedCanvases; } -const lCanvases = {}; -(() => { +function translateCanvases() { + const parsedCanvases = {}; const langs = Object.keys(ttag); langs.forEach((lang) => { - lCanvases[lang] = getCanvases(ttag[lang].t); + parsedCanvases[lang] = getCanvases(ttag[lang].t); }); -})(); - -export function getLocalizedCanvases(lang = 'en') { - return lCanvases[lang] || lCanvases.en; + return parsedCanvases; } -export default lCanvases; +let lCanvases = translateCanvases(); +// reload on asset change +assetWatcher.onChange(() => { + lCanvases = translateCanvases(); +}); + +export default function getLocalizedCanvases(lang = 'en') { + return lCanvases[lang] || lCanvases.en; +} diff --git a/src/core/assets.js b/src/core/assets.js index 73270cb..4df66d7 100644 --- a/src/core/assets.js +++ b/src/core/assets.js @@ -1,7 +1,13 @@ +/* + * Provide css and js asset files for client + */ + import fs from 'fs'; import path from 'path'; -const ASSET_DIR = '/assets'; +import assetWatcher from './fsWatcher'; +import { ASSET_DIR } from './config'; + const assetDir = path.join(__dirname, 'public', ASSET_DIR); /* * { @@ -78,8 +84,11 @@ function checkAssets() { return parsedAssets; } -// eslint-disable-next-line prefer-const assets = checkAssets(); +// reload on asset change +assetWatcher.onChange(() => { + assets = checkAssets(); +}); export function getLangsOfJsAsset(name) { const nameAssets = assets.js[name]; diff --git a/src/core/config.js b/src/core/config.js index ef371be..7afa8dd 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -10,6 +10,8 @@ if (process.env.BROWSER) { ); } +export const ASSET_DIR = '/assets'; + export const PORT = process.env.PORT || 8080; export const HOST = process.env.HOST || 'localhost'; diff --git a/src/core/fsWatcher.js b/src/core/fsWatcher.js new file mode 100644 index 0000000..c5023e5 --- /dev/null +++ b/src/core/fsWatcher.js @@ -0,0 +1,55 @@ +/* + * Watch for filesystem changes + */ +import fs from 'fs'; +import path from 'path'; + +import logger from './logger'; +import { ASSET_DIR } from './config'; + +class FsWatcher { + #path; + #timeout = null; + #listeners = []; + filetypes; + delay; + + constructor(watchPath, { delay = 5000, filetypes = [] }) { + if (!watchPath) { + throw new Error('Must define a path to watch'); + } + this.#path = watchPath; + this.delay = delay; + this.filetypes = filetypes; + this.initialize(); + } + + initialize() { + const watchPath = this.#path; + fs.watch(watchPath, (eventType, filename) => { + if (filename && this.filetypes.length) { + const ext = filename.split('.').pop(); + if (!this.filetypes.includes(ext)) { + return; + } + } + if (this.#timeout) { + clearTimeout(this.#timeout); + } + this.#timeout = setTimeout(() => { + logger.info('ASSET CHANGE, detected change in asset files'); + this.#listeners.forEach((cb) => cb(eventType, filename)); + }, this.delay); + }); + } + + onChange(cb) { + this.#listeners.push(cb); + } +} + +const assetWatcher = new FsWatcher( + path.join(__dirname, 'public', ASSET_DIR), + { filetypes: ['js', 'css'] }, +); +export default assetWatcher; diff --git a/src/core/me.js b/src/core/me.js index 2a83a2c..c961021 100644 --- a/src/core/me.js +++ b/src/core/me.js @@ -4,7 +4,7 @@ * various api endpoints. * */ -import { getLocalizedCanvases } from '../canvasesDesc'; +import getLocalizedCanvases from '../canvasesDesc'; import { USE_MAILER } from './config'; import chatProvider from './ChatProvider'; diff --git a/src/core/ttag.js b/src/core/ttag.js index fb6e209..b935471 100644 --- a/src/core/ttag.js +++ b/src/core/ttag.js @@ -4,6 +4,7 @@ import { TTag } from 'ttag'; import cookie from 'cookie'; +import assetWatcher from './fsWatcher'; import { getLangsOfJsAsset } from './assets'; // eslint-disable-next-line max-len @@ -13,13 +14,18 @@ const ttags = {}; export const availableLangs = []; -(() => { +function loadTtags() { const langs = localeImports.keys(); const jsLangs = getLangsOfJsAsset('client'); + availableLangs.length = 0; if (jsLangs.includes('en')) { - ttags.en = new TTag(); + if (!ttags.en) { + ttags.en = new TTag(); + } availableLangs.push(['en', 'gb']); + } else if (ttags.en) { + delete ttags.en; } for (let i = 0; i < langs.length; i += 1) { @@ -37,14 +43,24 @@ export const availableLangs = []; [lang, flag] = lang.split('-'); } if (jsLangs.includes(lang)) { - const ttag = new TTag(); - ttag.addLocale(lang, localeImports(file).default); - ttag.useLocale(lang); - ttags[lang] = ttag; + if (!ttags[lang]) { + const ttag = new TTag(); + ttag.addLocale(lang, localeImports(file).default); + ttag.useLocale(lang); + ttags[lang] = ttag; + } availableLangs.push([lang, flag]); + } else if (ttags[lang]) { + delete ttags[lang]; } } -})(); +} + +loadTtags(); +// reload on asset change +assetWatcher.onChange(() => { + loadTtags(); +}); export function getTTag(lang) { return ttags[lang] || ttags.en || Object.values(ttags)[0]; diff --git a/src/ssr/Main.jsx b/src/ssr/Main.jsx index 3b5abbe..bc224e0 100644 --- a/src/ssr/Main.jsx +++ b/src/ssr/Main.jsx @@ -12,17 +12,6 @@ import socketEvents from '../socket/socketEvents'; import { BACKUP_URL } from '../core/config'; import { getHostFromRequest } from '../utils/ip'; -/* - * values that we pass to client scripts - */ -const ssv = { - availableStyles: getCssAssets(), - langs, -}; -if (BACKUP_URL) { - ssv.backupurl = BACKUP_URL; -} - const bodyScript = '(function(){const sr=(e)=>{if(e.shadowRoot)e.remove();else if(e.children){for(let i=0;ie.forEach(e=>e.addedNodes.forEach((l)=>{if(l.querySelectorAll)l.querySelectorAll("option").forEach((o)=>{if(o.value==="random")window.location="https://discord.io/pixeltraaa";});sr(l);})));a.observe(document.body,{childList:!0});})()'; const bodyScriptHash = createHash('sha256').update(bodyScript).digest('base64'); @@ -38,7 +27,9 @@ function generateMainPage(req) { const shard = (host.startsWith(`${socketEvents.thisShard}.`)) ? null : socketEvents.getLowestActiveShard(); const ssvR = JSON.stringify({ - ...ssv, + availableStyles: getCssAssets(), + langs, + backupurl: BACKUP_URL, shard, lang, }); diff --git a/src/ssr/PopUp.jsx b/src/ssr/PopUp.jsx index dbe6ea2..64075c7 100644 --- a/src/ssr/PopUp.jsx +++ b/src/ssr/PopUp.jsx @@ -12,16 +12,6 @@ import { getJsAssets, getCssAssets } from '../core/assets'; import { BACKUP_URL } from '../core/config'; import { getHostFromRequest } from '../utils/ip'; -/* - * values that we pass to client scripts - */ -const ssv = { - availableStyles: getCssAssets(), - langs, -}; -if (BACKUP_URL) { - ssv.backupurl = BACKUP_URL; -} /* * generates string with html of win page @@ -34,7 +24,9 @@ function generatePopUpPage(req) { const shard = (host.startsWith(`${socketEvents.thisShard}.`)) ? null : socketEvents.getLowestActiveShard(); const ssvR = JSON.stringify({ - ...ssv, + availableStyles: getCssAssets(), + langs, + backupurl: BACKUP_URL, shard, lang, });