channelOwner.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. "use strict";
  2. var __defProp = Object.defineProperty;
  3. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  4. var __getOwnPropNames = Object.getOwnPropertyNames;
  5. var __hasOwnProp = Object.prototype.hasOwnProperty;
  6. var __export = (target, all) => {
  7. for (var name in all)
  8. __defProp(target, name, { get: all[name], enumerable: true });
  9. };
  10. var __copyProps = (to, from, except, desc) => {
  11. if (from && typeof from === "object" || typeof from === "function") {
  12. for (let key of __getOwnPropNames(from))
  13. if (!__hasOwnProp.call(to, key) && key !== except)
  14. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  15. }
  16. return to;
  17. };
  18. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  19. var channelOwner_exports = {};
  20. __export(channelOwner_exports, {
  21. ChannelOwner: () => ChannelOwner
  22. });
  23. module.exports = __toCommonJS(channelOwner_exports);
  24. var import_eventEmitter = require("./eventEmitter");
  25. var import_validator = require("../protocol/validator");
  26. var import_protocolMetainfo = require("../utils/isomorphic/protocolMetainfo");
  27. var import_clientStackTrace = require("./clientStackTrace");
  28. var import_stackTrace = require("../utils/isomorphic/stackTrace");
  29. class ChannelOwner extends import_eventEmitter.EventEmitter {
  30. constructor(parent, type, guid, initializer) {
  31. const connection = parent instanceof ChannelOwner ? parent._connection : parent;
  32. super(connection._platform);
  33. this._objects = /* @__PURE__ */ new Map();
  34. this._eventToSubscriptionMapping = /* @__PURE__ */ new Map();
  35. this._wasCollected = false;
  36. this.setMaxListeners(0);
  37. this._connection = connection;
  38. this._type = type;
  39. this._guid = guid;
  40. this._parent = parent instanceof ChannelOwner ? parent : void 0;
  41. this._instrumentation = this._connection._instrumentation;
  42. this._connection._objects.set(guid, this);
  43. if (this._parent) {
  44. this._parent._objects.set(guid, this);
  45. this._logger = this._parent._logger;
  46. }
  47. this._channel = this._createChannel(new import_eventEmitter.EventEmitter(connection._platform));
  48. this._initializer = initializer;
  49. }
  50. _setEventToSubscriptionMapping(mapping) {
  51. this._eventToSubscriptionMapping = mapping;
  52. }
  53. _updateSubscription(event, enabled) {
  54. const protocolEvent = this._eventToSubscriptionMapping.get(String(event));
  55. if (protocolEvent)
  56. this._channel.updateSubscription({ event: protocolEvent, enabled }).catch(() => {
  57. });
  58. }
  59. on(event, listener) {
  60. if (!this.listenerCount(event))
  61. this._updateSubscription(event, true);
  62. super.on(event, listener);
  63. return this;
  64. }
  65. addListener(event, listener) {
  66. if (!this.listenerCount(event))
  67. this._updateSubscription(event, true);
  68. super.addListener(event, listener);
  69. return this;
  70. }
  71. prependListener(event, listener) {
  72. if (!this.listenerCount(event))
  73. this._updateSubscription(event, true);
  74. super.prependListener(event, listener);
  75. return this;
  76. }
  77. off(event, listener) {
  78. super.off(event, listener);
  79. if (!this.listenerCount(event))
  80. this._updateSubscription(event, false);
  81. return this;
  82. }
  83. removeListener(event, listener) {
  84. super.removeListener(event, listener);
  85. if (!this.listenerCount(event))
  86. this._updateSubscription(event, false);
  87. return this;
  88. }
  89. _adopt(child) {
  90. child._parent._objects.delete(child._guid);
  91. this._objects.set(child._guid, child);
  92. child._parent = this;
  93. }
  94. _dispose(reason) {
  95. if (this._parent)
  96. this._parent._objects.delete(this._guid);
  97. this._connection._objects.delete(this._guid);
  98. this._wasCollected = reason === "gc";
  99. for (const object of [...this._objects.values()])
  100. object._dispose(reason);
  101. this._objects.clear();
  102. }
  103. _debugScopeState() {
  104. return {
  105. _guid: this._guid,
  106. objects: Array.from(this._objects.values()).map((o) => o._debugScopeState())
  107. };
  108. }
  109. _validatorToWireContext() {
  110. return {
  111. tChannelImpl: tChannelImplToWire,
  112. binary: this._connection.rawBuffers() ? "buffer" : "toBase64",
  113. isUnderTest: () => this._platform.isUnderTest()
  114. };
  115. }
  116. _createChannel(base) {
  117. const channel = new Proxy(base, {
  118. get: (obj, prop) => {
  119. if (typeof prop === "string") {
  120. const validator = (0, import_validator.maybeFindValidator)(this._type, prop, "Params");
  121. const { internal } = import_protocolMetainfo.methodMetainfo.get(this._type + "." + prop) || {};
  122. if (validator) {
  123. return async (params) => {
  124. return await this._wrapApiCall(async (apiZone) => {
  125. const validatedParams = validator(params, "", this._validatorToWireContext());
  126. if (!apiZone.internal && !apiZone.reported) {
  127. apiZone.reported = true;
  128. this._instrumentation.onApiCallBegin(apiZone, { type: this._type, method: prop, params });
  129. logApiCall(this._platform, this._logger, `=> ${apiZone.apiName} started`);
  130. return await this._connection.sendMessageToServer(this, prop, validatedParams, apiZone);
  131. }
  132. return await this._connection.sendMessageToServer(this, prop, validatedParams, { internal: true });
  133. }, { internal });
  134. };
  135. }
  136. }
  137. return obj[prop];
  138. }
  139. });
  140. channel._object = this;
  141. return channel;
  142. }
  143. async _wrapApiCall(func, options) {
  144. const logger = this._logger;
  145. const existingApiZone = this._platform.zones.current().data();
  146. if (existingApiZone)
  147. return await func(existingApiZone);
  148. const stackTrace = (0, import_clientStackTrace.captureLibraryStackTrace)(this._platform);
  149. const apiZone = { title: options?.title, apiName: stackTrace.apiName, frames: stackTrace.frames, internal: options?.internal ?? false, reported: false, userData: void 0, stepId: void 0 };
  150. try {
  151. const result = await this._platform.zones.current().push(apiZone).run(async () => await func(apiZone));
  152. if (!options?.internal) {
  153. logApiCall(this._platform, logger, `<= ${apiZone.apiName} succeeded`);
  154. this._instrumentation.onApiCallEnd(apiZone);
  155. }
  156. return result;
  157. } catch (e) {
  158. const innerError = (this._platform.showInternalStackFrames() || this._platform.isUnderTest()) && e.stack ? "\n<inner error>\n" + e.stack : "";
  159. if (apiZone.apiName && !apiZone.apiName.includes("<anonymous>"))
  160. e.message = apiZone.apiName + ": " + e.message;
  161. const stackFrames = "\n" + (0, import_stackTrace.stringifyStackFrames)(stackTrace.frames).join("\n") + innerError;
  162. if (stackFrames.trim())
  163. e.stack = e.message + stackFrames;
  164. else
  165. e.stack = "";
  166. if (!options?.internal) {
  167. apiZone.error = e;
  168. logApiCall(this._platform, logger, `<= ${apiZone.apiName} failed`);
  169. this._instrumentation.onApiCallEnd(apiZone);
  170. }
  171. throw e;
  172. }
  173. }
  174. toJSON() {
  175. return {
  176. _type: this._type,
  177. _guid: this._guid
  178. };
  179. }
  180. }
  181. function logApiCall(platform, logger, message) {
  182. if (logger && logger.isEnabled("api", "info"))
  183. logger.log("api", "info", message, [], { color: "cyan" });
  184. platform.log("api", message);
  185. }
  186. function tChannelImplToWire(names, arg, path, context) {
  187. if (arg._object instanceof ChannelOwner && (names === "*" || names.includes(arg._object._type)))
  188. return { guid: arg._object._guid };
  189. throw new import_validator.ValidationError(`${path}: expected channel ${names.toString()}`);
  190. }
  191. // Annotate the CommonJS export names for ESM import in node:
  192. 0 && (module.exports = {
  193. ChannelOwner
  194. });