index.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. 'use strict';
  2. process.env.NODE_CONFIG_DIR = `${__dirname}/config`;
  3. const async = require('async');
  4. const fs = require('fs');
  5. const Discord = require("discord.js");
  6. const client = new Discord.Client();
  7. const db = require('./logic/db');
  8. const app = require('./logic/app');
  9. const mail = require('./logic/mail');
  10. const api = require('./logic/api');
  11. const io = require('./logic/io');
  12. const stations = require('./logic/stations');
  13. const songs = require('./logic/songs');
  14. const playlists = require('./logic/playlists');
  15. const cache = require('./logic/cache');
  16. const notifications = require('./logic/notifications');
  17. const punishments = require('./logic/punishments');
  18. const logger = require('./logic/logger');
  19. const tasks = require('./logic/tasks');
  20. const config = require('config');
  21. let currentComponent;
  22. let initializedComponents = [];
  23. let lockdownB = false;
  24. process.on('uncaughtException', err => {
  25. if (lockdownB || err.code === 'ECONNREFUSED' || err.code === 'UNCERTAIN_STATE') return;
  26. console.log(`UNCAUGHT EXCEPTION: ${err.stack}`);
  27. });
  28. const getError = (err) => {
  29. let error = 'An error occurred.';
  30. if (typeof err === "string") error = err;
  31. else if (err.message) {
  32. if (err.message !== 'Validation failed') error = err.message;
  33. else error = err.errors[Object.keys(err.errors)].message;
  34. }
  35. return error;
  36. };
  37. client.on('ready', () => {
  38. discordClientCBS.forEach((cb) => {
  39. cb();
  40. });
  41. console.log(`Logged in to Discord as ${client.user.username}#${client.user.discriminator}`);
  42. });
  43. client.login(config.get('apis.discord.token'));
  44. let discordClientCBS = [];
  45. const getDiscordClient = (cb) => {
  46. if (client.status === 0) return cb();
  47. else discordClientCBS.push(cb);
  48. };
  49. const logToDiscord = (message, color, type, critical, extraFields, cb = ()=>{}) => {
  50. getDiscordClient(() => {
  51. let richEmbed = new Discord.RichEmbed();
  52. richEmbed.setAuthor("Musare Logger", config.get("domain")+"/favicon-194x194.png", config.get("domain"));
  53. richEmbed.setColor(color);
  54. richEmbed.setDescription(message);
  55. //richEmbed.setFooter("Footer", "https://musare.com/favicon-194x194.png");
  56. //richEmbed.setImage("https://musare.com/favicon-194x194.png");
  57. //richEmbed.setThumbnail("https://musare.com/favicon-194x194.png");
  58. richEmbed.setTimestamp(new Date());
  59. richEmbed.setTitle("MUSARE ALERT");
  60. richEmbed.setURL(config.get("domain"));
  61. richEmbed.addField("Type:", type, true);
  62. richEmbed.addField("Critical:", (critical) ? 'True' : 'False', true);
  63. extraFields.forEach((extraField) => {
  64. richEmbed.addField(extraField.name, extraField.value, extraField.inline);
  65. });
  66. client.channels.get(config.get('apis.discord.loggingChannel')).sendEmbed(richEmbed).then(() => {
  67. cb();
  68. }).then((reason) => {
  69. cb(reason);
  70. });
  71. });
  72. };
  73. function lockdown() {
  74. if (lockdownB) return;
  75. lockdownB = true;
  76. initializedComponents.forEach((component) => {
  77. component._lockdown();
  78. });
  79. console.log("Backend locked down.");
  80. }
  81. function errorCb(message, err, component) {
  82. err = getError(err);
  83. lockdown();
  84. logToDiscord(message, "#FF0000", message, true, [{name: "Error:", value: err, inline: false}, {name: "Component:", value: component, inline: true}]);
  85. }
  86. async.waterfall([
  87. // setup our Redis cache
  88. (next) => {
  89. currentComponent = 'Cache';
  90. cache.init(config.get('redis').url, config.get('redis').password, errorCb, () => {
  91. next();
  92. });
  93. },
  94. // setup our MongoDB database
  95. (next) => {
  96. initializedComponents.push(cache);
  97. currentComponent = 'DB';
  98. db.init(config.get("mongo").url, errorCb, next);
  99. },
  100. // setup the express server
  101. (next) => {
  102. initializedComponents.push(db);
  103. currentComponent = 'App';
  104. app.init(next);
  105. },
  106. // setup the mail
  107. (next) => {
  108. initializedComponents.push(app);
  109. currentComponent = 'Mail';
  110. mail.init(next);
  111. },
  112. // setup the socket.io server (all client / server communication is done over this)
  113. (next) => {
  114. initializedComponents.push(mail);
  115. currentComponent = 'IO';
  116. io.init(next);
  117. },
  118. // setup the punishment system
  119. (next) => {
  120. initializedComponents.push(io);
  121. currentComponent = 'Punishments';
  122. punishments.init(next);
  123. },
  124. // setup the notifications
  125. (next) => {
  126. initializedComponents.push(punishments);
  127. currentComponent = 'Notifications';
  128. notifications.init(config.get('redis').url, config.get('redis').password, errorCb, next);
  129. },
  130. // setup the stations
  131. (next) => {
  132. initializedComponents.push(notifications);
  133. currentComponent = 'Stations';
  134. stations.init(next)
  135. },
  136. // setup the songs
  137. (next) => {
  138. initializedComponents.push(stations);
  139. currentComponent = 'Songs';
  140. songs.init(next)
  141. },
  142. // setup the playlists
  143. (next) => {
  144. initializedComponents.push(songs);
  145. currentComponent = 'Playlists';
  146. playlists.init(next)
  147. },
  148. // setup the API
  149. (next) => {
  150. initializedComponents.push(playlists);
  151. currentComponent = 'API';
  152. api.init(next)
  153. },
  154. // setup the logger
  155. (next) => {
  156. initializedComponents.push(api);
  157. currentComponent = 'Logger';
  158. logger.init(next)
  159. },
  160. // setup the tasks system
  161. (next) => {
  162. initializedComponents.push(logger);
  163. currentComponent = 'Tasks';
  164. tasks.init(next)
  165. },
  166. // setup the frontend for local setups
  167. (next) => {
  168. initializedComponents.push(tasks);
  169. currentComponent = 'Windows';
  170. if (!config.get("isDocker")) {
  171. const express = require('express');
  172. const app = express();
  173. app.listen(80);
  174. const rootDir = __dirname.substr(0, __dirname.lastIndexOf("backend")) + "frontend\\build\\";
  175. app.get("/*", (req, res) => {
  176. const path = req.path;
  177. fs.access(rootDir + path, function(err) {
  178. if (!err) {
  179. res.sendFile(rootDir + path);
  180. } else {
  181. res.sendFile(rootDir + "index.html");
  182. }
  183. });
  184. });
  185. }
  186. if (lockdownB) return;
  187. next();
  188. }
  189. ], (err) => {
  190. if (err && err !== true) {
  191. lockdown();
  192. logToDiscord("An error occurred while initializing the backend server.", "#FF0000", "Startup error", true, [{name: "Error:", value: err, inline: false}, {name: "Component:", value: currentComponent, inline: true}]);
  193. console.error('An error occurred while initializing the backend server');
  194. } else {
  195. logToDiscord("The backend server started successfully.", "#00AA00", "Startup", false, []);
  196. console.info('Backend server has been successfully started');
  197. }
  198. });