You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

WebhookProxy.ts 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import WebSocket from 'ws';
  2. /**
  3. * Uses the webhook proxy service to proxy events to the testing clients.
  4. */
  5. export default class WebhookProxy {
  6. private url;
  7. private secret;
  8. private ws: WebSocket | undefined;
  9. private cache = new Map();
  10. private listeners = new Map();
  11. private consumers = new Map();
  12. /**
  13. * Initializes the webhook proxy.
  14. * @param url
  15. * @param secret
  16. */
  17. constructor(url: string, secret: string) {
  18. this.url = url;
  19. this.secret = secret;
  20. }
  21. /**
  22. * Connects.
  23. */
  24. connect() {
  25. this.ws = new WebSocket(this.url, {
  26. headers: {
  27. Authorization: this.secret
  28. }
  29. });
  30. this.ws.on('error', console.error);
  31. this.ws.on('open', function open() {
  32. console.log('WebhookProxy connected');
  33. });
  34. this.ws.on('message', (data: any) => {
  35. const msg = JSON.parse(data.toString());
  36. if (msg.eventType) {
  37. if (this.consumers.has(msg.eventType)) {
  38. this.consumers.get(msg.eventType)(msg);
  39. this.consumers.delete(msg.eventType);
  40. } else {
  41. this.cache.set(msg.eventType, msg);
  42. }
  43. if (this.listeners.has(msg.eventType)) {
  44. this.listeners.get(msg.eventType)(msg);
  45. }
  46. }
  47. });
  48. }
  49. /**
  50. * Adds event consumer. Consumers receive the event single time and we remove them from the list of consumers.
  51. * @param eventType
  52. * @param callback
  53. */
  54. addConsumer(eventType: string, callback: (deventata: any) => void) {
  55. if (this.cache.has(eventType)) {
  56. callback(this.cache.get(eventType));
  57. this.cache.delete(eventType);
  58. return;
  59. }
  60. this.consumers.set(eventType, callback);
  61. }
  62. /**
  63. * Clear any stored event.
  64. */
  65. clearCache() {
  66. this.cache.clear();
  67. }
  68. /**
  69. * Waits for the event to be received.
  70. * @param eventType
  71. * @param timeout
  72. */
  73. async waitForEvent(eventType: string, timeout = 4000): Promise<any> {
  74. // we create the error here so we have a meaningful stack trace
  75. const error = new Error(`Timeout waiting for event:${eventType}`);
  76. return new Promise((resolve, reject) => {
  77. const waiter = setTimeout(() => reject(error), timeout);
  78. this.addConsumer(eventType, event => {
  79. clearTimeout(waiter);
  80. resolve(event);
  81. });
  82. });
  83. }
  84. /**
  85. * Adds a listener for the event type.
  86. * @param eventType
  87. * @param callback
  88. */
  89. addListener(eventType: string, callback: (data: any) => void) {
  90. this.listeners.set(eventType, callback);
  91. }
  92. /**
  93. * Adds a listener for the event type.
  94. * @param eventType
  95. */
  96. removeListener(eventType: string) {
  97. this.listeners.delete(eventType);
  98. }
  99. /**
  100. * Disconnects the webhook proxy.
  101. */
  102. disconnect() {
  103. if (this.ws) {
  104. this.ws.close();
  105. console.log('WebhookProxy disconnected');
  106. this.ws = undefined;
  107. }
  108. }
  109. }