@aiot-toolkit/emulator 2.0.2-dev.4 → 2.0.2-dev.6

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/avd/index.js CHANGED
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
6
7
  const fs_1 = __importDefault(require("fs"));
7
8
  const path_1 = __importDefault(require("path"));
8
9
  const constants_1 = require("../static/constants");
@@ -62,7 +63,7 @@ class VelaAvdCls {
62
63
  return true;
63
64
  }
64
65
  catch (e) {
65
- return false;
66
+ throw (`createVelaAvd: ${e.message}`);
66
67
  }
67
68
  }
68
69
  getVelaAvdInfo(avdName) {
@@ -76,24 +77,30 @@ class VelaAvdCls {
76
77
  };
77
78
  const currAvdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
78
79
  const configIni = path_1.default.resolve(currAvdDir, 'config.ini');
79
- const contents = fs_1.default.readFileSync(configIni, 'utf-8');
80
- // 这里需要使用惰性匹配
81
- const archRegex = /hw.cpu.arch = ([\d\D]+?)\n/;
82
- const archMatcher = contents.match(archRegex);
83
- const heightRegex = /hw.lcd.height = ([\d\D]+?)\n/;
84
- const heightMatcher = contents.match(heightRegex);
85
- const widthRegex = /hw.lcd.width = ([\d\D]+?)\n/;
86
- const widthMatcher = contents.match(widthRegex);
87
- const skinRegex = /skin.name = ([\d\D]+?)\n/;
88
- const skinMatcher = contents.match(skinRegex);
89
- const imagePathRegex = /image.sysdir.1 = ([\d\D]+?)\n/;
90
- const imagePathMather = contents.match(imagePathRegex);
91
- archMatcher && (avdInfo.avdArch = archMatcher[1]);
92
- heightMatcher && (avdInfo.avdHeight = heightMatcher[1]);
93
- widthMatcher && (avdInfo.avdWidth = widthMatcher[1]);
94
- skinMatcher && (avdInfo.avdSkin = skinMatcher[1]);
95
- imagePathMather && (avdInfo.avdImagePath = imagePathMather[1]);
96
- return avdInfo;
80
+ try {
81
+ const contents = fs_1.default.readFileSync(configIni, 'utf-8');
82
+ // 这里需要使用惰性匹配
83
+ const archRegex = /hw.cpu.arch = ([\d\D]+?)\n/;
84
+ const archMatcher = contents.match(archRegex);
85
+ const heightRegex = /hw.lcd.height = ([\d\D]+?)\n/;
86
+ const heightMatcher = contents.match(heightRegex);
87
+ const widthRegex = /hw.lcd.width = ([\d\D]+?)\n/;
88
+ const widthMatcher = contents.match(widthRegex);
89
+ const skinRegex = /skin.name = ([\d\D]+?)\n/;
90
+ const skinMatcher = contents.match(skinRegex);
91
+ const imagePathRegex = /image.sysdir.1 = ([\d\D]+?)\n/;
92
+ const imagePathMather = contents.match(imagePathRegex);
93
+ archMatcher && (avdInfo.avdArch = archMatcher[1]);
94
+ heightMatcher && (avdInfo.avdHeight = heightMatcher[1]);
95
+ widthMatcher && (avdInfo.avdWidth = widthMatcher[1]);
96
+ skinMatcher && (avdInfo.avdSkin = skinMatcher[1]);
97
+ imagePathMather && (avdInfo.avdImagePath = imagePathMather[1]);
98
+ return avdInfo;
99
+ }
100
+ catch (err) {
101
+ ColorConsole_1.default.log(`getVelaAvdInfo: ${err.message}`);
102
+ return avdInfo;
103
+ }
97
104
  }
98
105
  deleteVelaAvd(avdName) {
99
106
  const avdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
@@ -108,23 +115,18 @@ class VelaAvdCls {
108
115
  }
109
116
  }
110
117
  getVelaAvdList() {
111
- try {
112
- const avdList = [];
113
- const files = fs_1.default.readdirSync(constants_1.defaultAvdHome);
114
- const regex = /^(Vela[\d\D]*)\.avd$/;
115
- for (const fileName of files) {
116
- const matcher = fileName.match(regex);
117
- if (matcher) {
118
- const avdName = matcher[1];
119
- const avdInfo = this.getVelaAvdInfo(avdName);
120
- avdList.push(avdInfo);
121
- }
118
+ const avdList = [];
119
+ const files = fs_1.default.readdirSync(this.avdHome);
120
+ const regex = /^(Vela[\d\D]*)\.avd$/;
121
+ for (const fileName of files) {
122
+ const matcher = fileName.match(regex);
123
+ if (matcher) {
124
+ const avdName = matcher[1];
125
+ const avdInfo = this.getVelaAvdInfo(avdName);
126
+ avdList.push(avdInfo);
122
127
  }
123
- return avdList;
124
- }
125
- catch (err) {
126
- return [];
127
128
  }
129
+ return avdList;
128
130
  }
129
131
  getVelaSkinList() {
130
132
  try {
@@ -17,6 +17,7 @@ declare class CommonInstance {
17
17
  isFirstStart: boolean;
18
18
  startOptions: IStartOptions | undefined;
19
19
  projectInfo: IManifest;
20
+ isRpk: boolean;
20
21
  constructor(params: INewGoldfishInstanceParams);
21
22
  /** 获取模拟器二进制文件所在位置 */
22
23
  getEmulatorBinPath(): string;
@@ -57,6 +57,7 @@ class CommonInstance {
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
@@ -84,7 +85,8 @@ class CommonInstance {
84
85
  yield this.createWebsockeServer();
85
86
  }
86
87
  // adb push快应用到模拟器的/data/app目录
87
- yield this.pushRpk(path_1.default.resolve(this.projectPath, './dist'));
88
+ const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
89
+ this.pushRpk(buildedFilesPath);
88
90
  // 在模拟器中启动快应用
89
91
  this.startupQuickApp(options);
90
92
  this.isFirstStart = false;
@@ -260,10 +262,7 @@ class CommonInstance {
260
262
  }
261
263
  /** 重启模拟器 */
262
264
  restart() {
263
- if (this.goldfishProcess) {
264
- this.killProcess(this.goldfishProcess);
265
- this.goldfishProcess = undefined;
266
- }
265
+ this.stop();
267
266
  this.start(this.startOptions);
268
267
  }
269
268
  /** 创建server */
@@ -60,7 +60,8 @@ class GoldfishInstance extends common_1.default {
60
60
  yield this.createWebsockeServer();
61
61
  }
62
62
  // adb push快应用到模拟器的/data/app目录
63
- yield this.pushRpk(path_1.default.resolve(this.projectPath, './build'));
63
+ const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
64
+ yield this.pushRpk(buildedFilesPath);
64
65
  // 在模拟器中启动快应用
65
66
  this.startupQuickApp(options);
66
67
  this.isFirstStart = false;
@@ -148,7 +149,8 @@ class GoldfishInstance extends common_1.default {
148
149
  }
149
150
  });
150
151
  (_b = this.goldfishProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
151
- console.log(data.toString());
152
+ const stderrCb = options.stderrCallback || console.log;
153
+ stderrCb(data.toString());
152
154
  });
153
155
  }
154
156
  else {
@@ -159,6 +161,9 @@ class GoldfishInstance extends common_1.default {
159
161
  }
160
162
  this.goldfishProcess.on('exit', (code) => {
161
163
  ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
164
+ if (options.exitCallback) {
165
+ options.exitCallback(code);
166
+ }
162
167
  });
163
168
  });
164
169
  });
@@ -6,6 +6,7 @@ import CommonInstance from './common';
6
6
  */
7
7
  declare class MiwearInstance extends CommonInstance {
8
8
  private appPathInEmulator;
9
+ private debugSocket?;
9
10
  constructor(params: INewGoldfishInstanceParams);
10
11
  /** 在goldfish模拟器中运行快应用 */
11
12
  start(options: IStartOptions): Promise<void>;
@@ -17,5 +18,10 @@ declare class MiwearInstance extends CommonInstance {
17
18
  startupQuickApp(options: IStartOptions): Promise<void>;
18
19
  /** 将快应用安装到应用列表 */
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>;
20
26
  }
21
27
  export default MiwearInstance;
@@ -42,6 +42,7 @@ const child_process_1 = require("child_process");
42
42
  const fs_extra_1 = __importDefault(require("fs-extra"));
43
43
  const path_1 = __importDefault(require("path"));
44
44
  const portfinder_1 = __importDefault(require("portfinder"));
45
+ const ws_1 = __importStar(require("ws"));
45
46
  const constants_1 = require("../static/constants");
46
47
  const utils_1 = require("../utils");
47
48
  const common_1 = __importDefault(require("./common"));
@@ -64,6 +65,9 @@ class MiwearInstance extends common_1.default {
64
65
  const connected = yield this.connectGoldfish();
65
66
  if (connected) {
66
67
  ColorConsole_1.default.info('### Emulator ### Goldfish emulator connected successfully');
68
+ if (this.isFirstStart && this.startOptions.serverPort) {
69
+ yield this.createWebsockeServer();
70
+ }
67
71
  this.startupQuickApp(options);
68
72
  this.isFirstStart = false;
69
73
  }
@@ -116,30 +120,37 @@ class MiwearInstance extends common_1.default {
116
120
  const spawnBin = spawnArgs.shift();
117
121
  ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
118
122
  return new Promise((resolve) => {
119
- var _a;
123
+ var _a, _b, _c;
120
124
  this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
121
125
  (_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
122
- console.log(data.toString());
126
+ const stderrCb = options.stderrCallback || console.log;
127
+ stderrCb(data.toString());
123
128
  });
124
129
  this.goldfishProcess.on('exit', (code) => {
125
130
  ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
131
+ if (options.exitCallback) {
132
+ options.exitCallback(code);
133
+ }
126
134
  });
127
- const p1 = new Promise((resolve) => {
128
- var _a, _b;
129
- (_b = (_a = this.goldfishProcess) === null || _a === void 0 ? void 0 : _a.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
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();
130
138
  const stdoutCb = options.stdoutCallback || console.log;
131
- stdoutCb(data.toString());
132
- // if (data.toString().includes('proto_on_start: on_start finished')) {
133
- // ColorConsole.info(`### Emulator ### Goldfish emulator starts successfully`)
134
- // resolve()
135
- // }
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
+ }
136
144
  });
137
- });
138
- const p2 = setTimeout(() => {
145
+ }
146
+ else {
147
+ setTimeout(() => {
148
+ ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
149
+ resolve();
150
+ }, 8000);
139
151
  ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
140
152
  resolve();
141
- }, 8000);
142
- return Promise.race([p1, p2]);
153
+ }
143
154
  });
144
155
  });
145
156
  }
@@ -215,12 +226,12 @@ class MiwearInstance extends common_1.default {
215
226
  yield (0, utils_1.sleep)(2000);
216
227
  }
217
228
  // 2. adb push应用的rpk
218
- const pushCmd = `adb -s ${sn} push ${rpkPath} ${targetDir}`;
229
+ const targetPath = `${targetDir}/${packageName}.rpk`;
230
+ const pushCmd = `adb -s ${sn} push ${rpkPath} ${targetPath}`;
219
231
  ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${pushCmd}`);
220
232
  yield adbMiwt.execAdbCmdAsync(pushCmd);
221
233
  yield (0, utils_1.sleep)(100);
222
234
  // 3. 安装应用
223
- const targetPath = `${targetDir}/${rpkName}`;
224
235
  const installCmd = `adb -s ${sn} shell pm install ${targetPath}`;
225
236
  ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${installCmd}`);
226
237
  adbMiwt.execAdbCmdAsync(installCmd);
@@ -228,5 +239,70 @@ class MiwearInstance extends common_1.default {
228
239
  catch (e) { }
229
240
  });
230
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
+ }
231
307
  }
232
308
  exports.default = MiwearInstance;
@@ -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"));
@@ -58,8 +57,9 @@ class OldGoldfishInstance extends common_1.default {
58
57
  // host启动9p server
59
58
  yield this.ensure9pServerRunnning();
60
59
  this.startOptions = options;
61
- // 将rpk推到host的QuickappHome目录
62
- this.pushRpk(path_1.default.resolve(this.projectPath, './build'));
60
+ // 将rpk推到host的./export/qa/app目录
61
+ const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
62
+ this.pushRpk(buildedFilesPath);
63
63
  // 启动模拟器
64
64
  yield this.startGoldfish(options);
65
65
  const connected = yield this.connectGoldfish();
@@ -190,10 +190,14 @@ class OldGoldfishInstance extends common_1.default {
190
190
  var _a;
191
191
  this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
192
192
  (_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
193
- console.log(data.toString());
193
+ const stderrCb = options.stderrCallback || console.log;
194
+ stderrCb(data.toString());
194
195
  });
195
196
  this.goldfishProcess.on('exit', (code) => {
196
197
  ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
198
+ if (options.exitCallback) {
199
+ options.exitCallback(code);
200
+ }
197
201
  });
198
202
  const p1 = new Promise((resolve) => {
199
203
  var _a, _b;
@@ -246,7 +250,7 @@ class OldGoldfishInstance extends common_1.default {
246
250
  }
247
251
  pushRpk(sourceRoot) {
248
252
  return __awaiter(this, void 0, void 0, function* () {
249
- const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath);
253
+ const { package: appPackageName } = this.projectInfo;
250
254
  const appRunDir = path_1.default.resolve(this.sdkHome, 'qa/app', appPackageName);
251
255
  ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${appRunDir}`);
252
256
  fs_1.default.rmSync(appRunDir, { recursive: true, force: true });
@@ -11,4 +11,6 @@ export interface IStartOptions {
11
11
  serverPort?: number;
12
12
  vncPort?: number;
13
13
  stdoutCallback?: (buffer: Buffer) => void;
14
+ stderrCallback?: (buffer: Buffer) => void;
15
+ exitCallback?: (code: number | null) => void;
14
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiot-toolkit/emulator",
3
- "version": "2.0.2-dev.4",
3
+ "version": "2.0.2-dev.6",
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.4",
39
- "@aiot-toolkit/shared-utils": "2.0.2-dev.4",
38
+ "@aiot-toolkit/aiotpack": "2.0.2-dev.6",
39
+ "@aiot-toolkit/shared-utils": "2.0.2-dev.6",
40
40
  "find-process": "^1.4.7",
41
41
  "portfinder": "^1.0.32"
42
42
  },
43
- "gitHead": "534fdc7c6f018623c05499bf9add8db813ef8660"
43
+ "gitHead": "736a21d4d2f4fcc102766312d2529e426f27b6c4"
44
44
  }