@aiot-toolkit/emulator 2.0.6-beta.8 → 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.
- package/lib/broker/index.d.ts +21 -0
- package/lib/broker/index.js +98 -0
- package/lib/emulatorutil/constants.js +16 -17
- package/lib/index.d.ts +1 -0
- package/lib/index.js +12 -0
- package/lib/instance/common.d.ts +1 -0
- package/lib/instance/common.js +1 -0
- package/lib/instance/index.d.ts +2 -1
- package/lib/instance/index.js +3 -1
- package/lib/instance/minisound.js +1 -1
- package/lib/instance/miwear.d.ts +1 -0
- package/lib/instance/miwear.js +4 -1
- package/lib/instance/openSmartspeaker5.d.ts +19 -0
- package/lib/instance/openSmartspeaker5.js +70 -0
- package/lib/instance/vela5.js +1 -1
- package/lib/typing/Vvd.d.ts +3 -1
- package/lib/typing/Vvd.js +2 -0
- package/lib/vvd/grpc/index.d.ts +1 -0
- package/lib/vvd/grpc/index.js +1 -0
- package/lib/vvd/index.d.ts +1 -0
- package/lib/vvd/index.js +37 -13
- package/package.json +7 -3
|
@@ -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
|
|
55
|
-
|
|
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
|
|
72
|
+
label: 'vela-miwear-watch-5',
|
|
81
73
|
description: '适用于手表/手环的,带表盘的 vela 5.0 镜像,不可自定义模拟器尺寸',
|
|
82
74
|
value: _Vvd.VelaImageType.VELA_MIWEAR_WATCH_5,
|
|
83
|
-
time: '
|
|
75
|
+
time: '20260130',
|
|
84
76
|
hide: false,
|
|
85
77
|
icon: ''
|
|
86
78
|
}, {
|
|
87
|
-
label: 'vela-watch-5
|
|
79
|
+
label: 'vela-watch-5',
|
|
88
80
|
description: '适用于手表/手环的,不带表盘的 vela 5.0 镜像,可自定义模拟器尺寸',
|
|
89
81
|
value: _Vvd.VelaImageType.VELA_WATCH_5,
|
|
90
|
-
time: '
|
|
82
|
+
time: '20260422',
|
|
91
83
|
hide: false,
|
|
92
84
|
icon: ''
|
|
93
85
|
}, {
|
|
94
|
-
label: 'vela-miwear-watch-4
|
|
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
|
|
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
|
|
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
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;
|
package/lib/instance/common.d.ts
CHANGED
package/lib/instance/common.js
CHANGED
|
@@ -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"));
|
package/lib/instance/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
package/lib/instance/index.js
CHANGED
|
@@ -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 = /
|
|
16
|
+
xmsInitedFlag = /AMS/;
|
|
17
17
|
static appStartedFlag = /Start main loop/;
|
|
18
18
|
|
|
19
19
|
/**
|
package/lib/instance/miwear.d.ts
CHANGED
|
@@ -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;
|
package/lib/instance/miwear.js
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/lib/instance/vela5.js
CHANGED
|
@@ -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
|
|
package/lib/typing/Vvd.d.ts
CHANGED
|
@@ -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";
|
package/lib/vvd/grpc/index.d.ts
CHANGED
package/lib/vvd/grpc/index.js
CHANGED
|
@@ -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");
|
package/lib/vvd/index.d.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
200
|
-
vvdInfo.customImagePath = config['image.sysdir
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
|
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
|
|
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": "
|
|
56
|
+
"gitHead": "8bb39a59fbe7a7c22c1167e69d44c78024330cec"
|
|
53
57
|
}
|