remote-client-manager.js (4101B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 CONNECTION_TYPES, 9 } = require("resource://devtools/client/shared/remote-debugging/constants.js"); 10 11 /** 12 * This class is designed to be a singleton shared by all DevTools to get access to 13 * existing clients created for remote debugging. 14 */ 15 class RemoteClientManager { 16 constructor() { 17 this._clients = new Map(); 18 this._runtimeInfoMap = new Map(); 19 this._onClientClosed = this._onClientClosed.bind(this); 20 } 21 22 /** 23 * Store a remote client that is already connected. 24 * 25 * @param {string} id 26 * Remote runtime id (see devtools/client/aboutdebugging/src/types). 27 * @param {string} type 28 * Remote runtime type (see devtools/client/aboutdebugging/src/types). 29 * @param {DevToolsClient} client 30 * @param {object} runtimeInfo 31 * See runtimeInfo type from client/aboutdebugging/src/types/runtime.js 32 */ 33 setClient(id, type, client, runtimeInfo) { 34 const key = this._getKey(id, type); 35 this._clients.set(key, client); 36 if (runtimeInfo) { 37 this._runtimeInfoMap.set(key, runtimeInfo); 38 } 39 client.once("closed", this._onClientClosed); 40 } 41 42 // See JSDoc for id, type from setClient. 43 hasClient(id, type) { 44 return this._clients.has(this._getKey(id, type)); 45 } 46 47 // See JSDoc for id, type from setClient. 48 getClient(id, type) { 49 return this._clients.get(this._getKey(id, type)); 50 } 51 52 // See JSDoc for id, type from setClient. 53 removeClient(id, type) { 54 const key = this._getKey(id, type); 55 this._removeClientByKey(key); 56 } 57 58 removeAllClients() { 59 const keys = [...this._clients.keys()]; 60 for (const key of keys) { 61 this._removeClientByKey(key); 62 } 63 } 64 65 /** 66 * Retrieve a unique, url-safe key based on a runtime id and type. 67 */ 68 getRemoteId(id, type) { 69 return encodeURIComponent(this._getKey(id, type)); 70 } 71 72 /** 73 * Retrieve a managed client for a remote id. The remote id should have been generated 74 * using getRemoteId. 75 */ 76 getClientByRemoteId(remoteId) { 77 const key = this._getKeyByRemoteId(remoteId); 78 return this._clients.get(key); 79 } 80 81 /** 82 * Retrieve the runtime info for a remote id. To display metadata about a runtime, such 83 * as name, device name, version... this runtimeInfo should be used rather than calling 84 * APIs on the client. 85 */ 86 getRuntimeInfoByRemoteId(remoteId) { 87 const key = this._getKeyByRemoteId(remoteId); 88 return this._runtimeInfoMap.get(key); 89 } 90 91 /** 92 * Retrieve a managed client for a remote id. The remote id should have been generated 93 * using getRemoteId. 94 */ 95 getConnectionTypeByRemoteId(remoteId) { 96 const key = this._getKeyByRemoteId(remoteId); 97 for (const type of Object.values(CONNECTION_TYPES)) { 98 if (key.endsWith(type)) { 99 return type; 100 } 101 } 102 return CONNECTION_TYPES.UNKNOWN; 103 } 104 105 _getKey(id, type) { 106 return id + "-" + type; 107 } 108 109 _getKeyByRemoteId(remoteId) { 110 if (!remoteId) { 111 // If no remote id was provided, return the key corresponding to the local 112 // this-firefox runtime. 113 const { THIS_FIREFOX } = CONNECTION_TYPES; 114 return this._getKey(THIS_FIREFOX, THIS_FIREFOX); 115 } 116 117 return decodeURIComponent(remoteId); 118 } 119 120 _removeClientByKey(key) { 121 const client = this._clients.get(key); 122 if (client) { 123 client.off("closed", this._onClientClosed); 124 this._clients.delete(key); 125 this._runtimeInfoMap.delete(key); 126 } 127 } 128 129 /** 130 * Cleanup all closed clients when a "closed" notification is received from a client. 131 */ 132 _onClientClosed() { 133 const closedClientKeys = [...this._clients.keys()].filter(key => { 134 return this._clients.get(key)._transportClosed; 135 }); 136 137 for (const key of closedClientKeys) { 138 this._removeClientByKey(key); 139 } 140 } 141 } 142 143 // Expose a singleton of RemoteClientManager. 144 module.exports = { 145 remoteClientManager: new RemoteClientManager(), 146 };