@alwaysai/device-agent 0.0.12 → 0.0.14

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 (227) hide show
  1. package/lib/application-control/backup.d.ts.map +1 -1
  2. package/lib/application-control/backup.js +11 -5
  3. package/lib/application-control/backup.js.map +1 -1
  4. package/lib/application-control/config.d.ts +12 -4
  5. package/lib/application-control/config.d.ts.map +1 -1
  6. package/lib/application-control/config.js +59 -16
  7. package/lib/application-control/config.js.map +1 -1
  8. package/lib/application-control/environment-variables.d.ts.map +1 -1
  9. package/lib/application-control/environment-variables.js.map +1 -1
  10. package/lib/application-control/index.d.ts +5 -5
  11. package/lib/application-control/index.d.ts.map +1 -1
  12. package/lib/application-control/index.js +4 -6
  13. package/lib/application-control/index.js.map +1 -1
  14. package/lib/application-control/install.d.ts +1 -1
  15. package/lib/application-control/install.d.ts.map +1 -1
  16. package/lib/application-control/install.js +58 -57
  17. package/lib/application-control/install.js.map +1 -1
  18. package/lib/application-control/models.d.ts +7 -5
  19. package/lib/application-control/models.d.ts.map +1 -1
  20. package/lib/application-control/models.js +78 -57
  21. package/lib/application-control/models.js.map +1 -1
  22. package/lib/application-control/status.d.ts +0 -6
  23. package/lib/application-control/status.d.ts.map +1 -1
  24. package/lib/application-control/status.js +21 -33
  25. package/lib/application-control/status.js.map +1 -1
  26. package/lib/application-control/utils.d.ts +3 -2
  27. package/lib/application-control/utils.d.ts.map +1 -1
  28. package/lib/application-control/utils.js +54 -34
  29. package/lib/application-control/utils.js.map +1 -1
  30. package/lib/cloud-connection/app-install-status.d.ts +16 -0
  31. package/lib/cloud-connection/app-install-status.d.ts.map +1 -0
  32. package/lib/cloud-connection/app-install-status.js +53 -0
  33. package/lib/cloud-connection/app-install-status.js.map +1 -0
  34. package/lib/cloud-connection/bootstrap-provision.d.ts +2 -0
  35. package/lib/cloud-connection/bootstrap-provision.d.ts.map +1 -0
  36. package/lib/cloud-connection/bootstrap-provision.js +34 -0
  37. package/lib/cloud-connection/bootstrap-provision.js.map +1 -0
  38. package/lib/cloud-connection/cmd-status.d.ts +16 -0
  39. package/lib/cloud-connection/cmd-status.d.ts.map +1 -0
  40. package/lib/cloud-connection/cmd-status.js +49 -0
  41. package/lib/cloud-connection/cmd-status.js.map +1 -0
  42. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +21 -34
  43. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  44. package/lib/cloud-connection/device-agent-cloud-connection.js +211 -387
  45. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  46. package/lib/cloud-connection/device-agent.d.ts.map +1 -1
  47. package/lib/cloud-connection/device-agent.js +22 -26
  48. package/lib/cloud-connection/device-agent.js.map +1 -1
  49. package/lib/cloud-connection/live-updates-handler.d.ts +34 -0
  50. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -0
  51. package/lib/cloud-connection/live-updates-handler.js +167 -0
  52. package/lib/cloud-connection/live-updates-handler.js.map +1 -0
  53. package/lib/cloud-connection/messages.d.ts +14 -0
  54. package/lib/cloud-connection/messages.d.ts.map +1 -0
  55. package/lib/cloud-connection/messages.js +38 -0
  56. package/lib/cloud-connection/messages.js.map +1 -0
  57. package/lib/cloud-connection/passthrough-handler.d.ts +11 -0
  58. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -0
  59. package/lib/cloud-connection/passthrough-handler.js +59 -0
  60. package/lib/cloud-connection/passthrough-handler.js.map +1 -0
  61. package/lib/cloud-connection/publisher.d.ts +15 -0
  62. package/lib/cloud-connection/publisher.d.ts.map +1 -0
  63. package/lib/cloud-connection/publisher.js +58 -0
  64. package/lib/cloud-connection/publisher.js.map +1 -0
  65. package/lib/cloud-connection/shadow-handler.d.ts +33 -0
  66. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -0
  67. package/lib/cloud-connection/shadow-handler.js +108 -0
  68. package/lib/cloud-connection/shadow-handler.js.map +1 -0
  69. package/lib/cloud-connection/shadow-handler.test.d.ts +2 -0
  70. package/lib/cloud-connection/shadow-handler.test.d.ts.map +1 -0
  71. package/lib/cloud-connection/shadow-handler.test.js +321 -0
  72. package/lib/cloud-connection/shadow-handler.test.js.map +1 -0
  73. package/lib/cloud-connection/shadow.d.ts +16 -0
  74. package/lib/cloud-connection/shadow.d.ts.map +1 -0
  75. package/lib/cloud-connection/shadow.js +36 -0
  76. package/lib/cloud-connection/shadow.js.map +1 -0
  77. package/lib/device-control/device-control.d.ts.map +1 -1
  78. package/lib/device-control/device-control.js +1 -0
  79. package/lib/device-control/device-control.js.map +1 -1
  80. package/lib/docker/docker-cmd.js +1 -1
  81. package/lib/docker/docker-compose-cmd.d.ts.map +1 -1
  82. package/lib/docker/docker-compose-cmd.js +1 -1
  83. package/lib/docker/docker-compose-cmd.js.map +1 -1
  84. package/lib/endpoints.js +10 -10
  85. package/lib/endpoints.js.map +1 -1
  86. package/lib/environment.d.ts +1 -0
  87. package/lib/environment.d.ts.map +1 -1
  88. package/lib/environment.js +2 -1
  89. package/lib/environment.js.map +1 -1
  90. package/lib/infrastructure/agent-config.d.ts +15 -58
  91. package/lib/infrastructure/agent-config.d.ts.map +1 -1
  92. package/lib/infrastructure/agent-config.js +22 -15
  93. package/lib/infrastructure/agent-config.js.map +1 -1
  94. package/lib/infrastructure/agent-config.test.js +25 -23
  95. package/lib/infrastructure/agent-config.test.js.map +1 -1
  96. package/lib/infrastructure/system-id.d.ts +2 -0
  97. package/lib/infrastructure/system-id.d.ts.map +1 -0
  98. package/lib/infrastructure/system-id.js +21 -0
  99. package/lib/infrastructure/system-id.js.map +1 -0
  100. package/lib/infrastructure/tokens-and-device-cfg.d.ts +4 -0
  101. package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -0
  102. package/lib/infrastructure/tokens-and-device-cfg.js +27 -0
  103. package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -0
  104. package/lib/infrastructure/urls.d.ts.map +1 -1
  105. package/lib/infrastructure/urls.js +3 -3
  106. package/lib/infrastructure/urls.js.map +1 -1
  107. package/lib/local-connection/rabbitmq-connection.d.ts +4 -0
  108. package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -0
  109. package/lib/local-connection/rabbitmq-connection.js +58 -0
  110. package/lib/local-connection/rabbitmq-connection.js.map +1 -0
  111. package/lib/root.d.ts.map +1 -1
  112. package/lib/root.js +2 -7
  113. package/lib/root.js.map +1 -1
  114. package/lib/subcommands/app/app.d.ts +2 -1
  115. package/lib/subcommands/app/app.d.ts.map +1 -1
  116. package/lib/subcommands/app/app.js +112 -77
  117. package/lib/subcommands/app/app.js.map +1 -1
  118. package/lib/subcommands/app/index.js +2 -2
  119. package/lib/subcommands/device/clean.d.ts +2 -0
  120. package/lib/subcommands/device/clean.d.ts.map +1 -0
  121. package/lib/subcommands/device/clean.js +29 -0
  122. package/lib/subcommands/device/clean.js.map +1 -0
  123. package/lib/subcommands/device/device.d.ts +1 -1
  124. package/lib/subcommands/device/device.d.ts.map +1 -1
  125. package/lib/subcommands/device/device.js +44 -33
  126. package/lib/subcommands/device/device.js.map +1 -1
  127. package/lib/subcommands/device/index.d.ts.map +1 -1
  128. package/lib/subcommands/device/index.js +2 -1
  129. package/lib/subcommands/device/index.js.map +1 -1
  130. package/lib/subcommands/get-model-package.js +5 -5
  131. package/lib/subcommands/index.d.ts +0 -1
  132. package/lib/subcommands/index.d.ts.map +1 -1
  133. package/lib/subcommands/index.js +1 -1
  134. package/lib/subcommands/login.d.ts +0 -1
  135. package/lib/subcommands/login.d.ts.map +1 -1
  136. package/lib/subcommands/login.js +6 -14
  137. package/lib/subcommands/login.js.map +1 -1
  138. package/lib/util/clean-certs.d.ts +2 -0
  139. package/lib/util/clean-certs.d.ts.map +1 -0
  140. package/lib/util/clean-certs.js +16 -0
  141. package/lib/util/clean-certs.js.map +1 -0
  142. package/lib/util/directories.d.ts +16 -15
  143. package/lib/util/directories.d.ts.map +1 -1
  144. package/lib/util/directories.js +45 -26
  145. package/lib/util/directories.js.map +1 -1
  146. package/lib/util/fetch-with-timeout.d.ts +4 -0
  147. package/lib/util/fetch-with-timeout.d.ts.map +1 -0
  148. package/lib/util/fetch-with-timeout.js +15 -0
  149. package/lib/util/fetch-with-timeout.js.map +1 -0
  150. package/lib/util/get-device-id.d.ts +1 -1
  151. package/lib/util/get-device-id.d.ts.map +1 -1
  152. package/lib/util/get-device-id.js +14 -19
  153. package/lib/util/get-device-id.js.map +1 -1
  154. package/lib/util/http-client.d.ts +1 -1
  155. package/lib/util/http-client.d.ts.map +1 -1
  156. package/lib/util/http-client.js +10 -8
  157. package/lib/util/http-client.js.map +1 -1
  158. package/lib/util/logger.d.ts.map +1 -1
  159. package/lib/util/logger.js +4 -5
  160. package/lib/util/logger.js.map +1 -1
  161. package/lib/util/require-logged-in-and-paid-plan.d.ts +2 -0
  162. package/lib/util/require-logged-in-and-paid-plan.d.ts.map +1 -0
  163. package/lib/util/require-logged-in-and-paid-plan.js +18 -0
  164. package/lib/util/require-logged-in-and-paid-plan.js.map +1 -0
  165. package/lib/util/run-in-dir.d.ts.map +1 -1
  166. package/lib/util/run-in-dir.js +1 -0
  167. package/lib/util/run-in-dir.js.map +1 -1
  168. package/lib/util/timer.d.ts +2 -0
  169. package/lib/util/timer.d.ts.map +1 -0
  170. package/lib/util/timer.js +6 -0
  171. package/lib/util/timer.js.map +1 -0
  172. package/package.json +32 -35
  173. package/readme.md +100 -89
  174. package/src/application-control/backup.ts +11 -6
  175. package/src/application-control/config.ts +75 -13
  176. package/src/application-control/environment-variables.ts +3 -3
  177. package/src/application-control/index.ts +18 -11
  178. package/src/application-control/install.ts +82 -78
  179. package/src/application-control/models.ts +104 -72
  180. package/src/application-control/status.ts +29 -40
  181. package/src/application-control/utils.ts +66 -38
  182. package/src/cloud-connection/app-install-status.ts +62 -0
  183. package/src/cloud-connection/bootstrap-provision.ts +40 -0
  184. package/src/cloud-connection/cmd-status.ts +52 -0
  185. package/src/cloud-connection/device-agent-cloud-connection.ts +302 -526
  186. package/src/cloud-connection/device-agent.ts +31 -38
  187. package/src/cloud-connection/live-updates-handler.ts +226 -0
  188. package/src/cloud-connection/messages.ts +39 -0
  189. package/src/cloud-connection/passthrough-handler.ts +67 -0
  190. package/src/cloud-connection/publisher.ts +86 -0
  191. package/src/cloud-connection/shadow-handler.test.ts +361 -0
  192. package/src/cloud-connection/shadow-handler.ts +175 -0
  193. package/src/cloud-connection/shadow.ts +50 -0
  194. package/src/device-control/device-control.ts +1 -0
  195. package/src/docker/docker-cmd.ts +1 -1
  196. package/src/docker/docker-compose-cmd.ts +5 -2
  197. package/src/endpoints.ts +9 -9
  198. package/src/environment.ts +11 -3
  199. package/src/infrastructure/agent-config.test.ts +33 -29
  200. package/src/infrastructure/agent-config.ts +57 -22
  201. package/src/infrastructure/system-id.ts +18 -0
  202. package/src/infrastructure/tokens-and-device-cfg.ts +34 -0
  203. package/src/infrastructure/urls.ts +4 -2
  204. package/src/local-connection/rabbitmq-connection.ts +53 -0
  205. package/src/root.ts +2 -8
  206. package/src/subcommands/app/app.ts +119 -83
  207. package/src/subcommands/app/index.ts +3 -3
  208. package/src/subcommands/device/clean.ts +26 -0
  209. package/src/subcommands/device/device.ts +67 -54
  210. package/src/subcommands/device/index.ts +2 -1
  211. package/src/subcommands/get-model-package.ts +5 -5
  212. package/src/subcommands/index.ts +1 -1
  213. package/src/subcommands/login.ts +6 -14
  214. package/src/util/clean-certs.ts +12 -0
  215. package/src/util/directories.ts +68 -52
  216. package/src/util/fetch-with-timeout.ts +18 -0
  217. package/src/util/get-device-id.ts +16 -18
  218. package/src/util/http-client.ts +18 -13
  219. package/src/util/logger.ts +6 -6
  220. package/src/util/require-logged-in-and-paid-plan.ts +16 -0
  221. package/src/util/run-in-dir.ts +2 -1
  222. package/src/util/timer.ts +1 -0
  223. package/lib/infrastructure/certificates-and-tokens.d.ts +0 -6
  224. package/lib/infrastructure/certificates-and-tokens.d.ts.map +0 -1
  225. package/lib/infrastructure/certificates-and-tokens.js +0 -43
  226. package/lib/infrastructure/certificates-and-tokens.js.map +0 -1
  227. package/src/infrastructure/certificates-and-tokens.ts +0 -53
@@ -1,62 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runDeviceAgentCloudInterface = exports.DeviceAgentCloudConnection = void 0;
4
- const awsIot = require("aws-iot-device-sdk");
4
+ // eslint-disable-next-line
5
+ const awsIot = require('aws-iot-device-sdk');
5
6
  const urls_1 = require("../infrastructure/urls");
6
7
  const fs_1 = require("fs");
7
8
  const directories_1 = require("../util/directories");
8
- const device_agent_1 = require("./device-agent");
9
- const sleep_1 = require("../util/sleep");
10
- const status_1 = require("../application-control/status");
11
- const install_1 = require("../application-control/install");
12
9
  const device_agent_schemas_1 = require("@alwaysai/device-agent-schemas");
13
10
  const get_device_id_1 = require("../util/get-device-id");
14
- const util_1 = require("alwaysai/lib/util");
15
- const device_control_1 = require("../device-control/device-control");
11
+ const logger_1 = require("../util/logger");
16
12
  const agent_config_1 = require("../infrastructure/agent-config");
17
- const utils_1 = require("../application-control/utils");
18
- const models_1 = require("../application-control/models");
19
- const config_1 = require("../application-control/config");
13
+ const application_control_1 = require("../application-control");
14
+ const shadow_handler_1 = require("./shadow-handler");
15
+ const publisher_1 = require("./publisher");
16
+ const live_updates_handler_1 = require("./live-updates-handler");
17
+ const bootstrap_provision_1 = require("./bootstrap-provision");
18
+ const app_install_status_1 = require("./app-install-status");
19
+ const cmd_status_1 = require("./cmd-status");
20
+ const passthrough_handler_1 = require("./passthrough-handler");
21
+ const environment_1 = require("../environment");
20
22
  class DeviceAgentCloudConnection {
23
+ // Public Methods
21
24
  constructor() {
22
- this.clientId = (0, get_device_id_1.getDeviceId)();
25
+ this.device = awsIot.device;
26
+ this.clientId = (0, get_device_id_1.getDeviceUuid)();
23
27
  this.host = (0, urls_1.getIoTCoreEndpointUrl)();
24
- this.liveUpdatesAlive = {
25
- [device_agent_schemas_1.keyMirrors.agentMessageType.device_stats]: false,
26
- [device_agent_schemas_1.keyMirrors.agentMessageType.app_state]: false,
27
- [device_agent_schemas_1.keyMirrors.agentMessageType.app_logs]: false,
28
- };
29
- this.liveUpdatesSleepIntervals = {
30
- [device_agent_schemas_1.keyMirrors.agentMessageType.device_stats]: 5000,
31
- [device_agent_schemas_1.keyMirrors.agentMessageType.app_state]: 5000,
32
- [device_agent_schemas_1.keyMirrors.agentMessageType.app_logs]: 5000,
33
- [device_agent_schemas_1.keyMirrors.agentMessageType.app_install_status]: 5000,
34
- };
35
- this.appLogStreams = new Set();
36
- this.shadowPrefix = `$aws/things/${this.clientId}/shadow/name/`;
37
- this.shadowTopics = {
38
- projects: {
39
- updateDelta: `${this.shadowPrefix}projects/update/delta`,
40
- getAccepted: `${this.shadowPrefix}projects/get/accepted`,
41
- },
42
- };
43
- this.toCloudTopic = (0, device_agent_schemas_1.getCloudTopic)(this.clientId);
44
- this.toClientTopic = (0, device_agent_schemas_1.getClientTopic)(this.clientId);
45
28
  this.toDeviceTopic = (0, device_agent_schemas_1.getDeviceTopic)(this.clientId);
46
- // must be arrow function due to this context when function is passed as param
47
- this.getAppInstallStatusMessage = async () => {
48
- const appInstallStatus = this.getAppInstallStatus();
49
- const appInstallStatusMessage = {
50
- messageType: device_agent_schemas_1.keyMirrors.agentMessageType.app_install_status,
51
- appInstallStatus,
52
- };
53
- return appInstallStatusMessage;
54
- };
29
+ // FIXME: Add support for multiple simultaneous project updates
30
+ this.newAppCfgQueue = [];
55
31
  this.handleDeviceCommand = async (packet) => {
56
32
  // TODO
57
33
  };
58
- // Public Methods
59
- this.device = awsIot.device;
60
34
  this.device = awsIot.device({
61
35
  keyPath: (0, directories_1.getPrivateKeyFilePath)(),
62
36
  certPath: (0, directories_1.getCertificateFilePath)(),
@@ -64,262 +38,145 @@ class DeviceAgentCloudConnection {
64
38
  clientId: this.clientId,
65
39
  host: this.host,
66
40
  port: 8883,
41
+ keepalive: 1 // time before re-connect attempt on dropped connection, default is 400 seconds
67
42
  });
68
- this.device.subscribe(this.toDeviceTopic);
69
- this.device.subscribe(this.shadowTopics.projects.getAccepted);
70
- this.device.subscribe(this.shadowTopics.projects.updateDelta);
71
- }
72
- // device shadow utils
73
- getShadowPrefix() {
74
- return this.shadowPrefix;
75
- }
76
- async handleNamedShadowUpdate({ payload }) {
77
- const delta = JSON.parse(payload);
78
- const deltaKeys = Object.keys(delta);
79
- for (const projectId of deltaKeys) {
80
- const projectShadow = delta[projectId];
81
- if (projectShadow.appConfig) {
82
- const appConfig = projectShadow.appConfig;
83
- const appDir = (0, utils_1.getAppDir)(projectId);
84
- await (0, config_1.updateAppConfig)(projectId, appConfig);
85
- if (appConfig.models) {
86
- this.publishCloudRequest({
87
- messageType: device_agent_schemas_1.keyMirrors.agentMessageType.signed_urls_request,
88
- modelsOnlyUrlsRequest: {
89
- projectId,
90
- models: appConfig.models,
91
- },
92
- });
93
- }
94
- if (appConfig.scripts && !appConfig.models) {
95
- const appState = await (0, status_1.getAppStatus)({ projectId });
96
- await (0, utils_1.buildApp)({ appDir });
97
- if (appState.services.length &&
98
- appState.services[0].state !== device_agent_schemas_1.keyMirrors.appState.stopped) {
99
- (0, status_1.restartApp)({ projectId });
100
- }
101
- await this.publishReportedState(projectId);
102
- }
103
- }
104
- }
105
- }
106
- async startAppLogStream(projectId) {
107
- this.appLogStreams.add(projectId);
108
- const readable = await (0, status_1.getAppLogs)({
109
- projectId,
110
- args: ["--tail", "100", "--no-log-prefix"],
111
- });
112
- readable.on("data", (chunk) => {
113
- if (!this.appLogStreams.has(projectId)) {
114
- // why doesn't typescript know about this function?
115
- // @ts-ignore
116
- readable.destroy();
117
- util_1.logger.info(`App log stream terminated for project ${projectId}`);
118
- return;
119
- }
120
- const logStr = chunk.toString();
121
- const message = {
122
- messageType: device_agent_schemas_1.keyMirrors.agentMessageType.app_logs,
123
- appLogs: {
124
- projectId,
125
- logChunk: logStr,
126
- },
127
- };
128
- const packet = this.buildMessagePacket(this.getClientId(), this.toClientTopic, message);
129
- this.publishMessage(this.toClientTopic, JSON.stringify(packet));
130
- });
131
- readable.on("error", (error) => {
132
- util_1.logger.error(`App log stream terminated for project ${projectId}: ${error}`);
133
- });
134
- readable.on("finished", () => {
135
- util_1.logger.info(`App logs finished piping for project ${projectId}`);
136
- });
137
- }
138
- // must contain app release hash
139
- initAppInstallStatus(installationStatus) {
140
- this.appInstallStatus = installationStatus;
141
- }
142
- updateAppInstallStatus(installationStatus) {
143
- this.appInstallStatus.status = installationStatus.status;
144
- this.appInstallStatus.message = installationStatus.message;
145
- }
146
- getAppInstallStatus() {
147
- return this.appInstallStatus;
148
- }
149
- // Message Builders
150
- buildMessagePacket(deviceId, topic, payload) {
151
- const packet = {
152
- timestamp: new Date().toUTCString(),
153
- deviceId,
154
- topic,
155
- payload,
156
- };
157
- return packet;
158
- }
159
- async getAppStateMessage() {
160
- const appStateMessage = [];
161
- const apps = await (0, agent_config_1.AgentConfigFile)().getReadyApps();
162
- for (const app of apps) {
163
- const projectId = app.projectId;
164
- const status = await (0, status_1.getAppStatus)({ projectId });
165
- appStateMessage.push(status);
166
- }
167
- const appStatePackage = {
168
- messageType: device_agent_schemas_1.keyMirrors.agentMessageType.app_state,
169
- appState: appStateMessage,
170
- };
171
- return appStatePackage;
172
- }
173
- async getDeviceStatsMessage() {
174
- const cpuUsage = await (0, device_control_1.getCpuUtil)();
175
- const diskUtil = await (0, device_control_1.getDiskUtil)();
176
- const memUtil = await (0, device_control_1.getMemUtil)();
177
- const deviceStatsMessage = {
178
- messageType: device_agent_schemas_1.keyMirrors.agentMessageType.device_stats,
179
- deviceStats: {
180
- cpuUsage,
181
- diskUtil,
182
- usedMemoryPercentage: memUtil,
183
- },
184
- };
185
- return deviceStatsMessage;
186
- }
187
- async startPublishingLiveUpdates(topic, messageType, getMessageData) {
188
- while (true) {
189
- try {
190
- const message = await getMessageData();
191
- const packet = this.buildMessagePacket(this.getClientId(), topic, message);
192
- this.publishMessage(topic, JSON.stringify(packet));
193
- }
194
- catch (e) {
195
- util_1.logger.error(`Error publishing live updates for ${messageType}: ${e.message}`);
196
- break;
197
- }
198
- if (!this.continuePublishing(messageType)) {
199
- util_1.logger.info(`Turned off live updates for ${messageType}`);
200
- break;
201
- }
202
- await (0, sleep_1.default)(this.getLiveUpdatesInterval(messageType));
203
- }
204
- }
205
- continuePublishing(flag) {
206
- switch (flag) {
207
- case device_agent_schemas_1.keyMirrors.agentMessageType.device_stats:
208
- case device_agent_schemas_1.keyMirrors.agentMessageType.app_state:
209
- return this.liveUpdatesAlive[flag];
210
- case device_agent_schemas_1.keyMirrors.agentMessageType.app_install_status:
211
- return (this.appInstallStatus.status ===
212
- device_agent_schemas_1.keyMirrors.appInstallStatus.in_progress);
213
- default:
214
- util_1.logger.error(`Unrecognized publishable flag ${flag}`);
215
- return false;
216
- }
217
- }
218
- getLiveUpdatesInterval(flag) {
219
- const exists = this.liveUpdatesSleepIntervals[flag];
220
- if (exists) {
221
- return exists;
222
- }
223
- util_1.logger.error(`Unrecognized live updates flag ${flag}`);
224
- return -1;
225
- }
226
- setLiveUpdates(toggles) {
227
- if (toggles.deviceStats) {
228
- this.liveUpdatesAlive.device_stats = toggles.deviceStats;
229
- }
230
- if (toggles.appState) {
231
- this.liveUpdatesAlive.app_state = toggles.appState;
232
- }
43
+ this.publisher = new publisher_1.Publisher(this.device, this.clientId);
44
+ this.shadowHandler = new shadow_handler_1.ShadowHandler(this.clientId, this.publisher);
45
+ this.cmdStatusMgr = new cmd_status_1.CmdStatusManager();
46
+ this.appInstallStatusMgr = new app_install_status_1.AppInstallStatusManager();
47
+ this.liveUpdatesHandler = new live_updates_handler_1.LiveUpdatesHandler(this.publisher, this.appInstallStatusMgr);
48
+ this.subscribe(this.toDeviceTopic);
49
+ this.subscribe(this.shadowHandler.shadowTopics.projects.getAccepted);
50
+ this.subscribe(this.shadowHandler.shadowTopics.projects.updateDelta);
233
51
  }
234
52
  handleAppStateControl(payload) {
235
53
  const { baseCommand, projectId } = payload;
236
54
  switch (baseCommand) {
237
55
  case device_agent_schemas_1.keyMirrors.appStateControl.start:
238
- (0, status_1.startApp)({ projectId });
56
+ (0, application_control_1.startApp)({ projectId });
239
57
  break;
240
58
  case device_agent_schemas_1.keyMirrors.appStateControl.stop:
241
- (0, status_1.stopApp)({ projectId });
59
+ (0, application_control_1.stopApp)({ projectId });
242
60
  break;
243
61
  case device_agent_schemas_1.keyMirrors.appStateControl.restart:
244
- (0, status_1.restartApp)({ projectId });
62
+ (0, application_control_1.restartApp)({ projectId });
245
63
  break;
246
64
  }
247
65
  }
248
66
  handleAppVersionControl(payload) {
249
- const { projectId, appReleaseHash } = payload;
250
- const signedUrlsRequest = { projectId, appReleaseHash };
251
- this.publishCloudRequest({
252
- messageType: device_agent_schemas_1.keyMirrors.agentMessageType.signed_urls_request,
253
- signedUrlsRequest,
254
- });
67
+ switch (payload.baseCommand) {
68
+ case device_agent_schemas_1.keyMirrors.appVersionControl.install: {
69
+ const { projectId, appReleaseHash } = payload;
70
+ this.cmdStatusMgr.update(projectId, 'in_progress');
71
+ const signedUrlsRequest = { projectId, appReleaseHash };
72
+ this.publishCloudRequest({
73
+ messageType: device_agent_schemas_1.keyMirrors.agentMessageType.signed_urls_request,
74
+ signedUrlsRequest
75
+ });
76
+ break;
77
+ }
78
+ default:
79
+ logger_1.logger.warn(`Ignore App Version Control packet: ${JSON.stringify(payload, null, 2)}`);
80
+ }
255
81
  }
256
82
  handleAgentCommand(message) {
257
83
  switch (message.messageType) {
258
84
  case device_agent_schemas_1.keyMirrors.clientMessageType.live_state_updates:
259
- this.liveUpdatesBroker(message.liveUpdatesToggles);
85
+ this.liveUpdatesHandler.update(message.liveUpdatesToggles);
260
86
  break;
261
87
  default:
262
- util_1.logger.error(`Invalid agent action message type from message '${message}'`);
88
+ logger_1.logger.error(`Invalid agent action message type from message '${message}'`);
263
89
  }
264
90
  }
265
- restartLiveUpdatesTimeout() {
266
- clearTimeout(this.liveUpdatesTimeout);
267
- this.liveUpdatesTimeout = setTimeout(() => {
268
- this.setLiveUpdates({
269
- deviceStats: false,
270
- appState: false,
271
- });
272
- this.appLogStreams.clear();
273
- // TODO: Make constant, not hard coded
274
- }, 600000); // 10 min
91
+ async publishCloudRequest(payload) {
92
+ this.publisher.publishToCloud(payload);
275
93
  }
276
- async liveUpdatesBroker({ deviceStats, appState, appLogs, }) {
277
- this.restartLiveUpdatesTimeout();
278
- if (deviceStats !== undefined) {
279
- this.liveUpdatesAlive.device_stats = deviceStats;
280
- if (deviceStats) {
281
- this.startPublishingLiveUpdates(this.toClientTopic, device_agent_schemas_1.keyMirrors.agentMessageType.device_stats, this.getDeviceStatsMessage);
282
- }
94
+ subscribe(topic) {
95
+ logger_1.logger.info(`Subscribing to ${topic}`);
96
+ this.device.subscribe(topic);
97
+ }
98
+ // eslint-disable-next-line
99
+ async atomicApplicationUpdate(func, args, projectId, appReleaseHash) {
100
+ this.appInstallStatusMgr.update(appReleaseHash, device_agent_schemas_1.keyMirrors.appInstallStatus.in_progress);
101
+ this.liveUpdatesHandler.update({
102
+ appInstallStatus: { toggle: true, appReleaseHash }
103
+ });
104
+ // Install the app and models
105
+ try {
106
+ const out = await func(...args);
107
+ this.appInstallStatusMgr.update(appReleaseHash, device_agent_schemas_1.keyMirrors.appInstallStatus.success);
108
+ this.liveUpdatesHandler.update({
109
+ appInstallStatus: { toggle: false, appReleaseHash }
110
+ });
111
+ this.cmdStatusMgr.update(projectId, 'idle');
112
+ // update app config shadow for project
113
+ await this.shadowHandler.publishAppState(projectId);
114
+ return out;
283
115
  }
284
- if (appState !== undefined) {
285
- this.liveUpdatesAlive.app_state = appState;
286
- if (appState) {
287
- this.startPublishingLiveUpdates(this.toClientTopic, device_agent_schemas_1.keyMirrors.agentMessageType.app_state, this.getAppStateMessage);
288
- }
116
+ catch (e) {
117
+ logger_1.logger.error(e);
118
+ const message = e.message;
119
+ // uninstall the failed app to put system back in good state
120
+ await (0, application_control_1.uninstallApp)({ projectId });
121
+ this.appInstallStatusMgr.update(appReleaseHash, device_agent_schemas_1.keyMirrors.appInstallStatus.failure, message);
122
+ this.liveUpdatesHandler.update({
123
+ appInstallStatus: { toggle: false, appReleaseHash }
124
+ });
125
+ this.cmdStatusMgr.update(projectId, 'idle');
126
+ // delete shadow for project
127
+ this.shadowHandler.deleteProjectShadow(projectId);
289
128
  }
290
- if (appLogs !== undefined) {
291
- if (appLogs.toggle) {
292
- this.startAppLogStream(appLogs.projectId);
129
+ }
130
+ async handleAppConfigUpdates(appConfgUpdates) {
131
+ for (const appConfigUpdate of appConfgUpdates) {
132
+ const { projectId, newAppCfg, updatedModels } = appConfigUpdate;
133
+ this.cmdStatusMgr.update(projectId, 'in_progress');
134
+ if (updatedModels && Object.keys(updatedModels).length) {
135
+ // Publish request for model urls
136
+ this.newAppCfgQueue.push(newAppCfg);
137
+ logger_1.logger.debug(`Requesting presigned urls from cloud for model versions: ${JSON.stringify(updatedModels)}`);
138
+ this.publisher.publishToCloud({
139
+ messageType: device_agent_schemas_1.keyMirrors.agentMessageType.signed_urls_request,
140
+ modelsOnlyUrlsRequest: {
141
+ projectId,
142
+ models: updatedModels
143
+ }
144
+ });
293
145
  }
294
146
  else {
295
- this.appLogStreams.delete(appLogs.projectId);
147
+ // FIXME: do we need to send this up to the cloud?
148
+ // should it be something other than appReleaseHash?
149
+ const appReleaseHash = await (0, agent_config_1.AgentConfigFile)().getAppVersion({
150
+ projectId
151
+ });
152
+ await this.atomicApplicationUpdate(application_control_1.updateAppCfg, [
153
+ {
154
+ projectId,
155
+ appReleaseHash,
156
+ newAppCfg
157
+ }
158
+ ], projectId, appReleaseHash);
296
159
  }
297
160
  }
298
161
  }
299
- async publishReportedState(projectId) {
300
- const newAppCfg = await (0, utils_1.getAppConfig)(projectId);
301
- const packet = {
302
- state: {
303
- reported: {
304
- [projectId]: { appConfig: newAppCfg },
305
- },
306
- },
307
- };
308
- this.publishMessage(`${this.shadowPrefix}projects/update`, JSON.stringify(packet));
309
- }
310
- async publishCloudRequest(payload) {
311
- const topic = this.toCloudTopic;
312
- const deviceRequestPacket = this.buildMessagePacket(this.getClientId(), topic, payload);
313
- this.publishMessage(topic, JSON.stringify({ deviceRequestPacket }));
314
- }
315
162
  getClientId() {
316
163
  return this.clientId;
317
164
  }
318
- publishMessage(topic, message) {
319
- // TODO: topic validation
320
- this.device.publish(topic, message, (err) => { });
165
+ getToDeviceTopic() {
166
+ return this.toDeviceTopic;
167
+ }
168
+ getShadowTopics() {
169
+ return this.shadowHandler.shadowTopics;
321
170
  }
322
- async handleClientMessage({ topic, message, }) {
171
+ getCmdStatus(projectId) {
172
+ return this.cmdStatusMgr.getAppCmdStatus(projectId);
173
+ }
174
+ async handleClientMessage({ topic, message }) {
175
+ const valid = (0, device_agent_schemas_1.validateClientMessage)(message);
176
+ if (!valid) {
177
+ logger_1.logger.error(`Error validating message: ${JSON.stringify({ topic, message, errors: device_agent_schemas_1.validateClientMessage.errors }, null, 2)}`);
178
+ return;
179
+ }
323
180
  const payload = message.payload;
324
181
  switch (payload.messageType) {
325
182
  case device_agent_schemas_1.keyMirrors.clientMessageType.app_state_control: {
@@ -335,147 +192,114 @@ class DeviceAgentCloudConnection {
335
192
  break;
336
193
  }
337
194
  case device_agent_schemas_1.keyMirrors.clientMessageType.app_install_cloud_response: {
338
- const { projectId, appReleaseHash, appInstallPayload, modelsInstallPayload, } = payload.appInstallCloudResponse;
339
- this.initAppInstallStatus({
340
- status: device_agent_schemas_1.keyMirrors.appInstallStatus.in_progress,
341
- appReleaseHash,
342
- });
343
- this.startPublishingLiveUpdates(this.toClientTopic, device_agent_schemas_1.keyMirrors.agentMessageType.app_install_status, this.getAppInstallStatusMessage);
344
- // Install the app and models
345
- try {
346
- const signedUrlsPayload = {
347
- appInstallPayload,
348
- modelsInstallPayload,
349
- };
350
- await (0, install_1.installApp)({
351
- projectId,
352
- appReleaseHash,
353
- signedUrlsPayload,
354
- });
355
- this.updateAppInstallStatus({
356
- status: device_agent_schemas_1.keyMirrors.appInstallStatus.success,
357
- });
358
- // update app config shadow for project
359
- await this.publishReportedState(projectId);
360
- }
361
- catch (e) {
362
- util_1.logger.error(e);
363
- const message = e.message;
364
- // uninstall the failed app to put system back in good state
365
- await (0, install_1.uninstallApp)({ projectId });
366
- this.updateAppInstallStatus({
367
- status: device_agent_schemas_1.keyMirrors.appInstallStatus.failure,
368
- message,
369
- });
370
- // delete shadow for project
371
- this.publishMessage(`${this.shadowPrefix}${projectId}/delete`, "");
372
- }
195
+ const { projectId, appReleaseHash, appInstallPayload, modelsInstallPayload } = payload.appInstallCloudResponse;
196
+ const signedUrlsPayload = {
197
+ appInstallPayload,
198
+ modelsInstallPayload
199
+ };
200
+ await this.atomicApplicationUpdate(application_control_1.installApp, [{ projectId, appReleaseHash, signedUrlsPayload }], projectId, appReleaseHash);
373
201
  break;
374
202
  }
375
203
  case device_agent_schemas_1.keyMirrors.clientMessageType.models_install_cloud_response: {
376
204
  const { projectId, newModels } = payload.modelsInstallCloudResponse;
377
- try {
378
- await (0, models_1.updateModelsWithPresignedUrls)(projectId, newModels);
379
- await this.publishReportedState(projectId);
380
- }
381
- catch (e) {
382
- util_1.logger.error(e);
205
+ const appReleaseHash = await (0, agent_config_1.AgentConfigFile)().getAppVersion({
206
+ projectId
207
+ });
208
+ const newAppCfg = this.newAppCfgQueue.shift();
209
+ if (newAppCfg === undefined) {
210
+ logger_1.logger.error('Unknown error while updating models via application config! No config present for model update.');
211
+ return;
383
212
  }
213
+ await this.atomicApplicationUpdate(application_control_1.updateModelsWithPresignedUrls, [
214
+ {
215
+ projectId,
216
+ modelInstallPayloads: newModels,
217
+ newAppCfg,
218
+ appReleaseHash
219
+ }
220
+ ], projectId, appReleaseHash);
384
221
  break;
385
222
  }
386
223
  default:
387
- util_1.logger.error(`Invalid Client Message '${JSON.stringify(payload)}'`);
224
+ logger_1.logger.error(`Invalid client message: '${JSON.stringify({ topic, message }, null, 2)}'`);
388
225
  }
389
226
  }
390
- async handleShadowTopic({ topic, payload, }) {
391
- const shadowName = topic.split("/")[5];
392
- const message = JSON.parse(payload);
393
- if (topic === this.shadowTopics.projects.updateDelta) {
394
- this.handleNamedShadowUpdate({ payload });
395
- }
396
- else if (topic === this.shadowTopics.projects.getAccepted) {
397
- if (message.delta) {
398
- this.handleNamedShadowUpdate({
399
- payload: JSON.stringify(message.delta),
227
+ async handleMessage(topic, message) {
228
+ switch (topic) {
229
+ case this.shadowHandler.shadowTopics.projects.getAccepted:
230
+ case this.shadowHandler.shadowTopics.projects.updateDelta: {
231
+ const appConfigUpdates = await this.shadowHandler.handleShadowTopic({
232
+ topic,
233
+ payload: message.state
400
234
  });
235
+ await this.handleAppConfigUpdates(appConfigUpdates);
236
+ break;
401
237
  }
402
- else {
403
- util_1.logger.info(`No delta updates in shadow ${shadowName}`);
404
- }
238
+ case this.toDeviceTopic:
239
+ this.handleClientMessage({
240
+ topic,
241
+ message
242
+ });
243
+ break;
244
+ default:
245
+ logger_1.logger.error(`Unexpected topic, ignoring! ${topic}`);
405
246
  }
406
247
  }
248
+ async setupHandlers() {
249
+ this.device.on('connect', (connack) => {
250
+ logger_1.logger.info('Device Agent has connected to the cloud');
251
+ this.shadowHandler.getShadowUpdates();
252
+ });
253
+ this.device.on('disconnect', () => {
254
+ logger_1.logger.warn('Device Agent has been disconnected from the cloud');
255
+ });
256
+ this.device.on('reconnect', () => {
257
+ logger_1.logger.info(`Device Agent attempting to re-connect ${new Date().toLocaleString()}`);
258
+ });
259
+ this.device.on('error', function (error) {
260
+ const errorString = error.message.toString();
261
+ logger_1.logger.error(`${errorString}`);
262
+ });
263
+ this.device.on('message', async (topic, payload) => {
264
+ try {
265
+ const jsonPacket = JSON.parse(payload);
266
+ logger_1.logger.debug(`Received message: ${JSON.stringify({ topic, jsonPacket }, null, 2)}`);
267
+ await this.handleMessage(topic, jsonPacket);
268
+ }
269
+ catch (error) {
270
+ logger_1.logger.error(`Error parsing message: ${error}`);
271
+ }
272
+ });
273
+ this.device.on('offline', () => {
274
+ logger_1.logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
275
+ });
276
+ }
277
+ stop() {
278
+ this.device.end();
279
+ }
407
280
  }
408
281
  exports.DeviceAgentCloudConnection = DeviceAgentCloudConnection;
409
282
  async function runDeviceAgentCloudInterface() {
410
- switch ((0, fs_1.existsSync)((0, directories_1.getCertificateFilePath)())) {
411
- case true:
412
- {
413
- const deviceAgent = new DeviceAgentCloudConnection();
414
- deviceAgent.device.on("connect", function (connack) {
415
- util_1.logger.info("Device Agent has connected to the cloud");
416
- // Get shadow updates
417
- deviceAgent.publishMessage(`${deviceAgent.getShadowPrefix()}projects/get`, "");
418
- });
419
- deviceAgent.device.on("disconnect", function () {
420
- util_1.logger.info("Device Agent has been disconnected from the cloud");
421
- });
422
- deviceAgent.device.on("message", function (topic, payload) {
423
- console.log(topic);
424
- console.log(JSON.parse(payload));
425
- try {
426
- const jsonPacket = JSON.parse(payload);
427
- if (jsonPacket.hasOwnProperty("state")) {
428
- deviceAgent.handleShadowTopic({
429
- topic,
430
- payload: JSON.stringify(jsonPacket.state),
431
- });
432
- }
433
- else {
434
- const valid = (0, device_agent_schemas_1.validateClientMessage)(jsonPacket);
435
- if (!valid) {
436
- console.error(JSON.stringify(device_agent_schemas_1.validateClientMessage.errors));
437
- }
438
- else {
439
- deviceAgent.handleClientMessage({
440
- topic,
441
- message: jsonPacket,
442
- });
443
- }
444
- }
445
- }
446
- catch (error) {
447
- util_1.logger.error(error);
448
- }
449
- });
450
- deviceAgent.device.on("packetsend", (packet) => {
451
- console.log({ packet: packet });
452
- });
453
- }
454
- break;
455
- case false: {
456
- //set timer
457
- const clientId = (0, get_device_id_1.getDeviceId)();
458
- const bootstrapConfig = {
459
- keyPath: directories_1.BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH,
460
- certPath: directories_1.BOOTSTRAP_DEVICE_CERTIFICATE_FILE_PATH,
461
- caPath: directories_1.AWS_ROOT_CERTIFICATE_FILE_PATH,
462
- clientId,
463
- host: (0, urls_1.getIoTCoreEndpointUrl)(),
464
- };
465
- const bootstrapAgent = new device_agent_1.BootstrapAgent(bootstrapConfig);
466
- bootstrapAgent.subscribeToAllTopics();
467
- bootstrapAgent.publishMessage("$aws/certificates/create/json", "");
468
- bootstrapAgent.device.on("connect", () => {
469
- console.log("Your device is being provisioned");
470
- });
471
- bootstrapAgent.device.on("message", (topic, payload) => {
472
- bootstrapAgent.handleAwsCertificateTopics(topic, payload);
473
- });
474
- bootstrapAgent.device.on("packetsend", (packet) => {
475
- console.log({ packet: packet.subscriptions });
476
- });
283
+ // FIXME: Check for KeyPath as well
284
+ if ((0, fs_1.existsSync)((0, directories_1.getCertificateFilePath)())) {
285
+ const deviceAgent = new DeviceAgentCloudConnection();
286
+ await deviceAgent.setupHandlers();
287
+ if (environment_1.ALWAYSAI_ANALYTICS_PASSTHROUGH === true) {
288
+ const publisher = deviceAgent.publisher;
289
+ const passthroughHandler = new passthrough_handler_1.PassthroughHandler(publisher);
290
+ await passthroughHandler.setup();
291
+ (0, passthrough_handler_1.runChannel)(passthroughHandler);
477
292
  }
478
293
  }
294
+ else if ((0, fs_1.existsSync)((0, directories_1.BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH)())) {
295
+ (0, bootstrap_provision_1.bootstrapProvision)();
296
+ }
297
+ else if ((0, fs_1.existsSync)((0, directories_1.BOOTSTRAP_CERTIFICATES_DIR_PATH)())) {
298
+ throw new Error("Device has not been created using 'aai-agent device init' or there has been an issue with device initialization");
299
+ }
300
+ else {
301
+ throw new Error("Set device agent to local mode and retry the 'aai-agent device init' command");
302
+ }
479
303
  }
480
304
  exports.runDeviceAgentCloudInterface = runDeviceAgentCloudInterface;
481
305
  //# sourceMappingURL=device-agent-cloud-connection.js.map