@webos-tools/cli 3.0.5 → 3.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/.eslintignore +1 -1
  2. package/.eslintrc.js +52 -52
  3. package/APIs.js +79 -79
  4. package/CHANGELOG.md +138 -128
  5. package/LICENSE +201 -201
  6. package/README.md +218 -218
  7. package/bin/ares-config.js +199 -199
  8. package/bin/ares-device-info.js +30 -30
  9. package/bin/ares-device.js +219 -219
  10. package/bin/ares-generate.js +270 -270
  11. package/bin/ares-inspect.js +179 -179
  12. package/bin/ares-install.js +223 -223
  13. package/bin/ares-launch.js +318 -318
  14. package/bin/ares-log.js +255 -255
  15. package/bin/ares-novacom.js +223 -223
  16. package/bin/ares-package.js +336 -336
  17. package/bin/ares-pull.js +156 -156
  18. package/bin/ares-push.js +155 -155
  19. package/bin/ares-server.js +174 -174
  20. package/bin/ares-setup-device.js +520 -520
  21. package/bin/ares-shell.js +132 -132
  22. package/bin/ares.js +166 -166
  23. package/files/conf/ares.json +49 -49
  24. package/files/conf/command-service.json +73 -73
  25. package/files/conf/config.json +22 -22
  26. package/files/conf/ipk.json +30 -30
  27. package/files/conf/novacom-devices.json +35 -35
  28. package/files/conf/query/query-app.json +14 -14
  29. package/files/conf/query/query-hosted.json +18 -18
  30. package/files/conf/query/query-package.json +10 -10
  31. package/files/conf/query/query-service.json +6 -6
  32. package/files/conf/sdk.json +8 -8
  33. package/files/conf/template.json +57 -57
  34. package/files/conf/webos_emul +27 -27
  35. package/files/conf-base/env/sdk-ose.json +8 -8
  36. package/files/conf-base/env/sdk-tv.json +8 -8
  37. package/files/conf-base/profile/config-ose.json +21 -21
  38. package/files/conf-base/profile/config-tv.json +22 -22
  39. package/files/conf-base/query/query-app.json +14 -14
  40. package/files/conf-base/query/query-hosted.json +18 -18
  41. package/files/conf-base/query/query-package.json +10 -10
  42. package/files/conf-base/query/query-service.json +6 -6
  43. package/files/conf-base/template-conf/ose-templates.json +67 -67
  44. package/files/conf-base/template-conf/tv-sdk-templates.json +57 -57
  45. package/files/help/ares-config.help +43 -43
  46. package/files/help/ares-device.help +94 -94
  47. package/files/help/ares-generate.help +65 -65
  48. package/files/help/ares-inspect.help +70 -70
  49. package/files/help/ares-install.help +90 -90
  50. package/files/help/ares-launch.help +100 -100
  51. package/files/help/ares-log-pmlogd.help +84 -84
  52. package/files/help/ares-log.help +101 -101
  53. package/files/help/ares-novacom.help +68 -68
  54. package/files/help/ares-package.help +101 -101
  55. package/files/help/ares-pull.help +38 -38
  56. package/files/help/ares-push.help +38 -38
  57. package/files/help/ares-server.help +39 -39
  58. package/files/help/ares-setup-device.help +75 -75
  59. package/files/help/ares-shell.help +42 -42
  60. package/files/help/ares.help +47 -47
  61. package/files/help/readme.help +23 -23
  62. package/files/schema/ApplicationDescription.schema +319 -319
  63. package/files/schema/NovacomDevices.schema +61 -61
  64. package/files/templates/ose-sdk-templates/appinfo/appinfo.json +10 -10
  65. package/files/templates/ose-sdk-templates/bootplate-web/index.html +88 -88
  66. package/files/templates/ose-sdk-templates/hosted-webapp/index.html +13 -13
  67. package/files/templates/ose-sdk-templates/icon/icon.png +0 -0
  68. package/files/templates/ose-sdk-templates/js-service/helloclient.js +31 -31
  69. package/files/templates/ose-sdk-templates/js-service/helloworld_webos_service.js +188 -188
  70. package/files/templates/ose-sdk-templates/qml-app/main.qml +68 -68
  71. package/files/templates/ose-sdk-templates/qmlappinfo/appinfo.json +10 -10
  72. package/files/templates/ose-sdk-templates/serviceinfo/package.json +11 -11
  73. package/files/templates/ose-sdk-templates/serviceinfo/services.json +8 -8
  74. package/files/templates/tv-sdk-templates/appinfo/appinfo.json +10 -10
  75. package/files/templates/tv-sdk-templates/bootplate-web/index.html +58 -58
  76. package/files/templates/tv-sdk-templates/bootplate-web/webOSTVjs-1.2.10/LICENSE-2.0.txt +202 -202
  77. package/files/templates/tv-sdk-templates/hosted-webapp/index.html +14 -14
  78. package/files/templates/tv-sdk-templates/js-service/helloworld_service.js +39 -39
  79. package/files/templates/tv-sdk-templates/packageinfo/packageinfo.json +3 -3
  80. package/files/templates/tv-sdk-templates/serviceinfo/package.json +11 -11
  81. package/files/templates/tv-sdk-templates/serviceinfo/services.json +8 -8
  82. package/files/templates/tv-sdk-templates/webicon/icon.png +0 -0
  83. package/files/templates/tv-sdk-templates/webicon/largeIcon.png +0 -0
  84. package/lib/base/ares.html +40 -40
  85. package/lib/base/cli-appdata.js +290 -290
  86. package/lib/base/cli-control.js +44 -44
  87. package/lib/base/common-tools.js +29 -29
  88. package/lib/base/error-handler.js +265 -265
  89. package/lib/base/file-watcher.js +155 -155
  90. package/lib/base/help-format.js +147 -147
  91. package/lib/base/luna.js +178 -178
  92. package/lib/base/novacom.js +1191 -1191
  93. package/lib/base/sdkenv.js +59 -59
  94. package/lib/base/server.js +137 -137
  95. package/lib/base/setup-device.js +328 -328
  96. package/lib/base/version-tools.js +79 -79
  97. package/lib/device.js +1419 -1419
  98. package/lib/generator.js +377 -377
  99. package/lib/inspect.js +494 -494
  100. package/lib/install.js +463 -463
  101. package/lib/launch.js +605 -605
  102. package/lib/log.js +584 -584
  103. package/lib/package.js +2129 -2129
  104. package/lib/pull.js +231 -231
  105. package/lib/pusher.js +210 -210
  106. package/lib/session.js +74 -74
  107. package/lib/shell.js +193 -193
  108. package/lib/tar-filter-pack.js +62 -62
  109. package/lib/util/copy.js +31 -31
  110. package/lib/util/createFileName.js +40 -40
  111. package/lib/util/eof.js +30 -30
  112. package/lib/util/json.js +63 -63
  113. package/lib/util/merge.js +14 -14
  114. package/lib/util/objclone.js +40 -40
  115. package/lib/util/spinner.js +37 -37
  116. package/npm-shrinkwrap.json +9115 -9115
  117. package/package.json +100 -100
  118. package/scripts/postinstall.js +24 -24
  119. package/spec/helpers/reporter.js +65 -65
  120. package/spec/jsSpecs/apiTest/generator.spec.js +372 -372
  121. package/spec/jsSpecs/apiTest/inspector.spec.js +89 -89
  122. package/spec/jsSpecs/apiTest/installer.spec.js +67 -67
  123. package/spec/jsSpecs/apiTest/launcher.spec.js +150 -150
  124. package/spec/jsSpecs/apiTest/packager.spec.js +194 -194
  125. package/spec/jsSpecs/apiTest/puller.spec.js +101 -101
  126. package/spec/jsSpecs/apiTest/pusher.spec.js +103 -103
  127. package/spec/jsSpecs/apiTest/server.spec.js +115 -115
  128. package/spec/jsSpecs/apiTest/setupDevice.spec.js +93 -93
  129. package/spec/jsSpecs/apiTest/shell.spec.js +49 -49
  130. package/spec/jsSpecs/ares-config.spec.js +78 -78
  131. package/spec/jsSpecs/ares-device.spec.js +443 -443
  132. package/spec/jsSpecs/ares-generate.spec.js +397 -397
  133. package/spec/jsSpecs/ares-inspect.spec.js +252 -252
  134. package/spec/jsSpecs/ares-install.spec.js +150 -150
  135. package/spec/jsSpecs/ares-launch.spec.js +301 -301
  136. package/spec/jsSpecs/ares-log.spec.js +824 -824
  137. package/spec/jsSpecs/ares-novacom.spec.js +149 -149
  138. package/spec/jsSpecs/ares-package.spec.js +1211 -1211
  139. package/spec/jsSpecs/ares-pull.spec.js +157 -157
  140. package/spec/jsSpecs/ares-push.spec.js +146 -146
  141. package/spec/jsSpecs/ares-server.spec.js +160 -160
  142. package/spec/jsSpecs/ares-setup-device.spec.js +281 -281
  143. package/spec/jsSpecs/ares-shell.spec.js +220 -220
  144. package/spec/jsSpecs/ares.spec.js +83 -83
  145. package/spec/jsSpecs/common-spec.js +169 -169
  146. package/spec/support/jasmine.json +22 -22
  147. package/spec/tempFiles/nativeApp/auto/pkg_arm64/GLES2 +0 -0
  148. package/spec/tempFiles/nativeApp/auto/pkg_arm64/appinfo.json +9 -9
  149. package/spec/tempFiles/nativeApp/ose/pkg_arm/Hello +0 -0
  150. package/spec/tempFiles/nativeApp/ose/pkg_arm/appinfo.json +8 -8
  151. package/spec/tempFiles/nativeApp/ose/pkg_arm/package.properties +2 -2
  152. package/spec/tempFiles/nativeApp/oseEmul/pkg_x86/Hello +0 -0
  153. package/spec/tempFiles/nativeApp/oseEmul/pkg_x86/appinfo.json +9 -9
  154. package/spec/tempFiles/nativeApp/rsi/pkg_x86/GLES2 +0 -0
  155. package/spec/tempFiles/nativeApp/rsi/pkg_x86/appinfo.json +9 -9
  156. package/spec/tempFiles/sign/sign.crt +32 -32
  157. package/spec/tempFiles/sign/signPriv.key +52 -52
  158. package/spec/test_data/ares-generate.json +41 -41
  159. 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
+ }());