@alwaysai/device-agent 0.0.13 → 0.0.15
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/backup.js +3 -3
- package/lib/application-control/backup.js.map +1 -1
- package/lib/application-control/index.d.ts +4 -4
- package/lib/application-control/index.d.ts.map +1 -1
- package/lib/application-control/index.js +1 -4
- package/lib/application-control/index.js.map +1 -1
- package/lib/application-control/install.d.ts +1 -1
- package/lib/application-control/install.d.ts.map +1 -1
- package/lib/application-control/install.js +41 -54
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/models.d.ts +0 -4
- package/lib/application-control/models.d.ts.map +1 -1
- package/lib/application-control/models.js +13 -22
- package/lib/application-control/models.js.map +1 -1
- package/lib/application-control/status.d.ts +0 -6
- package/lib/application-control/status.d.ts.map +1 -1
- package/lib/application-control/status.js +3 -19
- package/lib/application-control/status.js.map +1 -1
- package/lib/application-control/utils.d.ts +3 -0
- package/lib/application-control/utils.d.ts.map +1 -1
- package/lib/application-control/utils.js +50 -21
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/bootstrap-provision.d.ts +1 -1
- package/lib/cloud-connection/bootstrap-provision.d.ts.map +1 -1
- package/lib/cloud-connection/bootstrap-provision.js +9 -9
- package/lib/cloud-connection/bootstrap-provision.js.map +1 -1
- package/lib/cloud-connection/cmd-status.d.ts +8 -0
- package/lib/cloud-connection/cmd-status.d.ts.map +1 -0
- package/lib/cloud-connection/cmd-status.js +62 -0
- package/lib/cloud-connection/cmd-status.js.map +1 -0
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +10 -2
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +156 -66
- package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
- package/lib/cloud-connection/device-agent.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent.js +4 -3
- package/lib/cloud-connection/device-agent.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.d.ts +10 -18
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
- package/lib/cloud-connection/live-updates-handler.js +50 -50
- package/lib/cloud-connection/live-updates-handler.js.map +1 -1
- package/lib/cloud-connection/messages.d.ts +3 -1
- package/lib/cloud-connection/messages.d.ts.map +1 -1
- package/lib/cloud-connection/messages.js +13 -1
- package/lib/cloud-connection/messages.js.map +1 -1
- package/lib/cloud-connection/passthrough-handler.d.ts +11 -0
- package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -0
- package/lib/cloud-connection/passthrough-handler.js +59 -0
- package/lib/cloud-connection/passthrough-handler.js.map +1 -0
- package/lib/cloud-connection/publisher.d.ts +1 -0
- package/lib/cloud-connection/publisher.d.ts.map +1 -1
- package/lib/cloud-connection/publisher.js +14 -0
- package/lib/cloud-connection/publisher.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.d.ts +2 -3
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +18 -4
- package/lib/cloud-connection/shadow-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.test.d.ts +2 -0
- package/lib/cloud-connection/shadow-handler.test.d.ts.map +1 -0
- package/lib/cloud-connection/shadow-handler.test.js +321 -0
- package/lib/cloud-connection/shadow-handler.test.js.map +1 -0
- package/lib/environment.d.ts +1 -0
- package/lib/environment.d.ts.map +1 -1
- package/lib/environment.js +3 -2
- package/lib/environment.js.map +1 -1
- package/lib/index.js +2 -2
- package/lib/index.js.map +1 -1
- package/lib/infrastructure/agent-config.d.ts +15 -48
- package/lib/infrastructure/agent-config.d.ts.map +1 -1
- package/lib/infrastructure/agent-config.js.map +1 -1
- package/lib/infrastructure/agent-config.test.js +0 -6
- package/lib/infrastructure/agent-config.test.js.map +1 -1
- package/lib/infrastructure/system-id.js +2 -2
- package/lib/infrastructure/system-id.js.map +1 -1
- package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -1
- package/lib/infrastructure/tokens-and-device-cfg.js +5 -9
- package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -1
- package/lib/local-connection/rabbitmq-connection.d.ts +4 -0
- package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -0
- package/lib/local-connection/rabbitmq-connection.js +58 -0
- package/lib/local-connection/rabbitmq-connection.js.map +1 -0
- package/lib/subcommands/app/app.d.ts +4 -3
- package/lib/subcommands/app/app.d.ts.map +1 -1
- package/lib/subcommands/app/app.js +78 -27
- package/lib/subcommands/app/app.js.map +1 -1
- package/lib/subcommands/app/index.js +2 -2
- package/lib/subcommands/device/clean.js +4 -4
- package/lib/subcommands/device/clean.js.map +1 -1
- package/lib/subcommands/device/device.d.ts +1 -1
- package/lib/subcommands/device/device.d.ts.map +1 -1
- package/lib/subcommands/device/device.js +9 -10
- package/lib/subcommands/device/device.js.map +1 -1
- package/lib/subcommands/index.d.ts +0 -1
- package/lib/subcommands/index.d.ts.map +1 -1
- package/lib/subcommands/login.d.ts +0 -1
- package/lib/subcommands/login.d.ts.map +1 -1
- package/lib/subcommands/login.js +1 -9
- package/lib/subcommands/login.js.map +1 -1
- package/lib/util/directories.d.ts +11 -12
- package/lib/util/directories.d.ts.map +1 -1
- package/lib/util/directories.js +24 -29
- package/lib/util/directories.js.map +1 -1
- package/lib/util/fetch-with-timeout.d.ts +4 -0
- package/lib/util/fetch-with-timeout.d.ts.map +1 -0
- package/lib/util/fetch-with-timeout.js +15 -0
- package/lib/util/fetch-with-timeout.js.map +1 -0
- package/lib/util/logger.js +1 -0
- package/lib/util/logger.js.map +1 -1
- package/lib/util/require-logged-in-and-paid-plan.d.ts +2 -0
- package/lib/util/require-logged-in-and-paid-plan.d.ts.map +1 -0
- package/lib/util/require-logged-in-and-paid-plan.js +18 -0
- package/lib/util/require-logged-in-and-paid-plan.js.map +1 -0
- package/package.json +20 -32
- package/readme.md +100 -89
- package/src/application-control/backup.ts +3 -3
- package/src/application-control/index.ts +0 -6
- package/src/application-control/install.ts +53 -73
- package/src/application-control/models.ts +7 -19
- package/src/application-control/status.ts +3 -19
- package/src/application-control/utils.ts +61 -22
- package/src/cloud-connection/bootstrap-provision.ts +13 -10
- package/src/cloud-connection/cmd-status.ts +71 -0
- package/src/cloud-connection/device-agent-cloud-connection.ts +211 -102
- package/src/cloud-connection/device-agent.ts +7 -4
- package/src/cloud-connection/live-updates-handler.ts +79 -86
- package/src/cloud-connection/messages.ts +22 -1
- package/src/cloud-connection/passthrough-handler.ts +67 -0
- package/src/cloud-connection/publisher.ts +21 -0
- package/src/cloud-connection/shadow-handler.test.ts +361 -0
- package/src/cloud-connection/shadow-handler.ts +28 -7
- package/src/environment.ts +4 -1
- package/src/index.ts +2 -2
- package/src/infrastructure/agent-config.test.ts +0 -7
- package/src/infrastructure/agent-config.ts +24 -2
- package/src/infrastructure/system-id.ts +1 -1
- package/src/infrastructure/tokens-and-device-cfg.ts +8 -13
- package/src/local-connection/rabbitmq-connection.ts +53 -0
- package/src/subcommands/app/app.ts +82 -31
- package/src/subcommands/app/index.ts +4 -4
- package/src/subcommands/device/clean.ts +4 -4
- package/src/subcommands/device/device.ts +13 -13
- package/src/subcommands/login.ts +1 -9
- package/src/util/directories.ts +31 -29
- package/src/util/fetch-with-timeout.ts +18 -0
- package/src/util/logger.ts +2 -0
- package/src/util/require-logged-in-and-paid-plan.ts +16 -0
- package/lib/cloud-connection/app-install-status.d.ts +0 -16
- package/lib/cloud-connection/app-install-status.d.ts.map +0 -1
- package/lib/cloud-connection/app-install-status.js +0 -53
- package/lib/cloud-connection/app-install-status.js.map +0 -1
- package/src/cloud-connection/app-install-status.ts +0 -62
|
@@ -3,11 +3,11 @@ const awsIot = require('aws-iot-device-sdk');
|
|
|
3
3
|
import { getIoTCoreEndpointUrl } from '../infrastructure/urls';
|
|
4
4
|
import { existsSync } from 'fs';
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
getCertificateFilePath,
|
|
8
|
-
BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH,
|
|
6
|
+
BOOTSTRAP_PRIVATE_KEY_FILE_PATH,
|
|
9
7
|
AWS_ROOT_CERTIFICATE_FILE_PATH,
|
|
10
|
-
BOOTSTRAP_CERTIFICATES_DIR_PATH
|
|
8
|
+
BOOTSTRAP_CERTIFICATES_DIR_PATH,
|
|
9
|
+
DEVICE_PRIVATE_KEY_FILE_PATH,
|
|
10
|
+
DEVICE_CERTIFICATE_FILE_PATH
|
|
11
11
|
} from '../util/directories';
|
|
12
12
|
import {
|
|
13
13
|
keyMirrors,
|
|
@@ -31,18 +31,21 @@ import {
|
|
|
31
31
|
uninstallApp,
|
|
32
32
|
updateAppCfg
|
|
33
33
|
} from '../application-control';
|
|
34
|
-
import { AppConfigUpdate, ShadowHandler } from './shadow-handler';
|
|
34
|
+
import { AppConfigUpdate, ShadowHandler, ShadowTopics } from './shadow-handler';
|
|
35
35
|
import { Publisher } from './publisher';
|
|
36
36
|
import { LiveUpdatesHandler } from './live-updates-handler';
|
|
37
37
|
import { bootstrapProvision } from './bootstrap-provision';
|
|
38
|
-
import { AppInstallStatusManager } from './app-install-status';
|
|
39
38
|
import { AppConfig } from '@alwaysai/app-configuration-schemas';
|
|
39
|
+
import { CmdStatusManager } from './cmd-status';
|
|
40
|
+
import { PassthroughHandler, runChannel } from './passthrough-handler';
|
|
41
|
+
import { ALWAYSAI_ANALYTICS_PASSTHROUGH } from '../environment';
|
|
42
|
+
import { getAppInstallStatusMessage } from './messages';
|
|
40
43
|
|
|
41
44
|
export class DeviceAgentCloudConnection {
|
|
42
45
|
private shadowHandler: ShadowHandler;
|
|
43
|
-
|
|
46
|
+
public publisher: Publisher;
|
|
47
|
+
private cmdStatusMgr: CmdStatusManager;
|
|
44
48
|
private liveUpdatesHandler: LiveUpdatesHandler;
|
|
45
|
-
private appInstallStatusMgr: AppInstallStatusManager;
|
|
46
49
|
private device = awsIot.device;
|
|
47
50
|
|
|
48
51
|
private clientId = getDeviceUuid();
|
|
@@ -51,38 +54,62 @@ export class DeviceAgentCloudConnection {
|
|
|
51
54
|
// FIXME: Add support for multiple simultaneous project updates
|
|
52
55
|
private newAppCfgQueue: AppConfig[] = [];
|
|
53
56
|
|
|
54
|
-
private handleAppStateControl(payload: AppStateControlPacket) {
|
|
57
|
+
private async handleAppStateControl(payload: AppStateControlPacket) {
|
|
55
58
|
const { baseCommand, projectId } = payload;
|
|
56
59
|
switch (baseCommand) {
|
|
57
60
|
case keyMirrors.appStateControl.start:
|
|
58
|
-
startApp({ projectId });
|
|
61
|
+
await startApp({ projectId });
|
|
59
62
|
break;
|
|
60
63
|
case keyMirrors.appStateControl.stop:
|
|
61
|
-
stopApp({ projectId });
|
|
64
|
+
await stopApp({ projectId });
|
|
62
65
|
break;
|
|
63
66
|
case keyMirrors.appStateControl.restart:
|
|
64
|
-
restartApp({ projectId });
|
|
67
|
+
await restartApp({ projectId });
|
|
65
68
|
break;
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
|
|
69
|
-
private handleAppVersionControl(payload: AppVersionControlPacket) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
private async handleAppVersionControl(payload: AppVersionControlPacket) {
|
|
73
|
+
switch (payload.baseCommand) {
|
|
74
|
+
case keyMirrors.appVersionControl.install: {
|
|
75
|
+
const { projectId, appReleaseHash } = payload;
|
|
76
|
+
await this.cmdStatusMgr.start(projectId);
|
|
77
|
+
await this.liveUpdatesHandler.enableAppInstallStatus({
|
|
78
|
+
projectId,
|
|
79
|
+
appReleaseHash
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const signedUrlsRequest = { projectId, appReleaseHash };
|
|
83
|
+
await this.publishCloudRequest({
|
|
84
|
+
messageType: keyMirrors.agentMessageType.signed_urls_request,
|
|
85
|
+
signedUrlsRequest
|
|
86
|
+
});
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case keyMirrors.appVersionControl.uninstall: {
|
|
90
|
+
const { projectId } = payload;
|
|
91
|
+
await this.atomicApplicationUninstall(projectId);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
logger.warn(
|
|
96
|
+
`Ignore App Version Control packet: ${JSON.stringify(
|
|
97
|
+
payload,
|
|
98
|
+
null,
|
|
99
|
+
2
|
|
100
|
+
)}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
76
103
|
}
|
|
77
104
|
|
|
78
105
|
private handleDeviceCommand = async (packet: any) => {
|
|
79
106
|
// TODO
|
|
80
107
|
};
|
|
81
108
|
|
|
82
|
-
private handleAgentCommand(message: LiveUpdatesToggleMessage) {
|
|
109
|
+
private async handleAgentCommand(message: LiveUpdatesToggleMessage) {
|
|
83
110
|
switch (message.messageType) {
|
|
84
111
|
case keyMirrors.clientMessageType.live_state_updates:
|
|
85
|
-
this.liveUpdatesHandler.
|
|
112
|
+
await this.liveUpdatesHandler.handleToggles(message.liveUpdatesToggles);
|
|
86
113
|
break;
|
|
87
114
|
default:
|
|
88
115
|
logger.error(
|
|
@@ -100,6 +127,49 @@ export class DeviceAgentCloudConnection {
|
|
|
100
127
|
this.device.subscribe(topic);
|
|
101
128
|
}
|
|
102
129
|
|
|
130
|
+
private async atomicApplicationUninstall(projectId: string) {
|
|
131
|
+
const appReleaseHash = await AgentConfigFile().getAppVersion({
|
|
132
|
+
projectId
|
|
133
|
+
});
|
|
134
|
+
await this.cmdStatusMgr.start(projectId);
|
|
135
|
+
await this.liveUpdatesHandler.enableAppInstallStatus({
|
|
136
|
+
projectId,
|
|
137
|
+
appReleaseHash
|
|
138
|
+
});
|
|
139
|
+
try {
|
|
140
|
+
await uninstallApp({ projectId });
|
|
141
|
+
this.shadowHandler.deleteProjectShadow(projectId);
|
|
142
|
+
|
|
143
|
+
await this.cmdStatusMgr.stop(projectId);
|
|
144
|
+
await this.liveUpdatesHandler.disableAppInstallStatus({
|
|
145
|
+
projectId
|
|
146
|
+
});
|
|
147
|
+
// Send final status message
|
|
148
|
+
this.publisher.publishToClient(
|
|
149
|
+
await getAppInstallStatusMessage(
|
|
150
|
+
keyMirrors.appInstallStatus.success,
|
|
151
|
+
'',
|
|
152
|
+
appReleaseHash
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
logger.error(`Failed to uninstall ${projectId}: ${e}`);
|
|
157
|
+
const message: string = e.message;
|
|
158
|
+
await this.cmdStatusMgr.stop(projectId);
|
|
159
|
+
await this.liveUpdatesHandler.disableAppInstallStatus({
|
|
160
|
+
projectId
|
|
161
|
+
});
|
|
162
|
+
// Send final status message
|
|
163
|
+
this.publisher.publishToClient(
|
|
164
|
+
await getAppInstallStatusMessage(
|
|
165
|
+
keyMirrors.appInstallStatus.failure,
|
|
166
|
+
message,
|
|
167
|
+
appReleaseHash
|
|
168
|
+
)
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
103
173
|
// eslint-disable-next-line
|
|
104
174
|
private async atomicApplicationUpdate<T extends any[], R extends any>(
|
|
105
175
|
func: (...args: T) => R,
|
|
@@ -107,53 +177,67 @@ export class DeviceAgentCloudConnection {
|
|
|
107
177
|
projectId: string,
|
|
108
178
|
appReleaseHash: string
|
|
109
179
|
) {
|
|
110
|
-
this.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
this.liveUpdatesHandler.update({
|
|
116
|
-
appInstallStatus: { toggle: true, appReleaseHash }
|
|
180
|
+
await this.cmdStatusMgr.start(projectId);
|
|
181
|
+
await this.liveUpdatesHandler.enableAppInstallStatus({
|
|
182
|
+
projectId,
|
|
183
|
+
appReleaseHash
|
|
117
184
|
});
|
|
118
185
|
|
|
119
186
|
// Install the app and models
|
|
120
187
|
try {
|
|
121
188
|
const out: R = await func(...args);
|
|
122
|
-
this.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
);
|
|
126
|
-
this.liveUpdatesHandler.update({
|
|
127
|
-
appInstallStatus: { toggle: false, appReleaseHash }
|
|
189
|
+
await this.cmdStatusMgr.stop(projectId);
|
|
190
|
+
await this.liveUpdatesHandler.disableAppInstallStatus({
|
|
191
|
+
projectId
|
|
128
192
|
});
|
|
193
|
+
// Send final status message
|
|
194
|
+
this.publisher.publishToClient(
|
|
195
|
+
await getAppInstallStatusMessage(
|
|
196
|
+
keyMirrors.appInstallStatus.success,
|
|
197
|
+
'',
|
|
198
|
+
appReleaseHash
|
|
199
|
+
)
|
|
200
|
+
);
|
|
129
201
|
|
|
130
202
|
// update app config shadow for project
|
|
131
203
|
await this.shadowHandler.publishAppState(projectId);
|
|
132
204
|
return out;
|
|
133
205
|
} catch (e) {
|
|
134
|
-
logger.error(e);
|
|
206
|
+
logger.error(`Failed to install ${projectId}: ${e}`);
|
|
135
207
|
const message: string = e.message;
|
|
136
208
|
|
|
137
209
|
// uninstall the failed app to put system back in good state
|
|
210
|
+
// TODO: Replace this with rollback
|
|
138
211
|
await uninstallApp({ projectId });
|
|
139
|
-
this.
|
|
140
|
-
appReleaseHash,
|
|
141
|
-
keyMirrors.appInstallStatus.failure,
|
|
142
|
-
message
|
|
143
|
-
);
|
|
144
|
-
this.liveUpdatesHandler.update({
|
|
145
|
-
appInstallStatus: { toggle: false, appReleaseHash }
|
|
146
|
-
});
|
|
212
|
+
this.shadowHandler.deleteProjectShadow(projectId);
|
|
147
213
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
214
|
+
await this.cmdStatusMgr.stop(projectId);
|
|
215
|
+
await this.liveUpdatesHandler.disableAppInstallStatus({
|
|
216
|
+
projectId
|
|
217
|
+
});
|
|
218
|
+
// Send final status message
|
|
219
|
+
this.publisher.publishToClient(
|
|
220
|
+
await getAppInstallStatusMessage(
|
|
221
|
+
keyMirrors.appInstallStatus.failure,
|
|
222
|
+
message,
|
|
223
|
+
appReleaseHash
|
|
224
|
+
)
|
|
225
|
+
);
|
|
151
226
|
}
|
|
152
227
|
}
|
|
153
228
|
|
|
154
|
-
private async handleAppConfigUpdates(
|
|
155
|
-
for (const appConfigUpdate of
|
|
229
|
+
private async handleAppConfigUpdates(appCfgUpdates: AppConfigUpdate[]) {
|
|
230
|
+
for (const appConfigUpdate of appCfgUpdates) {
|
|
156
231
|
const { projectId, newAppCfg, updatedModels } = appConfigUpdate;
|
|
232
|
+
const appReleaseHash = await AgentConfigFile().getAppVersion({
|
|
233
|
+
projectId
|
|
234
|
+
});
|
|
235
|
+
await this.cmdStatusMgr.start(projectId);
|
|
236
|
+
await this.liveUpdatesHandler.enableAppInstallStatus({
|
|
237
|
+
projectId,
|
|
238
|
+
appReleaseHash
|
|
239
|
+
});
|
|
240
|
+
|
|
157
241
|
if (updatedModels && Object.keys(updatedModels).length) {
|
|
158
242
|
// Publish request for model urls
|
|
159
243
|
this.newAppCfgQueue.push(newAppCfg);
|
|
@@ -193,12 +277,14 @@ export class DeviceAgentCloudConnection {
|
|
|
193
277
|
}
|
|
194
278
|
}
|
|
195
279
|
|
|
196
|
-
|
|
280
|
+
/*=================================================================
|
|
281
|
+
Public interface
|
|
282
|
+
=================================================================*/
|
|
197
283
|
|
|
198
284
|
constructor() {
|
|
199
285
|
this.device = awsIot.device({
|
|
200
|
-
keyPath:
|
|
201
|
-
certPath:
|
|
286
|
+
keyPath: DEVICE_PRIVATE_KEY_FILE_PATH,
|
|
287
|
+
certPath: DEVICE_CERTIFICATE_FILE_PATH,
|
|
202
288
|
caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
|
|
203
289
|
clientId: this.clientId,
|
|
204
290
|
host: this.host,
|
|
@@ -207,11 +293,8 @@ export class DeviceAgentCloudConnection {
|
|
|
207
293
|
});
|
|
208
294
|
this.publisher = new Publisher(this.device, this.clientId);
|
|
209
295
|
this.shadowHandler = new ShadowHandler(this.clientId, this.publisher);
|
|
210
|
-
this.
|
|
211
|
-
this.liveUpdatesHandler = new LiveUpdatesHandler(
|
|
212
|
-
this.publisher,
|
|
213
|
-
this.appInstallStatusMgr
|
|
214
|
-
);
|
|
296
|
+
this.cmdStatusMgr = new CmdStatusManager();
|
|
297
|
+
this.liveUpdatesHandler = new LiveUpdatesHandler(this.publisher);
|
|
215
298
|
|
|
216
299
|
this.subscribe(this.toDeviceTopic);
|
|
217
300
|
this.subscribe(this.shadowHandler.shadowTopics.projects.getAccepted);
|
|
@@ -222,6 +305,18 @@ export class DeviceAgentCloudConnection {
|
|
|
222
305
|
return this.clientId;
|
|
223
306
|
}
|
|
224
307
|
|
|
308
|
+
public getToDeviceTopic() {
|
|
309
|
+
return this.toDeviceTopic;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
public getShadowTopics(): ShadowTopics {
|
|
313
|
+
return this.shadowHandler.shadowTopics;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
public isCmdInProgress(projectId: string): boolean {
|
|
317
|
+
return this.cmdStatusMgr.isCmdInProgress(projectId);
|
|
318
|
+
}
|
|
319
|
+
|
|
225
320
|
public async handleClientMessage({
|
|
226
321
|
topic,
|
|
227
322
|
message
|
|
@@ -229,18 +324,29 @@ export class DeviceAgentCloudConnection {
|
|
|
229
324
|
topic: string;
|
|
230
325
|
message: ClientMessage;
|
|
231
326
|
}) {
|
|
327
|
+
const valid = validateClientMessage(message);
|
|
328
|
+
if (!valid) {
|
|
329
|
+
logger.error(
|
|
330
|
+
`Error validating message: ${JSON.stringify(
|
|
331
|
+
{ topic, message, errors: validateClientMessage.errors },
|
|
332
|
+
null,
|
|
333
|
+
2
|
|
334
|
+
)}`
|
|
335
|
+
);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
232
338
|
const payload = message.payload;
|
|
233
339
|
switch (payload.messageType) {
|
|
234
340
|
case keyMirrors.clientMessageType.app_state_control: {
|
|
235
|
-
this.handleAppStateControl(payload.appStateControl);
|
|
341
|
+
await this.handleAppStateControl(payload.appStateControl);
|
|
236
342
|
break;
|
|
237
343
|
}
|
|
238
344
|
case keyMirrors.clientMessageType.app_version_control: {
|
|
239
|
-
this.handleAppVersionControl(payload.appVersionControl);
|
|
345
|
+
await this.handleAppVersionControl(payload.appVersionControl);
|
|
240
346
|
break;
|
|
241
347
|
}
|
|
242
348
|
case keyMirrors.clientMessageType.live_state_updates: {
|
|
243
|
-
this.handleAgentCommand(payload);
|
|
349
|
+
await this.handleAgentCommand(payload);
|
|
244
350
|
break;
|
|
245
351
|
}
|
|
246
352
|
case keyMirrors.clientMessageType.app_install_cloud_response: {
|
|
@@ -271,9 +377,10 @@ export class DeviceAgentCloudConnection {
|
|
|
271
377
|
|
|
272
378
|
const newAppCfg = this.newAppCfgQueue.shift();
|
|
273
379
|
if (newAppCfg === undefined) {
|
|
274
|
-
|
|
380
|
+
logger.error(
|
|
275
381
|
'Unknown error while updating models via application config! No config present for model update.'
|
|
276
382
|
);
|
|
383
|
+
return;
|
|
277
384
|
}
|
|
278
385
|
|
|
279
386
|
await this.atomicApplicationUpdate(
|
|
@@ -303,11 +410,35 @@ export class DeviceAgentCloudConnection {
|
|
|
303
410
|
}
|
|
304
411
|
}
|
|
305
412
|
|
|
413
|
+
public async handleMessage(topic: string, message: ClientMessage | any) {
|
|
414
|
+
logger.debug(
|
|
415
|
+
`Received message: ${JSON.stringify({ topic, message }, null, 2)}`
|
|
416
|
+
);
|
|
417
|
+
switch (topic) {
|
|
418
|
+
case this.shadowHandler.shadowTopics.projects.getAccepted:
|
|
419
|
+
case this.shadowHandler.shadowTopics.projects.updateDelta: {
|
|
420
|
+
const appConfigUpdates = await this.shadowHandler.handleShadowTopic({
|
|
421
|
+
topic,
|
|
422
|
+
payload: message.state
|
|
423
|
+
});
|
|
424
|
+
await this.handleAppConfigUpdates(appConfigUpdates);
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
case this.toDeviceTopic:
|
|
428
|
+
await this.handleClientMessage({
|
|
429
|
+
topic,
|
|
430
|
+
message
|
|
431
|
+
});
|
|
432
|
+
break;
|
|
433
|
+
default:
|
|
434
|
+
logger.error(`Unexpected topic, ignoring! ${topic}`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
306
438
|
public async setupHandlers() {
|
|
307
439
|
this.device.on('connect', (connack: any) => {
|
|
308
440
|
logger.info('Device Agent has connected to the cloud');
|
|
309
441
|
|
|
310
|
-
// Get shadow updates
|
|
311
442
|
this.shadowHandler.getShadowUpdates();
|
|
312
443
|
});
|
|
313
444
|
|
|
@@ -321,47 +452,15 @@ export class DeviceAgentCloudConnection {
|
|
|
321
452
|
);
|
|
322
453
|
});
|
|
323
454
|
|
|
455
|
+
this.device.on('error', function (error) {
|
|
456
|
+
const errorString = error.message.toString();
|
|
457
|
+
logger.error(`${errorString}`);
|
|
458
|
+
});
|
|
459
|
+
|
|
324
460
|
this.device.on('message', async (topic: string, payload: string) => {
|
|
325
461
|
try {
|
|
326
462
|
const jsonPacket = JSON.parse(payload);
|
|
327
|
-
|
|
328
|
-
`Received message: ${JSON.stringify({ topic, jsonPacket }, null, 2)}`
|
|
329
|
-
);
|
|
330
|
-
|
|
331
|
-
if (Object.prototype.hasOwnProperty.call(jsonPacket, 'state')) {
|
|
332
|
-
if (jsonPacket.clientToken === this.getClientId()) {
|
|
333
|
-
logger.debug(
|
|
334
|
-
`Ignoring message sent from self: ${JSON.stringify(
|
|
335
|
-
{ topic, jsonPacket },
|
|
336
|
-
null,
|
|
337
|
-
2
|
|
338
|
-
)}`
|
|
339
|
-
);
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const appConfigUpdates = await this.shadowHandler.handleShadowTopic({
|
|
344
|
-
topic,
|
|
345
|
-
payload: jsonPacket.state
|
|
346
|
-
});
|
|
347
|
-
await this.handleAppConfigUpdates(appConfigUpdates);
|
|
348
|
-
} else {
|
|
349
|
-
const valid = validateClientMessage(jsonPacket);
|
|
350
|
-
if (!valid) {
|
|
351
|
-
logger.error(
|
|
352
|
-
`Error validating message: ${JSON.stringify(
|
|
353
|
-
validateClientMessage.errors,
|
|
354
|
-
null,
|
|
355
|
-
2
|
|
356
|
-
)}`
|
|
357
|
-
);
|
|
358
|
-
} else {
|
|
359
|
-
this.handleClientMessage({
|
|
360
|
-
topic,
|
|
361
|
-
message: jsonPacket
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
}
|
|
463
|
+
await this.handleMessage(topic, jsonPacket);
|
|
365
464
|
} catch (error) {
|
|
366
465
|
logger.error(`Error parsing message: ${error}`);
|
|
367
466
|
}
|
|
@@ -371,15 +470,25 @@ export class DeviceAgentCloudConnection {
|
|
|
371
470
|
logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
|
|
372
471
|
});
|
|
373
472
|
}
|
|
473
|
+
|
|
474
|
+
public stop() {
|
|
475
|
+
this.device.end();
|
|
476
|
+
}
|
|
374
477
|
}
|
|
375
478
|
|
|
376
479
|
export async function runDeviceAgentCloudInterface() {
|
|
377
480
|
// FIXME: Check for KeyPath as well
|
|
378
|
-
if (existsSync(
|
|
481
|
+
if (existsSync(DEVICE_CERTIFICATE_FILE_PATH)) {
|
|
379
482
|
const deviceAgent = new DeviceAgentCloudConnection();
|
|
380
483
|
await deviceAgent.setupHandlers();
|
|
381
|
-
|
|
382
|
-
|
|
484
|
+
if (ALWAYSAI_ANALYTICS_PASSTHROUGH === true) {
|
|
485
|
+
const publisher = deviceAgent.publisher;
|
|
486
|
+
const passthroughHandler = new PassthroughHandler(publisher);
|
|
487
|
+
await passthroughHandler.setup();
|
|
488
|
+
await runChannel(passthroughHandler);
|
|
489
|
+
}
|
|
490
|
+
} else if (existsSync(BOOTSTRAP_PRIVATE_KEY_FILE_PATH())) {
|
|
491
|
+
await bootstrapProvision();
|
|
383
492
|
} else if (existsSync(BOOTSTRAP_CERTIFICATES_DIR_PATH())) {
|
|
384
493
|
throw new Error(
|
|
385
494
|
"Device has not been created using 'aai-agent device init' or there has been an issue with device initialization"
|
|
@@ -3,7 +3,7 @@ const awsIot = require('aws-iot-device-sdk');
|
|
|
3
3
|
import {
|
|
4
4
|
DEVICE_PRIVATE_KEY_FILE_NAME,
|
|
5
5
|
CERTIFICATE_OWNERSHIP_TOKEN_FILE_NAME,
|
|
6
|
-
|
|
6
|
+
DEVICE_ID_FILE_NAME,
|
|
7
7
|
DEVICE_CERTIFICATE_FILE_NAME
|
|
8
8
|
} from '../util/directories';
|
|
9
9
|
import { getDeviceUuid } from '../util/get-device-id';
|
|
@@ -66,6 +66,9 @@ export class BootstrapAgent extends DeviceAgent {
|
|
|
66
66
|
public async handleAwsCertificateTopics(topic: string, payload: any) {
|
|
67
67
|
switch (topic) {
|
|
68
68
|
case '$aws/certificates/create/json/accepted': {
|
|
69
|
+
logger.debug(
|
|
70
|
+
`Received Certs: ${JSON.stringify(JSON.parse(payload), null, 2)}`
|
|
71
|
+
);
|
|
69
72
|
const {
|
|
70
73
|
certificateId,
|
|
71
74
|
certificatePem,
|
|
@@ -76,13 +79,13 @@ export class BootstrapAgent extends DeviceAgent {
|
|
|
76
79
|
const certSpawner = JsSpawner({ path: LOCAL_CERT_AND_KEY_DIR });
|
|
77
80
|
|
|
78
81
|
await certSpawner.writeFile(
|
|
79
|
-
DEVICE_CERTIFICATE_FILE_NAME
|
|
82
|
+
DEVICE_CERTIFICATE_FILE_NAME,
|
|
80
83
|
certificatePem
|
|
81
84
|
);
|
|
82
85
|
|
|
83
|
-
await certSpawner.writeFile(DEVICE_PRIVATE_KEY_FILE_NAME
|
|
86
|
+
await certSpawner.writeFile(DEVICE_PRIVATE_KEY_FILE_NAME, privateKey);
|
|
84
87
|
|
|
85
|
-
await certSpawner.writeFile(
|
|
88
|
+
await certSpawner.writeFile(DEVICE_ID_FILE_NAME, certificateId);
|
|
86
89
|
|
|
87
90
|
await certSpawner.writeFile(
|
|
88
91
|
CERTIFICATE_OWNERSHIP_TOKEN_FILE_NAME,
|