diff --git a/packages/dev-middleware/src/__tests__/InspectorDebuggerUtils.js b/packages/dev-middleware/src/__tests__/InspectorDebuggerUtils.js index 79c9a2ffabd..98fbe08d0b1 100644 --- a/packages/dev-middleware/src/__tests__/InspectorDebuggerUtils.js +++ b/packages/dev-middleware/src/__tests__/InspectorDebuggerUtils.js @@ -20,15 +20,15 @@ import until from 'wait-for-expect'; import WebSocket from 'ws'; export class DebuggerAgent { - _ws: ?WebSocket; - _readyPromise: Promise; + #ws: ?WebSocket; + #readyPromise: Promise; constructor(url: string, signal?: AbortSignal) { const ws = new WebSocket(url, { // The mock server uses a self-signed certificate. rejectUnauthorized: false, }); - this._ws = ws; + this.#ws = ws; ws.on('message', data => { this.__handle(JSON.parse(data.toString())); }); @@ -37,7 +37,7 @@ export class DebuggerAgent { this.close(); }); } - this._readyPromise = new Promise((resolve, reject) => { + this.#readyPromise = new Promise((resolve, reject) => { ws.once('open', () => { resolve(); }); @@ -50,29 +50,29 @@ export class DebuggerAgent { __handle(message: JSONSerializable): void {} send(message: JSONSerializable) { - if (!this._ws) { + if (!this.#ws) { return; } - this._ws.send(JSON.stringify(message)); + this.#ws.send(JSON.stringify(message)); } ready(): Promise { - return this._readyPromise; + return this.#readyPromise; } close() { - if (!this._ws) { + if (!this.#ws) { return; } try { - this._ws.terminate(); + this.#ws.terminate(); } catch {} - this._ws = null; + this.#ws = null; } // $FlowIgnore[unsafe-getters-setters] get socket(): WebSocket { - return nullthrows(this._ws); + return nullthrows(this.#ws); } } diff --git a/packages/dev-middleware/src/__tests__/InspectorDeviceUtils.js b/packages/dev-middleware/src/__tests__/InspectorDeviceUtils.js index a1170fbfaea..0ccf1f39712 100644 --- a/packages/dev-middleware/src/__tests__/InspectorDeviceUtils.js +++ b/packages/dev-middleware/src/__tests__/InspectorDeviceUtils.js @@ -23,15 +23,15 @@ import type { import WebSocket from 'ws'; export class DeviceAgent { - _ws: ?WebSocket; - _readyPromise: Promise; + #ws: ?WebSocket; + #readyPromise: Promise; constructor(url: string, signal?: AbortSignal) { const ws = new WebSocket(url, { // The mock server uses a self-signed certificate. rejectUnauthorized: false, }); - this._ws = ws; + this.#ws = ws; ws.on('message', data => { this.__handle(JSON.parse(data.toString())); }); @@ -40,7 +40,7 @@ export class DeviceAgent { this.close(); }); } - this._readyPromise = new Promise((resolve, reject) => { + this.#readyPromise = new Promise((resolve, reject) => { ws.once('open', () => { resolve(); }); @@ -53,24 +53,24 @@ export class DeviceAgent { __handle(message: MessageToDevice): void {} send(message: MessageFromDevice) { - if (!this._ws) { + if (!this.#ws) { return; } - this._ws.send(JSON.stringify(message)); + this.#ws.send(JSON.stringify(message)); } ready(): Promise { - return this._readyPromise; + return this.#readyPromise; } close() { - if (!this._ws) { + if (!this.#ws) { return; } try { - this._ws.terminate(); + this.#ws.terminate(); } catch {} - this._ws = null; + this.#ws = null; } sendWrappedEvent(pageId: string, event: JSONSerializable) { @@ -110,7 +110,7 @@ export class DeviceMock extends DeviceAgent { break; case 'getPages': const result = this.getPages(message); - this._sendPayloadIfNonNull('getPages', result); + this.#sendPayloadIfNonNull('getPages', result); break; case 'wrappedEvent': this.wrappedEvent(message); @@ -125,7 +125,7 @@ export class DeviceMock extends DeviceAgent { } } - _sendPayloadIfNonNull( + #sendPayloadIfNonNull( event: Event, maybePayload: | MessageFromDevice['payload'] diff --git a/packages/dev-middleware/src/inspector-proxy/Device.js b/packages/dev-middleware/src/inspector-proxy/Device.js index d6e1d8bd3f8..3a48cf939c4 100644 --- a/packages/dev-middleware/src/inspector-proxy/Device.js +++ b/packages/dev-middleware/src/inspector-proxy/Device.js @@ -34,7 +34,7 @@ const PAGES_POLLING_INTERVAL = 1000; // Android's stock emulator and other emulators such as genymotion use a standard localhost alias. const EMULATOR_LOCALHOST_ADDRESSES: Array = ['10.0.2.2', '10.0.3.2']; -// Prefix for script URLs that are alphanumeric IDs. See comment in _processMessageFromDevice method for +// Prefix for script URLs that are alphanumeric IDs. See comment in #processMessageFromDevice method for // more details. const FILE_PREFIX = 'file://'; @@ -57,43 +57,43 @@ const REACT_NATIVE_RELOADABLE_PAGE_ID = '-1'; */ export default class Device { // ID of the device. - _id: string; + #id: string; // Name of the device. - _name: string; + #name: string; // Package name of the app. - _app: string; + #app: string; // Stores socket connection between Inspector Proxy and device. - _deviceSocket: WS; + #deviceSocket: WS; // Stores last list of device's pages. - _pages: $ReadOnlyArray; + #pages: $ReadOnlyArray; // Stores information about currently connected debugger (if any). - _debuggerConnection: ?DebuggerInfo = null; + #debuggerConnection: ?DebuggerInfo = null; // Last known Page ID of the React Native page. // This is used by debugger connections that don't have PageID specified // (and will interact with the latest React Native page). - _lastConnectedReactNativePage: ?Page = null; + #lastConnectedReactNativePage: ?Page = null; // Whether we are in the middle of a reload in the REACT_NATIVE_RELOADABLE_PAGE. - _isReloading: boolean = false; + #isReloading: boolean = false; // The previous "GetPages" message, for deduplication in debug logs. - _lastGetPagesMessage: string = ''; + #lastGetPagesMessage: string = ''; // Mapping built from scriptParsed events and used to fetch file content in `Debugger.getScriptSource`. - _scriptIdToSourcePathMapping: Map = new Map(); + #scriptIdToSourcePathMapping: Map = new Map(); // Root of the project used for relative to absolute source path conversion. - _projectRoot: string; + #projectRoot: string; - _deviceEventReporter: ?DeviceEventReporter; + #deviceEventReporter: ?DeviceEventReporter; - _pagesPollingIntervalId: ReturnType; + #pagesPollingIntervalId: ReturnType; constructor( id: string, @@ -103,13 +103,13 @@ export default class Device { projectRoot: string, eventReporter: ?EventReporter, ) { - this._id = id; - this._name = name; - this._app = app; - this._pages = []; - this._deviceSocket = socket; - this._projectRoot = projectRoot; - this._deviceEventReporter = eventReporter + this.#id = id; + this.#name = name; + this.#app = app; + this.#pages = []; + this.#deviceSocket = socket; + this.#projectRoot = projectRoot; + this.#deviceEventReporter = eventReporter ? new DeviceEventReporter(eventReporter, { deviceId: id, deviceName: name, @@ -118,57 +118,57 @@ export default class Device { : null; // $FlowFixMe[incompatible-call] - this._deviceSocket.on('message', (message: string) => { + this.#deviceSocket.on('message', (message: string) => { const parsedMessage = JSON.parse(message); if (parsedMessage.event === 'getPages') { // There's a 'getPages' message every second, so only show them if they change - if (message !== this._lastGetPagesMessage) { + if (message !== this.#lastGetPagesMessage) { debug( '(Debugger) (Proxy) <- (Device), getPages ping has changed: ' + message, ); - this._lastGetPagesMessage = message; + this.#lastGetPagesMessage = message; } } else { debug('(Debugger) (Proxy) <- (Device): ' + message); } - this._handleMessageFromDevice(parsedMessage); + this.#handleMessageFromDevice(parsedMessage); }); // Sends 'getPages' request to device every PAGES_POLLING_INTERVAL milliseconds. - this._pagesPollingIntervalId = setInterval( - () => this._sendMessageToDevice({event: 'getPages'}), + this.#pagesPollingIntervalId = setInterval( + () => this.#sendMessageToDevice({event: 'getPages'}), PAGES_POLLING_INTERVAL, ); - this._deviceSocket.on('close', () => { - this._deviceEventReporter?.logDisconnection('device'); + this.#deviceSocket.on('close', () => { + this.#deviceEventReporter?.logDisconnection('device'); // Device disconnected - close debugger connection. - if (this._debuggerConnection) { - this._debuggerConnection.socket.close(); - this._debuggerConnection = null; + if (this.#debuggerConnection) { + this.#debuggerConnection.socket.close(); + this.#debuggerConnection = null; } - clearInterval(this._pagesPollingIntervalId); + clearInterval(this.#pagesPollingIntervalId); }); } getName(): string { - return this._name; + return this.#name; } getApp(): string { - return this._app; + return this.#app; } getPagesList(): $ReadOnlyArray { - if (this._lastConnectedReactNativePage) { + if (this.#lastConnectedReactNativePage) { const reactNativeReloadablePage = { id: REACT_NATIVE_RELOADABLE_PAGE_ID, title: 'React Native Experimental (Improved Chrome Reloads)', vm: "don't use", - app: this._app, + app: this.#app, }; - return this._pages.concat(reactNativeReloadablePage); + return this.#pages.concat(reactNativeReloadablePage); } else { - return this._pages; + return this.#pages; } } @@ -184,17 +184,17 @@ export default class Device { }>, ) { // Clear any commands we were waiting on. - this._deviceEventReporter?.logDisconnection('debugger'); + this.#deviceEventReporter?.logDisconnection('debugger'); - this._deviceEventReporter?.logConnection('debugger', { + this.#deviceEventReporter?.logConnection('debugger', { pageId, frontendUserAgent: metadata.userAgent, }); // Disconnect current debugger if we already have debugger connected. - if (this._debuggerConnection) { - this._debuggerConnection.socket.close(); - this._debuggerConnection = null; + if (this.#debuggerConnection) { + this.#debuggerConnection.socket.close(); + this.#debuggerConnection = null; } const debuggerInfo = { @@ -203,14 +203,14 @@ export default class Device { pageId, userAgent: metadata.userAgent, }; - this._debuggerConnection = debuggerInfo; + this.#debuggerConnection = debuggerInfo; - debug(`Got new debugger connection for page ${pageId} of ${this._name}`); + debug(`Got new debugger connection for page ${pageId} of ${this.#name}`); - this._sendMessageToDevice({ + this.#sendMessageToDevice({ event: 'connect', payload: { - pageId: this._mapToDevicePageId(pageId), + pageId: this.#mapToDevicePageId(pageId), }, }); @@ -218,36 +218,36 @@ export default class Device { socket.on('message', (message: string) => { debug('(Debugger) -> (Proxy) (Device): ' + message); const debuggerRequest = JSON.parse(message); - this._deviceEventReporter?.logRequest(debuggerRequest, 'debugger', { - pageId: this._debuggerConnection?.pageId ?? null, + this.#deviceEventReporter?.logRequest(debuggerRequest, 'debugger', { + pageId: this.#debuggerConnection?.pageId ?? null, frontendUserAgent: metadata.userAgent, }); - const processedReq = this._interceptMessageFromDebugger( + const processedReq = this.#interceptMessageFromDebugger( debuggerRequest, debuggerInfo, socket, ); if (processedReq) { - this._sendMessageToDevice({ + this.#sendMessageToDevice({ event: 'wrappedEvent', payload: { - pageId: this._mapToDevicePageId(pageId), + pageId: this.#mapToDevicePageId(pageId), wrappedEvent: JSON.stringify(processedReq), }, }); } }); socket.on('close', () => { - debug(`Debugger for page ${pageId} and ${this._name} disconnected.`); - this._deviceEventReporter?.logDisconnection('debugger'); - this._sendMessageToDevice({ + debug(`Debugger for page ${pageId} and ${this.#name} disconnected.`); + this.#deviceEventReporter?.logDisconnection('debugger'); + this.#sendMessageToDevice({ event: 'disconnect', payload: { - pageId: this._mapToDevicePageId(pageId), + pageId: this.#mapToDevicePageId(pageId), }, }); - this._debuggerConnection = null; + this.#debuggerConnection = null; }); // $FlowFixMe[method-unbinding] @@ -270,19 +270,19 @@ export default class Device { */ handleDuplicateDeviceConnection(newDevice: Device) { if ( - this._app !== newDevice.getApp() || - this._name !== newDevice.getName() + this.#app !== newDevice.getApp() || + this.#name !== newDevice.getName() ) { - this._deviceSocket.close(); - this._debuggerConnection?.socket.close(); + this.#deviceSocket.close(); + this.#debuggerConnection?.socket.close(); } - const oldDebugger = this._debuggerConnection; - this._debuggerConnection = null; + const oldDebugger = this.#debuggerConnection; + this.#debuggerConnection = null; if (oldDebugger) { oldDebugger.socket.removeAllListeners(); - this._deviceSocket.close(); + this.#deviceSocket.close(); newDevice.handleDebuggerConnection( oldDebugger.socket, oldDebugger.pageId, @@ -294,25 +294,25 @@ export default class Device { } // Handles messages received from device: - // 1. For getPages responses updates local _pages list. + // 1. For getPages responses updates local #pages list. // 2. All other messages are forwarded to debugger as wrappedEvent. // // In the future more logic will be added to this method for modifying // some of the messages (like updating messages with source maps and file // locations). - _handleMessageFromDevice(message: MessageFromDevice) { + #handleMessageFromDevice(message: MessageFromDevice) { if (message.event === 'getPages') { - this._pages = message.payload; + this.#pages = message.payload; // Check if device have new React Native page. // There is usually no more than 2-3 pages per device so this operation // is not expensive. // TODO(hypuk): It is better for VM to send update event when new page is // created instead of manually checking this on every getPages result. - for (let i = 0; i < this._pages.length; ++i) { - if (this._pages[i].title.indexOf('React') >= 0) { - if (this._pages[i].id !== this._lastConnectedReactNativePage?.id) { - this._newReactNativePage(this._pages[i]); + for (let i = 0; i < this.#pages.length; ++i) { + if (this.#pages[i].title.indexOf('React') >= 0) { + if (this.#pages[i].id !== this.#lastConnectedReactNativePage?.id) { + this.#newReactNativePage(this.#pages[i]); break; } } @@ -321,27 +321,27 @@ export default class Device { // Device sends disconnect events only when page is reloaded or // if debugger socket was disconnected. const pageId = message.payload.pageId; - const debuggerSocket = this._debuggerConnection - ? this._debuggerConnection.socket + const debuggerSocket = this.#debuggerConnection + ? this.#debuggerConnection.socket : null; if (debuggerSocket && debuggerSocket.readyState === WS.OPEN) { if ( - this._debuggerConnection != null && - this._debuggerConnection.pageId !== REACT_NATIVE_RELOADABLE_PAGE_ID + this.#debuggerConnection != null && + this.#debuggerConnection.pageId !== REACT_NATIVE_RELOADABLE_PAGE_ID ) { debug(`Page ${pageId} is reloading.`); debuggerSocket.send(JSON.stringify({method: 'reload'})); } } } else if (message.event === 'wrappedEvent') { - if (this._debuggerConnection == null) { + if (this.#debuggerConnection == null) { return; } // FIXME: Is it possible that we received message for pageID that does not // correspond to current debugger connection? - const debuggerSocket = this._debuggerConnection.socket; + const debuggerSocket = this.#debuggerConnection.socket; if (debuggerSocket == null || debuggerSocket.readyState !== WS.OPEN) { // TODO(hypuk): Send error back to device? return; @@ -349,18 +349,18 @@ export default class Device { const parsedPayload = JSON.parse(message.payload.wrappedEvent); if ('id' in parsedPayload) { - this._deviceEventReporter?.logResponse(parsedPayload, 'device', { - pageId: this._debuggerConnection?.pageId ?? null, - frontendUserAgent: this._debuggerConnection?.userAgent ?? null, + this.#deviceEventReporter?.logResponse(parsedPayload, 'device', { + pageId: this.#debuggerConnection?.pageId ?? null, + frontendUserAgent: this.#debuggerConnection?.userAgent ?? null, }); } - if (this._debuggerConnection) { + if (this.#debuggerConnection) { // Wrapping just to make flow happy :) // $FlowFixMe[unused-promise] - this._processMessageFromDevice( + this.#processMessageFromDevice( parsedPayload, - this._debuggerConnection, + this.#debuggerConnection, ).then(() => { const messageToSend = JSON.stringify(parsedPayload); debuggerSocket.send(messageToSend); @@ -370,31 +370,31 @@ export default class Device { } // Sends single message to device. - _sendMessageToDevice(message: MessageToDevice) { + #sendMessageToDevice(message: MessageToDevice) { try { if (message.event !== 'getPages') { debug('(Debugger) (Proxy) -> (Device): ' + JSON.stringify(message)); } - this._deviceSocket.send(JSON.stringify(message)); + this.#deviceSocket.send(JSON.stringify(message)); } catch (error) {} } // We received new React Native Page ID. - _newReactNativePage(page: Page) { + #newReactNativePage(page: Page) { debug(`React Native page updated to ${page.id}`); if ( - this._debuggerConnection == null || - this._debuggerConnection.pageId !== REACT_NATIVE_RELOADABLE_PAGE_ID + this.#debuggerConnection == null || + this.#debuggerConnection.pageId !== REACT_NATIVE_RELOADABLE_PAGE_ID ) { // We can just remember new page ID without any further actions if no // debugger is currently attached or attached debugger is not // "Reloadable React Native" connection. - this._lastConnectedReactNativePage = page; + this.#lastConnectedReactNativePage = page; return; } - const oldPageId = this._lastConnectedReactNativePage?.id; - this._lastConnectedReactNativePage = page; - this._isReloading = true; + const oldPageId = this.#lastConnectedReactNativePage?.id; + this.#lastConnectedReactNativePage = page; + this.#isReloading = true; // We already had a debugger connected to React Native page and a // new one appeared - in this case we need to emulate execution context @@ -402,7 +402,7 @@ export default class Device { // page. if (oldPageId != null) { - this._sendMessageToDevice({ + this.#sendMessageToDevice({ event: 'disconnect', payload: { pageId: oldPageId, @@ -410,7 +410,7 @@ export default class Device { }); } - this._sendMessageToDevice({ + this.#sendMessageToDevice({ event: 'connect', payload: { pageId: page.id, @@ -423,14 +423,14 @@ export default class Device { ]; for (const message of toSend) { - this._deviceEventReporter?.logRequest(message, 'proxy', { - pageId: this._debuggerConnection?.pageId ?? null, - frontendUserAgent: this._debuggerConnection?.userAgent ?? null, + this.#deviceEventReporter?.logRequest(message, 'proxy', { + pageId: this.#debuggerConnection?.pageId ?? null, + frontendUserAgent: this.#debuggerConnection?.userAgent ?? null, }); - this._sendMessageToDevice({ + this.#sendMessageToDevice({ event: 'wrappedEvent', payload: { - pageId: this._mapToDevicePageId(page.id), + pageId: this.#mapToDevicePageId(page.id), wrappedEvent: JSON.stringify(message), }, }); @@ -438,7 +438,7 @@ export default class Device { } // Allows to make changes in incoming message from device. - async _processMessageFromDevice( + async #processMessageFromDevice( payload: {method: string, params: {sourceMapURL: string, url: string}}, debuggerInfo: DebuggerInfo, ) { @@ -457,7 +457,7 @@ export default class Device { } } - const sourceMapURL = this._tryParseHTTPURL(params.sourceMapURL); + const sourceMapURL = this.#tryParseHTTPURL(params.sourceMapURL); if (sourceMapURL) { // Some debug clients do not support fetching HTTP URLs. If the // message headed to the debug client identifies the source map with @@ -465,12 +465,12 @@ export default class Device { // Data URL (which is more widely supported) before passing the // message to the debug client. try { - const sourceMap = await this._fetchText(sourceMapURL); + const sourceMap = await this.#fetchText(sourceMapURL); payload.params.sourceMapURL = 'data:application/json;charset=utf-8;base64,' + new Buffer(sourceMap).toString('base64'); } catch (exception) { - this._sendErrorToDebugger( + this.#sendErrorToDebugger( `Failed to fetch source map ${params.sourceMapURL}: ${exception.message}`, ); } @@ -496,14 +496,14 @@ export default class Device { // $FlowFixMe[prop-missing] if (params.scriptId != null) { - this._scriptIdToSourcePathMapping.set(params.scriptId, params.url); + this.#scriptIdToSourcePathMapping.set(params.scriptId, params.url); } } } if ( payload.method === 'Runtime.executionContextCreated' && - this._isReloading + this.#isReloading ) { // The new context is ready. First notify Chrome that we've reloaded so // it'll resend its breakpoints. If we do this earlier, we may not be @@ -520,40 +520,40 @@ export default class Device { // This is not an issue in VSCode/Nuclide where the IDE knows to resume // at its convenience. const resumeMessage = {method: 'Debugger.resume', id: 0}; - this._deviceEventReporter?.logRequest(resumeMessage, 'proxy', { - pageId: this._debuggerConnection?.pageId ?? null, - frontendUserAgent: this._debuggerConnection?.userAgent ?? null, + this.#deviceEventReporter?.logRequest(resumeMessage, 'proxy', { + pageId: this.#debuggerConnection?.pageId ?? null, + frontendUserAgent: this.#debuggerConnection?.userAgent ?? null, }); - this._sendMessageToDevice({ + this.#sendMessageToDevice({ event: 'wrappedEvent', payload: { - pageId: this._mapToDevicePageId(debuggerInfo.pageId), + pageId: this.#mapToDevicePageId(debuggerInfo.pageId), wrappedEvent: JSON.stringify(resumeMessage), }, }); - this._isReloading = false; + this.#isReloading = false; } } // Allows to make changes in incoming messages from debugger. Returns a boolean // indicating whether the message has been handled locally (i.e. does not need // to be forwarded to the target). - _interceptMessageFromDebugger( + #interceptMessageFromDebugger( req: DebuggerRequest, debuggerInfo: DebuggerInfo, socket: WS, ): ?DebuggerRequest { if (req.method === 'Debugger.setBreakpointByUrl') { - return this._processDebuggerSetBreakpointByUrl(req, debuggerInfo); + return this.#processDebuggerSetBreakpointByUrl(req, debuggerInfo); } else if (req.method === 'Debugger.getScriptSource') { - this._processDebuggerGetScriptSource(req, socket); + this.#processDebuggerGetScriptSource(req, socket); return null; } return req; } - _processDebuggerSetBreakpointByUrl( + #processDebuggerSetBreakpointByUrl( req: SetBreakpointByUrlRequest, debuggerInfo: DebuggerInfo, ): SetBreakpointByUrlRequest { @@ -571,7 +571,7 @@ export default class Device { processedReq.params.url.startsWith(FILE_PREFIX) && debuggerInfo.prependedFilePrefix ) { - // Remove fake URL prefix if we modified URL in _processMessageFromDevice. + // Remove fake URL prefix if we modified URL in #processMessageFromDevice. // $FlowFixMe[incompatible-use] processedReq.params.url = processedReq.params.url.slice( FILE_PREFIX.length, @@ -590,14 +590,14 @@ export default class Device { return req; } - _processDebuggerGetScriptSource(req: GetScriptSourceRequest, socket: WS) { + #processDebuggerGetScriptSource(req: GetScriptSourceRequest, socket: WS) { const sendSuccessResponse = (scriptSource: string) => { const result: GetScriptSourceResponse = {scriptSource}; const response = {id: req.id, result}; socket.send(JSON.stringify(response)); - this._deviceEventReporter?.logResponse(response, 'proxy', { - pageId: this._debuggerConnection?.pageId ?? null, - frontendUserAgent: this._debuggerConnection?.userAgent ?? null, + this.#deviceEventReporter?.logResponse(response, 'proxy', { + pageId: this.#debuggerConnection?.pageId ?? null, + frontendUserAgent: this.#debuggerConnection?.userAgent ?? null, }); }; const sendErrorResponse = (error: string) => { @@ -607,20 +607,20 @@ export default class Device { socket.send(JSON.stringify(response)); // Send to the console as well, so the user can see it - this._sendErrorToDebugger(error); - this._deviceEventReporter?.logResponse(response, 'proxy', { - pageId: this._debuggerConnection?.pageId ?? null, - frontendUserAgent: this._debuggerConnection?.userAgent ?? null, + this.#sendErrorToDebugger(error); + this.#deviceEventReporter?.logResponse(response, 'proxy', { + pageId: this.#debuggerConnection?.pageId ?? null, + frontendUserAgent: this.#debuggerConnection?.userAgent ?? null, }); }; - const pathToSource = this._scriptIdToSourcePathMapping.get( + const pathToSource = this.#scriptIdToSourcePathMapping.get( req.params.scriptId, ); if (pathToSource != null) { - const httpURL = this._tryParseHTTPURL(pathToSource); + const httpURL = this.#tryParseHTTPURL(pathToSource); if (httpURL) { - this._fetchText(httpURL).then( + this.#fetchText(httpURL).then( text => sendSuccessResponse(text), err => sendErrorResponse( @@ -631,7 +631,7 @@ export default class Device { let file; try { file = fs.readFileSync( - path.resolve(this._projectRoot, pathToSource), + path.resolve(this.#projectRoot, pathToSource), 'utf8', ); } catch (err) { @@ -646,18 +646,18 @@ export default class Device { } } - _mapToDevicePageId(pageId: string): string { + #mapToDevicePageId(pageId: string): string { if ( pageId === REACT_NATIVE_RELOADABLE_PAGE_ID && - this._lastConnectedReactNativePage != null + this.#lastConnectedReactNativePage != null ) { - return this._lastConnectedReactNativePage.id; + return this.#lastConnectedReactNativePage.id; } else { return pageId; } } - _tryParseHTTPURL(url: string): ?URL { + #tryParseHTTPURL(url: string): ?URL { let parsedURL: ?URL; try { parsedURL = new URL(url); @@ -673,7 +673,7 @@ export default class Device { // Fetch text, raising an exception if the text could not be fetched, // or is too large. - async _fetchText(url: URL): Promise { + async #fetchText(url: URL): Promise { if (!['localhost', '127.0.0.1'].includes(url.hostname)) { throw new Error('remote fetches not permitted'); } @@ -692,8 +692,8 @@ export default class Device { return text; } - _sendErrorToDebugger(message: string) { - const debuggerSocket = this._debuggerConnection?.socket; + #sendErrorToDebugger(message: string) { + const debuggerSocket = this.#debuggerConnection?.socket; if (debuggerSocket && debuggerSocket.readyState === WS.OPEN) { debuggerSocket.send( JSON.stringify({ diff --git a/packages/dev-middleware/src/inspector-proxy/DeviceEventReporter.js b/packages/dev-middleware/src/inspector-proxy/DeviceEventReporter.js index af574d15212..fb5fd9aac9c 100644 --- a/packages/dev-middleware/src/inspector-proxy/DeviceEventReporter.js +++ b/packages/dev-middleware/src/inspector-proxy/DeviceEventReporter.js @@ -31,9 +31,9 @@ type RequestMetadata = $ReadOnly<{ }>; class DeviceEventReporter { - _eventReporter: EventReporter; + #eventReporter: EventReporter; - _pendingCommands: TTLCache = new TTLCache({ + #pendingCommands: TTLCache = new TTLCache({ ttl: 10000, dispose: ( command: PendingCommand, @@ -44,15 +44,15 @@ class DeviceEventReporter { // TODO: Report clobbering ('set') using a dedicated error code return; } - this._logExpiredCommand(command); + this.#logExpiredCommand(command); }, }); - _metadata: DeviceMetadata; + #metadata: DeviceMetadata; constructor(eventReporter: EventReporter, metadata: DeviceMetadata) { - this._eventReporter = eventReporter; - this._metadata = metadata; + this.#eventReporter = eventReporter; + this.#metadata = metadata; } logRequest( @@ -60,7 +60,7 @@ class DeviceEventReporter { origin: 'debugger' | 'proxy', metadata: RequestMetadata, ): void { - this._pendingCommands.set(req.id, { + this.#pendingCommands.set(req.id, { method: req.method, requestOrigin: origin, requestTime: Date.now(), @@ -80,9 +80,9 @@ class DeviceEventReporter { frontendUserAgent: string | null, }>, ): void { - const pendingCommand = this._pendingCommands.get(res.id); + const pendingCommand = this.#pendingCommands.get(res.id); if (!pendingCommand) { - this._eventReporter.logEvent({ + this.#eventReporter.logEvent({ type: 'debugger_command', protocol: 'CDP', requestOrigin: null, @@ -91,22 +91,22 @@ class DeviceEventReporter { errorCode: 'UNMATCHED_REQUEST_ID', responseOrigin: 'proxy', timeSinceStart: null, - appId: this._metadata.appId, - deviceId: this._metadata.deviceId, - deviceName: this._metadata.deviceName, + appId: this.#metadata.appId, + deviceId: this.#metadata.deviceId, + deviceName: this.#metadata.deviceName, pageId: metadata.pageId, frontendUserAgent: metadata.frontendUserAgent, }); return; } const timeSinceStart = Date.now() - pendingCommand.requestTime; - this._pendingCommands.delete(res.id); + this.#pendingCommands.delete(res.id); if (res.error) { let {message} = res.error; if ('data' in res.error) { message += ` (${String(res.error.data)})`; } - this._eventReporter.logEvent({ + this.#eventReporter.logEvent({ type: 'debugger_command', requestOrigin: pendingCommand.requestOrigin, method: pendingCommand.method, @@ -116,15 +116,15 @@ class DeviceEventReporter { errorDetails: message, responseOrigin: origin, timeSinceStart, - appId: this._metadata.appId, - deviceId: this._metadata.deviceId, - deviceName: this._metadata.deviceName, + appId: this.#metadata.appId, + deviceId: this.#metadata.deviceId, + deviceName: this.#metadata.deviceName, pageId: pendingCommand.metadata.pageId, frontendUserAgent: pendingCommand.metadata.frontendUserAgent, }); return; } - this._eventReporter.logEvent({ + this.#eventReporter.logEvent({ type: 'debugger_command', protocol: 'CDP', requestOrigin: pendingCommand.requestOrigin, @@ -132,9 +132,9 @@ class DeviceEventReporter { status: 'success', responseOrigin: origin, timeSinceStart, - appId: this._metadata.appId, - deviceId: this._metadata.deviceId, - deviceName: this._metadata.deviceName, + appId: this.#metadata.appId, + deviceId: this.#metadata.deviceId, + deviceName: this.#metadata.deviceName, pageId: pendingCommand.metadata.pageId, frontendUserAgent: pendingCommand.metadata.frontendUserAgent, }); @@ -147,19 +147,19 @@ class DeviceEventReporter { frontendUserAgent: string | null, }>, ) { - this._eventReporter.logEvent({ + this.#eventReporter.logEvent({ type: 'connect_debugger_frontend', status: 'success', - appId: this._metadata.appId, - deviceName: this._metadata.deviceName, - deviceId: this._metadata.deviceId, + appId: this.#metadata.appId, + deviceName: this.#metadata.deviceName, + deviceId: this.#metadata.deviceId, pageId: metadata.pageId, frontendUserAgent: metadata.frontendUserAgent, }); } logDisconnection(disconnectedEntity: 'device' | 'debugger') { - const eventReporter = this._eventReporter; + const eventReporter = this.#eventReporter; if (!eventReporter) { return; } @@ -167,8 +167,8 @@ class DeviceEventReporter { disconnectedEntity === 'device' ? 'DEVICE_DISCONNECTED' : 'DEBUGGER_DISCONNECTED'; - for (const pendingCommand of this._pendingCommands.values()) { - this._eventReporter.logEvent({ + for (const pendingCommand of this.#pendingCommands.values()) { + this.#eventReporter.logEvent({ type: 'debugger_command', protocol: 'CDP', requestOrigin: pendingCommand.requestOrigin, @@ -177,18 +177,18 @@ class DeviceEventReporter { errorCode, responseOrigin: 'proxy', timeSinceStart: Date.now() - pendingCommand.requestTime, - appId: this._metadata.appId, - deviceId: this._metadata.deviceId, - deviceName: this._metadata.deviceName, + appId: this.#metadata.appId, + deviceId: this.#metadata.deviceId, + deviceName: this.#metadata.deviceName, pageId: pendingCommand.metadata.pageId, frontendUserAgent: pendingCommand.metadata.frontendUserAgent, }); } - this._pendingCommands.clear(); + this.#pendingCommands.clear(); } - _logExpiredCommand(pendingCommand: PendingCommand): void { - this._eventReporter.logEvent({ + #logExpiredCommand(pendingCommand: PendingCommand): void { + this.#eventReporter.logEvent({ type: 'debugger_command', protocol: 'CDP', requestOrigin: pendingCommand.requestOrigin, @@ -197,9 +197,9 @@ class DeviceEventReporter { errorCode: 'TIMED_OUT', responseOrigin: 'proxy', timeSinceStart: Date.now() - pendingCommand.requestTime, - appId: this._metadata.appId, - deviceId: this._metadata.deviceId, - deviceName: this._metadata.deviceName, + appId: this.#metadata.appId, + deviceId: this.#metadata.deviceId, + deviceName: this.#metadata.deviceName, pageId: pendingCommand.metadata.pageId, frontendUserAgent: pendingCommand.metadata.frontendUserAgent, }); diff --git a/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js b/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js index ead03c540c3..3cab2c70158 100644 --- a/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js +++ b/packages/dev-middleware/src/inspector-proxy/InspectorProxy.js @@ -42,20 +42,20 @@ export interface InspectorProxyQueries { */ export default class InspectorProxy implements InspectorProxyQueries { // Root of the project used for relative to absolute source path conversion. - _projectRoot: string; + #projectRoot: string; /** The base URL to the dev server from the developer machine. */ - _serverBaseUrl: string; + #serverBaseUrl: string; // Maps device ID to Device instance. - _devices: Map; + #devices: Map; // Internal counter for device IDs -- just gets incremented for each new device. - _deviceCounter: number = 0; + #deviceCounter: number = 0; - _eventReporter: ?EventReporter; + #eventReporter: ?EventReporter; - _experiments: Experiments; + #experiments: Experiments; constructor( projectRoot: string, @@ -63,22 +63,22 @@ export default class InspectorProxy implements InspectorProxyQueries { eventReporter: ?EventReporter, experiments: Experiments, ) { - this._projectRoot = projectRoot; - this._serverBaseUrl = serverBaseUrl; - this._devices = new Map(); - this._eventReporter = eventReporter; - this._experiments = experiments; + this.#projectRoot = projectRoot; + this.#serverBaseUrl = serverBaseUrl; + this.#devices = new Map(); + this.#eventReporter = eventReporter; + this.#experiments = experiments; } getPageDescriptions(): Array { // Build list of pages from all devices. let result: Array = []; - Array.from(this._devices.entries()).forEach(([deviceId, device]) => { + Array.from(this.#devices.entries()).forEach(([deviceId, device]) => { result = result.concat( device .getPagesList() .map((page: Page) => - this._buildPageDescription(deviceId, device, page), + this.#buildPageDescription(deviceId, device, page), ), ); }); @@ -99,9 +99,9 @@ export default class InspectorProxy implements InspectorProxyQueries { pathname === PAGES_LIST_JSON_URL || pathname === PAGES_LIST_JSON_URL_2 ) { - this._sendJsonResponse(response, this.getPageDescriptions()); + this.#sendJsonResponse(response, this.getPageDescriptions()); } else if (pathname === PAGES_LIST_JSON_VERSION_URL) { - this._sendJsonResponse(response, { + this.#sendJsonResponse(response, { Browser: 'Mobile JavaScript', 'Protocol-Version': '1.1', }); @@ -114,19 +114,19 @@ export default class InspectorProxy implements InspectorProxyQueries { [path: string]: WS.Server, } { return { - [WS_DEVICE_URL]: this._createDeviceConnectionWSServer(), - [WS_DEBUGGER_URL]: this._createDebuggerConnectionWSServer(), + [WS_DEVICE_URL]: this.#createDeviceConnectionWSServer(), + [WS_DEBUGGER_URL]: this.#createDebuggerConnectionWSServer(), }; } // Converts page information received from device into PageDescription object // that is sent to debugger. - _buildPageDescription( + #buildPageDescription( deviceId: string, device: Device, page: Page, ): PageDescription { - const {host, protocol} = new URL(this._serverBaseUrl); + const {host, protocol} = new URL(this.#serverBaseUrl); const webSocketScheme = protocol === 'https:' ? 'wss' : 'ws'; const webSocketUrlWithoutProtocol = `${host}${WS_DEBUGGER_URL}?device=${deviceId}&page=${page.id}`; @@ -157,7 +157,7 @@ export default class InspectorProxy implements InspectorProxyQueries { // Sends object as response to HTTP request. // Just serializes object using JSON and sets required headers. - _sendJsonResponse( + #sendJsonResponse( response: ServerResponse, object: JsonPagesListResponse | JsonVersionResponse, ) { @@ -176,7 +176,7 @@ export default class InspectorProxy implements InspectorProxyQueries { // HTTP GET params. // For each new websocket connection we parse device and app names and create // new instance of Device class. - _createDeviceConnectionWSServer(): ws$WebSocketServer { + #createDeviceConnectionWSServer(): ws$WebSocketServer { const wss = new WS.Server({ noServer: true, perMessageDeflate: true, @@ -187,35 +187,35 @@ export default class InspectorProxy implements InspectorProxyQueries { // $FlowFixMe[value-as-type] wss.on('connection', async (socket: WS, req) => { try { - const fallbackDeviceId = String(this._deviceCounter++); + const fallbackDeviceId = String(this.#deviceCounter++); const query = url.parse(req.url || '', true).query || {}; const deviceId = query.device || fallbackDeviceId; const deviceName = query.name || 'Unknown'; const appName = query.app || 'Unknown'; - const oldDevice = this._devices.get(deviceId); + const oldDevice = this.#devices.get(deviceId); const newDevice = new Device( deviceId, deviceName, appName, socket, - this._projectRoot, - this._eventReporter, + this.#projectRoot, + this.#eventReporter, ); if (oldDevice) { oldDevice.handleDuplicateDeviceConnection(newDevice); } - this._devices.set(deviceId, newDevice); + this.#devices.set(deviceId, newDevice); debug( `Got new connection: name=${deviceName}, app=${appName}, device=${deviceId}`, ); socket.on('close', () => { - this._devices.delete(deviceId); + this.#devices.delete(deviceId); debug(`Device ${deviceName} disconnected.`); }); } catch (e) { @@ -231,7 +231,7 @@ export default class InspectorProxy implements InspectorProxyQueries { // in /json response. // When debugger connects we try to parse device and page IDs from the query and pass // websocket object to corresponding Device instance. - _createDebuggerConnectionWSServer(): ws$WebSocketServer { + #createDebuggerConnectionWSServer(): ws$WebSocketServer { const wss = new WS.Server({ noServer: true, perMessageDeflate: false, @@ -250,7 +250,7 @@ export default class InspectorProxy implements InspectorProxyQueries { throw new Error('Incorrect URL - must provide device and page IDs'); } - const device = this._devices.get(deviceId); + const device = this.#devices.get(deviceId); if (device == null) { throw new Error('Unknown device with ID ' + deviceId); } @@ -261,7 +261,7 @@ export default class InspectorProxy implements InspectorProxyQueries { } catch (e) { console.error(e); socket.close(INTERNAL_ERROR_CODE, e?.toString() ?? 'Unknown error'); - this._eventReporter?.logEvent({ + this.#eventReporter?.logEvent({ type: 'connect_debugger_frontend', status: 'error', error: e,