@alwaysai/device-agent 1.4.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 (313) hide show
  1. package/lib/application-control/config.d.ts.map +1 -1
  2. package/lib/application-control/config.js +10 -5
  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 +9 -7
  16. package/lib/application-control/install.js.map +1 -1
  17. package/lib/application-control/models.d.ts +5 -11
  18. package/lib/application-control/models.d.ts.map +1 -1
  19. package/lib/application-control/models.js +27 -64
  20. package/lib/application-control/models.js.map +1 -1
  21. package/lib/application-control/status.d.ts.map +1 -1
  22. package/lib/application-control/status.js +10 -12
  23. package/lib/application-control/status.js.map +1 -1
  24. package/lib/application-control/utils.d.ts +0 -4
  25. package/lib/application-control/utils.d.ts.map +1 -1
  26. package/lib/application-control/utils.js +3 -26
  27. package/lib/application-control/utils.js.map +1 -1
  28. package/lib/cloud-connection/bootstrap-provision.js +3 -2
  29. package/lib/cloud-connection/bootstrap-provision.js.map +1 -1
  30. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +11 -16
  31. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  32. package/lib/cloud-connection/device-agent-cloud-connection.js +295 -246
  33. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  34. package/lib/cloud-connection/device-agent.d.ts.map +1 -1
  35. package/lib/cloud-connection/device-agent.js +11 -9
  36. package/lib/cloud-connection/device-agent.js.map +1 -1
  37. package/lib/cloud-connection/live-updates-handler.d.ts +18 -27
  38. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  39. package/lib/cloud-connection/live-updates-handler.js +58 -170
  40. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  41. package/lib/cloud-connection/live-updates-handler.test.js +76 -54
  42. package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
  43. package/lib/cloud-connection/passthrough-handler.d.ts +9 -4
  44. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
  45. package/lib/cloud-connection/passthrough-handler.js +95 -62
  46. package/lib/cloud-connection/passthrough-handler.js.map +1 -1
  47. package/lib/cloud-connection/shadow-handler.d.ts +5 -1
  48. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  49. package/lib/cloud-connection/shadow-handler.js +63 -31
  50. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  51. package/lib/cloud-connection/shadow-handler.test.js +45 -57
  52. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  53. package/lib/cloud-connection/shadow.d.ts.map +1 -1
  54. package/lib/cloud-connection/shadow.js +2 -1
  55. package/lib/cloud-connection/shadow.js.map +1 -1
  56. package/lib/cloud-connection/transaction-manager.d.ts +7 -2
  57. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  58. package/lib/cloud-connection/transaction-manager.js +29 -29
  59. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  60. package/lib/cloud-connection/transaction-manager.test.js +105 -3
  61. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  62. package/lib/device-control/device-control.d.ts +14 -6
  63. package/lib/device-control/device-control.d.ts.map +1 -1
  64. package/lib/device-control/device-control.js +172 -72
  65. package/lib/device-control/device-control.js.map +1 -1
  66. package/lib/docker/docker-compose.d.ts +14 -0
  67. package/lib/docker/docker-compose.d.ts.map +1 -0
  68. package/lib/docker/docker-compose.js +57 -0
  69. package/lib/docker/docker-compose.js.map +1 -0
  70. package/lib/index.js +2 -5
  71. package/lib/index.js.map +1 -1
  72. package/lib/infrastructure/agent-config.d.ts +46 -14
  73. package/lib/infrastructure/agent-config.d.ts.map +1 -1
  74. package/lib/infrastructure/agent-config.js +36 -21
  75. package/lib/infrastructure/agent-config.js.map +1 -1
  76. package/lib/infrastructure/agent-config.test.js +6 -1
  77. package/lib/infrastructure/agent-config.test.js.map +1 -1
  78. package/lib/infrastructure/config-check-utility.d.ts +6 -0
  79. package/lib/infrastructure/config-check-utility.d.ts.map +1 -0
  80. package/lib/infrastructure/config-check-utility.js +67 -0
  81. package/lib/infrastructure/config-check-utility.js.map +1 -0
  82. package/lib/infrastructure/config-check-utility.test.d.ts +2 -0
  83. package/lib/infrastructure/config-check-utility.test.d.ts.map +1 -0
  84. package/lib/infrastructure/config-check-utility.test.js +109 -0
  85. package/lib/infrastructure/config-check-utility.test.js.map +1 -0
  86. package/lib/infrastructure/device-certificate.d.ts +10 -0
  87. package/lib/infrastructure/device-certificate.d.ts.map +1 -0
  88. package/lib/infrastructure/device-certificate.js +47 -0
  89. package/lib/infrastructure/device-certificate.js.map +1 -0
  90. package/lib/infrastructure/device-certificate.test.d.ts +2 -0
  91. package/lib/infrastructure/device-certificate.test.d.ts.map +1 -0
  92. package/lib/infrastructure/device-certificate.test.js +24 -0
  93. package/lib/infrastructure/device-certificate.test.js.map +1 -0
  94. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts +2 -0
  95. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts.map +1 -0
  96. package/lib/infrastructure/legacy-migration/legacy-file.test.js +61 -0
  97. package/lib/infrastructure/legacy-migration/legacy-file.test.js.map +1 -0
  98. package/lib/infrastructure/legacy-migration/legacy-files.d.ts +75 -0
  99. package/lib/infrastructure/legacy-migration/legacy-files.d.ts.map +1 -0
  100. package/lib/infrastructure/legacy-migration/legacy-files.js +75 -0
  101. package/lib/infrastructure/legacy-migration/legacy-files.js.map +1 -0
  102. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts +6 -0
  103. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -0
  104. package/lib/infrastructure/legacy-migration/legacy-migration.js +149 -0
  105. package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -0
  106. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts +2 -0
  107. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts.map +1 -0
  108. package/lib/infrastructure/legacy-migration/legacy-migration.test.js +226 -0
  109. package/lib/infrastructure/legacy-migration/legacy-migration.test.js.map +1 -0
  110. package/lib/infrastructure/require-files-present-ready.test.d.ts +2 -0
  111. package/lib/infrastructure/require-files-present-ready.test.d.ts.map +1 -0
  112. package/lib/infrastructure/require-files-present-ready.test.js +44 -0
  113. package/lib/infrastructure/require-files-present-ready.test.js.map +1 -0
  114. package/lib/infrastructure/required-config-checks.d.ts +2 -0
  115. package/lib/infrastructure/required-config-checks.d.ts.map +1 -0
  116. package/lib/infrastructure/required-config-checks.js +30 -0
  117. package/lib/infrastructure/required-config-checks.js.map +1 -0
  118. package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -1
  119. package/lib/infrastructure/tokens-and-device-cfg.js +11 -8
  120. package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -1
  121. package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -1
  122. package/lib/local-connection/rabbitmq-connection.js +21 -21
  123. package/lib/local-connection/rabbitmq-connection.js.map +1 -1
  124. package/lib/secure-tunneling/secure-tunneling.d.ts +15 -23
  125. package/lib/secure-tunneling/secure-tunneling.d.ts.map +1 -1
  126. package/lib/secure-tunneling/secure-tunneling.js +52 -47
  127. package/lib/secure-tunneling/secure-tunneling.js.map +1 -1
  128. package/lib/secure-tunneling/secure-tunneling.test.js +29 -31
  129. package/lib/secure-tunneling/secure-tunneling.test.js.map +1 -1
  130. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  131. package/lib/subcommands/app/analytics.js +1 -2
  132. package/lib/subcommands/app/analytics.js.map +1 -1
  133. package/lib/subcommands/app/env-vars.d.ts +4 -0
  134. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  135. package/lib/subcommands/app/env-vars.js +52 -6
  136. package/lib/subcommands/app/env-vars.js.map +1 -1
  137. package/lib/subcommands/app/index.d.ts.map +1 -1
  138. package/lib/subcommands/app/index.js +1 -3
  139. package/lib/subcommands/app/index.js.map +1 -1
  140. package/lib/subcommands/app/models.d.ts +0 -11
  141. package/lib/subcommands/app/models.d.ts.map +1 -1
  142. package/lib/subcommands/app/models.js +2 -58
  143. package/lib/subcommands/app/models.js.map +1 -1
  144. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  145. package/lib/subcommands/app/shadow.js +6 -5
  146. package/lib/subcommands/app/shadow.js.map +1 -1
  147. package/lib/subcommands/app/version.d.ts.map +1 -1
  148. package/lib/subcommands/app/version.js +2 -4
  149. package/lib/subcommands/app/version.js.map +1 -1
  150. package/lib/subcommands/config.d.ts +2 -0
  151. package/lib/subcommands/config.d.ts.map +1 -0
  152. package/lib/subcommands/config.js +39 -0
  153. package/lib/subcommands/config.js.map +1 -0
  154. package/lib/subcommands/device/clean.d.ts +1 -1
  155. package/lib/subcommands/device/clean.d.ts.map +1 -1
  156. package/lib/subcommands/device/clean.js +25 -15
  157. package/lib/subcommands/device/clean.js.map +1 -1
  158. package/lib/subcommands/device/get-info.d.ts +2 -0
  159. package/lib/subcommands/device/get-info.d.ts.map +1 -0
  160. package/lib/subcommands/device/get-info.js +36 -0
  161. package/lib/subcommands/device/get-info.js.map +1 -0
  162. package/lib/subcommands/device/index.d.ts.map +1 -1
  163. package/lib/subcommands/device/index.js +13 -2
  164. package/lib/subcommands/device/index.js.map +1 -1
  165. package/lib/subcommands/device/init.d.ts +5 -0
  166. package/lib/subcommands/device/init.d.ts.map +1 -0
  167. package/lib/subcommands/device/{device.js → init.js} +10 -49
  168. package/lib/subcommands/device/init.js.map +1 -0
  169. package/lib/subcommands/device/migrate.d.ts +2 -0
  170. package/lib/subcommands/device/migrate.d.ts.map +1 -0
  171. package/lib/subcommands/device/migrate.js +24 -0
  172. package/lib/subcommands/device/migrate.js.map +1 -0
  173. package/lib/subcommands/device/refresh.d.ts +2 -0
  174. package/lib/subcommands/device/refresh.d.ts.map +1 -0
  175. package/lib/subcommands/device/refresh.js +25 -0
  176. package/lib/subcommands/device/refresh.js.map +1 -0
  177. package/lib/subcommands/device/restart.d.ts +2 -0
  178. package/lib/subcommands/device/restart.d.ts.map +1 -0
  179. package/lib/subcommands/device/restart.js +14 -0
  180. package/lib/subcommands/device/restart.js.map +1 -0
  181. package/lib/subcommands/index.d.ts +1 -1
  182. package/lib/subcommands/index.d.ts.map +1 -1
  183. package/lib/subcommands/index.js +3 -1
  184. package/lib/subcommands/index.js.map +1 -1
  185. package/lib/subcommands/rabbitmq-connection.d.ts +1 -1
  186. package/lib/subcommands/rabbitmq-connection.d.ts.map +1 -1
  187. package/lib/util/aai-error.d.ts +12 -0
  188. package/lib/util/aai-error.d.ts.map +1 -0
  189. package/lib/util/aai-error.js +11 -0
  190. package/lib/util/aai-error.js.map +1 -0
  191. package/lib/util/aws-regions.d.ts +2 -0
  192. package/lib/util/aws-regions.d.ts.map +1 -0
  193. package/lib/util/{cloud-mode-ready.js → aws-regions.js} +2 -20
  194. package/lib/util/aws-regions.js.map +1 -0
  195. package/lib/util/check-for-updates.d.ts +3 -0
  196. package/lib/util/check-for-updates.d.ts.map +1 -0
  197. package/lib/util/check-for-updates.js +46 -0
  198. package/lib/util/check-for-updates.js.map +1 -0
  199. package/lib/util/clean-certs.d.ts.map +1 -1
  200. package/lib/util/clean-certs.js +5 -4
  201. package/lib/util/clean-certs.js.map +1 -1
  202. package/lib/util/directories.d.ts +4 -18
  203. package/lib/util/directories.d.ts.map +1 -1
  204. package/lib/util/directories.js +18 -32
  205. package/lib/util/directories.js.map +1 -1
  206. package/lib/util/file.d.ts +11 -0
  207. package/lib/util/file.d.ts.map +1 -0
  208. package/lib/util/file.js +127 -0
  209. package/lib/util/file.js.map +1 -0
  210. package/lib/util/file.test.d.ts +2 -0
  211. package/lib/util/file.test.d.ts.map +1 -0
  212. package/lib/util/file.test.js +87 -0
  213. package/lib/util/file.test.js.map +1 -0
  214. package/lib/util/get-device-id.d.ts.map +1 -1
  215. package/lib/util/get-device-id.js +7 -1
  216. package/lib/util/get-device-id.js.map +1 -1
  217. package/lib/util/http-client.js +3 -3
  218. package/lib/util/http-client.js.map +1 -1
  219. package/package.json +22 -19
  220. package/readme.md +15 -35
  221. package/src/application-control/config.ts +10 -13
  222. package/src/application-control/environment-variables.test.ts +28 -7
  223. package/src/application-control/environment-variables.ts +13 -40
  224. package/src/application-control/index.ts +3 -16
  225. package/src/application-control/install.ts +16 -10
  226. package/src/application-control/models.ts +40 -98
  227. package/src/application-control/status.ts +9 -7
  228. package/src/application-control/utils.ts +1 -29
  229. package/src/cloud-connection/bootstrap-provision.ts +7 -7
  230. package/src/cloud-connection/device-agent-cloud-connection.ts +647 -509
  231. package/src/cloud-connection/device-agent.ts +16 -7
  232. package/src/cloud-connection/live-updates-handler.test.ts +137 -64
  233. package/src/cloud-connection/live-updates-handler.ts +103 -234
  234. package/src/cloud-connection/passthrough-handler.ts +134 -75
  235. package/src/cloud-connection/shadow-handler.test.ts +45 -57
  236. package/src/cloud-connection/shadow-handler.ts +114 -56
  237. package/src/cloud-connection/shadow.ts +4 -1
  238. package/src/cloud-connection/transaction-manager.test.ts +127 -3
  239. package/src/cloud-connection/transaction-manager.ts +68 -39
  240. package/src/device-control/device-control.ts +179 -72
  241. package/src/docker/docker-compose.ts +61 -0
  242. package/src/index.ts +2 -6
  243. package/src/infrastructure/agent-config.test.ts +9 -2
  244. package/src/infrastructure/agent-config.ts +45 -46
  245. package/src/infrastructure/config-check-utility.test.ts +154 -0
  246. package/src/infrastructure/config-check-utility.ts +77 -0
  247. package/src/infrastructure/device-certificate.test.ts +40 -0
  248. package/src/infrastructure/device-certificate.ts +58 -0
  249. package/src/infrastructure/legacy-migration/legacy-file.test.ts +88 -0
  250. package/src/infrastructure/legacy-migration/legacy-files.ts +101 -0
  251. package/src/infrastructure/legacy-migration/legacy-migration.test.ts +396 -0
  252. package/src/infrastructure/legacy-migration/legacy-migration.ts +229 -0
  253. package/src/infrastructure/require-files-present-ready.test.ts +53 -0
  254. package/src/infrastructure/required-config-checks.ts +33 -0
  255. package/src/infrastructure/tokens-and-device-cfg.ts +12 -10
  256. package/src/local-connection/rabbitmq-connection.ts +28 -23
  257. package/src/secure-tunneling/secure-tunneling.test.ts +37 -39
  258. package/src/secure-tunneling/secure-tunneling.ts +74 -69
  259. package/src/subcommands/app/analytics.ts +2 -4
  260. package/src/subcommands/app/env-vars.ts +72 -9
  261. package/src/subcommands/app/index.ts +3 -11
  262. package/src/subcommands/app/models.ts +5 -81
  263. package/src/subcommands/app/shadow.ts +6 -5
  264. package/src/subcommands/app/version.ts +3 -4
  265. package/src/subcommands/config.ts +42 -0
  266. package/src/subcommands/device/clean.ts +32 -18
  267. package/src/subcommands/device/get-info.ts +49 -0
  268. package/src/subcommands/device/index.ts +13 -2
  269. package/src/subcommands/device/{device.ts → init.ts} +11 -69
  270. package/src/subcommands/device/migrate.ts +20 -0
  271. package/src/subcommands/device/refresh.ts +23 -0
  272. package/src/subcommands/device/restart.ts +11 -0
  273. package/src/subcommands/index.ts +3 -1
  274. package/src/util/aai-error.ts +20 -0
  275. package/src/util/{cloud-mode-ready.ts → aws-regions.ts} +0 -24
  276. package/src/util/check-for-updates.ts +53 -0
  277. package/src/util/clean-certs.ts +8 -4
  278. package/src/util/directories.ts +23 -67
  279. package/src/util/file.test.ts +90 -0
  280. package/src/util/file.ts +156 -0
  281. package/src/util/get-device-id.ts +7 -7
  282. package/src/util/http-client.ts +2 -2
  283. package/lib/docker/docker-compose-cmd.d.ts +0 -5
  284. package/lib/docker/docker-compose-cmd.d.ts.map +0 -1
  285. package/lib/docker/docker-compose-cmd.js +0 -16
  286. package/lib/docker/docker-compose-cmd.js.map +0 -1
  287. package/lib/subcommands/device/device.d.ts +0 -7
  288. package/lib/subcommands/device/device.d.ts.map +0 -1
  289. package/lib/subcommands/device/device.js.map +0 -1
  290. package/lib/util/cloud-mode-ready.d.ts +0 -3
  291. package/lib/util/cloud-mode-ready.d.ts.map +0 -1
  292. package/lib/util/cloud-mode-ready.js.map +0 -1
  293. package/lib/util/download-file.d.ts +0 -6
  294. package/lib/util/download-file.d.ts.map +0 -1
  295. package/lib/util/download-file.js +0 -25
  296. package/lib/util/download-file.js.map +0 -1
  297. package/lib/util/fetch-with-timeout.d.ts +0 -4
  298. package/lib/util/fetch-with-timeout.d.ts.map +0 -1
  299. package/lib/util/fetch-with-timeout.js +0 -30
  300. package/lib/util/fetch-with-timeout.js.map +0 -1
  301. package/lib/util/parsing.d.ts +0 -2
  302. package/lib/util/parsing.d.ts.map +0 -1
  303. package/lib/util/parsing.js +0 -17
  304. package/lib/util/parsing.js.map +0 -1
  305. package/lib/util/safe-rimraf.d.ts +0 -2
  306. package/lib/util/safe-rimraf.d.ts.map +0 -1
  307. package/lib/util/safe-rimraf.js +0 -16
  308. package/lib/util/safe-rimraf.js.map +0 -1
  309. package/src/docker/docker-compose-cmd.ts +0 -15
  310. package/src/util/download-file.ts +0 -25
  311. package/src/util/fetch-with-timeout.ts +0 -35
  312. package/src/util/parsing.ts +0 -11
  313. package/src/util/safe-rimraf.ts +0 -14
@@ -3,27 +3,27 @@ import {
3
3
  validateAppConfig
4
4
  } from '@alwaysai/app-configuration-schemas';
5
5
  import {
6
+ buildUpdateShadowMessage,
6
7
  EnvVars,
7
- getAllEnvs,
8
- readAppCfgFile,
9
- setEnv
10
- } from '../application-control';
8
+ generateTxId,
9
+ getShadowTopic,
10
+ getUpdateDeltaStateFromMessage,
11
+ ProjectShadowUpdate,
12
+ SecureTunnelShadowUpdate,
13
+ validateEnvVarSchemaShadowUpdate,
14
+ validateProjectShadowUpdate
15
+ } from '@alwaysai/device-agent-schemas';
16
+ import {
17
+ buildBaseShadowMessage,
18
+ DeviceAgentStatusShadowUpdate,
19
+ ShadowProjectsUpdateAll
20
+ } from '@alwaysai/device-agent-schemas/lib/shadow-schema';
21
+ import { stringifyError } from 'alwaysai/lib/util';
22
+ import { getAllEnvs, readAppCfgFile, setEnv } from '../application-control';
11
23
  import { getSystemInformation } from '../device-control/device-control';
12
24
  import { logger } from '../util/logger';
13
25
  import { Publisher } from './publisher';
14
26
  import { AppConfigModels, getAppCfgModelsDiff } from './shadow';
15
- import {
16
- generateTxId,
17
- validateProjectShadowUpdate,
18
- buildBaseShadowMessage,
19
- buildUpdateProjectShadowMessage,
20
- buildUpdateSystemInfoShadowMessage,
21
- getShadowTopic,
22
- ShadowProjectsUpdateAll,
23
- getDesiredFromMessage,
24
- ShadowTopics,
25
- ProjectShadowUpdate
26
- } from '@alwaysai/device-agent-schemas';
27
27
 
28
28
  export type AppConfigUpdate = {
29
29
  newAppCfg: AppConfig;
@@ -107,15 +107,15 @@ export class ShadowHandler {
107
107
  txId: string;
108
108
  projectId: string;
109
109
  }): Promise<AppConfigUpdate | null> {
110
- let appCfgUpdate: any;
111
110
  let newAppCfg: any;
112
-
113
111
  // Handle errors and validation
114
112
  try {
115
113
  newAppCfg = JSON.parse(appConfig);
116
- } catch (error) {
114
+ } catch (e) {
117
115
  logger.error(
118
- `Could not parse the appConfig for transaction ${txId}!\n${error}`
116
+ `Could not parse the appConfig for transaction ${txId}!\n${stringifyError(
117
+ e
118
+ )}`
119
119
  );
120
120
  return null;
121
121
  }
@@ -139,14 +139,47 @@ export class ShadowHandler {
139
139
  projectId
140
140
  });
141
141
 
142
+ const appCfgUpdate: AppConfigUpdate = { newAppCfg };
142
143
  if (updatedModels && Object.keys(updatedModels).length) {
143
- appCfgUpdate = { newAppCfg, updatedModels };
144
- } else {
145
- appCfgUpdate = { newAppCfg };
144
+ appCfgUpdate.updatedModels = updatedModels;
146
145
  }
147
146
  return appCfgUpdate;
148
147
  }
149
148
 
149
+ private async generateEnvVarsUpdate({
150
+ envVars,
151
+ txId,
152
+ projectId
153
+ }: {
154
+ envVars: string;
155
+ txId: string;
156
+ projectId: string;
157
+ }): Promise<EnvVarUpdate | null> {
158
+ let newEnvVars: any;
159
+ try {
160
+ newEnvVars = JSON.parse(envVars);
161
+ } catch (e) {
162
+ logger.error(
163
+ `Could not parse the environment variables for transaction ${txId}!\n${stringifyError(
164
+ e
165
+ )}`
166
+ );
167
+ return null;
168
+ }
169
+
170
+ if (!validateEnvVarSchemaShadowUpdate(newEnvVars)) {
171
+ logger.error(
172
+ `Received invalid environment variables update for ${projectId}!\n${JSON.stringify(
173
+ validateEnvVarSchemaShadowUpdate.errors,
174
+ null,
175
+ 2
176
+ )}`
177
+ );
178
+ return null;
179
+ }
180
+ return { envVars: newEnvVars };
181
+ }
182
+
150
183
  private async processProjectShadowUpdates({
151
184
  delta
152
185
  }: {
@@ -220,7 +253,14 @@ export class ShadowHandler {
220
253
  `Found a delta for app environment variable shadow. Updating ${projectId}`
221
254
  );
222
255
  const envVars = projectDelta.envVars;
223
- shadowUpdate.envVarUpdate = { envVars };
256
+ const envVarsUpdate = await this.generateEnvVarsUpdate({
257
+ envVars,
258
+ txId,
259
+ projectId
260
+ });
261
+ if (envVarsUpdate) {
262
+ shadowUpdate.envVarUpdate = envVarsUpdate;
263
+ }
224
264
  }
225
265
 
226
266
  return shadowUpdate.appCfgUpdate || shadowUpdate.envVarUpdate
@@ -244,24 +284,14 @@ export class ShadowHandler {
244
284
  throw Error(`Topic ${topic} is not in the ${this.projectShadowTopics}`);
245
285
  }
246
286
  switch (topic) {
247
- case this.shadowTopics.project.updateAccepted: {
248
- if (clientToken === this.clientId) {
287
+ case this.shadowTopics.project.updateDelta: {
288
+ const delta = getUpdateDeltaStateFromMessage(payload);
289
+ if (!delta) {
249
290
  logger.debug(
250
- `Ignoring message as it was caused by Device Agent itself: ${JSON.stringify(
251
- { topic, payload },
252
- null,
253
- 2
254
- )}`
255
- );
256
- break;
257
- }
258
- const desired = getDesiredFromMessage(payload);
259
- if (!desired) {
260
- logger.debug(
261
- `No desired state found in message: ${JSON.stringify(payload)}`
291
+ `No delta state found in message: ${JSON.stringify(payload)}`
262
292
  );
263
293
  } else {
264
- return await this.processProjectShadowUpdates({ delta: desired });
294
+ return await this.processProjectShadowUpdates({ delta });
265
295
  }
266
296
  break;
267
297
  }
@@ -276,21 +306,18 @@ export class ShadowHandler {
276
306
  );
277
307
  break;
278
308
  }
279
- if (payload.state.delta) {
280
- return await this.processProjectShadowUpdates({
281
- delta: payload.state.delta
282
- });
283
- } else {
284
- logger.info(
285
- `No delta in projects.getAccepted in named shadow '${
286
- topic.split('/')[5]
287
- }'`
309
+ const delta = getUpdateDeltaStateFromMessage(payload);
310
+ if (!delta) {
311
+ logger.debug(
312
+ `No delta state found in message: ${JSON.stringify(payload)}`
288
313
  );
314
+ } else {
315
+ return await this.processProjectShadowUpdates({ delta });
289
316
  }
290
317
  break;
291
318
  }
292
319
  case this.shadowTopics.project.getRejected:
293
- case this.shadowTopics.project.updateDelta:
320
+ case this.shadowTopics.project.updateAccepted:
294
321
  case this.shadowTopics.project.updateRejected: {
295
322
  // Not handling these for now
296
323
  break;
@@ -312,7 +339,10 @@ export class ShadowHandler {
312
339
  this.publisher.publish(
313
340
  getShadowTopic(this.clientId, 'system-info', 'update'),
314
341
  JSON.stringify(
315
- buildUpdateSystemInfoShadowMessage(this.clientId, systemInfo)
342
+ buildUpdateShadowMessage({
343
+ clientId: this.clientId,
344
+ reported: systemInfo
345
+ })
316
346
  )
317
347
  );
318
348
  }
@@ -324,13 +354,13 @@ export class ShadowHandler {
324
354
  const toReport: ShadowProjectsUpdateAll = {
325
355
  [projectId]: {
326
356
  appConfig: JSON.stringify(appCfg),
327
- envVars
357
+ envVars: JSON.stringify(envVars)
328
358
  }
329
359
  };
330
360
  this.publisher.publish(
331
361
  getShadowTopic(this.clientId, 'projects', 'update'),
332
362
  JSON.stringify(
333
- buildUpdateProjectShadowMessage({
363
+ buildUpdateShadowMessage({
334
364
  clientId: this.clientId,
335
365
  reported: toReport
336
366
  })
@@ -346,15 +376,15 @@ export class ShadowHandler {
346
376
  envVars: EnvVars;
347
377
  }) {
348
378
  await setEnv({ projectId, envVars });
349
-
379
+ const currentEnvs = await getAllEnvs({ projectId });
350
380
  this.publisher.publish(
351
381
  getShadowTopic(this.clientId, 'projects', 'update'),
352
382
  JSON.stringify(
353
- buildUpdateProjectShadowMessage({
383
+ buildUpdateShadowMessage({
354
384
  clientId: this.clientId,
355
385
  reported: {
356
386
  [projectId]: {
357
- envVars
387
+ envVars: JSON.stringify(currentEnvs)
358
388
  }
359
389
  }
360
390
  })
@@ -362,6 +392,34 @@ export class ShadowHandler {
362
392
  );
363
393
  }
364
394
 
395
+ public async updateSecureTunnelShadow(
396
+ secureTunnelShadowUpdate: SecureTunnelShadowUpdate
397
+ ) {
398
+ this.publisher.publish(
399
+ getShadowTopic(this.clientId, 'secure-tunnel', 'update'),
400
+ JSON.stringify(
401
+ buildUpdateShadowMessage({
402
+ reported: secureTunnelShadowUpdate,
403
+ clientId: this.clientId
404
+ })
405
+ )
406
+ );
407
+ }
408
+
409
+ public async updateDeviceAgentStatusShadow(
410
+ deviceAgentStatusShadowUpdate: DeviceAgentStatusShadowUpdate
411
+ ) {
412
+ this.publisher.publish(
413
+ getShadowTopic(this.clientId, 'device-agent-status', 'update'),
414
+ JSON.stringify(
415
+ buildUpdateShadowMessage({
416
+ reported: deviceAgentStatusShadowUpdate,
417
+ clientId: this.clientId
418
+ })
419
+ )
420
+ );
421
+ }
422
+
365
423
  public getProjectShadowUpdates() {
366
424
  this.publisher.publish(
367
425
  getShadowTopic(this.clientId, 'projects', 'get'),
@@ -373,7 +431,7 @@ export class ShadowHandler {
373
431
  this.publisher.publish(
374
432
  getShadowTopic(this.clientId, 'projects', 'update'),
375
433
  JSON.stringify(
376
- buildUpdateProjectShadowMessage({
434
+ buildUpdateShadowMessage({
377
435
  clientId: this.clientId,
378
436
  reported: { [projectId]: null },
379
437
  desired: { [projectId]: null }
@@ -1,6 +1,7 @@
1
1
  import { logger } from '../util/logger';
2
2
  import { readAppCfgFile } from '../application-control';
3
3
  import { AppConfig } from '@alwaysai/app-configuration-schemas';
4
+ import { stringifyError } from 'alwaysai/lib/util';
4
5
 
5
6
  export type AppConfigModels = {
6
7
  [modelId: string]: number;
@@ -43,7 +44,9 @@ export const getAppCfgModelsDiff = async ({
43
44
  newScripts[scriptName] = shadowScripts[scriptName];
44
45
  });
45
46
  } catch (e) {
46
- logger.error(`Error parsing app config update: ${e.message}`);
47
+ logger.error(
48
+ `Error parsing app config update for ${projectId}!\n${stringifyError(e)}`
49
+ );
47
50
  }
48
51
 
49
52
  return { scripts: newScripts, updatedModels, untouchedModels };
@@ -7,6 +7,7 @@ import { TransactionManager } from './transaction-manager';
7
7
  import { v4 as uuidv4 } from 'uuid';
8
8
  import { Publisher } from './publisher';
9
9
  import { LiveUpdatesHandler } from './live-updates-handler';
10
+ import { AppConfigUpdate, ShadowUpdate } from './shadow-handler';
10
11
 
11
12
  const mockClient = {
12
13
  publish: jest.fn()
@@ -14,8 +15,8 @@ const mockClient = {
14
15
  const clientId = 'test-client';
15
16
 
16
17
  const mockLiveUpdatesHandler = {
17
- enableTransactionStatus: jest.fn(),
18
- disableTransactionStatus: jest.fn()
18
+ enable: jest.fn(),
19
+ disable: jest.fn()
19
20
  } as any as LiveUpdatesHandler;
20
21
 
21
22
  describe('Test Transaction Manager', () => {
@@ -187,7 +188,7 @@ describe('Test Transaction Manager', () => {
187
188
  throw new Error('Expected start transaction to fail!');
188
189
  } catch (e) {
189
190
  console.log(e);
190
- expect(e.code).toBe(txnMgr.Errors.PROJECT_ONGOING);
191
+ expect(e.code).toBe(txnMgr.Errors.PROJECT_TRANSACTION_ONGOING);
191
192
  }
192
193
  expect(txnMgr.getTransactionFromProject(projectId)).toEqual(txId);
193
194
  expect(txnMgr.getProjectFromTransaction(txId)).toEqual(projectId);
@@ -245,4 +246,127 @@ describe('Test Transaction Manager', () => {
245
246
 
246
247
  expect(txnMgr.getProjectFromTransaction(txId)).toBeUndefined();
247
248
  });
249
+
250
+ test('add an appCfgUpdate from txDetails', async () => {
251
+ const txId = generateTxId();
252
+ const projectId = generateRandomProjectId();
253
+ const cfgUpdate: ShadowUpdate = { txId: txId, projectId: projectId };
254
+
255
+ await txnMgr.runTransactionStep({
256
+ func: func_incomplete,
257
+ projectId,
258
+ txId,
259
+ start: true
260
+ });
261
+
262
+ expect(txnMgr.getAppCfgUpdateFromTxID(txId)).toEqual(undefined);
263
+
264
+ txnMgr.setAppCfgUpdateToTx(txId, cfgUpdate);
265
+
266
+ expect(txnMgr.getProjectFromTransaction(txId)).toEqual(projectId);
267
+ expect(txnMgr.getTransactionFromProject(projectId)).toEqual(txId);
268
+ expect(txnMgr.isOngoingTransaction(txId)).toBe(true);
269
+ expect(txnMgr.isOngoingTransactionForProjectID(projectId)).toBe(true);
270
+ expect(txnMgr.isAnyOngoingTransaction()).toBe(true);
271
+ expect(txnMgr.getAppCfgUpdateFromTxID(txId)).toEqual(cfgUpdate);
272
+ });
273
+
274
+ test('update a tx while holding appCfgUpdate', async () => {
275
+ const txId = generateTxId();
276
+ const projectId = generateRandomProjectId();
277
+ const cfgUpdate: ShadowUpdate = { txId: txId, projectId: projectId };
278
+
279
+ await txnMgr.runTransactionStep({
280
+ func: func_incomplete,
281
+ projectId,
282
+ txId,
283
+ start: true
284
+ });
285
+
286
+ txnMgr.setAppCfgUpdateToTx(txId, cfgUpdate);
287
+
288
+ await txnMgr.runTransactionStep({
289
+ func: func_incomplete,
290
+ projectId,
291
+ txId,
292
+ start: false,
293
+ stepName: 'step2'
294
+ });
295
+
296
+ expect(txnMgr.getProjectFromTransaction(txId)).toEqual(projectId);
297
+ expect(txnMgr.getTransactionFromProject(projectId)).toEqual(txId);
298
+ expect(txnMgr.isOngoingTransaction(txId)).toBe(true);
299
+ expect(txnMgr.isOngoingTransactionForProjectID(projectId)).toBe(true);
300
+ expect(txnMgr.isAnyOngoingTransaction()).toBe(true);
301
+ expect(txnMgr.getAppCfgUpdateFromTxID(txId)).toEqual(cfgUpdate);
302
+ });
303
+
304
+ test('update an appCfgUpdate to the same tx ', async () => {
305
+ const txId = generateTxId();
306
+ const projectId = generateRandomProjectId();
307
+ const cfgUpdate: ShadowUpdate = { txId: txId, projectId: projectId };
308
+
309
+ const ogAppCfg1: AppConfigUpdate = {
310
+ newAppCfg: {
311
+ scripts: {
312
+ start: 'python app.py'
313
+ },
314
+ models: {}
315
+ }
316
+ };
317
+
318
+ const cfgUpdate2: ShadowUpdate = {
319
+ txId: txId,
320
+ projectId: projectId,
321
+ appCfgUpdate: ogAppCfg1
322
+ };
323
+
324
+ await txnMgr.runTransactionStep({
325
+ func: func_incomplete,
326
+ projectId,
327
+ txId,
328
+ start: true
329
+ });
330
+
331
+ txnMgr.setAppCfgUpdateToTx(txId, cfgUpdate);
332
+
333
+ await txnMgr.runTransactionStep({
334
+ func: func_incomplete,
335
+ projectId,
336
+ txId,
337
+ start: false,
338
+ stepName: 'step2'
339
+ });
340
+ txnMgr.setAppCfgUpdateToTx(txId, cfgUpdate2);
341
+
342
+ expect(txnMgr.getProjectFromTransaction(txId)).toEqual(projectId);
343
+ expect(txnMgr.getTransactionFromProject(projectId)).toEqual(txId);
344
+ expect(txnMgr.isOngoingTransaction(txId)).toBe(true);
345
+ expect(txnMgr.isOngoingTransactionForProjectID(projectId)).toBe(true);
346
+ expect(txnMgr.isAnyOngoingTransaction()).toBe(true);
347
+ expect(txnMgr.getAppCfgUpdateFromTxID(txId)).toEqual(cfgUpdate2);
348
+ });
349
+
350
+ test('remove a tx, ensure appCfgUpdate is removed', async () => {
351
+ const txId = generateTxId();
352
+ const projectId = generateRandomProjectId();
353
+ const cfgUpdate: ShadowUpdate = { txId: txId, projectId: projectId };
354
+
355
+ await txnMgr.runTransactionStep({
356
+ func: func_incomplete,
357
+ projectId,
358
+ txId,
359
+ start: true
360
+ });
361
+
362
+ txnMgr.setAppCfgUpdateToTx(txId, cfgUpdate);
363
+ txnMgr.completeTransaction(txId);
364
+
365
+ expect(txnMgr.getProjectFromTransaction(txId)).toEqual(undefined);
366
+ expect(txnMgr.getTransactionFromProject(projectId)).toEqual(undefined);
367
+ expect(txnMgr.isOngoingTransaction(txId)).toBe(false);
368
+ expect(txnMgr.isOngoingTransactionForProjectID(projectId)).toBe(false);
369
+ expect(txnMgr.isAnyOngoingTransaction()).toBe(false);
370
+ expect(txnMgr.getAppCfgUpdateFromTxID(txId)).toEqual(undefined);
371
+ });
248
372
  });
@@ -1,13 +1,14 @@
1
1
  import {
2
- StatusResponsePayload,
2
+ ToClientStatusResponseMessage,
3
3
  buildToClientStatusResponseMessage,
4
4
  keyMirrors
5
5
  } from '@alwaysai/device-agent-schemas';
6
6
  import { LiveUpdatesHandler } from './live-updates-handler';
7
7
  import { Publisher } from './publisher';
8
8
  import { logger } from '../util/logger';
9
- import { keyMirror } from 'alwaysai/lib/util';
9
+ import { keyMirror, stringifyError } from 'alwaysai/lib/util';
10
10
  import { CodedError } from '@carnesen/coded-error';
11
+ import { ShadowUpdate } from './shadow-handler';
11
12
 
12
13
  interface TransactionDetails {
13
14
  txId: string;
@@ -16,6 +17,7 @@ interface TransactionDetails {
16
17
  start: string;
17
18
  update?: string;
18
19
  stop?: string;
20
+ appCfgUpdate?: ShadowUpdate;
19
21
  }
20
22
 
21
23
  export class TransactionManager {
@@ -24,11 +26,12 @@ export class TransactionManager {
24
26
  private liveUpdatesHandler: LiveUpdatesHandler;
25
27
  private publisher: Publisher;
26
28
 
27
- private startTransaction(
29
+ private async startTransaction(
28
30
  txId: string,
29
31
  projectId: string,
32
+ liveUpdatesPublishFn?: () => Promise<void>,
30
33
  stepName?: string
31
- ): void {
34
+ ): Promise<void> {
32
35
  // Check if the transaction already exists
33
36
  if (this.detailsByTx[txId]) {
34
37
  const txnDetails = this.detailsByTx[txId];
@@ -51,7 +54,7 @@ export class TransactionManager {
51
54
  null,
52
55
  2
53
56
  )}`,
54
- this.Errors.PROJECT_ONGOING
57
+ this.Errors.PROJECT_TRANSACTION_ONGOING
55
58
  );
56
59
  }
57
60
 
@@ -65,10 +68,14 @@ export class TransactionManager {
65
68
  this.detailsByTx[txId] = txDetails;
66
69
  this.detailsByProject[projectId] = txDetails;
67
70
  logger.info(`Started transaction:\n${JSON.stringify(txDetails, null, 2)}`);
68
- // send live updates
69
- void this.liveUpdatesHandler.enableTransactionStatus({
70
- txId
71
- });
71
+
72
+ if (liveUpdatesPublishFn) {
73
+ await this.liveUpdatesHandler.enable(
74
+ keyMirrors.toClientMessageType.status_response,
75
+ liveUpdatesPublishFn,
76
+ txId
77
+ );
78
+ }
72
79
  }
73
80
 
74
81
  private updateTransaction(txId: string, stepName?: string): void {
@@ -93,7 +100,7 @@ export class TransactionManager {
93
100
 
94
101
  public Errors = keyMirror({
95
102
  TRANSACTION_ONGOING: null,
96
- PROJECT_ONGOING: null,
103
+ PROJECT_TRANSACTION_ONGOING: null,
97
104
  TRANSACTION_NOT_ONGOING: null
98
105
  });
99
106
 
@@ -102,48 +109,49 @@ export class TransactionManager {
102
109
  projectId: string;
103
110
  txId: string;
104
111
  start: boolean;
112
+ liveUpdatesPublishFn?: () => Promise<void>;
105
113
  stepName?: string;
106
114
  }) {
107
- const { func, projectId, txId, start, stepName } = props;
115
+ const { func, projectId, txId, start, liveUpdatesPublishFn, stepName } =
116
+ props;
108
117
  if (start) {
109
- this.startTransaction(txId, projectId, stepName);
118
+ await this.startTransaction(
119
+ txId,
120
+ projectId,
121
+ liveUpdatesPublishFn,
122
+ stepName
123
+ );
110
124
  } else {
111
125
  this.updateTransaction(txId, stepName);
112
126
  }
113
127
  try {
114
128
  const completed = await func();
115
129
  if (completed) {
116
- this.completeTransaction(txId);
117
- const successStatusResponsePayload: StatusResponsePayload = {
118
- status: keyMirrors.statusResponse.success
119
- };
120
- // Send final status message
121
- const message = buildToClientStatusResponseMessage(
122
- this.publisher.getClientId(),
123
- successStatusResponsePayload,
124
- txId
130
+ this.completeTransaction(
131
+ txId,
132
+ buildToClientStatusResponseMessage(
133
+ this.publisher.getClientId(),
134
+ { status: keyMirrors.statusResponse.success },
135
+ txId
136
+ )
125
137
  );
126
- this.publisher.publishToClient(message);
127
138
  }
128
139
  } catch (e) {
129
- const message: string = e.message;
130
140
  logger.error(
131
- `Failed to execute cmd for ${projectId}:\n${message}\n${e.stack}`
141
+ `Failed to execute cmd for ${projectId}!\n${stringifyError(e)}`
132
142
  );
133
143
 
134
- this.completeTransaction(txId);
135
-
136
- const failureStatusResponsePayload: StatusResponsePayload = {
137
- status: keyMirrors.statusResponse.failure,
138
- message
139
- };
140
- // Send final status message
141
- const failureStatusResponseMessage = buildToClientStatusResponseMessage(
142
- this.publisher.getClientId(),
143
- failureStatusResponsePayload,
144
- txId
144
+ this.completeTransaction(
145
+ txId,
146
+ buildToClientStatusResponseMessage(
147
+ this.publisher.getClientId(),
148
+ {
149
+ status: keyMirrors.statusResponse.failure,
150
+ message: e.message
151
+ },
152
+ txId
153
+ )
145
154
  );
146
- this.publisher.publishToClient(failureStatusResponseMessage);
147
155
  }
148
156
  }
149
157
 
@@ -169,7 +177,23 @@ export class TransactionManager {
169
177
  return txnDetails?.projectId;
170
178
  }
171
179
 
172
- public completeTransaction(txId: string): void {
180
+ public getAppCfgUpdateFromTxID(txId: string): ShadowUpdate | undefined {
181
+ return this.detailsByTx[txId]?.appCfgUpdate;
182
+ }
183
+
184
+ public setAppCfgUpdateToTx(txId: string, appCfgUpdate: ShadowUpdate) {
185
+ if (this.isOngoingTransaction(txId)) {
186
+ this.detailsByTx[txId].appCfgUpdate = appCfgUpdate;
187
+ } else
188
+ throw new Error(
189
+ `Could not set appCfgUpdate, the transaction ${txId} does not exist.`
190
+ );
191
+ }
192
+
193
+ public completeTransaction(
194
+ txId: string,
195
+ messageToPublish?: ToClientStatusResponseMessage
196
+ ): void {
173
197
  const txDetails = this.detailsByTx[txId];
174
198
  if (txDetails === undefined) {
175
199
  throw new CodedError(
@@ -184,8 +208,13 @@ export class TransactionManager {
184
208
  delete this.detailsByTx[txId];
185
209
  delete this.detailsByProject[txDetails.projectId];
186
210
 
187
- void this.liveUpdatesHandler.disableTransactionStatus({
211
+ this.liveUpdatesHandler.disable(
212
+ keyMirrors.toClientMessageType.status_response,
188
213
  txId
189
- });
214
+ );
215
+
216
+ if (messageToPublish) {
217
+ this.publisher.publishToClient(messageToPublish);
218
+ }
190
219
  }
191
220
  }