@webos-tools/cli 3.0.0

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