@alwaysai/device-agent 1.5.0 → 2.0.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 (305) 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 +5 -5
  5. package/lib/application-control/environment-variables.d.ts.map +1 -1
  6. package/lib/application-control/environment-variables.js +25 -38
  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 +4 -1
  15. package/lib/application-control/install.d.ts.map +1 -1
  16. package/lib/application-control/install.js +24 -8
  17. package/lib/application-control/install.js.map +1 -1
  18. package/lib/application-control/models.d.ts +0 -11
  19. package/lib/application-control/models.d.ts.map +1 -1
  20. package/lib/application-control/models.js +5 -54
  21. package/lib/application-control/models.js.map +1 -1
  22. package/lib/application-control/utils.d.ts +0 -4
  23. package/lib/application-control/utils.d.ts.map +1 -1
  24. package/lib/application-control/utils.js +12 -22
  25. package/lib/application-control/utils.js.map +1 -1
  26. package/lib/cloud-connection/base-message-handler.d.ts +27 -0
  27. package/lib/cloud-connection/base-message-handler.d.ts.map +1 -0
  28. package/lib/cloud-connection/base-message-handler.js +72 -0
  29. package/lib/cloud-connection/base-message-handler.js.map +1 -0
  30. package/lib/cloud-connection/bootstrap-provision.js +3 -2
  31. package/lib/cloud-connection/bootstrap-provision.js.map +1 -1
  32. package/lib/cloud-connection/connection-manager.d.ts +21 -0
  33. package/lib/cloud-connection/connection-manager.d.ts.map +1 -0
  34. package/lib/cloud-connection/connection-manager.js +158 -0
  35. package/lib/cloud-connection/connection-manager.js.map +1 -0
  36. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +9 -30
  37. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  38. package/lib/cloud-connection/device-agent-cloud-connection.js +69 -508
  39. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  40. package/lib/cloud-connection/device-agent-message-handler.d.ts +22 -0
  41. package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -0
  42. package/lib/cloud-connection/device-agent-message-handler.js +357 -0
  43. package/lib/cloud-connection/device-agent-message-handler.js.map +1 -0
  44. package/lib/cloud-connection/device-agent.d.ts.map +1 -1
  45. package/lib/cloud-connection/device-agent.js +11 -9
  46. package/lib/cloud-connection/device-agent.js.map +1 -1
  47. package/lib/cloud-connection/live-updates-handler.d.ts +19 -28
  48. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  49. package/lib/cloud-connection/live-updates-handler.js +60 -172
  50. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  51. package/lib/cloud-connection/live-updates-handler.test.js +71 -165
  52. package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
  53. package/lib/cloud-connection/message-dispatcher.d.ts +10 -0
  54. package/lib/cloud-connection/message-dispatcher.d.ts.map +1 -0
  55. package/lib/cloud-connection/message-dispatcher.js +27 -0
  56. package/lib/cloud-connection/message-dispatcher.js.map +1 -0
  57. package/lib/cloud-connection/passthrough-handler.d.ts +4 -1
  58. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
  59. package/lib/cloud-connection/passthrough-handler.js +30 -11
  60. package/lib/cloud-connection/passthrough-handler.js.map +1 -1
  61. package/lib/cloud-connection/shadow-handler.d.ts +11 -3
  62. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  63. package/lib/cloud-connection/shadow-handler.js +133 -28
  64. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  65. package/lib/cloud-connection/shadow-handler.test.js +45 -57
  66. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  67. package/lib/cloud-connection/shadow.d.ts.map +1 -1
  68. package/lib/cloud-connection/shadow.js +2 -1
  69. package/lib/cloud-connection/shadow.js.map +1 -1
  70. package/lib/cloud-connection/transaction-manager.d.ts +12 -3
  71. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  72. package/lib/cloud-connection/transaction-manager.js +29 -28
  73. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  74. package/lib/cloud-connection/transaction-manager.test.js +46 -5
  75. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  76. package/lib/device-control/device-control.d.ts +8 -8
  77. package/lib/device-control/device-control.d.ts.map +1 -1
  78. package/lib/device-control/device-control.js +95 -71
  79. package/lib/device-control/device-control.js.map +1 -1
  80. package/lib/docker/docker-compose.d.ts.map +1 -1
  81. package/lib/docker/docker-compose.js +2 -1
  82. package/lib/docker/docker-compose.js.map +1 -1
  83. package/lib/infrastructure/agent-config.d.ts +2 -1
  84. package/lib/infrastructure/agent-config.d.ts.map +1 -1
  85. package/lib/infrastructure/agent-config.js +7 -7
  86. package/lib/infrastructure/agent-config.js.map +1 -1
  87. package/lib/infrastructure/agent-config.test.js +3 -1
  88. package/lib/infrastructure/agent-config.test.js.map +1 -1
  89. package/lib/infrastructure/config-check-utility.d.ts +6 -0
  90. package/lib/infrastructure/config-check-utility.d.ts.map +1 -0
  91. package/lib/infrastructure/config-check-utility.js +67 -0
  92. package/lib/infrastructure/config-check-utility.js.map +1 -0
  93. package/lib/infrastructure/config-check-utility.test.d.ts +2 -0
  94. package/lib/infrastructure/config-check-utility.test.d.ts.map +1 -0
  95. package/lib/infrastructure/config-check-utility.test.js +109 -0
  96. package/lib/infrastructure/config-check-utility.test.js.map +1 -0
  97. package/lib/infrastructure/device-certificate.d.ts +10 -0
  98. package/lib/infrastructure/device-certificate.d.ts.map +1 -0
  99. package/lib/infrastructure/device-certificate.js +47 -0
  100. package/lib/infrastructure/device-certificate.js.map +1 -0
  101. package/lib/infrastructure/device-certificate.test.d.ts +2 -0
  102. package/lib/infrastructure/device-certificate.test.d.ts.map +1 -0
  103. package/lib/infrastructure/device-certificate.test.js +24 -0
  104. package/lib/infrastructure/device-certificate.test.js.map +1 -0
  105. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts +2 -0
  106. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts.map +1 -0
  107. package/lib/infrastructure/legacy-migration/legacy-file.test.js +61 -0
  108. package/lib/infrastructure/legacy-migration/legacy-file.test.js.map +1 -0
  109. package/lib/infrastructure/legacy-migration/legacy-files.d.ts +75 -0
  110. package/lib/infrastructure/legacy-migration/legacy-files.d.ts.map +1 -0
  111. package/lib/infrastructure/legacy-migration/legacy-files.js +75 -0
  112. package/lib/infrastructure/legacy-migration/legacy-files.js.map +1 -0
  113. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts +6 -0
  114. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -0
  115. package/lib/infrastructure/legacy-migration/legacy-migration.js +149 -0
  116. package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -0
  117. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts +2 -0
  118. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts.map +1 -0
  119. package/lib/infrastructure/legacy-migration/legacy-migration.test.js +226 -0
  120. package/lib/infrastructure/legacy-migration/legacy-migration.test.js.map +1 -0
  121. package/lib/infrastructure/require-files-present-ready.test.d.ts +2 -0
  122. package/lib/infrastructure/require-files-present-ready.test.d.ts.map +1 -0
  123. package/lib/infrastructure/require-files-present-ready.test.js +44 -0
  124. package/lib/infrastructure/require-files-present-ready.test.js.map +1 -0
  125. package/lib/infrastructure/required-config-checks.d.ts +2 -0
  126. package/lib/infrastructure/required-config-checks.d.ts.map +1 -0
  127. package/lib/infrastructure/required-config-checks.js +30 -0
  128. package/lib/infrastructure/required-config-checks.js.map +1 -0
  129. package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -1
  130. package/lib/infrastructure/tokens-and-device-cfg.js +11 -8
  131. package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -1
  132. package/lib/jobs/job-handler.d.ts +23 -0
  133. package/lib/jobs/job-handler.d.ts.map +1 -0
  134. package/lib/jobs/job-handler.js +131 -0
  135. package/lib/jobs/job-handler.js.map +1 -0
  136. package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -1
  137. package/lib/local-connection/rabbitmq-connection.js +14 -14
  138. package/lib/local-connection/rabbitmq-connection.js.map +1 -1
  139. package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts +8 -0
  140. package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts.map +1 -0
  141. package/lib/secure-tunneling/secure-tunnel-message-handler.js +42 -0
  142. package/lib/secure-tunneling/secure-tunnel-message-handler.js.map +1 -0
  143. package/lib/secure-tunneling/secure-tunneling.d.ts +9 -9
  144. package/lib/secure-tunneling/secure-tunneling.d.ts.map +1 -1
  145. package/lib/secure-tunneling/secure-tunneling.js +21 -16
  146. package/lib/secure-tunneling/secure-tunneling.js.map +1 -1
  147. package/lib/secure-tunneling/secure-tunneling.test.js +11 -13
  148. package/lib/secure-tunneling/secure-tunneling.test.js.map +1 -1
  149. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  150. package/lib/subcommands/app/analytics.js +1 -2
  151. package/lib/subcommands/app/analytics.js.map +1 -1
  152. package/lib/subcommands/app/env-vars.d.ts +4 -0
  153. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  154. package/lib/subcommands/app/env-vars.js +52 -6
  155. package/lib/subcommands/app/env-vars.js.map +1 -1
  156. package/lib/subcommands/app/index.d.ts.map +1 -1
  157. package/lib/subcommands/app/index.js +1 -3
  158. package/lib/subcommands/app/index.js.map +1 -1
  159. package/lib/subcommands/app/models.d.ts +0 -11
  160. package/lib/subcommands/app/models.d.ts.map +1 -1
  161. package/lib/subcommands/app/models.js +2 -58
  162. package/lib/subcommands/app/models.js.map +1 -1
  163. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  164. package/lib/subcommands/app/shadow.js +6 -5
  165. package/lib/subcommands/app/shadow.js.map +1 -1
  166. package/lib/subcommands/app/version.d.ts +2 -0
  167. package/lib/subcommands/app/version.d.ts.map +1 -1
  168. package/lib/subcommands/app/version.js +16 -6
  169. package/lib/subcommands/app/version.js.map +1 -1
  170. package/lib/subcommands/config.d.ts +2 -0
  171. package/lib/subcommands/config.d.ts.map +1 -0
  172. package/lib/subcommands/config.js +39 -0
  173. package/lib/subcommands/config.js.map +1 -0
  174. package/lib/subcommands/device/clean.d.ts +1 -1
  175. package/lib/subcommands/device/clean.d.ts.map +1 -1
  176. package/lib/subcommands/device/clean.js +23 -13
  177. package/lib/subcommands/device/clean.js.map +1 -1
  178. package/lib/subcommands/device/index.d.ts.map +1 -1
  179. package/lib/subcommands/device/index.js +3 -1
  180. package/lib/subcommands/device/index.js.map +1 -1
  181. package/lib/subcommands/device/init.js +8 -8
  182. package/lib/subcommands/device/init.js.map +1 -1
  183. package/lib/subcommands/device/migrate.d.ts +2 -0
  184. package/lib/subcommands/device/migrate.d.ts.map +1 -0
  185. package/lib/subcommands/device/migrate.js +24 -0
  186. package/lib/subcommands/device/migrate.js.map +1 -0
  187. package/lib/subcommands/device/refresh.d.ts.map +1 -1
  188. package/lib/subcommands/device/refresh.js +1 -0
  189. package/lib/subcommands/device/refresh.js.map +1 -1
  190. package/lib/subcommands/index.d.ts +1 -1
  191. package/lib/subcommands/index.d.ts.map +1 -1
  192. package/lib/subcommands/index.js +3 -1
  193. package/lib/subcommands/index.js.map +1 -1
  194. package/lib/subcommands/rabbitmq-connection.d.ts +1 -1
  195. package/lib/subcommands/rabbitmq-connection.d.ts.map +1 -1
  196. package/lib/util/aai-error.d.ts +12 -0
  197. package/lib/util/aai-error.d.ts.map +1 -0
  198. package/lib/util/aai-error.js +11 -0
  199. package/lib/util/aai-error.js.map +1 -0
  200. package/lib/util/aws-regions.d.ts +2 -0
  201. package/lib/util/aws-regions.d.ts.map +1 -0
  202. package/lib/util/{cloud-mode-ready.js → aws-regions.js} +2 -20
  203. package/lib/util/aws-regions.js.map +1 -0
  204. package/lib/util/check-for-updates.d.ts.map +1 -1
  205. package/lib/util/check-for-updates.js +5 -28
  206. package/lib/util/check-for-updates.js.map +1 -1
  207. package/lib/util/clean-certs.d.ts.map +1 -1
  208. package/lib/util/clean-certs.js +5 -4
  209. package/lib/util/clean-certs.js.map +1 -1
  210. package/lib/util/directories.d.ts +4 -18
  211. package/lib/util/directories.d.ts.map +1 -1
  212. package/lib/util/directories.js +18 -32
  213. package/lib/util/directories.js.map +1 -1
  214. package/lib/util/file.d.ts +4 -0
  215. package/lib/util/file.d.ts.map +1 -1
  216. package/lib/util/file.js +65 -4
  217. package/lib/util/file.js.map +1 -1
  218. package/lib/util/get-device-id.d.ts.map +1 -1
  219. package/lib/util/get-device-id.js +7 -1
  220. package/lib/util/get-device-id.js.map +1 -1
  221. package/lib/util/http-client.js +3 -3
  222. package/lib/util/http-client.js.map +1 -1
  223. package/package.json +19 -17
  224. package/readme.md +12 -32
  225. package/src/application-control/config.ts +9 -12
  226. package/src/application-control/environment-variables.test.ts +28 -7
  227. package/src/application-control/environment-variables.ts +42 -59
  228. package/src/application-control/index.ts +3 -16
  229. package/src/application-control/install.ts +39 -13
  230. package/src/application-control/models.ts +6 -87
  231. package/src/application-control/utils.ts +10 -25
  232. package/src/cloud-connection/base-message-handler.ts +118 -0
  233. package/src/cloud-connection/bootstrap-provision.ts +7 -7
  234. package/src/cloud-connection/connection-manager.ts +187 -0
  235. package/src/cloud-connection/device-agent-cloud-connection.ts +130 -723
  236. package/src/cloud-connection/device-agent-message-handler.ts +642 -0
  237. package/src/cloud-connection/device-agent.ts +16 -7
  238. package/src/cloud-connection/live-updates-handler.test.ts +121 -189
  239. package/src/cloud-connection/live-updates-handler.ts +105 -232
  240. package/src/cloud-connection/message-dispatcher.ts +33 -0
  241. package/src/cloud-connection/passthrough-handler.ts +55 -18
  242. package/src/cloud-connection/shadow-handler.test.ts +45 -57
  243. package/src/cloud-connection/shadow-handler.ts +224 -54
  244. package/src/cloud-connection/shadow.ts +4 -1
  245. package/src/cloud-connection/transaction-manager.test.ts +68 -6
  246. package/src/cloud-connection/transaction-manager.ts +69 -41
  247. package/src/device-control/device-control.ts +102 -70
  248. package/src/docker/docker-compose.ts +3 -2
  249. package/src/infrastructure/agent-config.test.ts +6 -2
  250. package/src/infrastructure/agent-config.ts +8 -7
  251. package/src/infrastructure/config-check-utility.test.ts +154 -0
  252. package/src/infrastructure/config-check-utility.ts +77 -0
  253. package/src/infrastructure/device-certificate.test.ts +40 -0
  254. package/src/infrastructure/device-certificate.ts +58 -0
  255. package/src/infrastructure/legacy-migration/legacy-file.test.ts +88 -0
  256. package/src/infrastructure/legacy-migration/legacy-files.ts +101 -0
  257. package/src/infrastructure/legacy-migration/legacy-migration.test.ts +396 -0
  258. package/src/infrastructure/legacy-migration/legacy-migration.ts +229 -0
  259. package/src/infrastructure/require-files-present-ready.test.ts +53 -0
  260. package/src/infrastructure/required-config-checks.ts +33 -0
  261. package/src/infrastructure/tokens-and-device-cfg.ts +12 -10
  262. package/src/jobs/job-handler.ts +146 -0
  263. package/src/local-connection/rabbitmq-connection.ts +22 -17
  264. package/src/secure-tunneling/secure-tunnel-message-handler.ts +56 -0
  265. package/src/secure-tunneling/secure-tunneling.test.ts +20 -22
  266. package/src/secure-tunneling/secure-tunneling.ts +41 -29
  267. package/src/subcommands/app/analytics.ts +2 -4
  268. package/src/subcommands/app/env-vars.ts +72 -9
  269. package/src/subcommands/app/index.ts +3 -11
  270. package/src/subcommands/app/models.ts +5 -81
  271. package/src/subcommands/app/shadow.ts +6 -5
  272. package/src/subcommands/app/version.ts +23 -6
  273. package/src/subcommands/config.ts +42 -0
  274. package/src/subcommands/device/clean.ts +31 -17
  275. package/src/subcommands/device/index.ts +3 -1
  276. package/src/subcommands/device/init.ts +11 -11
  277. package/src/subcommands/device/migrate.ts +20 -0
  278. package/src/subcommands/device/refresh.ts +1 -0
  279. package/src/subcommands/index.ts +3 -1
  280. package/src/util/aai-error.ts +20 -0
  281. package/src/util/{cloud-mode-ready.ts → aws-regions.ts} +0 -24
  282. package/src/util/check-for-updates.ts +14 -30
  283. package/src/util/clean-certs.ts +8 -4
  284. package/src/util/directories.ts +23 -67
  285. package/src/util/file.ts +83 -3
  286. package/src/util/get-device-id.ts +7 -7
  287. package/src/util/http-client.ts +2 -2
  288. package/lib/util/cloud-mode-ready.d.ts +0 -3
  289. package/lib/util/cloud-mode-ready.d.ts.map +0 -1
  290. package/lib/util/cloud-mode-ready.js.map +0 -1
  291. package/lib/util/download-file.d.ts +0 -6
  292. package/lib/util/download-file.d.ts.map +0 -1
  293. package/lib/util/download-file.js +0 -25
  294. package/lib/util/download-file.js.map +0 -1
  295. package/lib/util/fetch-with-timeout.d.ts +0 -4
  296. package/lib/util/fetch-with-timeout.d.ts.map +0 -1
  297. package/lib/util/fetch-with-timeout.js +0 -30
  298. package/lib/util/fetch-with-timeout.js.map +0 -1
  299. package/lib/util/parsing.d.ts +0 -2
  300. package/lib/util/parsing.d.ts.map +0 -1
  301. package/lib/util/parsing.js +0 -17
  302. package/lib/util/parsing.js.map +0 -1
  303. package/src/util/download-file.ts +0 -25
  304. package/src/util/fetch-with-timeout.ts +0 -35
  305. package/src/util/parsing.ts +0 -11
@@ -1,47 +1,17 @@
1
- // eslint-disable-next-line
2
- const awsIot = require('aws-iot-device-sdk');
3
1
  import {
4
- AppInstallResponsePayload,
5
- AppStateControlPayload,
6
- AppVersionControlInstallPayload,
7
- AppVersionControlUninstallPayload,
8
- DeviceActionPayload,
9
- ModelsInstallResponsePayload,
10
- SignedUrlsRequestPayload,
11
- ToCloudMessage,
12
- ToDeviceAgentMessage,
13
- getToDeviceTopic,
14
- buildSignedUrlsRequestMessage,
15
2
  buildToClientStatusResponseMessage,
16
- StatusResponsePayload,
17
- keyMirrors,
18
- validateToDeviceAgentMessage,
19
- validateSecureTunnelShadowUpdate
3
+ getToDeviceTopic,
4
+ keyMirrors
20
5
  } from '@alwaysai/device-agent-schemas';
21
6
  import { existsSync } from 'fs';
22
- import {
23
- installApp,
24
- restartApp,
25
- startApp,
26
- stopApp,
27
- uninstallApp,
28
- updateAppCfg,
29
- updateModelsWithPresignedUrls
30
- } from '../application-control';
31
- import { createAppBackup, rollbackApp } from '../application-control/backup';
32
- import { reboot } from '../device-control/device-control';
33
7
  import { ALWAYSAI_ANALYTICS_PASSTHROUGH } from '../environment';
34
- import { AgentConfigFile } from '../infrastructure/agent-config';
8
+ import { getBootstrapPrivateKeyFilePath } from '../infrastructure/device-certificate';
9
+ import { migrateFromLegacyCertsAndTokens } from '../infrastructure/legacy-migration/legacy-migration';
10
+ import { requiredConfigFilesPresentAndValid } from '../infrastructure/required-config-checks';
35
11
  import { getIoTCoreEndpointUrl } from '../infrastructure/urls';
36
12
  import { SecureTunnelHandlerSingleton } from '../secure-tunneling/secure-tunneling';
37
- import { cloudModeReady } from '../util/cloud-mode-ready';
38
- import {
39
- AWS_ROOT_CERTIFICATE_FILE_PATH,
40
- BOOTSTRAP_CERTIFICATES_DIR_PATH,
41
- BOOTSTRAP_PRIVATE_KEY_FILE_PATH,
42
- DEVICE_CERTIFICATE_FILE_PATH,
43
- DEVICE_PRIVATE_KEY_FILE_PATH
44
- } from '../util/directories';
13
+ import { SecureTunnelMessageHandler } from '../secure-tunneling/secure-tunnel-message-handler';
14
+ import { getDeviceAgentVersion } from '../util/check-for-updates';
45
15
  import { getDeviceUuid } from '../util/get-device-id';
46
16
  import { logger } from '../util/logger';
47
17
  import sleep from '../util/sleep';
@@ -49,716 +19,142 @@ import { bootstrapProvision } from './bootstrap-provision';
49
19
  import { LiveUpdatesHandler } from './live-updates-handler';
50
20
  import { PassthroughHandler } from './passthrough-handler';
51
21
  import { Publisher } from './publisher';
52
- import { ShadowHandler, ShadowUpdate } from './shadow-handler';
22
+ import { ShadowHandler, ProjectShadowMessageHandler } from './shadow-handler';
23
+ import { JobHandler } from '../jobs/job-handler';
53
24
  import { TransactionManager } from './transaction-manager';
54
- import { exec } from 'child_process';
55
- import { promisify } from 'util';
56
- import { pruneModels } from '../application-control/models';
57
- import { getDeviceAgentVersion } from '../util/check-for-updates';
58
-
59
- const exec_promise = promisify(exec);
25
+ import { ConnectionManager } from './connection-manager';
26
+ import { DeviceAgentMessageHandler } from './device-agent-message-handler';
27
+ import { HandlerContext } from './base-message-handler';
60
28
 
61
29
  export class DeviceAgentCloudConnection {
62
- private shadowHandler: ShadowHandler;
63
- public publisher: Publisher;
30
+ private connectionManager: ConnectionManager;
31
+ private transactionManager: TransactionManager;
64
32
  private liveUpdatesHandler: LiveUpdatesHandler;
65
- private txnMgr: TransactionManager;
66
- private device = awsIot.device;
33
+ public shadowHandler: ShadowHandler;
34
+ public publisher: Publisher;
67
35
 
68
- private clientId = getDeviceUuid();
69
- private host = getIoTCoreEndpointUrl();
70
- private port = 8883;
36
+ private readonly clientId = getDeviceUuid();
37
+ private readonly host = getIoTCoreEndpointUrl();
38
+ private readonly port = 8883;
71
39
  private readonly toDeviceTopic = getToDeviceTopic(this.clientId);
72
- private readonly secureTunnelNotifyTopic = `$aws/things/${this.clientId}/tunnels/notify`;
73
40
  private readonly secureTunnelHandler =
74
41
  SecureTunnelHandlerSingleton.getInstance();
75
42
 
76
- private handleAppStateControl = async (
77
- payload: AppStateControlPayload
78
- ): Promise<boolean> => {
79
- const { baseCommand, projectId } = payload;
80
- switch (baseCommand) {
81
- case keyMirrors.appStateControl.start:
82
- await startApp({ projectId });
83
- break;
84
- case keyMirrors.appStateControl.stop:
85
- await stopApp({ projectId });
86
- break;
87
- case keyMirrors.appStateControl.restart:
88
- await restartApp({ projectId });
89
- break;
90
- }
91
- return true;
92
- };
93
-
94
- private handleAppVersionControl = async (
95
- payload:
96
- | AppVersionControlInstallPayload
97
- | AppVersionControlUninstallPayload,
98
- txId: string
99
- ): Promise<boolean> => {
100
- switch (payload.baseCommand) {
101
- case keyMirrors.appVersionControl.install: {
102
- const { projectId, appReleaseHash } = payload;
103
-
104
- const signedUrlsRequestPayload: SignedUrlsRequestPayload = {
105
- signedUrlsRequest: {
106
- projectId,
107
- appReleaseHash
108
- }
109
- };
110
- const message = buildSignedUrlsRequestMessage(
111
- this.clientId,
112
- signedUrlsRequestPayload,
113
- txId
114
- );
115
- await this.publishCloudRequest(message);
116
- return false;
117
- }
118
- case keyMirrors.appVersionControl.uninstall: {
119
- const { projectId } = payload;
120
- await this.atomicApplicationUninstall(projectId);
121
- return true;
122
- }
123
- default:
124
- logger.warn(
125
- `Ignore App Version Control packet: ${JSON.stringify(
126
- payload,
127
- null,
128
- 2
129
- )}`
130
- );
131
- return true;
132
- }
133
- };
134
-
135
- private handleAppInstallCloudResponsePayload = async (
136
- payload: AppInstallResponsePayload
137
- ): Promise<boolean> => {
138
- const {
139
- projectId,
140
- appReleaseHash,
141
- appInstallPayload,
142
- modelsInstallPayload
143
- } = payload.appInstallResponse;
144
- const signedUrlsPayload = {
145
- appInstallPayload,
146
- modelsInstallPayload
147
- };
148
- await this.atomicApplicationUpdate(async () => {
149
- this.shadowHandler.clearProjectShadow(projectId);
150
- await installApp({ projectId, appReleaseHash, signedUrlsPayload });
151
- }, projectId);
152
- return true;
153
- };
154
-
155
- private handleModelsInstallCloudResponsePayload = async (
156
- payload: ModelsInstallResponsePayload,
157
- txId: string
158
- ): Promise<boolean> => {
159
- const projectId = payload.modelsInstallResponse.projectId;
160
-
161
- const update = this.txnMgr.getAppCfgUpdateFromTxID(txId);
162
- if (update === undefined) {
163
- throw new Error(
164
- 'Unknown error while updating models via application config! No config present for model update.'
165
- );
166
- }
167
- const { appCfgUpdate, envVarUpdate } = update;
168
- if (appCfgUpdate) {
169
- await this.atomicApplicationUpdate(
170
- async () =>
171
- await updateModelsWithPresignedUrls({
172
- projectId,
173
- modelInstallPayloads: payload.modelsInstallResponse.newModels,
174
- newAppCfg: appCfgUpdate.newAppCfg
175
- }),
176
- projectId
177
- );
178
- }
179
-
180
- if (envVarUpdate) {
181
- await this.atomicApplicationUpdate(
182
- async () =>
183
- await this.shadowHandler.updateProjectEnvVars({
184
- projectId,
185
- envVars: envVarUpdate.envVars
186
- }),
187
- projectId,
188
- true
189
- );
190
- }
191
-
192
- return true;
193
- };
194
-
195
- private async handleDeviceAction(payload: DeviceActionPayload) {
196
- const { system_restart } = keyMirrors.deviceAction;
197
- switch (payload.action) {
198
- case system_restart: {
199
- await reboot();
200
- break;
201
- }
202
- default: {
203
- logger.info(
204
- `Unrecognized device action requested: '${payload.action}'.`
205
- );
206
- }
207
- }
208
- }
209
-
210
- private async publishCloudRequest(message: ToCloudMessage) {
211
- this.publisher.publishToCloud(message);
212
- }
213
-
214
- private subscribe(topic: string) {
215
- logger.info(`Subscribing to ${topic}`);
216
- this.device.subscribe(topic);
217
- }
218
-
219
- private async atomicApplicationUninstall(projectId: string) {
220
- try {
221
- await uninstallApp({ projectId });
222
- this.shadowHandler.clearProjectShadow(projectId);
223
- } catch (e) {
224
- logger.error(`Failed to uninstall ${projectId}: ${e.message}`);
225
- throw e;
226
- }
227
- }
228
-
229
- // eslint-disable-next-line
230
- private async atomicApplicationUpdate <F extends () => any>(
231
- func: F,
232
- projectId: string,
233
- skipUpdateShadow?: boolean
234
- ): Promise<ReturnType<F>> {
235
- // First try to create a backup, so that there is one available if something goes wrong in the next try:catch.
236
- if (await AgentConfigFile().isAppPresent({ projectId })) {
237
- try {
238
- await createAppBackup({ projectId });
239
- } catch (e) {
240
- logger.error(
241
- `Could not create a backup for the project: ${projectId}:\n${e.message}\n${e.stack}`
242
- );
243
- }
244
- }
245
-
246
- try {
247
- const out: ReturnType<F> = await func();
248
- if (!skipUpdateShadow)
249
- await this.shadowHandler.updateProjectShadow(projectId);
250
- return out;
251
- } catch (errorAppUpdate) {
252
- logger.error(
253
- `Failed to update ${projectId}:\n${JSON.stringify(errorAppUpdate)}}`
254
- );
255
- // If something goes wrong, first try to rollback
256
- try {
257
- await rollbackApp({ projectId });
258
- logger.error(
259
- `Application update failed, rolled back to previous version: ${errorAppUpdate}`
260
- );
261
- } catch (errorRollbackApp) {
262
- // and if that fails, uninstall the app as a last resort.
263
- try {
264
- await this.atomicApplicationUninstall(projectId);
265
- } catch {
266
- // atomicApplicationUninstall handles failing, so there's nothing to handle here.
267
- }
268
- logger.error(
269
- `Application update failed, rolled back to previous version: ${errorAppUpdate}`
270
- );
271
- throw new Error(
272
- `Application update and rollback failed, uninstalled the application: ${errorAppUpdate}`
273
- );
274
- }
275
- throw new Error(
276
- `Application update failed, rolled the application back: ${errorAppUpdate}`
277
- );
278
- }
279
- }
280
-
281
- private handleProjectShadowConfigUpdate = async (
282
- update: ShadowUpdate,
283
- txId: string
284
- ): Promise<boolean> => {
285
- const { projectId, appCfgUpdate, envVarUpdate } = update;
286
-
287
- if (
288
- appCfgUpdate?.updatedModels &&
289
- Object.keys(appCfgUpdate.updatedModels).length
290
- ) {
291
- // When there are model updates request signed URLs and wait to apply config changes
292
- const { updatedModels } = appCfgUpdate;
293
-
294
- logger.debug(
295
- `Requesting presigned urls from cloud for model versions: ${JSON.stringify(
296
- updatedModels
297
- )}`
298
- );
299
- const modelsOnlyUrlsRequestPayload: SignedUrlsRequestPayload = {
300
- modelsOnlyUrlsRequest: {
301
- projectId,
302
- models: updatedModels
303
- }
304
- };
305
- const message = buildSignedUrlsRequestMessage(
306
- this.clientId,
307
- modelsOnlyUrlsRequestPayload,
308
- txId
309
- );
310
- this.publisher.publishToCloud(message);
311
-
312
- this.txnMgr.setAppCfgUpdateToTx(txId, update);
313
-
314
- return false;
315
- }
316
-
317
- if (appCfgUpdate) {
318
- await this.atomicApplicationUpdate(async () => {
319
- await pruneModels({
320
- projectId,
321
- appCfg: appCfgUpdate.newAppCfg
322
- });
323
- await updateAppCfg({
324
- projectId,
325
- newAppCfg: appCfgUpdate.newAppCfg
326
- });
327
- }, projectId);
328
- }
329
-
330
- if (envVarUpdate) {
331
- await this.atomicApplicationUpdate(
332
- async () =>
333
- await this.shadowHandler.updateProjectEnvVars({
334
- projectId,
335
- envVars: envVarUpdate.envVars
336
- }),
337
- projectId,
338
- true
339
- );
340
- }
341
- return true;
342
- };
343
-
344
- private async handleProjectShadowMessage(topic: string, message: any) {
345
- const shadowUpdates = await this.shadowHandler.handleProjectShadow({
346
- topic,
347
- payload: message,
348
- clientToken: message.clientToken
349
- });
350
- if (shadowUpdates.length) {
351
- const shadowUpdatePromises: Promise<void>[] = [];
352
- for (const shadowUpdate of shadowUpdates) {
353
- const projectId = shadowUpdate.projectId;
354
- const txId = shadowUpdate.txId;
355
- shadowUpdatePromises.push(
356
- this.txnMgr
357
- .runTransactionStep({
358
- func: () =>
359
- this.handleProjectShadowConfigUpdate(shadowUpdate, txId),
360
- projectId,
361
- txId,
362
- start: true,
363
- stepName: topic
364
- })
365
- .catch((e: Error) => {
366
- logger.error(
367
- `There was an issue updating project shadow config: ${JSON.stringify(
368
- e
369
- )}`
370
- );
371
- })
372
- );
373
- }
374
-
375
- await Promise.all(shadowUpdatePromises);
376
- }
377
- }
378
-
379
- public async handleSecureTunnelMessage(payload: any): Promise<void> {
380
- logger.info(`Received secure tunnel update: ${JSON.stringify(payload)}`);
381
- const state = payload.state;
382
- if (!state) {
383
- logger.debug(`No state found in message: ${JSON.stringify(payload)}`);
384
- return;
385
- }
386
- const valid = validateSecureTunnelShadowUpdate(state);
387
- if (!valid) {
388
- logger.error(
389
- `Error validating message: ${JSON.stringify(
390
- { payload, errors: validateSecureTunnelShadowUpdate.errors },
391
- null,
392
- 2
393
- )}`
394
- );
395
- return;
396
- }
397
- const secureTunnelUpdate =
398
- await this.secureTunnelHandler.syncShadowToDeviceState(payload);
399
- await this.shadowHandler.updateSecureTunnelShadow(secureTunnelUpdate);
400
- return;
401
- }
43
+ constructor() {
44
+ this.liveUpdatesHandler = new LiveUpdatesHandler();
402
45
 
403
- /*=================================================================
404
- Public interface
405
- =================================================================*/
46
+ // Initialize & setup the connection
47
+ this.connectionManager = new ConnectionManager(
48
+ this.clientId,
49
+ this.host,
50
+ this.port
51
+ );
52
+ this.connectionManager.setupConnection();
406
53
 
407
- constructor() {
408
- this.device = awsIot.device({
409
- keyPath: DEVICE_PRIVATE_KEY_FILE_PATH,
410
- certPath: DEVICE_CERTIFICATE_FILE_PATH,
411
- caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
412
- clientId: this.clientId,
413
- host: this.host,
414
- port: this.port,
415
- keepalive: 1 // time before re-connect attempt on dropped connection, default is 400 seconds
416
- });
417
- this.publisher = new Publisher(this.device, this.clientId);
418
- this.shadowHandler = new ShadowHandler(this.clientId, this.publisher);
419
- this.liveUpdatesHandler = new LiveUpdatesHandler(
420
- this.publisher,
54
+ // Initialize the Publisher, ShadowHandler & Transaction Manager
55
+ this.publisher = new Publisher(
56
+ this.connectionManager.getIoTDevice(),
421
57
  this.clientId
422
58
  );
423
- this.txnMgr = new TransactionManager(
59
+ this.shadowHandler = new ShadowHandler(this.clientId, this.publisher);
60
+
61
+ this.transactionManager = new TransactionManager(
424
62
  this.publisher,
425
63
  this.liveUpdatesHandler
426
64
  );
427
65
 
428
- this.subscribe(this.toDeviceTopic);
429
- this.subscribe(this.secureTunnelNotifyTopic);
430
- for (const topic of this.shadowHandler.projectShadowTopics) {
431
- this.subscribe(topic);
432
- }
433
- this.subscribe(this.shadowHandler.shadowTopics.secureTunnel.updateDelta);
434
- this.subscribe(this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted);
435
- }
436
-
437
- public getClientId(): string {
438
- return this.clientId;
439
- }
440
-
441
- public getToDeviceTopic() {
442
- return this.toDeviceTopic;
443
- }
444
-
445
- public isCmdInProgress(projectId: string): boolean {
446
- return this.txnMgr.isOngoingTransactionForProjectID(projectId);
447
- }
448
-
449
- public async updateProjectShadow(projectId: string) {
450
- await this.shadowHandler.updateProjectShadow(projectId);
451
- }
66
+ // Construct a HandlerContext used by all the message handlers
67
+ const handlerContext: HandlerContext = {
68
+ clientId: this.clientId,
69
+ txnMgr: this.transactionManager,
70
+ publisher: this.publisher,
71
+ shadowHandler: this.shadowHandler,
72
+ liveUpdatesHandler: this.liveUpdatesHandler,
73
+ secureTunnelHandler: this.secureTunnelHandler
74
+ };
452
75
 
453
- public async handleDeviceAgentMessage({
454
- topic,
455
- message
456
- }: {
457
- topic: string;
458
- message: ToDeviceAgentMessage;
459
- }) {
460
- const valid = validateToDeviceAgentMessage(message);
461
- if (!valid) {
462
- logger.error(
463
- `Error validating message: ${JSON.stringify(
464
- { topic, message, errors: validateToDeviceAgentMessage.errors },
465
- null,
466
- 2
467
- )}`
76
+ // Instantiate & register message handlers for Project Shadow topics
77
+ const projectShadowMessageHandler = new ProjectShadowMessageHandler(
78
+ handlerContext
79
+ );
80
+ this.shadowHandler.projectShadowTopics.forEach((topic) => {
81
+ this.connectionManager.registerHandler(
82
+ topic,
83
+ projectShadowMessageHandler
468
84
  );
469
- // TODO: Send generic error response
470
- return;
471
- }
472
- const txId = message.txId;
473
- const {
474
- app_state_control,
475
- app_version_control,
476
- live_state_updates,
477
- app_install_response,
478
- models_install_response,
479
- status_response,
480
- device_action
481
- } = keyMirrors.toDeviceAgentMessageType;
482
- switch (message.messageType) {
483
- case app_state_control: {
484
- // txId sent from cloud, just need to continue it
485
- const payload = message.payload;
486
- const projectId = payload.projectId;
487
-
488
- try {
489
- await this.txnMgr.runTransactionStep({
490
- func: () => this.handleAppStateControl(message.payload),
491
- projectId,
492
- txId,
493
- start: true,
494
- stepName: payload.baseCommand
495
- });
496
- } catch (e) {
497
- logger.error(
498
- `Error processing application state control request: ${e}!`
499
- );
500
- }
501
-
502
- break;
503
- }
504
- case app_version_control: {
505
- // txId sent from cloud, just need to continue it
506
- const payload = message.payload;
507
- const projectId = payload.projectId;
508
- try {
509
- await this.txnMgr.runTransactionStep({
510
- func: () => this.handleAppVersionControl(payload, txId),
511
- projectId,
512
- txId,
513
- start: true,
514
- stepName: payload.baseCommand
515
- });
516
- } catch (e) {
517
- logger.error(`Error processing application install request: ${e}!`);
518
- }
519
-
520
- break;
521
- }
522
- case live_state_updates: {
523
- const payload = message.payload;
524
- // TODO: Send response?
525
- void this.liveUpdatesHandler.handleToggles(payload, txId);
526
- break;
527
- }
528
- case app_install_response: {
529
- const payload = message.payload;
530
- const { projectId } = payload.appInstallResponse;
531
- if (txId !== this.txnMgr.getTransactionFromProject(projectId)) {
532
- throw new Error(
533
- `App install response received a message for a transaction ID ${txId} that is not currently underway (${this.txnMgr.getTransactionFromProject(
534
- projectId
535
- )})!`
536
- );
537
- }
538
- await this.txnMgr.runTransactionStep({
539
- func: () => this.handleAppInstallCloudResponsePayload(payload),
540
- projectId,
541
- txId,
542
- start: false,
543
- stepName: message.messageType
544
- });
545
- break;
546
- }
547
- case models_install_response: {
548
- // This message doesn't have appReleaseHash in it's payload, but
549
- // atomicCmd should be able to read it from the installed app
550
- const payload = message.payload;
551
- const { projectId } = payload.modelsInstallResponse;
552
- if (txId !== this.txnMgr.getTransactionFromProject(projectId)) {
553
- throw new Error(
554
- `Model install response received a message for a transaction ID ${txId} that is not currently underway (${this.txnMgr.getTransactionFromProject(
555
- projectId
556
- )})!`
557
- );
558
- }
559
- await this.txnMgr.runTransactionStep({
560
- func: () =>
561
- this.handleModelsInstallCloudResponsePayload(payload, txId),
562
- projectId,
563
- txId,
564
- start: false,
565
- stepName: message.messageType
566
- });
567
- break;
568
- }
569
- case status_response: {
570
- const { failure } = keyMirrors.statusResponse;
571
- if (message.payload.status === failure) {
572
- this.txnMgr.completeTransaction(txId);
85
+ });
573
86
 
574
- const failureStatusResponsePayload: StatusResponsePayload = {
575
- status: keyMirrors.statusResponse.failure,
576
- message: message.payload.message
577
- };
578
- // Send final status message
579
- const failureStatusResponseMessage =
580
- buildToClientStatusResponseMessage(
581
- this.clientId,
582
- failureStatusResponsePayload,
583
- txId
584
- );
585
- this.publisher.publishToClient(failureStatusResponseMessage);
586
- }
587
- break;
588
- }
589
- case device_action: {
590
- try {
591
- const statusResponsePayload: StatusResponsePayload = {
592
- status: keyMirrors.statusResponse.in_progress
593
- };
594
- const statusResponseMessage = buildToClientStatusResponseMessage(
595
- this.clientId,
596
- statusResponsePayload,
87
+ // Instantiate & register message handlers for to-device and secureTunnel topics
88
+ this.connectionManager.registerHandler(
89
+ this.toDeviceTopic,
90
+ new DeviceAgentMessageHandler(
91
+ handlerContext,
92
+ (txId: string, errorMsg: string) => {
93
+ const msg = buildToClientStatusResponseMessage(
94
+ this.publisher.getClientId(),
95
+ {
96
+ status: keyMirrors.statusResponse.failure,
97
+ message: errorMsg
98
+ },
597
99
  txId
598
100
  );
599
- this.publisher.publishToClient(statusResponseMessage);
600
-
601
- await this.handleDeviceAction(message.payload);
602
-
603
- const successStatusResponsePayload: StatusResponsePayload = {
604
- status: keyMirrors.statusResponse.success
605
- };
606
- const successStatusResponseMessage =
607
- buildToClientStatusResponseMessage(
608
- this.clientId,
609
- successStatusResponsePayload,
610
- txId
611
- );
612
- this.publisher.publishToClient(successStatusResponseMessage);
613
- } catch (e) {
614
- logger.error(
615
- `There was a problem performing device action '${message.payload.action}': ${e.message}`
101
+ this.publisher.publishToClient(msg);
102
+ },
103
+ (txId: string) => {
104
+ const msg = buildToClientStatusResponseMessage(
105
+ this.publisher.getClientId(),
106
+ { status: keyMirrors.statusResponse.success },
107
+ txId
616
108
  );
617
- const failureStatusResponsePayload: StatusResponsePayload = {
618
- status: keyMirrors.statusResponse.failure,
619
- message: e.message
620
- };
621
- const failureStatusResponseMessage =
622
- buildToClientStatusResponseMessage(
623
- this.clientId,
624
- failureStatusResponsePayload,
625
- txId
626
- );
627
- this.publisher.publishToClient(failureStatusResponseMessage);
109
+ this.publisher.publishToClient(msg);
628
110
  }
629
- break;
630
- }
631
- default:
632
- logger.error(
633
- `Invalid client message: '${JSON.stringify(
634
- { topic, message, txId },
635
- null,
636
- 2
637
- )}'`
638
- );
639
- }
640
- }
111
+ )
112
+ );
641
113
 
642
- public async handleMessage(topic: string, message: any) {
643
- logger.debug(
644
- `Received message: ${JSON.stringify({ topic, message }, null, 2)}`
114
+ const secureTunnelMessageHandler = new SecureTunnelMessageHandler(
115
+ handlerContext
116
+ );
117
+ this.connectionManager.registerHandler(
118
+ secureTunnelMessageHandler.getNotifyTopic(),
119
+ secureTunnelMessageHandler
645
120
  );
646
- // ProjectShadow messages
647
- if (this.shadowHandler.projectShadowTopics.includes(topic)) {
648
- await this.handleProjectShadowMessage(topic, message);
649
- } else if (topic === this.toDeviceTopic) {
650
- await this.handleDeviceAgentMessage({
651
- topic,
652
- message
653
- });
654
- // SecureTunnelNotify messages
655
- } else if (topic === this.secureTunnelNotifyTopic) {
656
- await this.secureTunnelHandler.secureTunnelNotifyHandler(message);
657
- // SecureTunnel messages
658
- } else if (
659
- topic === this.shadowHandler.shadowTopics.secureTunnel.updateDelta
660
- ) {
661
- await this.handleSecureTunnelMessage(message);
662
- } else if (
663
- topic === this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted
664
- ) {
665
- logger.info(`Received secure tunnel deleteAccepted: ${message}`);
666
- await this.secureTunnelHandler.destroy();
667
- } else {
668
- logger.error(`Unexpected topic, ignoring! ${topic}`);
669
- }
670
- }
671
121
 
672
- public async setupHandlers() {
673
- this.device.on('connect', (connack: any) => {
674
- logger.info('Device Agent has connected to the cloud');
675
- // FIXME: EI-709 Skip this request for now to prevent kicking off another
676
- // shadow update process if IoT Core disconnect occurs during app config update
677
- //this.shadowHandler.getShadowUpdates();
678
- void this.shadowHandler.updateSystemInfoShadow();
679
- });
122
+ this.connectionManager.registerHandler(
123
+ this.shadowHandler.shadowTopics.secureTunnel.updateDelta,
124
+ secureTunnelMessageHandler
125
+ );
126
+ this.connectionManager.registerHandler(
127
+ this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted,
128
+ secureTunnelMessageHandler
129
+ );
680
130
 
681
- this.device.on('disconnect', () => {
682
- logger.warn('Device Agent has been disconnected from the cloud');
683
- });
131
+ const jobHandler = new JobHandler(handlerContext);
684
132
 
685
- this.device.on('reconnect', () => {
686
- logger.info(
687
- `Device Agent attempting to re-connect ${new Date().toLocaleString()}`
688
- );
689
- });
133
+ const JOB_HANDLER_TOPICS = jobHandler.getJobTopic();
690
134
 
691
- this.device.on('error', function (error) {
692
- const errorString = error.message.toString();
693
- logger.error(`${errorString}`);
694
- });
135
+ this.connectionManager.registerHandler(
136
+ JOB_HANDLER_TOPICS.NOTIFY_NEXT,
137
+ jobHandler
138
+ );
695
139
 
696
- this.device.on('message', async (topic: string, payload: string) => {
697
- try {
698
- const jsonPacket = JSON.parse(payload);
699
- await this.handleMessage(topic, jsonPacket);
700
- } catch (e) {
701
- logger.error(`Error parsing message: ${e.message}`);
702
- }
703
- });
140
+ this.connectionManager.registerHandler(
141
+ JOB_HANDLER_TOPICS.START_NEXT_ACCEPTED,
142
+ jobHandler
143
+ );
704
144
 
705
- this.device.on('offline', () => {
706
- logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
707
- void this.logConnectionInfo();
708
- });
145
+ // Initialize job
146
+ this.publisher.publish(JOB_HANDLER_TOPICS.START_NEXT, JSON.stringify({}));
709
147
  }
710
148
 
711
- public async logConnectionInfo() {
712
- try {
713
- /**
714
- * We're using the 'netcat' or 'nc' command to test the connection to the IoT Core endpoint.
715
- * This command doesn't always exit (see below), so
716
- * we use timeout to break out of the prompt
717
- * and catch the resulting error/parse the resulting stderr
718
- *
719
- * Sample command for current host and port:
720
- * nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
721
- *
722
- * Sample output when port is not blocked and host is reachable:
723
- * $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443
724
- * Connection to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443 port [tcp/https] succeeded!
725
- *
726
- *
727
- * Sample output when port is blocked (will repeatedly try until ctrl-C out):
728
- * $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
729
- * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
730
- * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
731
- * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
732
- * ^C
733
- *
734
- *
735
- * Sample command/output when the port isn't enable on that host:
736
- * $ nc -zv -w 1 localhost 8883
737
- * nc: connect to localhost port 8883 (tcp) failed: Connection refused
738
- */
739
- await exec_promise(`nc -zv -w 1 ${this.host} ${this.port}`, {
740
- timeout: 2000
741
- });
742
- } catch (err) {
743
- const output = JSON.stringify(err['stderr']);
744
- if (output.indexOf('not known') !== -1) {
745
- logger.warn(
746
- 'Iot Core endpoint appears to be unreachable, internet connection may be unstable or the host may be down.'
747
- );
748
- } else if (output.indexOf('timed out') !== -1) {
749
- logger.warn(
750
- `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.`
751
- );
752
- } else if (output.indexOf('refused') !== -1) {
753
- logger.warn(
754
- `The connection was refused, likely ${this.host} is not running a service on ${this.port}.`
755
- );
756
- } else {
757
- logger.warn(
758
- `Output from checking connection to ${this.host} on ${this.port}: ${output}`
759
- );
760
- }
761
- }
149
+ /*=================================================================
150
+ Public interface
151
+ =================================================================*/
152
+ public getClientId(): string {
153
+ return this.clientId;
154
+ }
155
+
156
+ public isCmdInProgress(projectId: string): boolean {
157
+ return this.transactionManager.isOngoingTransactionForProjectID(projectId);
762
158
  }
763
159
 
764
160
  public async stop() {
@@ -766,7 +162,10 @@ export class DeviceAgentCloudConnection {
766
162
  // lost since we aren't waiting for responses so sleep for a short time to
767
163
  // receive them
768
164
  await sleep(1000);
769
- this.device.end();
165
+ this.connectionManager.disconnect();
166
+ }
167
+ public async handleMessage(topic: string, message: any) {
168
+ this.connectionManager.dispatch(topic, message);
770
169
  }
771
170
  }
772
171
 
@@ -774,20 +173,28 @@ export async function runDeviceAgentCloudInterface() {
774
173
  logger.info(
775
174
  `Starting alwaysAI Device Agent v${await getDeviceAgentVersion()}`
776
175
  );
777
- if (cloudModeReady()) {
176
+ if (existsSync(getBootstrapPrivateKeyFilePath())) {
177
+ await bootstrapProvision();
178
+ return;
179
+ }
180
+
181
+ const filesAlreadyMigrated = await requiredConfigFilesPresentAndValid();
182
+ if (!filesAlreadyMigrated) {
183
+ logger.debug('Attempting configuration file migration.');
184
+ await migrateFromLegacyCertsAndTokens();
185
+ }
186
+
187
+ if (await requiredConfigFilesPresentAndValid()) {
778
188
  const deviceAgent = new DeviceAgentCloudConnection();
779
- await deviceAgent.setupHandlers();
780
189
  if (ALWAYSAI_ANALYTICS_PASSTHROUGH === true) {
190
+ const shadowHandler = deviceAgent.shadowHandler;
781
191
  const publisher = deviceAgent.publisher;
782
- const passthroughHandler = new PassthroughHandler(publisher);
192
+ const passthroughHandler = new PassthroughHandler(
193
+ publisher,
194
+ shadowHandler
195
+ );
783
196
  await passthroughHandler.setup();
784
197
  }
785
- } else if (existsSync(BOOTSTRAP_PRIVATE_KEY_FILE_PATH())) {
786
- await bootstrapProvision();
787
- } else if (existsSync(BOOTSTRAP_CERTIFICATES_DIR_PATH())) {
788
- throw new Error(
789
- "Device has not been created using 'aai-agent device init' or there has been an issue with device initialization"
790
- );
791
198
  } else {
792
199
  throw new Error(
793
200
  "Set device agent to local mode and retry the 'aai-agent device init' command"