@webos-tools/cli 3.2.0 → 3.2.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.
Files changed (152) hide show
  1. package/.eslintignore +1 -1
  2. package/.eslintrc.js +52 -52
  3. package/.vscode/c_cpp_properties.json +21 -0
  4. package/.vscode/launch.json +97 -0
  5. package/.vscode/settings.json +13 -0
  6. package/.vscode/tasks.json +32 -0
  7. package/APIs.js +79 -79
  8. package/CHANGELOG.md +11 -5
  9. package/LICENSE +201 -201
  10. package/bin/ares-config.js +1 -1
  11. package/bin/ares-device-info.js +30 -30
  12. package/bin/ares-generate.js +274 -274
  13. package/bin/ares-inspect.js +179 -179
  14. package/bin/ares-install.js +223 -223
  15. package/bin/ares-log.js +259 -259
  16. package/bin/ares-pull.js +156 -156
  17. package/bin/ares-push.js +155 -155
  18. package/bin/ares-server.js +174 -174
  19. package/bin/ares-setup-device.js +6 -10
  20. package/bin/ares-shell.js +132 -132
  21. package/bin/ares.js +166 -166
  22. package/files/conf/ares.json +1 -2
  23. package/files/conf/ipk.json +30 -30
  24. package/files/conf/novacom-devices.json +2 -2
  25. package/files/conf/query/query-app.json +14 -14
  26. package/files/conf/query/query-hosted.json +18 -18
  27. package/files/conf/query/query-package.json +10 -10
  28. package/files/conf/query/query-service.json +6 -6
  29. package/files/conf/webos_emul +27 -27
  30. package/files/conf-base/env/sdk-apollo.json +8 -8
  31. package/files/conf-base/env/sdk-ose.json +8 -8
  32. package/files/conf-base/env/sdk-tv.json +8 -8
  33. package/files/conf-base/profile/config-apollo.json +29 -29
  34. package/files/conf-base/profile/config-ose.json +29 -29
  35. package/files/conf-base/profile/config-tv.json +31 -31
  36. package/files/conf-base/query/query-app.json +14 -14
  37. package/files/conf-base/query/query-hosted.json +18 -18
  38. package/files/conf-base/query/query-package.json +10 -10
  39. package/files/conf-base/query/query-service.json +6 -6
  40. package/files/conf-base/query/signage/query-app.json +1 -1
  41. package/files/conf-base/query/signage/query-service.json +1 -1
  42. package/files/conf-base/template-conf/ose-templates.json +67 -67
  43. package/files/conf-base/template-conf/tv-sdk-templates.json +57 -57
  44. package/files/help/ares-device.help +109 -109
  45. package/files/help/ares-install.help +95 -95
  46. package/files/help/ares-launch.help +1 -1
  47. package/files/help/ares-log-pmlogd.help +84 -84
  48. package/files/help/ares-log.help +101 -101
  49. package/files/help/ares-novacom.help +68 -68
  50. package/files/help/ares-pull.help +38 -38
  51. package/files/help/ares-push.help +38 -38
  52. package/files/help/ares-server.help +44 -44
  53. package/files/help/ares-shell.help +42 -42
  54. package/files/help/ares.help +52 -52
  55. package/files/help/readme.help +23 -23
  56. package/files/schema/ApplicationDescription.schema +319 -319
  57. package/files/templates/apollo-sdk-templates/appinfo/appinfo.json +10 -10
  58. package/files/templates/apollo-sdk-templates/bootplate-web/index.html +88 -88
  59. package/files/templates/apollo-sdk-templates/hosted-webapp/index.html +13 -13
  60. package/files/templates/apollo-sdk-templates/js-service/helloclient.js +31 -31
  61. package/files/templates/apollo-sdk-templates/js-service/helloworld_webos_service.js +188 -188
  62. package/files/templates/apollo-sdk-templates/serviceinfo/package.json +11 -11
  63. package/files/templates/apollo-sdk-templates/serviceinfo/services.json +8 -8
  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/js-service/helloclient.js +31 -31
  68. package/files/templates/ose-sdk-templates/js-service/helloworld_webos_service.js +188 -188
  69. package/files/templates/ose-sdk-templates/qml-app/main.qml +68 -68
  70. package/files/templates/ose-sdk-templates/qmlappinfo/appinfo.json +10 -10
  71. package/files/templates/ose-sdk-templates/serviceinfo/package.json +11 -11
  72. package/files/templates/ose-sdk-templates/serviceinfo/services.json +8 -8
  73. package/files/templates/signage-sdk-templates/Backlight_Scheduling/index.html +1 -1
  74. package/files/templates/signage-sdk-templates/Backlight_Scheduling/scheduler.js +2 -3
  75. package/files/templates/signage-sdk-templates/File_Explorer/index.html +1 -33
  76. package/files/templates/signage-sdk-templates/File_Explorer/js/Root.js +0 -9
  77. package/files/templates/tv-sdk-templates/appinfo/appinfo.json +10 -10
  78. package/files/templates/tv-sdk-templates/bootplate-web/index.html +58 -58
  79. package/files/templates/tv-sdk-templates/bootplate-web/webOSTVjs-1.2.10/LICENSE-2.0.txt +202 -202
  80. package/files/templates/tv-sdk-templates/hosted-webapp/index.html +14 -14
  81. package/files/templates/tv-sdk-templates/js-service/helloworld_service.js +39 -39
  82. package/files/templates/tv-sdk-templates/packageinfo/packageinfo.json +3 -3
  83. package/files/templates/tv-sdk-templates/serviceinfo/package.json +11 -11
  84. package/files/templates/tv-sdk-templates/serviceinfo/services.json +8 -8
  85. package/lib/base/ares.html +40 -40
  86. package/lib/base/cli-appdata.js +290 -289
  87. package/lib/base/cli-control.js +44 -44
  88. package/lib/base/common-tools.js +29 -29
  89. package/lib/base/error-handler.js +265 -265
  90. package/lib/base/file-watcher.js +155 -155
  91. package/lib/base/help-format.js +147 -147
  92. package/lib/base/luna.js +178 -178
  93. package/lib/base/novacom.js +4 -4
  94. package/lib/base/sdkenv.js +59 -59
  95. package/lib/base/server.js +137 -137
  96. package/lib/base/setup-device.js +2 -2
  97. package/lib/base/version-tools.js +79 -79
  98. package/lib/device.js +1419 -1419
  99. package/lib/generator.js +1 -1
  100. package/lib/inspect.js +493 -493
  101. package/lib/log.js +584 -584
  102. package/lib/package.js +61 -7
  103. package/lib/pull.js +231 -231
  104. package/lib/pusher.js +210 -210
  105. package/lib/session.js +74 -74
  106. package/lib/shell.js +193 -193
  107. package/lib/tar-filter-pack.js +62 -62
  108. package/lib/util/copy.js +31 -31
  109. package/lib/util/createFileName.js +40 -40
  110. package/lib/util/eof.js +30 -30
  111. package/lib/util/json.js +63 -63
  112. package/lib/util/merge.js +14 -14
  113. package/lib/util/objclone.js +40 -40
  114. package/lib/util/spinner.js +37 -37
  115. package/npm-shrinkwrap.json +2 -2
  116. package/package.json +1 -1
  117. package/scripts/postinstall.js +24 -24
  118. package/spec/helpers/reporter.js +65 -65
  119. package/spec/jsSpecs/apiTest/generator.spec.js +372 -372
  120. package/spec/jsSpecs/apiTest/inspector.spec.js +89 -89
  121. package/spec/jsSpecs/apiTest/installer.spec.js +67 -67
  122. package/spec/jsSpecs/apiTest/launcher.spec.js +150 -150
  123. package/spec/jsSpecs/apiTest/packager.spec.js +194 -194
  124. package/spec/jsSpecs/apiTest/puller.spec.js +101 -101
  125. package/spec/jsSpecs/apiTest/pusher.spec.js +103 -103
  126. package/spec/jsSpecs/apiTest/server.spec.js +115 -115
  127. package/spec/jsSpecs/apiTest/setupDevice.spec.js +93 -93
  128. package/spec/jsSpecs/apiTest/shell.spec.js +49 -49
  129. package/spec/jsSpecs/ares-config.spec.js +88 -88
  130. package/spec/jsSpecs/ares-device.spec.js +443 -443
  131. package/spec/jsSpecs/ares-generate.spec.js +397 -401
  132. package/spec/jsSpecs/ares-inspect.spec.js +252 -252
  133. package/spec/jsSpecs/ares-install.spec.js +150 -150
  134. package/spec/jsSpecs/ares-log.spec.js +824 -824
  135. package/spec/jsSpecs/ares-novacom.spec.js +149 -149
  136. package/spec/jsSpecs/ares-pull.spec.js +157 -157
  137. package/spec/jsSpecs/ares-push.spec.js +146 -146
  138. package/spec/jsSpecs/ares-setup-device.spec.js +1 -0
  139. package/spec/jsSpecs/ares-shell.spec.js +220 -220
  140. package/spec/jsSpecs/ares.spec.js +83 -83
  141. package/spec/support/jasmine.json +22 -22
  142. package/spec/tempFiles/nativeApp/auto/pkg_arm64/appinfo.json +9 -9
  143. package/spec/tempFiles/nativeApp/ose/pkg_arm/appinfo.json +8 -8
  144. package/spec/tempFiles/nativeApp/ose/pkg_arm/package.properties +2 -2
  145. package/spec/tempFiles/nativeApp/oseEmul/pkg_x86/appinfo.json +9 -9
  146. package/spec/tempFiles/nativeApp/rsi/pkg_x86/appinfo.json +9 -9
  147. package/spec/tempFiles/sign/sign.crt +32 -32
  148. package/spec/tempFiles/sign/signPriv.key +52 -52
  149. package/spec/test_data/ares-generate.json +58 -91
  150. package/spec/test_data/ares.json +50 -50
  151. package/webos-tools-cli-3.2.1.tgz +0 -0
  152. package/webos-tools-cli-3.2.0.tgz +0 -0
package/lib/device.js CHANGED
@@ -1,1419 +1,1419 @@
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
- createCsvWriter = require('csv-writer').createObjectCsvWriter,
10
- fs = require('fs'),
11
- npmlog = require('npmlog'),
12
- path = require('path'),
13
- streamBuffers = require('stream-buffers'),
14
- Table = require('easy-table'),
15
- util = require('util'),
16
- pullLib = require('./pull'),
17
- errHndl = require('./base/error-handler'),
18
- luna = require('./base/luna'),
19
- novacom = require('./base/novacom'),
20
- createDateFileName = require('./util/createFileName').createDateFileName,
21
- convertJsonToList = require('./util/json').convertJsonToList;
22
-
23
- (function() {
24
- const log = npmlog;
25
- log.heading = 'device';
26
- log.level = 'warn';
27
-
28
- const device = {
29
-
30
- /**
31
- * @property {Object} log an npm log instance
32
- */
33
- log: log,
34
-
35
- /**
36
- * Print system information of the given device
37
- * @property options {String} device the device to connect to
38
- */
39
- systemInfo: function(options, next) {
40
- if (typeof next !== 'function') {
41
- throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
42
- }
43
- options = options || {};
44
- async.series([
45
- _makeSession,
46
- _getOsInfo,
47
- _getDeviceInfo,
48
- _getChromiumVersion,
49
- _getQtbaseVersion,
50
- _getSoftwareInfo
51
- ], function(err, results) {
52
- log.silly("device#systemInfo()", "err:", err, ", results:", results);
53
- let resultTxt = "";
54
- for (let i = 1; i < results.length; i++) {
55
- resultTxt += results[i] + "\n";
56
- }
57
- next(err, {msg: resultTxt.trim()});
58
- });
59
-
60
- function _makeSession(next) {
61
- makeSession(options, next);
62
- }
63
-
64
- function _getOsInfo(next) {
65
- log.info("device#systemInfo()#_getOsInfo()");
66
- const target = options.session.getDevice(),
67
- addr = target.lunaAddr.osInfo,
68
- param = {
69
- // luna param
70
- parameters:["webos_build_id","webos_imagename","webos_name","webos_release",
71
- "webos_manufacturing_version", "core_os_kernel_version"],
72
- subscribe: false
73
- };
74
-
75
- luna.send(options, addr, param, function(lineObj, next) {
76
- const resultValue = lineObj;
77
-
78
- if (resultValue.returnValue) {
79
- log.verbose("device#systemInfo()#_getOsInfo()", "success");
80
- delete resultValue.returnValue; // remove unnecessary data
81
- next(null, _makeReturnTxt(resultValue));
82
- } else {
83
- log.verbose("device#systemInfo()#_getOsInfo()", "failure");
84
- next(errHndl.getErrMsg("INVALID_OBJECT"));
85
- }
86
- }, next);
87
- }
88
-
89
- function _getDeviceInfo(next) {
90
- log.info("device#systemInfo()#_getDeviceInfo()");
91
- const target = options.session.getDevice(),
92
- addr = target.lunaAddr.deviceInfo,
93
- param = {
94
- // luna param
95
- subscribe: false
96
- };
97
-
98
- luna.send(options, addr, param, function(lineObj, next) {
99
- const resultValue = lineObj,
100
- returnObj ={};
101
-
102
- if (resultValue.returnValue) {
103
- log.verbose("device#systemInfo()#_getDeviceInfo()", "success");
104
- returnObj.device_name = resultValue.device_name;
105
- returnObj.device_id = resultValue.device_id;
106
- next(null, _makeReturnTxt(returnObj));
107
- } else {
108
- log.verbose("device#systemInfo()#_getDeviceInfo()", "failure");
109
- next(errHndl.getErrMsg("INVALID_OBJECT"));
110
- }
111
- }, next);
112
- }
113
-
114
- function _getChromiumVersion(next) {
115
- log.info("device#systemInfo()#_getChromiumInfo()");
116
-
117
- // opkg is required permission as root.
118
- if (options.session.getDevice().username !== 'root') {
119
- return next(null, "chromium_version : " + "not supported");
120
- } else {
121
- const cmd = '/usr/bin/opkg list-installed webruntime*';
122
- options.session.run(cmd, null, __data, null, function(err) {
123
- if (err) {
124
- return next(err);
125
- }
126
- });
127
- }
128
- function __data(data) {
129
- const str = (Buffer.isBuffer(data)) ? data.toString() : data,
130
- exp = /\d*\.\d*\.\d*\.\d*/,
131
- version = str.match(exp);
132
-
133
- next(null, "chromium_version : " + version);
134
- }
135
- }
136
-
137
- function _getQtbaseVersion(next) {
138
- log.info("device#systemInfo()#_getQtbaseInfo()");
139
-
140
- // opkg is required permission as root.
141
- if (options.session.getDevice().username !== 'root') {
142
- return next(null, "qt_version : " + "not supported");
143
- } else {
144
- const cmd = '/usr/bin/opkg list-installed qtbase';
145
- options.session.run(cmd, null, __data, null, function(err) {
146
- if (err) {
147
- return next(err);
148
- }
149
- });
150
- }
151
- function __data(data) {
152
- const str = (Buffer.isBuffer(data)) ? data.toString() : data,
153
- exp = /\d*\.\d*\.\d*/,
154
- version = str.match(exp);
155
- next(null, "qt_version : " + version);
156
- }
157
- }
158
-
159
- function _getSoftwareInfo(next) {
160
- log.info("device#systemInfo#_getSoftwareInfo()");
161
- const target = options.session.getDevice(),
162
- addr = target.lunaAddr.softwareInfo,
163
- param = {
164
- parameters: ["nodejs_versions"]
165
- };
166
-
167
- luna.sendWithoutErrorHandle(options, addr, param, function(lineObj, next) {
168
- log.silly("device#systemInfo#_getSoftwareInfo():", "lineObj:", lineObj);
169
-
170
- const resultValue = lineObj,
171
- returnObj ={};
172
-
173
- if (resultValue.returnValue) {
174
- log.verbose("device#systemInfo#_getSoftwareInfo():", "success");
175
- returnObj.nodejs_versions = resultValue.nodejs_versions;
176
- next(null, _makeReturnTxt(returnObj));
177
- } else {
178
- // handle if the target device does not support softwareInfo/query
179
- return next(null, "nodejs_versions : " + "not supported");
180
- }
181
- }, next);
182
- }
183
-
184
- function _makeReturnTxt(resultValue) {
185
- let returnTxt = "";
186
-
187
- for (const key in resultValue) {
188
- if (resultValue[key] === undefined) {
189
- resultValue[key] = "(unknown)";
190
- }
191
- returnTxt += key + " : " + resultValue[key] + "\n";
192
- }
193
- return returnTxt.trim();
194
- }
195
- },
196
- /**
197
- * Print session information of the given device
198
- * @property options {String} device the device to connect to
199
- */
200
- sessionInfo: function(options, next) {
201
- if (typeof next !== 'function') {
202
- throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
203
- }
204
- options = options || {};
205
- async.series([
206
- _makeSession,
207
- _getSessionList
208
- ], function(err, results) {
209
- log.silly("device#sessionInfo()", "err:", err, ", results:", results);
210
- let resultTxt = "";
211
-
212
- if (results[1] !== undefined) {
213
- if (typeof results[1] === "object") {
214
- if (results[1].length === 0) {
215
- return next(errHndl.getErrMsg("SELECT_PROFILE"));
216
- }
217
- for (let i = 0; i < results[1].length; i++) {
218
- resultTxt += convertJsonToList(results[1][i], 0) + '\n';
219
- }
220
- } else {
221
- resultTxt = results[1];
222
- }
223
- }
224
- next(err, {msg: resultTxt.trim()});
225
- });
226
-
227
- function _makeSession(next) {
228
- makeSession(options, next);
229
- }
230
-
231
- function _getSessionList(next) {
232
- log.info("device#sessionInfo#_getSessionList()");
233
- const target = options.session.getDevice(),
234
- addr = target.lunaAddr.getSessionList,
235
- param = {
236
- // luna param
237
- subscribe: false
238
- };
239
-
240
- luna.send(options, addr, param, function(lineObj, next) {
241
- if (lineObj.returnValue) {
242
- log.verbose("device#sessionInfo()#_getSessionList()", "success");
243
- next(null, lineObj.sessionList);
244
- } else {
245
- log.verbose("device#sessionInfo()#_getSessionList()", "failure");
246
- next(errHndl.getErrMsg("INVALID_OBJECT"));
247
- }
248
- }, next);
249
- }
250
- },
251
- /**
252
- * Print system information of the given device
253
- * @property options {String} device the device to connect to
254
- */
255
- tvSystemInfo: function(options, next) {
256
- if (typeof next !== 'function') {
257
- throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
258
- }
259
- options = options || {};
260
- async.series([
261
- _makeSession,
262
- _getSystemInfo,
263
- ], function(err, results) {
264
- log.silly("device#tvSystemInfo()", "err:", err, ", results:", results);
265
- next(err, {msg: results[1]});
266
- });
267
-
268
- function _makeSession(next) {
269
- makeSession(options, next);
270
- }
271
-
272
- function _getSystemInfo(next) {
273
- log.info("device#tvSystemInfo#_getSystemInfo()");
274
- const target = options.session.getDevice(),
275
- addr = target.lunaAddr.deviceInfoSystem,
276
- param = {
277
- // luna param
278
- keys: ["modelName", "sdkVersion", "firmwareVersion", "boardType", "otaId"],
279
- subscribe: false
280
- };
281
-
282
- luna.sendWithoutErrorHandle(options, addr, param, function (lineObj, next) {
283
- if (lineObj) {
284
- log.verbose("deviceInfo#systemInfo#_getSystemInfo():", "success");
285
- next(null, __makeReturnObj(lineObj, param.keys));
286
- } else {
287
- next(errHndl.getErrMsg("INVALID_OBJECT"));
288
- }
289
- }, next);
290
- }
291
-
292
- function __makeReturnObj(resultValue, paramkey) {
293
- let returnTxt = "";
294
-
295
- for (const key in paramkey) {
296
- if (Object.hasOwnProperty.call(resultValue, paramkey[key]))
297
- returnTxt += paramkey[key] + " : " + resultValue[paramkey[key]] + "\n";
298
- }
299
- log.verbose("deviceInfo#systemInfo#__makeReturnObj():", returnTxt);
300
- return returnTxt.trim();
301
- }
302
- },
303
- /**
304
- * Get all CPUs and memories usage of target device
305
- * @property options {String} device, interval
306
- */
307
- systemResource: function(options, next) {
308
- if (typeof next !== 'function') {
309
- throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
310
- }
311
- const systemGroup = {};
312
- systemGroup.initialExecution = true;
313
- options = options || {};
314
- options.destinationPath = "";
315
- options.fileName = "";
316
- options.csvPath = "";
317
- async.series([
318
- _createOutputPath,
319
- _makeSession,
320
- _getSystemResouceInfo
321
- ], function(err, results) {
322
- log.silly("device#systemResource()", "err:", err, ", results:", results);
323
- next(err);
324
- });
325
-
326
- function _createOutputPath(next) {
327
- if (options.save && options.csvPath === "") {
328
- makeCSVOutputPath(options, next);
329
- } else {
330
- next();
331
- }
332
- }
333
-
334
- function _makeSession(next) {
335
- makeSession(options, next);
336
- }
337
-
338
- function _getSystemResouceInfo(next) {
339
- log.info("device#systemResource()#_getSystemResouceInfo()");
340
-
341
- let timerId;
342
- if (!options.interval) {
343
- // If interval option is not given, call timer logic 2 times
344
- const defaultRepeat = 2;
345
- let repeatCount = 0;
346
- try {
347
- timerId = setTimeout(function repeat() {
348
- if (repeatCount < defaultRepeat) {
349
- _callSystemResourceInfoCmd();
350
- repeatCount++;
351
- timerId = setTimeout(repeat, 1000);
352
- } else {
353
- clearTimeout(timerId);
354
- return next();
355
- }
356
- }, 100);
357
- } catch (err) {
358
- log.silly("device#systemResource()#_getSystemResouceInfo()", "one timer. err:", err.toString());
359
- clearTimeout(timerId);
360
- // ignore timer logic error
361
- return next();
362
- }
363
- } else {
364
- try {
365
- // when interval option is given, print initial data at first
366
- const defaultRepeat = 1;
367
- let repeatCount = 0;
368
- timerId = setTimeout(function repeat() {
369
- if (repeatCount < defaultRepeat) {
370
- _callSystemResourceInfoCmd();
371
- repeatCount++;
372
- timerId = setTimeout(repeat, 1000);
373
- } else {
374
- _callSystemResourceInfoCmd();
375
- timerId = setTimeout(repeat, options.interval * 1000);
376
- }
377
- }, 100);
378
- } catch (err) {
379
- log.silly("device#systemResource()#_getSystemResouceInfo()", "repeat timer. err:", err.toString());
380
- clearTimeout(timerId);
381
- // ignore timer logic error
382
- return next();
383
- }
384
- }
385
- }
386
-
387
- function _callSystemResourceInfoCmd() {
388
- log.info("device#systemResource()#_callSystemResourceInfoCmd()");
389
-
390
- const wStream = new streamBuffers.WritableStreamBuffer();
391
- const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep -c ^processor /proc/cpuinfo; grep "cpu *" /proc/stat; free -k';
392
- try {
393
- options.session.run(cmd, null, wStream, null, function(err) {
394
- if (err) {
395
- // do not print error message to user
396
- // when user press Ctrl + C , the ssh connection is not completed, it makes error
397
- log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "ssh call. err:"+ err.toString());
398
- return next();
399
- } else {
400
- const result = wStream.getContentsAsString();
401
- _setSystemResouceInfo(result);
402
- systemGroup.initialExecution = false;
403
- }
404
- });
405
- } catch (err) {
406
- // do not print error message to user
407
- // when user press Ctrl + C , the ssh connection is not completed, it makes error
408
- log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "in try-catch. err:", err.toString());
409
- return next();
410
- }
411
- }
412
-
413
- function _setSystemResouceInfo(systemData) {
414
- log.info("device#systemResource()#_callSystemResourceInfoCmd()");
415
-
416
- const CPU_PATTERN = /\s+/,
417
- cpuinfo = {},
418
- meminfo = {};
419
- let sysinfo = {};
420
- try {
421
- const allvalues = systemData.split("\n"),
422
- date = allvalues[0], // Setup date
423
- pcore = +allvalues[1] * 100;
424
- let index,
425
- columns,
426
- isBuff_Cached = false; // This is to check the format version of kernel to find system memory parameter
427
- for (index = 2; index < (allvalues.length - 1); index++) {
428
- columns = allvalues[index].split(CPU_PATTERN);
429
- // setup CPU information
430
- if (columns[0].indexOf("cpu") === 0) {
431
- const prevTotal = "prev" + columns[0] + "Total",
432
- prevIdle = "prev" + columns[0] + "Idle",
433
- prevUser = "prev" + columns[0] + "User",
434
- prevkernel = "prev" + columns[0] + "Kernel",
435
- prevOther = "prev" + columns[0] + "Other";
436
- if (!systemGroup[prevTotal]) {
437
- systemGroup[prevTotal] = 0;
438
- systemGroup[prevIdle] = 0;
439
- systemGroup[prevUser] = 0;
440
- systemGroup[prevkernel] = 0;
441
- systemGroup[prevOther] = 0;
442
- }
443
- const user = parseInt(columns[1]),
444
- nice = parseInt(columns[2]),
445
- kernel = parseInt(columns[3]),
446
- idle = parseInt(columns[4]),
447
- other = nice + parseInt(columns[5]) + parseInt(columns[6]) + parseInt(columns[7]) + parseInt(columns[8]) +
448
- parseInt(columns[9]) + parseInt(columns[10]),
449
- subTotal = user + nice + kernel + idle + other;
450
-
451
- if (!systemGroup.initialExecution) {
452
- const diffIdle = idle - systemGroup[prevIdle],
453
- diffUser = user - systemGroup[prevUser],
454
- diffKernel = kernel - systemGroup[prevkernel],
455
- diffOther = other - systemGroup[prevOther],
456
- diffTotal = subTotal - systemGroup[prevTotal];
457
-
458
- let userModeCpuOccupation = (diffUser/diffTotal) * 100,
459
- kernelModeCpuOccupation = (diffKernel/diffTotal) * 100,
460
- otherModeCpuOccupation = (diffOther/diffTotal) * 100,
461
- overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100;
462
-
463
- userModeCpuOccupation < 0 ? (userModeCpuOccupation = 0) : userModeCpuOccupation;
464
- userModeCpuOccupation > pcore ? (userModeCpuOccupation = pcore) : userModeCpuOccupation;
465
- kernelModeCpuOccupation < 0 ? (kernelModeCpuOccupation = 0) : kernelModeCpuOccupation;
466
- kernelModeCpuOccupation > pcore ? (kernelModeCpuOccupation = pcore) : kernelModeCpuOccupation;
467
- otherModeCpuOccupation < 0 ? (otherModeCpuOccupation = 0) : otherModeCpuOccupation;
468
- otherModeCpuOccupation > pcore ? (otherModeCpuOccupation = pcore) : otherModeCpuOccupation;
469
- overallCpuOccupation < 0 ? (overallCpuOccupation = 0) : overallCpuOccupation;
470
- overallCpuOccupation > pcore ? (overallCpuOccupation = pcore) : overallCpuOccupation;
471
-
472
- cpuinfo[columns[0]] = {
473
- "overall": +overallCpuOccupation.toFixed(2),
474
- "usermode": +userModeCpuOccupation.toFixed(2),
475
- "kernelmode": +kernelModeCpuOccupation.toFixed(2),
476
- "others": +otherModeCpuOccupation.toFixed(2)
477
- };
478
- }
479
- systemGroup[prevIdle] = idle;
480
- systemGroup[prevUser] = user;
481
- systemGroup[prevkernel] = kernel;
482
- systemGroup[prevOther] = other;
483
- systemGroup[prevTotal] = subTotal;
484
- }
485
-
486
- if (!systemGroup.initialExecution) {
487
- // setup memory infomation
488
- if (columns[5] && columns[5].indexOf('buff/cache') !== -1) {
489
- isBuff_Cached = true;
490
- }
491
- if (columns[0].indexOf('Mem:') === 0) {
492
- meminfo['memory'] = !isBuff_Cached ? {
493
- "total": +columns[1],
494
- "used": +columns[2],
495
- "free": +columns[3],
496
- "shared": +columns[4],
497
- "buffers": +columns[5],
498
- "cached": +columns[6]
499
- } : {
500
- "total": +columns[1],
501
- "used": +columns[2],
502
- "free": +columns[3],
503
- "shared": +columns[4],
504
- "buff_cache": +columns[5],
505
- "available": +columns[6]
506
- };
507
- }
508
- if (columns[0].indexOf('-/+') === 0) {
509
- meminfo['buffers'] = {
510
- "used": +columns[2],
511
- "free": +columns[3]
512
- };
513
- }
514
- if (columns[0].indexOf('Swap:') === 0) {
515
- meminfo['swap'] = {
516
- "total": +columns[1],
517
- "used": +columns[2],
518
- "free": +columns[3]
519
- };
520
- }
521
- }
522
- }
523
- if (!systemGroup.initialExecution) {
524
- sysinfo = {
525
- "date": date,
526
- "cpuinfo": cpuinfo,
527
- "meminfo": meminfo
528
- };
529
- _printSystemInfo(sysinfo);
530
- }
531
- } catch (err) {
532
- // do not print error message to user
533
- // when user press Ctrl + C , the ssh cmd data is not completed, it makes error
534
- log.silly("device#systemResource()#_setSystemResouceInfo()", "in try-catch. err:", err.toString());
535
- return;
536
- }
537
- }
538
-
539
- function _printSystemInfo(sysinfo) {
540
- const cpuinfo = sysinfo.cpuinfo,
541
- meminfo = sysinfo.meminfo,
542
- cpuinfoTable = new Table(),
543
- meminfoTable = new Table(),
544
- dataForCSV = [];
545
-
546
- // add CPU info to the table
547
- for (const key in cpuinfo) {
548
- cpuinfoTable.cell('(%)', key);
549
- cpuinfoTable.cell('overall', cpuinfo[key].overall);
550
- cpuinfoTable.cell('usermode', cpuinfo[key].usermode);
551
- cpuinfoTable.cell('kernelmode', cpuinfo[key].kernelmode);
552
- cpuinfoTable.cell('others', cpuinfo[key].others);
553
- cpuinfoTable.newRow();
554
-
555
- // Add csv array
556
- const obj = {
557
- time: sysinfo.date,
558
- cpu: key,
559
- overall: cpuinfo[key].overall,
560
- usermode: cpuinfo[key].usermode,
561
- kernelmode: cpuinfo[key].kernelmode,
562
- others: cpuinfo[key].others
563
- };
564
- dataForCSV.push(obj);
565
- }
566
- // add memoryInfo to the table
567
- for (const key in meminfo) {
568
- meminfoTable.cell('(KB)', key);
569
- meminfoTable.cell('total', meminfo[key].total);
570
- meminfoTable.cell('used', meminfo[key].used);
571
- meminfoTable.cell('free', meminfo[key].free);
572
- meminfoTable.cell('shared', meminfo[key].shared);
573
- meminfoTable.cell('buff/cache', meminfo[key].buff_cache);
574
- meminfoTable.cell('available', meminfo[key].available);
575
- meminfoTable.newRow();
576
-
577
- const obj = {
578
- time: sysinfo.date,
579
- memory: key,
580
- total: meminfo[key].total,
581
- used: meminfo[key].used,
582
- free: meminfo[key].free,
583
- shared: meminfo[key].shared,
584
- "buff/cache": meminfo[key].buff_cache,
585
- available: meminfo[key].available
586
- };
587
- dataForCSV.push(obj);
588
- }
589
- // write CSV file if user gives --save option
590
- if (options.save && options.csvPath) {
591
- // write csv file
592
- // when openMode is false, the new csv file will be created and "Header" add to the file
593
- let openMode = false;
594
- if (fs.existsSync(options.csvPath)) {
595
- openMode = true;
596
- }
597
-
598
- const csvWriter = createCsvWriter({
599
- path: options.csvPath,
600
- header: [
601
- {id: 'time', title: 'time'},
602
- {id: 'cpu', title: '(%)'},
603
- {id: 'overall', title: 'overall'},
604
- {id: 'usermode', title: 'usermode'},
605
- {id: 'kernelmode', title: 'kernelmode'},
606
- {id: 'others', title: 'others'},
607
- {id: 'memory', title: '(KB)'},
608
- {id: 'total', title: 'total'},
609
- {id: 'used', title: 'used'},
610
- {id: 'free', title: 'free'},
611
- {id: 'shared', title: 'shared'},
612
- {id: 'buff/cache', title: 'buff/cache'},
613
- {id: 'available', title: 'available'}
614
- ],
615
- append: openMode
616
- });
617
-
618
- csvWriter
619
- .writeRecords(dataForCSV)
620
- .then(function() {
621
- log.silly("device#systemResource()#_printSystemInfo()", "CSV file updated");
622
- // csv file has been created at first
623
- if (openMode === false) {
624
- const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath;
625
- console.log(resultTxt);
626
- }
627
- __printTable();
628
- }).catch(function(err) {
629
- return setImmediate(next, errHndl.getErrMsg(err));
630
- });
631
- } else {
632
- __printTable();
633
- }
634
-
635
- function __printTable() {
636
- console.log(sysinfo.date + "\n");
637
- console.log(cpuinfoTable.toString());
638
- console.log(meminfoTable.toString());
639
- console.log("=================================================================");
640
- }
641
- }
642
- },
643
- /**
644
- * Get running apps and services CPUs and memories usage
645
- * @property options {String} device, interval
646
- */
647
- processResource: function(options, next) {
648
- if (typeof next !== 'function') {
649
- throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
650
- }
651
-
652
- const processGroup = {};
653
- processGroup.initialExecution = true;
654
- options = options || {};
655
- options.destinationPath = "";
656
- options.fileName = "";
657
- options.csvPath = "";
658
-
659
- async.series([
660
- _createOutputPath,
661
- _makeSession,
662
- _getProcessResouceInfo
663
- ], function(err, results) {
664
- log.silly("device#processResource()", "err:", err, ", results:", results);
665
- next(err);
666
- });
667
-
668
- function _createOutputPath(next) {
669
- if (options.save && options.csvPath === "") {
670
- makeCSVOutputPath(options, next);
671
- } else {
672
- next();
673
- }
674
- }
675
-
676
- function _makeSession(next) {
677
- makeSession(options, next);
678
- }
679
-
680
- function _getProcessResouceInfo(next) {
681
- log.info("device#processResource()#_getProcessResouceInfo()");
682
-
683
- let timerId;
684
- if (!options.interval) {
685
- // If interval option is not given, call timer logic 2 times
686
- const defaultRepeat = 2;
687
- let repeatCount = 0;
688
- try {
689
- timerId = setTimeout(function repeat() {
690
- if (repeatCount < defaultRepeat) {
691
- _callProcessInfoCmd();
692
- repeatCount++;
693
- timerId = setTimeout(repeat, 1000);
694
- } else {
695
- clearTimeout(timerId);
696
- return next();
697
- }
698
- }, 100);
699
- } catch (err) {
700
- log.silly("device#systemResource()#_getProcessResouceInfo()", "one timer. err:", err.toString());
701
- clearTimeout(timerId);
702
- // ignore timer logic error
703
- return next();
704
- }
705
- } else {
706
- try {
707
- // when interval option is given, print initial data at first
708
- const defaultRepeat = 1;
709
- let repeatCount = 0;
710
- timerId = setTimeout(function repeat() {
711
- if (repeatCount < defaultRepeat) {
712
- _callProcessInfoCmd();
713
- repeatCount++;
714
- timerId = setTimeout(repeat, 1000);
715
- } else {
716
- _callProcessInfoCmd();
717
- timerId = setTimeout(repeat, options.interval * 1000);
718
- }
719
- }, 100);
720
- } catch (err) {
721
- log.silly("device#systemResource()#_getProcessResouceInfo()", "repeat timer. err:", err.toString());
722
- clearTimeout(timerId);
723
- // ignore timer logic error
724
- return next();
725
- }
726
- }
727
- }
728
-
729
- function _callProcessInfoCmd() {
730
- log.info("device#processResource()#_callProcessInfoCmd()");
731
-
732
- const wStream = new streamBuffers.WritableStreamBuffer();
733
- const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep "cpu *" /proc/stat | sed "1d" | awk \'{for (i=0;i<NR;i++){if (i==NR-1){totalSum+=$2+$3+$4+$5+$6+$7+$8+$9+$10+$11;idleSum+=$5}}} END { for (i=0;i<NR;i++){if (i==NR-1){print idleSum;print totalSum}}}\'; cat /proc/[0-9]*/stat; echo \'psList\' ; ps -ax | sed "1d" | awk \'/ /{print $1 "\t"$5}\'; echo \'serviceStringStart\'; ls /media/developer/apps/usr/palm/services ; echo \'serviceStringEnd\'; luna-send-pub -n 1 -f luna://com.webos.applicationManager/dev/running \'{}\'; grep -c ^processor /proc/cpuinfo';
734
- try {
735
- options.session.run(cmd, null, wStream, null, function(err) {
736
- if (err) {
737
- // do not print error message to user
738
- // when user press Ctrl + C , the ssh connection is not completed, it makes error
739
- log.silly("device#processResource()#_callProcessInfoCmd()", "ssh call. err:", err.toString());
740
- return next(null);
741
- } else {
742
- const result = wStream.getContentsAsString();
743
- _setProcessInfo(result);
744
- processGroup.initialExecution = false;
745
- }
746
- });
747
- } catch (err) {
748
- // do not print error message to user
749
- // when user press Ctrl + C , the ssh connection is not completed, it makes error
750
- log.silly("device#processResource()#_callProcessInfoCmd()", "in try-catch. err:", err.toString());
751
- return next(null);
752
- }
753
- }
754
-
755
- function _setProcessInfo(processData) {
756
- log.info("device#processResource()#_setProcessInfo()");
757
- const PROC_GROUP_INFO_PATTERN = /\s+/;
758
- try {
759
- // Intialize temporary groups with values
760
- const processList = ["Service", "System"],
761
- groupProcessList = [],
762
- tempProcGrps = {},
763
- arrActiveServices = [];
764
- // loop through all the categories and create groups
765
- for (let i = 0; i < processList.length; i++) {
766
- tempProcGrps[processList[i]] = {};
767
- tempProcGrps[processList[i]]["pid"] = 0;
768
- tempProcGrps[processList[i]]["cputime"] = 0;
769
- tempProcGrps[processList[i]]["RSS"] = 0;
770
- tempProcGrps[processList[i]]["pmem"] = 0;
771
- }
772
-
773
- const processinfo = [],
774
- groupProcessinfo = [], // only for dev app & service info
775
- allvalues = processData.split("\n"),
776
- otherList = [],
777
- date = allvalues[0],
778
- lastIndex = allvalues.length;
779
-
780
- allvalues.splice(lastIndex - 1, 1);
781
- const pcore = +allvalues[allvalues.length-1] * 100;
782
- /* memCol[1] from 'grep "MemTotal *" /proc/meminfo' is not used */
783
- let totalRAM = 0;
784
- const idleCPUtime = +allvalues[1],
785
- totalCPUtime = +allvalues[2],
786
- psListStartIndex = allvalues.indexOf("psList", 2),
787
- serviceStartIndex = allvalues.indexOf("serviceStringStart", 2), // from where to start (2)
788
- serviceEndIndex = allvalues.indexOf("serviceStringEnd", 2); // from where to start (2)
789
-
790
- const arryInstalledServices = [];
791
- for (let i = serviceStartIndex + 1; i < serviceEndIndex; i++) {
792
- arryInstalledServices[i-serviceStartIndex-1] = allvalues[i];
793
- }
794
-
795
- // get processid of external service on ps list
796
- let arrayCount = 0;
797
- for (let k = psListStartIndex+1 ; k < serviceStartIndex ;k++) {
798
- const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN),
799
- pid = parseInt(columns[0]),
800
- procname = columns[1].trim();
801
-
802
- if (arryInstalledServices.indexOf(procname) !== -1) {
803
- const ObjService = {
804
- "processid": pid,
805
- "id": procname
806
- };
807
- arrActiveServices[arrayCount++] = ObjService;
808
- }
809
- }
810
-
811
- const appStartIndex = allvalues.indexOf("{", 2); // From where to start (2)
812
- // some times specific platform does not gives list of running info itself then appStartIndex becomes -1
813
- if (appStartIndex < 0) {
814
- // do not print error message to user
815
- // when user press Ctrl + C , the ssh cmd data is not completed, it makes error
816
- log.silly("device#processResource()#_setProcessInfo()", "running app list is invalid");
817
- return;
818
- }
819
- const appEndIndex = allvalues.length-1;
820
- let strActiveApps = "",
821
- objActiveApps;
822
- for (let i = appStartIndex; i < appEndIndex; i++) {
823
- strActiveApps += allvalues[i];
824
- }
825
- try {
826
- objActiveApps = JSON.parse(strActiveApps);
827
- } catch (err) {
828
- // do not print error message to user
829
- // when user press Ctrl + C , the ssh cmd data is not completed, it makes error
830
- log.silly("device#processResource()#_setProcessInfo()", "active app parsing. err:", err.toString());
831
- return;
832
- }
833
-
834
- if (objActiveApps.returnValue === false) {
835
- const errValue = objActiveApps["errorText"] || "running app list is invalid";
836
- return next(errHndl.getErrMsg("FAILED_CALL_LUNA", errValue, null, "com.webos.applicationManager"));
837
- }
838
-
839
- const arrActiveApps = objActiveApps["running"],
840
- groupObjList = {};
841
-
842
- // 1st row is date, 2nd row is total CPU time and last row is total RAM(Meminfo) hence ignore it
843
- // check process group info until "psList" string
844
- for (let k = 3; k < psListStartIndex; k++) {
845
- const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN),
846
- procname = columns[1].trim().split(/.*\(|\)/gi)[1],
847
- grpname = _getProcessGrp(procname),
848
- pid = parseInt(columns[0]),
849
- pname = procname,
850
- ppid = parseInt(columns[3]),
851
- cputime = parseInt(columns[13]) + parseInt(columns[14]),
852
- rss = parseInt(columns[23]) * 4,
853
- pmem = (rss * 100);
854
- // sum total used RSS
855
- totalRAM += rss;
856
- if (grpname === "Other") {
857
- const objOther = {};
858
- objOther["pid"] = pid;
859
- objOther["pname"] = pname;
860
- objOther["ppid"] = ppid;
861
- objOther["cputime"] = cputime;
862
- objOther["RSS"] = rss;
863
- objOther["pmem"] = pmem;
864
- otherList.push(objOther);
865
- } else {
866
- tempProcGrps[grpname]["pid"] = pid;
867
- tempProcGrps[grpname]["cputime"] += cputime;
868
- tempProcGrps[grpname]["RSS"] += rss;
869
- tempProcGrps[grpname]["pmem"] += pmem;
870
- }
871
- }
872
- // get the Children of Service
873
- for (const k in tempProcGrps) {
874
- const attrName = k;
875
- if (attrName === "System") {
876
- continue;
877
- }
878
- const objOther = tempProcGrps[k];
879
- for (let i = 0; i < otherList.length; i++) {
880
- if (objOther["pid"] !== otherList[i]["ppid"]) {
881
- continue;
882
- }
883
- }
884
- }
885
-
886
- // this variable will mantain the aggregate pcpuVal of Service + dynamic apps
887
- let aggcpuVal = 0;
888
- // get the Web App processes data
889
- if (arrActiveApps.length === 0) {
890
- // get only the existing categories(3) if no running apps.
891
- // dispose all the existing process variables
892
- for (const name in processGroup) {
893
- // if propertyName starts with "prev_" then dispose it
894
- if (!Object.prototype.hasOwnProperty.call(processGroup, name)) {
895
- continue;
896
- }
897
- if (name.indexOf("prev_app_") >= 0) {
898
- processGroup[name] = undefined;
899
- }
900
- }
901
- } else {
902
- // loop through each of the running apps
903
- // in loop - Check if app is newly running app (or) already existing running app
904
- for (let j = 0; j < arrActiveApps.length; j++) {
905
- const objActApp = arrActiveApps[j],
906
- webprocId = objActApp["webprocessid"],
907
- procId = objActApp["processid"],
908
- displayId = objActApp["displayId"] || 0;
909
- let processId;
910
- if (webprocId !== "" && webprocId !== undefined && webprocId !== "undefined") {
911
- processId = webprocId;
912
- } else if (procId !== "" && procId !== undefined && procId !== "undefined") {
913
- processId = procId;
914
- } else {
915
- break;
916
- }
917
-
918
- const prevcpuTime = "prev_app_" + processId + "cputime",
919
- appid = parseInt(processId);
920
- let pcputime = 0;
921
- // get the cputime from otherList
922
- for (let l = 0; l < otherList.length; l++) {
923
- if (otherList[l]["pid"] !== appid) {
924
- continue;
925
- }
926
- pcputime = otherList[l]["cputime"];
927
- if (!processGroup[prevcpuTime]) {
928
- processGroup[prevcpuTime] = pcputime;
929
- break;
930
- }
931
- let webpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime));
932
- // restrict showing the negative % values by making lowest to be zero.
933
- if (webpcpuval < 0 || webpcpuval === undefined || isNaN(webpcpuval)) webpcpuval = 0;
934
- aggcpuVal += webpcpuval;
935
- const groupListAppKey = objActApp["id"]+ "-" + appid;
936
- groupObjList[groupListAppKey] = {
937
- "id": objActApp["id"],
938
- "pid": appid,
939
- "cpu": webpcpuval,
940
- "memory": {
941
- "size": otherList[l]["RSS"],
942
- "percent": otherList[l]["pmem"].toFixed(2)
943
- },
944
- "displayId": displayId
945
- };
946
- processGroup[prevcpuTime] = pcputime;
947
- otherList.splice(l, 1);
948
- break;
949
- }
950
- }
951
- }
952
- // get the service processes data
953
- if (arrActiveServices.length === 0) {
954
- // get only the existing categories(3) if no running apps.
955
- // dispose all the existing process variables
956
- for (const name in processGroup) {
957
- // if propertyName starts with "prev_" then dispose it
958
- if (!Object.prototype.hasOwnProperty.call(processGroup, name)) {
959
- continue;
960
- }
961
- if (name.indexOf("prev_svc_") >= 0) {
962
- processGroup[name] = undefined;
963
- }
964
- }
965
- } else {
966
- // loop through each of the running apps
967
- // in loop - Check if app is newly running app (or) already existing running app
968
- for (let j = 0; j < arrActiveServices.length; j++) {
969
- const objActService = arrActiveServices[j],
970
- processId = objActService["processid"],
971
- prevcpuTime = "prev_svc_" + processId + "cputime",
972
- appid = parseInt(processId);
973
- let pcputime = 0;
974
- // get the cputime from otherList
975
- for (let l = 0; l < otherList.length; l++) {
976
- if (otherList[l]["pid"] !== appid) {
977
- continue;
978
- }
979
- pcputime = otherList[l]["cputime"];
980
- if (!processGroup[prevcpuTime]) {
981
- processGroup[prevcpuTime] = pcputime;
982
- break;
983
- }
984
- let svcpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime));
985
- // restrict showing the negative % values by making lowest to be zero.
986
- if (svcpcpuval < 0 || svcpcpuval === undefined || isNaN(svcpcpuval)) svcpcpuval = 0;
987
- aggcpuVal+= svcpcpuval;
988
- groupObjList[objActService["id"]] = {
989
- "pid": appid,
990
- "cpu": svcpcpuval,
991
- "memory": {
992
- "size": otherList[l]["RSS"],
993
- "percent": otherList[l]["pmem"].toFixed(2)
994
- }
995
- };
996
- processGroup[prevcpuTime] = pcputime;
997
- otherList.splice(l, 1);
998
- break;
999
- }
1000
- }
1001
- }
1002
- // get the remaining System Category processes
1003
- for (let i = 0; i < otherList.length; i++) {
1004
- tempProcGrps["System"]["pid"] = otherList[i]["pid"];
1005
- tempProcGrps["System"]["cputime"]+= otherList[i]["cputime"];
1006
- tempProcGrps["System"]["RSS"]+= otherList[i]["RSS"];
1007
- tempProcGrps["System"]["pmem"]+= otherList[i]["pmem"];
1008
- }
1009
- if (!processGroup.initialExecution) {
1010
- const diffIdle = idleCPUtime - processGroup.prevIdlecputime,
1011
- diffTotal = totalCPUtime - processGroup.prevTotalcputime,
1012
- overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100;
1013
- // assign all the values to return Object
1014
- for (const key in tempProcGrps) {
1015
- const processName = key;
1016
- let tempPcpuval = 0;
1017
- if (processName === "Service") {
1018
- tempPcpuval = ((tempProcGrps[processName]["cputime"] - processGroup.prevServicecputime) * 100/diffTotal);
1019
- }
1020
- // restrict showing the negative % values by making lowest to be zero.
1021
- if (tempPcpuval < 0 || tempPcpuval === undefined || isNaN(tempPcpuval)) tempPcpuval = 0;
1022
- aggcpuVal += tempPcpuval;
1023
- // system = overallCpuOccupation - (Service used + dynamic apps used);
1024
- if (processName === "System") {
1025
- tempPcpuval = overallCpuOccupation - aggcpuVal;
1026
- }
1027
- // restrict Negative/peak values due to cores fluctuation
1028
- tempPcpuval < 0 ? (tempPcpuval = 0) : tempPcpuval;
1029
- tempPcpuval > pcore ? (tempPcpuval = pcore) : tempPcpuval;
1030
- tempProcGrps[processName]["pmem"] /= totalRAM;
1031
- const procinfo = {
1032
- "pid": tempProcGrps[processName]["pid"],
1033
- "appid": processName,
1034
- "cpu": parseFloat(tempPcpuval.toFixed(2)),
1035
- "memory": {
1036
- "size": tempProcGrps[processName]["RSS"],
1037
- "percent": tempProcGrps[processName]["pmem"].toFixed(2)
1038
- }
1039
- };
1040
- processinfo.push(procinfo);
1041
- }
1042
- // push the calculated groups into list
1043
- for (const propertyName in groupObjList) {
1044
- if (!Object.prototype.hasOwnProperty.call(groupObjList, propertyName)) {
1045
- continue;
1046
- }
1047
-
1048
- const procObj = groupObjList[propertyName];
1049
- let pcpuval = parseFloat(procObj["cpu"].toFixed(2));
1050
- if (pcpuval === undefined || isNaN(pcpuval)) {
1051
- pcpuval = 0;
1052
- }
1053
- procObj["memory"]["percent"] /= totalRAM;
1054
- const procinfo = {
1055
- "pid": procObj["pid"],
1056
- "appid": procObj["id"] || propertyName,
1057
- "cpu": pcpuval,
1058
- "memory": {
1059
- "size": procObj["memory"]["size"],
1060
- "percent": parseFloat(procObj["memory"]["percent"]).toFixed(2)
1061
- },
1062
- "displayId": procObj["displayId"]
1063
- };
1064
-
1065
- processinfo.push(procinfo);
1066
- // copy only app and service info to group for printing
1067
- groupProcessinfo.push(procinfo);
1068
-
1069
- if (processinfo.indexOf(propertyName) < 0) {
1070
- processList.push(propertyName);
1071
- groupProcessList.push(propertyName);
1072
- }
1073
- }
1074
- }
1075
- processGroup.prevIdlecputime = idleCPUtime;
1076
- processGroup.prevTotalcputime = totalCPUtime;
1077
- processGroup.prevServicecputime = tempProcGrps["Service"]["cputime"];
1078
-
1079
- if (!processGroup.initialExecution) {
1080
- const processgrpinfo = {
1081
- "date": date,
1082
- "processinfo": groupProcessinfo,
1083
- "processList": groupProcessList
1084
- };
1085
- _printProcessList(processgrpinfo);
1086
- }
1087
- } catch (err) {
1088
- // do not print error message to user
1089
- // when user press Ctrl + C , the ssh cmd data is not completed, it makes error
1090
- log.silly("device#processResource()#_setProcessInfo()", "in try-catch. err:", err.toString());
1091
- return;
1092
- }
1093
- }
1094
-
1095
- function _getProcessGrp(pname) {
1096
- let group;
1097
- switch (pname) {
1098
- case 'ls-hubd':
1099
- group = 'Service'; break;
1100
- default:
1101
- group = 'Other'; // it could be children of above categories or System
1102
- }
1103
- return group;
1104
- }
1105
-
1106
- function _printProcessList(processgrpinfo) {
1107
- log.info("device#processResource()#_printProcessList()", JSON.stringify(processgrpinfo));
1108
-
1109
- const processinfo = processgrpinfo.processinfo,
1110
- processinfoTable = new Table();
1111
-
1112
- let found = false;
1113
- if (options.id) {
1114
- processinfo.forEach(function(process) {
1115
- if (options.id === process.appid) {
1116
- found = true;
1117
- }
1118
- });
1119
- if (found === false) {
1120
- // print guide message to user
1121
- console.log("<" + options.id + ">" + " is not running. Please launch the app or service.");
1122
- return;
1123
- }
1124
- }
1125
- if (processgrpinfo.processList.length === 0) {
1126
- // print guide message to user
1127
- console.log("There are no running apps or services. Please launch any app or service.");
1128
- return;
1129
- }
1130
-
1131
- // add process list to table
1132
- const dataForCSV = [];
1133
- if (Array.isArray(processinfo)) {
1134
- processinfo.forEach(function(process) {
1135
- // if user gives ID, print only the ID's information
1136
- if (options.id && options.id !== process.appid) {
1137
- return;
1138
- }
1139
- processinfoTable.cell('PID', process.pid);
1140
- processinfoTable.cell('ID', process.appid);
1141
- processinfoTable.cell('DISPLAY ID', process.displayId);
1142
- processinfoTable.cell('CPU(%)', process.cpu);
1143
-
1144
- const meminfo = process.memory;
1145
- processinfoTable.cell('MEMORY(%)', meminfo.percent);
1146
- processinfoTable.cell('MEMORY(KB)', meminfo.size);
1147
- processinfoTable.newRow();
1148
-
1149
- // add data object
1150
- const obj = {
1151
- time: processgrpinfo.date,
1152
- pid: process.pid,
1153
- id: process.appid,
1154
- displayId: process.displayId,
1155
- cpu: process.cpu,
1156
- memory: meminfo.percent,
1157
- memory_size: meminfo.size
1158
- };
1159
- dataForCSV.push(obj);
1160
- });
1161
- }
1162
- // write CSV file if user gives --save option
1163
- if (options.save && options.csvPath) {
1164
- // write csv file
1165
- // when openMode is false, the new csv file will be created and "Header" add to the file
1166
- let openMode = false;
1167
- if (fs.existsSync(options.csvPath)) {
1168
- openMode = true;
1169
- }
1170
- const csvWriter = createCsvWriter({
1171
- path: options.csvPath,
1172
- header: [
1173
- {id: 'time', title: 'TIME'},
1174
- {id: 'pid', title: 'PID'},
1175
- {id: 'id', title: 'ID'},
1176
- {id: 'displayId', title: 'DISPLAY ID'},
1177
- {id: 'cpu', title: 'CPU(%)'},
1178
- {id: 'memory', title: 'MEMORY(%)'},
1179
- {id: 'memory_size', title: 'MEMORY(KB)'}
1180
- ],
1181
- append: openMode
1182
- });
1183
-
1184
- csvWriter
1185
- .writeRecords(dataForCSV)
1186
- .then(function() {
1187
- log.silly("device#processResource()#_printProcessList()", "CSV file updated");
1188
- // csv file has been created at first
1189
- if (openMode === false) {
1190
- const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath;
1191
- console.log(resultTxt);
1192
- }
1193
- __printTable();
1194
- }).catch(function(err) {
1195
- return setImmediate(next, errHndl.getErrMsg(err));
1196
- });
1197
- } else {
1198
- __printTable();
1199
- }
1200
-
1201
- function __printTable() {
1202
- // Print resullt to terminal
1203
- console.log(processgrpinfo.date + "\n");
1204
- console.log(processinfoTable.toString());
1205
- console.log("======================================================================");
1206
- }
1207
- }
1208
- },
1209
- /**
1210
- * get screen capture of the given device
1211
- * @property options {String} device, display, outputPath
1212
- */
1213
- captureScreen: function(options, next) {
1214
- if (typeof next !== 'function') {
1215
- throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
1216
- }
1217
- options = options || {};
1218
- async.series([
1219
- _makeSession,
1220
- _makeCaptureOption,
1221
- _captureScreenFile,
1222
- _copyFileToLocal
1223
- ], function(err, results) {
1224
- log.silly("device#captureScreen()", "err:", err, ", results:", results);
1225
- const resultTxt = "Create " + chalk.green(options.captureFileName) + " to " + options.destinationPath +"\nSuccess";
1226
-
1227
- // clean up /tmp/aresCapture directory in target device
1228
- if (options.createdTmpDir) {
1229
- _removeTmpDir(function finish(removeErr) {
1230
- next(err ? err : removeErr, {msg: resultTxt});
1231
- });
1232
- } else {
1233
- next(err, {msg: resultTxt});
1234
- }
1235
- });
1236
-
1237
- function _makeSession(next) {
1238
- makeSession(options, next);
1239
- }
1240
-
1241
- function _makeCaptureOption(next) {
1242
- log.info("device#captureScreen()#_makeCaptureOption()");
1243
-
1244
- const captureFormat = "PNG", // PNG is default format
1245
- fileNameSeperator = "_";
1246
-
1247
- let captureFileName = options.session.target.name + "_" + "display" + options.display + "_",
1248
- destinationPath = "";
1249
-
1250
- if (options.outputPath === null) {
1251
- captureFileName += createDateFileName(fileNameSeperator, captureFormat.toLowerCase());
1252
- destinationPath = path.resolve('.');
1253
- } else {
1254
- // get directory path, file path, file Extenstion from given path
1255
- const parseDirPath = path.dirname(options.outputPath),
1256
- parseBase = path.parse(options.outputPath).base;
1257
-
1258
- let parseExt = path.parse(options.outputPath).ext;
1259
-
1260
- parseExt = parseExt.split('.').pop();
1261
- log.info("device#captureScreen()#_makeCaptureOption()" + "dir name:" + parseDirPath
1262
- + " ,file name:" + parseBase + " ,inputFormat:" + parseExt);
1263
-
1264
- // if specific path is given
1265
- if (parseBase) {
1266
- captureFileName = parseBase;
1267
- destinationPath = path.resolve(parseDirPath);
1268
- // parseBase is [filename].[ext] format
1269
- if (parseExt === "") {
1270
- // paresBase does not have file extesntion, add .png format
1271
- captureFileName += "." + captureFormat.toLowerCase();
1272
- } else if (parseExt !== "png" && parseExt !== "bmp" && parseExt !== "jpg") {
1273
- return next(errHndl.getErrMsg("INVALID_CAPTURE_FORMAT"));
1274
- }
1275
- } else if (parseDirPath) {
1276
- // the path has only "directory" without parseBase
1277
- // for example, "ares-device -c /"
1278
- captureFileName = createDateFileName(fileNameSeperator, captureFormat.toLowerCase());
1279
- destinationPath = path.resolve(parseDirPath);
1280
- }
1281
- }
1282
-
1283
- options.captureFormat = captureFormat;
1284
- options.captureFileName = captureFileName;
1285
- options.captureDirPath = "/tmp/aresCapture/";
1286
- options.sourcePath = options.captureDirPath + captureFileName;
1287
- options.destinationPath = destinationPath;
1288
- options.ignore = true;
1289
- options.silent = true;
1290
-
1291
- next();
1292
- }
1293
-
1294
- function _captureScreenFile(next) {
1295
- log.info("device#captureScreen()#_captureScreenFile()");
1296
- const cmd = "/bin/mkdir -p " + options.captureDirPath + " && chmod 777 " + options.captureDirPath;
1297
- options.session.run(cmd, null, null, null, function(err) {
1298
- if (err) {
1299
- return setImmediate(next, err);
1300
- } else {
1301
- options.createdTmpDir = true;
1302
- const target = options.session.getDevice(),
1303
- addr = target.lunaAddr.captureCompositorOutput,
1304
- param = {
1305
- // luna param
1306
- subscribe: false,
1307
- output: options.sourcePath,
1308
- format: options.captureFormat,
1309
- displayId: options.display
1310
- };
1311
-
1312
- luna.send(options, addr, param, function(lineObj, next) {
1313
- if (lineObj.returnValue) {
1314
- log.verbose("device#captureScreen()#_captureScreenFile()","Capture file in target:" + lineObj.output);
1315
- next(null, {});
1316
- } else {
1317
- log.verbose("device#captureScreen()#_captureScreenFile()", "failure");
1318
- next(errHndl.getErrMsg("INVALID_OBJECT"));
1319
- }
1320
- }, next);
1321
- }
1322
- });
1323
- }
1324
-
1325
- function _copyFileToLocal(next) {
1326
- log.info("device#captureScreen()#_copyFileToLocal()");
1327
- pullLib.pull(options.sourcePath, options.destinationPath, options, next);
1328
- }
1329
-
1330
- function _removeTmpDir(next) {
1331
- log.info("device#captureScreen()#_removeTmpDir()");
1332
- const cmd = '/bin/rm -rf ' + options.captureDirPath;
1333
- options.session.run(cmd, null, null, null, function(err) {
1334
- if (err) {
1335
- return setImmediate(next, err);
1336
- } else {
1337
- next();
1338
- }
1339
- });
1340
- }
1341
- }
1342
- };
1343
-
1344
- function makeSession(options, next) {
1345
- options.nReplies = 1; // -n 1
1346
- if (!options.session) {
1347
- log.info("device#makeSession()", "need to make new session");
1348
- const printTarget = true;
1349
- options.session = new novacom.Session(options.device, printTarget, next);
1350
- } else {
1351
- log.info("device#makeSession()", "already exist session");
1352
- next();
1353
- }
1354
- }
1355
-
1356
- function makeCSVOutputPath(options, next) {
1357
- const csvFormat = "csv", // csv is default format
1358
- fileNameSeperator = "_";
1359
-
1360
- if (options.outputPath === null) {
1361
- options.fileName = createDateFileName(fileNameSeperator, csvFormat);
1362
- options.destinationPath = path.resolve('.');
1363
- } else {
1364
- // get directory path, file path, file Extenstion from given path
1365
- const parseDirPath = path.dirname(options.outputPath),
1366
- parseBase = path.parse(options.outputPath).base;
1367
-
1368
- let parseExt = path.parse(options.outputPath).ext;
1369
-
1370
- parseExt = parseExt.split('.').pop();
1371
- log.info("device#captureScreen()#_makeCaptureOption()" + "dir name:" + parseDirPath
1372
- + " ,file name:" + parseBase + " ,inputFormat:" + parseExt);
1373
-
1374
- // if specific path is given
1375
- if (parseBase) {
1376
- options.fileName = parseBase;
1377
- options.destinationPath = path.resolve(parseDirPath);
1378
- // parseBase is [filename].[ext] format
1379
- if (parseExt === "") {
1380
- // paresBase does not have file extesntion, add .png format
1381
- options.fileName += "." + csvFormat;
1382
- } else if (parseExt !== csvFormat) {
1383
- return next(errHndl.getErrMsg("INVALID_CSV_FORMAT"));
1384
- }
1385
- } else if (parseDirPath) {
1386
- // the path has only "directory" without parseBase
1387
- // for example, "ares-device -r -s /"
1388
- options.fileName = createDateFileName(fileNameSeperator, csvFormat);
1389
- options.destinationPath = path.resolve(parseDirPath);
1390
- }
1391
- }
1392
-
1393
- options.csvPath = path.resolve(options.destinationPath, options.fileName);
1394
- log.verbose("device#makeCSVOutputPath()", "csvPath:", options.csvPath);
1395
-
1396
- fs.open(options.csvPath, 'w', function(err, fd) {
1397
- if (err) {
1398
- return next(errHndl.getErrMsg(err));
1399
- }
1400
- fs.close(fd, function(error) {
1401
- if (error) {
1402
- return next(errHndl.getErrMsg(error));
1403
- }
1404
- log.verbose("device#makeCSVOutputPath()", options.csvPath + " is closed");
1405
-
1406
- // Defense code
1407
- if (fs.existsSync(options.csvPath)) {
1408
- fs.unlinkSync(options.csvPath);
1409
- }
1410
- log.verbose("device#makeCSVOutputPath()", options.csvPath + " is exist: " + fs.existsSync(options.csvPath));
1411
- next();
1412
- });
1413
- });
1414
- }
1415
-
1416
- if (typeof module !== 'undefined' && module.exports) {
1417
- module.exports = device;
1418
- }
1419
- }());
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
+ createCsvWriter = require('csv-writer').createObjectCsvWriter,
10
+ fs = require('fs'),
11
+ npmlog = require('npmlog'),
12
+ path = require('path'),
13
+ streamBuffers = require('stream-buffers'),
14
+ Table = require('easy-table'),
15
+ util = require('util'),
16
+ pullLib = require('./pull'),
17
+ errHndl = require('./base/error-handler'),
18
+ luna = require('./base/luna'),
19
+ novacom = require('./base/novacom'),
20
+ createDateFileName = require('./util/createFileName').createDateFileName,
21
+ convertJsonToList = require('./util/json').convertJsonToList;
22
+
23
+ (function() {
24
+ const log = npmlog;
25
+ log.heading = 'device';
26
+ log.level = 'warn';
27
+
28
+ const device = {
29
+
30
+ /**
31
+ * @property {Object} log an npm log instance
32
+ */
33
+ log: log,
34
+
35
+ /**
36
+ * Print system information of the given device
37
+ * @property options {String} device the device to connect to
38
+ */
39
+ systemInfo: function(options, next) {
40
+ if (typeof next !== 'function') {
41
+ throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
42
+ }
43
+ options = options || {};
44
+ async.series([
45
+ _makeSession,
46
+ _getOsInfo,
47
+ _getDeviceInfo,
48
+ _getChromiumVersion,
49
+ _getQtbaseVersion,
50
+ _getSoftwareInfo
51
+ ], function(err, results) {
52
+ log.silly("device#systemInfo()", "err:", err, ", results:", results);
53
+ let resultTxt = "";
54
+ for (let i = 1; i < results.length; i++) {
55
+ resultTxt += results[i] + "\n";
56
+ }
57
+ next(err, {msg: resultTxt.trim()});
58
+ });
59
+
60
+ function _makeSession(next) {
61
+ makeSession(options, next);
62
+ }
63
+
64
+ function _getOsInfo(next) {
65
+ log.info("device#systemInfo()#_getOsInfo()");
66
+ const target = options.session.getDevice(),
67
+ addr = target.lunaAddr.osInfo,
68
+ param = {
69
+ // luna param
70
+ parameters:["webos_build_id","webos_imagename","webos_name","webos_release",
71
+ "webos_manufacturing_version", "core_os_kernel_version"],
72
+ subscribe: false
73
+ };
74
+
75
+ luna.send(options, addr, param, function(lineObj, next) {
76
+ const resultValue = lineObj;
77
+
78
+ if (resultValue.returnValue) {
79
+ log.verbose("device#systemInfo()#_getOsInfo()", "success");
80
+ delete resultValue.returnValue; // remove unnecessary data
81
+ next(null, _makeReturnTxt(resultValue));
82
+ } else {
83
+ log.verbose("device#systemInfo()#_getOsInfo()", "failure");
84
+ next(errHndl.getErrMsg("INVALID_OBJECT"));
85
+ }
86
+ }, next);
87
+ }
88
+
89
+ function _getDeviceInfo(next) {
90
+ log.info("device#systemInfo()#_getDeviceInfo()");
91
+ const target = options.session.getDevice(),
92
+ addr = target.lunaAddr.deviceInfo,
93
+ param = {
94
+ // luna param
95
+ subscribe: false
96
+ };
97
+
98
+ luna.send(options, addr, param, function(lineObj, next) {
99
+ const resultValue = lineObj,
100
+ returnObj ={};
101
+
102
+ if (resultValue.returnValue) {
103
+ log.verbose("device#systemInfo()#_getDeviceInfo()", "success");
104
+ returnObj.device_name = resultValue.device_name;
105
+ returnObj.device_id = resultValue.device_id;
106
+ next(null, _makeReturnTxt(returnObj));
107
+ } else {
108
+ log.verbose("device#systemInfo()#_getDeviceInfo()", "failure");
109
+ next(errHndl.getErrMsg("INVALID_OBJECT"));
110
+ }
111
+ }, next);
112
+ }
113
+
114
+ function _getChromiumVersion(next) {
115
+ log.info("device#systemInfo()#_getChromiumInfo()");
116
+
117
+ // opkg is required permission as root.
118
+ if (options.session.getDevice().username !== 'root') {
119
+ return next(null, "chromium_version : " + "not supported");
120
+ } else {
121
+ const cmd = '/usr/bin/opkg list-installed webruntime*';
122
+ options.session.run(cmd, null, __data, null, function(err) {
123
+ if (err) {
124
+ return next(err);
125
+ }
126
+ });
127
+ }
128
+ function __data(data) {
129
+ const str = (Buffer.isBuffer(data)) ? data.toString() : data,
130
+ exp = /\d*\.\d*\.\d*\.\d*/,
131
+ version = str.match(exp);
132
+
133
+ next(null, "chromium_version : " + version);
134
+ }
135
+ }
136
+
137
+ function _getQtbaseVersion(next) {
138
+ log.info("device#systemInfo()#_getQtbaseInfo()");
139
+
140
+ // opkg is required permission as root.
141
+ if (options.session.getDevice().username !== 'root') {
142
+ return next(null, "qt_version : " + "not supported");
143
+ } else {
144
+ const cmd = '/usr/bin/opkg list-installed qtbase';
145
+ options.session.run(cmd, null, __data, null, function(err) {
146
+ if (err) {
147
+ return next(err);
148
+ }
149
+ });
150
+ }
151
+ function __data(data) {
152
+ const str = (Buffer.isBuffer(data)) ? data.toString() : data,
153
+ exp = /\d*\.\d*\.\d*/,
154
+ version = str.match(exp);
155
+ next(null, "qt_version : " + version);
156
+ }
157
+ }
158
+
159
+ function _getSoftwareInfo(next) {
160
+ log.info("device#systemInfo#_getSoftwareInfo()");
161
+ const target = options.session.getDevice(),
162
+ addr = target.lunaAddr.softwareInfo,
163
+ param = {
164
+ parameters: ["nodejs_versions"]
165
+ };
166
+
167
+ luna.sendWithoutErrorHandle(options, addr, param, function(lineObj, next) {
168
+ log.silly("device#systemInfo#_getSoftwareInfo():", "lineObj:", lineObj);
169
+
170
+ const resultValue = lineObj,
171
+ returnObj ={};
172
+
173
+ if (resultValue.returnValue) {
174
+ log.verbose("device#systemInfo#_getSoftwareInfo():", "success");
175
+ returnObj.nodejs_versions = resultValue.nodejs_versions;
176
+ next(null, _makeReturnTxt(returnObj));
177
+ } else {
178
+ // handle if the target device does not support softwareInfo/query
179
+ return next(null, "nodejs_versions : " + "not supported");
180
+ }
181
+ }, next);
182
+ }
183
+
184
+ function _makeReturnTxt(resultValue) {
185
+ let returnTxt = "";
186
+
187
+ for (const key in resultValue) {
188
+ if (resultValue[key] === undefined) {
189
+ resultValue[key] = "(unknown)";
190
+ }
191
+ returnTxt += key + " : " + resultValue[key] + "\n";
192
+ }
193
+ return returnTxt.trim();
194
+ }
195
+ },
196
+ /**
197
+ * Print session information of the given device
198
+ * @property options {String} device the device to connect to
199
+ */
200
+ sessionInfo: function(options, next) {
201
+ if (typeof next !== 'function') {
202
+ throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
203
+ }
204
+ options = options || {};
205
+ async.series([
206
+ _makeSession,
207
+ _getSessionList
208
+ ], function(err, results) {
209
+ log.silly("device#sessionInfo()", "err:", err, ", results:", results);
210
+ let resultTxt = "";
211
+
212
+ if (results[1] !== undefined) {
213
+ if (typeof results[1] === "object") {
214
+ if (results[1].length === 0) {
215
+ return next(errHndl.getErrMsg("SELECT_PROFILE"));
216
+ }
217
+ for (let i = 0; i < results[1].length; i++) {
218
+ resultTxt += convertJsonToList(results[1][i], 0) + '\n';
219
+ }
220
+ } else {
221
+ resultTxt = results[1];
222
+ }
223
+ }
224
+ next(err, {msg: resultTxt.trim()});
225
+ });
226
+
227
+ function _makeSession(next) {
228
+ makeSession(options, next);
229
+ }
230
+
231
+ function _getSessionList(next) {
232
+ log.info("device#sessionInfo#_getSessionList()");
233
+ const target = options.session.getDevice(),
234
+ addr = target.lunaAddr.getSessionList,
235
+ param = {
236
+ // luna param
237
+ subscribe: false
238
+ };
239
+
240
+ luna.send(options, addr, param, function(lineObj, next) {
241
+ if (lineObj.returnValue) {
242
+ log.verbose("device#sessionInfo()#_getSessionList()", "success");
243
+ next(null, lineObj.sessionList);
244
+ } else {
245
+ log.verbose("device#sessionInfo()#_getSessionList()", "failure");
246
+ next(errHndl.getErrMsg("INVALID_OBJECT"));
247
+ }
248
+ }, next);
249
+ }
250
+ },
251
+ /**
252
+ * Print system information of the given device
253
+ * @property options {String} device the device to connect to
254
+ */
255
+ tvSystemInfo: function(options, next) {
256
+ if (typeof next !== 'function') {
257
+ throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
258
+ }
259
+ options = options || {};
260
+ async.series([
261
+ _makeSession,
262
+ _getSystemInfo,
263
+ ], function(err, results) {
264
+ log.silly("device#tvSystemInfo()", "err:", err, ", results:", results);
265
+ next(err, {msg: results[1]});
266
+ });
267
+
268
+ function _makeSession(next) {
269
+ makeSession(options, next);
270
+ }
271
+
272
+ function _getSystemInfo(next) {
273
+ log.info("device#tvSystemInfo#_getSystemInfo()");
274
+ const target = options.session.getDevice(),
275
+ addr = target.lunaAddr.deviceInfoSystem,
276
+ param = {
277
+ // luna param
278
+ keys: ["modelName", "sdkVersion", "firmwareVersion", "boardType", "otaId"],
279
+ subscribe: false
280
+ };
281
+
282
+ luna.sendWithoutErrorHandle(options, addr, param, function (lineObj, next) {
283
+ if (lineObj) {
284
+ log.verbose("deviceInfo#systemInfo#_getSystemInfo():", "success");
285
+ next(null, __makeReturnObj(lineObj, param.keys));
286
+ } else {
287
+ next(errHndl.getErrMsg("INVALID_OBJECT"));
288
+ }
289
+ }, next);
290
+ }
291
+
292
+ function __makeReturnObj(resultValue, paramkey) {
293
+ let returnTxt = "";
294
+
295
+ for (const key in paramkey) {
296
+ if (Object.hasOwnProperty.call(resultValue, paramkey[key]))
297
+ returnTxt += paramkey[key] + " : " + resultValue[paramkey[key]] + "\n";
298
+ }
299
+ log.verbose("deviceInfo#systemInfo#__makeReturnObj():", returnTxt);
300
+ return returnTxt.trim();
301
+ }
302
+ },
303
+ /**
304
+ * Get all CPUs and memories usage of target device
305
+ * @property options {String} device, interval
306
+ */
307
+ systemResource: function(options, next) {
308
+ if (typeof next !== 'function') {
309
+ throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
310
+ }
311
+ const systemGroup = {};
312
+ systemGroup.initialExecution = true;
313
+ options = options || {};
314
+ options.destinationPath = "";
315
+ options.fileName = "";
316
+ options.csvPath = "";
317
+ async.series([
318
+ _createOutputPath,
319
+ _makeSession,
320
+ _getSystemResouceInfo
321
+ ], function(err, results) {
322
+ log.silly("device#systemResource()", "err:", err, ", results:", results);
323
+ next(err);
324
+ });
325
+
326
+ function _createOutputPath(next) {
327
+ if (options.save && options.csvPath === "") {
328
+ makeCSVOutputPath(options, next);
329
+ } else {
330
+ next();
331
+ }
332
+ }
333
+
334
+ function _makeSession(next) {
335
+ makeSession(options, next);
336
+ }
337
+
338
+ function _getSystemResouceInfo(next) {
339
+ log.info("device#systemResource()#_getSystemResouceInfo()");
340
+
341
+ let timerId;
342
+ if (!options.interval) {
343
+ // If interval option is not given, call timer logic 2 times
344
+ const defaultRepeat = 2;
345
+ let repeatCount = 0;
346
+ try {
347
+ timerId = setTimeout(function repeat() {
348
+ if (repeatCount < defaultRepeat) {
349
+ _callSystemResourceInfoCmd();
350
+ repeatCount++;
351
+ timerId = setTimeout(repeat, 1000);
352
+ } else {
353
+ clearTimeout(timerId);
354
+ return next();
355
+ }
356
+ }, 100);
357
+ } catch (err) {
358
+ log.silly("device#systemResource()#_getSystemResouceInfo()", "one timer. err:", err.toString());
359
+ clearTimeout(timerId);
360
+ // ignore timer logic error
361
+ return next();
362
+ }
363
+ } else {
364
+ try {
365
+ // when interval option is given, print initial data at first
366
+ const defaultRepeat = 1;
367
+ let repeatCount = 0;
368
+ timerId = setTimeout(function repeat() {
369
+ if (repeatCount < defaultRepeat) {
370
+ _callSystemResourceInfoCmd();
371
+ repeatCount++;
372
+ timerId = setTimeout(repeat, 1000);
373
+ } else {
374
+ _callSystemResourceInfoCmd();
375
+ timerId = setTimeout(repeat, options.interval * 1000);
376
+ }
377
+ }, 100);
378
+ } catch (err) {
379
+ log.silly("device#systemResource()#_getSystemResouceInfo()", "repeat timer. err:", err.toString());
380
+ clearTimeout(timerId);
381
+ // ignore timer logic error
382
+ return next();
383
+ }
384
+ }
385
+ }
386
+
387
+ function _callSystemResourceInfoCmd() {
388
+ log.info("device#systemResource()#_callSystemResourceInfoCmd()");
389
+
390
+ const wStream = new streamBuffers.WritableStreamBuffer();
391
+ const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep -c ^processor /proc/cpuinfo; grep "cpu *" /proc/stat; free -k';
392
+ try {
393
+ options.session.run(cmd, null, wStream, null, function(err) {
394
+ if (err) {
395
+ // do not print error message to user
396
+ // when user press Ctrl + C , the ssh connection is not completed, it makes error
397
+ log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "ssh call. err:"+ err.toString());
398
+ return next();
399
+ } else {
400
+ const result = wStream.getContentsAsString();
401
+ _setSystemResouceInfo(result);
402
+ systemGroup.initialExecution = false;
403
+ }
404
+ });
405
+ } catch (err) {
406
+ // do not print error message to user
407
+ // when user press Ctrl + C , the ssh connection is not completed, it makes error
408
+ log.silly("device#systemResource()#_callSystemResourceInfoCmd()", "in try-catch. err:", err.toString());
409
+ return next();
410
+ }
411
+ }
412
+
413
+ function _setSystemResouceInfo(systemData) {
414
+ log.info("device#systemResource()#_callSystemResourceInfoCmd()");
415
+
416
+ const CPU_PATTERN = /\s+/,
417
+ cpuinfo = {},
418
+ meminfo = {};
419
+ let sysinfo = {};
420
+ try {
421
+ const allvalues = systemData.split("\n"),
422
+ date = allvalues[0], // Setup date
423
+ pcore = +allvalues[1] * 100;
424
+ let index,
425
+ columns,
426
+ isBuff_Cached = false; // This is to check the format version of kernel to find system memory parameter
427
+ for (index = 2; index < (allvalues.length - 1); index++) {
428
+ columns = allvalues[index].split(CPU_PATTERN);
429
+ // setup CPU information
430
+ if (columns[0].indexOf("cpu") === 0) {
431
+ const prevTotal = "prev" + columns[0] + "Total",
432
+ prevIdle = "prev" + columns[0] + "Idle",
433
+ prevUser = "prev" + columns[0] + "User",
434
+ prevkernel = "prev" + columns[0] + "Kernel",
435
+ prevOther = "prev" + columns[0] + "Other";
436
+ if (!systemGroup[prevTotal]) {
437
+ systemGroup[prevTotal] = 0;
438
+ systemGroup[prevIdle] = 0;
439
+ systemGroup[prevUser] = 0;
440
+ systemGroup[prevkernel] = 0;
441
+ systemGroup[prevOther] = 0;
442
+ }
443
+ const user = parseInt(columns[1]),
444
+ nice = parseInt(columns[2]),
445
+ kernel = parseInt(columns[3]),
446
+ idle = parseInt(columns[4]),
447
+ other = nice + parseInt(columns[5]) + parseInt(columns[6]) + parseInt(columns[7]) + parseInt(columns[8]) +
448
+ parseInt(columns[9]) + parseInt(columns[10]),
449
+ subTotal = user + nice + kernel + idle + other;
450
+
451
+ if (!systemGroup.initialExecution) {
452
+ const diffIdle = idle - systemGroup[prevIdle],
453
+ diffUser = user - systemGroup[prevUser],
454
+ diffKernel = kernel - systemGroup[prevkernel],
455
+ diffOther = other - systemGroup[prevOther],
456
+ diffTotal = subTotal - systemGroup[prevTotal];
457
+
458
+ let userModeCpuOccupation = (diffUser/diffTotal) * 100,
459
+ kernelModeCpuOccupation = (diffKernel/diffTotal) * 100,
460
+ otherModeCpuOccupation = (diffOther/diffTotal) * 100,
461
+ overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100;
462
+
463
+ userModeCpuOccupation < 0 ? (userModeCpuOccupation = 0) : userModeCpuOccupation;
464
+ userModeCpuOccupation > pcore ? (userModeCpuOccupation = pcore) : userModeCpuOccupation;
465
+ kernelModeCpuOccupation < 0 ? (kernelModeCpuOccupation = 0) : kernelModeCpuOccupation;
466
+ kernelModeCpuOccupation > pcore ? (kernelModeCpuOccupation = pcore) : kernelModeCpuOccupation;
467
+ otherModeCpuOccupation < 0 ? (otherModeCpuOccupation = 0) : otherModeCpuOccupation;
468
+ otherModeCpuOccupation > pcore ? (otherModeCpuOccupation = pcore) : otherModeCpuOccupation;
469
+ overallCpuOccupation < 0 ? (overallCpuOccupation = 0) : overallCpuOccupation;
470
+ overallCpuOccupation > pcore ? (overallCpuOccupation = pcore) : overallCpuOccupation;
471
+
472
+ cpuinfo[columns[0]] = {
473
+ "overall": +overallCpuOccupation.toFixed(2),
474
+ "usermode": +userModeCpuOccupation.toFixed(2),
475
+ "kernelmode": +kernelModeCpuOccupation.toFixed(2),
476
+ "others": +otherModeCpuOccupation.toFixed(2)
477
+ };
478
+ }
479
+ systemGroup[prevIdle] = idle;
480
+ systemGroup[prevUser] = user;
481
+ systemGroup[prevkernel] = kernel;
482
+ systemGroup[prevOther] = other;
483
+ systemGroup[prevTotal] = subTotal;
484
+ }
485
+
486
+ if (!systemGroup.initialExecution) {
487
+ // setup memory infomation
488
+ if (columns[5] && columns[5].indexOf('buff/cache') !== -1) {
489
+ isBuff_Cached = true;
490
+ }
491
+ if (columns[0].indexOf('Mem:') === 0) {
492
+ meminfo['memory'] = !isBuff_Cached ? {
493
+ "total": +columns[1],
494
+ "used": +columns[2],
495
+ "free": +columns[3],
496
+ "shared": +columns[4],
497
+ "buffers": +columns[5],
498
+ "cached": +columns[6]
499
+ } : {
500
+ "total": +columns[1],
501
+ "used": +columns[2],
502
+ "free": +columns[3],
503
+ "shared": +columns[4],
504
+ "buff_cache": +columns[5],
505
+ "available": +columns[6]
506
+ };
507
+ }
508
+ if (columns[0].indexOf('-/+') === 0) {
509
+ meminfo['buffers'] = {
510
+ "used": +columns[2],
511
+ "free": +columns[3]
512
+ };
513
+ }
514
+ if (columns[0].indexOf('Swap:') === 0) {
515
+ meminfo['swap'] = {
516
+ "total": +columns[1],
517
+ "used": +columns[2],
518
+ "free": +columns[3]
519
+ };
520
+ }
521
+ }
522
+ }
523
+ if (!systemGroup.initialExecution) {
524
+ sysinfo = {
525
+ "date": date,
526
+ "cpuinfo": cpuinfo,
527
+ "meminfo": meminfo
528
+ };
529
+ _printSystemInfo(sysinfo);
530
+ }
531
+ } catch (err) {
532
+ // do not print error message to user
533
+ // when user press Ctrl + C , the ssh cmd data is not completed, it makes error
534
+ log.silly("device#systemResource()#_setSystemResouceInfo()", "in try-catch. err:", err.toString());
535
+ return;
536
+ }
537
+ }
538
+
539
+ function _printSystemInfo(sysinfo) {
540
+ const cpuinfo = sysinfo.cpuinfo,
541
+ meminfo = sysinfo.meminfo,
542
+ cpuinfoTable = new Table(),
543
+ meminfoTable = new Table(),
544
+ dataForCSV = [];
545
+
546
+ // add CPU info to the table
547
+ for (const key in cpuinfo) {
548
+ cpuinfoTable.cell('(%)', key);
549
+ cpuinfoTable.cell('overall', cpuinfo[key].overall);
550
+ cpuinfoTable.cell('usermode', cpuinfo[key].usermode);
551
+ cpuinfoTable.cell('kernelmode', cpuinfo[key].kernelmode);
552
+ cpuinfoTable.cell('others', cpuinfo[key].others);
553
+ cpuinfoTable.newRow();
554
+
555
+ // Add csv array
556
+ const obj = {
557
+ time: sysinfo.date,
558
+ cpu: key,
559
+ overall: cpuinfo[key].overall,
560
+ usermode: cpuinfo[key].usermode,
561
+ kernelmode: cpuinfo[key].kernelmode,
562
+ others: cpuinfo[key].others
563
+ };
564
+ dataForCSV.push(obj);
565
+ }
566
+ // add memoryInfo to the table
567
+ for (const key in meminfo) {
568
+ meminfoTable.cell('(KB)', key);
569
+ meminfoTable.cell('total', meminfo[key].total);
570
+ meminfoTable.cell('used', meminfo[key].used);
571
+ meminfoTable.cell('free', meminfo[key].free);
572
+ meminfoTable.cell('shared', meminfo[key].shared);
573
+ meminfoTable.cell('buff/cache', meminfo[key].buff_cache);
574
+ meminfoTable.cell('available', meminfo[key].available);
575
+ meminfoTable.newRow();
576
+
577
+ const obj = {
578
+ time: sysinfo.date,
579
+ memory: key,
580
+ total: meminfo[key].total,
581
+ used: meminfo[key].used,
582
+ free: meminfo[key].free,
583
+ shared: meminfo[key].shared,
584
+ "buff/cache": meminfo[key].buff_cache,
585
+ available: meminfo[key].available
586
+ };
587
+ dataForCSV.push(obj);
588
+ }
589
+ // write CSV file if user gives --save option
590
+ if (options.save && options.csvPath) {
591
+ // write csv file
592
+ // when openMode is false, the new csv file will be created and "Header" add to the file
593
+ let openMode = false;
594
+ if (fs.existsSync(options.csvPath)) {
595
+ openMode = true;
596
+ }
597
+
598
+ const csvWriter = createCsvWriter({
599
+ path: options.csvPath,
600
+ header: [
601
+ {id: 'time', title: 'time'},
602
+ {id: 'cpu', title: '(%)'},
603
+ {id: 'overall', title: 'overall'},
604
+ {id: 'usermode', title: 'usermode'},
605
+ {id: 'kernelmode', title: 'kernelmode'},
606
+ {id: 'others', title: 'others'},
607
+ {id: 'memory', title: '(KB)'},
608
+ {id: 'total', title: 'total'},
609
+ {id: 'used', title: 'used'},
610
+ {id: 'free', title: 'free'},
611
+ {id: 'shared', title: 'shared'},
612
+ {id: 'buff/cache', title: 'buff/cache'},
613
+ {id: 'available', title: 'available'}
614
+ ],
615
+ append: openMode
616
+ });
617
+
618
+ csvWriter
619
+ .writeRecords(dataForCSV)
620
+ .then(function() {
621
+ log.silly("device#systemResource()#_printSystemInfo()", "CSV file updated");
622
+ // csv file has been created at first
623
+ if (openMode === false) {
624
+ const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath;
625
+ console.log(resultTxt);
626
+ }
627
+ __printTable();
628
+ }).catch(function(err) {
629
+ return setImmediate(next, errHndl.getErrMsg(err));
630
+ });
631
+ } else {
632
+ __printTable();
633
+ }
634
+
635
+ function __printTable() {
636
+ console.log(sysinfo.date + "\n");
637
+ console.log(cpuinfoTable.toString());
638
+ console.log(meminfoTable.toString());
639
+ console.log("=================================================================");
640
+ }
641
+ }
642
+ },
643
+ /**
644
+ * Get running apps and services CPUs and memories usage
645
+ * @property options {String} device, interval
646
+ */
647
+ processResource: function(options, next) {
648
+ if (typeof next !== 'function') {
649
+ throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
650
+ }
651
+
652
+ const processGroup = {};
653
+ processGroup.initialExecution = true;
654
+ options = options || {};
655
+ options.destinationPath = "";
656
+ options.fileName = "";
657
+ options.csvPath = "";
658
+
659
+ async.series([
660
+ _createOutputPath,
661
+ _makeSession,
662
+ _getProcessResouceInfo
663
+ ], function(err, results) {
664
+ log.silly("device#processResource()", "err:", err, ", results:", results);
665
+ next(err);
666
+ });
667
+
668
+ function _createOutputPath(next) {
669
+ if (options.save && options.csvPath === "") {
670
+ makeCSVOutputPath(options, next);
671
+ } else {
672
+ next();
673
+ }
674
+ }
675
+
676
+ function _makeSession(next) {
677
+ makeSession(options, next);
678
+ }
679
+
680
+ function _getProcessResouceInfo(next) {
681
+ log.info("device#processResource()#_getProcessResouceInfo()");
682
+
683
+ let timerId;
684
+ if (!options.interval) {
685
+ // If interval option is not given, call timer logic 2 times
686
+ const defaultRepeat = 2;
687
+ let repeatCount = 0;
688
+ try {
689
+ timerId = setTimeout(function repeat() {
690
+ if (repeatCount < defaultRepeat) {
691
+ _callProcessInfoCmd();
692
+ repeatCount++;
693
+ timerId = setTimeout(repeat, 1000);
694
+ } else {
695
+ clearTimeout(timerId);
696
+ return next();
697
+ }
698
+ }, 100);
699
+ } catch (err) {
700
+ log.silly("device#systemResource()#_getProcessResouceInfo()", "one timer. err:", err.toString());
701
+ clearTimeout(timerId);
702
+ // ignore timer logic error
703
+ return next();
704
+ }
705
+ } else {
706
+ try {
707
+ // when interval option is given, print initial data at first
708
+ const defaultRepeat = 1;
709
+ let repeatCount = 0;
710
+ timerId = setTimeout(function repeat() {
711
+ if (repeatCount < defaultRepeat) {
712
+ _callProcessInfoCmd();
713
+ repeatCount++;
714
+ timerId = setTimeout(repeat, 1000);
715
+ } else {
716
+ _callProcessInfoCmd();
717
+ timerId = setTimeout(repeat, options.interval * 1000);
718
+ }
719
+ }, 100);
720
+ } catch (err) {
721
+ log.silly("device#systemResource()#_getProcessResouceInfo()", "repeat timer. err:", err.toString());
722
+ clearTimeout(timerId);
723
+ // ignore timer logic error
724
+ return next();
725
+ }
726
+ }
727
+ }
728
+
729
+ function _callProcessInfoCmd() {
730
+ log.info("device#processResource()#_callProcessInfoCmd()");
731
+
732
+ const wStream = new streamBuffers.WritableStreamBuffer();
733
+ const cmd = 'date "+%Y-%m-%d %H:%M:%S"; grep "cpu *" /proc/stat | sed "1d" | awk \'{for (i=0;i<NR;i++){if (i==NR-1){totalSum+=$2+$3+$4+$5+$6+$7+$8+$9+$10+$11;idleSum+=$5}}} END { for (i=0;i<NR;i++){if (i==NR-1){print idleSum;print totalSum}}}\'; cat /proc/[0-9]*/stat; echo \'psList\' ; ps -ax | sed "1d" | awk \'/ /{print $1 "\t"$5}\'; echo \'serviceStringStart\'; ls /media/developer/apps/usr/palm/services ; echo \'serviceStringEnd\'; luna-send-pub -n 1 -f luna://com.webos.applicationManager/dev/running \'{}\'; grep -c ^processor /proc/cpuinfo';
734
+ try {
735
+ options.session.run(cmd, null, wStream, null, function(err) {
736
+ if (err) {
737
+ // do not print error message to user
738
+ // when user press Ctrl + C , the ssh connection is not completed, it makes error
739
+ log.silly("device#processResource()#_callProcessInfoCmd()", "ssh call. err:", err.toString());
740
+ return next(null);
741
+ } else {
742
+ const result = wStream.getContentsAsString();
743
+ _setProcessInfo(result);
744
+ processGroup.initialExecution = false;
745
+ }
746
+ });
747
+ } catch (err) {
748
+ // do not print error message to user
749
+ // when user press Ctrl + C , the ssh connection is not completed, it makes error
750
+ log.silly("device#processResource()#_callProcessInfoCmd()", "in try-catch. err:", err.toString());
751
+ return next(null);
752
+ }
753
+ }
754
+
755
+ function _setProcessInfo(processData) {
756
+ log.info("device#processResource()#_setProcessInfo()");
757
+ const PROC_GROUP_INFO_PATTERN = /\s+/;
758
+ try {
759
+ // Intialize temporary groups with values
760
+ const processList = ["Service", "System"],
761
+ groupProcessList = [],
762
+ tempProcGrps = {},
763
+ arrActiveServices = [];
764
+ // loop through all the categories and create groups
765
+ for (let i = 0; i < processList.length; i++) {
766
+ tempProcGrps[processList[i]] = {};
767
+ tempProcGrps[processList[i]]["pid"] = 0;
768
+ tempProcGrps[processList[i]]["cputime"] = 0;
769
+ tempProcGrps[processList[i]]["RSS"] = 0;
770
+ tempProcGrps[processList[i]]["pmem"] = 0;
771
+ }
772
+
773
+ const processinfo = [],
774
+ groupProcessinfo = [], // only for dev app & service info
775
+ allvalues = processData.split("\n"),
776
+ otherList = [],
777
+ date = allvalues[0],
778
+ lastIndex = allvalues.length;
779
+
780
+ allvalues.splice(lastIndex - 1, 1);
781
+ const pcore = +allvalues[allvalues.length-1] * 100;
782
+ /* memCol[1] from 'grep "MemTotal *" /proc/meminfo' is not used */
783
+ let totalRAM = 0;
784
+ const idleCPUtime = +allvalues[1],
785
+ totalCPUtime = +allvalues[2],
786
+ psListStartIndex = allvalues.indexOf("psList", 2),
787
+ serviceStartIndex = allvalues.indexOf("serviceStringStart", 2), // from where to start (2)
788
+ serviceEndIndex = allvalues.indexOf("serviceStringEnd", 2); // from where to start (2)
789
+
790
+ const arryInstalledServices = [];
791
+ for (let i = serviceStartIndex + 1; i < serviceEndIndex; i++) {
792
+ arryInstalledServices[i-serviceStartIndex-1] = allvalues[i];
793
+ }
794
+
795
+ // get processid of external service on ps list
796
+ let arrayCount = 0;
797
+ for (let k = psListStartIndex+1 ; k < serviceStartIndex ;k++) {
798
+ const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN),
799
+ pid = parseInt(columns[0]),
800
+ procname = columns[1].trim();
801
+
802
+ if (arryInstalledServices.indexOf(procname) !== -1) {
803
+ const ObjService = {
804
+ "processid": pid,
805
+ "id": procname
806
+ };
807
+ arrActiveServices[arrayCount++] = ObjService;
808
+ }
809
+ }
810
+
811
+ const appStartIndex = allvalues.indexOf("{", 2); // From where to start (2)
812
+ // some times specific platform does not gives list of running info itself then appStartIndex becomes -1
813
+ if (appStartIndex < 0) {
814
+ // do not print error message to user
815
+ // when user press Ctrl + C , the ssh cmd data is not completed, it makes error
816
+ log.silly("device#processResource()#_setProcessInfo()", "running app list is invalid");
817
+ return;
818
+ }
819
+ const appEndIndex = allvalues.length-1;
820
+ let strActiveApps = "",
821
+ objActiveApps;
822
+ for (let i = appStartIndex; i < appEndIndex; i++) {
823
+ strActiveApps += allvalues[i];
824
+ }
825
+ try {
826
+ objActiveApps = JSON.parse(strActiveApps);
827
+ } catch (err) {
828
+ // do not print error message to user
829
+ // when user press Ctrl + C , the ssh cmd data is not completed, it makes error
830
+ log.silly("device#processResource()#_setProcessInfo()", "active app parsing. err:", err.toString());
831
+ return;
832
+ }
833
+
834
+ if (objActiveApps.returnValue === false) {
835
+ const errValue = objActiveApps["errorText"] || "running app list is invalid";
836
+ return next(errHndl.getErrMsg("FAILED_CALL_LUNA", errValue, null, "com.webos.applicationManager"));
837
+ }
838
+
839
+ const arrActiveApps = objActiveApps["running"],
840
+ groupObjList = {};
841
+
842
+ // 1st row is date, 2nd row is total CPU time and last row is total RAM(Meminfo) hence ignore it
843
+ // check process group info until "psList" string
844
+ for (let k = 3; k < psListStartIndex; k++) {
845
+ const columns = allvalues[k].trim().split(PROC_GROUP_INFO_PATTERN),
846
+ procname = columns[1].trim().split(/.*\(|\)/gi)[1],
847
+ grpname = _getProcessGrp(procname),
848
+ pid = parseInt(columns[0]),
849
+ pname = procname,
850
+ ppid = parseInt(columns[3]),
851
+ cputime = parseInt(columns[13]) + parseInt(columns[14]),
852
+ rss = parseInt(columns[23]) * 4,
853
+ pmem = (rss * 100);
854
+ // sum total used RSS
855
+ totalRAM += rss;
856
+ if (grpname === "Other") {
857
+ const objOther = {};
858
+ objOther["pid"] = pid;
859
+ objOther["pname"] = pname;
860
+ objOther["ppid"] = ppid;
861
+ objOther["cputime"] = cputime;
862
+ objOther["RSS"] = rss;
863
+ objOther["pmem"] = pmem;
864
+ otherList.push(objOther);
865
+ } else {
866
+ tempProcGrps[grpname]["pid"] = pid;
867
+ tempProcGrps[grpname]["cputime"] += cputime;
868
+ tempProcGrps[grpname]["RSS"] += rss;
869
+ tempProcGrps[grpname]["pmem"] += pmem;
870
+ }
871
+ }
872
+ // get the Children of Service
873
+ for (const k in tempProcGrps) {
874
+ const attrName = k;
875
+ if (attrName === "System") {
876
+ continue;
877
+ }
878
+ const objOther = tempProcGrps[k];
879
+ for (let i = 0; i < otherList.length; i++) {
880
+ if (objOther["pid"] !== otherList[i]["ppid"]) {
881
+ continue;
882
+ }
883
+ }
884
+ }
885
+
886
+ // this variable will mantain the aggregate pcpuVal of Service + dynamic apps
887
+ let aggcpuVal = 0;
888
+ // get the Web App processes data
889
+ if (arrActiveApps.length === 0) {
890
+ // get only the existing categories(3) if no running apps.
891
+ // dispose all the existing process variables
892
+ for (const name in processGroup) {
893
+ // if propertyName starts with "prev_" then dispose it
894
+ if (!Object.prototype.hasOwnProperty.call(processGroup, name)) {
895
+ continue;
896
+ }
897
+ if (name.indexOf("prev_app_") >= 0) {
898
+ processGroup[name] = undefined;
899
+ }
900
+ }
901
+ } else {
902
+ // loop through each of the running apps
903
+ // in loop - Check if app is newly running app (or) already existing running app
904
+ for (let j = 0; j < arrActiveApps.length; j++) {
905
+ const objActApp = arrActiveApps[j],
906
+ webprocId = objActApp["webprocessid"],
907
+ procId = objActApp["processid"],
908
+ displayId = objActApp["displayId"] || 0;
909
+ let processId;
910
+ if (webprocId !== "" && webprocId !== undefined && webprocId !== "undefined") {
911
+ processId = webprocId;
912
+ } else if (procId !== "" && procId !== undefined && procId !== "undefined") {
913
+ processId = procId;
914
+ } else {
915
+ break;
916
+ }
917
+
918
+ const prevcpuTime = "prev_app_" + processId + "cputime",
919
+ appid = parseInt(processId);
920
+ let pcputime = 0;
921
+ // get the cputime from otherList
922
+ for (let l = 0; l < otherList.length; l++) {
923
+ if (otherList[l]["pid"] !== appid) {
924
+ continue;
925
+ }
926
+ pcputime = otherList[l]["cputime"];
927
+ if (!processGroup[prevcpuTime]) {
928
+ processGroup[prevcpuTime] = pcputime;
929
+ break;
930
+ }
931
+ let webpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime));
932
+ // restrict showing the negative % values by making lowest to be zero.
933
+ if (webpcpuval < 0 || webpcpuval === undefined || isNaN(webpcpuval)) webpcpuval = 0;
934
+ aggcpuVal += webpcpuval;
935
+ const groupListAppKey = objActApp["id"]+ "-" + appid;
936
+ groupObjList[groupListAppKey] = {
937
+ "id": objActApp["id"],
938
+ "pid": appid,
939
+ "cpu": webpcpuval,
940
+ "memory": {
941
+ "size": otherList[l]["RSS"],
942
+ "percent": otherList[l]["pmem"].toFixed(2)
943
+ },
944
+ "displayId": displayId
945
+ };
946
+ processGroup[prevcpuTime] = pcputime;
947
+ otherList.splice(l, 1);
948
+ break;
949
+ }
950
+ }
951
+ }
952
+ // get the service processes data
953
+ if (arrActiveServices.length === 0) {
954
+ // get only the existing categories(3) if no running apps.
955
+ // dispose all the existing process variables
956
+ for (const name in processGroup) {
957
+ // if propertyName starts with "prev_" then dispose it
958
+ if (!Object.prototype.hasOwnProperty.call(processGroup, name)) {
959
+ continue;
960
+ }
961
+ if (name.indexOf("prev_svc_") >= 0) {
962
+ processGroup[name] = undefined;
963
+ }
964
+ }
965
+ } else {
966
+ // loop through each of the running apps
967
+ // in loop - Check if app is newly running app (or) already existing running app
968
+ for (let j = 0; j < arrActiveServices.length; j++) {
969
+ const objActService = arrActiveServices[j],
970
+ processId = objActService["processid"],
971
+ prevcpuTime = "prev_svc_" + processId + "cputime",
972
+ appid = parseInt(processId);
973
+ let pcputime = 0;
974
+ // get the cputime from otherList
975
+ for (let l = 0; l < otherList.length; l++) {
976
+ if (otherList[l]["pid"] !== appid) {
977
+ continue;
978
+ }
979
+ pcputime = otherList[l]["cputime"];
980
+ if (!processGroup[prevcpuTime]) {
981
+ processGroup[prevcpuTime] = pcputime;
982
+ break;
983
+ }
984
+ let svcpcpuval = ((pcputime - processGroup[prevcpuTime]) * 100/(totalCPUtime - processGroup.prevTotalcputime));
985
+ // restrict showing the negative % values by making lowest to be zero.
986
+ if (svcpcpuval < 0 || svcpcpuval === undefined || isNaN(svcpcpuval)) svcpcpuval = 0;
987
+ aggcpuVal+= svcpcpuval;
988
+ groupObjList[objActService["id"]] = {
989
+ "pid": appid,
990
+ "cpu": svcpcpuval,
991
+ "memory": {
992
+ "size": otherList[l]["RSS"],
993
+ "percent": otherList[l]["pmem"].toFixed(2)
994
+ }
995
+ };
996
+ processGroup[prevcpuTime] = pcputime;
997
+ otherList.splice(l, 1);
998
+ break;
999
+ }
1000
+ }
1001
+ }
1002
+ // get the remaining System Category processes
1003
+ for (let i = 0; i < otherList.length; i++) {
1004
+ tempProcGrps["System"]["pid"] = otherList[i]["pid"];
1005
+ tempProcGrps["System"]["cputime"]+= otherList[i]["cputime"];
1006
+ tempProcGrps["System"]["RSS"]+= otherList[i]["RSS"];
1007
+ tempProcGrps["System"]["pmem"]+= otherList[i]["pmem"];
1008
+ }
1009
+ if (!processGroup.initialExecution) {
1010
+ const diffIdle = idleCPUtime - processGroup.prevIdlecputime,
1011
+ diffTotal = totalCPUtime - processGroup.prevTotalcputime,
1012
+ overallCpuOccupation = ((diffTotal - diffIdle)/diffTotal) * 100;
1013
+ // assign all the values to return Object
1014
+ for (const key in tempProcGrps) {
1015
+ const processName = key;
1016
+ let tempPcpuval = 0;
1017
+ if (processName === "Service") {
1018
+ tempPcpuval = ((tempProcGrps[processName]["cputime"] - processGroup.prevServicecputime) * 100/diffTotal);
1019
+ }
1020
+ // restrict showing the negative % values by making lowest to be zero.
1021
+ if (tempPcpuval < 0 || tempPcpuval === undefined || isNaN(tempPcpuval)) tempPcpuval = 0;
1022
+ aggcpuVal += tempPcpuval;
1023
+ // system = overallCpuOccupation - (Service used + dynamic apps used);
1024
+ if (processName === "System") {
1025
+ tempPcpuval = overallCpuOccupation - aggcpuVal;
1026
+ }
1027
+ // restrict Negative/peak values due to cores fluctuation
1028
+ tempPcpuval < 0 ? (tempPcpuval = 0) : tempPcpuval;
1029
+ tempPcpuval > pcore ? (tempPcpuval = pcore) : tempPcpuval;
1030
+ tempProcGrps[processName]["pmem"] /= totalRAM;
1031
+ const procinfo = {
1032
+ "pid": tempProcGrps[processName]["pid"],
1033
+ "appid": processName,
1034
+ "cpu": parseFloat(tempPcpuval.toFixed(2)),
1035
+ "memory": {
1036
+ "size": tempProcGrps[processName]["RSS"],
1037
+ "percent": tempProcGrps[processName]["pmem"].toFixed(2)
1038
+ }
1039
+ };
1040
+ processinfo.push(procinfo);
1041
+ }
1042
+ // push the calculated groups into list
1043
+ for (const propertyName in groupObjList) {
1044
+ if (!Object.prototype.hasOwnProperty.call(groupObjList, propertyName)) {
1045
+ continue;
1046
+ }
1047
+
1048
+ const procObj = groupObjList[propertyName];
1049
+ let pcpuval = parseFloat(procObj["cpu"].toFixed(2));
1050
+ if (pcpuval === undefined || isNaN(pcpuval)) {
1051
+ pcpuval = 0;
1052
+ }
1053
+ procObj["memory"]["percent"] /= totalRAM;
1054
+ const procinfo = {
1055
+ "pid": procObj["pid"],
1056
+ "appid": procObj["id"] || propertyName,
1057
+ "cpu": pcpuval,
1058
+ "memory": {
1059
+ "size": procObj["memory"]["size"],
1060
+ "percent": parseFloat(procObj["memory"]["percent"]).toFixed(2)
1061
+ },
1062
+ "displayId": procObj["displayId"]
1063
+ };
1064
+
1065
+ processinfo.push(procinfo);
1066
+ // copy only app and service info to group for printing
1067
+ groupProcessinfo.push(procinfo);
1068
+
1069
+ if (processinfo.indexOf(propertyName) < 0) {
1070
+ processList.push(propertyName);
1071
+ groupProcessList.push(propertyName);
1072
+ }
1073
+ }
1074
+ }
1075
+ processGroup.prevIdlecputime = idleCPUtime;
1076
+ processGroup.prevTotalcputime = totalCPUtime;
1077
+ processGroup.prevServicecputime = tempProcGrps["Service"]["cputime"];
1078
+
1079
+ if (!processGroup.initialExecution) {
1080
+ const processgrpinfo = {
1081
+ "date": date,
1082
+ "processinfo": groupProcessinfo,
1083
+ "processList": groupProcessList
1084
+ };
1085
+ _printProcessList(processgrpinfo);
1086
+ }
1087
+ } catch (err) {
1088
+ // do not print error message to user
1089
+ // when user press Ctrl + C , the ssh cmd data is not completed, it makes error
1090
+ log.silly("device#processResource()#_setProcessInfo()", "in try-catch. err:", err.toString());
1091
+ return;
1092
+ }
1093
+ }
1094
+
1095
+ function _getProcessGrp(pname) {
1096
+ let group;
1097
+ switch (pname) {
1098
+ case 'ls-hubd':
1099
+ group = 'Service'; break;
1100
+ default:
1101
+ group = 'Other'; // it could be children of above categories or System
1102
+ }
1103
+ return group;
1104
+ }
1105
+
1106
+ function _printProcessList(processgrpinfo) {
1107
+ log.info("device#processResource()#_printProcessList()", JSON.stringify(processgrpinfo));
1108
+
1109
+ const processinfo = processgrpinfo.processinfo,
1110
+ processinfoTable = new Table();
1111
+
1112
+ let found = false;
1113
+ if (options.id) {
1114
+ processinfo.forEach(function(process) {
1115
+ if (options.id === process.appid) {
1116
+ found = true;
1117
+ }
1118
+ });
1119
+ if (found === false) {
1120
+ // print guide message to user
1121
+ console.log("<" + options.id + ">" + " is not running. Please launch the app or service.");
1122
+ return;
1123
+ }
1124
+ }
1125
+ if (processgrpinfo.processList.length === 0) {
1126
+ // print guide message to user
1127
+ console.log("There are no running apps or services. Please launch any app or service.");
1128
+ return;
1129
+ }
1130
+
1131
+ // add process list to table
1132
+ const dataForCSV = [];
1133
+ if (Array.isArray(processinfo)) {
1134
+ processinfo.forEach(function(process) {
1135
+ // if user gives ID, print only the ID's information
1136
+ if (options.id && options.id !== process.appid) {
1137
+ return;
1138
+ }
1139
+ processinfoTable.cell('PID', process.pid);
1140
+ processinfoTable.cell('ID', process.appid);
1141
+ processinfoTable.cell('DISPLAY ID', process.displayId);
1142
+ processinfoTable.cell('CPU(%)', process.cpu);
1143
+
1144
+ const meminfo = process.memory;
1145
+ processinfoTable.cell('MEMORY(%)', meminfo.percent);
1146
+ processinfoTable.cell('MEMORY(KB)', meminfo.size);
1147
+ processinfoTable.newRow();
1148
+
1149
+ // add data object
1150
+ const obj = {
1151
+ time: processgrpinfo.date,
1152
+ pid: process.pid,
1153
+ id: process.appid,
1154
+ displayId: process.displayId,
1155
+ cpu: process.cpu,
1156
+ memory: meminfo.percent,
1157
+ memory_size: meminfo.size
1158
+ };
1159
+ dataForCSV.push(obj);
1160
+ });
1161
+ }
1162
+ // write CSV file if user gives --save option
1163
+ if (options.save && options.csvPath) {
1164
+ // write csv file
1165
+ // when openMode is false, the new csv file will be created and "Header" add to the file
1166
+ let openMode = false;
1167
+ if (fs.existsSync(options.csvPath)) {
1168
+ openMode = true;
1169
+ }
1170
+ const csvWriter = createCsvWriter({
1171
+ path: options.csvPath,
1172
+ header: [
1173
+ {id: 'time', title: 'TIME'},
1174
+ {id: 'pid', title: 'PID'},
1175
+ {id: 'id', title: 'ID'},
1176
+ {id: 'displayId', title: 'DISPLAY ID'},
1177
+ {id: 'cpu', title: 'CPU(%)'},
1178
+ {id: 'memory', title: 'MEMORY(%)'},
1179
+ {id: 'memory_size', title: 'MEMORY(KB)'}
1180
+ ],
1181
+ append: openMode
1182
+ });
1183
+
1184
+ csvWriter
1185
+ .writeRecords(dataForCSV)
1186
+ .then(function() {
1187
+ log.silly("device#processResource()#_printProcessList()", "CSV file updated");
1188
+ // csv file has been created at first
1189
+ if (openMode === false) {
1190
+ const resultTxt = "Create " + chalk.green(options.fileName) + " to " + options.destinationPath;
1191
+ console.log(resultTxt);
1192
+ }
1193
+ __printTable();
1194
+ }).catch(function(err) {
1195
+ return setImmediate(next, errHndl.getErrMsg(err));
1196
+ });
1197
+ } else {
1198
+ __printTable();
1199
+ }
1200
+
1201
+ function __printTable() {
1202
+ // Print resullt to terminal
1203
+ console.log(processgrpinfo.date + "\n");
1204
+ console.log(processinfoTable.toString());
1205
+ console.log("======================================================================");
1206
+ }
1207
+ }
1208
+ },
1209
+ /**
1210
+ * get screen capture of the given device
1211
+ * @property options {String} device, display, outputPath
1212
+ */
1213
+ captureScreen: function(options, next) {
1214
+ if (typeof next !== 'function') {
1215
+ throw errHndl.getErrMsg("MISSING_CALLBACK", "next", util.inspect(next));
1216
+ }
1217
+ options = options || {};
1218
+ async.series([
1219
+ _makeSession,
1220
+ _makeCaptureOption,
1221
+ _captureScreenFile,
1222
+ _copyFileToLocal
1223
+ ], function(err, results) {
1224
+ log.silly("device#captureScreen()", "err:", err, ", results:", results);
1225
+ const resultTxt = "Create " + chalk.green(options.captureFileName) + " to " + options.destinationPath +"\nSuccess";
1226
+
1227
+ // clean up /tmp/aresCapture directory in target device
1228
+ if (options.createdTmpDir) {
1229
+ _removeTmpDir(function finish(removeErr) {
1230
+ next(err ? err : removeErr, {msg: resultTxt});
1231
+ });
1232
+ } else {
1233
+ next(err, {msg: resultTxt});
1234
+ }
1235
+ });
1236
+
1237
+ function _makeSession(next) {
1238
+ makeSession(options, next);
1239
+ }
1240
+
1241
+ function _makeCaptureOption(next) {
1242
+ log.info("device#captureScreen()#_makeCaptureOption()");
1243
+
1244
+ const captureFormat = "PNG", // PNG is default format
1245
+ fileNameSeperator = "_";
1246
+
1247
+ let captureFileName = options.session.target.name + "_" + "display" + options.display + "_",
1248
+ destinationPath = "";
1249
+
1250
+ if (options.outputPath === null) {
1251
+ captureFileName += createDateFileName(fileNameSeperator, captureFormat.toLowerCase());
1252
+ destinationPath = path.resolve('.');
1253
+ } else {
1254
+ // get directory path, file path, file Extenstion from given path
1255
+ const parseDirPath = path.dirname(options.outputPath),
1256
+ parseBase = path.parse(options.outputPath).base;
1257
+
1258
+ let parseExt = path.parse(options.outputPath).ext;
1259
+
1260
+ parseExt = parseExt.split('.').pop();
1261
+ log.info("device#captureScreen()#_makeCaptureOption()" + "dir name:" + parseDirPath
1262
+ + " ,file name:" + parseBase + " ,inputFormat:" + parseExt);
1263
+
1264
+ // if specific path is given
1265
+ if (parseBase) {
1266
+ captureFileName = parseBase;
1267
+ destinationPath = path.resolve(parseDirPath);
1268
+ // parseBase is [filename].[ext] format
1269
+ if (parseExt === "") {
1270
+ // paresBase does not have file extesntion, add .png format
1271
+ captureFileName += "." + captureFormat.toLowerCase();
1272
+ } else if (parseExt !== "png" && parseExt !== "bmp" && parseExt !== "jpg") {
1273
+ return next(errHndl.getErrMsg("INVALID_CAPTURE_FORMAT"));
1274
+ }
1275
+ } else if (parseDirPath) {
1276
+ // the path has only "directory" without parseBase
1277
+ // for example, "ares-device -c /"
1278
+ captureFileName = createDateFileName(fileNameSeperator, captureFormat.toLowerCase());
1279
+ destinationPath = path.resolve(parseDirPath);
1280
+ }
1281
+ }
1282
+
1283
+ options.captureFormat = captureFormat;
1284
+ options.captureFileName = captureFileName;
1285
+ options.captureDirPath = "/tmp/aresCapture/";
1286
+ options.sourcePath = options.captureDirPath + captureFileName;
1287
+ options.destinationPath = destinationPath;
1288
+ options.ignore = true;
1289
+ options.silent = true;
1290
+
1291
+ next();
1292
+ }
1293
+
1294
+ function _captureScreenFile(next) {
1295
+ log.info("device#captureScreen()#_captureScreenFile()");
1296
+ const cmd = "/bin/mkdir -p " + options.captureDirPath + " && chmod 777 " + options.captureDirPath;
1297
+ options.session.run(cmd, null, null, null, function(err) {
1298
+ if (err) {
1299
+ return setImmediate(next, err);
1300
+ } else {
1301
+ options.createdTmpDir = true;
1302
+ const target = options.session.getDevice(),
1303
+ addr = target.lunaAddr.captureCompositorOutput,
1304
+ param = {
1305
+ // luna param
1306
+ subscribe: false,
1307
+ output: options.sourcePath,
1308
+ format: options.captureFormat,
1309
+ displayId: options.display
1310
+ };
1311
+
1312
+ luna.send(options, addr, param, function(lineObj, next) {
1313
+ if (lineObj.returnValue) {
1314
+ log.verbose("device#captureScreen()#_captureScreenFile()","Capture file in target:" + lineObj.output);
1315
+ next(null, {});
1316
+ } else {
1317
+ log.verbose("device#captureScreen()#_captureScreenFile()", "failure");
1318
+ next(errHndl.getErrMsg("INVALID_OBJECT"));
1319
+ }
1320
+ }, next);
1321
+ }
1322
+ });
1323
+ }
1324
+
1325
+ function _copyFileToLocal(next) {
1326
+ log.info("device#captureScreen()#_copyFileToLocal()");
1327
+ pullLib.pull(options.sourcePath, options.destinationPath, options, next);
1328
+ }
1329
+
1330
+ function _removeTmpDir(next) {
1331
+ log.info("device#captureScreen()#_removeTmpDir()");
1332
+ const cmd = '/bin/rm -rf ' + options.captureDirPath;
1333
+ options.session.run(cmd, null, null, null, function(err) {
1334
+ if (err) {
1335
+ return setImmediate(next, err);
1336
+ } else {
1337
+ next();
1338
+ }
1339
+ });
1340
+ }
1341
+ }
1342
+ };
1343
+
1344
+ function makeSession(options, next) {
1345
+ options.nReplies = 1; // -n 1
1346
+ if (!options.session) {
1347
+ log.info("device#makeSession()", "need to make new session");
1348
+ const printTarget = true;
1349
+ options.session = new novacom.Session(options.device, printTarget, next);
1350
+ } else {
1351
+ log.info("device#makeSession()", "already exist session");
1352
+ next();
1353
+ }
1354
+ }
1355
+
1356
+ function makeCSVOutputPath(options, next) {
1357
+ const csvFormat = "csv", // csv is default format
1358
+ fileNameSeperator = "_";
1359
+
1360
+ if (options.outputPath === null) {
1361
+ options.fileName = createDateFileName(fileNameSeperator, csvFormat);
1362
+ options.destinationPath = path.resolve('.');
1363
+ } else {
1364
+ // get directory path, file path, file Extenstion from given path
1365
+ const parseDirPath = path.dirname(options.outputPath),
1366
+ parseBase = path.parse(options.outputPath).base;
1367
+
1368
+ let parseExt = path.parse(options.outputPath).ext;
1369
+
1370
+ parseExt = parseExt.split('.').pop();
1371
+ log.info("device#captureScreen()#_makeCaptureOption()" + "dir name:" + parseDirPath
1372
+ + " ,file name:" + parseBase + " ,inputFormat:" + parseExt);
1373
+
1374
+ // if specific path is given
1375
+ if (parseBase) {
1376
+ options.fileName = parseBase;
1377
+ options.destinationPath = path.resolve(parseDirPath);
1378
+ // parseBase is [filename].[ext] format
1379
+ if (parseExt === "") {
1380
+ // paresBase does not have file extesntion, add .png format
1381
+ options.fileName += "." + csvFormat;
1382
+ } else if (parseExt !== csvFormat) {
1383
+ return next(errHndl.getErrMsg("INVALID_CSV_FORMAT"));
1384
+ }
1385
+ } else if (parseDirPath) {
1386
+ // the path has only "directory" without parseBase
1387
+ // for example, "ares-device -r -s /"
1388
+ options.fileName = createDateFileName(fileNameSeperator, csvFormat);
1389
+ options.destinationPath = path.resolve(parseDirPath);
1390
+ }
1391
+ }
1392
+
1393
+ options.csvPath = path.resolve(options.destinationPath, options.fileName);
1394
+ log.verbose("device#makeCSVOutputPath()", "csvPath:", options.csvPath);
1395
+
1396
+ fs.open(options.csvPath, 'w', function(err, fd) {
1397
+ if (err) {
1398
+ return next(errHndl.getErrMsg(err));
1399
+ }
1400
+ fs.close(fd, function(error) {
1401
+ if (error) {
1402
+ return next(errHndl.getErrMsg(error));
1403
+ }
1404
+ log.verbose("device#makeCSVOutputPath()", options.csvPath + " is closed");
1405
+
1406
+ // Defense code
1407
+ if (fs.existsSync(options.csvPath)) {
1408
+ fs.unlinkSync(options.csvPath);
1409
+ }
1410
+ log.verbose("device#makeCSVOutputPath()", options.csvPath + " is exist: " + fs.existsSync(options.csvPath));
1411
+ next();
1412
+ });
1413
+ });
1414
+ }
1415
+
1416
+ if (typeof module !== 'undefined' && module.exports) {
1417
+ module.exports = device;
1418
+ }
1419
+ }());