diff --git a/Dockerfile b/Dockerfile index 9a3fa84..9a4d8c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,9 @@ RUN npm install COPY . . RUN addgroup -S app -g 50000 && \ - adduser -S -g app -u 50000 app + adduser -S -g app -u 50000 app && \ + mkdir /data && chown app:app /data/ + USER app ENTRYPOINT [ "node", "src/server.js" ] diff --git a/env.json b/env.json index 39cf79f..3ef3d4a 100644 --- a/env.json +++ b/env.json @@ -6,6 +6,10 @@ "options": ["development", "testing", "staging", "production"] }] }, + "TENANT": { + "required": true, + "description": "The tenant of the owning service." + }, "LOGDNA_API_KEY": { "required": false, "description": "If set, enables application logging to the LogDNA logger service." diff --git a/src/data.js b/src/data.js index 4747dc8..52fc336 100644 --- a/src/data.js +++ b/src/data.js @@ -4,9 +4,8 @@ const logger = require('./logging.js'); function readWarnings () { // Load the warnings file into the bans variable. - fs.readFile('data/discordWarnings.json', 'utf8', function (err, data) { - if (err && err.code === 'ENOENT') { return; } - if (err) { logger.error(err); } + fs.readFile('/data/discordWarnings.json', 'utf8', function (err, data) { + if (err) { throw err; } state.warnings = JSON.parse(data); logger.debug('Loaded warnings file.'); }); @@ -14,9 +13,8 @@ function readWarnings () { function readBans () { // Load the ban file into the bans variable. - fs.readFile('data/discordBans.json', 'utf8', function (err, data) { - if (err && err.code === 'ENOENT') { return; } - if (err) { logger.error(err); } + fs.readFile('/data/discordBans.json', 'utf8', function (err, data) { + if (err) { throw err; } state.bans = JSON.parse(data); logger.debug('Loaded bans file.'); }); @@ -25,18 +23,17 @@ function readBans () { function readCustomResponses() { // Load the responses file into the responses variable. - fs.readFile('data/responses.json', 'utf8', function (err, data) { - if (err && err.code === 'ENOENT') { return; } - if (err) { logger.error(err); } + fs.readFile('/data/responses.json', 'utf8', function (err, data) { + if (err) { throw err; } state.responses = JSON.parse(data); - logger.debug('Loaded responses file.'); + logger.debug('Loaded responses file from external source.'); }); } function flushWarnings () { var warningsJson = JSON.stringify(state.warnings, null, 4); if (!fs.existsSync('./data/')) fs.mkdirSync('data'); - fs.writeFile('data/discordWarnings.json', warningsJson, 'utf8', function (err) { + fs.writeFile('/data/discordWarnings.json', warningsJson, 'utf8', function (err) { if (err) { logger.error(err); } }); } @@ -44,7 +41,7 @@ function flushWarnings () { function flushBans () { var bansJson = JSON.stringify(state.bans, null, 4); if (!fs.existsSync('data')) fs.mkdirSync('data'); - fs.writeFile('data/discordBans.json', bansJson, 'utf8', function (err) { + fs.writeFile('/data/discordBans.json', bansJson, 'utf8', function (err) { if (err) { logger.error(err); } }); } diff --git a/src/logging.js b/src/logging.js index 4e6216c..43b0b42 100644 --- a/src/logging.js +++ b/src/logging.js @@ -18,16 +18,18 @@ var logger = new winston.Logger({ // Setup logging for LogDNA cloud logging. if (process.env.LOGDNA_API_KEY) { require('logdna'); - logger.add(winston.transports.Logdna, { - level: 'info', - app: 'discord-bot', - index_meta: true, - key: process.env.LOGDNA_API_KEY, - ip: ip.address(), - hostname: os.hostname() - }); + const logLevel = process.env.LOGDNA_LEVEL || 'info'; + + logger.add(winston.transports.Logdna, { + level: logLevel, + app: process.env.LOGDNA_APPNAME, + index_meta: true, + key: process.env.LOGDNA_API_KEY, + ip: ip.address(), + hostname: os.hostname() + }); - logger.info('Started LogDNA winston transport.'); + logger.info(`[core] Started LogDNA winston transport. Running at log level ${logLevel}.`); } module.exports = logger; diff --git a/src/responses.json b/src/responses.json index 81eeb2e..c876e9f 100644 --- a/src/responses.json +++ b/src/responses.json @@ -1,23 +1,6 @@ { - "pmReply": "Please refer to our **Frequently Asked Questions**. ", + "pmReply": "Hello world!", "quotes": { - "faq": { "reply": "Please refer to our **Frequently Asked Questions**. " }, - "cpu": { "reply": "Citra requires powerful single-core performance. Refer to your CPU in this graph. Your experience with Citra won't be enjoyable in most games if it's below 1,800. " }, - "requirements": { "reply": "Please refer to our **Frequently Asked Questions**. The only requirements for Citra are a GPU that supports at least OpenGL 3.3 and a 64-bit OS, but you definitely want a processor with the highest possible performance per core. "}, - "roms": { "reply": "Please read our __community rules__. Warez/downloading games talk is strictly prohibited. To prevent legal issues, you are not allowed to post links or refer to any kind of ROM, NAND, ISO, game, or other copyrighted material that has been illegally obtained or shared. "}, - "dump-game": { "reply": "Please refer to our __game dumping guides__. *or* "}, - "dump-system": { "reply": "Please refer to our __system dumping guide__. "}, - "pokemon": { "reply": "Click here to view our game compatibility list: "}, - "alpha": { "reply": "*Citra* is currently in very early stages of development. Games usually run less than full-speed even on the best computers. Expect bugs and glitches to appear in most games. Many features found in more mature emulators are still in the works. For any major updates, please visit "}, - "updates": { "reply": "You can check our latest updates on *Github*. "}, - "download": { "reply": "Please only download from the official *Citra* website, as downloading from other sources is not supported here. "}, - "legal": { "reply": "*Citra* is legal, we don't support illegal activities. Dumping your purchased games and system files from your 3DS is legal. Downloading them is not."}, - "building": { "reply": "Please refer to our building guides.\nWindows: \nmacOS: \nLinux: "}, - "controller": { "reply": "This forum topic tells you how to __configure your gamepad / controller__: "}, - "issues": { "reply": "This forum topic lists __known issues in games and their workarounds__: \nPlease read it carefully. It includes help with most games"}, - "forum": { "reply": "This question might be more suitable for the *Citra* forum. "}, - "game": { "reply": "Click here to view our game compatibility list: "}, - "log": { "reply": "This forum topic tells you how to __get the log file__: "}, - "canary": { "reply": "The nightly build of Citra contains already reviewed and tested features. If you require support with the installation or use of Citra, or you want to report bugs you should use this version.\nThe Canary build of Citra is the same as our nightly builds, with additional features that are still waiting on review before making it into the official Citra builds. We will not provide support for issues found only in this version. If you believe you’ve found a bug, please retest on our nightly builds. Both versions are still in development, so expect crashes and bugs."} + "ping": { "reply": "Pong!" } } } diff --git a/src/server.js b/src/server.js index 5c9b012..7486492 100644 --- a/src/server.js +++ b/src/server.js @@ -16,8 +16,14 @@ var cachedModules = []; var cachedTriggers = []; var client = new discord.Client(); -process.on('unhandledRejection', function onError (err) { - logger.error(err); +logger.info('Application startup. Configuring environment.'); + +process.on('unhandledRejection', (error, promise) => { + logger.error(`Unhandled promise rejection: ${error.message}.`, error); +}); + +process.on('uncaughtException', error => { + logger.error(`Unhandled exception: ${error.message}.`, error); }); function findArray (haystack, arr) {