@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.
- package/lib/application-control/config.js +1 -1
- package/lib/application-control/config.js.map +1 -1
- package/lib/application-control/install.d.ts.map +1 -1
- package/lib/application-control/install.js +7 -3
- package/lib/application-control/install.js.map +1 -1
- package/lib/cloud-connection/base-message-handler.d.ts.map +1 -1
- package/lib/cloud-connection/base-message-handler.js +5 -4
- package/lib/cloud-connection/base-message-handler.js.map +1 -1
- package/lib/cloud-connection/bootstrap-agent.d.ts +16 -0
- package/lib/cloud-connection/bootstrap-agent.d.ts.map +1 -0
- package/lib/cloud-connection/{device-agent.js → bootstrap-agent.js} +45 -22
- package/lib/cloud-connection/bootstrap-agent.js.map +1 -0
- package/lib/cloud-connection/connection-manager.d.ts +20 -9
- package/lib/cloud-connection/connection-manager.d.ts.map +1 -1
- package/lib/cloud-connection/connection-manager.js +97 -68
- package/lib/cloud-connection/connection-manager.js.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +3 -1
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +62 -50
- package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
- package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-message-handler.js +19 -18
- package/lib/cloud-connection/device-agent-message-handler.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
- package/lib/cloud-connection/live-updates-handler.js +11 -4
- package/lib/cloud-connection/live-updates-handler.js.map +1 -1
- package/lib/cloud-connection/passthrough-handler.d.ts +3 -3
- package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
- package/lib/cloud-connection/passthrough-handler.js +105 -79
- package/lib/cloud-connection/passthrough-handler.js.map +1 -1
- package/lib/cloud-connection/publisher.d.ts +1 -1
- package/lib/cloud-connection/publisher.d.ts.map +1 -1
- package/lib/cloud-connection/publisher.js +22 -20
- package/lib/cloud-connection/publisher.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +3 -3
- package/lib/cloud-connection/shadow-handler.js.map +1 -1
- package/lib/cloud-connection/shadow.d.ts.map +1 -1
- package/lib/cloud-connection/shadow.js +1 -1
- package/lib/cloud-connection/shadow.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
- package/lib/cloud-connection/transaction-manager.js +17 -7
- package/lib/cloud-connection/transaction-manager.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.test.js +52 -44
- package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
- package/lib/device-control/device-control.d.ts.map +1 -1
- package/lib/device-control/device-control.js +13 -9
- package/lib/device-control/device-control.js.map +1 -1
- package/lib/docker/docker-compose.d.ts.map +1 -1
- package/lib/docker/docker-compose.js +1 -1
- package/lib/docker/docker-compose.js.map +1 -1
- package/lib/environment.d.ts +3 -0
- package/lib/environment.d.ts.map +1 -1
- package/lib/environment.js +12 -1
- package/lib/environment.js.map +1 -1
- package/lib/index.js +12 -0
- package/lib/index.js.map +1 -1
- package/lib/infrastructure/config-check-utility.js +2 -2
- package/lib/infrastructure/config-check-utility.js.map +1 -1
- package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -1
- package/lib/infrastructure/legacy-migration/legacy-migration.js +6 -10
- package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -1
- package/lib/jobs/job-handler.d.ts +1 -1
- package/lib/jobs/job-handler.d.ts.map +1 -1
- package/lib/jobs/job-handler.js +4 -4
- package/lib/jobs/job-handler.js.map +1 -1
- package/lib/local-connection/rabbitmq-container.d.ts +6 -0
- package/lib/local-connection/rabbitmq-container.d.ts.map +1 -0
- package/lib/local-connection/rabbitmq-container.js +111 -0
- package/lib/local-connection/rabbitmq-container.js.map +1 -0
- package/lib/local-connection/rabbitmq-container.test.d.ts +2 -0
- package/lib/local-connection/rabbitmq-container.test.d.ts.map +1 -0
- package/lib/local-connection/rabbitmq-container.test.js +219 -0
- package/lib/local-connection/rabbitmq-container.test.js.map +1 -0
- package/lib/subcommands/app/analytics.d.ts.map +1 -1
- package/lib/subcommands/app/analytics.js +2 -3
- package/lib/subcommands/app/analytics.js.map +1 -1
- package/lib/subcommands/app/env-vars.d.ts.map +1 -1
- package/lib/subcommands/app/env-vars.js +4 -6
- package/lib/subcommands/app/env-vars.js.map +1 -1
- package/lib/subcommands/app/models.d.ts.map +1 -1
- package/lib/subcommands/app/models.js +2 -3
- package/lib/subcommands/app/models.js.map +1 -1
- package/lib/subcommands/app/shadow.d.ts.map +1 -1
- package/lib/subcommands/app/shadow.js +4 -6
- package/lib/subcommands/app/shadow.js.map +1 -1
- package/lib/subcommands/app/version.d.ts.map +1 -1
- package/lib/subcommands/app/version.js +6 -9
- package/lib/subcommands/app/version.js.map +1 -1
- package/lib/subcommands/device/clean.d.ts.map +1 -1
- package/lib/subcommands/device/clean.js +15 -17
- package/lib/subcommands/device/clean.js.map +1 -1
- package/lib/subcommands/device/index.d.ts.map +1 -1
- package/lib/subcommands/device/index.js +3 -1
- package/lib/subcommands/device/index.js.map +1 -1
- package/lib/subcommands/device/local-connection.d.ts +2 -0
- package/lib/subcommands/device/local-connection.d.ts.map +1 -0
- package/lib/subcommands/device/local-connection.js +17 -0
- package/lib/subcommands/device/local-connection.js.map +1 -0
- package/lib/subcommands/index.d.ts +4 -1
- package/lib/subcommands/index.d.ts.map +1 -1
- package/lib/subcommands/index.js +1 -3
- package/lib/subcommands/index.js.map +1 -1
- package/lib/util/check-for-updates.d.ts.map +1 -1
- package/lib/util/check-for-updates.js +2 -2
- package/lib/util/check-for-updates.js.map +1 -1
- package/lib/util/file.d.ts.map +1 -1
- package/lib/util/file.js +6 -1
- package/lib/util/file.js.map +1 -1
- package/lib/util/file.test.js +1 -1
- package/lib/util/file.test.js.map +1 -1
- package/lib/util/get-device-id.d.ts.map +1 -1
- package/lib/util/get-device-id.js +1 -1
- package/lib/util/get-device-id.js.map +1 -1
- package/package.json +3 -3
- package/readme.md +16 -4
- package/src/application-control/config.ts +1 -1
- package/src/application-control/install.ts +11 -5
- package/src/cloud-connection/base-message-handler.ts +10 -5
- package/src/cloud-connection/{device-agent.ts → bootstrap-agent.ts} +68 -35
- package/src/cloud-connection/connection-manager.ts +160 -82
- package/src/cloud-connection/device-agent-cloud-connection.ts +108 -98
- package/src/cloud-connection/device-agent-message-handler.ts +10 -7
- package/src/cloud-connection/live-updates-handler.ts +12 -5
- package/src/cloud-connection/passthrough-handler.ts +137 -92
- package/src/cloud-connection/publisher.ts +30 -28
- package/src/cloud-connection/shadow-handler.ts +3 -3
- package/src/cloud-connection/shadow.ts +3 -1
- package/src/cloud-connection/transaction-manager.test.ts +60 -41
- package/src/cloud-connection/transaction-manager.ts +26 -12
- package/src/device-control/device-control.ts +23 -13
- package/src/docker/docker-compose.ts +3 -1
- package/src/environment.ts +17 -0
- package/src/index.ts +19 -0
- package/src/infrastructure/config-check-utility.ts +2 -2
- package/src/infrastructure/legacy-migration/legacy-migration.ts +8 -13
- package/src/jobs/job-handler.ts +4 -4
- package/src/local-connection/rabbitmq-container.test.ts +255 -0
- package/src/local-connection/rabbitmq-container.ts +151 -0
- package/src/subcommands/app/analytics.ts +2 -3
- package/src/subcommands/app/env-vars.ts +4 -6
- package/src/subcommands/app/models.ts +2 -3
- package/src/subcommands/app/shadow.ts +4 -6
- package/src/subcommands/app/version.ts +7 -8
- package/src/subcommands/device/clean.ts +20 -19
- package/src/subcommands/device/index.ts +3 -1
- package/src/subcommands/device/local-connection.ts +16 -0
- package/src/subcommands/index.ts +1 -3
- package/src/util/check-for-updates.ts +4 -2
- package/src/util/file.test.ts +1 -1
- package/src/util/file.ts +7 -1
- package/src/util/get-device-id.ts +3 -1
- package/lib/cloud-connection/bootstrap-provision.d.ts +0 -2
- package/lib/cloud-connection/bootstrap-provision.d.ts.map +0 -1
- package/lib/cloud-connection/bootstrap-provision.js +0 -35
- package/lib/cloud-connection/bootstrap-provision.js.map +0 -1
- package/lib/cloud-connection/device-agent.d.ts +0 -21
- package/lib/cloud-connection/device-agent.d.ts.map +0 -1
- package/lib/cloud-connection/device-agent.js.map +0 -1
- package/lib/local-connection/rabbitmq-connection.d.ts +0 -7
- package/lib/local-connection/rabbitmq-connection.d.ts.map +0 -1
- package/lib/local-connection/rabbitmq-connection.js +0 -95
- package/lib/local-connection/rabbitmq-connection.js.map +0 -1
- package/lib/subcommands/rabbitmq-connection.d.ts +0 -2
- package/lib/subcommands/rabbitmq-connection.d.ts.map +0 -1
- package/lib/subcommands/rabbitmq-connection.js +0 -14
- package/lib/subcommands/rabbitmq-connection.js.map +0 -1
- package/lib/util/clean-certs.d.ts +0 -2
- package/lib/util/clean-certs.d.ts.map +0 -1
- package/lib/util/clean-certs.js +0 -17
- package/lib/util/clean-certs.js.map +0 -1
- package/src/cloud-connection/bootstrap-provision.ts +0 -43
- package/src/local-connection/rabbitmq-connection.ts +0 -124
- package/src/subcommands/rabbitmq-connection.ts +0 -11
- 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
|
|
40
|
-
|
|
41
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
36
|
+
constructor(deviceAgentConfig: DeviceAgentConfigType) {
|
|
23
37
|
super();
|
|
24
|
-
this.clientId = clientId;
|
|
25
|
-
this.host = host;
|
|
26
|
-
this.port = port;
|
|
27
|
-
}
|
|
28
38
|
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
34
|
-
|
|
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.
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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.
|
|
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(
|
|
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.
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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.
|
|
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.
|
|
111
|
-
|
|
112
|
-
|
|
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.
|
|
155
|
+
this.client.on('error', (error) => {
|
|
117
156
|
logger.error(
|
|
118
|
-
`Error connecting to the AWS IoT Core
|
|
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.
|
|
123
|
-
logger.warn(
|
|
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.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
|