@alwaysai/device-agent 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/lib/application-control/config.d.ts.map +1 -1
  2. package/lib/application-control/config.js +8 -3
  3. package/lib/application-control/config.js.map +1 -1
  4. package/lib/application-control/environment-variables.d.ts +1 -5
  5. package/lib/application-control/environment-variables.d.ts.map +1 -1
  6. package/lib/application-control/environment-variables.js +9 -26
  7. package/lib/application-control/environment-variables.js.map +1 -1
  8. package/lib/application-control/environment-variables.test.js +27 -7
  9. package/lib/application-control/environment-variables.test.js.map +1 -1
  10. package/lib/application-control/index.d.ts +4 -4
  11. package/lib/application-control/index.d.ts.map +1 -1
  12. package/lib/application-control/index.js +1 -4
  13. package/lib/application-control/index.js.map +1 -1
  14. package/lib/application-control/install.d.ts.map +1 -1
  15. package/lib/application-control/install.js +8 -7
  16. package/lib/application-control/install.js.map +1 -1
  17. package/lib/application-control/models.d.ts +0 -11
  18. package/lib/application-control/models.d.ts.map +1 -1
  19. package/lib/application-control/models.js +5 -54
  20. package/lib/application-control/models.js.map +1 -1
  21. package/lib/application-control/utils.d.ts +0 -4
  22. package/lib/application-control/utils.d.ts.map +1 -1
  23. package/lib/application-control/utils.js +1 -24
  24. package/lib/application-control/utils.js.map +1 -1
  25. package/lib/cloud-connection/bootstrap-provision.js +3 -2
  26. package/lib/cloud-connection/bootstrap-provision.js.map +1 -1
  27. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +10 -15
  28. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  29. package/lib/cloud-connection/device-agent-cloud-connection.js +279 -250
  30. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  31. package/lib/cloud-connection/device-agent.d.ts.map +1 -1
  32. package/lib/cloud-connection/device-agent.js +11 -9
  33. package/lib/cloud-connection/device-agent.js.map +1 -1
  34. package/lib/cloud-connection/live-updates-handler.d.ts +18 -28
  35. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  36. package/lib/cloud-connection/live-updates-handler.js +54 -169
  37. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  38. package/lib/cloud-connection/live-updates-handler.test.js +71 -165
  39. package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
  40. package/lib/cloud-connection/passthrough-handler.d.ts +4 -1
  41. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
  42. package/lib/cloud-connection/passthrough-handler.js +30 -11
  43. package/lib/cloud-connection/passthrough-handler.js.map +1 -1
  44. package/lib/cloud-connection/shadow-handler.d.ts +5 -3
  45. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  46. package/lib/cloud-connection/shadow-handler.js +59 -27
  47. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  48. package/lib/cloud-connection/shadow-handler.test.js +45 -57
  49. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  50. package/lib/cloud-connection/shadow.d.ts.map +1 -1
  51. package/lib/cloud-connection/shadow.js +2 -1
  52. package/lib/cloud-connection/shadow.js.map +1 -1
  53. package/lib/cloud-connection/transaction-manager.d.ts +4 -2
  54. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  55. package/lib/cloud-connection/transaction-manager.js +18 -29
  56. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  57. package/lib/cloud-connection/transaction-manager.test.js +3 -3
  58. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  59. package/lib/device-control/device-control.d.ts +8 -8
  60. package/lib/device-control/device-control.d.ts.map +1 -1
  61. package/lib/device-control/device-control.js +95 -71
  62. package/lib/device-control/device-control.js.map +1 -1
  63. package/lib/docker/docker-compose.d.ts.map +1 -1
  64. package/lib/docker/docker-compose.js +2 -1
  65. package/lib/docker/docker-compose.js.map +1 -1
  66. package/lib/infrastructure/agent-config.d.ts +2 -1
  67. package/lib/infrastructure/agent-config.d.ts.map +1 -1
  68. package/lib/infrastructure/agent-config.js +7 -7
  69. package/lib/infrastructure/agent-config.js.map +1 -1
  70. package/lib/infrastructure/agent-config.test.js +3 -1
  71. package/lib/infrastructure/agent-config.test.js.map +1 -1
  72. package/lib/infrastructure/config-check-utility.d.ts +6 -0
  73. package/lib/infrastructure/config-check-utility.d.ts.map +1 -0
  74. package/lib/infrastructure/config-check-utility.js +67 -0
  75. package/lib/infrastructure/config-check-utility.js.map +1 -0
  76. package/lib/infrastructure/config-check-utility.test.d.ts +2 -0
  77. package/lib/infrastructure/config-check-utility.test.d.ts.map +1 -0
  78. package/lib/infrastructure/config-check-utility.test.js +109 -0
  79. package/lib/infrastructure/config-check-utility.test.js.map +1 -0
  80. package/lib/infrastructure/device-certificate.d.ts +10 -0
  81. package/lib/infrastructure/device-certificate.d.ts.map +1 -0
  82. package/lib/infrastructure/device-certificate.js +47 -0
  83. package/lib/infrastructure/device-certificate.js.map +1 -0
  84. package/lib/infrastructure/device-certificate.test.d.ts +2 -0
  85. package/lib/infrastructure/device-certificate.test.d.ts.map +1 -0
  86. package/lib/infrastructure/device-certificate.test.js +24 -0
  87. package/lib/infrastructure/device-certificate.test.js.map +1 -0
  88. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts +2 -0
  89. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts.map +1 -0
  90. package/lib/infrastructure/legacy-migration/legacy-file.test.js +61 -0
  91. package/lib/infrastructure/legacy-migration/legacy-file.test.js.map +1 -0
  92. package/lib/infrastructure/legacy-migration/legacy-files.d.ts +75 -0
  93. package/lib/infrastructure/legacy-migration/legacy-files.d.ts.map +1 -0
  94. package/lib/infrastructure/legacy-migration/legacy-files.js +75 -0
  95. package/lib/infrastructure/legacy-migration/legacy-files.js.map +1 -0
  96. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts +6 -0
  97. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -0
  98. package/lib/infrastructure/legacy-migration/legacy-migration.js +149 -0
  99. package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -0
  100. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts +2 -0
  101. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts.map +1 -0
  102. package/lib/infrastructure/legacy-migration/legacy-migration.test.js +226 -0
  103. package/lib/infrastructure/legacy-migration/legacy-migration.test.js.map +1 -0
  104. package/lib/infrastructure/require-files-present-ready.test.d.ts +2 -0
  105. package/lib/infrastructure/require-files-present-ready.test.d.ts.map +1 -0
  106. package/lib/infrastructure/require-files-present-ready.test.js +44 -0
  107. package/lib/infrastructure/require-files-present-ready.test.js.map +1 -0
  108. package/lib/infrastructure/required-config-checks.d.ts +2 -0
  109. package/lib/infrastructure/required-config-checks.d.ts.map +1 -0
  110. package/lib/infrastructure/required-config-checks.js +30 -0
  111. package/lib/infrastructure/required-config-checks.js.map +1 -0
  112. package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -1
  113. package/lib/infrastructure/tokens-and-device-cfg.js +11 -8
  114. package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -1
  115. package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -1
  116. package/lib/local-connection/rabbitmq-connection.js +14 -14
  117. package/lib/local-connection/rabbitmq-connection.js.map +1 -1
  118. package/lib/secure-tunneling/secure-tunneling.d.ts +9 -9
  119. package/lib/secure-tunneling/secure-tunneling.d.ts.map +1 -1
  120. package/lib/secure-tunneling/secure-tunneling.js +21 -16
  121. package/lib/secure-tunneling/secure-tunneling.js.map +1 -1
  122. package/lib/secure-tunneling/secure-tunneling.test.js +11 -13
  123. package/lib/secure-tunneling/secure-tunneling.test.js.map +1 -1
  124. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  125. package/lib/subcommands/app/analytics.js +1 -2
  126. package/lib/subcommands/app/analytics.js.map +1 -1
  127. package/lib/subcommands/app/env-vars.d.ts +4 -0
  128. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  129. package/lib/subcommands/app/env-vars.js +52 -6
  130. package/lib/subcommands/app/env-vars.js.map +1 -1
  131. package/lib/subcommands/app/index.d.ts.map +1 -1
  132. package/lib/subcommands/app/index.js +1 -3
  133. package/lib/subcommands/app/index.js.map +1 -1
  134. package/lib/subcommands/app/models.d.ts +0 -11
  135. package/lib/subcommands/app/models.d.ts.map +1 -1
  136. package/lib/subcommands/app/models.js +2 -58
  137. package/lib/subcommands/app/models.js.map +1 -1
  138. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  139. package/lib/subcommands/app/shadow.js +6 -5
  140. package/lib/subcommands/app/shadow.js.map +1 -1
  141. package/lib/subcommands/app/version.d.ts.map +1 -1
  142. package/lib/subcommands/app/version.js +2 -4
  143. package/lib/subcommands/app/version.js.map +1 -1
  144. package/lib/subcommands/config.d.ts +2 -0
  145. package/lib/subcommands/config.d.ts.map +1 -0
  146. package/lib/subcommands/config.js +39 -0
  147. package/lib/subcommands/config.js.map +1 -0
  148. package/lib/subcommands/device/clean.d.ts +1 -1
  149. package/lib/subcommands/device/clean.d.ts.map +1 -1
  150. package/lib/subcommands/device/clean.js +23 -13
  151. package/lib/subcommands/device/clean.js.map +1 -1
  152. package/lib/subcommands/device/index.d.ts.map +1 -1
  153. package/lib/subcommands/device/index.js +3 -1
  154. package/lib/subcommands/device/index.js.map +1 -1
  155. package/lib/subcommands/device/init.js +8 -8
  156. package/lib/subcommands/device/init.js.map +1 -1
  157. package/lib/subcommands/device/migrate.d.ts +2 -0
  158. package/lib/subcommands/device/migrate.d.ts.map +1 -0
  159. package/lib/subcommands/device/migrate.js +24 -0
  160. package/lib/subcommands/device/migrate.js.map +1 -0
  161. package/lib/subcommands/device/refresh.d.ts.map +1 -1
  162. package/lib/subcommands/device/refresh.js +1 -0
  163. package/lib/subcommands/device/refresh.js.map +1 -1
  164. package/lib/subcommands/index.d.ts +1 -1
  165. package/lib/subcommands/index.d.ts.map +1 -1
  166. package/lib/subcommands/index.js +3 -1
  167. package/lib/subcommands/index.js.map +1 -1
  168. package/lib/subcommands/rabbitmq-connection.d.ts +1 -1
  169. package/lib/subcommands/rabbitmq-connection.d.ts.map +1 -1
  170. package/lib/util/aai-error.d.ts +12 -0
  171. package/lib/util/aai-error.d.ts.map +1 -0
  172. package/lib/util/aai-error.js +11 -0
  173. package/lib/util/aai-error.js.map +1 -0
  174. package/lib/util/aws-regions.d.ts +2 -0
  175. package/lib/util/aws-regions.d.ts.map +1 -0
  176. package/lib/util/{cloud-mode-ready.js → aws-regions.js} +2 -20
  177. package/lib/util/aws-regions.js.map +1 -0
  178. package/lib/util/check-for-updates.d.ts.map +1 -1
  179. package/lib/util/check-for-updates.js +5 -28
  180. package/lib/util/check-for-updates.js.map +1 -1
  181. package/lib/util/clean-certs.d.ts.map +1 -1
  182. package/lib/util/clean-certs.js +5 -4
  183. package/lib/util/clean-certs.js.map +1 -1
  184. package/lib/util/directories.d.ts +4 -18
  185. package/lib/util/directories.d.ts.map +1 -1
  186. package/lib/util/directories.js +18 -32
  187. package/lib/util/directories.js.map +1 -1
  188. package/lib/util/file.d.ts +4 -0
  189. package/lib/util/file.d.ts.map +1 -1
  190. package/lib/util/file.js +65 -4
  191. package/lib/util/file.js.map +1 -1
  192. package/lib/util/get-device-id.d.ts.map +1 -1
  193. package/lib/util/get-device-id.js +7 -1
  194. package/lib/util/get-device-id.js.map +1 -1
  195. package/lib/util/http-client.js +3 -3
  196. package/lib/util/http-client.js.map +1 -1
  197. package/package.json +19 -17
  198. package/readme.md +12 -32
  199. package/src/application-control/config.ts +9 -12
  200. package/src/application-control/environment-variables.test.ts +28 -7
  201. package/src/application-control/environment-variables.ts +13 -40
  202. package/src/application-control/index.ts +3 -16
  203. package/src/application-control/install.ts +15 -10
  204. package/src/application-control/models.ts +6 -87
  205. package/src/application-control/utils.ts +0 -28
  206. package/src/cloud-connection/bootstrap-provision.ts +7 -7
  207. package/src/cloud-connection/device-agent-cloud-connection.ts +639 -525
  208. package/src/cloud-connection/device-agent.ts +16 -7
  209. package/src/cloud-connection/live-updates-handler.test.ts +121 -189
  210. package/src/cloud-connection/live-updates-handler.ts +99 -234
  211. package/src/cloud-connection/passthrough-handler.ts +55 -18
  212. package/src/cloud-connection/shadow-handler.test.ts +45 -57
  213. package/src/cloud-connection/shadow-handler.ts +103 -57
  214. package/src/cloud-connection/shadow.ts +4 -1
  215. package/src/cloud-connection/transaction-manager.test.ts +3 -3
  216. package/src/cloud-connection/transaction-manager.ts +53 -39
  217. package/src/device-control/device-control.ts +102 -70
  218. package/src/docker/docker-compose.ts +3 -2
  219. package/src/infrastructure/agent-config.test.ts +6 -2
  220. package/src/infrastructure/agent-config.ts +8 -7
  221. package/src/infrastructure/config-check-utility.test.ts +154 -0
  222. package/src/infrastructure/config-check-utility.ts +77 -0
  223. package/src/infrastructure/device-certificate.test.ts +40 -0
  224. package/src/infrastructure/device-certificate.ts +58 -0
  225. package/src/infrastructure/legacy-migration/legacy-file.test.ts +88 -0
  226. package/src/infrastructure/legacy-migration/legacy-files.ts +101 -0
  227. package/src/infrastructure/legacy-migration/legacy-migration.test.ts +396 -0
  228. package/src/infrastructure/legacy-migration/legacy-migration.ts +229 -0
  229. package/src/infrastructure/require-files-present-ready.test.ts +53 -0
  230. package/src/infrastructure/required-config-checks.ts +33 -0
  231. package/src/infrastructure/tokens-and-device-cfg.ts +12 -10
  232. package/src/local-connection/rabbitmq-connection.ts +22 -17
  233. package/src/secure-tunneling/secure-tunneling.test.ts +20 -22
  234. package/src/secure-tunneling/secure-tunneling.ts +41 -29
  235. package/src/subcommands/app/analytics.ts +2 -4
  236. package/src/subcommands/app/env-vars.ts +72 -9
  237. package/src/subcommands/app/index.ts +3 -11
  238. package/src/subcommands/app/models.ts +5 -81
  239. package/src/subcommands/app/shadow.ts +6 -5
  240. package/src/subcommands/app/version.ts +3 -4
  241. package/src/subcommands/config.ts +42 -0
  242. package/src/subcommands/device/clean.ts +31 -17
  243. package/src/subcommands/device/index.ts +3 -1
  244. package/src/subcommands/device/init.ts +11 -11
  245. package/src/subcommands/device/migrate.ts +20 -0
  246. package/src/subcommands/device/refresh.ts +1 -0
  247. package/src/subcommands/index.ts +3 -1
  248. package/src/util/aai-error.ts +20 -0
  249. package/src/util/{cloud-mode-ready.ts → aws-regions.ts} +0 -24
  250. package/src/util/check-for-updates.ts +14 -30
  251. package/src/util/clean-certs.ts +8 -4
  252. package/src/util/directories.ts +23 -67
  253. package/src/util/file.ts +83 -3
  254. package/src/util/get-device-id.ts +7 -7
  255. package/src/util/http-client.ts +2 -2
  256. package/lib/util/cloud-mode-ready.d.ts +0 -3
  257. package/lib/util/cloud-mode-ready.d.ts.map +0 -1
  258. package/lib/util/cloud-mode-ready.js.map +0 -1
  259. package/lib/util/download-file.d.ts +0 -6
  260. package/lib/util/download-file.d.ts.map +0 -1
  261. package/lib/util/download-file.js +0 -25
  262. package/lib/util/download-file.js.map +0 -1
  263. package/lib/util/fetch-with-timeout.d.ts +0 -4
  264. package/lib/util/fetch-with-timeout.d.ts.map +0 -1
  265. package/lib/util/fetch-with-timeout.js +0 -30
  266. package/lib/util/fetch-with-timeout.js.map +0 -1
  267. package/lib/util/parsing.d.ts +0 -2
  268. package/lib/util/parsing.d.ts.map +0 -1
  269. package/lib/util/parsing.js +0 -17
  270. package/lib/util/parsing.js.map +0 -1
  271. package/src/util/download-file.ts +0 -25
  272. package/src/util/fetch-with-timeout.ts +0 -35
  273. package/src/util/parsing.ts +0 -11
@@ -4,34 +4,37 @@ exports.runDeviceAgentCloudInterface = exports.DeviceAgentCloudConnection = void
4
4
  // eslint-disable-next-line
5
5
  const awsIot = require('aws-iot-device-sdk');
6
6
  const device_agent_schemas_1 = require("@alwaysai/device-agent-schemas");
7
+ const infrastructure_1 = require("alwaysai/lib/infrastructure");
8
+ const util_1 = require("alwaysai/lib/util");
9
+ const child_process_1 = require("child_process");
7
10
  const fs_1 = require("fs");
11
+ const util_2 = require("util");
8
12
  const application_control_1 = require("../application-control");
9
13
  const backup_1 = require("../application-control/backup");
14
+ const models_1 = require("../application-control/models");
10
15
  const device_control_1 = require("../device-control/device-control");
11
16
  const environment_1 = require("../environment");
12
17
  const agent_config_1 = require("../infrastructure/agent-config");
18
+ const device_certificate_1 = require("../infrastructure/device-certificate");
19
+ const legacy_migration_1 = require("../infrastructure/legacy-migration/legacy-migration");
20
+ const required_config_checks_1 = require("../infrastructure/required-config-checks");
13
21
  const urls_1 = require("../infrastructure/urls");
14
22
  const secure_tunneling_1 = require("../secure-tunneling/secure-tunneling");
15
- const cloud_mode_ready_1 = require("../util/cloud-mode-ready");
23
+ const aai_error_1 = require("../util/aai-error");
24
+ const check_for_updates_1 = require("../util/check-for-updates");
16
25
  const directories_1 = require("../util/directories");
17
26
  const get_device_id_1 = require("../util/get-device-id");
18
27
  const logger_1 = require("../util/logger");
19
28
  const sleep_1 = require("../util/sleep");
20
29
  const bootstrap_provision_1 = require("./bootstrap-provision");
21
30
  const live_updates_handler_1 = require("./live-updates-handler");
31
+ const messages_1 = require("./messages");
22
32
  const passthrough_handler_1 = require("./passthrough-handler");
23
33
  const publisher_1 = require("./publisher");
24
34
  const shadow_handler_1 = require("./shadow-handler");
25
35
  const transaction_manager_1 = require("./transaction-manager");
26
- const child_process_1 = require("child_process");
27
- const util_1 = require("util");
28
- const models_1 = require("../application-control/models");
29
- const check_for_updates_1 = require("../util/check-for-updates");
30
- const exec_promise = (0, util_1.promisify)(child_process_1.exec);
36
+ const exec_promise = (0, util_2.promisify)(child_process_1.exec);
31
37
  class DeviceAgentCloudConnection {
32
- /*=================================================================
33
- Public interface
34
- =================================================================*/
35
38
  constructor() {
36
39
  this.device = awsIot.device;
37
40
  this.clientId = (0, get_device_id_1.getDeviceUuid)();
@@ -152,17 +155,17 @@ class DeviceAgentCloudConnection {
152
155
  return true;
153
156
  };
154
157
  this.device = awsIot.device({
155
- keyPath: directories_1.DEVICE_PRIVATE_KEY_FILE_PATH,
156
- certPath: directories_1.DEVICE_CERTIFICATE_FILE_PATH,
158
+ keyPath: infrastructure_1.DEVICE_PRIVATE_KEY_FILE_PATH,
159
+ certPath: infrastructure_1.DEVICE_CERTIFICATE_FILE_PATH,
157
160
  caPath: directories_1.AWS_ROOT_CERTIFICATE_FILE_PATH,
158
161
  clientId: this.clientId,
159
162
  host: this.host,
160
163
  port: this.port,
161
- keepalive: 1 // time before re-connect attempt on dropped connection, default is 400 seconds
164
+ keepalive: 10 // time before re-connect attempt on dropped connection, default is 400 seconds
162
165
  });
163
166
  this.publisher = new publisher_1.Publisher(this.device, this.clientId);
164
167
  this.shadowHandler = new shadow_handler_1.ShadowHandler(this.clientId, this.publisher);
165
- this.liveUpdatesHandler = new live_updates_handler_1.LiveUpdatesHandler(this.publisher, this.clientId);
168
+ this.liveUpdatesHandler = new live_updates_handler_1.LiveUpdatesHandler();
166
169
  this.txnMgr = new transaction_manager_1.TransactionManager(this.publisher, this.liveUpdatesHandler);
167
170
  this.subscribe(this.toDeviceTopic);
168
171
  this.subscribe(this.secureTunnelNotifyTopic);
@@ -171,127 +174,133 @@ class DeviceAgentCloudConnection {
171
174
  }
172
175
  this.subscribe(this.shadowHandler.shadowTopics.secureTunnel.updateDelta);
173
176
  this.subscribe(this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted);
177
+ this.setupHandlers();
174
178
  }
175
- async handleDeviceAction(payload) {
176
- const { system_restart } = device_agent_schemas_1.keyMirrors.deviceAction;
177
- switch (payload.action) {
178
- case system_restart: {
179
- await (0, device_control_1.reboot)();
180
- break;
181
- }
182
- default: {
183
- logger_1.logger.info(`Unrecognized device action requested: '${payload.action}'.`);
184
- }
185
- }
186
- }
187
- async publishCloudRequest(message) {
188
- this.publisher.publishToCloud(message);
179
+ /*=================================================================
180
+ Public interface
181
+ =================================================================*/
182
+ getClientId() {
183
+ return this.clientId;
189
184
  }
190
- subscribe(topic) {
191
- logger_1.logger.info(`Subscribing to ${topic}`);
192
- this.device.subscribe(topic);
185
+ isCmdInProgress(projectId) {
186
+ return this.txnMgr.isOngoingTransactionForProjectID(projectId);
193
187
  }
194
- async atomicApplicationUninstall(projectId) {
195
- try {
196
- await (0, application_control_1.uninstallApp)({ projectId });
197
- this.shadowHandler.clearProjectShadow(projectId);
188
+ async handleMessage(topic, message) {
189
+ logger_1.logger.debug(`Received message: ${JSON.stringify({ topic, message }, null, 2)}`);
190
+ // ProjectShadow messages
191
+ if (this.shadowHandler.projectShadowTopics.includes(topic)) {
192
+ await this.handleProjectShadowMessage(topic, message);
198
193
  }
199
- catch (e) {
200
- logger_1.logger.error(`Failed to uninstall ${projectId}: ${e.message}`);
201
- throw e;
194
+ else if (topic === this.toDeviceTopic) {
195
+ await this.handleDeviceAgentMessage({
196
+ topic,
197
+ message
198
+ });
199
+ // SecureTunnelNotify messages
200
+ }
201
+ else if (topic === this.secureTunnelNotifyTopic) {
202
+ await this.secureTunnelHandler.secureTunnelNotifyHandler(message);
203
+ // SecureTunnel messages
204
+ }
205
+ else if (topic === this.shadowHandler.shadowTopics.secureTunnel.updateDelta) {
206
+ await this.handleSecureTunnelMessage(message);
207
+ }
208
+ else if (topic === this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted) {
209
+ logger_1.logger.info(`Received secure tunnel deleteAccepted: ${message}`);
210
+ await this.secureTunnelHandler.destroy();
211
+ }
212
+ else {
213
+ logger_1.logger.error(`Unexpected topic, ignoring! ${topic}`);
202
214
  }
203
215
  }
204
- // eslint-disable-next-line
205
- async atomicApplicationUpdate(func, projectId, skipUpdateShadow) {
206
- // First try to create a backup, so that there is one available if something goes wrong in the next try:catch.
207
- if (await (0, agent_config_1.AgentConfigFile)().isAppPresent({ projectId })) {
216
+ async stop() {
217
+ // This method is currently only used by the CLI, and shadow messages can be
218
+ // lost since we aren't waiting for responses so sleep for a short time to
219
+ // receive them
220
+ await (0, sleep_1.default)(1000);
221
+ this.device.end();
222
+ }
223
+ /*=================================================================
224
+ Private interface
225
+ =================================================================*/
226
+ setupHandlers() {
227
+ this.device.on('connect', (connack) => {
228
+ logger_1.logger.info('Device Agent has connected to the cloud');
229
+ // FIXME: EI-709 Skip this request for now to prevent kicking off another
230
+ // shadow update process if IoT Core disconnect occurs during app config update
231
+ //this.shadowHandler.getShadowUpdates();
232
+ void this.shadowHandler.updateSystemInfoShadow();
233
+ });
234
+ this.device.on('disconnect', () => {
235
+ logger_1.logger.warn('Device Agent has been disconnected from the cloud');
236
+ });
237
+ this.device.on('reconnect', () => {
238
+ logger_1.logger.info(`Device Agent attempting to re-connect ${new Date().toLocaleString()}`);
239
+ });
240
+ this.device.on('error', function (e) {
241
+ logger_1.logger.error(`Error connecting to cloud!\n${(0, util_1.stringifyError)(e)}`);
242
+ });
243
+ this.device.on('message', async (topic, payload) => {
208
244
  try {
209
- await (0, backup_1.createAppBackup)({ projectId });
245
+ const jsonPacket = JSON.parse(payload);
246
+ await this.handleMessage(topic, jsonPacket);
210
247
  }
211
248
  catch (e) {
212
- logger_1.logger.error(`Could not create a backup for the project: ${projectId}:\n${e.message}\n${e.stack}`);
249
+ logger_1.logger.error(`Error parsing message!\n${(0, util_1.stringifyError)(e)}`);
213
250
  }
214
- }
251
+ });
252
+ this.device.on('offline', () => {
253
+ logger_1.logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
254
+ void this.logConnectionInfo();
255
+ });
256
+ }
257
+ async logConnectionInfo() {
215
258
  try {
216
- const out = await func();
217
- if (!skipUpdateShadow)
218
- await this.shadowHandler.updateProjectShadow(projectId);
219
- return out;
259
+ /**
260
+ * We're using the 'netcat' or 'nc' command to test the connection to the IoT Core endpoint.
261
+ * This command doesn't always exit (see below), so
262
+ * we use timeout to break out of the prompt
263
+ * and catch the resulting error/parse the resulting stderr
264
+ *
265
+ * Sample command for current host and port:
266
+ * nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
267
+ *
268
+ * Sample output when port is not blocked and host is reachable:
269
+ * $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443
270
+ * Connection to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443 port [tcp/https] succeeded!
271
+ *
272
+ *
273
+ * Sample output when port is blocked (will repeatedly try until ctrl-C out):
274
+ * $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
275
+ * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
276
+ * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
277
+ * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
278
+ * ^C
279
+ *
280
+ *
281
+ * Sample command/output when the port isn't enable on that host:
282
+ * $ nc -zv -w 1 localhost 8883
283
+ * nc: connect to localhost port 8883 (tcp) failed: Connection refused
284
+ */
285
+ await exec_promise(`nc -zv -w 1 ${this.host} ${this.port}`, {
286
+ timeout: 2000
287
+ });
220
288
  }
221
- catch (errorAppUpdate) {
222
- logger_1.logger.error(`Failed to update ${projectId}:\n${JSON.stringify(errorAppUpdate)}}`);
223
- // If something goes wrong, first try to rollback
224
- try {
225
- await (0, backup_1.rollbackApp)({ projectId });
226
- logger_1.logger.error(`Application update failed, rolled back to previous version: ${errorAppUpdate}`);
289
+ catch (err) {
290
+ const output = JSON.stringify(err['stderr']);
291
+ if (output.indexOf('not known') !== -1) {
292
+ logger_1.logger.warn('Iot Core endpoint appears to be unreachable, internet connection may be unstable or the host may be down.');
227
293
  }
228
- catch (errorRollbackApp) {
229
- // and if that fails, uninstall the app as a last resort.
230
- try {
231
- await this.atomicApplicationUninstall(projectId);
232
- }
233
- catch (_a) {
234
- // atomicApplicationUninstall handles failing, so there's nothing to handle here.
235
- }
236
- logger_1.logger.error(`Application update failed, rolled back to previous version: ${errorAppUpdate}`);
237
- throw new Error(`Application update and rollback failed, uninstalled the application: ${errorAppUpdate}`);
294
+ else if (output.indexOf('timed out') !== -1) {
295
+ logger_1.logger.warn(`Internet connection appears fine, however the endpoint was not reachable on the current connection port: ${this.port}\nPlease check if a firewall is in place.`);
238
296
  }
239
- throw new Error(`Application update failed, rolled the application back: ${errorAppUpdate}`);
240
- }
241
- }
242
- async handleProjectShadowMessage(topic, message) {
243
- const shadowUpdates = await this.shadowHandler.handleProjectShadow({
244
- topic,
245
- payload: message,
246
- clientToken: message.clientToken
247
- });
248
- if (shadowUpdates.length) {
249
- const shadowUpdatePromises = [];
250
- for (const shadowUpdate of shadowUpdates) {
251
- const projectId = shadowUpdate.projectId;
252
- const txId = shadowUpdate.txId;
253
- shadowUpdatePromises.push(this.txnMgr
254
- .runTransactionStep({
255
- func: () => this.handleProjectShadowConfigUpdate(shadowUpdate, txId),
256
- projectId,
257
- txId,
258
- start: true,
259
- stepName: topic
260
- })
261
- .catch((e) => {
262
- logger_1.logger.error(`There was an issue updating project shadow config: ${JSON.stringify(e)}`);
263
- }));
297
+ else if (output.indexOf('refused') !== -1) {
298
+ logger_1.logger.warn(`The connection was refused, likely ${this.host} is not running a service on ${this.port}.`);
299
+ }
300
+ else {
301
+ logger_1.logger.warn(`Output from checking connection to ${this.host} on ${this.port}: ${output}`);
264
302
  }
265
- await Promise.all(shadowUpdatePromises);
266
- }
267
- }
268
- async handleSecureTunnelMessage(payload) {
269
- logger_1.logger.info(`Received secure tunnel update: ${JSON.stringify(payload)}`);
270
- const state = payload.state;
271
- if (!state) {
272
- logger_1.logger.debug(`No state found in message: ${JSON.stringify(payload)}`);
273
- return;
274
- }
275
- const valid = (0, device_agent_schemas_1.validateSecureTunnelShadowUpdate)(state);
276
- if (!valid) {
277
- logger_1.logger.error(`Error validating message: ${JSON.stringify({ payload, errors: device_agent_schemas_1.validateSecureTunnelShadowUpdate.errors }, null, 2)}`);
278
- return;
279
303
  }
280
- const secureTunnelUpdate = await this.secureTunnelHandler.syncShadowToDeviceState(payload);
281
- await this.shadowHandler.updateSecureTunnelShadow(secureTunnelUpdate);
282
- return;
283
- }
284
- getClientId() {
285
- return this.clientId;
286
- }
287
- getToDeviceTopic() {
288
- return this.toDeviceTopic;
289
- }
290
- isCmdInProgress(projectId) {
291
- return this.txnMgr.isOngoingTransactionForProjectID(projectId);
292
- }
293
- async updateProjectShadow(projectId) {
294
- await this.shadowHandler.updateProjectShadow(projectId);
295
304
  }
296
305
  async handleDeviceAgentMessage({ topic, message }) {
297
306
  const valid = (0, device_agent_schemas_1.validateToDeviceAgentMessage)(message);
@@ -313,11 +322,12 @@ class DeviceAgentCloudConnection {
313
322
  projectId,
314
323
  txId,
315
324
  start: true,
325
+ liveUpdatesPublishFn: async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, { status: device_agent_schemas_1.keyMirrors.statusResponse.in_progress }, txId), logger_1.logger.silly),
316
326
  stepName: payload.baseCommand
317
327
  });
318
328
  }
319
329
  catch (e) {
320
- logger_1.logger.error(`Error processing application state control request: ${e}!`);
330
+ logger_1.logger.error(`Error processing application state control request for ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
321
331
  }
322
332
  break;
323
333
  }
@@ -331,18 +341,47 @@ class DeviceAgentCloudConnection {
331
341
  projectId,
332
342
  txId,
333
343
  start: true,
344
+ liveUpdatesPublishFn: async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, { status: device_agent_schemas_1.keyMirrors.statusResponse.in_progress }, txId), logger_1.logger.silly),
334
345
  stepName: payload.baseCommand
335
346
  });
336
347
  }
337
348
  catch (e) {
338
- logger_1.logger.error(`Error processing application install request: ${e}!`);
349
+ logger_1.logger.error(`Error processing application install request for ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
339
350
  }
340
351
  break;
341
352
  }
342
353
  case live_state_updates: {
343
- const payload = message.payload;
344
- // TODO: Send response?
345
- void this.liveUpdatesHandler.handleToggles(payload, txId);
354
+ const { deviceStats, appState, appLogs } = message.payload;
355
+ if (deviceStats !== undefined) {
356
+ if (deviceStats) {
357
+ await this.liveUpdatesHandler.enable(device_agent_schemas_1.keyMirrors.toClientMessageType.device_stats, async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildDeviceStatsMessage)(this.clientId, await (0, messages_1.getDeviceStatsPayload)(), txId), logger_1.logger.silly));
358
+ }
359
+ else {
360
+ this.liveUpdatesHandler.disable(device_agent_schemas_1.keyMirrors.toClientMessageType.device_stats);
361
+ }
362
+ }
363
+ if (appState !== undefined) {
364
+ if (appState) {
365
+ await this.liveUpdatesHandler.enable(device_agent_schemas_1.keyMirrors.toClientMessageType.app_state, async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildAppStateMessage)(this.clientId, await (0, messages_1.getAppStatePayload)(), txId), logger_1.logger.silly));
366
+ }
367
+ else {
368
+ this.liveUpdatesHandler.disable(device_agent_schemas_1.keyMirrors.toClientMessageType.app_state);
369
+ }
370
+ }
371
+ if (appLogs !== undefined) {
372
+ if (appLogs.toggle) {
373
+ await this.liveUpdatesHandler.startStream(appLogs.projectId, async () => await (0, application_control_1.getAppLogs)({
374
+ projectId: appLogs.projectId,
375
+ args: ['--tail', '100', '--no-log-prefix']
376
+ }), async (logChunk) => this.publisher.publishToClient((0, device_agent_schemas_1.buildAppLogsMessage)(this.clientId, {
377
+ projectId: appLogs.projectId,
378
+ logChunk
379
+ }, txId), logger_1.logger.silly));
380
+ }
381
+ else {
382
+ this.liveUpdatesHandler.stopStream(appLogs.projectId);
383
+ }
384
+ }
346
385
  break;
347
386
  }
348
387
  case app_install_response: {
@@ -380,39 +419,29 @@ class DeviceAgentCloudConnection {
380
419
  case status_response: {
381
420
  const { failure } = device_agent_schemas_1.keyMirrors.statusResponse;
382
421
  if (message.payload.status === failure) {
383
- this.txnMgr.completeTransaction(txId);
384
- const failureStatusResponsePayload = {
422
+ this.txnMgr.completeTransaction(txId, (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, {
385
423
  status: device_agent_schemas_1.keyMirrors.statusResponse.failure,
386
424
  message: message.payload.message
387
- };
388
- // Send final status message
389
- const failureStatusResponseMessage = (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, failureStatusResponsePayload, txId);
390
- this.publisher.publishToClient(failureStatusResponseMessage);
425
+ }, txId));
391
426
  }
392
427
  break;
393
428
  }
394
429
  case device_action: {
395
430
  try {
396
- const statusResponsePayload = {
431
+ this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, {
397
432
  status: device_agent_schemas_1.keyMirrors.statusResponse.in_progress
398
- };
399
- const statusResponseMessage = (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, statusResponsePayload, txId);
400
- this.publisher.publishToClient(statusResponseMessage);
433
+ }, txId));
401
434
  await this.handleDeviceAction(message.payload);
402
- const successStatusResponsePayload = {
435
+ this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, {
403
436
  status: device_agent_schemas_1.keyMirrors.statusResponse.success
404
- };
405
- const successStatusResponseMessage = (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, successStatusResponsePayload, txId);
406
- this.publisher.publishToClient(successStatusResponseMessage);
437
+ }, txId));
407
438
  }
408
439
  catch (e) {
409
- logger_1.logger.error(`There was a problem performing device action '${message.payload.action}': ${e.message}`);
410
- const failureStatusResponsePayload = {
440
+ logger_1.logger.error(`There was a problem performing device action '${message.payload.action}'!\n${(0, util_1.stringifyError)(e)}`);
441
+ this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, {
411
442
  status: device_agent_schemas_1.keyMirrors.statusResponse.failure,
412
443
  message: e.message
413
- };
414
- const failureStatusResponseMessage = (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, failureStatusResponsePayload, txId);
415
- this.publisher.publishToClient(failureStatusResponseMessage);
444
+ }, txId));
416
445
  }
417
446
  break;
418
447
  }
@@ -420,140 +449,140 @@ class DeviceAgentCloudConnection {
420
449
  logger_1.logger.error(`Invalid client message: '${JSON.stringify({ topic, message, txId }, null, 2)}'`);
421
450
  }
422
451
  }
423
- async handleMessage(topic, message) {
424
- logger_1.logger.debug(`Received message: ${JSON.stringify({ topic, message }, null, 2)}`);
425
- // ProjectShadow messages
426
- if (this.shadowHandler.projectShadowTopics.includes(topic)) {
427
- await this.handleProjectShadowMessage(topic, message);
428
- }
429
- else if (topic === this.toDeviceTopic) {
430
- await this.handleDeviceAgentMessage({
431
- topic,
432
- message
433
- });
434
- // SecureTunnelNotify messages
435
- }
436
- else if (topic === this.secureTunnelNotifyTopic) {
437
- await this.secureTunnelHandler.secureTunnelNotifyHandler(message);
438
- // SecureTunnel messages
439
- }
440
- else if (topic === this.shadowHandler.shadowTopics.secureTunnel.updateDelta) {
441
- await this.handleSecureTunnelMessage(message);
452
+ async handleDeviceAction(payload) {
453
+ const { system_restart } = device_agent_schemas_1.keyMirrors.deviceAction;
454
+ switch (payload.action) {
455
+ case system_restart: {
456
+ await (0, device_control_1.reboot)();
457
+ break;
458
+ }
459
+ default: {
460
+ logger_1.logger.info(`Unrecognized device action requested: '${payload.action}'.`);
461
+ }
442
462
  }
443
- else if (topic === this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted) {
444
- logger_1.logger.info(`Received secure tunnel deleteAccepted: ${message}`);
445
- await this.secureTunnelHandler.destroy();
463
+ }
464
+ async publishCloudRequest(message) {
465
+ this.publisher.publishToCloud(message);
466
+ }
467
+ subscribe(topic) {
468
+ logger_1.logger.info(`Subscribing to ${topic}`);
469
+ this.device.subscribe(topic);
470
+ }
471
+ async atomicApplicationUninstall(projectId) {
472
+ try {
473
+ await (0, application_control_1.uninstallApp)({ projectId });
474
+ this.shadowHandler.clearProjectShadow(projectId);
446
475
  }
447
- else {
448
- logger_1.logger.error(`Unexpected topic, ignoring! ${topic}`);
476
+ catch (e) {
477
+ logger_1.logger.error(`Failed to uninstall ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
478
+ throw e;
449
479
  }
450
480
  }
451
- async setupHandlers() {
452
- this.device.on('connect', (connack) => {
453
- logger_1.logger.info('Device Agent has connected to the cloud');
454
- // FIXME: EI-709 Skip this request for now to prevent kicking off another
455
- // shadow update process if IoT Core disconnect occurs during app config update
456
- //this.shadowHandler.getShadowUpdates();
457
- void this.shadowHandler.updateSystemInfoShadow();
458
- });
459
- this.device.on('disconnect', () => {
460
- logger_1.logger.warn('Device Agent has been disconnected from the cloud');
461
- });
462
- this.device.on('reconnect', () => {
463
- logger_1.logger.info(`Device Agent attempting to re-connect ${new Date().toLocaleString()}`);
464
- });
465
- this.device.on('error', function (error) {
466
- const errorString = error.message.toString();
467
- logger_1.logger.error(`${errorString}`);
468
- });
469
- this.device.on('message', async (topic, payload) => {
481
+ // eslint-disable-next-line
482
+ async atomicApplicationUpdate(func, projectId, skipUpdateShadow) {
483
+ if (await (0, agent_config_1.AgentConfigFile)().isAppPresent({ projectId })) {
484
+ // Reject the application update if app is present but not ready
485
+ if (!(await (0, agent_config_1.AgentConfigFile)().isAppReady({ projectId }))) {
486
+ throw new Error('Application already has installation in progress!');
487
+ }
488
+ // Try to create a backup, so that there is one available if something goes wrong in the next try:catch.
470
489
  try {
471
- const jsonPacket = JSON.parse(payload);
472
- await this.handleMessage(topic, jsonPacket);
490
+ await (0, backup_1.createAppBackup)({ projectId });
473
491
  }
474
492
  catch (e) {
475
- logger_1.logger.error(`Error parsing message: ${e.message}`);
493
+ logger_1.logger.error(`Could not create a backup for the project: ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
476
494
  }
477
- });
478
- this.device.on('offline', () => {
479
- logger_1.logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
480
- void this.logConnectionInfo();
481
- });
482
- }
483
- async logConnectionInfo() {
495
+ }
484
496
  try {
485
- /**
486
- * We're using the 'netcat' or 'nc' command to test the connection to the IoT Core endpoint.
487
- * This command doesn't always exit (see below), so
488
- * we use timeout to break out of the prompt
489
- * and catch the resulting error/parse the resulting stderr
490
- *
491
- * Sample command for current host and port:
492
- * nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
493
- *
494
- * Sample output when port is not blocked and host is reachable:
495
- * $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443
496
- * Connection to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443 port [tcp/https] succeeded!
497
- *
498
- *
499
- * Sample output when port is blocked (will repeatedly try until ctrl-C out):
500
- * $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
501
- * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
502
- * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
503
- * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
504
- * ^C
505
- *
506
- *
507
- * Sample command/output when the port isn't enable on that host:
508
- * $ nc -zv -w 1 localhost 8883
509
- * nc: connect to localhost port 8883 (tcp) failed: Connection refused
510
- */
511
- await exec_promise(`nc -zv -w 1 ${this.host} ${this.port}`, {
512
- timeout: 2000
513
- });
497
+ const out = await func();
498
+ if (!skipUpdateShadow)
499
+ await this.shadowHandler.updateProjectShadow(projectId);
500
+ return out;
514
501
  }
515
- catch (err) {
516
- const output = JSON.stringify(err['stderr']);
517
- if (output.indexOf('not known') !== -1) {
518
- logger_1.logger.warn('Iot Core endpoint appears to be unreachable, internet connection may be unstable or the host may be down.');
519
- }
520
- else if (output.indexOf('timed out') !== -1) {
521
- logger_1.logger.warn(`Internet connection appears fine, however the endpoint was not reachable on the current connection port: ${this.port}\nPlease check if a firewall is in place.`);
502
+ catch (errorAppUpdate) {
503
+ logger_1.logger.error(`Failed to update ${projectId}!\n${(0, util_1.stringifyError)(errorAppUpdate)}`);
504
+ // If something goes wrong, first try to rollback
505
+ try {
506
+ await (0, backup_1.rollbackApp)({ projectId });
522
507
  }
523
- else if (output.indexOf('refused') !== -1) {
524
- logger_1.logger.warn(`The connection was refused, likely ${this.host} is not running a service on ${this.port}.`);
508
+ catch (errorRollbackApp) {
509
+ logger_1.logger.error(`Application rollback failed for ${projectId}!\n${(0, util_1.stringifyError)(errorRollbackApp)}`);
510
+ // and if that fails, uninstall the app as a last resort.
511
+ try {
512
+ await this.atomicApplicationUninstall(projectId);
513
+ }
514
+ catch (_a) {
515
+ // atomicApplicationUninstall logs failure, so there's nothing to do here.
516
+ }
517
+ throw new aai_error_1.default('Application update and rollback failed, uninstalled the application!', { cause: errorAppUpdate });
525
518
  }
526
- else {
527
- logger_1.logger.warn(`Output from checking connection to ${this.host} on ${this.port}: ${output}`);
519
+ throw new Error('Application update failed, rolled the application back!', { cause: errorAppUpdate });
520
+ }
521
+ }
522
+ async handleProjectShadowMessage(topic, message) {
523
+ const shadowUpdates = await this.shadowHandler.handleProjectShadow({
524
+ topic,
525
+ payload: message,
526
+ clientToken: message.clientToken
527
+ });
528
+ if (shadowUpdates.length) {
529
+ const shadowUpdatePromises = [];
530
+ for (const shadowUpdate of shadowUpdates) {
531
+ const projectId = shadowUpdate.projectId;
532
+ const txId = shadowUpdate.txId;
533
+ shadowUpdatePromises.push(this.txnMgr
534
+ .runTransactionStep({
535
+ func: () => this.handleProjectShadowConfigUpdate(shadowUpdate, txId),
536
+ projectId,
537
+ txId,
538
+ start: true,
539
+ liveUpdatesPublishFn: async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, { status: device_agent_schemas_1.keyMirrors.statusResponse.in_progress }, txId), logger_1.logger.silly),
540
+ stepName: topic
541
+ })
542
+ .catch((e) => {
543
+ logger_1.logger.error(`There was an issue updating project shadow config for ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
544
+ }));
528
545
  }
546
+ await Promise.all(shadowUpdatePromises);
529
547
  }
530
548
  }
531
- async stop() {
532
- // This method is currently only used by the CLI, and shadow messages can be
533
- // lost since we aren't waiting for responses so sleep for a short time to
534
- // receive them
535
- await (0, sleep_1.default)(1000);
536
- this.device.end();
549
+ async handleSecureTunnelMessage(payload) {
550
+ logger_1.logger.info(`Received secure tunnel update: ${JSON.stringify(payload)}`);
551
+ const state = (0, device_agent_schemas_1.getUpdateDeltaStateFromMessage)(payload);
552
+ if (!state) {
553
+ logger_1.logger.debug(`No state found in message: ${JSON.stringify(payload)}`);
554
+ return;
555
+ }
556
+ const valid = (0, device_agent_schemas_1.validateSecureTunnelShadowUpdate)(state);
557
+ if (!valid) {
558
+ logger_1.logger.error(`Error validating message: ${JSON.stringify({ payload, errors: device_agent_schemas_1.validateSecureTunnelShadowUpdate.errors }, null, 2)}`);
559
+ return;
560
+ }
561
+ const secureTunnelUpdate = await this.secureTunnelHandler.syncShadowToDeviceState(payload);
562
+ await this.shadowHandler.updateSecureTunnelShadow(secureTunnelUpdate);
537
563
  }
538
564
  }
539
565
  exports.DeviceAgentCloudConnection = DeviceAgentCloudConnection;
540
566
  async function runDeviceAgentCloudInterface() {
541
567
  logger_1.logger.info(`Starting alwaysAI Device Agent v${await (0, check_for_updates_1.getDeviceAgentVersion)()}`);
542
- if ((0, cloud_mode_ready_1.cloudModeReady)()) {
568
+ if ((0, fs_1.existsSync)((0, device_certificate_1.getBootstrapPrivateKeyFilePath)())) {
569
+ await (0, bootstrap_provision_1.bootstrapProvision)();
570
+ return;
571
+ }
572
+ const filesAlreadyMigrated = await (0, required_config_checks_1.requiredConfigFilesPresentAndValid)();
573
+ if (!filesAlreadyMigrated) {
574
+ logger_1.logger.debug('Attempting configuration file migration.');
575
+ await (0, legacy_migration_1.migrateFromLegacyCertsAndTokens)();
576
+ }
577
+ if (await (0, required_config_checks_1.requiredConfigFilesPresentAndValid)()) {
543
578
  const deviceAgent = new DeviceAgentCloudConnection();
544
- await deviceAgent.setupHandlers();
545
579
  if (environment_1.ALWAYSAI_ANALYTICS_PASSTHROUGH === true) {
580
+ const shadowHandler = deviceAgent.shadowHandler;
546
581
  const publisher = deviceAgent.publisher;
547
- const passthroughHandler = new passthrough_handler_1.PassthroughHandler(publisher);
582
+ const passthroughHandler = new passthrough_handler_1.PassthroughHandler(publisher, shadowHandler);
548
583
  await passthroughHandler.setup();
549
584
  }
550
585
  }
551
- else if ((0, fs_1.existsSync)((0, directories_1.BOOTSTRAP_PRIVATE_KEY_FILE_PATH)())) {
552
- await (0, bootstrap_provision_1.bootstrapProvision)();
553
- }
554
- else if ((0, fs_1.existsSync)((0, directories_1.BOOTSTRAP_CERTIFICATES_DIR_PATH)())) {
555
- throw new Error("Device has not been created using 'aai-agent device init' or there has been an issue with device initialization");
556
- }
557
586
  else {
558
587
  throw new Error("Set device agent to local mode and retry the 'aai-agent device init' command");
559
588
  }