main.ts 8.8 KB

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