waiter.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.Waiter = void 0;
  6. var _stackTrace = require("../utils/stackTrace");
  7. var _errors = require("./errors");
  8. var _utils = require("../utils");
  9. /**
  10. * Copyright (c) Microsoft Corporation.
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. class Waiter {
  25. constructor(channelOwner, event) {
  26. this._dispose = void 0;
  27. this._failures = [];
  28. this._immediateError = void 0;
  29. this._logs = [];
  30. this._channelOwner = void 0;
  31. this._waitId = void 0;
  32. this._error = void 0;
  33. this._waitId = (0, _utils.createGuid)();
  34. this._channelOwner = channelOwner;
  35. this._channelOwner._channel.waitForEventInfo({
  36. info: {
  37. waitId: this._waitId,
  38. phase: 'before',
  39. event
  40. }
  41. }).catch(() => {});
  42. this._dispose = [() => this._channelOwner._wrapApiCall(async () => {
  43. await this._channelOwner._channel.waitForEventInfo({
  44. info: {
  45. waitId: this._waitId,
  46. phase: 'after',
  47. error: this._error
  48. }
  49. });
  50. }, true).catch(() => {})];
  51. }
  52. static createForEvent(channelOwner, event) {
  53. return new Waiter(channelOwner, event);
  54. }
  55. async waitForEvent(emitter, event, predicate) {
  56. const {
  57. promise,
  58. dispose
  59. } = waitForEvent(emitter, event, predicate);
  60. return await this.waitForPromise(promise, dispose);
  61. }
  62. rejectOnEvent(emitter, event, error, predicate) {
  63. const {
  64. promise,
  65. dispose
  66. } = waitForEvent(emitter, event, predicate);
  67. this._rejectOn(promise.then(() => {
  68. throw typeof error === 'function' ? error() : error;
  69. }), dispose);
  70. }
  71. rejectOnTimeout(timeout, message) {
  72. if (!timeout) return;
  73. const {
  74. promise,
  75. dispose
  76. } = waitForTimeout(timeout);
  77. this._rejectOn(promise.then(() => {
  78. throw new _errors.TimeoutError(message);
  79. }), dispose);
  80. }
  81. rejectImmediately(error) {
  82. this._immediateError = error;
  83. }
  84. dispose() {
  85. for (const dispose of this._dispose) dispose();
  86. }
  87. async waitForPromise(promise, dispose) {
  88. try {
  89. if (this._immediateError) throw this._immediateError;
  90. const result = await Promise.race([promise, ...this._failures]);
  91. if (dispose) dispose();
  92. return result;
  93. } catch (e) {
  94. if (dispose) dispose();
  95. this._error = e.message;
  96. this.dispose();
  97. (0, _stackTrace.rewriteErrorMessage)(e, e.message + formatLogRecording(this._logs));
  98. throw e;
  99. }
  100. }
  101. log(s) {
  102. this._logs.push(s);
  103. this._channelOwner._wrapApiCall(async () => {
  104. await this._channelOwner._channel.waitForEventInfo({
  105. info: {
  106. waitId: this._waitId,
  107. phase: 'log',
  108. message: s
  109. }
  110. }).catch(() => {});
  111. }, true);
  112. }
  113. _rejectOn(promise, dispose) {
  114. this._failures.push(promise);
  115. if (dispose) this._dispose.push(dispose);
  116. }
  117. }
  118. exports.Waiter = Waiter;
  119. function waitForEvent(emitter, event, predicate) {
  120. let listener;
  121. const promise = new Promise((resolve, reject) => {
  122. listener = async eventArg => {
  123. try {
  124. if (predicate && !(await predicate(eventArg))) return;
  125. emitter.removeListener(event, listener);
  126. resolve(eventArg);
  127. } catch (e) {
  128. emitter.removeListener(event, listener);
  129. reject(e);
  130. }
  131. };
  132. emitter.addListener(event, listener);
  133. });
  134. const dispose = () => emitter.removeListener(event, listener);
  135. return {
  136. promise,
  137. dispose
  138. };
  139. }
  140. function waitForTimeout(timeout) {
  141. let timeoutId;
  142. const promise = new Promise(resolve => timeoutId = setTimeout(resolve, timeout));
  143. const dispose = () => clearTimeout(timeoutId);
  144. return {
  145. promise,
  146. dispose
  147. };
  148. }
  149. function formatLogRecording(log) {
  150. if (!log.length) return '';
  151. const header = ` logs `;
  152. const headerLength = 60;
  153. const leftLength = (headerLength - header.length) / 2;
  154. const rightLength = headerLength - header.length - leftLength;
  155. return `\n${'='.repeat(leftLength)}${header}${'='.repeat(rightLength)}\n${log.join('\n')}\n${'='.repeat(headerLength)}`;
  156. }