@aiot-toolkit/emulator 2.0.6-beta.9 → 2.1.0-prender.1

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.
@@ -0,0 +1,21 @@
1
+ import Aedes from 'aedes';
2
+ import { TlsOptions } from 'tls';
3
+ import { IncomingMessage, ServerResponse, Server as HttpServer } from 'http';
4
+ export interface BrokerOptions {
5
+ preferredMqttPort?: number;
6
+ preferredHttpPort?: number;
7
+ tlsDir?: string;
8
+ host?: string;
9
+ onHttpRequest?: (req: IncomingMessage, res: ServerResponse) => boolean;
10
+ }
11
+ export interface BrokerInstance {
12
+ aedes: Aedes;
13
+ mqttPort: number;
14
+ httpPort: number;
15
+ mqttHost: string;
16
+ tlsOptions: TlsOptions;
17
+ httpServer: HttpServer;
18
+ close(): Promise<void>;
19
+ }
20
+ export declare function getLocalIP(): string;
21
+ export declare function startBroker(options?: BrokerOptions): Promise<BrokerInstance>;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getLocalIP = getLocalIP;
7
+ exports.startBroker = startBroker;
8
+ var _aedes = _interopRequireDefault(require("aedes"));
9
+ var _tls = require("tls");
10
+ var _http = require("http");
11
+ var _path = _interopRequireDefault(require("path"));
12
+ var _fs = _interopRequireDefault(require("fs"));
13
+ var _os = _interopRequireDefault(require("os"));
14
+ var _aedesPersistence = _interopRequireDefault(require("aedes-persistence"));
15
+ var _selfsigned = _interopRequireDefault(require("selfsigned"));
16
+ var _constants = require("../emulatorutil/constants");
17
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
+ function getLocalIP() {
19
+ const interfaces = _os.default.networkInterfaces();
20
+ const skip = ['VMware', 'VirtualBox', 'Hyper-V', 'DockerNAT', 'vEthernet', 'WSL', 'Parallels'];
21
+ for (const name in interfaces) {
22
+ if (skip.some(s => name.includes(s))) continue;
23
+ for (const alias of interfaces[name] ?? []) {
24
+ if (alias.family === 'IPv4' && !alias.internal) return alias.address;
25
+ }
26
+ }
27
+ return '127.0.0.1';
28
+ }
29
+ function ensureTlsCerts(tlsDir) {
30
+ const keyPath = _path.default.join(tlsDir, 'key.pem');
31
+ const certPath = _path.default.join(tlsDir, 'cert.pem');
32
+ if (!_fs.default.existsSync(keyPath) || !_fs.default.existsSync(certPath)) {
33
+ const pems = _selfsigned.default.generate([{
34
+ name: 'commonName',
35
+ value: 'localhost'
36
+ }], {
37
+ days: 365
38
+ });
39
+ _fs.default.mkdirSync(tlsDir, {
40
+ recursive: true
41
+ });
42
+ _fs.default.writeFileSync(keyPath, pems.private);
43
+ _fs.default.writeFileSync(certPath, pems.cert);
44
+ }
45
+ return {
46
+ key: _fs.default.readFileSync(keyPath),
47
+ cert: _fs.default.readFileSync(certPath),
48
+ rejectUnauthorized: false
49
+ };
50
+ }
51
+ async function startBroker(options) {
52
+ const {
53
+ preferredMqttPort = 1884,
54
+ preferredHttpPort = 8883,
55
+ tlsDir = _path.default.join(_constants.defaultSDKHome, 'tls'),
56
+ host,
57
+ onHttpRequest
58
+ } = options ?? {};
59
+ const mqttHost = host ?? getLocalIP();
60
+ const persistence = (0, _aedesPersistence.default)();
61
+ const aedes = new _aedes.default({
62
+ persistence,
63
+ queueLimit: 80
64
+ });
65
+ const tlsOptions = ensureTlsCerts(tlsDir);
66
+ const tlsServer = (0, _tls.createServer)(tlsOptions, aedes.handle);
67
+ const httpServer = (0, _http.createServer)((req, res) => {
68
+ if (onHttpRequest?.(req, res)) return;
69
+ res.statusCode = 404;
70
+ res.end();
71
+ });
72
+ const getPort = (await import('get-port')).default;
73
+ const mqttPort = await getPort({
74
+ port: preferredMqttPort
75
+ });
76
+ const httpPort = await getPort({
77
+ port: preferredHttpPort
78
+ });
79
+ await new Promise((resolve, reject) => {
80
+ tlsServer.once('error', reject);
81
+ tlsServer.listen(mqttPort, '0.0.0.0', () => {
82
+ httpServer.listen(httpPort, '0.0.0.0', () => resolve());
83
+ });
84
+ });
85
+ return {
86
+ aedes,
87
+ mqttPort,
88
+ httpPort,
89
+ mqttHost,
90
+ tlsOptions,
91
+ httpServer,
92
+ async close() {
93
+ await new Promise(r => httpServer.close(() => r()));
94
+ await new Promise(r => tlsServer.close(() => r()));
95
+ aedes.close();
96
+ }
97
+ };
98
+ }
@@ -27,7 +27,6 @@ Object.defineProperty(exports, "isVelaImageType", {
27
27
  });
28
28
  var _os = _interopRequireDefault(require("os"));
29
29
  var _path = _interopRequireDefault(require("path"));
30
- var _https = _interopRequireDefault(require("https"));
31
30
  var _Vvd = require("../typing/Vvd");
32
31
  var _utils = require("../utils");
33
32
  var _shared = require("../shared");
@@ -51,15 +50,8 @@ async function getSdkUrl() {
51
50
  const internalBaseUrl = 'https://cnbj3-fusion-fds.api.xiaomi.net/vela-ide';
52
51
  // 优先使用内网域名,因为云上工程没有外网环境
53
52
  let base = internalBaseUrl;
54
- await new Promise(resolve => {
55
- _https.default.get(`${base}/versions.json`, {
56
- timeout: 2000
57
- }, res => {
58
- if (res.statusCode !== 200) {
59
- base = externalBaseUrl;
60
- }
61
- resolve();
62
- });
53
+ await fetch(`${base}/versions.json`).catch(() => {
54
+ base = externalBaseUrl;
63
55
  });
64
56
  return {
65
57
  baseUrl: base,
@@ -77,40 +69,47 @@ async function getSdkUrl() {
77
69
  * vela-dev-0.0.4 : vela 4.0 dev 分支
78
70
  */
79
71
  const VelaImageVersionList = exports.VelaImageVersionList = [{
80
- label: 'vela-miwear-watch-5.0',
72
+ label: 'vela-miwear-watch-5',
81
73
  description: '适用于手表/手环的,带表盘的 vela 5.0 镜像,不可自定义模拟器尺寸',
82
74
  value: _Vvd.VelaImageType.VELA_MIWEAR_WATCH_5,
83
- time: '20250716',
75
+ time: '20260130',
84
76
  hide: false,
85
77
  icon: ''
86
78
  }, {
87
- label: 'vela-watch-5.0',
79
+ label: 'vela-watch-5',
88
80
  description: '适用于手表/手环的,不带表盘的 vela 5.0 镜像,可自定义模拟器尺寸',
89
81
  value: _Vvd.VelaImageType.VELA_WATCH_5,
90
- time: '20250716',
82
+ time: '20260422',
91
83
  hide: false,
92
84
  icon: ''
93
85
  }, {
94
- label: 'vela-miwear-watch-4.0',
86
+ label: 'vela-miwear-watch-4',
95
87
  description: '原 vela-release-4.0 版本,适用于手表/手环的,带表盘的 vela 4.0 镜像,不可自定义模拟器尺寸',
96
88
  value: _Vvd.VelaImageType.REL,
97
89
  time: '20250526',
98
90
  hide: false,
99
91
  icon: ''
100
92
  }, {
101
- label: 'vela-watch-4.0',
93
+ label: 'vela-watch-4',
102
94
  description: '原 vela-pre-4.0 版本,适用于手表/手环的,不带表盘的 vela 4.0 镜像,可自定义模拟器尺寸',
103
95
  value: _Vvd.VelaImageType.PRE,
104
96
  time: '20250225',
105
97
  hide: false,
106
98
  icon: ''
107
99
  }, {
108
- label: 'vela-miwear-minisound-5.0',
100
+ label: 'vela-miwear-minisound-5',
109
101
  description: '适用于音响的 vela-miwear 5.0 镜像,不可自定义模拟器尺寸',
110
102
  value: _Vvd.VelaImageType.VELA_MIWEAR_MINISOUND_5,
111
103
  time: '20250318',
112
104
  hide: true,
113
105
  icon: ''
106
+ }, {
107
+ label: 'openvela-smartspeaker-5',
108
+ description: '适用于音响的 vela-miwear 5.0 镜像,不可自定义模拟器尺寸',
109
+ value: _Vvd.VelaImageType.OPENVELA_SMARTSPEAKER_5,
110
+ time: '20260128',
111
+ hide: true,
112
+ icon: ''
114
113
  }];
115
114
  const EmulatorEnvVersion = exports.EmulatorEnvVersion = {
116
115
  name: '模拟器资源版本管理',
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './broker';
1
2
  export * from './vvd';
2
3
  export { getSystemArch, tryRun } from './utils';
3
4
  export * from './instance';
package/lib/index.js CHANGED
@@ -19,6 +19,18 @@ Object.defineProperty(exports, "tryRun", {
19
19
  return _utils.tryRun;
20
20
  }
21
21
  });
22
+ var _broker = require("./broker");
23
+ Object.keys(_broker).forEach(function (key) {
24
+ if (key === "default" || key === "__esModule") return;
25
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
26
+ if (key in exports && exports[key] === _broker[key]) return;
27
+ Object.defineProperty(exports, key, {
28
+ enumerable: true,
29
+ get: function () {
30
+ return _broker[key];
31
+ }
32
+ });
33
+ });
22
34
  var _vvd = require("./vvd");
23
35
  Object.keys(_vvd).forEach(function (key) {
24
36
  if (key === "default" || key === "__esModule") return;
@@ -1,3 +1,4 @@
1
+ import 'core-js/actual/promise/with-resolvers';
1
2
  import readline from 'readline';
2
3
  import { IEmulatorInstanceParams } from '../typing/Instance';
3
4
  import { VelaImageType } from '../typing/Vvd';
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ require("core-js/actual/promise/with-resolvers");
7
8
  var _ColorConsole = _interopRequireDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
8
9
  var _ILog = require("@aiot-toolkit/shared-utils/lib/interface/ILog");
9
10
  var _adb = _interopRequireWildcard(require("@miwt/adb"));
@@ -7,7 +7,8 @@ import { IEmulatorInstanceParams } from '../typing/Instance';
7
7
  import { Vela5Instance } from './vela5';
8
8
  import { VelaMiwear5 } from './miwear5';
9
9
  import { MiniSound5 } from './minisound';
10
- declare function getInstanceClass(imageType: VelaImageType): typeof GoldfishInstance | typeof MiwearInstance | typeof PreInstance | typeof Vela5Instance | typeof VelaMiwear5 | typeof MiniSound5;
10
+ import { OpenSmartspeaker5 } from './openSmartspeaker5';
11
+ declare function getInstanceClass(imageType: VelaImageType): typeof GoldfishInstance | typeof MiwearInstance | typeof PreInstance | typeof Vela5Instance | typeof VelaMiwear5 | typeof MiniSound5 | typeof OpenSmartspeaker5;
11
12
  /**
12
13
  * 根据镜像决定使用哪个instance
13
14
  * Vela正式版(4.0) -> MiwearInstance
@@ -43,6 +43,7 @@ var _Vvd = require("../typing/Vvd");
43
43
  var _vela = require("./vela5");
44
44
  var _miwear2 = require("./miwear5");
45
45
  var _minisound = require("./minisound");
46
+ var _openSmartspeaker = require("./openSmartspeaker5");
46
47
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
47
48
  function getInstanceClass(imageType) {
48
49
  const map = {
@@ -51,7 +52,8 @@ function getInstanceClass(imageType) {
51
52
  [_Vvd.VelaImageType.DEV]: _dev.default,
52
53
  [_Vvd.VelaImageType.VELA_WATCH_5]: _vela.Vela5Instance,
53
54
  [_Vvd.VelaImageType.VELA_MIWEAR_WATCH_5]: _miwear2.VelaMiwear5,
54
- [_Vvd.VelaImageType.VELA_MIWEAR_MINISOUND_5]: _minisound.MiniSound5
55
+ [_Vvd.VelaImageType.VELA_MIWEAR_MINISOUND_5]: _minisound.MiniSound5,
56
+ [_Vvd.VelaImageType.OPENVELA_SMARTSPEAKER_5]: _openSmartspeaker.OpenSmartspeaker5
55
57
  };
56
58
  return map[imageType] || _miwear2.VelaMiwear5;
57
59
  }
@@ -13,7 +13,7 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
13
13
  class MiniSound5 extends _miwear.VelaMiwear5 {
14
14
  imageType = (() => _Vvd.VelaImageType.VELA_MIWEAR_MINISOUND_5)();
15
15
  appDir = '/data/app';
16
- xmsInitedFlag = /Boot completed/;
16
+ xmsInitedFlag = /AMS/;
17
17
  static appStartedFlag = /Start main loop/;
18
18
 
19
19
  /**
@@ -7,6 +7,7 @@ import { VelaImageType } from '../typing/Vvd';
7
7
  declare class MiwearInstance extends CommonEmulatorInstance {
8
8
  xmsInitedFlag: RegExp;
9
9
  static appInstalledFlag: RegExp;
10
+ static appInstallFailedFlag: RegExp;
10
11
  imageType: VelaImageType;
11
12
  appDir: string;
12
13
  static isAppInstalled(log: string, targetRpk: string): boolean;
@@ -20,12 +20,15 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
20
20
  class MiwearInstance extends _common.default {
21
21
  xmsInitedFlag = /quickapp_rpk_installer_init|rpk installer init done/;
22
22
  static appInstalledFlag = /InstallState_Finished|install finished/;
23
+ static appInstallFailedFlag = /uv_mq_read_cb: install prepare failed|rpk_install_status: rpk install failed/;
23
24
  imageType = (() => _Vvd.VelaImageType.REL)();
24
25
  appDir = '/data/quickapp/app';
25
26
  static isAppInstalled(log, targetRpk) {
26
27
  // 注意:targetRpk 可能包含特殊字符,需要转义
27
28
  const escapedRpk = targetRpk.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
28
- const reg = new RegExp(`executeInstall: rpk install: ${escapedRpk} .* success`);
29
+ // 旧版本日志格式:executeInstall: rpk install: <rpk> ... success
30
+ // 新版本日志格式:rpk_install_status: rpk file [<rpk>] installed, cleanup it
31
+ const reg = new RegExp(`executeInstall: rpk install: ${escapedRpk} .* success` + `|rpk_install_status: rpk file \\[${escapedRpk}\\] installed`);
29
32
  return reg.test(log);
30
33
  }
31
34
  /**
@@ -0,0 +1,19 @@
1
+ import { VelaImageType } from '../typing/Vvd';
2
+ import { VelaMiwear5 } from './miwear5';
3
+ export declare class OpenSmartspeaker5 extends VelaMiwear5 {
4
+ imageType: VelaImageType;
5
+ appDir: string;
6
+ xmsInitedFlag: RegExp;
7
+ static appStartedFlag: RegExp;
8
+ /**
9
+ * 使用 pm 安装快应用
10
+ * @param targeRpk 快应用的rpk文件路径
11
+ */
12
+ install(targeRpk: string): Promise<void>;
13
+ /**
14
+ * 使用 pm 卸载快应用
15
+ * @param packageName 快应用的包名
16
+ */
17
+ uninstall(packageName: string): Promise<void>;
18
+ reloadApp(appPackageName: string): Promise<void>;
19
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.OpenSmartspeaker5 = void 0;
7
+ var _Vvd = require("../typing/Vvd");
8
+ var _utils = require("../utils");
9
+ var _miwear = require("./miwear5");
10
+ var adbMiwt = _interopRequireWildcard(require("@miwt/adb"));
11
+ var _util = require("util");
12
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
13
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
14
+ class OpenSmartspeaker5 extends _miwear.VelaMiwear5 {
15
+ imageType = (() => _Vvd.VelaImageType.OPENVELA_SMARTSPEAKER_5)();
16
+ appDir = '/data/app';
17
+ xmsInitedFlag = /AMS/;
18
+ static appStartedFlag = /Start main loop/;
19
+
20
+ /**
21
+ * 使用 pm 安装快应用
22
+ * @param targeRpk 快应用的rpk文件路径
23
+ */
24
+ async install(targeRpk) {
25
+ await this.xmsStatus.promise;
26
+ const installCmd = `adb -s ${this.sn} shell pm install ${targeRpk}`;
27
+ this.logger(`Excuting: ${installCmd}`);
28
+ const res = await adbMiwt.execAdbCmdAsync(installCmd);
29
+ await (0, _util.promisify)(process.nextTick)();
30
+ this.logger(`Install result: ${res}`);
31
+ // vela 5 安装成功的日志为:
32
+ // onInstallResult: com.application.watch.demo(success 0)
33
+ if (res.includes('(success 0)')) {
34
+ return Promise.resolve();
35
+ } else {
36
+ return Promise.reject(res);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * 使用 pm 卸载快应用
42
+ * @param packageName 快应用的包名
43
+ */
44
+ async uninstall(packageName) {
45
+ await this.xmsStatus.promise;
46
+ const res = await adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} shell pm uninstall ${packageName}`);
47
+ if (res.includes('(success 0)')) {
48
+ return Promise.resolve();
49
+ } else {
50
+ return Promise.reject(res);
51
+ }
52
+ }
53
+ async reloadApp(appPackageName) {
54
+ await this.xmsStatus.promise;
55
+ try {
56
+ // 2. 执行am stop和am start命令
57
+ const stopCmd = `adb -s ${this.sn} shell am stop ${appPackageName}`;
58
+ await adbMiwt.execAdbCmdAsync(stopCmd);
59
+ this.logger(`Stop ${this.vvdName} ${appPackageName} successfully`);
60
+ // 这里是为了等am stop命令清除资源等
61
+ await (0, _utils.sleep)(1500);
62
+ const startCmd = `adb -s ${this.sn} shell am start ${appPackageName}`;
63
+ await adbMiwt.execAdbCmdAsync(startCmd);
64
+ this.logger(`Start ${this.vvdName} ${appPackageName} successfully`);
65
+ } catch (e) {
66
+ this.logger(`${e}`);
67
+ }
68
+ }
69
+ }
70
+ exports.OpenSmartspeaker5 = OpenSmartspeaker5;
@@ -15,7 +15,7 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
15
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
16
  class Vela5Instance extends _miwear.default {
17
17
  xmsInitedFlag = /booting completed|Boot completed/;
18
- static appStartedFlag = /Start main loop/;
18
+ static appStartedFlag = /Start main loop|reportActivityStatus called by .+? \[resumed\]/;
19
19
  imageType = (() => _Vvd.VelaImageType.VELA_WATCH_5)();
20
20
  appDir = '/data/app';
21
21
 
@@ -4,9 +4,11 @@ export interface IVvdResourcePaths {
4
4
  imageHome?: string;
5
5
  }
6
6
  export declare enum IVvdArchType {
7
- arm = "arm"
7
+ arm = "arm",
8
+ arm64 = "arm64"
8
9
  }
9
10
  export declare enum VelaImageType {
11
+ OPENVELA_SMARTSPEAKER_5 = "openvela-smartspeaker-5.0",
10
12
  VELA_MIWEAR_MINISOUND_5 = "vela-miwear-minisound-5.0",
11
13
  VELA_MIWEAR_WATCH_5 = "vela-miwear-watch-5.0",
12
14
  VELA_WATCH_5 = "vela-watch-5.0",
package/lib/typing/Vvd.js CHANGED
@@ -6,9 +6,11 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.VelaImageType = exports.VELAHOME = exports.SDKParts = exports.IVvdArchType = void 0;
7
7
  let IVvdArchType = exports.IVvdArchType = /*#__PURE__*/function (IVvdArchType) {
8
8
  IVvdArchType["arm"] = "arm";
9
+ IVvdArchType["arm64"] = "arm64";
9
10
  return IVvdArchType;
10
11
  }({});
11
12
  let VelaImageType = exports.VelaImageType = /*#__PURE__*/function (VelaImageType) {
13
+ VelaImageType["OPENVELA_SMARTSPEAKER_5"] = "openvela-smartspeaker-5.0";
12
14
  VelaImageType["VELA_MIWEAR_MINISOUND_5"] = "vela-miwear-minisound-5.0";
13
15
  VelaImageType["VELA_MIWEAR_WATCH_5"] = "vela-miwear-watch-5.0";
14
16
  VelaImageType["VELA_WATCH_5"] = "vela-watch-5.0";
@@ -1,3 +1,4 @@
1
+ import 'core-js/actual/promise/with-resolvers';
1
2
  import { Readable } from 'stream';
2
3
  import { GrpcClient } from './types/GrpcClient';
3
4
  import { EmulatorConfig } from '../../emulatorutil/running';
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.GrpcEmulator = exports.AuthorizationKey = void 0;
7
7
  exports.createGrpcClient = createGrpcClient;
8
+ require("core-js/actual/promise/with-resolvers");
8
9
  var _path = _interopRequireDefault(require("path"));
9
10
  var _protoLoader = require("@grpc/proto-loader");
10
11
  var _grpcError = require("./grpcError");
@@ -1,3 +1,4 @@
1
+ import 'core-js/actual/promise/with-resolvers';
1
2
  import { IVvdParams, IVvdResourcePaths, SDKParts, SDKDownloadOpt, SkinInfo, VelaImageType } from '../typing/Vvd';
2
3
  import { IStartOptions, IStartWithSerialPort } from '../typing/Instance';
3
4
  import { EmulatorConfig } from '../emulatorutil';
package/lib/vvd/index.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.isHeadlessEnvironment = exports.VvdManager = void 0;
7
+ require("core-js/actual/promise/with-resolvers");
7
8
  var _ColorConsole = _interopRequireDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
8
9
  var _promises = _interopRequireDefault(require("fs/promises"));
9
10
  var _fs = _interopRequireDefault(require("fs"));
@@ -134,8 +135,7 @@ class VvdManager {
134
135
  if (marketName) {
135
136
  configIniJson['product.marketname'] = marketName;
136
137
  }
137
- // 默认使用 'image.sysdir.2' 自定义使用 'image.sysdir.1'
138
- configIniJson['image.sysdir.2'] = imagePath;
138
+ configIniJson['image.sysdir.1'] = imagePath;
139
139
  try {
140
140
  _fs.default.mkdirSync(vvdDir, {
141
141
  recursive: true
@@ -196,8 +196,8 @@ class VvdManager {
196
196
  vvdInfo.width = config['hw.lcd.width'];
197
197
  vvdInfo.shape = config['hw.lcd.shape'];
198
198
  vvdInfo.skin = config['skin.name'];
199
- vvdInfo.imageDir = config['image.sysdir.2'];
200
- vvdInfo.customImagePath = config['image.sysdir.1'];
199
+ vvdInfo.imageDir = config['image.sysdir.1'];
200
+ vvdInfo.customImagePath = config['ide.image.reset.sysdir'];
201
201
  vvdInfo.customLcdRadius = config['ide.lcd.radius'];
202
202
  if (config['ide.image.type']) vvdInfo.imageType = config['ide.image.type'];
203
203
  if (vvdInfo.skin) {
@@ -321,6 +321,7 @@ class VvdManager {
321
321
  const configIni = _path.default.resolve(currVvdDir, 'config.ini');
322
322
  const contents = _fs.default.readFileSync(configIni, 'utf-8');
323
323
  const config = (0, _ini.parse)(contents);
324
+ config['ide.image.reset.sysdir'] = config['image.sysdir.1'];
324
325
  config['image.sysdir.1'] = target;
325
326
  await _fs.default.promises.writeFile(configIni, (0, _ini.stringify)(config));
326
327
  const defaultImageHome = config['image.sysdir.1'];
@@ -350,8 +351,7 @@ class VvdManager {
350
351
  const config = (0, _ini.parse)(contents);
351
352
  const home = this.getSDKPart(_Vvd.SDKParts.SYSTEM_IMAGES);
352
353
  let imageDir = _path.default.resolve(home, config['ide.image.type']);
353
- config['image.sysdir.2'] = imageDir;
354
- delete config['image.sysdir.1'];
354
+ config['image.sysdir.1'] = imageDir;
355
355
  _fs.default.writeFileSync(configIni, (0, _ini.stringify)(config));
356
356
  }
357
357
  getEmulatorBinPath(sdkHome) {
@@ -421,6 +421,18 @@ class VvdManager {
421
421
  needUpdate = true;
422
422
  config['image.sysdir.2'] = normalizePath(config['image.sysdir.2'].toString()).replace('.export_dev/system-images', '.vela/sdk/system-images');
423
423
  }
424
+
425
+ // 不在使用 'image.sysdir.2' 字段,统一使用 'ide.image.reset.sysdir'
426
+ if (config['image.sysdir.2']) {
427
+ needUpdate = true;
428
+ const oldVal = config['image.sysdir.2'];
429
+ // TODO delete 会造成 image.sysdir.2= 留下一个空值
430
+ delete config['image.sysdir.2'];
431
+ if (config['image.sysdir.1']) {
432
+ config['ide.image.reset.sysdir'] = config['image.sysdir.1'];
433
+ }
434
+ config['image.sysdir.1'] = oldVal;
435
+ }
424
436
  if (needUpdate) {
425
437
  await _promises.default.writeFile(configIni, (0, _ini.stringify)(config));
426
438
  _ColorConsole.default.log(`update ${vvdName} config.ini`);
@@ -439,7 +451,7 @@ class VvdManager {
439
451
  length: 100
440
452
  }).map((_, i) => 10055 + i)
441
453
  }));
442
- let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${degbugProt}-10.0.2.15:101`;
454
+ let portMappingStr = '';
443
455
 
444
456
  // qemu 配置
445
457
  const HOST_9PFS_DIR = _path.default.join(vvdDir, 'share');
@@ -455,7 +467,7 @@ class VvdManager {
455
467
  // -fsdev local,security_model=none,id=fsdev0,path=${HOST_9PFS_DIR} \
456
468
  // -device virtio-9p-device,id=fs0,fsdev=fsdev0,mount_tag=host `
457
469
 
458
- const qemuOption = `-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting -smp 2`;
470
+ let qemuOption = `-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting -smp 2`;
459
471
 
460
472
  // qt windows 配置
461
473
  // 在 docker,wls,等无界面平台上用 -no-window ,否则用 -qt-hide-window
@@ -474,9 +486,19 @@ class VvdManager {
474
486
  }
475
487
  const verboseOption = options.verbose ? `-verbose` : ``;
476
488
  // 启动模拟器的命令和参数
477
- const cmd = `${emulatorBin} -vela -avd ${options.vvdName} ${serialStr} -show-kernel ${portMappingStr} ${windowOption} ${grpcStr} ${verboseOption} -qemu ${qemuOption}`;
478
- const vvdInfo = this.getVvdInfo(vvdName);
489
+
479
490
  await this.oldEmulatorMigrate(vvdName);
491
+ const vvdInfo = this.getVvdInfo(vvdName);
492
+
493
+ // vela4 系列或未指定 imageType 时需要端口转发
494
+ const v4Types = [_Vvd.VelaImageType.REL, _Vvd.VelaImageType.PRE, _Vvd.VelaImageType.DEV];
495
+ if (!vvdInfo.imageType || v4Types.includes(vvdInfo.imageType)) {
496
+ portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${degbugProt}-10.0.2.15:101`;
497
+ }
498
+ if (vvdInfo.imageType === _Vvd.VelaImageType.OPENVELA_SMARTSPEAKER_5) {
499
+ qemuOption = `-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting -smp 4 -device virtio-gpu-device,xres=480,yres=800,bus=virtio-mmio-bus.5`;
500
+ }
501
+ const cmd = `${emulatorBin} -vela -avd ${options.vvdName} ${serialStr} -show-kernel ${portMappingStr} ${windowOption} ${grpcStr} ${verboseOption} -qemu ${qemuOption}`;
480
502
  const imageDir = vvdInfo.customImagePath || vvdInfo.imageDir;
481
503
  if (!imageDir) {
482
504
  const errMsg = `${vvdName} is not supported`;
@@ -540,6 +562,9 @@ class VvdManager {
540
562
  timeout: 3000,
541
563
  encoding: 'utf-8'
542
564
  });
565
+ if (res.includes('miim-arm64')) {
566
+ return _Vvd.VelaImageType.OPENVELA_SMARTSPEAKER_5;
567
+ }
543
568
  if (res.includes('miwear')) {
544
569
  return _Vvd.VelaImageType.VELA_MIWEAR_WATCH_5;
545
570
  }
@@ -600,7 +625,7 @@ class VvdManager {
600
625
  // 利用 readline 接口可解决子进程日志换行的问题
601
626
  const readlines = (0, _logcat.attachReadline)(emulatorProcess, onStdout, onErrout);
602
627
  const emulatorStartedHandler = async msg => {
603
- if (msg.includes('INFO | Boot completed')) {
628
+ if (msg.includes('INFO | Boot completed') || msg.includes('[AMS]')) {
604
629
  const e = (0, _emulatorutil.getRunningAvdConfigByName)(vvdName);
605
630
  if (e) {
606
631
  const imageType = await getImageType(e['port.serial']);
@@ -617,9 +642,8 @@ class VvdManager {
617
642
  readlines.stdoutReadline.off('line', emulatorStartedHandler);
618
643
  const velaAgent = (0, _grpc.createGrpcClient)(e);
619
644
  await velaAgent.waitForReady();
620
- if (imageType.includes('miwear')) {
645
+ if ([_Vvd.VelaImageType.VELA_MIWEAR_WATCH_5, _Vvd.VelaImageType.REL].includes(imageType)) {
621
646
  // 这个时候系统启动成功了,但是 rpk 安装程序还没准备好
622
-
623
647
  const miwearXmsReadyHander = msg => {
624
648
  const startedFunc = emulatorInstance.isXmsInited.bind(emulatorInstance);
625
649
  if (startedFunc(msg)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiot-toolkit/emulator",
3
- "version": "2.0.6-beta.9",
3
+ "version": "2.1.0-prender.1",
4
4
  "description": "vela emulator tool.",
5
5
  "homepage": "",
6
6
  "license": "ISC",
@@ -32,22 +32,26 @@
32
32
  "emulator"
33
33
  ],
34
34
  "dependencies": {
35
- "@aiot-toolkit/shared-utils": "2.0.6-beta.9",
35
+ "@aiot-toolkit/shared-utils": "2.1.0-prender.1",
36
36
  "@grpc/grpc-js": "^1.13.3",
37
37
  "@grpc/proto-loader": "^0.7.13",
38
38
  "@miwt/adb": "0.10.5",
39
39
  "adm-zip": "^0.5.16",
40
+ "aedes": "^0.51.3",
41
+ "aedes-persistence": "^10.0.0",
42
+ "core-js": "^3.48.0",
40
43
  "dayjs": "^1.11.12",
41
44
  "find-process": "^1.4.7",
42
45
  "get-port": "^7.1.0",
43
46
  "ini": "^4.1.3",
44
47
  "ipull": "^3.6.2",
45
48
  "portfinder": "^1.0.32",
49
+ "selfsigned": "^3.0.1",
46
50
  "semver": "^7.6.3"
47
51
  },
48
52
  "devDependencies": {
49
53
  "@types/adm-zip": "^0.5.5",
50
54
  "@types/ini": "^4.1.1"
51
55
  },
52
- "gitHead": "18718f09f1ee7f1d7361022c5fb7858c87cee2bd"
56
+ "gitHead": "8bb39a59fbe7a7c22c1167e69d44c78024330cec"
53
57
  }