@webos-tools/cli 3.0.6 → 3.1.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/.eslintignore +1 -1
- package/.eslintrc.js +52 -52
- package/APIs.js +79 -79
- package/CHANGELOG.md +157 -138
- package/LICENSE +201 -201
- package/README.md +218 -218
- package/bin/ares-config.js +199 -199
- package/bin/ares-device-info.js +30 -30
- package/bin/ares-device.js +219 -219
- package/bin/ares-generate.js +274 -270
- package/bin/ares-inspect.js +179 -179
- package/bin/ares-install.js +223 -223
- package/bin/ares-launch.js +318 -318
- package/bin/ares-log.js +255 -255
- package/bin/ares-novacom.js +220 -223
- package/bin/ares-package.js +336 -336
- package/bin/ares-pull.js +156 -156
- package/bin/ares-push.js +155 -155
- package/bin/ares-server.js +174 -174
- package/bin/ares-setup-device.js +528 -520
- package/bin/ares-shell.js +132 -132
- package/bin/ares.js +166 -166
- package/files/conf/ares.json +49 -49
- package/files/conf/command-service.json +73 -73
- package/files/conf/config.json +31 -22
- package/files/conf/ipk.json +30 -30
- package/files/conf/novacom-devices.json +35 -35
- package/files/conf/query/query-app.json +14 -14
- package/files/conf/query/query-hosted.json +18 -18
- package/files/conf/query/query-package.json +10 -10
- package/files/conf/query/query-service.json +6 -6
- package/files/conf/sdk.json +8 -8
- package/files/conf/template.json +57 -57
- package/files/conf/webos_emul +27 -27
- package/files/conf-base/env/sdk-ose.json +8 -8
- package/files/conf-base/env/sdk-tv.json +8 -8
- package/files/conf-base/profile/config-ose.json +29 -21
- package/files/conf-base/profile/config-tv.json +31 -22
- package/files/conf-base/query/query-app.json +14 -14
- package/files/conf-base/query/query-hosted.json +18 -18
- package/files/conf-base/query/query-package.json +10 -10
- package/files/conf-base/query/query-service.json +6 -6
- package/files/conf-base/template-conf/ose-templates.json +67 -67
- package/files/conf-base/template-conf/tv-sdk-templates.json +57 -57
- package/files/help/ares-config.help +43 -43
- package/files/help/ares-device.help +94 -94
- package/files/help/ares-generate.help +65 -65
- package/files/help/ares-inspect.help +70 -70
- package/files/help/ares-install.help +90 -90
- package/files/help/ares-launch.help +100 -100
- package/files/help/ares-log-pmlogd.help +84 -84
- package/files/help/ares-log.help +101 -101
- package/files/help/ares-novacom.help +68 -68
- package/files/help/ares-package.help +101 -101
- package/files/help/ares-pull.help +38 -38
- package/files/help/ares-push.help +38 -38
- package/files/help/ares-server.help +39 -39
- package/files/help/ares-setup-device.help +116 -75
- package/files/help/ares-shell.help +42 -42
- package/files/help/ares.help +47 -47
- package/files/help/readme.help +23 -23
- package/files/schema/ApplicationDescription.schema +319 -319
- package/files/schema/NovacomDevices.schema +61 -61
- package/files/templates/ose-sdk-templates/appinfo/appinfo.json +10 -10
- package/files/templates/ose-sdk-templates/bootplate-web/index.html +88 -88
- package/files/templates/ose-sdk-templates/hosted-webapp/index.html +13 -13
- package/files/templates/ose-sdk-templates/icon/icon.png +0 -0
- package/files/templates/ose-sdk-templates/js-service/helloclient.js +31 -31
- package/files/templates/ose-sdk-templates/js-service/helloworld_webos_service.js +188 -188
- package/files/templates/ose-sdk-templates/qml-app/main.qml +68 -68
- package/files/templates/ose-sdk-templates/qmlappinfo/appinfo.json +10 -10
- package/files/templates/ose-sdk-templates/serviceinfo/package.json +11 -11
- package/files/templates/ose-sdk-templates/serviceinfo/services.json +8 -8
- package/files/templates/tv-sdk-templates/appinfo/appinfo.json +10 -10
- package/files/templates/tv-sdk-templates/bootplate-web/index.html +58 -58
- package/files/templates/tv-sdk-templates/bootplate-web/webOSTVjs-1.2.10/LICENSE-2.0.txt +202 -202
- package/files/templates/tv-sdk-templates/hosted-webapp/index.html +14 -14
- package/files/templates/tv-sdk-templates/js-service/helloworld_service.js +39 -39
- package/files/templates/tv-sdk-templates/packageinfo/packageinfo.json +3 -3
- package/files/templates/tv-sdk-templates/serviceinfo/package.json +11 -11
- package/files/templates/tv-sdk-templates/serviceinfo/services.json +8 -8
- package/files/templates/tv-sdk-templates/webicon/icon.png +0 -0
- package/files/templates/tv-sdk-templates/webicon/largeIcon.png +0 -0
- package/lib/base/ares.html +40 -40
- package/lib/base/cli-appdata.js +290 -290
- package/lib/base/cli-control.js +44 -44
- package/lib/base/common-tools.js +29 -29
- package/lib/base/error-handler.js +265 -265
- package/lib/base/file-watcher.js +155 -155
- package/lib/base/help-format.js +147 -147
- package/lib/base/luna.js +178 -178
- package/lib/base/novacom.js +1202 -1191
- package/lib/base/sdkenv.js +59 -59
- package/lib/base/server.js +137 -137
- package/lib/base/setup-device.js +335 -328
- package/lib/base/version-tools.js +79 -79
- package/lib/device.js +1419 -1419
- package/lib/generator.js +377 -377
- package/lib/inspect.js +493 -494
- package/lib/install.js +463 -463
- package/lib/launch.js +605 -605
- package/lib/log.js +584 -584
- package/lib/package.js +2147 -2129
- package/lib/pull.js +231 -231
- package/lib/pusher.js +210 -210
- package/lib/session.js +74 -74
- package/lib/shell.js +193 -193
- package/lib/tar-filter-pack.js +62 -62
- package/lib/util/copy.js +31 -31
- package/lib/util/createFileName.js +40 -40
- package/lib/util/eof.js +30 -30
- package/lib/util/json.js +63 -63
- package/lib/util/merge.js +14 -14
- package/lib/util/objclone.js +40 -40
- package/lib/util/spinner.js +37 -37
- package/npm-shrinkwrap.json +9242 -9116
- package/package.json +100 -100
- package/scripts/postinstall.js +24 -24
- package/spec/helpers/reporter.js +65 -65
- package/spec/jsSpecs/apiTest/generator.spec.js +372 -372
- package/spec/jsSpecs/apiTest/inspector.spec.js +89 -89
- package/spec/jsSpecs/apiTest/installer.spec.js +67 -67
- package/spec/jsSpecs/apiTest/launcher.spec.js +150 -150
- package/spec/jsSpecs/apiTest/packager.spec.js +194 -194
- package/spec/jsSpecs/apiTest/puller.spec.js +101 -101
- package/spec/jsSpecs/apiTest/pusher.spec.js +103 -103
- package/spec/jsSpecs/apiTest/server.spec.js +115 -115
- package/spec/jsSpecs/apiTest/setupDevice.spec.js +93 -93
- package/spec/jsSpecs/apiTest/shell.spec.js +49 -49
- package/spec/jsSpecs/ares-config.spec.js +78 -78
- package/spec/jsSpecs/ares-device.spec.js +443 -443
- package/spec/jsSpecs/ares-generate.spec.js +397 -397
- package/spec/jsSpecs/ares-inspect.spec.js +252 -252
- package/spec/jsSpecs/ares-install.spec.js +150 -150
- package/spec/jsSpecs/ares-launch.spec.js +301 -301
- package/spec/jsSpecs/ares-log.spec.js +824 -824
- package/spec/jsSpecs/ares-novacom.spec.js +149 -149
- package/spec/jsSpecs/ares-package.spec.js +1211 -1211
- package/spec/jsSpecs/ares-pull.spec.js +157 -157
- package/spec/jsSpecs/ares-push.spec.js +146 -146
- package/spec/jsSpecs/ares-server.spec.js +160 -160
- package/spec/jsSpecs/ares-setup-device.spec.js +300 -281
- package/spec/jsSpecs/ares-shell.spec.js +220 -220
- package/spec/jsSpecs/ares.spec.js +83 -83
- package/spec/jsSpecs/common-spec.js +169 -169
- package/spec/support/jasmine.json +22 -22
- package/spec/tempFiles/nativeApp/auto/pkg_arm64/GLES2 +0 -0
- package/spec/tempFiles/nativeApp/auto/pkg_arm64/appinfo.json +9 -9
- package/spec/tempFiles/nativeApp/ose/pkg_arm/Hello +0 -0
- package/spec/tempFiles/nativeApp/ose/pkg_arm/appinfo.json +8 -8
- package/spec/tempFiles/nativeApp/ose/pkg_arm/package.properties +2 -2
- package/spec/tempFiles/nativeApp/oseEmul/pkg_x86/Hello +0 -0
- package/spec/tempFiles/nativeApp/oseEmul/pkg_x86/appinfo.json +9 -9
- package/spec/tempFiles/nativeApp/rsi/pkg_x86/GLES2 +0 -0
- package/spec/tempFiles/nativeApp/rsi/pkg_x86/appinfo.json +9 -9
- package/spec/tempFiles/sign/sign.crt +32 -32
- package/spec/tempFiles/sign/signPriv.key +52 -52
- package/spec/test_data/ares-generate.json +41 -41
- package/spec/test_data/ares.json +33 -33
package/lib/launch.js
CHANGED
|
@@ -1,605 +1,605 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2020-2024 LG Electronics Inc.
|
|
3
|
-
*
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const async = require('async'),
|
|
8
|
-
chalk = require('chalk'),
|
|
9
|
-
exec = require('child_process').exec,
|
|
10
|
-
fs = require('fs'),
|
|
11
|
-
npmlog = require('npmlog'),
|
|
12
|
-
os = require('os'),
|
|
13
|
-
path = require('path'),
|
|
14
|
-
semver = require('semver'),
|
|
15
|
-
util = require('util'),
|
|
16
|
-
fileWatcher = require('./base/file-watcher'),
|
|
17
|
-
inspector = require('./inspect'),
|
|
18
|
-
installer = require('./install'),
|
|
19
|
-
sessionLib = require('./session'),
|
|
20
|
-
commonTools = require('./base/common-tools'),
|
|
21
|
-
errHndl = require('./base/error-handler'),
|
|
22
|
-
luna = require('./base/luna'),
|
|
23
|
-
novacom = require('./base/novacom'),
|
|
24
|
-
spinner = require('./util/spinner');
|
|
25
|
-
|
|
26
|
-
const appdata = commonTools.appdata,
|
|
27
|
-
sdkenv = commonTools.sdkenv;
|
|
28
|
-
|
|
29
|
-
(function() {
|
|
30
|
-
const log = npmlog;
|
|
31
|
-
log.heading = 'launcher';
|
|
32
|
-
log.level = 'warn';
|
|
33
|
-
|
|
34
|
-
const launcher = {
|
|
35
|
-
/**
|
|
36
|
-
* @property {Object} log an npm log instance
|
|
37
|
-
*/
|
|
38
|
-
log: log,
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Launch the given application id
|
|
42
|
-
* @param {Object} options
|
|
43
|
-
* @property options {String} device the device to connect to
|
|
44
|
-
* @property options {Boolean} inspect run the application with web-inspector turned on
|
|
45
|
-
*/
|
|
46
|
-
launch: function(options, id, params, next, middleCb) {
|
|
47
|
-
if (typeof next !== 'function') {
|
|
48
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
49
|
-
}
|
|
50
|
-
const self = this,
|
|
51
|
-
hostedAppId = "com.sdk.ares.hostedapp";
|
|
52
|
-
let hostedAppInstalled = false;
|
|
53
|
-
options = options || {};
|
|
54
|
-
|
|
55
|
-
async.series([
|
|
56
|
-
_checkInstalledApp,
|
|
57
|
-
_checkRunningApp,
|
|
58
|
-
_installHostedApp,
|
|
59
|
-
_makeSession,
|
|
60
|
-
_runAppServer,
|
|
61
|
-
_setAppServerInfo,
|
|
62
|
-
_getSessionList,
|
|
63
|
-
_checkDisplayAffinity,
|
|
64
|
-
_launch,
|
|
65
|
-
_runFileWatcher,
|
|
66
|
-
_runInspector
|
|
67
|
-
], function(err, results) {
|
|
68
|
-
log.silly("launch#launch()", "err:", err, ", results:", results);
|
|
69
|
-
const result = results[8];
|
|
70
|
-
if (!err) {
|
|
71
|
-
if (options.installMode !== "Hosted") {
|
|
72
|
-
result.msg = "Launched application " + id;
|
|
73
|
-
if (self.displayId !== undefined) {
|
|
74
|
-
result.msg += " on display " + self.displayId;
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
options.session = null;
|
|
78
|
-
options.printTarget = false;
|
|
79
|
-
self.close(options, hostedAppId, params, next);
|
|
80
|
-
result.msg = "";
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
next(err, result);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
function _checkInstalledApp(next) {
|
|
88
|
-
if (options.installMode === "Hosted") {
|
|
89
|
-
installer.list(options, function(err, result) {
|
|
90
|
-
for (const index in result) {
|
|
91
|
-
if (result[index].id === hostedAppId) {
|
|
92
|
-
hostedAppInstalled = true;
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
next(err);
|
|
97
|
-
});
|
|
98
|
-
} else {
|
|
99
|
-
next();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function _checkRunningApp(next) {
|
|
104
|
-
if (options.installMode === "Hosted") {
|
|
105
|
-
self.listRunningApp(options, function(err, result) {
|
|
106
|
-
for (const index in result) {
|
|
107
|
-
if (result[index].id === hostedAppId) {
|
|
108
|
-
self.close(options, hostedAppId, params, next);
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
next(err);
|
|
113
|
-
});
|
|
114
|
-
} else {
|
|
115
|
-
next();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function _installHostedApp(next) {
|
|
120
|
-
if (options.installMode === "Hosted" && !hostedAppInstalled) {
|
|
121
|
-
const hostedAppUrl = path.join(__dirname, hostedAppId + ".ipk");
|
|
122
|
-
options.appId = id;
|
|
123
|
-
installer.install(options, hostedAppUrl, next, function(value) {
|
|
124
|
-
middleCb(value);
|
|
125
|
-
});
|
|
126
|
-
} else {
|
|
127
|
-
next();
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function _makeSession(next) {
|
|
132
|
-
makeSession(options, next);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function _runAppServer(next) {
|
|
136
|
-
if (options.installMode === "Hosted") {
|
|
137
|
-
options.session.runHostedAppServer(options.hostedurl, next);
|
|
138
|
-
spinner.stop();
|
|
139
|
-
middleCb("Ares Hosted App is now running...");
|
|
140
|
-
} else {
|
|
141
|
-
next();
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function _setAppServerInfo(next) {
|
|
146
|
-
if (options.installMode === "Hosted") {
|
|
147
|
-
if (options.hostIp) {
|
|
148
|
-
options.localIP = options.hostIp;
|
|
149
|
-
} else {
|
|
150
|
-
const networkInterfaces = os.networkInterfaces();
|
|
151
|
-
let localIP = "";
|
|
152
|
-
|
|
153
|
-
for (const devName in networkInterfaces) {
|
|
154
|
-
for (let index = 0; index < networkInterfaces[devName].length; index++) {
|
|
155
|
-
const alias = networkInterfaces[devName][index];
|
|
156
|
-
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
|
|
157
|
-
localIP = localIP || alias.address;
|
|
158
|
-
options.localIP = localIP;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
const port = options.session.getHostedAppServerPort();
|
|
164
|
-
if (params === null) {
|
|
165
|
-
params = {};
|
|
166
|
-
}
|
|
167
|
-
params.hostedurl = "http://" + options.localIP + ":" + port + "/";
|
|
168
|
-
}
|
|
169
|
-
next();
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function _getSessionList(next) {
|
|
173
|
-
sessionLib.getSessionList(options, next);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function _checkDisplayAffinity(next) {
|
|
177
|
-
checkDisplayAffinity(options, params, next);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function _launch(next) {
|
|
181
|
-
const target = options.session.getDevice(),
|
|
182
|
-
addr = target.lunaAddr.launch,
|
|
183
|
-
returnValue = addr.returnValue.split('.'),
|
|
184
|
-
param = {
|
|
185
|
-
// luna param
|
|
186
|
-
id: id,
|
|
187
|
-
subscribe: false,
|
|
188
|
-
params: params
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
luna.send(options, addr, param, function(lineObj, next) {
|
|
192
|
-
let resultValue = lineObj;
|
|
193
|
-
|
|
194
|
-
for (let index = 1; index < returnValue.length; index++) {
|
|
195
|
-
resultValue = resultValue[returnValue[index]];
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (resultValue) {
|
|
199
|
-
// success: stop
|
|
200
|
-
log.verbose("launch#launch()#_launch()", "success");
|
|
201
|
-
|
|
202
|
-
// If sam returns "displayId" show displayId in result msg
|
|
203
|
-
if (lineObj.displayId !== undefined) {
|
|
204
|
-
self.displayId = lineObj.displayId;
|
|
205
|
-
}
|
|
206
|
-
next(null, {procId: resultValue});
|
|
207
|
-
} else {
|
|
208
|
-
// failure: stop
|
|
209
|
-
log.verbose("launch#launch()#_launch()", "failure");
|
|
210
|
-
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
211
|
-
}
|
|
212
|
-
}, next);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function _runFileWatcher(next) {
|
|
216
|
-
if (options.installMode === "Hosted") {
|
|
217
|
-
log.verbose("launcher#launch#_runFileWatcher()");
|
|
218
|
-
options.appId = id;
|
|
219
|
-
fileWatcher.watch(options, params);
|
|
220
|
-
next();
|
|
221
|
-
} else {
|
|
222
|
-
next();
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function _runInspector(next) {
|
|
227
|
-
if (options.inspect) {
|
|
228
|
-
options.appId = id;
|
|
229
|
-
options.running = true;
|
|
230
|
-
|
|
231
|
-
async.series([
|
|
232
|
-
inspector.inspect.bind(inspector, options, null),
|
|
233
|
-
function() {
|
|
234
|
-
// TODO: hold process to keep alive
|
|
235
|
-
}
|
|
236
|
-
], function(err) {
|
|
237
|
-
next(err);
|
|
238
|
-
});
|
|
239
|
-
} else if (options.installMode === "Hosted") {
|
|
240
|
-
process.on("SIGINT", function() {
|
|
241
|
-
log.verbose("launcher#launch#_runInspector():", "SIGINT is detected in Hosted mode");
|
|
242
|
-
next();
|
|
243
|
-
});
|
|
244
|
-
} else {
|
|
245
|
-
next();
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
/**
|
|
250
|
-
* Close the given application id
|
|
251
|
-
* @param {Object} options
|
|
252
|
-
* @property options {String} device the device to connect to
|
|
253
|
-
* @property options {Boolean} inspect run the application with web-inspector turned on
|
|
254
|
-
*/
|
|
255
|
-
close: function(options, id, params, next) {
|
|
256
|
-
if (typeof next !== 'function') {
|
|
257
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
258
|
-
}
|
|
259
|
-
const self = this;
|
|
260
|
-
options = options || {};
|
|
261
|
-
|
|
262
|
-
async.series([
|
|
263
|
-
_makeSession,
|
|
264
|
-
_getSessionList,
|
|
265
|
-
_checkDisplayAffinity,
|
|
266
|
-
_close
|
|
267
|
-
], function(err, results) {
|
|
268
|
-
log.silly("launch#close()", "err:", err, ", results:", results);
|
|
269
|
-
// 2 steps in async.series, we want to
|
|
270
|
-
// the value returned by the second
|
|
271
|
-
// step (index=1)
|
|
272
|
-
const result = results[3];
|
|
273
|
-
if (result) {
|
|
274
|
-
if (options.installMode !== "Hosted") {
|
|
275
|
-
result.msg = "Closed application " + id;
|
|
276
|
-
if (self.displayId !== undefined) {
|
|
277
|
-
result.msg += " on display " + self.displayId;
|
|
278
|
-
}
|
|
279
|
-
} else {
|
|
280
|
-
result.msg = "...Closed Ares Hosted App";
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
next(err, result);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
function _makeSession(next) {
|
|
287
|
-
makeSession(options, next);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function _getSessionList(next) {
|
|
291
|
-
sessionLib.getSessionList(options, next);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
function _checkDisplayAffinity(next) {
|
|
295
|
-
checkDisplayAffinity(options, params, next);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function _close(next) {
|
|
299
|
-
const target = options.session.getDevice(),
|
|
300
|
-
addr = target.lunaAddr.terminate,
|
|
301
|
-
returnValue = addr.returnValue.split('.'),
|
|
302
|
-
param = {
|
|
303
|
-
// luna param
|
|
304
|
-
id: id,
|
|
305
|
-
subscribe: false,
|
|
306
|
-
params: params
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
luna.send(options, addr, param, function(lineObj, next) {
|
|
310
|
-
let resultValue = lineObj;
|
|
311
|
-
|
|
312
|
-
for (let index = 1; index < returnValue.length; index++) {
|
|
313
|
-
resultValue = resultValue[returnValue[index]];
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (resultValue) {
|
|
317
|
-
// success: stop
|
|
318
|
-
log.verbose("launch#close()#_close()", "success");
|
|
319
|
-
|
|
320
|
-
// If sam returns "displayId" show displayId in result msg
|
|
321
|
-
if (lineObj.displayId !== undefined) {
|
|
322
|
-
self.displayId = lineObj.displayId;
|
|
323
|
-
}
|
|
324
|
-
next(null, {procId: resultValue});
|
|
325
|
-
} else {
|
|
326
|
-
// failure: stop
|
|
327
|
-
log.verbose("launch#close()#_close()", "failure");
|
|
328
|
-
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
329
|
-
}
|
|
330
|
-
}, next);
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* list the running applications
|
|
336
|
-
* @param {Object} options
|
|
337
|
-
* @property options {String} device the device to connect to
|
|
338
|
-
* @property options {Boolean} inspect run the application with web-inspector turned on
|
|
339
|
-
*/
|
|
340
|
-
listRunningApp: function(options, next) {
|
|
341
|
-
if (typeof next !== 'function') {
|
|
342
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
options = options || {};
|
|
346
|
-
async.series([
|
|
347
|
-
_makeSession,
|
|
348
|
-
_getSessionList,
|
|
349
|
-
_listRunningApp
|
|
350
|
-
], function(err, results) {
|
|
351
|
-
log.silly("launch#listRunningApp()", "err:", err, ", results:", results);
|
|
352
|
-
next(err, results[2]);
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
function _makeSession(next) {
|
|
356
|
-
makeSession(options, next);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function _getSessionList(next) {
|
|
360
|
-
sessionLib.getSessionList(options, next);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
function _listRunningApp(next) {
|
|
364
|
-
const target = options.session.getDevice(),
|
|
365
|
-
addr = target.lunaAddr.running,
|
|
366
|
-
returnValue = addr.returnValue.split('.'),
|
|
367
|
-
param = {
|
|
368
|
-
// luna param
|
|
369
|
-
subscribe: false
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
if (!addr || !returnValue) {
|
|
373
|
-
return next(errHndl.getErrMsg("NOT_SUPPORT_RUNNINGLIST"));
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
luna.send(options, addr, param, function(lineObj, next) {
|
|
377
|
-
let resultValue = lineObj;
|
|
378
|
-
|
|
379
|
-
for (let index = 1; index < returnValue.length; index++) {
|
|
380
|
-
resultValue = resultValue[returnValue[index]];
|
|
381
|
-
}
|
|
382
|
-
resultValue = resultValue || [];
|
|
383
|
-
|
|
384
|
-
if (lineObj.returnValue) {
|
|
385
|
-
// success: stop
|
|
386
|
-
log.verbose("launch#listRunningApp()", "success");
|
|
387
|
-
next(null, resultValue);
|
|
388
|
-
} else {
|
|
389
|
-
// failure: stop
|
|
390
|
-
log.verbose("launch#listRunningApp()", "failure");
|
|
391
|
-
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
392
|
-
}
|
|
393
|
-
}, next);
|
|
394
|
-
}
|
|
395
|
-
},
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Launch the given application directory to the simulator
|
|
399
|
-
* @param {Object} options
|
|
400
|
-
* @property options {String} simulator the webOS TV version of simulator to launch
|
|
401
|
-
* @param {String} appDir the path of application directory
|
|
402
|
-
* @param {Object} params parameters to launch with
|
|
403
|
-
*/
|
|
404
|
-
launchSimulator: function(options, appDir, params, next, middleCb) {
|
|
405
|
-
if (typeof next !== 'function') {
|
|
406
|
-
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
options = options || {};
|
|
410
|
-
options.simulatorPrefix = `webOS_TV_${options.simulator}_Simulator`;
|
|
411
|
-
async.waterfall([
|
|
412
|
-
_checkSimulatorConfig,
|
|
413
|
-
_checkEnvPath,
|
|
414
|
-
_checkSimulatorDirectory,
|
|
415
|
-
_findSimulatorVersion,
|
|
416
|
-
_launchSimulator
|
|
417
|
-
], function(err, results) {
|
|
418
|
-
next(err, results);
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
function _checkSimulatorConfig(next) {
|
|
422
|
-
const configPath = appdata.getSimulatorConfigPath();
|
|
423
|
-
let cofigData = {};
|
|
424
|
-
|
|
425
|
-
if (fs.existsSync(configPath)) {
|
|
426
|
-
cofigData = JSON.parse(fs.readFileSync(configPath));
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (options.simulatorPath) {
|
|
430
|
-
cofigData[options.simulator] = options.simulatorPath;
|
|
431
|
-
try {
|
|
432
|
-
fs.writeFileSync(configPath, JSON.stringify(cofigData, null, Number(4)) + "\n");
|
|
433
|
-
} catch(err) {
|
|
434
|
-
next(err, null);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
Object.keys(cofigData).forEach(function(version) {
|
|
439
|
-
if (version === options.simulator) {
|
|
440
|
-
options.simulatorDir = cofigData[options.simulator];
|
|
441
|
-
}
|
|
442
|
-
});
|
|
443
|
-
next(null, options.simulatorDir);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function _checkEnvPath(simulatorDir, next) {
|
|
447
|
-
log.silly("launcher#launchSimulator#_checkEnvPath():", "simulatorDir:", simulatorDir);
|
|
448
|
-
if (!simulatorDir) {
|
|
449
|
-
sdkenv.getEnvValue("SDK", function(err, sdkHomePath) {
|
|
450
|
-
if (sdkHomePath) {
|
|
451
|
-
middleCb(chalk.yellow("[WARNING] Use <--simulator-path> option instead of environment variable <LG_WEBOS_TV_SDK_HOME>"));
|
|
452
|
-
simulatorDir = path.join(sdkHomePath, "Simulator");
|
|
453
|
-
|
|
454
|
-
if (fs.existsSync(simulatorDir)) {
|
|
455
|
-
if (fs.statSync(simulatorDir).isDirectory()) {
|
|
456
|
-
const dirList = fs.readdirSync(simulatorDir);
|
|
457
|
-
for (let i = 0; i < dirList.length; i++) {
|
|
458
|
-
if (dirList[i].indexOf(options.simulatorPrefix) === 0) {
|
|
459
|
-
const subDirPath = path.resolve(simulatorDir, dirList[i]);
|
|
460
|
-
if (fs.statSync(subDirPath).isDirectory()) {
|
|
461
|
-
options.simulatorDir = subDirPath;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
if (options.simulatorDir) {
|
|
466
|
-
next(null, options.simulatorDir);
|
|
467
|
-
} else {
|
|
468
|
-
next(errHndl.getErrMsg('EMPTY_VALUE', "--simulator-path"));
|
|
469
|
-
}
|
|
470
|
-
} else {
|
|
471
|
-
next(errHndl.getErrMsg('NOT_DIRTYPE_PATH', simulatorDir));
|
|
472
|
-
}
|
|
473
|
-
} else {
|
|
474
|
-
next(errHndl.getErrMsg('NOT_EXIST_PATH', simulatorDir));
|
|
475
|
-
}
|
|
476
|
-
} else {
|
|
477
|
-
next(errHndl.getErrMsg('EMPTY_VALUE', "--simulator-path"));
|
|
478
|
-
}
|
|
479
|
-
});
|
|
480
|
-
} else {
|
|
481
|
-
next(null, options.simulatorDir);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
function _checkSimulatorDirectory(dirPath, next) {
|
|
486
|
-
log.silly("launcher#launchSimulator#_checkSimulatorDirectory():", "dirPath:", dirPath);
|
|
487
|
-
if (fs.existsSync(dirPath)) {
|
|
488
|
-
if (fs.statSync(dirPath).isDirectory()) {
|
|
489
|
-
middleCb("Finding simulator in " + dirPath);
|
|
490
|
-
next(null, fs.readdirSync(dirPath));
|
|
491
|
-
} else {
|
|
492
|
-
next(errHndl.getErrMsg('NOT_DIRTYPE_PATH', dirPath));
|
|
493
|
-
}
|
|
494
|
-
} else {
|
|
495
|
-
next(errHndl.getErrMsg('NOT_EXIST_PATH', dirPath));
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
function _findSimulatorVersion(fileList, next) {
|
|
500
|
-
log.silly("launcher#launchSimulator#_findSimulatorVersion():", "fileList:", fileList);
|
|
501
|
-
let versionList = [];
|
|
502
|
-
for (let i = 0; i < fileList.length; i++) {
|
|
503
|
-
if (fileList[i].indexOf(options.simulatorPrefix) === 0) {
|
|
504
|
-
const filePath = path.resolve(options.simulatorDir, fileList[i]);
|
|
505
|
-
if (fs.existsSync(filePath)
|
|
506
|
-
&& [".exe", ".appimage", ".app"].includes(path.extname(filePath))) {
|
|
507
|
-
versionList.push(path.parse(filePath).name.slice(options.simulatorPrefix.length + 1));
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
if (versionList.length === 0) {
|
|
513
|
-
next(errHndl.getErrMsg("NOT_EXIST_SIMULATOR", options.simulatorPrefix));
|
|
514
|
-
} else {
|
|
515
|
-
try {
|
|
516
|
-
// sort version descending order
|
|
517
|
-
versionList = versionList.sort(semver.rcompare);
|
|
518
|
-
options.simulatorVersion = versionList[0];
|
|
519
|
-
next();
|
|
520
|
-
} catch(err) {
|
|
521
|
-
next(err, null);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
function _launchSimulator(next) {
|
|
527
|
-
let ext = '';
|
|
528
|
-
switch (process.platform) {
|
|
529
|
-
case 'win32':
|
|
530
|
-
ext = 'exe';
|
|
531
|
-
break;
|
|
532
|
-
case 'linux':
|
|
533
|
-
ext = 'appimage';
|
|
534
|
-
break;
|
|
535
|
-
case 'darwin':
|
|
536
|
-
ext = 'app';
|
|
537
|
-
break;
|
|
538
|
-
default:
|
|
539
|
-
}
|
|
540
|
-
const simulatorName = `${options.simulatorPrefix}_${options.simulatorVersion}`,
|
|
541
|
-
simulatorPath = path.join(options.simulatorDir, `${simulatorName}.${ext}`);
|
|
542
|
-
if (!fs.existsSync(simulatorPath)) {
|
|
543
|
-
return setImmediate(next, errHndl.getErrMsg('NOT_EXIST_PATH', simulatorPath));
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
const paramsStr = JSON.stringify(params).replace(/"/g, "\\\""),
|
|
547
|
-
cmd = process.platform === 'darwin'
|
|
548
|
-
? `open "${simulatorPath}" --args "${appDir}" "${paramsStr}"`
|
|
549
|
-
: `"${simulatorPath}" "${appDir}" "${paramsStr}"`;
|
|
550
|
-
|
|
551
|
-
log.info("launcher#launchSimulator#_launchSimulator():", "cmd:", cmd);
|
|
552
|
-
exec(cmd, function(err) {
|
|
553
|
-
if (err) {
|
|
554
|
-
return setImmediate(next, err);
|
|
555
|
-
}
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
// exec callback is called when the simulator is closed.
|
|
559
|
-
// Call next callback if there is no error for 1 second.
|
|
560
|
-
setTimeout(function() {
|
|
561
|
-
next(null, {msg: "Launched " + path.basename(simulatorPath)});
|
|
562
|
-
}, 1000);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
function makeSession(options, next) {
|
|
568
|
-
options.nReplies = 1; // -n 1
|
|
569
|
-
if (!options.session) {
|
|
570
|
-
log.info("launch#makeSession()", "need to make new session");
|
|
571
|
-
const printTarget = (options.printTarget === false) ? options.printTarget : true;
|
|
572
|
-
options.session = new novacom.Session(options.device, printTarget, next);
|
|
573
|
-
} else {
|
|
574
|
-
log.info("launch#makeSession()", "already exist session");
|
|
575
|
-
next();
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
function checkDisplayAffinity(options, params, next) {
|
|
580
|
-
// case of do not need to call session call(ose), check displayAffinity with display
|
|
581
|
-
if (!options.sessionCall) {
|
|
582
|
-
if (params && params.displayAffinity !== undefined && params.displayAffinity !== null) {
|
|
583
|
-
if (typeof(params.displayAffinity) === 'string') {
|
|
584
|
-
next(errHndl.getErrMsg("INVALID_DISPLAY"));
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
if (options && options.display && (Number(options.display) !== params.displayAffinity)) {
|
|
588
|
-
if (Number(options.display) !== params.displayAffinity) {
|
|
589
|
-
next(errHndl.getErrMsg("UNMATCHED_DISPLAY_AFFINITY"));
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
} else {
|
|
593
|
-
params.displayAffinity = 0;
|
|
594
|
-
if (options && options.display) {
|
|
595
|
-
params.displayAffinity = Number(options.display);
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
next(null, {});
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
603
|
-
module.exports = launcher;
|
|
604
|
-
}
|
|
605
|
-
}());
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2020-2024 LG Electronics Inc.
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const async = require('async'),
|
|
8
|
+
chalk = require('chalk'),
|
|
9
|
+
exec = require('child_process').exec,
|
|
10
|
+
fs = require('fs'),
|
|
11
|
+
npmlog = require('npmlog'),
|
|
12
|
+
os = require('os'),
|
|
13
|
+
path = require('path'),
|
|
14
|
+
semver = require('semver'),
|
|
15
|
+
util = require('util'),
|
|
16
|
+
fileWatcher = require('./base/file-watcher'),
|
|
17
|
+
inspector = require('./inspect'),
|
|
18
|
+
installer = require('./install'),
|
|
19
|
+
sessionLib = require('./session'),
|
|
20
|
+
commonTools = require('./base/common-tools'),
|
|
21
|
+
errHndl = require('./base/error-handler'),
|
|
22
|
+
luna = require('./base/luna'),
|
|
23
|
+
novacom = require('./base/novacom'),
|
|
24
|
+
spinner = require('./util/spinner');
|
|
25
|
+
|
|
26
|
+
const appdata = commonTools.appdata,
|
|
27
|
+
sdkenv = commonTools.sdkenv;
|
|
28
|
+
|
|
29
|
+
(function() {
|
|
30
|
+
const log = npmlog;
|
|
31
|
+
log.heading = 'launcher';
|
|
32
|
+
log.level = 'warn';
|
|
33
|
+
|
|
34
|
+
const launcher = {
|
|
35
|
+
/**
|
|
36
|
+
* @property {Object} log an npm log instance
|
|
37
|
+
*/
|
|
38
|
+
log: log,
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Launch the given application id
|
|
42
|
+
* @param {Object} options
|
|
43
|
+
* @property options {String} device the device to connect to
|
|
44
|
+
* @property options {Boolean} inspect run the application with web-inspector turned on
|
|
45
|
+
*/
|
|
46
|
+
launch: function(options, id, params, next, middleCb) {
|
|
47
|
+
if (typeof next !== 'function') {
|
|
48
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
49
|
+
}
|
|
50
|
+
const self = this,
|
|
51
|
+
hostedAppId = "com.sdk.ares.hostedapp";
|
|
52
|
+
let hostedAppInstalled = false;
|
|
53
|
+
options = options || {};
|
|
54
|
+
|
|
55
|
+
async.series([
|
|
56
|
+
_checkInstalledApp,
|
|
57
|
+
_checkRunningApp,
|
|
58
|
+
_installHostedApp,
|
|
59
|
+
_makeSession,
|
|
60
|
+
_runAppServer,
|
|
61
|
+
_setAppServerInfo,
|
|
62
|
+
_getSessionList,
|
|
63
|
+
_checkDisplayAffinity,
|
|
64
|
+
_launch,
|
|
65
|
+
_runFileWatcher,
|
|
66
|
+
_runInspector
|
|
67
|
+
], function(err, results) {
|
|
68
|
+
log.silly("launch#launch()", "err:", err, ", results:", results);
|
|
69
|
+
const result = results[8];
|
|
70
|
+
if (!err) {
|
|
71
|
+
if (options.installMode !== "Hosted") {
|
|
72
|
+
result.msg = "Launched application " + id;
|
|
73
|
+
if (self.displayId !== undefined) {
|
|
74
|
+
result.msg += " on display " + self.displayId;
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
options.session = null;
|
|
78
|
+
options.printTarget = false;
|
|
79
|
+
self.close(options, hostedAppId, params, next);
|
|
80
|
+
result.msg = "";
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
next(err, result);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
function _checkInstalledApp(next) {
|
|
88
|
+
if (options.installMode === "Hosted") {
|
|
89
|
+
installer.list(options, function(err, result) {
|
|
90
|
+
for (const index in result) {
|
|
91
|
+
if (result[index].id === hostedAppId) {
|
|
92
|
+
hostedAppInstalled = true;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
next(err);
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
next();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function _checkRunningApp(next) {
|
|
104
|
+
if (options.installMode === "Hosted") {
|
|
105
|
+
self.listRunningApp(options, function(err, result) {
|
|
106
|
+
for (const index in result) {
|
|
107
|
+
if (result[index].id === hostedAppId) {
|
|
108
|
+
self.close(options, hostedAppId, params, next);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
next(err);
|
|
113
|
+
});
|
|
114
|
+
} else {
|
|
115
|
+
next();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function _installHostedApp(next) {
|
|
120
|
+
if (options.installMode === "Hosted" && !hostedAppInstalled) {
|
|
121
|
+
const hostedAppUrl = path.join(__dirname, hostedAppId + ".ipk");
|
|
122
|
+
options.appId = id;
|
|
123
|
+
installer.install(options, hostedAppUrl, next, function(value) {
|
|
124
|
+
middleCb(value);
|
|
125
|
+
});
|
|
126
|
+
} else {
|
|
127
|
+
next();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function _makeSession(next) {
|
|
132
|
+
makeSession(options, next);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function _runAppServer(next) {
|
|
136
|
+
if (options.installMode === "Hosted") {
|
|
137
|
+
options.session.runHostedAppServer(options.hostedurl, next);
|
|
138
|
+
spinner.stop();
|
|
139
|
+
middleCb("Ares Hosted App is now running...");
|
|
140
|
+
} else {
|
|
141
|
+
next();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function _setAppServerInfo(next) {
|
|
146
|
+
if (options.installMode === "Hosted") {
|
|
147
|
+
if (options.hostIp) {
|
|
148
|
+
options.localIP = options.hostIp;
|
|
149
|
+
} else {
|
|
150
|
+
const networkInterfaces = os.networkInterfaces();
|
|
151
|
+
let localIP = "";
|
|
152
|
+
|
|
153
|
+
for (const devName in networkInterfaces) {
|
|
154
|
+
for (let index = 0; index < networkInterfaces[devName].length; index++) {
|
|
155
|
+
const alias = networkInterfaces[devName][index];
|
|
156
|
+
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
|
|
157
|
+
localIP = localIP || alias.address;
|
|
158
|
+
options.localIP = localIP;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const port = options.session.getHostedAppServerPort();
|
|
164
|
+
if (params === null) {
|
|
165
|
+
params = {};
|
|
166
|
+
}
|
|
167
|
+
params.hostedurl = "http://" + options.localIP + ":" + port + "/";
|
|
168
|
+
}
|
|
169
|
+
next();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function _getSessionList(next) {
|
|
173
|
+
sessionLib.getSessionList(options, next);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function _checkDisplayAffinity(next) {
|
|
177
|
+
checkDisplayAffinity(options, params, next);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function _launch(next) {
|
|
181
|
+
const target = options.session.getDevice(),
|
|
182
|
+
addr = target.lunaAddr.launch,
|
|
183
|
+
returnValue = addr.returnValue.split('.'),
|
|
184
|
+
param = {
|
|
185
|
+
// luna param
|
|
186
|
+
id: id,
|
|
187
|
+
subscribe: false,
|
|
188
|
+
params: params
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
luna.send(options, addr, param, function(lineObj, next) {
|
|
192
|
+
let resultValue = lineObj;
|
|
193
|
+
|
|
194
|
+
for (let index = 1; index < returnValue.length; index++) {
|
|
195
|
+
resultValue = resultValue[returnValue[index]];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (resultValue) {
|
|
199
|
+
// success: stop
|
|
200
|
+
log.verbose("launch#launch()#_launch()", "success");
|
|
201
|
+
|
|
202
|
+
// If sam returns "displayId" show displayId in result msg
|
|
203
|
+
if (lineObj.displayId !== undefined) {
|
|
204
|
+
self.displayId = lineObj.displayId;
|
|
205
|
+
}
|
|
206
|
+
next(null, {procId: resultValue});
|
|
207
|
+
} else {
|
|
208
|
+
// failure: stop
|
|
209
|
+
log.verbose("launch#launch()#_launch()", "failure");
|
|
210
|
+
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
211
|
+
}
|
|
212
|
+
}, next);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function _runFileWatcher(next) {
|
|
216
|
+
if (options.installMode === "Hosted") {
|
|
217
|
+
log.verbose("launcher#launch#_runFileWatcher()");
|
|
218
|
+
options.appId = id;
|
|
219
|
+
fileWatcher.watch(options, params);
|
|
220
|
+
next();
|
|
221
|
+
} else {
|
|
222
|
+
next();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function _runInspector(next) {
|
|
227
|
+
if (options.inspect) {
|
|
228
|
+
options.appId = id;
|
|
229
|
+
options.running = true;
|
|
230
|
+
|
|
231
|
+
async.series([
|
|
232
|
+
inspector.inspect.bind(inspector, options, null),
|
|
233
|
+
function() {
|
|
234
|
+
// TODO: hold process to keep alive
|
|
235
|
+
}
|
|
236
|
+
], function(err) {
|
|
237
|
+
next(err);
|
|
238
|
+
});
|
|
239
|
+
} else if (options.installMode === "Hosted") {
|
|
240
|
+
process.on("SIGINT", function() {
|
|
241
|
+
log.verbose("launcher#launch#_runInspector():", "SIGINT is detected in Hosted mode");
|
|
242
|
+
next();
|
|
243
|
+
});
|
|
244
|
+
} else {
|
|
245
|
+
next();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
/**
|
|
250
|
+
* Close the given application id
|
|
251
|
+
* @param {Object} options
|
|
252
|
+
* @property options {String} device the device to connect to
|
|
253
|
+
* @property options {Boolean} inspect run the application with web-inspector turned on
|
|
254
|
+
*/
|
|
255
|
+
close: function(options, id, params, next) {
|
|
256
|
+
if (typeof next !== 'function') {
|
|
257
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
258
|
+
}
|
|
259
|
+
const self = this;
|
|
260
|
+
options = options || {};
|
|
261
|
+
|
|
262
|
+
async.series([
|
|
263
|
+
_makeSession,
|
|
264
|
+
_getSessionList,
|
|
265
|
+
_checkDisplayAffinity,
|
|
266
|
+
_close
|
|
267
|
+
], function(err, results) {
|
|
268
|
+
log.silly("launch#close()", "err:", err, ", results:", results);
|
|
269
|
+
// 2 steps in async.series, we want to
|
|
270
|
+
// the value returned by the second
|
|
271
|
+
// step (index=1)
|
|
272
|
+
const result = results[3];
|
|
273
|
+
if (result) {
|
|
274
|
+
if (options.installMode !== "Hosted") {
|
|
275
|
+
result.msg = "Closed application " + id;
|
|
276
|
+
if (self.displayId !== undefined) {
|
|
277
|
+
result.msg += " on display " + self.displayId;
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
result.msg = "...Closed Ares Hosted App";
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
next(err, result);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
function _makeSession(next) {
|
|
287
|
+
makeSession(options, next);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function _getSessionList(next) {
|
|
291
|
+
sessionLib.getSessionList(options, next);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function _checkDisplayAffinity(next) {
|
|
295
|
+
checkDisplayAffinity(options, params, next);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function _close(next) {
|
|
299
|
+
const target = options.session.getDevice(),
|
|
300
|
+
addr = target.lunaAddr.terminate,
|
|
301
|
+
returnValue = addr.returnValue.split('.'),
|
|
302
|
+
param = {
|
|
303
|
+
// luna param
|
|
304
|
+
id: id,
|
|
305
|
+
subscribe: false,
|
|
306
|
+
params: params
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
luna.send(options, addr, param, function(lineObj, next) {
|
|
310
|
+
let resultValue = lineObj;
|
|
311
|
+
|
|
312
|
+
for (let index = 1; index < returnValue.length; index++) {
|
|
313
|
+
resultValue = resultValue[returnValue[index]];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (resultValue) {
|
|
317
|
+
// success: stop
|
|
318
|
+
log.verbose("launch#close()#_close()", "success");
|
|
319
|
+
|
|
320
|
+
// If sam returns "displayId" show displayId in result msg
|
|
321
|
+
if (lineObj.displayId !== undefined) {
|
|
322
|
+
self.displayId = lineObj.displayId;
|
|
323
|
+
}
|
|
324
|
+
next(null, {procId: resultValue});
|
|
325
|
+
} else {
|
|
326
|
+
// failure: stop
|
|
327
|
+
log.verbose("launch#close()#_close()", "failure");
|
|
328
|
+
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
329
|
+
}
|
|
330
|
+
}, next);
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* list the running applications
|
|
336
|
+
* @param {Object} options
|
|
337
|
+
* @property options {String} device the device to connect to
|
|
338
|
+
* @property options {Boolean} inspect run the application with web-inspector turned on
|
|
339
|
+
*/
|
|
340
|
+
listRunningApp: function(options, next) {
|
|
341
|
+
if (typeof next !== 'function') {
|
|
342
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
options = options || {};
|
|
346
|
+
async.series([
|
|
347
|
+
_makeSession,
|
|
348
|
+
_getSessionList,
|
|
349
|
+
_listRunningApp
|
|
350
|
+
], function(err, results) {
|
|
351
|
+
log.silly("launch#listRunningApp()", "err:", err, ", results:", results);
|
|
352
|
+
next(err, results[2]);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
function _makeSession(next) {
|
|
356
|
+
makeSession(options, next);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function _getSessionList(next) {
|
|
360
|
+
sessionLib.getSessionList(options, next);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function _listRunningApp(next) {
|
|
364
|
+
const target = options.session.getDevice(),
|
|
365
|
+
addr = target.lunaAddr.running,
|
|
366
|
+
returnValue = addr.returnValue.split('.'),
|
|
367
|
+
param = {
|
|
368
|
+
// luna param
|
|
369
|
+
subscribe: false
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
if (!addr || !returnValue) {
|
|
373
|
+
return next(errHndl.getErrMsg("NOT_SUPPORT_RUNNINGLIST"));
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
luna.send(options, addr, param, function(lineObj, next) {
|
|
377
|
+
let resultValue = lineObj;
|
|
378
|
+
|
|
379
|
+
for (let index = 1; index < returnValue.length; index++) {
|
|
380
|
+
resultValue = resultValue[returnValue[index]];
|
|
381
|
+
}
|
|
382
|
+
resultValue = resultValue || [];
|
|
383
|
+
|
|
384
|
+
if (lineObj.returnValue) {
|
|
385
|
+
// success: stop
|
|
386
|
+
log.verbose("launch#listRunningApp()", "success");
|
|
387
|
+
next(null, resultValue);
|
|
388
|
+
} else {
|
|
389
|
+
// failure: stop
|
|
390
|
+
log.verbose("launch#listRunningApp()", "failure");
|
|
391
|
+
next(errHndl.getErrMsg("INVALID_OBJECT"));
|
|
392
|
+
}
|
|
393
|
+
}, next);
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Launch the given application directory to the simulator
|
|
399
|
+
* @param {Object} options
|
|
400
|
+
* @property options {String} simulator the webOS TV version of simulator to launch
|
|
401
|
+
* @param {String} appDir the path of application directory
|
|
402
|
+
* @param {Object} params parameters to launch with
|
|
403
|
+
*/
|
|
404
|
+
launchSimulator: function(options, appDir, params, next, middleCb) {
|
|
405
|
+
if (typeof next !== 'function') {
|
|
406
|
+
throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
options = options || {};
|
|
410
|
+
options.simulatorPrefix = `webOS_TV_${options.simulator}_Simulator`;
|
|
411
|
+
async.waterfall([
|
|
412
|
+
_checkSimulatorConfig,
|
|
413
|
+
_checkEnvPath,
|
|
414
|
+
_checkSimulatorDirectory,
|
|
415
|
+
_findSimulatorVersion,
|
|
416
|
+
_launchSimulator
|
|
417
|
+
], function(err, results) {
|
|
418
|
+
next(err, results);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
function _checkSimulatorConfig(next) {
|
|
422
|
+
const configPath = appdata.getSimulatorConfigPath();
|
|
423
|
+
let cofigData = {};
|
|
424
|
+
|
|
425
|
+
if (fs.existsSync(configPath)) {
|
|
426
|
+
cofigData = JSON.parse(fs.readFileSync(configPath));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (options.simulatorPath) {
|
|
430
|
+
cofigData[options.simulator] = options.simulatorPath;
|
|
431
|
+
try {
|
|
432
|
+
fs.writeFileSync(configPath, JSON.stringify(cofigData, null, Number(4)) + "\n");
|
|
433
|
+
} catch(err) {
|
|
434
|
+
next(err, null);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
Object.keys(cofigData).forEach(function(version) {
|
|
439
|
+
if (version === options.simulator) {
|
|
440
|
+
options.simulatorDir = cofigData[options.simulator];
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
next(null, options.simulatorDir);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function _checkEnvPath(simulatorDir, next) {
|
|
447
|
+
log.silly("launcher#launchSimulator#_checkEnvPath():", "simulatorDir:", simulatorDir);
|
|
448
|
+
if (!simulatorDir) {
|
|
449
|
+
sdkenv.getEnvValue("SDK", function(err, sdkHomePath) {
|
|
450
|
+
if (sdkHomePath) {
|
|
451
|
+
middleCb(chalk.yellow("[WARNING] Use <--simulator-path> option instead of environment variable <LG_WEBOS_TV_SDK_HOME>"));
|
|
452
|
+
simulatorDir = path.join(sdkHomePath, "Simulator");
|
|
453
|
+
|
|
454
|
+
if (fs.existsSync(simulatorDir)) {
|
|
455
|
+
if (fs.statSync(simulatorDir).isDirectory()) {
|
|
456
|
+
const dirList = fs.readdirSync(simulatorDir);
|
|
457
|
+
for (let i = 0; i < dirList.length; i++) {
|
|
458
|
+
if (dirList[i].indexOf(options.simulatorPrefix) === 0) {
|
|
459
|
+
const subDirPath = path.resolve(simulatorDir, dirList[i]);
|
|
460
|
+
if (fs.statSync(subDirPath).isDirectory()) {
|
|
461
|
+
options.simulatorDir = subDirPath;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (options.simulatorDir) {
|
|
466
|
+
next(null, options.simulatorDir);
|
|
467
|
+
} else {
|
|
468
|
+
next(errHndl.getErrMsg('EMPTY_VALUE', "--simulator-path"));
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
next(errHndl.getErrMsg('NOT_DIRTYPE_PATH', simulatorDir));
|
|
472
|
+
}
|
|
473
|
+
} else {
|
|
474
|
+
next(errHndl.getErrMsg('NOT_EXIST_PATH', simulatorDir));
|
|
475
|
+
}
|
|
476
|
+
} else {
|
|
477
|
+
next(errHndl.getErrMsg('EMPTY_VALUE', "--simulator-path"));
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
} else {
|
|
481
|
+
next(null, options.simulatorDir);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function _checkSimulatorDirectory(dirPath, next) {
|
|
486
|
+
log.silly("launcher#launchSimulator#_checkSimulatorDirectory():", "dirPath:", dirPath);
|
|
487
|
+
if (fs.existsSync(dirPath)) {
|
|
488
|
+
if (fs.statSync(dirPath).isDirectory()) {
|
|
489
|
+
middleCb("Finding simulator in " + dirPath);
|
|
490
|
+
next(null, fs.readdirSync(dirPath));
|
|
491
|
+
} else {
|
|
492
|
+
next(errHndl.getErrMsg('NOT_DIRTYPE_PATH', dirPath));
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
next(errHndl.getErrMsg('NOT_EXIST_PATH', dirPath));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function _findSimulatorVersion(fileList, next) {
|
|
500
|
+
log.silly("launcher#launchSimulator#_findSimulatorVersion():", "fileList:", fileList);
|
|
501
|
+
let versionList = [];
|
|
502
|
+
for (let i = 0; i < fileList.length; i++) {
|
|
503
|
+
if (fileList[i].indexOf(options.simulatorPrefix) === 0) {
|
|
504
|
+
const filePath = path.resolve(options.simulatorDir, fileList[i]);
|
|
505
|
+
if (fs.existsSync(filePath)
|
|
506
|
+
&& [".exe", ".appimage", ".app"].includes(path.extname(filePath))) {
|
|
507
|
+
versionList.push(path.parse(filePath).name.slice(options.simulatorPrefix.length + 1));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (versionList.length === 0) {
|
|
513
|
+
next(errHndl.getErrMsg("NOT_EXIST_SIMULATOR", options.simulatorPrefix));
|
|
514
|
+
} else {
|
|
515
|
+
try {
|
|
516
|
+
// sort version descending order
|
|
517
|
+
versionList = versionList.sort(semver.rcompare);
|
|
518
|
+
options.simulatorVersion = versionList[0];
|
|
519
|
+
next();
|
|
520
|
+
} catch(err) {
|
|
521
|
+
next(err, null);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function _launchSimulator(next) {
|
|
527
|
+
let ext = '';
|
|
528
|
+
switch (process.platform) {
|
|
529
|
+
case 'win32':
|
|
530
|
+
ext = 'exe';
|
|
531
|
+
break;
|
|
532
|
+
case 'linux':
|
|
533
|
+
ext = 'appimage';
|
|
534
|
+
break;
|
|
535
|
+
case 'darwin':
|
|
536
|
+
ext = 'app';
|
|
537
|
+
break;
|
|
538
|
+
default:
|
|
539
|
+
}
|
|
540
|
+
const simulatorName = `${options.simulatorPrefix}_${options.simulatorVersion}`,
|
|
541
|
+
simulatorPath = path.join(options.simulatorDir, `${simulatorName}.${ext}`);
|
|
542
|
+
if (!fs.existsSync(simulatorPath)) {
|
|
543
|
+
return setImmediate(next, errHndl.getErrMsg('NOT_EXIST_PATH', simulatorPath));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const paramsStr = JSON.stringify(params).replace(/"/g, "\\\""),
|
|
547
|
+
cmd = process.platform === 'darwin'
|
|
548
|
+
? `open "${simulatorPath}" --args "${appDir}" "${paramsStr}"`
|
|
549
|
+
: `"${simulatorPath}" "${appDir}" "${paramsStr}"`;
|
|
550
|
+
|
|
551
|
+
log.info("launcher#launchSimulator#_launchSimulator():", "cmd:", cmd);
|
|
552
|
+
exec(cmd, function(err) {
|
|
553
|
+
if (err) {
|
|
554
|
+
return setImmediate(next, err);
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// exec callback is called when the simulator is closed.
|
|
559
|
+
// Call next callback if there is no error for 1 second.
|
|
560
|
+
setTimeout(function() {
|
|
561
|
+
next(null, {msg: "Launched " + path.basename(simulatorPath)});
|
|
562
|
+
}, 1000);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
function makeSession(options, next) {
|
|
568
|
+
options.nReplies = 1; // -n 1
|
|
569
|
+
if (!options.session) {
|
|
570
|
+
log.info("launch#makeSession()", "need to make new session");
|
|
571
|
+
const printTarget = (options.printTarget === false) ? options.printTarget : true;
|
|
572
|
+
options.session = new novacom.Session(options.device, printTarget, next);
|
|
573
|
+
} else {
|
|
574
|
+
log.info("launch#makeSession()", "already exist session");
|
|
575
|
+
next();
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function checkDisplayAffinity(options, params, next) {
|
|
580
|
+
// case of do not need to call session call(ose), check displayAffinity with display
|
|
581
|
+
if (!options.sessionCall) {
|
|
582
|
+
if (params && params.displayAffinity !== undefined && params.displayAffinity !== null) {
|
|
583
|
+
if (typeof(params.displayAffinity) === 'string') {
|
|
584
|
+
next(errHndl.getErrMsg("INVALID_DISPLAY"));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (options && options.display && (Number(options.display) !== params.displayAffinity)) {
|
|
588
|
+
if (Number(options.display) !== params.displayAffinity) {
|
|
589
|
+
next(errHndl.getErrMsg("UNMATCHED_DISPLAY_AFFINITY"));
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
params.displayAffinity = 0;
|
|
594
|
+
if (options && options.display) {
|
|
595
|
+
params.displayAffinity = Number(options.display);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
next(null, {});
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
603
|
+
module.exports = launcher;
|
|
604
|
+
}
|
|
605
|
+
}());
|