diff --git a/app/server/libs/twitch/index.js b/app/server/libs/twitch/index.js index 634bb81b..3276dc1c 100644 --- a/app/server/libs/twitch/index.js +++ b/app/server/libs/twitch/index.js @@ -4,6 +4,8 @@ const { ApiClient } = require("twitch"); const AuthProvider = require("./AuthProvider"); const { ChatClient } = require("twitch-chat-client"); +require("./logger-hook"); + const api = { config, authProvider: null, diff --git a/app/server/libs/twitch/logger-hook.js b/app/server/libs/twitch/logger-hook.js new file mode 100644 index 00000000..efb9f54d --- /dev/null +++ b/app/server/libs/twitch/logger-hook.js @@ -0,0 +1,61 @@ +const { LogLevel, Logger } = require("@d-fischer/logger"); +const { watch, logsPath } = require("../../../utils"); +const chalk = require("chalk"); +const fs = require("fs-extra"); +const path = require("path"); + +let locked = false; +let queue = []; + +const maxLines = 500; +const logFile = path.join(logsPath, "twitch.log"); +const minLogLevel = watch ? LogLevel.DEBUG : LogLevel.WARNING; +const colors = [chalk.red, chalk.red, chalk.orange, chalk.blue, chalk.white]; + +fs.ensureFileSync(logFile); + +function getLogs() { + const text = fs.readFileSync(logFile); + return text.toString().split("\n"); +} + +function writeLogs(logs) { + if (locked) { + queue.unshift(logs); + return; + } + + locked = true; + + fs.writeFileSync(logFile, logs.slice(0, maxLines).join("\n")); + + if (queue.length) { + fs.writeFileSync( + logFile, + [...queue, ...logs].slice(0, maxLines).join("\n") + ); + queue = []; + } + + locked = false; +} + +function push(line) { + writeLogs([line, ...getLogs()]); +} + +Logger.prototype.log = function (level, message) { + if (level > minLogLevel) return; + + const levelName = LogLevel[level]; + const date = new Date().toISOString(); + const line = `[${date}] [${levelName}] [${this._name}] ${message}`; + + push(line); + + if (watch && level < LogLevel.INFO) { + const color = colors[level] || colors[colors.length - 1]; + // eslint-disable-next-line no-console + console.log(color(line)); + } +}; diff --git a/app/server/libs/twitch/pubsub/index.js b/app/server/libs/twitch/pubsub/index.js index 9b2dca6e..fd4ca8d4 100644 --- a/app/server/libs/twitch/pubsub/index.js +++ b/app/server/libs/twitch/pubsub/index.js @@ -1,13 +1,30 @@ -const { PubSubClient } = require("twitch-pubsub-client"); +const { BasicPubSubClient, PubSubClient } = require("twitch-pubsub-client"); const onRedemption = require("./onRedemption"); const onBits = require("./onBits"); const twitch = require("../index"); -const pubSubClient = new PubSubClient(); +const reconnectDelay = 5; + +const rootClient = new BasicPubSubClient(); +const pubSubClient = new PubSubClient(rootClient); + +function reconnect() { + console.log(`Reconnecting...`); + pubSubClient._rootClient.reconnect(); +} module.exports = async function init() { const userId = await pubSubClient.registerUserListener(twitch.api); await pubSubClient.onRedemption(userId, onRedemption); await pubSubClient.onBits(userId, onBits); + + pubSubClient._rootClient.onDisconnect((manually, reason) => { + // if (manually) return; + console.log("PUBSUB ERROR >>>", reason); + console.log(`Reconnecting in ${reconnectDelay} sec.`); + setTimeout(reconnect, reconnectDelay * 1000); + }); + + setTimeout(() => pubSubClient._rootClient.disconnect(), 5000); }; diff --git a/app/utils.js b/app/utils.js index 7c90dbc4..828799e8 100644 --- a/app/utils.js +++ b/app/utils.js @@ -17,10 +17,14 @@ if (watch) { const clientPath = path.join(appPath, "client"); const staticPath = path.join(appPath, "static"); + +const logsPath = path.join(userPath, "logs"); const uploadPath = path.join(userPath, "upload"); const storesPath = path.join(userPath, "stores"); -const filesPath = path.join(uploadPath, "files"); const databasePath = path.join(userPath, "database"); + +const filesPath = path.join(uploadPath, "files"); + const databaseFilename = "marv.sqlite"; const isFirstStart = !fs.existsSync(path.join(databasePath, databaseFilename)); @@ -30,6 +34,7 @@ module.exports = { watch, appPath, userPath, + logsPath, filesPath, uploadPath, storesPath,