main.ts 8.8 KB

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