@alwaysai/device-agent 2.0.2-0 → 2.0.3

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 (151) hide show
  1. package/lib/application-control/config.js +1 -1
  2. package/lib/application-control/config.js.map +1 -1
  3. package/lib/application-control/install.d.ts.map +1 -1
  4. package/lib/application-control/install.js +7 -3
  5. package/lib/application-control/install.js.map +1 -1
  6. package/lib/cloud-connection/base-message-handler.d.ts.map +1 -1
  7. package/lib/cloud-connection/base-message-handler.js +5 -4
  8. package/lib/cloud-connection/base-message-handler.js.map +1 -1
  9. package/lib/cloud-connection/connection-manager.d.ts +3 -4
  10. package/lib/cloud-connection/connection-manager.d.ts.map +1 -1
  11. package/lib/cloud-connection/connection-manager.js +22 -40
  12. package/lib/cloud-connection/connection-manager.js.map +1 -1
  13. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +3 -1
  14. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  15. package/lib/cloud-connection/device-agent-cloud-connection.js +52 -46
  16. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  17. package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -1
  18. package/lib/cloud-connection/device-agent-message-handler.js +19 -18
  19. package/lib/cloud-connection/device-agent-message-handler.js.map +1 -1
  20. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  21. package/lib/cloud-connection/live-updates-handler.js +11 -4
  22. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  23. package/lib/cloud-connection/passthrough-handler.d.ts +3 -3
  24. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
  25. package/lib/cloud-connection/passthrough-handler.js +97 -74
  26. package/lib/cloud-connection/passthrough-handler.js.map +1 -1
  27. package/lib/cloud-connection/shadow-handler.js +3 -3
  28. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  29. package/lib/cloud-connection/shadow.d.ts.map +1 -1
  30. package/lib/cloud-connection/shadow.js +1 -1
  31. package/lib/cloud-connection/shadow.js.map +1 -1
  32. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  33. package/lib/cloud-connection/transaction-manager.js +17 -7
  34. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  35. package/lib/cloud-connection/transaction-manager.test.js +52 -44
  36. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  37. package/lib/device-control/device-control.d.ts.map +1 -1
  38. package/lib/device-control/device-control.js +13 -9
  39. package/lib/device-control/device-control.js.map +1 -1
  40. package/lib/docker/docker-compose.d.ts.map +1 -1
  41. package/lib/docker/docker-compose.js +1 -1
  42. package/lib/docker/docker-compose.js.map +1 -1
  43. package/lib/environment.d.ts +3 -0
  44. package/lib/environment.d.ts.map +1 -1
  45. package/lib/environment.js +12 -1
  46. package/lib/environment.js.map +1 -1
  47. package/lib/index.js +12 -0
  48. package/lib/index.js.map +1 -1
  49. package/lib/infrastructure/config-check-utility.js +2 -2
  50. package/lib/infrastructure/config-check-utility.js.map +1 -1
  51. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -1
  52. package/lib/infrastructure/legacy-migration/legacy-migration.js +6 -10
  53. package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -1
  54. package/lib/jobs/job-handler.d.ts +1 -1
  55. package/lib/jobs/job-handler.d.ts.map +1 -1
  56. package/lib/jobs/job-handler.js +4 -4
  57. package/lib/jobs/job-handler.js.map +1 -1
  58. package/lib/local-connection/rabbitmq-container.d.ts +6 -0
  59. package/lib/local-connection/rabbitmq-container.d.ts.map +1 -0
  60. package/lib/local-connection/rabbitmq-container.js +111 -0
  61. package/lib/local-connection/rabbitmq-container.js.map +1 -0
  62. package/lib/local-connection/rabbitmq-container.test.d.ts +2 -0
  63. package/lib/local-connection/rabbitmq-container.test.d.ts.map +1 -0
  64. package/lib/local-connection/rabbitmq-container.test.js +219 -0
  65. package/lib/local-connection/rabbitmq-container.test.js.map +1 -0
  66. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  67. package/lib/subcommands/app/analytics.js +2 -3
  68. package/lib/subcommands/app/analytics.js.map +1 -1
  69. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  70. package/lib/subcommands/app/env-vars.js +4 -6
  71. package/lib/subcommands/app/env-vars.js.map +1 -1
  72. package/lib/subcommands/app/models.d.ts.map +1 -1
  73. package/lib/subcommands/app/models.js +2 -3
  74. package/lib/subcommands/app/models.js.map +1 -1
  75. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  76. package/lib/subcommands/app/shadow.js +4 -6
  77. package/lib/subcommands/app/shadow.js.map +1 -1
  78. package/lib/subcommands/app/version.d.ts.map +1 -1
  79. package/lib/subcommands/app/version.js +6 -9
  80. package/lib/subcommands/app/version.js.map +1 -1
  81. package/lib/subcommands/device/clean.d.ts.map +1 -1
  82. package/lib/subcommands/device/clean.js +15 -17
  83. package/lib/subcommands/device/clean.js.map +1 -1
  84. package/lib/subcommands/device/index.d.ts.map +1 -1
  85. package/lib/subcommands/device/index.js +3 -1
  86. package/lib/subcommands/device/index.js.map +1 -1
  87. package/lib/subcommands/device/local-connection.d.ts +2 -0
  88. package/lib/subcommands/device/local-connection.d.ts.map +1 -0
  89. package/lib/subcommands/device/local-connection.js +17 -0
  90. package/lib/subcommands/device/local-connection.js.map +1 -0
  91. package/lib/subcommands/index.d.ts +4 -1
  92. package/lib/subcommands/index.d.ts.map +1 -1
  93. package/lib/subcommands/index.js +1 -3
  94. package/lib/subcommands/index.js.map +1 -1
  95. package/lib/util/check-for-updates.d.ts.map +1 -1
  96. package/lib/util/check-for-updates.js +2 -2
  97. package/lib/util/check-for-updates.js.map +1 -1
  98. package/lib/util/file.d.ts.map +1 -1
  99. package/lib/util/file.js +6 -1
  100. package/lib/util/file.js.map +1 -1
  101. package/lib/util/file.test.js +1 -1
  102. package/lib/util/file.test.js.map +1 -1
  103. package/lib/util/get-device-id.d.ts.map +1 -1
  104. package/lib/util/get-device-id.js +1 -1
  105. package/lib/util/get-device-id.js.map +1 -1
  106. package/package.json +2 -2
  107. package/readme.md +16 -4
  108. package/src/application-control/config.ts +1 -1
  109. package/src/application-control/install.ts +11 -5
  110. package/src/cloud-connection/base-message-handler.ts +10 -5
  111. package/src/cloud-connection/connection-manager.ts +23 -45
  112. package/src/cloud-connection/device-agent-cloud-connection.ts +97 -89
  113. package/src/cloud-connection/device-agent-message-handler.ts +10 -7
  114. package/src/cloud-connection/live-updates-handler.ts +12 -5
  115. package/src/cloud-connection/passthrough-handler.ts +79 -38
  116. package/src/cloud-connection/shadow-handler.ts +3 -3
  117. package/src/cloud-connection/shadow.ts +3 -1
  118. package/src/cloud-connection/transaction-manager.test.ts +60 -41
  119. package/src/cloud-connection/transaction-manager.ts +26 -12
  120. package/src/device-control/device-control.ts +23 -13
  121. package/src/docker/docker-compose.ts +3 -1
  122. package/src/environment.ts +17 -0
  123. package/src/index.ts +19 -0
  124. package/src/infrastructure/config-check-utility.ts +2 -2
  125. package/src/infrastructure/legacy-migration/legacy-migration.ts +8 -13
  126. package/src/jobs/job-handler.ts +4 -4
  127. package/src/local-connection/rabbitmq-container.test.ts +255 -0
  128. package/src/local-connection/rabbitmq-container.ts +151 -0
  129. package/src/subcommands/app/analytics.ts +2 -3
  130. package/src/subcommands/app/env-vars.ts +4 -6
  131. package/src/subcommands/app/models.ts +2 -3
  132. package/src/subcommands/app/shadow.ts +4 -6
  133. package/src/subcommands/app/version.ts +7 -8
  134. package/src/subcommands/device/clean.ts +20 -19
  135. package/src/subcommands/device/index.ts +3 -1
  136. package/src/subcommands/device/local-connection.ts +16 -0
  137. package/src/subcommands/index.ts +1 -3
  138. package/src/util/check-for-updates.ts +4 -2
  139. package/src/util/file.test.ts +1 -1
  140. package/src/util/file.ts +7 -1
  141. package/src/util/get-device-id.ts +3 -1
  142. package/lib/local-connection/rabbitmq-connection.d.ts +0 -7
  143. package/lib/local-connection/rabbitmq-connection.d.ts.map +0 -1
  144. package/lib/local-connection/rabbitmq-connection.js +0 -95
  145. package/lib/local-connection/rabbitmq-connection.js.map +0 -1
  146. package/lib/subcommands/rabbitmq-connection.d.ts +0 -2
  147. package/lib/subcommands/rabbitmq-connection.d.ts.map +0 -1
  148. package/lib/subcommands/rabbitmq-connection.js +0 -14
  149. package/lib/subcommands/rabbitmq-connection.js.map +0 -1
  150. package/src/local-connection/rabbitmq-connection.ts +0 -124
  151. package/src/subcommands/rabbitmq-connection.ts +0 -11
@@ -16,7 +16,8 @@ import {
16
16
  appCleanDocker,
17
17
  getPythonVenvPaths,
18
18
  createPythonVenv,
19
- installPythonReqs
19
+ installPythonReqs,
20
+ TargetHardware
20
21
  } from 'alwaysai/lib/core/app';
21
22
  import { DOCKER_IMAGE_ID_INITIAL_VALUE } from 'alwaysai/lib/constants';
22
23
  import { runInDir } from '../util/run-in-dir';
@@ -30,8 +31,10 @@ import {
30
31
  } from '../local-connection/constants';
31
32
  import { DOCKERFILE, PYTHON_REQUIREMENTS_FILE_NAME } from 'alwaysai/lib/paths';
32
33
  import { downloadToFile } from '../util/file';
34
+ import { ALWAYSAI_TARGET_HW_OVERRIDE, parseTargetHW } from '../environment';
33
35
  import { setEnvInternal } from './environment-variables';
34
36
  import { AppConfig } from '@alwaysai/app-configuration-schemas';
37
+ import { CliTerseError } from '@alwaysai/alwayscli';
35
38
 
36
39
  type SignedUrlPayloadType = {
37
40
  appInstallPayload: {
@@ -80,7 +83,7 @@ export async function installApp(props: {
80
83
  await stopApp({ projectId });
81
84
  } catch (e) {
82
85
  logger.error(
83
- `Could not stop the application. Old container might still be present after installation.\n${stringifyError(
86
+ `Could not stop the application. Old container might still be present after installation. Error:\n${stringifyError(
84
87
  e
85
88
  )}`
86
89
  );
@@ -234,15 +237,18 @@ async function checkValidProjectFiles({ appDir }) {
234
237
  if (!AppJsonFile(appDir).readIfExists()) {
235
238
  throw new Error('App JSON file does not exist!');
236
239
  }
237
-
238
240
  // write target json
239
241
  if (!fs.existsSync(path.join(appDir, DOCKERFILE))) {
240
242
  throw new Error('No Dockerfile found for application!');
241
243
  }
244
+ const targetHw: TargetHardware =
245
+ parseTargetHW(ALWAYSAI_TARGET_HW_OVERRIDE) ??
246
+ (await getTargetHardwareType({}));
247
+ logger.debug(`Target Hardware selected to: ${targetHw}`);
242
248
  TargetJsonFile(appDir).write({
243
249
  targetProtocol: 'docker:',
244
250
  dockerImageId: DOCKER_IMAGE_ID_INITIAL_VALUE,
245
- targetHardware: await getTargetHardwareType({})
251
+ targetHardware: targetHw
246
252
  });
247
253
  }
248
254
 
@@ -260,7 +266,7 @@ export async function uninstallApp(props: {
260
266
  await stopApp({ projectId });
261
267
  } catch (e) {
262
268
  logger.warn(
263
- `Failed to stop ${projectId}, may be left running...\n${stringifyError(
269
+ `Failed to stop ${projectId}, may be left running... Error:\n${stringifyError(
264
270
  e
265
271
  )}`
266
272
  );
@@ -1,4 +1,4 @@
1
- import { logger, stringifyError } from 'alwaysai/lib/util';
1
+ import { stringifyError } from 'alwaysai/lib/util';
2
2
  import { uninstallApp, rollbackApp } from '../application-control';
3
3
  import { createAppBackup } from '../application-control/backup';
4
4
  import { AgentConfigFile } from '../infrastructure/agent-config';
@@ -12,6 +12,7 @@ import {
12
12
  ErrorFunction,
13
13
  SuccessFunction
14
14
  } from './transaction-manager';
15
+ import { logger } from '../util/logger';
15
16
 
16
17
  export interface HandlerContext {
17
18
  clientId: string;
@@ -52,7 +53,9 @@ export abstract class BaseHandler {
52
53
  await uninstallApp({ projectId });
53
54
  this.shadowHandler.clearProjectShadow(projectId);
54
55
  } catch (e) {
55
- logger.error(`Failed to uninstall ${projectId}!\n${stringifyError(e)}`);
56
+ logger.error(
57
+ `Failed to uninstall ${projectId}! Error:\n${stringifyError(e)}`
58
+ );
56
59
  throw e;
57
60
  }
58
61
  }
@@ -73,7 +76,7 @@ export abstract class BaseHandler {
73
76
  await createAppBackup({ projectId });
74
77
  } catch (e) {
75
78
  logger.error(
76
- `Could not create a backup for the project: ${projectId}!\n${stringifyError(
79
+ `Could not create a backup for the project: ${projectId}! Error:\n${stringifyError(
77
80
  e
78
81
  )}`
79
82
  );
@@ -87,14 +90,16 @@ export abstract class BaseHandler {
87
90
  return out;
88
91
  } catch (errorAppUpdate) {
89
92
  logger.error(
90
- `Failed to update ${projectId}!\n${stringifyError(errorAppUpdate)}`
93
+ `Failed to update ${projectId}! Error:\n${stringifyError(
94
+ errorAppUpdate
95
+ )}`
91
96
  );
92
97
  // If something goes wrong, first try to rollback
93
98
  try {
94
99
  await rollbackApp({ projectId });
95
100
  } catch (errorRollbackApp) {
96
101
  logger.error(
97
- `Application rollback failed for ${projectId}!\n${stringifyError(
102
+ `Application rollback failed for ${projectId}! Error:\n${stringifyError(
98
103
  errorRollbackApp
99
104
  )}`
100
105
  );
@@ -16,40 +16,32 @@ export class ConnectionManager extends MessageDispatcher<any> {
16
16
  private clientId: string;
17
17
  private host: string;
18
18
  private port: number;
19
- private device: awsIot.device | null = null;
19
+ private device: awsIot.device;
20
20
  private subscribedTopics: Set<string> = new Set();
21
+ private connected = false;
21
22
 
22
23
  constructor(clientId: string, host: string, port: number) {
23
24
  super();
24
25
  this.clientId = clientId;
25
26
  this.host = host;
26
27
  this.port = port;
28
+ this.device = awsIot.device({
29
+ keyPath: DEVICE_PRIVATE_KEY_FILE_PATH,
30
+ certPath: DEVICE_CERTIFICATE_FILE_PATH,
31
+ caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
32
+ clientId: this.clientId,
33
+ host: this.host,
34
+ port: this.port,
35
+ keepalive: 10 // time before re-connect attempt on dropped connection, default is 400 seconds
36
+ });
27
37
  }
28
38
 
29
39
  public getIoTDevice() {
30
40
  return this.device;
31
41
  }
32
42
 
33
- public connect(cb): void {
34
- try {
35
- this.device = awsIot.device({
36
- keyPath: DEVICE_PRIVATE_KEY_FILE_PATH,
37
- certPath: DEVICE_CERTIFICATE_FILE_PATH,
38
- caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
39
- clientId: this.clientId,
40
- host: this.host,
41
- port: this.port,
42
- keepalive: 10 // time before re-connect attempt on dropped connection, default is 400 seconds
43
- });
44
- this.setupHandlers(cb);
45
- } catch (error) {
46
- logger.error(`Error connecting to cloud!\n${stringifyError(error)}`);
47
- this.handleReconnection();
48
- }
49
- }
50
-
51
43
  public isConnected(): boolean {
52
- return this.device ? this.device.connected : false;
44
+ return this.connected;
53
45
  }
54
46
 
55
47
  public registerHandler(topic: string, handler: MessageHandler) {
@@ -58,16 +50,11 @@ export class ConnectionManager extends MessageDispatcher<any> {
58
50
  }
59
51
 
60
52
  public disconnect(): void {
61
- if (this.device) {
62
- this.device.end();
63
- logger.debug(`Device Agent has been disconnected from the AWS IoT Core.`);
64
- }
53
+ this.device.end();
54
+ logger.debug(`Device Agent has been disconnected from the AWS IoT Core.`);
65
55
  }
66
56
 
67
57
  public subscribe(topic: string): void {
68
- if (!this.device) {
69
- throw new Error('Must call connect() before subscribe()!');
70
- }
71
58
  if (!this.subscribedTopics.has(topic)) {
72
59
  this.device.subscribe(topic);
73
60
  this.subscribedTopics.add(topic);
@@ -76,9 +63,6 @@ export class ConnectionManager extends MessageDispatcher<any> {
76
63
  }
77
64
 
78
65
  public unsubscribe(topic: string): void {
79
- if (!this.device) {
80
- throw new Error('Must call connect() before unsubscribe()!');
81
- }
82
66
  if (this.subscribedTopics.has(topic)) {
83
67
  this.device.unsubscribe(topic);
84
68
  this.subscribedTopics.delete(topic);
@@ -86,25 +70,16 @@ export class ConnectionManager extends MessageDispatcher<any> {
86
70
  }
87
71
  }
88
72
 
89
- private handleReconnection() {
90
- logger.debug(`Attempting to reconnect to AWS IoT Core...`);
91
- setTimeout(
92
- () =>
93
- this.connect(() => {
94
- // Do nothing
95
- }),
96
- 5000
97
- ); // try in 5 seconds.
98
- }
99
-
100
- private setupHandlers(cb): void {
73
+ public initConnectionHandlers(connectCallback: () => void): void {
101
74
  this.device.on('connect', (connack: any) => {
102
75
  logger.info('Device Agent has connected to the cloud.');
103
- cb();
76
+ this.connected = true;
77
+ connectCallback();
104
78
  });
105
79
 
106
80
  this.device.on('disconnect', () => {
107
81
  logger.warn('Device Agent has been disconnected from the cloud');
82
+ this.connected = false;
108
83
  });
109
84
 
110
85
  this.device.on('reconnect', () => {
@@ -115,17 +90,20 @@ export class ConnectionManager extends MessageDispatcher<any> {
115
90
 
116
91
  this.device.on('error', function (e) {
117
92
  logger.error(
118
- `Error connecting to the AWS IoT Core!\n${stringifyError(e)}`
93
+ `Error connecting to the AWS IoT Core! Error:\n${stringifyError(e)}`
119
94
  );
95
+ this.connected = false;
120
96
  });
121
97
 
122
98
  this.device.on('close', () => {
123
99
  logger.warn('Device Agent AWS IoT Core connection closed.');
100
+ this.connected = false;
124
101
  });
125
102
 
126
103
  this.device.on('offline', () => {
127
104
  logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
128
105
  void this.logConnectionInfo();
106
+ this.connected = false;
129
107
  });
130
108
 
131
109
  this.device.on('message', async (topic: string, payload: string) => {
@@ -136,7 +114,7 @@ export class ConnectionManager extends MessageDispatcher<any> {
136
114
  const jsonPacket = JSON.parse(payload);
137
115
  this.dispatch(topic, jsonPacket);
138
116
  } catch (e) {
139
- logger.error(`Error parsing message!\n${stringifyError(e)}`);
117
+ logger.error(`Error parsing message! Error:\n${stringifyError(e)}`);
140
118
  }
141
119
  });
142
120
  }
@@ -41,8 +41,6 @@ export class DeviceAgentCloudConnection {
41
41
  SecureTunnelHandlerSingleton.getInstance();
42
42
 
43
43
  constructor() {
44
- this.liveUpdatesHandler = new LiveUpdatesHandler();
45
-
46
44
  // Initialize & setup the connection
47
45
  this.connectionManager = new ConnectionManager(
48
46
  this.clientId,
@@ -52,92 +50,91 @@ export class DeviceAgentCloudConnection {
52
50
 
53
51
  this.publisher = new Publisher(this.connectionManager, this.clientId);
54
52
  this.shadowHandler = new ShadowHandler(this.clientId, this.publisher);
55
-
56
- this.connectionManager.connect(() => {
57
- void this.shadowHandler.initShadows();
58
- this.publisher.publish(JOB_HANDLER_TOPICS.START_NEXT, JSON.stringify({}));
59
- });
60
-
53
+ this.liveUpdatesHandler = new LiveUpdatesHandler();
61
54
  this.transactionManager = new TransactionManager(this.liveUpdatesHandler);
62
55
 
63
- // Construct a HandlerContext used by all the message handlers
64
- const handlerContext: HandlerContext = {
65
- clientId: this.clientId,
66
- txnMgr: this.transactionManager,
67
- publisher: this.publisher,
68
- shadowHandler: this.shadowHandler,
69
- liveUpdatesHandler: this.liveUpdatesHandler,
70
- secureTunnelHandler: this.secureTunnelHandler
71
- };
72
-
73
- // Instantiate & register message handlers for Project Shadow topics
74
- const projectShadowMessageHandler = new ProjectShadowMessageHandler(
75
- handlerContext
76
- );
77
- this.shadowHandler.projectShadowTopics.forEach((topic) => {
56
+ this.connectionManager.initConnectionHandlers(() => {
57
+ // Construct a HandlerContext used by all the message handlers
58
+ const handlerContext: HandlerContext = {
59
+ clientId: this.clientId,
60
+ txnMgr: this.transactionManager,
61
+ publisher: this.publisher,
62
+ shadowHandler: this.shadowHandler,
63
+ liveUpdatesHandler: this.liveUpdatesHandler,
64
+ secureTunnelHandler: this.secureTunnelHandler
65
+ };
66
+
67
+ // Instantiate & register message handlers for Project Shadow topics
68
+ const projectShadowMessageHandler = new ProjectShadowMessageHandler(
69
+ handlerContext
70
+ );
71
+ this.shadowHandler.projectShadowTopics.forEach((topic) => {
72
+ this.connectionManager.registerHandler(
73
+ topic,
74
+ projectShadowMessageHandler
75
+ );
76
+ });
77
+
78
+ // Instantiate & register message handlers for to-device and secureTunnel topics
78
79
  this.connectionManager.registerHandler(
79
- topic,
80
- projectShadowMessageHandler
80
+ this.toDeviceTopic,
81
+ new DeviceAgentMessageHandler(
82
+ handlerContext,
83
+ (txId: string, errorMsg: string) => {
84
+ const msg = buildToClientStatusResponseMessage(
85
+ this.publisher.getClientId(),
86
+ {
87
+ status: keyMirrors.statusResponse.failure,
88
+ message: errorMsg
89
+ },
90
+ txId
91
+ );
92
+ this.publisher.publishToClient(msg);
93
+ },
94
+ (txId: string) => {
95
+ const msg = buildToClientStatusResponseMessage(
96
+ this.publisher.getClientId(),
97
+ { status: keyMirrors.statusResponse.success },
98
+ txId
99
+ );
100
+ this.publisher.publishToClient(msg);
101
+ }
102
+ )
81
103
  );
82
- });
83
104
 
84
- // Instantiate & register message handlers for to-device and secureTunnel topics
85
- this.connectionManager.registerHandler(
86
- this.toDeviceTopic,
87
- new DeviceAgentMessageHandler(
88
- handlerContext,
89
- (txId: string, errorMsg: string) => {
90
- const msg = buildToClientStatusResponseMessage(
91
- this.publisher.getClientId(),
92
- {
93
- status: keyMirrors.statusResponse.failure,
94
- message: errorMsg
95
- },
96
- txId
97
- );
98
- this.publisher.publishToClient(msg);
99
- },
100
- (txId: string) => {
101
- const msg = buildToClientStatusResponseMessage(
102
- this.publisher.getClientId(),
103
- { status: keyMirrors.statusResponse.success },
104
- txId
105
- );
106
- this.publisher.publishToClient(msg);
107
- }
108
- )
109
- );
110
-
111
- const secureTunnelMessageHandler = new SecureTunnelMessageHandler(
112
- handlerContext
113
- );
114
- this.connectionManager.registerHandler(
115
- secureTunnelMessageHandler.getNotifyTopic(),
116
- secureTunnelMessageHandler
117
- );
105
+ const secureTunnelMessageHandler = new SecureTunnelMessageHandler(
106
+ handlerContext
107
+ );
108
+ this.connectionManager.registerHandler(
109
+ secureTunnelMessageHandler.getNotifyTopic(),
110
+ secureTunnelMessageHandler
111
+ );
118
112
 
119
- this.connectionManager.registerHandler(
120
- this.shadowHandler.shadowTopics.secureTunnel.updateDelta,
121
- secureTunnelMessageHandler
122
- );
123
- this.connectionManager.registerHandler(
124
- this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted,
125
- secureTunnelMessageHandler
126
- );
113
+ this.connectionManager.registerHandler(
114
+ this.shadowHandler.shadowTopics.secureTunnel.updateDelta,
115
+ secureTunnelMessageHandler
116
+ );
117
+ this.connectionManager.registerHandler(
118
+ this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted,
119
+ secureTunnelMessageHandler
120
+ );
127
121
 
128
- const jobHandler = new JobHandler(handlerContext);
122
+ const jobHandler = new JobHandler(handlerContext);
123
+ const JOB_HANDLER_TOPICS = jobHandler.getJobTopics();
129
124
 
130
- const JOB_HANDLER_TOPICS = jobHandler.getJobTopic();
125
+ this.connectionManager.registerHandler(
126
+ JOB_HANDLER_TOPICS.NOTIFY_NEXT,
127
+ jobHandler
128
+ );
131
129
 
132
- this.connectionManager.registerHandler(
133
- JOB_HANDLER_TOPICS.NOTIFY_NEXT,
134
- jobHandler
135
- );
130
+ this.connectionManager.registerHandler(
131
+ JOB_HANDLER_TOPICS.START_NEXT_ACCEPTED,
132
+ jobHandler
133
+ );
134
+ this.publisher.publish(JOB_HANDLER_TOPICS.START_NEXT, JSON.stringify({}));
136
135
 
137
- this.connectionManager.registerHandler(
138
- JOB_HANDLER_TOPICS.START_NEXT_ACCEPTED,
139
- jobHandler
140
- );
136
+ void this.shadowHandler.initShadows();
137
+ });
141
138
  }
142
139
 
143
140
  /*=================================================================
@@ -158,7 +155,22 @@ export class DeviceAgentCloudConnection {
158
155
  await sleep(1000);
159
156
  this.connectionManager.disconnect();
160
157
  }
161
- public async handleMessage(topic: string, message: any) {
158
+
159
+ // CLI methods
160
+
161
+ public async waitForConnection() {
162
+ while (!this.connectionManager.isConnected()) {
163
+ await sleep(1000);
164
+ }
165
+ }
166
+
167
+ public async waitForCmd(projectId: string) {
168
+ while (this.isCmdInProgress(projectId)) {
169
+ await sleep(1000);
170
+ }
171
+ }
172
+
173
+ public async sendCliCmd(topic: string, message: any) {
162
174
  this.connectionManager.dispatch(topic, message);
163
175
  }
164
176
  }
@@ -179,16 +191,12 @@ export async function runDeviceAgentCloudInterface() {
179
191
  }
180
192
 
181
193
  if (await requiredConfigFilesPresentAndValid()) {
182
- const deviceAgent = new DeviceAgentCloudConnection();
183
- if (ALWAYSAI_ANALYTICS_PASSTHROUGH === true) {
184
- const shadowHandler = deviceAgent.shadowHandler;
185
- const publisher = deviceAgent.publisher;
186
- const passthroughHandler = new PassthroughHandler(
187
- publisher,
188
- shadowHandler
189
- );
190
- await passthroughHandler.setup();
191
- }
194
+ const cloudConnection = new DeviceAgentCloudConnection();
195
+ const passthroughHandler = new PassthroughHandler(
196
+ cloudConnection.publisher,
197
+ cloudConnection.shadowHandler
198
+ );
199
+ await passthroughHandler.run();
192
200
  } else {
193
201
  throw new Error(
194
202
  "Set device agent to local mode and retry the 'aai-agent device init' command"
@@ -27,7 +27,7 @@ import {
27
27
  ModelsInstallResponseMessage
28
28
  } from '@alwaysai/device-agent-schemas/lib/app-action-schema';
29
29
  import { DeviceActionMessage } from '@alwaysai/device-agent-schemas/lib/device-action-schema';
30
- import { logger, stringifyError } from 'alwaysai/lib/util';
30
+ import { stringifyError } from 'alwaysai/lib/util';
31
31
  import {
32
32
  startApp,
33
33
  stopApp,
@@ -45,6 +45,7 @@ import {
45
45
  AppConfig,
46
46
  validateAppConfig
47
47
  } from '@alwaysai/app-configuration-schemas';
48
+ import { logger } from '../util/logger';
48
49
 
49
50
  export type AppContent = {
50
51
  projectId: string;
@@ -160,7 +161,7 @@ class AppStateMessageHandler
160
161
  });
161
162
  } catch (e) {
162
163
  logger.error(
163
- `Error processing application state control request for ${projectId}!\n${stringifyError(
164
+ `Error processing application state control request for ${projectId}! Error:\n${stringifyError(
164
165
  e
165
166
  )}`
166
167
  );
@@ -215,7 +216,7 @@ class AppVersionControlMessageHandler
215
216
  });
216
217
  } catch (e) {
217
218
  logger.error(
218
- `Error processing application install request for ${projectId}!\n${stringifyError(
219
+ `Error processing application install request for ${projectId}! Error:\n${stringifyError(
219
220
  e
220
221
  )}`
221
222
  );
@@ -310,7 +311,9 @@ class AppVersionControlMessageHandler
310
311
  }
311
312
  } catch (e) {
312
313
  logger.error(
313
- `Could not parse the appConfig for transaction!\n${stringifyError(e)}`
314
+ `Could not parse the appConfig for transaction! Error:\n${stringifyError(
315
+ e
316
+ )}`
314
317
  );
315
318
  }
316
319
  }
@@ -340,9 +343,9 @@ class AppVersionControlMessageHandler
340
343
  appContent.envVars = envvarsUpdate;
341
344
  }
342
345
  } catch (e) {
343
- // throw here
346
+ // TODO: throw here
344
347
  logger.error(
345
- `Could not parse the environment variables for transaction!\n${stringifyError(
348
+ `Could not parse the environment variables for transaction! Error:\n${stringifyError(
346
349
  e
347
350
  )}`
348
351
  );
@@ -610,7 +613,7 @@ class DeviceActionMessageHandler
610
613
  logger.error(
611
614
  `There was a problem performing device action '${
612
615
  message.payload.action
613
- }'!\n${stringifyError(e)}`
616
+ }'! Error: \n${stringifyError(e)}`
614
617
  );
615
618
  this.publisher.publishToClient(
616
619
  buildToClientStatusResponseMessage(
@@ -14,6 +14,9 @@ interface IntervalOptions {
14
14
  ms?: number;
15
15
  }
16
16
 
17
+ /*
18
+ Responsible for managing the lifecycle of periodic updates and streams.
19
+ */
17
20
  export class LiveUpdatesHandler {
18
21
  private killAllTimeout: ReturnType<typeof setTimeout>;
19
22
  private livingIntervals: Record<string, ReturnType<typeof setInterval>> = {};
@@ -31,12 +34,14 @@ export class LiveUpdatesHandler {
31
34
  transactionId?: string,
32
35
  options?: IntervalOptions
33
36
  ) {
37
+ logger.silly(`LiveUpdatesHandler: Enabling ${intervalType}`);
34
38
  this.restartKillAllTimeout();
35
39
 
36
40
  const key = this.generateIntervalKey(intervalType, transactionId);
37
41
 
38
42
  this.safeSetInterval(key, publishingFn, options);
39
43
 
44
+ // Call publishing function right away for immediate results
40
45
  await publishingFn();
41
46
  }
42
47
 
@@ -44,6 +49,7 @@ export class LiveUpdatesHandler {
44
49
  intervalType: ToClientMessageTypeValue,
45
50
  transactionId?: string
46
51
  ) {
52
+ logger.silly(`LiveUpdatesHandler: Disabling ${intervalType}`);
47
53
  const key = this.generateIntervalKey(intervalType, transactionId);
48
54
  clearInterval(this.livingIntervals[key]);
49
55
  delete this.livingIntervals[key];
@@ -54,7 +60,7 @@ export class LiveUpdatesHandler {
54
60
  streamGetter: () => Promise<NodeJS.ReadableStream | null>,
55
61
  publishingFn: (logChunk: string) => void
56
62
  ) {
57
- logger.info(`Starting log stream for ${projectId}`);
63
+ logger.info(`LiveUpdatesHandler: Starting log stream for ${projectId}`);
58
64
 
59
65
  this.livingStreams.add(projectId);
60
66
 
@@ -84,7 +90,7 @@ export class LiveUpdatesHandler {
84
90
  });
85
91
 
86
92
  readable.on('finished', () => {
87
- logger.info(`Strean complete. ProjectId: ${projectId}`);
93
+ logger.info(`Stream complete. ProjectId: ${projectId}`);
88
94
  });
89
95
  }
90
96
 
@@ -105,8 +111,8 @@ export class LiveUpdatesHandler {
105
111
  try {
106
112
  return await streamGetter();
107
113
  } catch (e) {
108
- logger.info(
109
- `Failed to start app logs, retrying in 1 second.\n${stringifyError(
114
+ logger.error(
115
+ `Failed to start app logs, retrying in 1 second. Error:\n${stringifyError(
110
116
  e
111
117
  )}`
112
118
  );
@@ -117,7 +123,8 @@ export class LiveUpdatesHandler {
117
123
  return null;
118
124
  }
119
125
 
120
- // do not await any functions in the setSafeInterval other than inside setInterval() as per EI-1694.
126
+ // Do not await any functions in setSafeInterval other than inside
127
+ // setInterval() as per EI-1694.
121
128
  private safeSetInterval(
122
129
  key: string,
123
130
  publishingFn: () => Promise<void>,