@aiot-toolkit/emulator 2.0.2-dev.3 → 2.0.2-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { default as VelaAvdCls } from './avd';
2
- import { default as GoldfishInstance } from './instance/goldfish';
2
+ export * from './instance';
3
3
  export * from './typing/Avd';
4
4
  export * from './typing/Instance';
5
- export { GoldfishInstance, VelaAvdCls };
5
+ export { VelaAvdCls };
package/lib/index.js CHANGED
@@ -17,10 +17,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.VelaAvdCls = exports.GoldfishInstance = void 0;
20
+ exports.VelaAvdCls = void 0;
21
21
  const avd_1 = __importDefault(require("./avd"));
22
22
  Object.defineProperty(exports, "VelaAvdCls", { enumerable: true, get: function () { return avd_1.default; } });
23
- const goldfish_1 = __importDefault(require("./instance/goldfish"));
24
- Object.defineProperty(exports, "GoldfishInstance", { enumerable: true, get: function () { return goldfish_1.default; } });
23
+ __exportStar(require("./instance"), exports);
25
24
  __exportStar(require("./typing/Avd"), exports);
26
25
  __exportStar(require("./typing/Instance"), exports);
@@ -1,19 +1,23 @@
1
1
  /// <reference types="node" />
2
+ import IManifest from '@aiot-toolkit/aiotpack/lib/compiler/javascript/vela/interface/IManifest';
2
3
  import { ChildProcess } from 'child_process';
4
+ import VelaAvdCls from '../avd';
3
5
  import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
4
- declare class GoldfishInstance {
5
- private projectPath;
6
- private sdkHome;
7
- private avdHome;
8
- private adbPort;
6
+ /**
7
+ * CommonInstance
8
+ */
9
+ declare class CommonInstance {
10
+ projectPath: string;
11
+ sdkHome: string;
12
+ avdHome: string;
13
+ adbPort: number;
9
14
  debugPort: number;
10
- private host9pPort;
11
- private velaAvdCls;
12
- private packageName;
15
+ velaAvdCls: VelaAvdCls;
13
16
  goldfishProcess: ChildProcess | undefined;
14
- v9fsProcess: ChildProcess | undefined;
15
17
  isFirstStart: boolean;
16
- private startOptions;
18
+ startOptions: IStartOptions | undefined;
19
+ projectInfo: IManifest;
20
+ isRpk: boolean;
17
21
  constructor(params: INewGoldfishInstanceParams);
18
22
  /** 获取模拟器二进制文件所在位置 */
19
23
  getEmulatorBinPath(): string;
@@ -21,21 +25,19 @@ declare class GoldfishInstance {
21
25
  start(options: IStartOptions): Promise<void>;
22
26
  /** 在goldfish中启动快应用 */
23
27
  startupQuickApp(options: IStartOptions): void;
24
- /** host启动9pServer */
25
- ensure9pServerRunnning(): Promise<void>;
26
28
  /** 启动goldfish模拟器 */
27
29
  startGoldfish(options: IStartOptions): Promise<void>;
28
30
  /** 通过adb连接模拟器 */
29
31
  connectGoldfish(): Promise<boolean>;
30
32
  /** 将打包后的文件推到挂载的快应用目录 */
31
- pushRpk(): void;
33
+ pushRpk(sourceRoot: string): Promise<void>;
32
34
  /** 杀死进程 */
33
35
  killProcess(currProcess?: ChildProcess): void;
34
36
  /** 停止模拟器并释放相关资源 */
35
- stop(): void;
37
+ stop(): Promise<void>;
36
38
  /** 重启模拟器 */
37
39
  restart(): void;
38
40
  /** 创建server */
39
41
  createWebsockeServer(): Promise<void>;
40
42
  }
41
- export default GoldfishInstance;
43
+ export default CommonInstance;
@@ -39,8 +39,6 @@ const UxFileUtils_1 = __importDefault(require("@aiot-toolkit/aiotpack/lib/utils/
39
39
  const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
40
40
  const adbMiwt = __importStar(require("@miwt/adb"));
41
41
  const child_process_1 = require("child_process");
42
- const find_process_1 = __importDefault(require("find-process"));
43
- const fs_1 = __importDefault(require("fs"));
44
42
  const os_1 = __importDefault(require("os"));
45
43
  const path_1 = __importDefault(require("path"));
46
44
  const portfinder_1 = __importDefault(require("portfinder"));
@@ -48,21 +46,23 @@ const ws_1 = require("ws");
48
46
  const avd_1 = __importDefault(require("../avd"));
49
47
  const constants_1 = require("../static/constants");
50
48
  const utils_1 = require("../utils");
51
- class GoldfishInstance {
49
+ /**
50
+ * CommonInstance
51
+ */
52
+ class CommonInstance {
52
53
  constructor(params) {
53
54
  this.adbPort = 5555;
54
55
  this.debugPort = 10055;
55
- this.host9pPort = 7878;
56
56
  this.isFirstStart = true;
57
57
  this.projectPath = params.projectPath;
58
58
  this.sdkHome = params.sdkHome || constants_1.defaultSDKHome;
59
59
  this.avdHome = params.avdHome || constants_1.defaultAvdHome;
60
+ this.isRpk = params.sourceRoot === './';
60
61
  this.velaAvdCls = new avd_1.default({
61
62
  sdkHome: this.sdkHome,
62
63
  avdHome: this.avdHome
63
64
  });
64
- const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath, params.sourceRoot);
65
- this.packageName = appPackageName;
65
+ this.projectInfo = UxFileUtils_1.default.getMainfestInfo(this.projectPath, params.sourceRoot);
66
66
  }
67
67
  /** 获取模拟器二进制文件所在位置 */
68
68
  getEmulatorBinPath() {
@@ -85,7 +85,8 @@ class GoldfishInstance {
85
85
  yield this.createWebsockeServer();
86
86
  }
87
87
  // adb push快应用到模拟器的/data/app目录
88
- this.pushRpk();
88
+ const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
89
+ this.pushRpk(buildedFilesPath);
89
90
  // 在模拟器中启动快应用
90
91
  this.startupQuickApp(options);
91
92
  this.isFirstStart = false;
@@ -98,9 +99,9 @@ class GoldfishInstance {
98
99
  /** 在goldfish中启动快应用 */
99
100
  startupQuickApp(options) {
100
101
  try {
101
- let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${this.packageName} &`;
102
+ let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${this.projectInfo.package} &`;
102
103
  if (options.devtool) {
103
- vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${this.packageName} &`;
104
+ vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${this.projectInfo.package} &`;
104
105
  }
105
106
  ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
106
107
  // vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
@@ -110,44 +111,6 @@ class GoldfishInstance {
110
111
  ColorConsole_1.default.error(`### Emulator ### Failed to startup quickapp: ${e.message}`);
111
112
  }
112
113
  }
113
- /** host启动9pServer */
114
- ensure9pServerRunnning() {
115
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
116
- var _a;
117
- const yaFileName = os_1.default.platform() === 'win32' ? 'ya-vm-file-server.exe' : 'ya-vm-file-server';
118
- const pidList = yield (0, find_process_1.default)('name', yaFileName);
119
- if (pidList.length > 0) {
120
- ColorConsole_1.default.log('### Emulator ### 9p server started in host');
121
- return resolve();
122
- }
123
- ColorConsole_1.default.log('### Emulator ### Starting 9p server in host');
124
- const quickappMountDir = path_1.default.resolve(this.sdkHome, 'qa');
125
- const toolsHome = path_1.default.resolve(this.sdkHome, 'tools');
126
- const serverBinPath = path_1.default.resolve(toolsHome, yaFileName);
127
- fs_1.default.chmodSync(serverBinPath, 0o777);
128
- this.host9pPort = yield portfinder_1.default.getPortPromise({ port: 7878 });
129
- const address = `127.0.0.1:${this.host9pPort}`;
130
- this.v9fsProcess = (0, child_process_1.spawn)(serverBinPath, [
131
- '--mount-point',
132
- quickappMountDir,
133
- '--network-address',
134
- address,
135
- '--debug'
136
- ]);
137
- (_a = this.v9fsProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
138
- const output = data.toString();
139
- if (output.match(/Server started, listening on: 127.0.0.1:(\d+)/)) {
140
- ColorConsole_1.default.log(output);
141
- ColorConsole_1.default.log('### Emulator ### 9p server starts successfully');
142
- return resolve();
143
- }
144
- });
145
- this.v9fsProcess.on('exit', (code) => {
146
- ColorConsole_1.default.error(`### Emulator ### ya-vm-file-server exited with code ${code}`);
147
- return reject();
148
- });
149
- }));
150
- }
151
114
  /** 启动goldfish模拟器 */
152
115
  startGoldfish(options) {
153
116
  var _a;
@@ -250,14 +213,16 @@ class GoldfishInstance {
250
213
  });
251
214
  }
252
215
  /** 将打包后的文件推到挂载的快应用目录 */
253
- pushRpk() {
254
- const sn = `127.0.0.1:${this.adbPort}`;
255
- const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath);
256
- const appRunDir = '/data/app';
257
- ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${appRunDir}`);
258
- (0, child_process_1.execSync)(`adb -s ${sn} shell mkdir /data/app/${appPackageName}`, { stdio: 'ignore' });
259
- (0, child_process_1.execSync)(`adb -s ${sn} push ./build/* /data/app/${appPackageName}`, { cwd: this.projectPath, stdio: 'ignore' });
260
- ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${appRunDir} successfully`);
216
+ pushRpk(sourceRoot) {
217
+ return __awaiter(this, void 0, void 0, function* () {
218
+ const sn = `127.0.0.1:${this.adbPort}`;
219
+ const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath);
220
+ const appRunDir = '/data/app';
221
+ ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${appRunDir}`);
222
+ (0, child_process_1.execSync)(`adb -s ${sn} shell mkdir ${appRunDir}/${appPackageName}`, { stdio: 'ignore' });
223
+ yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourceRoot}/* ${appRunDir}/${appPackageName}`);
224
+ ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${appRunDir} successfully`);
225
+ });
261
226
  }
262
227
  /** 杀死进程 */
263
228
  killProcess(currProcess) {
@@ -281,26 +246,23 @@ class GoldfishInstance {
281
246
  }
282
247
  /** 停止模拟器并释放相关资源 */
283
248
  stop() {
284
- if (this.goldfishProcess) {
285
- // Linux删除goldfishProcess后,子进程仍存在,导致模拟器窗口未关闭
286
- // 这里的作用是手动删除创建出来的子进程
287
- if (os_1.default.platform() === 'linux' && this.goldfishProcess.pid) {
288
- process.kill(this.goldfishProcess.pid + 1);
249
+ var _a;
250
+ return __awaiter(this, void 0, void 0, function* () {
251
+ if (this.goldfishProcess) {
252
+ // Linux删除goldfishProcess后,子进程仍存在,导致模拟器窗口未关闭
253
+ // 这里的作用是手动删除创建出来的子进程
254
+ // if (os.platform() === 'linux' && this.goldfishProcess.pid) {
255
+ // process.kill(this.goldfishProcess.pid + 1)
256
+ // }
257
+ this.killProcess(this.goldfishProcess);
258
+ yield (0, utils_1.killProcessByCmd)((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.avdName);
259
+ this.goldfishProcess = undefined;
289
260
  }
290
- this.killProcess(this.goldfishProcess);
291
- this.goldfishProcess = undefined;
292
- }
293
- if (this.v9fsProcess) {
294
- this.killProcess(this.v9fsProcess);
295
- this.v9fsProcess = undefined;
296
- }
261
+ });
297
262
  }
298
263
  /** 重启模拟器 */
299
264
  restart() {
300
- if (this.goldfishProcess) {
301
- this.killProcess(this.goldfishProcess);
302
- this.goldfishProcess = undefined;
303
- }
265
+ this.stop();
304
266
  this.start(this.startOptions);
305
267
  }
306
268
  /** 创建server */
@@ -329,4 +291,4 @@ class GoldfishInstance {
329
291
  });
330
292
  }
331
293
  }
332
- exports.default = GoldfishInstance;
294
+ exports.default = CommonInstance;
@@ -0,0 +1,15 @@
1
+ import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
2
+ import CommonInstance from './common';
3
+ declare class GoldfishInstance extends CommonInstance {
4
+ private appRunDir;
5
+ constructor(params: INewGoldfishInstanceParams);
6
+ /** 在goldfish模拟器中运行快应用 */
7
+ start(options: IStartOptions): Promise<void>;
8
+ /** 在goldfish中启动快应用 */
9
+ startupQuickApp(options: IStartOptions): Promise<void>;
10
+ /** 启动goldfish模拟器 */
11
+ startGoldfish(options: IStartOptions): Promise<void>;
12
+ /** 将打包后的文件推到挂载的快应用目录 */
13
+ pushRpk(sourceRoot: string): Promise<void>;
14
+ }
15
+ export default GoldfishInstance;
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
39
+ const adbMiwt = __importStar(require("@miwt/adb"));
40
+ const child_process_1 = require("child_process");
41
+ const path_1 = __importDefault(require("path"));
42
+ const portfinder_1 = __importDefault(require("portfinder"));
43
+ const constants_1 = require("../static/constants");
44
+ const common_1 = __importDefault(require("./common"));
45
+ class GoldfishInstance extends common_1.default {
46
+ constructor(params) {
47
+ super(params);
48
+ this.appRunDir = '/data/app';
49
+ }
50
+ /** 在goldfish模拟器中运行快应用 */
51
+ start(options) {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ this.startOptions = options;
54
+ // 启动模拟器
55
+ yield this.startGoldfish(options);
56
+ const connected = yield this.connectGoldfish();
57
+ if (connected) {
58
+ ColorConsole_1.default.log('### Emulator ### Goldfish emulator connected successfully');
59
+ if (this.isFirstStart && this.startOptions.serverPort) {
60
+ yield this.createWebsockeServer();
61
+ }
62
+ // adb push快应用到模拟器的/data/app目录
63
+ const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
64
+ yield this.pushRpk(buildedFilesPath);
65
+ // 在模拟器中启动快应用
66
+ this.startupQuickApp(options);
67
+ this.isFirstStart = false;
68
+ }
69
+ else {
70
+ ColorConsole_1.default.throw('### Emulator ### Failed to connect emulator, please check whether the adb is normal');
71
+ }
72
+ });
73
+ }
74
+ /** 在goldfish中启动快应用 */
75
+ startupQuickApp(options) {
76
+ return __awaiter(this, void 0, void 0, function* () {
77
+ try {
78
+ const { package: packageName } = this.projectInfo;
79
+ let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${packageName} &`;
80
+ if (options.devtool) {
81
+ vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${packageName} &`;
82
+ }
83
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
84
+ // vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
85
+ adbMiwt.execAdbCmdAsync(vappCmd, { stdio: 'ignore', encoding: 'utf-8' });
86
+ }
87
+ catch (e) {
88
+ ColorConsole_1.default.error(`### Emulator ### Failed to startup quickapp: ${e.message}`);
89
+ }
90
+ });
91
+ }
92
+ /** 启动goldfish模拟器 */
93
+ startGoldfish(options) {
94
+ var _a;
95
+ return __awaiter(this, void 0, void 0, function* () {
96
+ const { avdName, devtool } = options;
97
+ const emulatorBin = this.getEmulatorBinPath();
98
+ ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
99
+ const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
100
+ const { avdArch, avdImagePath } = avdInfo;
101
+ this.adbPort = yield portfinder_1.default.getPortPromise({ port: this.adbPort });
102
+ ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
103
+ if (!avdImagePath) {
104
+ return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
105
+ }
106
+ const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
107
+ ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
108
+ // 端口映射
109
+ let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${this.adbPort}-10.0.2.15:5555`;
110
+ if (devtool) {
111
+ portMappingStr += `,hostfwd=tcp:127.0.0.1:${this.debugPort}-10.0.2.15:101`;
112
+ }
113
+ // 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
114
+ const systemImageBin = path_1.default.resolve(this.sdkHome, 'tools/image/system.img');
115
+ const dataImageBin = path_1.default.resolve(this.sdkHome, 'tools/image/data.img');
116
+ const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin} \
117
+ -device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
118
+ -drive index=1,id=userdata,if=none,format=raw,file=${dataImageBin} \
119
+ -device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
120
+ -device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
121
+ // vnc配置
122
+ let windowStr = '';
123
+ let vncStr = '';
124
+ if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.vncPort) {
125
+ windowStr = '-no-window';
126
+ const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
127
+ vncStr = `-vnc :${portSuffix}`;
128
+ }
129
+ const stdioType = options.disableNSH ? 'pipe' : 'inherit';
130
+ // 启动goldfish的命令和参数
131
+ const cmd = `${emulatorBin} -nuttx -avd ${avdName} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} -qemu ${vncStr} ${imageMountStr}`;
132
+ const spawnArgs = cmd.split(' ');
133
+ const spawnBin = spawnArgs.shift();
134
+ ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
135
+ return new Promise((resolve) => {
136
+ var _a, _b;
137
+ this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
138
+ if (options.disableNSH) {
139
+ (_a = this.goldfishProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
140
+ if (options.stdoutCallback) {
141
+ options.stdoutCallback(data);
142
+ }
143
+ else {
144
+ console.log(data.toString());
145
+ }
146
+ if (data.toString().includes('(NSH)')) {
147
+ ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
148
+ resolve();
149
+ }
150
+ });
151
+ (_b = this.goldfishProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
152
+ const stderrCb = options.stderrCallback || console.log;
153
+ stderrCb(data.toString());
154
+ });
155
+ }
156
+ else {
157
+ setTimeout(() => {
158
+ ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
159
+ resolve();
160
+ }, 2000);
161
+ }
162
+ this.goldfishProcess.on('exit', (code) => {
163
+ ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
164
+ if (options.exitCallback) {
165
+ options.exitCallback(code);
166
+ }
167
+ });
168
+ });
169
+ });
170
+ }
171
+ /** 将打包后的文件推到挂载的快应用目录 */
172
+ pushRpk(sourceRoot) {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ const sn = `127.0.0.1:${this.adbPort}`;
175
+ const { package: appPackageName } = this.projectInfo;
176
+ const sourcePath = path_1.default.resolve(sourceRoot, './*');
177
+ ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${this.appRunDir}`);
178
+ yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell mkdir ${this.appRunDir}/${appPackageName}`);
179
+ yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourcePath} ${this.appRunDir}/${appPackageName}`);
180
+ ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${this.appRunDir} successfully`);
181
+ });
182
+ }
183
+ }
184
+ exports.default = GoldfishInstance;
@@ -0,0 +1,7 @@
1
+ import { INewGoldfishInstanceParams } from '../typing/Instance';
2
+ import CommonInstance from './common';
3
+ import GoldfishInstance from './dev';
4
+ import MiwearInstance from "./miwear";
5
+ import OldGoldfishInstance from './preDev';
6
+ declare function findInstance(avdName: string, params: INewGoldfishInstanceParams): GoldfishInstance | MiwearInstance | OldGoldfishInstance | undefined;
7
+ export { CommonInstance, GoldfishInstance, MiwearInstance, OldGoldfishInstance, findInstance };
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.findInstance = exports.OldGoldfishInstance = exports.MiwearInstance = exports.GoldfishInstance = exports.CommonInstance = void 0;
7
+ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
8
+ const avd_1 = __importDefault(require("../avd"));
9
+ const common_1 = __importDefault(require("./common"));
10
+ exports.CommonInstance = common_1.default;
11
+ const dev_1 = __importDefault(require("./dev"));
12
+ exports.GoldfishInstance = dev_1.default;
13
+ const miwear_1 = __importDefault(require("./miwear"));
14
+ exports.MiwearInstance = miwear_1.default;
15
+ const preDev_1 = __importDefault(require("./preDev"));
16
+ exports.OldGoldfishInstance = preDev_1.default;
17
+ function findInstance(avdName, params) {
18
+ const { sdkHome, avdHome } = params;
19
+ const { avdImagePath } = new avd_1.default({ sdkHome, avdHome }).getVelaAvdInfo(avdName);
20
+ if (!avdImagePath) {
21
+ ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
22
+ return;
23
+ }
24
+ if (avdImagePath.includes('release')) {
25
+ return new miwear_1.default(params);
26
+ }
27
+ else if (avdImagePath.match(/0\.0\.2|0\.0\.1/)) {
28
+ return new preDev_1.default(params);
29
+ }
30
+ return new dev_1.default(params);
31
+ }
32
+ exports.findInstance = findInstance;
@@ -0,0 +1,27 @@
1
+ import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
2
+ import CommonInstance from './common';
3
+ /**
4
+ * MiwearInstance
5
+ * 针对 vela4.0 的镜像
6
+ */
7
+ declare class MiwearInstance extends CommonInstance {
8
+ private appPathInEmulator;
9
+ private debugSocket?;
10
+ constructor(params: INewGoldfishInstanceParams);
11
+ /** 在goldfish模拟器中运行快应用 */
12
+ start(options: IStartOptions): Promise<void>;
13
+ /** 启动goldfish模拟器 */
14
+ startGoldfish(options: IStartOptions): Promise<void>;
15
+ /** 通过adb连接模拟器 */
16
+ connectGoldfish(): Promise<boolean>;
17
+ /** 在goldfish中启动快应用 */
18
+ startupQuickApp(options: IStartOptions): Promise<void>;
19
+ /** 将快应用安装到应用列表 */
20
+ installRpkToAppList(rpkPath: string, targetDir: string): Promise<void>;
21
+ initDebugSocket(): Promise<void> | undefined;
22
+ /** 通知模拟器更新 */
23
+ handleUpdate(): Promise<void>;
24
+ /** 创建server */
25
+ createWebsockeServer(): Promise<void>;
26
+ }
27
+ export default MiwearInstance;
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ const JavascriptDefaultCompileOption_1 = __importDefault(require("@aiot-toolkit/aiotpack/lib/compiler/javascript/JavascriptDefaultCompileOption"));
39
+ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
40
+ const adbMiwt = __importStar(require("@miwt/adb"));
41
+ const child_process_1 = require("child_process");
42
+ const fs_extra_1 = __importDefault(require("fs-extra"));
43
+ const path_1 = __importDefault(require("path"));
44
+ const portfinder_1 = __importDefault(require("portfinder"));
45
+ const ws_1 = __importStar(require("ws"));
46
+ const constants_1 = require("../static/constants");
47
+ const utils_1 = require("../utils");
48
+ const common_1 = __importDefault(require("./common"));
49
+ /**
50
+ * MiwearInstance
51
+ * 针对 vela4.0 的镜像
52
+ */
53
+ class MiwearInstance extends common_1.default {
54
+ constructor(params) {
55
+ super(params);
56
+ this.appPathInEmulator = '/data/quickapp/app';
57
+ }
58
+ /** 在goldfish模拟器中运行快应用 */
59
+ start(options) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ this.startOptions = options;
62
+ // 启动模拟器
63
+ yield this.startGoldfish(options);
64
+ // adb连接模拟器
65
+ const connected = yield this.connectGoldfish();
66
+ if (connected) {
67
+ ColorConsole_1.default.info('### Emulator ### Goldfish emulator connected successfully');
68
+ if (this.isFirstStart && this.startOptions.serverPort) {
69
+ yield this.createWebsockeServer();
70
+ }
71
+ this.startupQuickApp(options);
72
+ this.isFirstStart = false;
73
+ }
74
+ else {
75
+ ColorConsole_1.default.throw('### Emulator ### Failed to connect emulator, please check whether the adb is normal');
76
+ }
77
+ });
78
+ }
79
+ /** 启动goldfish模拟器 */
80
+ startGoldfish(options) {
81
+ var _a;
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const { avdName, devtool } = options;
84
+ const emulatorBin = this.getEmulatorBinPath();
85
+ ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
86
+ const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
87
+ const { avdArch, avdImagePath } = avdInfo;
88
+ this.adbPort = yield portfinder_1.default.getPortPromise({ port: this.adbPort });
89
+ ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
90
+ if (!avdImagePath) {
91
+ return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
92
+ }
93
+ const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
94
+ ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
95
+ // 端口映射
96
+ let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${this.adbPort}-10.0.2.15:5555`;
97
+ if (devtool) {
98
+ portMappingStr += `,hostfwd=tcp:127.0.0.1:${this.debugPort}-10.0.2.15:101`;
99
+ }
100
+ // 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
101
+ const systemImageBin = path_1.default.resolve(avdImagePath, 'vela_resource.img');
102
+ const dataImageBin = path_1.default.resolve(avdImagePath, 'data.img');
103
+ const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin} \
104
+ -device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
105
+ -drive index=1,id=userdata,if=none,format=raw,file=${dataImageBin} \
106
+ -device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
107
+ -device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
108
+ // vnc配置
109
+ let windowStr = '';
110
+ let vncStr = '';
111
+ if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.vncPort) {
112
+ windowStr = '-no-window';
113
+ const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
114
+ vncStr = `-vnc :${portSuffix}`;
115
+ }
116
+ const stdioType = options.disableNSH ? 'pipe' : 'inherit';
117
+ // 启动goldfish的命令和参数
118
+ const cmd = `${emulatorBin} -nuttx -avd ${avdName} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} -qemu ${vncStr} ${imageMountStr}`;
119
+ const spawnArgs = cmd.split(' ');
120
+ const spawnBin = spawnArgs.shift();
121
+ ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
122
+ return new Promise((resolve) => {
123
+ var _a, _b, _c;
124
+ this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
125
+ (_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
126
+ const stderrCb = options.stderrCallback || console.log;
127
+ stderrCb(data.toString());
128
+ });
129
+ this.goldfishProcess.on('exit', (code) => {
130
+ ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
131
+ if (options.exitCallback) {
132
+ options.exitCallback(code);
133
+ }
134
+ });
135
+ if (options.disableNSH) {
136
+ (_c = (_b = this.goldfishProcess) === null || _b === void 0 ? void 0 : _b.stdout) === null || _c === void 0 ? void 0 : _c.on('data', (data) => {
137
+ const msg = data.toString();
138
+ const stdoutCb = options.stdoutCallback || console.log;
139
+ stdoutCb(msg);
140
+ if (msg.match(/quickapp_rpk_installer_init | rpk installer init done/)) {
141
+ ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
142
+ resolve();
143
+ }
144
+ });
145
+ }
146
+ else {
147
+ setTimeout(() => {
148
+ ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
149
+ resolve();
150
+ }, 8000);
151
+ ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
152
+ resolve();
153
+ }
154
+ });
155
+ });
156
+ }
157
+ /** 通过adb连接模拟器 */
158
+ connectGoldfish() {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ let adbConnected = false;
161
+ const connectFn = () => __awaiter(this, void 0, void 0, function* () {
162
+ const sn = `127.0.0.1:${this.adbPort}`;
163
+ while (!adbConnected) {
164
+ const adbKillCmd = `adb kill-server`;
165
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
166
+ yield adbMiwt.execAdbCmdAsync(adbKillCmd);
167
+ const adbConnectCmd = `adb connect ${sn}`;
168
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
169
+ const str = yield adbMiwt.execAdbCmdAsync(adbConnectCmd);
170
+ ColorConsole_1.default.log(`### Emulator ### ${str}`);
171
+ const devices = yield adbMiwt.getAdbDevices();
172
+ ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
173
+ adbConnected =
174
+ devices.filter((item) => item.sn === sn && item.status === 'device').length > 0;
175
+ }
176
+ Promise.resolve(adbConnected);
177
+ });
178
+ yield Promise.race([
179
+ connectFn(),
180
+ new Promise((resolve) => {
181
+ setTimeout(() => resolve(false), 600 * 1000);
182
+ })
183
+ ]);
184
+ return adbConnected;
185
+ });
186
+ }
187
+ /** 在goldfish中启动快应用 */
188
+ startupQuickApp(options) {
189
+ return __awaiter(this, void 0, void 0, function* () {
190
+ const { package: appPackageName } = this.projectInfo;
191
+ const releaseDir = path_1.default.resolve(this.projectPath, JavascriptDefaultCompileOption_1.default.releasePath || 'dist');
192
+ const files = fs_extra_1.default
193
+ .readdirSync(releaseDir)
194
+ .filter(item => item.includes(appPackageName) && item.endsWith('.rpk'));
195
+ if (files.length < 0) {
196
+ ColorConsole_1.default.error(`### Emulator the rpk does not exist`);
197
+ }
198
+ const rpkPath = path_1.default.resolve(releaseDir, files[0]);
199
+ // 调试模式需要push一个文件至miwear中
200
+ const sn = `127.0.0.1:${this.adbPort}`;
201
+ if (options.devtool) {
202
+ const debuggerCfgFile = path_1.default.join(__dirname, '../static/debugger_ip.cfg');
203
+ yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${debuggerCfgFile} /data/debugger_ip.cfg`);
204
+ }
205
+ else {
206
+ adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell rm /data/debugger_ip.cfg`);
207
+ }
208
+ this.installRpkToAppList(rpkPath, this.appPathInEmulator);
209
+ });
210
+ }
211
+ /** 将快应用安装到应用列表 */
212
+ installRpkToAppList(rpkPath, targetDir) {
213
+ return __awaiter(this, void 0, void 0, function* () {
214
+ try {
215
+ const sn = `127.0.0.1:${this.adbPort}`;
216
+ const { package: packageName } = this.projectInfo;
217
+ const rpkName = path_1.default.basename(rpkPath);
218
+ // 1. 查询应用是否已经安装,如果安装了,则先卸载
219
+ const lsCmd = `adb -s ${sn} shell ls ${this.appPathInEmulator}`;
220
+ const res = yield adbMiwt.execAdbCmdAsync(lsCmd);
221
+ if (res.includes(packageName)) {
222
+ const uninstallCmd = `adb -s ${sn} shell pm uninstall ${packageName}`;
223
+ ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${uninstallCmd}`);
224
+ adbMiwt.execAdbCmdAsync(uninstallCmd);
225
+ // 这里等待2s的作用是等qemu执行完uninstall操作的一系列工作
226
+ yield (0, utils_1.sleep)(2000);
227
+ }
228
+ // 2. adb push应用的rpk
229
+ const pushCmd = `adb -s ${sn} push ${rpkPath} ${targetDir}`;
230
+ ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${pushCmd}`);
231
+ yield adbMiwt.execAdbCmdAsync(pushCmd);
232
+ yield (0, utils_1.sleep)(100);
233
+ // 3. 安装应用
234
+ const targetPath = `${targetDir}/${rpkName}`;
235
+ const installCmd = `adb -s ${sn} shell pm install ${targetPath}`;
236
+ ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${installCmd}`);
237
+ adbMiwt.execAdbCmdAsync(installCmd);
238
+ }
239
+ catch (e) { }
240
+ });
241
+ }
242
+ initDebugSocket() {
243
+ if (this.debugSocket) {
244
+ return Promise.resolve();
245
+ }
246
+ this.debugSocket = new ws_1.default(`ws://localhost:${this.debugPort}`);
247
+ this.debugSocket.onopen = e => {
248
+ ColorConsole_1.default.info(`### debugSocket connect success`);
249
+ return Promise.resolve();
250
+ };
251
+ this.debugSocket.onerror = (e) => {
252
+ ColorConsole_1.default.error(`### Emulator ${e.data}`);
253
+ };
254
+ this.debugSocket.onclose = (e) => {
255
+ ColorConsole_1.default.error(`### Emulator debugSocket connect close: ${e.data}`);
256
+ this.debugSocket = undefined;
257
+ };
258
+ }
259
+ /** 通知模拟器更新 */
260
+ handleUpdate() {
261
+ var _a, _b;
262
+ return __awaiter(this, void 0, void 0, function* () {
263
+ yield this.initDebugSocket();
264
+ // 1. 将整包重新推到miwear中(TODO:增量更新)
265
+ const sn = `127.0.0.1:${this.adbPort}`;
266
+ const { package: appPackageName } = this.projectInfo;
267
+ const sourcePath = path_1.default.resolve(this.projectPath, './build/*');
268
+ yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourcePath} ${this.appPathInEmulator}/${appPackageName}`);
269
+ ColorConsole_1.default.info(`### Emulator push to ${this.appPathInEmulator}/${appPackageName} successfully`);
270
+ // 2. 下发CDP命令给调试服务告知刷新
271
+ if (((_a = this.debugSocket) === null || _a === void 0 ? void 0 : _a.readyState) === ws_1.default.OPEN) {
272
+ (_b = this.debugSocket) === null || _b === void 0 ? void 0 : _b.send(JSON.stringify({ id: 10000, method: 'Page.reload', params: {} }));
273
+ }
274
+ });
275
+ }
276
+ /** 创建server */
277
+ createWebsockeServer() {
278
+ var _a;
279
+ return __awaiter(this, void 0, void 0, function* () {
280
+ const wsServer = new ws_1.WebSocketServer({
281
+ port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort,
282
+ });
283
+ wsServer.on('connection', socket => {
284
+ ColorConsole_1.default.success(`### App Socket server ### Websocket connects to websocket server`);
285
+ socket.on('error', err => {
286
+ ColorConsole_1.default.error(`### App Socket server ### Websocket server error: ${err.message}`);
287
+ });
288
+ socket.on('message', (data) => __awaiter(this, void 0, void 0, function* () {
289
+ var _a;
290
+ const message = JSON.parse(data.toString());
291
+ ColorConsole_1.default.log(`### App Socket server ### Websocket server get data: ${data}`);
292
+ if (message.type === 'restart') {
293
+ // 非调试模式下无法热更新
294
+ if (!((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.devtool)) {
295
+ this.restart();
296
+ return;
297
+ }
298
+ this.handleUpdate();
299
+ }
300
+ else if (message.type === 'stop') {
301
+ this.stop();
302
+ }
303
+ }));
304
+ });
305
+ });
306
+ }
307
+ }
308
+ exports.default = MiwearInstance;
@@ -1,22 +1,11 @@
1
1
  /// <reference types="node" />
2
2
  import { ChildProcess } from 'child_process';
3
3
  import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
4
- declare class GoldfishInstance {
5
- private projectPath;
6
- private sdkHome;
7
- private avdHome;
8
- private adbPort;
9
- debugPort: number;
4
+ import CommonInstance from './common';
5
+ declare class OldGoldfishInstance extends CommonInstance {
10
6
  private host9pPort;
11
- private velaAvdCls;
12
- private packageName;
13
- goldfishProcess: ChildProcess | undefined;
14
7
  v9fsProcess: ChildProcess | undefined;
15
- isFirstStart: boolean;
16
- private startOptions;
17
8
  constructor(params: INewGoldfishInstanceParams);
18
- /** 获取模拟器二进制文件所在位置 */
19
- getEmulatorBinPath(): string;
20
9
  /** 在goldfish模拟器中运行快应用 */
21
10
  start(options: IStartOptions): Promise<void>;
22
11
  /** 在goldfish中启动快应用 */
@@ -27,15 +16,8 @@ declare class GoldfishInstance {
27
16
  startGoldfish(options: IStartOptions): Promise<void>;
28
17
  /** 通过adb连接模拟器 */
29
18
  connectGoldfish(): Promise<boolean>;
30
- /** 将打包后的文件推到挂载的快应用目录 */
31
- pushRpk(): void;
32
- /** 杀死进程 */
33
- killProcess(currProcess?: ChildProcess): void;
19
+ pushRpk(sourceRoot: string): Promise<void>;
34
20
  /** 停止模拟器并释放相关资源 */
35
- stop(): void;
36
- /** 重启模拟器 */
37
- restart(): void;
38
- /** 创建server */
39
- createWebsockeServer(): Promise<void>;
21
+ stop(): Promise<void>;
40
22
  }
41
- export default GoldfishInstance;
23
+ export default OldGoldfishInstance;
@@ -35,7 +35,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- const UxFileUtils_1 = __importDefault(require("@aiot-toolkit/aiotpack/lib/utils/ux/UxFileUtils"));
39
38
  const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
40
39
  const FileUtil_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/utils/FileUtil"));
41
40
  const adbMiwt = __importStar(require("@miwt/adb"));
@@ -45,33 +44,12 @@ const fs_1 = __importDefault(require("fs"));
45
44
  const os_1 = __importDefault(require("os"));
46
45
  const path_1 = __importDefault(require("path"));
47
46
  const portfinder_1 = __importDefault(require("portfinder"));
48
- const ws_1 = require("ws");
49
- const avd_1 = __importDefault(require("../avd"));
50
47
  const constants_1 = require("../static/constants");
51
- const utils_1 = require("../utils");
52
- class GoldfishInstance {
48
+ const common_1 = __importDefault(require("./common"));
49
+ class OldGoldfishInstance extends common_1.default {
53
50
  constructor(params) {
54
- this.adbPort = 15555;
55
- this.debugPort = 10055;
51
+ super(params);
56
52
  this.host9pPort = 7878;
57
- this.isFirstStart = true;
58
- this.projectPath = params.projectPath;
59
- this.sdkHome = params.sdkHome || constants_1.defaultSDKHome;
60
- this.avdHome = params.avdHome || constants_1.defaultAvdHome;
61
- this.velaAvdCls = new avd_1.default({
62
- sdkHome: this.sdkHome,
63
- avdHome: this.avdHome
64
- });
65
- const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath, params.sourceRoot);
66
- this.packageName = appPackageName;
67
- }
68
- /** 获取模拟器二进制文件所在位置 */
69
- getEmulatorBinPath() {
70
- const osPlatform = os_1.default.platform();
71
- const arch = (0, utils_1.getSystemArch)();
72
- const platform = osPlatform === 'win32' ? 'windows' : osPlatform;
73
- const emulatorHome = path_1.default.resolve(this.sdkHome, 'emulator');
74
- return path_1.default.resolve(emulatorHome, `${platform}-${arch}`, 'emulator');
75
53
  }
76
54
  /** 在goldfish模拟器中运行快应用 */
77
55
  start(options) {
@@ -79,8 +57,9 @@ class GoldfishInstance {
79
57
  // host启动9p server
80
58
  yield this.ensure9pServerRunnning();
81
59
  this.startOptions = options;
82
- // 将rpk推到host的QuickappHome目录
83
- this.pushRpk();
60
+ // 将rpk推到host的./export/qa/app目录
61
+ const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
62
+ this.pushRpk(buildedFilesPath);
84
63
  // 启动模拟器
85
64
  yield this.startGoldfish(options);
86
65
  const connected = yield this.connectGoldfish();
@@ -101,13 +80,14 @@ class GoldfishInstance {
101
80
  /** 在goldfish中启动快应用 */
102
81
  startupQuickApp(options) {
103
82
  try {
83
+ const { package: packageName } = this.projectInfo;
104
84
  const appMountDir = path_1.default.resolve(this.sdkHome, 'qa');
105
85
  const mountCmd = `adb -s 127.0.0.1:${this.adbPort} shell mount -t v9fs -o tag=10.0.2.2,port=${this.host9pPort},aname=${appMountDir} /data`;
106
86
  ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${mountCmd}`);
107
87
  adbMiwt.execAdbCmdSync(mountCmd);
108
- let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${this.packageName} &`;
88
+ let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${packageName} &`;
109
89
  if (options.devtool) {
110
- vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${this.packageName} &`;
90
+ vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${packageName} &`;
111
91
  }
112
92
  ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
113
93
  // vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
@@ -157,7 +137,6 @@ class GoldfishInstance {
157
137
  }
158
138
  /** 启动goldfish模拟器 */
159
139
  startGoldfish(options) {
160
- var _a;
161
140
  return __awaiter(this, void 0, void 0, function* () {
162
141
  const { avdName, devtool } = options;
163
142
  const emulatorBin = this.getEmulatorBinPath();
@@ -182,9 +161,9 @@ class GoldfishInstance {
182
161
  // vnc配置
183
162
  let noWindow = false;
184
163
  let vncStr = '';
185
- if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.vncPort) {
164
+ if (options.vncPort) {
186
165
  noWindow = true;
187
- const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
166
+ const portSuffix = options.vncPort - constants_1.defaultVncPort;
188
167
  vncStr = `-vnc :${portSuffix}`;
189
168
  }
190
169
  // 启动goldfish的命令和参数
@@ -211,15 +190,20 @@ class GoldfishInstance {
211
190
  var _a;
212
191
  this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
213
192
  (_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
214
- console.log(data.toString());
193
+ const stderrCb = options.stderrCallback || console.log;
194
+ stderrCb(data.toString());
215
195
  });
216
196
  this.goldfishProcess.on('exit', (code) => {
217
197
  ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
198
+ if (options.exitCallback) {
199
+ options.exitCallback(code);
200
+ }
218
201
  });
219
202
  const p1 = new Promise((resolve) => {
220
203
  var _a, _b;
221
204
  (_b = (_a = this.goldfishProcess) === null || _a === void 0 ? void 0 : _a.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
222
- console.log(data.toString());
205
+ const stdoutCb = options.stdoutCallback || console.log;
206
+ stdoutCb(data.toString());
223
207
  if (data.toString().includes('(NSH)')) {
224
208
  ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
225
209
  resolve();
@@ -264,84 +248,28 @@ class GoldfishInstance {
264
248
  return adbConnected;
265
249
  });
266
250
  }
267
- /** 将打包后的文件推到挂载的快应用目录 */
268
- pushRpk() {
269
- const buildDir = path_1.default.resolve(this.projectPath, 'build');
270
- const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath);
271
- const appRunDir = path_1.default.resolve(this.sdkHome, 'qa/app', appPackageName);
272
- ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${appRunDir}`);
273
- fs_1.default.rmSync(appRunDir, { recursive: true, force: true });
274
- FileUtil_1.default.copyFiles(buildDir, appRunDir);
275
- ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${appRunDir} successfully`);
276
- }
277
- /** 杀死进程 */
278
- killProcess(currProcess) {
279
- if (currProcess && currProcess.pid && currProcess.exitCode === null) {
280
- console.log('process pid:', currProcess.pid);
281
- try {
282
- if (os_1.default.platform() === 'win32') {
283
- (0, child_process_1.execSync)(`taskkill /pid ${currProcess.pid} /T /F`);
284
- }
285
- else if (os_1.default.platform() === 'darwin') {
286
- process.kill(currProcess.pid);
287
- }
288
- else {
289
- currProcess.kill();
290
- }
291
- }
292
- catch (err) {
293
- ColorConsole_1.default.log(`### Emulator ### kill process get error :\n${err.stack}`);
294
- }
295
- }
251
+ pushRpk(sourceRoot) {
252
+ return __awaiter(this, void 0, void 0, function* () {
253
+ const { package: appPackageName } = this.projectInfo;
254
+ const appRunDir = path_1.default.resolve(this.sdkHome, 'qa/app', appPackageName);
255
+ ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${appRunDir}`);
256
+ fs_1.default.rmSync(appRunDir, { recursive: true, force: true });
257
+ FileUtil_1.default.copyFiles(sourceRoot, appRunDir);
258
+ ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${appRunDir} successfully`);
259
+ });
296
260
  }
297
261
  /** 停止模拟器并释放相关资源 */
298
262
  stop() {
299
- if (this.goldfishProcess) {
300
- // Linux删除goldfishProcess后,子进程仍存在,导致模拟器窗口未关闭
301
- // 这里的作用是手动删除创建出来的子进程
302
- if (os_1.default.platform() === 'linux' && this.goldfishProcess.pid) {
303
- process.kill(this.goldfishProcess.pid + 1);
304
- }
305
- this.killProcess(this.goldfishProcess);
306
- this.goldfishProcess = undefined;
307
- }
308
- if (this.v9fsProcess) {
309
- this.killProcess(this.v9fsProcess);
310
- this.v9fsProcess = undefined;
311
- }
312
- }
313
- /** 重启模拟器 */
314
- restart() {
315
- if (this.goldfishProcess) {
316
- this.killProcess(this.goldfishProcess);
317
- this.goldfishProcess = undefined;
318
- }
319
- this.start(this.startOptions);
320
- }
321
- /** 创建server */
322
- createWebsockeServer() {
323
- var _a;
263
+ const _super = Object.create(null, {
264
+ stop: { get: () => super.stop }
265
+ });
324
266
  return __awaiter(this, void 0, void 0, function* () {
325
- const wsServer = new ws_1.WebSocketServer({
326
- port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort,
327
- });
328
- wsServer.on('connection', socket => {
329
- ColorConsole_1.default.success(`### App Socket server ### Websocket connects to websocket server`);
330
- socket.on('error', err => {
331
- ColorConsole_1.default.error(`### App Socket server ### Websocket server error: ${err.message}`);
332
- });
333
- socket.on('message', data => {
334
- const message = JSON.parse(data.toString());
335
- ColorConsole_1.default.log(`### App Socket server ### Websocket server get data: ${data}`);
336
- if (message.type === 'restart') {
337
- this.restart();
338
- }
339
- else if (message.type === 'stop') {
340
- this.stop();
341
- }
342
- });
343
- });
267
+ _super.stop.call(this);
268
+ if (this.v9fsProcess) {
269
+ this.killProcess(this.v9fsProcess);
270
+ this.v9fsProcess = undefined;
271
+ }
344
272
  });
345
273
  }
346
274
  }
347
- exports.default = GoldfishInstance;
275
+ exports.default = OldGoldfishInstance;
@@ -0,0 +1 @@
1
+ 10.0.2.15:101
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { IAvdResourcePaths } from "./Avd";
2
3
  export interface INewGoldfishInstanceParams extends IAvdResourcePaths {
3
4
  projectPath: string;
@@ -9,4 +10,7 @@ export interface IStartOptions {
9
10
  disableNSH?: boolean;
10
11
  serverPort?: number;
11
12
  vncPort?: number;
13
+ stdoutCallback?: (buffer: Buffer) => void;
14
+ stderrCallback?: (buffer: Buffer) => void;
15
+ exitCallback?: (code: number | null) => void;
12
16
  }
@@ -3,3 +3,10 @@
3
3
  * 所以15.0.0之前无法通过os.arch()区分,也无法通过execSync('uname -m')区分
4
4
  */
5
5
  export declare function getSystemArch(): string | void;
6
+ /** 根据PID杀死进程 */
7
+ export declare function killProcessByPid(pid: string): void;
8
+ /**
9
+ * 根据命令杀死进程
10
+ */
11
+ export declare function killProcessByCmd(cmd: string): Promise<void>;
12
+ export declare function sleep(time: number): Promise<void>;
@@ -1,11 +1,21 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
13
  };
5
14
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getSystemArch = void 0;
15
+ exports.sleep = exports.killProcessByCmd = exports.killProcessByPid = exports.getSystemArch = void 0;
7
16
  const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
8
17
  const child_process_1 = require("child_process");
18
+ const find_process_1 = __importDefault(require("find-process"));
9
19
  const os_1 = __importDefault(require("os"));
10
20
  const semver_1 = __importDefault(require("semver"));
11
21
  const cpuArch = {
@@ -37,3 +47,41 @@ function getSystemArch() {
37
47
  return cpuArch[osArch];
38
48
  }
39
49
  exports.getSystemArch = getSystemArch;
50
+ /** 根据PID杀死进程 */
51
+ function killProcessByPid(pid) {
52
+ try {
53
+ const cmd = os_1.default.platform() === "win32"
54
+ ? `taskkill /pid ${pid} /T /F`
55
+ : `kill -9 ${pid}`;
56
+ (0, child_process_1.execSync)(cmd);
57
+ }
58
+ catch (e) {
59
+ console.error(`kill process ${pid} get error: ${e}`);
60
+ }
61
+ }
62
+ exports.killProcessByPid = killProcessByPid;
63
+ /**
64
+ * 根据命令杀死进程
65
+ */
66
+ function killProcessByCmd(cmd) {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ if (!cmd)
69
+ return;
70
+ try {
71
+ const list = yield (0, find_process_1.default)('name', cmd);
72
+ list.forEach((item) => __awaiter(this, void 0, void 0, function* () {
73
+ killProcessByPid(item.pid.toString());
74
+ }));
75
+ }
76
+ catch (e) {
77
+ console.error(`kill process ${cmd} get error: ${e}`);
78
+ }
79
+ });
80
+ }
81
+ exports.killProcessByCmd = killProcessByCmd;
82
+ function sleep(time) {
83
+ return __awaiter(this, void 0, void 0, function* () {
84
+ return new Promise(resolve => setTimeout(resolve, time));
85
+ });
86
+ }
87
+ exports.sleep = sleep;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiot-toolkit/emulator",
3
- "version": "2.0.2-dev.3",
3
+ "version": "2.0.2-dev.5",
4
4
  "description": "vela emulator tool.",
5
5
  "homepage": "",
6
6
  "license": "ISC",
@@ -35,10 +35,10 @@
35
35
  "emulator"
36
36
  ],
37
37
  "dependencies": {
38
- "@aiot-toolkit/aiotpack": "2.0.2-dev.3",
39
- "@aiot-toolkit/shared-utils": "2.0.2-dev.3",
38
+ "@aiot-toolkit/aiotpack": "2.0.2-dev.5",
39
+ "@aiot-toolkit/shared-utils": "2.0.2-dev.5",
40
40
  "find-process": "^1.4.7",
41
41
  "portfinder": "^1.0.32"
42
42
  },
43
- "gitHead": "e143a7038d5efaa59f01b2e2eb98422b1ec01097"
43
+ "gitHead": "0c123fdd458966a4ca438cca03cc9efc2b5f634c"
44
44
  }