@alwaysai/device-agent 2.0.0 → 2.0.2-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 (81) hide show
  1. package/lib/application-control/environment-variables.d.ts +4 -0
  2. package/lib/application-control/environment-variables.d.ts.map +1 -1
  3. package/lib/application-control/environment-variables.js +17 -13
  4. package/lib/application-control/environment-variables.js.map +1 -1
  5. package/lib/application-control/install.d.ts +4 -1
  6. package/lib/application-control/install.d.ts.map +1 -1
  7. package/lib/application-control/install.js +16 -1
  8. package/lib/application-control/install.js.map +1 -1
  9. package/lib/application-control/utils.d.ts.map +1 -1
  10. package/lib/application-control/utils.js +13 -0
  11. package/lib/application-control/utils.js.map +1 -1
  12. package/lib/cloud-connection/base-message-handler.d.ts +27 -0
  13. package/lib/cloud-connection/base-message-handler.d.ts.map +1 -0
  14. package/lib/cloud-connection/base-message-handler.js +72 -0
  15. package/lib/cloud-connection/base-message-handler.js.map +1 -0
  16. package/lib/cloud-connection/connection-manager.d.ts +20 -0
  17. package/lib/cloud-connection/connection-manager.d.ts.map +1 -0
  18. package/lib/cloud-connection/connection-manager.js +164 -0
  19. package/lib/cloud-connection/connection-manager.js.map +1 -0
  20. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +7 -23
  21. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  22. package/lib/cloud-connection/device-agent-cloud-connection.js +49 -517
  23. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  24. package/lib/cloud-connection/device-agent-message-handler.d.ts +22 -0
  25. package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -0
  26. package/lib/cloud-connection/device-agent-message-handler.js +357 -0
  27. package/lib/cloud-connection/device-agent-message-handler.js.map +1 -0
  28. package/lib/cloud-connection/live-updates-handler.d.ts +1 -0
  29. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  30. package/lib/cloud-connection/live-updates-handler.js +13 -10
  31. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  32. package/lib/cloud-connection/message-dispatcher.d.ts +10 -0
  33. package/lib/cloud-connection/message-dispatcher.d.ts.map +1 -0
  34. package/lib/cloud-connection/message-dispatcher.js +27 -0
  35. package/lib/cloud-connection/message-dispatcher.js.map +1 -0
  36. package/lib/cloud-connection/publisher.d.ts +3 -2
  37. package/lib/cloud-connection/publisher.d.ts.map +1 -1
  38. package/lib/cloud-connection/publisher.js +8 -4
  39. package/lib/cloud-connection/publisher.js.map +1 -1
  40. package/lib/cloud-connection/shadow-handler.d.ts +7 -0
  41. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  42. package/lib/cloud-connection/shadow-handler.js +77 -1
  43. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  44. package/lib/cloud-connection/shadow-handler.test.js +5 -2
  45. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  46. package/lib/cloud-connection/transaction-manager.d.ts +9 -4
  47. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  48. package/lib/cloud-connection/transaction-manager.js +22 -11
  49. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  50. package/lib/cloud-connection/transaction-manager.test.js +43 -14
  51. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  52. package/lib/jobs/job-handler.d.ts +23 -0
  53. package/lib/jobs/job-handler.d.ts.map +1 -0
  54. package/lib/jobs/job-handler.js +131 -0
  55. package/lib/jobs/job-handler.js.map +1 -0
  56. package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts +8 -0
  57. package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts.map +1 -0
  58. package/lib/secure-tunneling/secure-tunnel-message-handler.js +42 -0
  59. package/lib/secure-tunneling/secure-tunnel-message-handler.js.map +1 -0
  60. package/lib/subcommands/app/version.d.ts +2 -0
  61. package/lib/subcommands/app/version.d.ts.map +1 -1
  62. package/lib/subcommands/app/version.js +14 -2
  63. package/lib/subcommands/app/version.js.map +1 -1
  64. package/package.json +2 -2
  65. package/src/application-control/environment-variables.ts +31 -21
  66. package/src/application-control/install.ts +24 -3
  67. package/src/application-control/utils.ts +13 -0
  68. package/src/cloud-connection/base-message-handler.ts +118 -0
  69. package/src/cloud-connection/connection-manager.ts +196 -0
  70. package/src/cloud-connection/device-agent-cloud-connection.ts +104 -817
  71. package/src/cloud-connection/device-agent-message-handler.ts +642 -0
  72. package/src/cloud-connection/live-updates-handler.ts +26 -18
  73. package/src/cloud-connection/message-dispatcher.ts +33 -0
  74. package/src/cloud-connection/publisher.ts +28 -23
  75. package/src/cloud-connection/shadow-handler.test.ts +6 -2
  76. package/src/cloud-connection/shadow-handler.ts +129 -1
  77. package/src/cloud-connection/transaction-manager.test.ts +55 -24
  78. package/src/cloud-connection/transaction-manager.ts +42 -31
  79. package/src/jobs/job-handler.ts +146 -0
  80. package/src/secure-tunneling/secure-tunnel-message-handler.ts +56 -0
  81. package/src/subcommands/app/version.ts +20 -2
@@ -0,0 +1,196 @@
1
+ import * as awsIot from 'aws-iot-device-sdk';
2
+ import {
3
+ DEVICE_CERTIFICATE_FILE_PATH,
4
+ DEVICE_PRIVATE_KEY_FILE_PATH
5
+ } from 'alwaysai/lib/infrastructure';
6
+ import { AWS_ROOT_CERTIFICATE_FILE_PATH } from '../util/directories';
7
+ import { stringifyError } from 'alwaysai/lib/util';
8
+ import { logger } from '../util/logger';
9
+ import { promisify } from 'util';
10
+ import { exec } from 'child_process';
11
+ import { MessageDispatcher, MessageHandler } from './message-dispatcher';
12
+
13
+ const exec_promise = promisify(exec);
14
+
15
+ export class ConnectionManager extends MessageDispatcher<any> {
16
+ private clientId: string;
17
+ private host: string;
18
+ private port: number;
19
+ private device: awsIot.device | null = null;
20
+ private subscribedTopics: Set<string> = new Set();
21
+
22
+ constructor(clientId: string, host: string, port: number) {
23
+ super();
24
+ this.clientId = clientId;
25
+ this.host = host;
26
+ this.port = port;
27
+ }
28
+
29
+ public getIoTDevice() {
30
+ return this.device;
31
+ }
32
+
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
+ public isConnected(): boolean {
52
+ return this.device ? this.device.connected : false;
53
+ }
54
+
55
+ public registerHandler(topic: string, handler: MessageHandler) {
56
+ super.registerHandler(topic, handler);
57
+ this.subscribe(topic);
58
+ }
59
+
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
+ }
65
+ }
66
+
67
+ public subscribe(topic: string): void {
68
+ if (!this.device) {
69
+ throw new Error('Must call connect() before subscribe()!');
70
+ }
71
+ if (!this.subscribedTopics.has(topic)) {
72
+ this.device.subscribe(topic);
73
+ this.subscribedTopics.add(topic);
74
+ logger.debug(`Subscribed to topic: ${topic}`);
75
+ }
76
+ }
77
+
78
+ public unsubscribe(topic: string): void {
79
+ if (!this.device) {
80
+ throw new Error('Must call connect() before unsubscribe()!');
81
+ }
82
+ if (this.subscribedTopics.has(topic)) {
83
+ this.device.unsubscribe(topic);
84
+ this.subscribedTopics.delete(topic);
85
+ logger.debug(`Unsubscribed from topic: ${topic}`);
86
+ }
87
+ }
88
+
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();
104
+ });
105
+
106
+ this.device.on('disconnect', () => {
107
+ logger.warn('Device Agent has been disconnected from the cloud');
108
+ });
109
+
110
+ this.device.on('reconnect', () => {
111
+ logger.info(
112
+ `Device Agent attempting to re-connect ${new Date().toLocaleString()}`
113
+ );
114
+ });
115
+
116
+ this.device.on('error', function (e) {
117
+ logger.error(
118
+ `Error connecting to the AWS IoT Core!\n${stringifyError(e)}`
119
+ );
120
+ });
121
+
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()}`);
128
+ void this.logConnectionInfo();
129
+ });
130
+
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)}`);
140
+ }
141
+ });
142
+ }
143
+
144
+ private async logConnectionInfo() {
145
+ try {
146
+ /**
147
+ * We're using the 'netcat' or 'nc' command to test the connection to the IoT Core endpoint.
148
+ * This command doesn't always exit (see below), so
149
+ * we use timeout to break out of the prompt
150
+ * and catch the resulting error/parse the resulting stderr
151
+ *
152
+ * Sample command for current host and port:
153
+ * nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
154
+ *
155
+ * Sample output when port is not blocked and host is reachable:
156
+ * $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443
157
+ * Connection to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443 port [tcp/https] succeeded!
158
+ *
159
+ *
160
+ * Sample output when port is blocked (will repeatedly try until ctrl-C out):
161
+ * $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
162
+ * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
163
+ * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
164
+ * nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
165
+ * ^C
166
+ *
167
+ *
168
+ * Sample command/output when the port isn't enable on that host:
169
+ * $ nc -zv -w 1 localhost 8883
170
+ * nc: connect to localhost port 8883 (tcp) failed: Connection refused
171
+ */
172
+ await exec_promise(`nc -zv -w 1 ${this.host} ${this.port}`, {
173
+ timeout: 2000
174
+ });
175
+ } catch (err) {
176
+ const output = JSON.stringify(err['stderr']);
177
+ if (output.indexOf('not known') !== -1) {
178
+ logger.warn(
179
+ 'Iot Core endpoint appears to be unreachable, internet connection may be unstable or the host may be down.'
180
+ );
181
+ } else if (output.indexOf('timed out') !== -1) {
182
+ logger.warn(
183
+ `Internet connection appears fine, however the endpoint was not reachable on the current connection port: ${this.port}\nPlease check if a firewall is in place.`
184
+ );
185
+ } else if (output.indexOf('refused') !== -1) {
186
+ logger.warn(
187
+ `The connection was refused, likely ${this.host} is not running a service on ${this.port}.`
188
+ );
189
+ } else {
190
+ logger.warn(
191
+ `Output from checking connection to ${this.host} on ${this.port}: ${output}`
192
+ );
193
+ }
194
+ }
195
+ }
196
+ }