@alwaysai/device-agent 0.0.11 → 0.0.13

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