backendAdb.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.AdbBackend = void 0;
  6. var _utilsBundle = require("../../utilsBundle");
  7. var net = _interopRequireWildcard(require("net"));
  8. var _events = require("events");
  9. var _utils = require("../../utils");
  10. function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
  11. function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  12. /**
  13. * Copyright Microsoft Corporation. All rights reserved.
  14. *
  15. * Licensed under the Apache License, Version 2.0 (the "License");
  16. * you may not use this file except in compliance with the License.
  17. * You may obtain a copy of the License at
  18. *
  19. * http://www.apache.org/licenses/LICENSE-2.0
  20. *
  21. * Unless required by applicable law or agreed to in writing, software
  22. * distributed under the License is distributed on an "AS IS" BASIS,
  23. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  24. * See the License for the specific language governing permissions and
  25. * limitations under the License.
  26. */
  27. class AdbBackend {
  28. async devices(options = {}) {
  29. const result = await runCommand('host:devices', options.host, options.port);
  30. const lines = result.toString().trim().split('\n');
  31. return lines.map(line => {
  32. const [serial, status] = line.trim().split('\t');
  33. return new AdbDevice(serial, status, options.host, options.port);
  34. });
  35. }
  36. }
  37. exports.AdbBackend = AdbBackend;
  38. class AdbDevice {
  39. constructor(serial, status, host, port) {
  40. this.serial = void 0;
  41. this.status = void 0;
  42. this.host = void 0;
  43. this.port = void 0;
  44. this._closed = false;
  45. this.serial = serial;
  46. this.status = status;
  47. this.host = host;
  48. this.port = port;
  49. }
  50. async init() {}
  51. async close() {
  52. this._closed = true;
  53. }
  54. runCommand(command) {
  55. if (this._closed) throw new Error('Device is closed');
  56. return runCommand(command, this.host, this.port, this.serial);
  57. }
  58. async open(command) {
  59. if (this._closed) throw new Error('Device is closed');
  60. const result = await open(command, this.host, this.port, this.serial);
  61. result.becomeSocket();
  62. return result;
  63. }
  64. }
  65. async function runCommand(command, host = '127.0.0.1', port = 5037, serial) {
  66. (0, _utilsBundle.debug)('pw:adb:runCommand')(command, serial);
  67. const socket = new BufferedSocketWrapper(command, net.createConnection({
  68. host,
  69. port
  70. }));
  71. try {
  72. if (serial) {
  73. await socket.write(encodeMessage(`host:transport:${serial}`));
  74. const status = await socket.read(4);
  75. (0, _utils.assert)(status.toString() === 'OKAY', status.toString());
  76. }
  77. await socket.write(encodeMessage(command));
  78. const status = await socket.read(4);
  79. (0, _utils.assert)(status.toString() === 'OKAY', status.toString());
  80. let commandOutput;
  81. if (!command.startsWith('shell:')) {
  82. const remainingLength = parseInt((await socket.read(4)).toString(), 16);
  83. commandOutput = await socket.read(remainingLength);
  84. } else {
  85. commandOutput = await socket.readAll();
  86. }
  87. return commandOutput;
  88. } finally {
  89. socket.close();
  90. }
  91. }
  92. async function open(command, host = '127.0.0.1', port = 5037, serial) {
  93. const socket = new BufferedSocketWrapper(command, net.createConnection({
  94. host,
  95. port
  96. }));
  97. if (serial) {
  98. await socket.write(encodeMessage(`host:transport:${serial}`));
  99. const status = await socket.read(4);
  100. (0, _utils.assert)(status.toString() === 'OKAY', status.toString());
  101. }
  102. await socket.write(encodeMessage(command));
  103. const status = await socket.read(4);
  104. (0, _utils.assert)(status.toString() === 'OKAY', status.toString());
  105. return socket;
  106. }
  107. function encodeMessage(message) {
  108. let lenHex = message.length.toString(16);
  109. lenHex = '0'.repeat(4 - lenHex.length) + lenHex;
  110. return Buffer.from(lenHex + message);
  111. }
  112. class BufferedSocketWrapper extends _events.EventEmitter {
  113. constructor(command, socket) {
  114. super();
  115. this.guid = (0, _utils.createGuid)();
  116. this._socket = void 0;
  117. this._buffer = Buffer.from([]);
  118. this._isSocket = false;
  119. this._notifyReader = void 0;
  120. this._connectPromise = void 0;
  121. this._isClosed = false;
  122. this._command = void 0;
  123. this._command = command;
  124. this._socket = socket;
  125. this._connectPromise = new Promise(f => this._socket.on('connect', f));
  126. this._socket.on('data', data => {
  127. (0, _utilsBundle.debug)('pw:adb:data')(data.toString());
  128. if (this._isSocket) {
  129. this.emit('data', data);
  130. return;
  131. }
  132. this._buffer = Buffer.concat([this._buffer, data]);
  133. if (this._notifyReader) this._notifyReader();
  134. });
  135. this._socket.on('close', () => {
  136. this._isClosed = true;
  137. if (this._notifyReader) this._notifyReader();
  138. this.close();
  139. this.emit('close');
  140. });
  141. this._socket.on('error', error => this.emit('error', error));
  142. }
  143. async write(data) {
  144. (0, _utilsBundle.debug)('pw:adb:send')(data.toString().substring(0, 100) + '...');
  145. await this._connectPromise;
  146. await new Promise(f => this._socket.write(data, f));
  147. }
  148. close() {
  149. if (this._isClosed) return;
  150. (0, _utilsBundle.debug)('pw:adb')('Close ' + this._command);
  151. this._socket.destroy();
  152. }
  153. async read(length) {
  154. await this._connectPromise;
  155. (0, _utils.assert)(!this._isSocket, 'Can not read by length in socket mode');
  156. while (this._buffer.length < length) await new Promise(f => this._notifyReader = f);
  157. const result = this._buffer.slice(0, length);
  158. this._buffer = this._buffer.slice(length);
  159. (0, _utilsBundle.debug)('pw:adb:recv')(result.toString().substring(0, 100) + '...');
  160. return result;
  161. }
  162. async readAll() {
  163. while (!this._isClosed) await new Promise(f => this._notifyReader = f);
  164. return this._buffer;
  165. }
  166. becomeSocket() {
  167. (0, _utils.assert)(!this._buffer.length);
  168. this._isSocket = true;
  169. }
  170. }