@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.
- package/lib/application-control/environment-variables.d.ts +4 -0
- package/lib/application-control/environment-variables.d.ts.map +1 -1
- package/lib/application-control/environment-variables.js +17 -13
- package/lib/application-control/environment-variables.js.map +1 -1
- package/lib/application-control/install.d.ts +4 -1
- package/lib/application-control/install.d.ts.map +1 -1
- package/lib/application-control/install.js +16 -1
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/utils.d.ts.map +1 -1
- package/lib/application-control/utils.js +13 -0
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/base-message-handler.d.ts +27 -0
- package/lib/cloud-connection/base-message-handler.d.ts.map +1 -0
- package/lib/cloud-connection/base-message-handler.js +72 -0
- package/lib/cloud-connection/base-message-handler.js.map +1 -0
- package/lib/cloud-connection/connection-manager.d.ts +20 -0
- package/lib/cloud-connection/connection-manager.d.ts.map +1 -0
- package/lib/cloud-connection/connection-manager.js +164 -0
- package/lib/cloud-connection/connection-manager.js.map +1 -0
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +7 -23
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +49 -517
- package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
- package/lib/cloud-connection/device-agent-message-handler.d.ts +22 -0
- package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -0
- package/lib/cloud-connection/device-agent-message-handler.js +357 -0
- package/lib/cloud-connection/device-agent-message-handler.js.map +1 -0
- package/lib/cloud-connection/live-updates-handler.d.ts +1 -0
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
- package/lib/cloud-connection/live-updates-handler.js +13 -10
- package/lib/cloud-connection/live-updates-handler.js.map +1 -1
- package/lib/cloud-connection/message-dispatcher.d.ts +10 -0
- package/lib/cloud-connection/message-dispatcher.d.ts.map +1 -0
- package/lib/cloud-connection/message-dispatcher.js +27 -0
- package/lib/cloud-connection/message-dispatcher.js.map +1 -0
- package/lib/cloud-connection/publisher.d.ts +3 -2
- package/lib/cloud-connection/publisher.d.ts.map +1 -1
- package/lib/cloud-connection/publisher.js +8 -4
- package/lib/cloud-connection/publisher.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.d.ts +7 -0
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +77 -1
- package/lib/cloud-connection/shadow-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.test.js +5 -2
- package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.d.ts +9 -4
- package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
- package/lib/cloud-connection/transaction-manager.js +22 -11
- package/lib/cloud-connection/transaction-manager.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.test.js +43 -14
- package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
- package/lib/jobs/job-handler.d.ts +23 -0
- package/lib/jobs/job-handler.d.ts.map +1 -0
- package/lib/jobs/job-handler.js +131 -0
- package/lib/jobs/job-handler.js.map +1 -0
- package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts +8 -0
- package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts.map +1 -0
- package/lib/secure-tunneling/secure-tunnel-message-handler.js +42 -0
- package/lib/secure-tunneling/secure-tunnel-message-handler.js.map +1 -0
- package/lib/subcommands/app/version.d.ts +2 -0
- package/lib/subcommands/app/version.d.ts.map +1 -1
- package/lib/subcommands/app/version.js +14 -2
- package/lib/subcommands/app/version.js.map +1 -1
- package/package.json +2 -2
- package/src/application-control/environment-variables.ts +31 -21
- package/src/application-control/install.ts +24 -3
- package/src/application-control/utils.ts +13 -0
- package/src/cloud-connection/base-message-handler.ts +118 -0
- package/src/cloud-connection/connection-manager.ts +196 -0
- package/src/cloud-connection/device-agent-cloud-connection.ts +104 -817
- package/src/cloud-connection/device-agent-message-handler.ts +642 -0
- package/src/cloud-connection/live-updates-handler.ts +26 -18
- package/src/cloud-connection/message-dispatcher.ts +33 -0
- package/src/cloud-connection/publisher.ts +28 -23
- package/src/cloud-connection/shadow-handler.test.ts +6 -2
- package/src/cloud-connection/shadow-handler.ts +129 -1
- package/src/cloud-connection/transaction-manager.test.ts +55 -24
- package/src/cloud-connection/transaction-manager.ts +42 -31
- package/src/jobs/job-handler.ts +146 -0
- package/src/secure-tunneling/secure-tunnel-message-handler.ts +56 -0
- 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
|
+
}
|