main.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import * as readline from "node:readline";
  2. import ModuleManager from "./ModuleManager";
  3. import LogBook from "./LogBook";
  4. const logBook = new LogBook();
  5. process.removeAllListeners("uncaughtException");
  6. process.on("uncaughtException", err => {
  7. if (err.name === "ECONNREFUSED" || err.name === "UNCERTAIN_STATE") return;
  8. logBook.log({
  9. message: err.message || err,
  10. type: "error",
  11. category: "uncaught-exceptions",
  12. data: {
  13. error: err.message
  14. ? {
  15. cause: err.cause,
  16. name: err.name,
  17. stack: err.stack
  18. }
  19. : err
  20. }
  21. });
  22. });
  23. const moduleManager = new ModuleManager(logBook);
  24. moduleManager.startup();
  25. // TOOD remove, or put behind debug option
  26. // eslint-disable-next-line
  27. // @ts-ignore
  28. global.moduleManager = moduleManager;
  29. // eslint-disable-next-line
  30. // @ts-ignore
  31. global.rs = () => {
  32. process.exit();
  33. };
  34. // const interval = setInterval(() => {
  35. // moduleManager
  36. // .runJob("stations", "addToQueue", { songId: "TestId" })
  37. // .catch(() => {});
  38. // moduleManager
  39. // .runJob("stations", "addA", {}, { priority: 5 })
  40. // .catch(() => {});
  41. // moduleManager
  42. // .runJob("others", "doThing", { test: "Test", test2: 123 })
  43. // .catch(() => {});
  44. // }, 40);
  45. // setTimeout(() => {
  46. // clearTimeout(interval);
  47. // }, 3000);
  48. setTimeout(async () => {
  49. const _id = "6371212daf4e9f8fb14444b2";
  50. // logBook.log("Find with no projection");
  51. // await moduleManager
  52. // .runJob("data", "find", {
  53. // collection: "abc",
  54. // filter: {
  55. // _id
  56. // }
  57. // })
  58. // .then(console.log)
  59. // .catch(console.error);
  60. // logBook.log("Find with no projection, and a more advanced filter");
  61. // await moduleManager
  62. // .runJob("data", "find", {
  63. // collection: "abc",
  64. // filter: {
  65. // "autofill.enabled": true
  66. // }
  67. // })
  68. // .then(console.log)
  69. // .catch(console.error);
  70. // logBook.log("Find with array projection");
  71. // await moduleManager
  72. // .runJob("data", "find", {
  73. // collection: "abc",
  74. // filter: {
  75. // _id
  76. // },
  77. // projection: ["name"]
  78. // })
  79. // .then(console.log)
  80. // .catch(console.error);
  81. // logBook.log("Find with object boolean projection");
  82. // await moduleManager
  83. // .runJob("data", "find", {
  84. // collection: "abc",
  85. // filter: {
  86. // _id
  87. // },
  88. // projection: { name: true },
  89. // limit: 1
  90. // })
  91. // .then(console.log)
  92. // .catch(console.error);
  93. // logBook.log("Find with object number projection");
  94. // await moduleManager
  95. // .runJob("data", "find", {
  96. // collection: "abc",
  97. // filter: {
  98. // _id
  99. // },
  100. // projection: { name: 1 }
  101. // })
  102. // .then(console.log)
  103. // .catch(console.error);
  104. // logBook.log("Find with object number projection");
  105. // await moduleManager
  106. // .runJob("data", "find", {
  107. // collection: "abc",
  108. // filter: {
  109. // _id
  110. // },
  111. // projection: { "autofill.enabled": true }
  112. // })
  113. // .then(console.log)
  114. // .catch(console.error);
  115. // logBook.log("Find for testing casting");
  116. // await moduleManager
  117. // .runJob("data", "find", {
  118. // collection: "abc",
  119. // filter: {
  120. // // "songs._id": "6371212daf4e9f8fb14444b0"
  121. // // "songs._id": "6371212daf4e9f8fb14444b2"
  122. // // songs: {
  123. // // _id: "6371212daf4e9f8fb14444b0"
  124. // // }
  125. // // songs: {
  126. // // randomProperty: "6371212daf4e9f8fb14444b0"
  127. // // }
  128. // "songs.obj.test": "6371212daf4e9f8fb14444b0"
  129. // },
  130. // // projection: {
  131. // // // songs: true,
  132. // // // someNumbers: false
  133. // // },
  134. // limit: 1
  135. // })
  136. // .then(console.log)
  137. // .catch(console.error);
  138. // logBook.log("Find for testing with $in");
  139. // await moduleManager
  140. // .runJob("data", "find", {
  141. // collection: "abc",
  142. // filter: {
  143. // _id
  144. // },
  145. // allowedRestricted: true,
  146. // // projection: {
  147. // // // songs: true,
  148. // // // someNumbers: false
  149. // // },
  150. // limit: 1
  151. // })
  152. // .then(console.log)
  153. // .catch(console.error);
  154. // logBook.log("Find for testing with $in");
  155. // await moduleManager
  156. // .runJob("data", "find", {
  157. // collection: "abc",
  158. // filter: {
  159. // "songs._id": "6371212daf4e9f8fb14444b0"
  160. // },
  161. // allowedRestricted: true,
  162. // // projection: {
  163. // // // songs: true,
  164. // // // someNumbers: false
  165. // // },
  166. // limit: 1
  167. // })
  168. // .then(console.log)
  169. // .catch(console.error);
  170. // logBook.log("Find for testing with $in with numbers");
  171. // await moduleManager
  172. // .runJob("data", "find", {
  173. // collection: "abc",
  174. // filter: {
  175. // someNumbers: { $in: [54, 84] }
  176. // },
  177. // limit: 1,
  178. // useCache: false
  179. // })
  180. // .then(console.log)
  181. // .catch(console.error);
  182. }, 0);
  183. const rl = readline.createInterface({
  184. input: process.stdin,
  185. output: process.stdout,
  186. completer: (command: string) => {
  187. const parts = command.split(" ");
  188. const commands = ["eval "];
  189. if (parts.length === 1) {
  190. const hits = commands.filter(c => c.startsWith(parts[0]));
  191. return [hits.length ? hits : commands, command];
  192. }
  193. return [];
  194. },
  195. removeHistoryDuplicates: true
  196. });
  197. const shutdown = async () => {
  198. if (rl) {
  199. rl.removeAllListeners();
  200. rl.close();
  201. }
  202. await moduleManager.shutdown().catch(() => process.exit(1));
  203. process.exit(0);
  204. };
  205. process.on("SIGINT", shutdown);
  206. process.on("SIGQUIT", shutdown);
  207. process.on("SIGTERM", shutdown);
  208. const runCommand = (line: string) => {
  209. const [command, ...args] = line.split(" ");
  210. switch (command) {
  211. case "help": {
  212. console.log("Commands:");
  213. console.log("status");
  214. console.log("stats");
  215. console.log("queue");
  216. console.log("active");
  217. console.log("eval");
  218. console.log("debug");
  219. console.log("log");
  220. break;
  221. }
  222. case "status": {
  223. console.log("Module Manager Status:");
  224. console.table(moduleManager.getStatus());
  225. console.log("Job Queue Status:");
  226. console.table(moduleManager.getJobsStatus());
  227. break;
  228. }
  229. case "stats": {
  230. console.log("Job Queue Stats:");
  231. console.table(moduleManager.getJobsStats());
  232. break;
  233. }
  234. case "queue": {
  235. const queueStatus = moduleManager.getQueueStatus().queue;
  236. if (queueStatus.length === 0)
  237. console.log("There are no jobs in the queue.");
  238. else
  239. console.log(
  240. `There are ${queueStatus.length} jobs in the queue.`
  241. );
  242. console.table(queueStatus);
  243. break;
  244. }
  245. case "active": {
  246. const activeStatus = moduleManager.getQueueStatus().active;
  247. if (activeStatus.length === 0)
  248. console.log("There are no active jobs.");
  249. else console.log(`There are ${activeStatus.length} active jobs.`);
  250. console.table(activeStatus);
  251. break;
  252. }
  253. case "eval": {
  254. const evalCommand = args.join(" ");
  255. console.log(`Running eval command: ${evalCommand}`);
  256. // eslint-disable-next-line no-eval
  257. const response = eval(evalCommand);
  258. console.log(`Eval response: `, response);
  259. break;
  260. }
  261. case "debug": {
  262. // eslint-disable-next-line no-debugger
  263. debugger;
  264. break;
  265. }
  266. case "log": {
  267. const [output, key, action, ...values] = args;
  268. if (
  269. output === undefined ||
  270. key === undefined ||
  271. action === undefined
  272. ) {
  273. console.log(
  274. `Missing required parameters (log <output> <key> <action> [values])`
  275. );
  276. break;
  277. }
  278. let value: any[] | undefined;
  279. if (values !== undefined && values.length >= 1) {
  280. value = values.map(_filter => JSON.parse(_filter));
  281. if (value.length === 1) [value] = value;
  282. }
  283. logBook
  284. // @ts-ignore
  285. .updateOutput(output, key, action, value)
  286. .then(() => console.log("Successfully updated outputs"))
  287. .catch((err: Error) =>
  288. console.log(`Error updating outputs "${err.message}"`)
  289. );
  290. break;
  291. }
  292. default: {
  293. if (!/^\s*$/.test(command))
  294. console.log(`Command "${command}" not found`);
  295. }
  296. }
  297. };
  298. rl.on("line", runCommand);