main.ts 9.1 KB

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