@alwaysai/device-agent 2.0.2-0 → 2.1.0-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) 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/bootstrap-agent.d.ts +16 -0
  10. package/lib/cloud-connection/bootstrap-agent.d.ts.map +1 -0
  11. package/lib/cloud-connection/{device-agent.js → bootstrap-agent.js} +45 -22
  12. package/lib/cloud-connection/bootstrap-agent.js.map +1 -0
  13. package/lib/cloud-connection/connection-manager.d.ts +20 -9
  14. package/lib/cloud-connection/connection-manager.d.ts.map +1 -1
  15. package/lib/cloud-connection/connection-manager.js +97 -68
  16. package/lib/cloud-connection/connection-manager.js.map +1 -1
  17. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +3 -1
  18. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  19. package/lib/cloud-connection/device-agent-cloud-connection.js +62 -50
  20. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  21. package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -1
  22. package/lib/cloud-connection/device-agent-message-handler.js +19 -18
  23. package/lib/cloud-connection/device-agent-message-handler.js.map +1 -1
  24. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  25. package/lib/cloud-connection/live-updates-handler.js +11 -4
  26. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  27. package/lib/cloud-connection/passthrough-handler.d.ts +3 -3
  28. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
  29. package/lib/cloud-connection/passthrough-handler.js +105 -79
  30. package/lib/cloud-connection/passthrough-handler.js.map +1 -1
  31. package/lib/cloud-connection/publisher.d.ts +1 -1
  32. package/lib/cloud-connection/publisher.d.ts.map +1 -1
  33. package/lib/cloud-connection/publisher.js +22 -20
  34. package/lib/cloud-connection/publisher.js.map +1 -1
  35. package/lib/cloud-connection/shadow-handler.js +3 -3
  36. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  37. package/lib/cloud-connection/shadow.d.ts.map +1 -1
  38. package/lib/cloud-connection/shadow.js +1 -1
  39. package/lib/cloud-connection/shadow.js.map +1 -1
  40. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  41. package/lib/cloud-connection/transaction-manager.js +17 -7
  42. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  43. package/lib/cloud-connection/transaction-manager.test.js +52 -44
  44. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  45. package/lib/device-control/device-control.d.ts.map +1 -1
  46. package/lib/device-control/device-control.js +13 -9
  47. package/lib/device-control/device-control.js.map +1 -1
  48. package/lib/docker/docker-compose.d.ts.map +1 -1
  49. package/lib/docker/docker-compose.js +1 -1
  50. package/lib/docker/docker-compose.js.map +1 -1
  51. package/lib/environment.d.ts +3 -0
  52. package/lib/environment.d.ts.map +1 -1
  53. package/lib/environment.js +12 -1
  54. package/lib/environment.js.map +1 -1
  55. package/lib/index.js +12 -0
  56. package/lib/index.js.map +1 -1
  57. package/lib/infrastructure/config-check-utility.js +2 -2
  58. package/lib/infrastructure/config-check-utility.js.map +1 -1
  59. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -1
  60. package/lib/infrastructure/legacy-migration/legacy-migration.js +6 -10
  61. package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -1
  62. package/lib/jobs/job-handler.d.ts +1 -1
  63. package/lib/jobs/job-handler.d.ts.map +1 -1
  64. package/lib/jobs/job-handler.js +4 -4
  65. package/lib/jobs/job-handler.js.map +1 -1
  66. package/lib/local-connection/rabbitmq-container.d.ts +6 -0
  67. package/lib/local-connection/rabbitmq-container.d.ts.map +1 -0
  68. package/lib/local-connection/rabbitmq-container.js +111 -0
  69. package/lib/local-connection/rabbitmq-container.js.map +1 -0
  70. package/lib/local-connection/rabbitmq-container.test.d.ts +2 -0
  71. package/lib/local-connection/rabbitmq-container.test.d.ts.map +1 -0
  72. package/lib/local-connection/rabbitmq-container.test.js +219 -0
  73. package/lib/local-connection/rabbitmq-container.test.js.map +1 -0
  74. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  75. package/lib/subcommands/app/analytics.js +2 -3
  76. package/lib/subcommands/app/analytics.js.map +1 -1
  77. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  78. package/lib/subcommands/app/env-vars.js +4 -6
  79. package/lib/subcommands/app/env-vars.js.map +1 -1
  80. package/lib/subcommands/app/models.d.ts.map +1 -1
  81. package/lib/subcommands/app/models.js +2 -3
  82. package/lib/subcommands/app/models.js.map +1 -1
  83. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  84. package/lib/subcommands/app/shadow.js +4 -6
  85. package/lib/subcommands/app/shadow.js.map +1 -1
  86. package/lib/subcommands/app/version.d.ts.map +1 -1
  87. package/lib/subcommands/app/version.js +6 -9
  88. package/lib/subcommands/app/version.js.map +1 -1
  89. package/lib/subcommands/device/clean.d.ts.map +1 -1
  90. package/lib/subcommands/device/clean.js +15 -17
  91. package/lib/subcommands/device/clean.js.map +1 -1
  92. package/lib/subcommands/device/index.d.ts.map +1 -1
  93. package/lib/subcommands/device/index.js +3 -1
  94. package/lib/subcommands/device/index.js.map +1 -1
  95. package/lib/subcommands/device/local-connection.d.ts +2 -0
  96. package/lib/subcommands/device/local-connection.d.ts.map +1 -0
  97. package/lib/subcommands/device/local-connection.js +17 -0
  98. package/lib/subcommands/device/local-connection.js.map +1 -0
  99. package/lib/subcommands/index.d.ts +4 -1
  100. package/lib/subcommands/index.d.ts.map +1 -1
  101. package/lib/subcommands/index.js +1 -3
  102. package/lib/subcommands/index.js.map +1 -1
  103. package/lib/util/check-for-updates.d.ts.map +1 -1
  104. package/lib/util/check-for-updates.js +2 -2
  105. package/lib/util/check-for-updates.js.map +1 -1
  106. package/lib/util/file.d.ts.map +1 -1
  107. package/lib/util/file.js +6 -1
  108. package/lib/util/file.js.map +1 -1
  109. package/lib/util/file.test.js +1 -1
  110. package/lib/util/file.test.js.map +1 -1
  111. package/lib/util/get-device-id.d.ts.map +1 -1
  112. package/lib/util/get-device-id.js +1 -1
  113. package/lib/util/get-device-id.js.map +1 -1
  114. package/package.json +3 -3
  115. package/readme.md +16 -4
  116. package/src/application-control/config.ts +1 -1
  117. package/src/application-control/install.ts +11 -5
  118. package/src/cloud-connection/base-message-handler.ts +10 -5
  119. package/src/cloud-connection/{device-agent.ts → bootstrap-agent.ts} +68 -35
  120. package/src/cloud-connection/connection-manager.ts +160 -82
  121. package/src/cloud-connection/device-agent-cloud-connection.ts +108 -98
  122. package/src/cloud-connection/device-agent-message-handler.ts +10 -7
  123. package/src/cloud-connection/live-updates-handler.ts +12 -5
  124. package/src/cloud-connection/passthrough-handler.ts +137 -92
  125. package/src/cloud-connection/publisher.ts +30 -28
  126. package/src/cloud-connection/shadow-handler.ts +3 -3
  127. package/src/cloud-connection/shadow.ts +3 -1
  128. package/src/cloud-connection/transaction-manager.test.ts +60 -41
  129. package/src/cloud-connection/transaction-manager.ts +26 -12
  130. package/src/device-control/device-control.ts +23 -13
  131. package/src/docker/docker-compose.ts +3 -1
  132. package/src/environment.ts +17 -0
  133. package/src/index.ts +19 -0
  134. package/src/infrastructure/config-check-utility.ts +2 -2
  135. package/src/infrastructure/legacy-migration/legacy-migration.ts +8 -13
  136. package/src/jobs/job-handler.ts +4 -4
  137. package/src/local-connection/rabbitmq-container.test.ts +255 -0
  138. package/src/local-connection/rabbitmq-container.ts +151 -0
  139. package/src/subcommands/app/analytics.ts +2 -3
  140. package/src/subcommands/app/env-vars.ts +4 -6
  141. package/src/subcommands/app/models.ts +2 -3
  142. package/src/subcommands/app/shadow.ts +4 -6
  143. package/src/subcommands/app/version.ts +7 -8
  144. package/src/subcommands/device/clean.ts +20 -19
  145. package/src/subcommands/device/index.ts +3 -1
  146. package/src/subcommands/device/local-connection.ts +16 -0
  147. package/src/subcommands/index.ts +1 -3
  148. package/src/util/check-for-updates.ts +4 -2
  149. package/src/util/file.test.ts +1 -1
  150. package/src/util/file.ts +7 -1
  151. package/src/util/get-device-id.ts +3 -1
  152. package/lib/cloud-connection/bootstrap-provision.d.ts +0 -2
  153. package/lib/cloud-connection/bootstrap-provision.d.ts.map +0 -1
  154. package/lib/cloud-connection/bootstrap-provision.js +0 -35
  155. package/lib/cloud-connection/bootstrap-provision.js.map +0 -1
  156. package/lib/cloud-connection/device-agent.d.ts +0 -21
  157. package/lib/cloud-connection/device-agent.d.ts.map +0 -1
  158. package/lib/cloud-connection/device-agent.js.map +0 -1
  159. package/lib/local-connection/rabbitmq-connection.d.ts +0 -7
  160. package/lib/local-connection/rabbitmq-connection.d.ts.map +0 -1
  161. package/lib/local-connection/rabbitmq-connection.js +0 -95
  162. package/lib/local-connection/rabbitmq-connection.js.map +0 -1
  163. package/lib/subcommands/rabbitmq-connection.d.ts +0 -2
  164. package/lib/subcommands/rabbitmq-connection.d.ts.map +0 -1
  165. package/lib/subcommands/rabbitmq-connection.js +0 -14
  166. package/lib/subcommands/rabbitmq-connection.js.map +0 -1
  167. package/lib/util/clean-certs.d.ts +0 -2
  168. package/lib/util/clean-certs.d.ts.map +0 -1
  169. package/lib/util/clean-certs.js +0 -17
  170. package/lib/util/clean-certs.js.map +0 -1
  171. package/src/cloud-connection/bootstrap-provision.ts +0 -43
  172. package/src/local-connection/rabbitmq-connection.ts +0 -124
  173. package/src/subcommands/rabbitmq-connection.ts +0 -11
  174. package/src/util/clean-certs.ts +0 -16
@@ -1,11 +1,10 @@
1
- // eslint-disable-next-line
2
- const awsIot = require('aws-iot-device-sdk');
3
1
  import { getTargetHardwareUuid } from 'alwaysai/lib/core/app';
4
2
  import {
5
3
  DEVICE_CERTIFICATE_FILE_NAME,
6
4
  DEVICE_CERTIFICATE_ID_FILE_NAME,
7
5
  DEVICE_PRIVATE_KEY_FILE_NAME,
8
- LOCAL_CERT_AND_KEY_DIR
6
+ LOCAL_CERT_AND_KEY_DIR,
7
+ LocalDeviceCertificates
9
8
  } from 'alwaysai/lib/infrastructure';
10
9
  import { JsSpawner } from 'alwaysai/lib/util';
11
10
  import {
@@ -14,18 +13,20 @@ import {
14
13
  } from '../infrastructure/device-certificate';
15
14
  import { getDeviceUuid } from '../util/get-device-id';
16
15
  import { logger } from '../util/logger';
16
+ import { ConnectionManager, DeviceAgentConfigType } from './connection-manager';
17
+ import { Publisher } from './publisher';
18
+ import { MessageHandler } from './message-dispatcher';
19
+ import {
20
+ getBootstrapCertificateFilePath,
21
+ getBootstrapPrivateKeyFilePath
22
+ } from '../infrastructure/device-certificate';
23
+ import { getIoTCoreEndpointUrl } from '../infrastructure/urls';
24
+ ``;
25
+ import { AWS_ROOT_CERTIFICATE_FILE_PATH } from '../util/directories';
17
26
 
18
27
  // eslint-disable-next-line
19
28
  const process = require('process');
20
29
 
21
- interface DeviceAgentConfigType {
22
- keyPath: string;
23
- certPath: string;
24
- caPath: string;
25
- clientId: string;
26
- host: string;
27
- }
28
-
29
30
  interface FleetProvisionTemplateMessageType {
30
31
  certificateOwnershipToken: string;
31
32
  parameters: {
@@ -36,38 +37,40 @@ interface FleetProvisionTemplateMessageType {
36
37
  };
37
38
  }
38
39
 
39
- export class DeviceAgent {
40
- constructor(config: DeviceAgentConfigType) {
41
- this.device = awsIot.device(config);
40
+ export class BootstrapAgent implements MessageHandler {
41
+ private connectionManager: ConnectionManager;
42
+ private publisher: Publisher;
43
+ private readonly clientId = getDeviceUuid();
44
+ private readonly host = getIoTCoreEndpointUrl();
45
+ private readonly port = 8883;
46
+
47
+ constructor() {
48
+ // Initialize & setup the connection
49
+ const bootstrapAgentConfig = {
50
+ clientId: this.clientId,
51
+ host: this.host,
52
+ port: this.port,
53
+ keyPath: getBootstrapPrivateKeyFilePath(),
54
+ certPath: getBootstrapCertificateFilePath(),
55
+ caPath: AWS_ROOT_CERTIFICATE_FILE_PATH
56
+ };
57
+ this.connectionManager = new ConnectionManager(bootstrapAgentConfig);
58
+
59
+ this.publisher = new Publisher(
60
+ this.connectionManager,
61
+ bootstrapAgentConfig.clientId
62
+ );
42
63
  }
43
64
 
44
- public deviceType = 'aai-device';
45
- public device = awsIot.device;
46
65
  public hardwareId = async () => await getTargetHardwareUuid(JsSpawner());
47
66
  public deviceId = getDeviceUuid();
67
+ public deviceType = 'aai-device';
48
68
 
49
69
  public publishMessage(topic: string, message: string) {
50
- this.device.publish(topic, message);
51
- }
52
- }
53
-
54
- export class BootstrapAgent extends DeviceAgent {
55
- public async subscribeToAllTopics() {
56
- const AWS_CERTIFICATE_ACCEPT_TOPIC =
57
- '$aws/certificates/create/json/accepted';
58
- const PROVISIONING_ACCEPTED_TOPIC =
59
- '$aws/provisioning-templates/FleetProvisionTemplate/provision/json/accepted';
60
-
61
- const topics = [AWS_CERTIFICATE_ACCEPT_TOPIC, PROVISIONING_ACCEPTED_TOPIC];
62
- const resp = this.device.subscribe(
63
- topics,
64
- function (err: any, granted: { topic: string; qos: number }[]) {
65
- logger.debug(`Bootstrap Agent: ${JSON.stringify(granted, null, 2)}`);
66
- }
67
- );
70
+ this.publisher.publish(topic, message);
68
71
  }
69
72
 
70
- public async handleAwsCertificateTopics(topic: string, payload: any) {
73
+ public async handle(payload: any, topic: string) {
71
74
  switch (topic) {
72
75
  case '$aws/certificates/create/json/accepted': {
73
76
  logger.debug(
@@ -124,4 +127,34 @@ export class BootstrapAgent extends DeviceAgent {
124
127
  }
125
128
  }
126
129
  }
130
+
131
+ public async bootstrapProvision() {
132
+ const rmBootstrapCertsAndClose = async () => {
133
+ const deviceCertificates = new LocalDeviceCertificates();
134
+ const spawner = JsSpawner();
135
+ await spawner.rimraf(getBootstrapCertificateDirectoryPath());
136
+ await spawner.rimraf(deviceCertificates.getCertificateDirectoryPath());
137
+ logger.error('Could not provision device. Try again.');
138
+ process.exit(1);
139
+ };
140
+
141
+ setTimeout(rmBootstrapCertsAndClose, 60000);
142
+
143
+ this.connectionManager.initConnectionHandlers(() => {
144
+ logger.info('Your device is being provisioned');
145
+ });
146
+
147
+ await this.connectionManager.waitForConnection();
148
+
149
+ this.connectionManager.registerHandler(
150
+ '$aws/certificates/create/json/accepted',
151
+ this
152
+ );
153
+ this.connectionManager.registerHandler(
154
+ '$aws/provisioning-templates/FleetProvisionTemplate/provision/json/accepted',
155
+ this
156
+ );
157
+
158
+ this.publishMessage('$aws/certificates/create/json', '{}');
159
+ }
127
160
  }
@@ -1,4 +1,4 @@
1
- import * as awsIot from 'aws-iot-device-sdk';
1
+ import { mqtt5, iot } from 'aws-iot-device-sdk-v2';
2
2
  import {
3
3
  DEVICE_CERTIFICATE_FILE_PATH,
4
4
  DEVICE_PRIVATE_KEY_FILE_PATH
@@ -9,135 +9,213 @@ import { logger } from '../util/logger';
9
9
  import { promisify } from 'util';
10
10
  import { exec } from 'child_process';
11
11
  import { MessageDispatcher, MessageHandler } from './message-dispatcher';
12
+ import { once } from 'events';
12
13
 
13
14
  const exec_promise = promisify(exec);
14
15
 
16
+ // replace with direct params: instead of interface
17
+ export interface DeviceAgentConfigType {
18
+ clientId: string;
19
+ host: string;
20
+ port: number;
21
+ keyPath?: string;
22
+ certPath?: string;
23
+ caPath?: string;
24
+ }
25
+
15
26
  export class ConnectionManager extends MessageDispatcher<any> {
16
27
  private clientId: string;
17
28
  private host: string;
18
29
  private port: number;
19
- private device: awsIot.device | null = null;
30
+ private config: mqtt5.Mqtt5ClientConfig;
31
+ private client: mqtt5.Mqtt5Client;
20
32
  private subscribedTopics: Set<string> = new Set();
33
+ private connected = false;
34
+ readonly qos: mqtt5.QoS;
21
35
 
22
- constructor(clientId: string, host: string, port: number) {
36
+ constructor(deviceAgentConfig: DeviceAgentConfigType) {
23
37
  super();
24
- this.clientId = clientId;
25
- this.host = host;
26
- this.port = port;
27
- }
28
38
 
29
- public getIoTDevice() {
30
- return this.device;
39
+ // Use config values if provided, otherwise use defaults
40
+ this.clientId = deviceAgentConfig.clientId;
41
+ this.host = deviceAgentConfig.host;
42
+ this.port = deviceAgentConfig.port;
43
+ this.qos = mqtt5.QoS.AtLeastOnce;
44
+
45
+ const certPath = deviceAgentConfig.certPath || DEVICE_CERTIFICATE_FILE_PATH;
46
+ const keyPath = deviceAgentConfig.keyPath || DEVICE_PRIVATE_KEY_FILE_PATH;
47
+ const caPath = deviceAgentConfig.caPath || AWS_ROOT_CERTIFICATE_FILE_PATH;
48
+
49
+ const builder =
50
+ iot.AwsIotMqtt5ClientConfigBuilder.newDirectMqttBuilderWithMtlsFromPath(
51
+ this.host,
52
+ certPath,
53
+ keyPath
54
+ );
55
+
56
+ builder.withConnectProperties({
57
+ clientId: this.clientId,
58
+ keepAliveIntervalSeconds: 10
59
+ });
60
+
61
+ builder.withCertificateAuthorityFromPath(undefined, caPath);
62
+
63
+ this.config = builder.build();
64
+ this.client = new mqtt5.Mqtt5Client(this.config);
65
+ this.client.start();
31
66
  }
32
67
 
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
- }
68
+ public getIoTDevice() {
69
+ return this.client;
49
70
  }
50
71
 
51
72
  public isConnected(): boolean {
52
- return this.device ? this.device.connected : false;
73
+ return this.connected;
53
74
  }
54
75
 
55
76
  public registerHandler(topic: string, handler: MessageHandler) {
56
77
  super.registerHandler(topic, handler);
57
- this.subscribe(topic);
78
+ void this.subscribe(topic);
58
79
  }
59
80
 
60
- 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
- }
81
+ public async disconnect(): Promise<void> {
82
+ const stopped = once(this.client, mqtt5.Mqtt5Client.STOPPED);
83
+ this.client.stop();
84
+ await stopped;
85
+ logger.debug(`Device Agent has been disconnected from the AWS IoT Core.`);
65
86
  }
66
87
 
67
- public subscribe(topic: string): void {
68
- if (!this.device) {
69
- throw new Error('Must call connect() before subscribe()!');
70
- }
88
+ public async subscribe(topic: string): Promise<void> {
71
89
  if (!this.subscribedTopics.has(topic)) {
72
- this.device.subscribe(topic);
90
+ const suback = await this.client.subscribe({
91
+ subscriptions: [{ qos: mqtt5.QoS.AtLeastOnce, topicFilter: topic }]
92
+ });
73
93
  this.subscribedTopics.add(topic);
74
- logger.debug(`Subscribed to topic: ${topic}`);
94
+ logger.debug(
95
+ `Subscribed to topic: ${topic}, result: ${JSON.stringify(suback)}`
96
+ );
75
97
  }
76
98
  }
77
99
 
78
- public unsubscribe(topic: string): void {
79
- if (!this.device) {
80
- throw new Error('Must call connect() before unsubscribe()!');
81
- }
100
+ public async unsubscribe(topic: string): Promise<void> {
82
101
  if (this.subscribedTopics.has(topic)) {
83
- this.device.unsubscribe(topic);
102
+ const unsuback = await this.client.unsubscribe({
103
+ topicFilters: [topic]
104
+ });
105
+ logger.debug(
106
+ `Unsubscribed from topic: ${topic}, result: ${JSON.stringify(unsuback)}`
107
+ );
84
108
  this.subscribedTopics.delete(topic);
85
- logger.debug(`Unsubscribed from topic: ${topic}`);
86
109
  }
87
110
  }
88
111
 
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 {
101
- this.device.on('connect', (connack: any) => {
102
- logger.info('Device Agent has connected to the cloud.');
103
- cb();
112
+ public initConnectionHandlers(connectCallback: () => void): void {
113
+ this.client.on('attemptingConnect', () => {
114
+ logger.debug(`Device Agent is attempting connection`);
104
115
  });
105
116
 
106
- this.device.on('disconnect', () => {
117
+ this.client.on(
118
+ 'connectionSuccess',
119
+ (eventData: mqtt5.ConnectionSuccessEvent) => {
120
+ logger.info('Device Agent has connected to the cloud.');
121
+ logger.debug(`Connack: ${JSON.stringify(eventData.connack)}`);
122
+ logger.debug(`Settings: ${JSON.stringify(eventData.settings)}`);
123
+ this.connected = true;
124
+ connectCallback();
125
+ }
126
+ );
127
+
128
+ this.client.on('disconnection', (eventData: mqtt5.DisconnectionEvent) => {
107
129
  logger.warn('Device Agent has been disconnected from the cloud');
130
+ logger.warn(`Disconnection event: ${eventData.error.toString()}`);
131
+ if (eventData.disconnect !== undefined) {
132
+ logger.debug(
133
+ 'Disconnect packet: ' + JSON.stringify(eventData.disconnect)
134
+ );
135
+ }
136
+ this.connected = false;
108
137
  });
109
138
 
110
- this.device.on('reconnect', () => {
111
- logger.info(
112
- `Device Agent attempting to re-connect ${new Date().toLocaleString()}`
113
- );
114
- });
139
+ this.client.on(
140
+ 'connectionFailure',
141
+ (eventData: mqtt5.ConnectionFailureEvent) => {
142
+ logger.error(
143
+ `Error connecting to the AWS IoT Core! Disconnection event: ${eventData.error.toString()}`
144
+ );
145
+ if (eventData.connack) {
146
+ logger.debug(
147
+ 'Disconnect packet: ' + JSON.stringify(eventData.connack)
148
+ );
149
+ }
150
+
151
+ this.connected = false;
152
+ }
153
+ );
115
154
 
116
- this.device.on('error', function (e) {
155
+ this.client.on('error', (error) => {
117
156
  logger.error(
118
- `Error connecting to the AWS IoT Core!\n${stringifyError(e)}`
157
+ `Error connecting to the AWS IoT Core! Error:\n${stringifyError(
158
+ error as Error
159
+ )}`
119
160
  );
161
+ this.connected = false;
120
162
  });
121
163
 
122
- this.device.on('close', () => {
123
- logger.warn('Device Agent AWS IoT Core connection closed.');
124
- });
125
-
126
- this.device.on('offline', () => {
127
- logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
164
+ this.client.on('stopped', () => {
165
+ logger.warn(`Device Agent has stopped ${new Date().toLocaleString()}`);
128
166
  void this.logConnectionInfo();
167
+ this.connected = false;
129
168
  });
130
169
 
131
- this.device.on('message', async (topic: string, payload: string) => {
132
- logger.debug(
133
- `Message received on topic: ${topic}:\n${payload.toString()}`
134
- );
135
- try {
136
- const jsonPacket = JSON.parse(payload);
137
- this.dispatch(topic, jsonPacket);
138
- } catch (e) {
139
- logger.error(`Error parsing message!\n${stringifyError(e)}`);
170
+ this.client.on(
171
+ 'messageReceived',
172
+ (eventData: mqtt5.MessageReceivedEvent) => {
173
+ const topic = eventData.message.topicName;
174
+ const payloadBuffer = eventData.message.payload as ArrayBuffer;
175
+ try {
176
+ const payloadString = payloadBuffer
177
+ ? Buffer.from(new Uint8Array(payloadBuffer)).toString('utf-8')
178
+ : null;
179
+ logger.debug(
180
+ `Message received on topic: ${topic}:\n${payloadString}`
181
+ );
182
+ this.dispatch(eventData.message.topicName, payloadString);
183
+ } catch (e) {
184
+ logger.error(
185
+ `Error parsing message on topic ${
186
+ eventData.message.topicName
187
+ }!:\n${stringifyError(e)}`
188
+ );
189
+ }
190
+ }
191
+ );
192
+ }
193
+
194
+ public waitForConnection(timeoutMs = 10000): Promise<void> {
195
+ return new Promise((resolve, reject) => {
196
+ if (this.connected) {
197
+ return resolve(); // already connected
140
198
  }
199
+
200
+ const timeout = setTimeout(() => {
201
+ reject(new Error('Timed out waiting for MQTT connection'));
202
+ }, timeoutMs);
203
+
204
+ this.client.on('connectionSuccess', () => {
205
+ clearTimeout(timeout);
206
+ this.connected = true;
207
+ resolve();
208
+ });
209
+
210
+ this.client.on('disconnection', (event) => {
211
+ const errorString = event.error
212
+ ? event.error.toString()
213
+ : 'Unknown reason';
214
+ logger.warn(
215
+ `Disconnected while waiting for connection: ${errorString}`
216
+ );
217
+ reject(new Error(`Disconnected: ${errorString}`));
218
+ });
141
219
  });
142
220
  }
143
221