poll.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { Request as ExpressRequest, Response as ExpressResponse } from "express";
  2. import { Option, tryDo } from "@shared/common/async_utils";
  3. import { rpcClient } from "src/utils/rpc";
  4. import { eventLogger } from "src/utils/logging";
  5. import { QueryOptions } from "winston";
  6. export interface LogEvent {
  7. _id: string;
  8. label: string;
  9. level: string;
  10. message: string;
  11. timestamp: string;
  12. }
  13. export interface PollOptions {
  14. limit?: string;
  15. }
  16. function zip(obj: Record<string, unknown[]>): unknown[] {
  17. return Object.values(obj).reduce((prev, cur) => [...prev, ...cur], []);
  18. }
  19. function isNumber(val: unknown): val is number {
  20. return !Number.isNaN(Number.parseInt(val as string, 10));
  21. }
  22. function queryEvents(opts?: QueryOptions | { includeIds?: boolean }):
  23. Promise<Record<string, unknown[]>> {
  24. return new Promise((resolve, reject) => {
  25. eventLogger.query(opts as QueryOptions, (error, results) => {
  26. if (error) {
  27. reject(error);
  28. } else {
  29. resolve(results);
  30. }
  31. });
  32. });
  33. }
  34. export type PollResult = Option<{ events: LogEvent[] }, { error: string }>;
  35. type GetResult = Promise<ExpressResponse<PollResult>>;
  36. export const get = async (req: ExpressRequest, res: ExpressResponse): GetResult => {
  37. const params = req.query as PollOptions;
  38. if (!req.session?.userId) {
  39. return res.json({
  40. ok: false,
  41. error: "Not logged in, please log in",
  42. });
  43. }
  44. const { authorised } = await rpcClient.userAuthorised({ userId: req.session.userId });
  45. if (!authorised) {
  46. return res.json({
  47. ok: false,
  48. error: "Not authorised, please log in",
  49. });
  50. }
  51. const DEFAULT_LIMIT = 50;
  52. const result = await tryDo(queryEvents({
  53. from: new Date(0),
  54. fields: ["level", "message", "label", "timestamp"],
  55. limit: isNumber(params.limit) ? +params.limit : DEFAULT_LIMIT,
  56. includeIds: true,
  57. }));
  58. if (!result.ok) {
  59. return res.json({
  60. ok: false,
  61. error: `Failed to query events. Error: ${result.error}`,
  62. });
  63. }
  64. return res.json({ ok: true, events: zip(result.result) });
  65. };