@alwaysai/device-agent 0.0.11 → 0.0.13
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.d.ts.map +1 -1
- package/lib/application-control/backup.js +8 -2
- package/lib/application-control/backup.js.map +1 -1
- package/lib/application-control/config.d.ts +12 -4
- package/lib/application-control/config.d.ts.map +1 -1
- package/lib/application-control/config.js +59 -16
- package/lib/application-control/config.js.map +1 -1
- package/lib/application-control/environment-variables.d.ts.map +1 -1
- package/lib/application-control/environment-variables.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 +4 -3
- package/lib/application-control/index.js.map +1 -1
- package/lib/application-control/install.d.ts.map +1 -1
- package/lib/application-control/install.js +28 -14
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/models.d.ts +7 -1
- package/lib/application-control/models.d.ts.map +1 -1
- package/lib/application-control/models.js +69 -39
- package/lib/application-control/models.js.map +1 -1
- package/lib/application-control/status.d.ts.map +1 -1
- package/lib/application-control/status.js +18 -14
- package/lib/application-control/status.js.map +1 -1
- package/lib/application-control/utils.d.ts +0 -2
- package/lib/application-control/utils.d.ts.map +1 -1
- package/lib/application-control/utils.js +7 -16
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/app-install-status.d.ts +16 -0
- package/lib/cloud-connection/app-install-status.d.ts.map +1 -0
- package/lib/cloud-connection/app-install-status.js +53 -0
- package/lib/cloud-connection/app-install-status.js.map +1 -0
- package/lib/cloud-connection/bootstrap-provision.d.ts +2 -0
- package/lib/cloud-connection/bootstrap-provision.d.ts.map +1 -0
- package/lib/cloud-connection/bootstrap-provision.js +34 -0
- package/lib/cloud-connection/bootstrap-provision.js.map +1 -0
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +12 -35
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +170 -387
- 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 +22 -26
- package/lib/cloud-connection/device-agent.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.d.ts +34 -0
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -0
- package/lib/cloud-connection/live-updates-handler.js +167 -0
- package/lib/cloud-connection/live-updates-handler.js.map +1 -0
- package/lib/cloud-connection/messages.d.ts +14 -0
- package/lib/cloud-connection/messages.d.ts.map +1 -0
- package/lib/cloud-connection/messages.js +38 -0
- package/lib/cloud-connection/messages.js.map +1 -0
- package/lib/cloud-connection/publisher.d.ts +14 -0
- package/lib/cloud-connection/publisher.d.ts.map +1 -0
- package/lib/cloud-connection/publisher.js +44 -0
- package/lib/cloud-connection/publisher.js.map +1 -0
- package/lib/cloud-connection/shadow-handler.d.ts +34 -0
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -0
- package/lib/cloud-connection/shadow-handler.js +94 -0
- package/lib/cloud-connection/shadow-handler.js.map +1 -0
- package/lib/cloud-connection/shadow.d.ts +16 -0
- package/lib/cloud-connection/shadow.d.ts.map +1 -0
- package/lib/cloud-connection/shadow.js +36 -0
- package/lib/cloud-connection/shadow.js.map +1 -0
- package/lib/device-control/device-control.d.ts.map +1 -1
- package/lib/device-control/device-control.js +1 -0
- package/lib/device-control/device-control.js.map +1 -1
- package/lib/docker/docker-cmd.js +1 -1
- package/lib/docker/docker-compose-cmd.d.ts.map +1 -1
- package/lib/docker/docker-compose-cmd.js +1 -1
- package/lib/docker/docker-compose-cmd.js.map +1 -1
- package/lib/endpoints.js +10 -10
- package/lib/endpoints.js.map +1 -1
- package/lib/environment.d.ts.map +1 -1
- package/lib/environment.js.map +1 -1
- package/lib/infrastructure/agent-config.d.ts +4 -14
- package/lib/infrastructure/agent-config.d.ts.map +1 -1
- package/lib/infrastructure/agent-config.js +22 -15
- package/lib/infrastructure/agent-config.js.map +1 -1
- package/lib/infrastructure/agent-config.test.js +26 -18
- package/lib/infrastructure/agent-config.test.js.map +1 -1
- package/lib/infrastructure/system-id.d.ts +2 -0
- package/lib/infrastructure/system-id.d.ts.map +1 -0
- package/lib/infrastructure/system-id.js +21 -0
- package/lib/infrastructure/system-id.js.map +1 -0
- package/lib/infrastructure/tokens-and-device-cfg.d.ts +4 -0
- package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -0
- package/lib/infrastructure/tokens-and-device-cfg.js +31 -0
- package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -0
- package/lib/infrastructure/urls.d.ts.map +1 -1
- package/lib/infrastructure/urls.js +3 -3
- package/lib/infrastructure/urls.js.map +1 -1
- package/lib/root.d.ts.map +1 -1
- package/lib/root.js +2 -7
- package/lib/root.js.map +1 -1
- package/lib/subcommands/app/app.d.ts.map +1 -1
- package/lib/subcommands/app/app.js +62 -60
- package/lib/subcommands/app/app.js.map +1 -1
- package/lib/subcommands/app/index.js +2 -2
- package/lib/subcommands/device/clean.d.ts +2 -0
- package/lib/subcommands/device/clean.d.ts.map +1 -0
- package/lib/subcommands/device/clean.js +29 -0
- package/lib/subcommands/device/clean.js.map +1 -0
- package/lib/subcommands/device/device.d.ts.map +1 -1
- package/lib/subcommands/device/device.js +40 -27
- package/lib/subcommands/device/device.js.map +1 -1
- package/lib/subcommands/device/index.d.ts.map +1 -1
- package/lib/subcommands/device/index.js +2 -1
- package/lib/subcommands/device/index.js.map +1 -1
- package/lib/subcommands/get-model-package.js +5 -5
- package/lib/subcommands/index.js +1 -1
- package/lib/subcommands/login.js +8 -8
- package/lib/subcommands/login.js.map +1 -1
- package/lib/util/clean-certs.d.ts +2 -0
- package/lib/util/clean-certs.d.ts.map +1 -0
- package/lib/util/clean-certs.js +16 -0
- package/lib/util/clean-certs.js.map +1 -0
- package/lib/util/directories.d.ts +16 -15
- package/lib/util/directories.d.ts.map +1 -1
- package/lib/util/directories.js +45 -26
- package/lib/util/directories.js.map +1 -1
- package/lib/util/get-device-id.d.ts +1 -1
- package/lib/util/get-device-id.d.ts.map +1 -1
- package/lib/util/get-device-id.js +14 -19
- package/lib/util/get-device-id.js.map +1 -1
- package/lib/util/http-client.d.ts +1 -1
- package/lib/util/http-client.d.ts.map +1 -1
- package/lib/util/http-client.js +10 -8
- package/lib/util/http-client.js.map +1 -1
- package/lib/util/logger.d.ts.map +1 -1
- package/lib/util/logger.js +4 -5
- package/lib/util/logger.js.map +1 -1
- package/lib/util/run-in-dir.d.ts.map +1 -1
- package/lib/util/run-in-dir.js +1 -0
- package/lib/util/run-in-dir.js.map +1 -1
- package/package.json +18 -8
- package/src/application-control/backup.ts +8 -3
- package/src/application-control/config.ts +75 -13
- package/src/application-control/environment-variables.ts +3 -3
- package/src/application-control/index.ts +19 -6
- package/src/application-control/install.ts +52 -28
- package/src/application-control/models.ts +100 -56
- package/src/application-control/status.ts +26 -21
- package/src/application-control/utils.ts +9 -20
- package/src/cloud-connection/app-install-status.ts +62 -0
- package/src/cloud-connection/bootstrap-provision.ts +40 -0
- package/src/cloud-connection/device-agent-cloud-connection.ts +258 -527
- package/src/cloud-connection/device-agent.ts +31 -38
- package/src/cloud-connection/live-updates-handler.ts +226 -0
- package/src/cloud-connection/messages.ts +39 -0
- package/src/cloud-connection/publisher.ts +65 -0
- package/src/cloud-connection/shadow-handler.ts +154 -0
- package/src/cloud-connection/shadow.ts +50 -0
- package/src/device-control/device-control.ts +1 -0
- package/src/docker/docker-cmd.ts +1 -1
- package/src/docker/docker-compose-cmd.ts +5 -2
- package/src/endpoints.ts +9 -9
- package/src/environment.ts +8 -3
- package/src/infrastructure/agent-config.test.ts +34 -23
- package/src/infrastructure/agent-config.ts +33 -20
- package/src/infrastructure/system-id.ts +18 -0
- package/src/infrastructure/tokens-and-device-cfg.ts +39 -0
- package/src/infrastructure/urls.ts +4 -2
- package/src/root.ts +2 -8
- package/src/subcommands/app/app.ts +64 -62
- package/src/subcommands/app/index.ts +3 -3
- package/src/subcommands/device/clean.ts +26 -0
- package/src/subcommands/device/device.ts +66 -50
- package/src/subcommands/device/index.ts +2 -1
- package/src/subcommands/get-model-package.ts +5 -5
- package/src/subcommands/index.ts +1 -1
- package/src/subcommands/login.ts +8 -8
- package/src/util/clean-certs.ts +12 -0
- package/src/util/directories.ts +68 -52
- package/src/util/get-device-id.ts +16 -18
- package/src/util/http-client.ts +18 -13
- package/src/util/logger.ts +6 -6
- package/src/util/run-in-dir.ts +2 -1
- package/lib/infrastructure/certificates-and-tokens.d.ts +0 -6
- package/lib/infrastructure/certificates-and-tokens.d.ts.map +0 -1
- package/lib/infrastructure/certificates-and-tokens.js +0 -43
- package/lib/infrastructure/certificates-and-tokens.js.map +0 -1
- package/src/infrastructure/certificates-and-tokens.ts +0 -53
|
@@ -1,316 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
// eslint-disable-next-line
|
|
2
|
+
const awsIot = require('aws-iot-device-sdk');
|
|
3
|
+
import { getIoTCoreEndpointUrl } from '../infrastructure/urls';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
4
5
|
import {
|
|
5
6
|
getPrivateKeyFilePath,
|
|
6
7
|
getCertificateFilePath,
|
|
7
|
-
getRootCertificateFilePath,
|
|
8
|
-
BOOTSTRAP_CLAIM_ID_FILE_PATH,
|
|
9
|
-
DEVICE_CLAIM_ID_FILE_PATH,
|
|
10
|
-
BOOTSTRAP_DEVICE_CERTIFICATE_FILE_PATH,
|
|
11
8
|
BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH,
|
|
12
9
|
AWS_ROOT_CERTIFICATE_FILE_PATH,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
import { BootstrapAgent } from "./device-agent";
|
|
16
|
-
|
|
17
|
-
import sleep from "../util/sleep";
|
|
18
|
-
import {
|
|
19
|
-
startApp,
|
|
20
|
-
stopApp,
|
|
21
|
-
restartApp,
|
|
22
|
-
getAppLogs,
|
|
23
|
-
getAppStatus,
|
|
24
|
-
} from "../application-control/status";
|
|
25
|
-
import {
|
|
26
|
-
getInstalledApps,
|
|
27
|
-
installApp,
|
|
28
|
-
uninstallApp,
|
|
29
|
-
} from "../application-control/install";
|
|
10
|
+
BOOTSTRAP_CERTIFICATES_DIR_PATH
|
|
11
|
+
} from '../util/directories';
|
|
30
12
|
import {
|
|
31
13
|
keyMirrors,
|
|
32
14
|
validateClientMessage,
|
|
33
|
-
DeviceAgentMessagePayload,
|
|
34
|
-
AppInstallStatusPacket,
|
|
35
15
|
AppStateControlPacket,
|
|
36
16
|
AppVersionControlPacket,
|
|
37
|
-
LiveUpdatesToggles,
|
|
38
|
-
AppLogsPacket,
|
|
39
|
-
AppStatePacket,
|
|
40
17
|
LiveUpdatesToggleMessage,
|
|
41
|
-
DeviceStatsMessage,
|
|
42
|
-
AppStateMessage,
|
|
43
|
-
AppLogsMessage,
|
|
44
|
-
AppInstallStatusMessage,
|
|
45
18
|
SignedUrlsRequestMessage,
|
|
46
|
-
DeviceAgentMessage,
|
|
47
19
|
ClientMessage,
|
|
48
|
-
|
|
49
|
-
} from
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
getCpuUtil,
|
|
54
|
-
getDiskUtil,
|
|
55
|
-
getMemUtil,
|
|
56
|
-
} from "../device-control/device-control";
|
|
57
|
-
import { AgentConfigFile } from "../infrastructure/agent-config";
|
|
20
|
+
getDeviceTopic
|
|
21
|
+
} from '@alwaysai/device-agent-schemas';
|
|
22
|
+
import { getDeviceUuid } from '../util/get-device-id';
|
|
23
|
+
import { logger } from '../util/logger';
|
|
24
|
+
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
58
25
|
import {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
26
|
+
startApp,
|
|
27
|
+
stopApp,
|
|
28
|
+
restartApp,
|
|
29
|
+
updateModelsWithPresignedUrls,
|
|
30
|
+
installApp,
|
|
31
|
+
uninstallApp,
|
|
32
|
+
updateAppCfg
|
|
33
|
+
} from '../application-control';
|
|
34
|
+
import { AppConfigUpdate, ShadowHandler } from './shadow-handler';
|
|
35
|
+
import { Publisher } from './publisher';
|
|
36
|
+
import { LiveUpdatesHandler } from './live-updates-handler';
|
|
37
|
+
import { bootstrapProvision } from './bootstrap-provision';
|
|
38
|
+
import { AppInstallStatusManager } from './app-install-status';
|
|
39
|
+
import { AppConfig } from '@alwaysai/app-configuration-schemas';
|
|
65
40
|
|
|
66
41
|
export class DeviceAgentCloudConnection {
|
|
67
|
-
private
|
|
68
|
-
private
|
|
69
|
-
private
|
|
70
|
-
private
|
|
71
|
-
private
|
|
72
|
-
[keyMirrors.agentMessageType.device_stats]: false,
|
|
73
|
-
[keyMirrors.agentMessageType.app_state]: false,
|
|
74
|
-
[keyMirrors.agentMessageType.app_logs]: false,
|
|
75
|
-
};
|
|
76
|
-
private liveUpdatesSleepIntervals = {
|
|
77
|
-
[keyMirrors.agentMessageType.device_stats]: 5000,
|
|
78
|
-
[keyMirrors.agentMessageType.app_state]: 5000,
|
|
79
|
-
[keyMirrors.agentMessageType.app_logs]: 5000,
|
|
80
|
-
[keyMirrors.agentMessageType.app_install_status]: 5000,
|
|
81
|
-
};
|
|
82
|
-
private appLogStreams = new Set<string>();
|
|
83
|
-
private deviceType = "aai-device";
|
|
84
|
-
private readonly shadowPrefix = `$aws/things/${this.clientId}/shadow/name/`;
|
|
85
|
-
private readonly shadowTopics = {
|
|
86
|
-
projects: {
|
|
87
|
-
updateDelta: `${this.shadowPrefix}projects/update/delta`,
|
|
88
|
-
getAccepted: `${this.shadowPrefix}projects/get/accepted`,
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
private readonly toCloudTopic = `to-cloud/${this.deviceType}/${this.clientId}`;
|
|
92
|
-
private readonly toClientTopic = `to-client/${this.deviceType}/${this.clientId}`;
|
|
93
|
-
private readonly toDeviceTopic = `to-device/${this.deviceType}/${this.clientId}`;
|
|
94
|
-
|
|
95
|
-
// device shadow utils
|
|
96
|
-
|
|
97
|
-
public getShadowPrefix() {
|
|
98
|
-
return this.shadowPrefix;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
private async handleNamedShadowUpdate({ payload }: { payload: string }) {
|
|
102
|
-
const delta = JSON.parse(payload);
|
|
103
|
-
const deltaKeys = Object.keys(delta);
|
|
104
|
-
|
|
105
|
-
for (const projectId of deltaKeys) {
|
|
106
|
-
const projectShadow = delta[projectId];
|
|
107
|
-
if (projectShadow.appConfig) {
|
|
108
|
-
const appConfig = projectShadow.appConfig;
|
|
109
|
-
const appDir = getAppDir(projectId);
|
|
110
|
-
await updateAppConfig(projectId, appConfig);
|
|
111
|
-
|
|
112
|
-
if (appConfig.models) {
|
|
113
|
-
this.publishCloudRequest({
|
|
114
|
-
messageType: keyMirrors.agentMessageType.signed_urls_request,
|
|
115
|
-
modelsOnlyUrlsRequest: {
|
|
116
|
-
projectId,
|
|
117
|
-
models: appConfig.models,
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (appConfig.scripts && !appConfig.models) {
|
|
123
|
-
const appState = await getAppStatus({ projectId });
|
|
124
|
-
|
|
125
|
-
await buildApp({ appDir });
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
appState.services.length &&
|
|
129
|
-
appState.services[0].state !== keyMirrors.appState.stopped
|
|
130
|
-
) {
|
|
131
|
-
restartApp({ projectId });
|
|
132
|
-
}
|
|
133
|
-
await this.publishReportedState(projectId);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private async startAppLogStream(projectId: string) {
|
|
140
|
-
this.appLogStreams.add(projectId);
|
|
141
|
-
const readable = await getAppLogs({
|
|
142
|
-
projectId,
|
|
143
|
-
args: ["--tail", "100", "--no-log-prefix"],
|
|
144
|
-
});
|
|
145
|
-
readable.on("data", (chunk: Buffer) => {
|
|
146
|
-
if (!this.appLogStreams.has(projectId)) {
|
|
147
|
-
// why doesn't typescript know about this function?
|
|
148
|
-
// @ts-ignore
|
|
149
|
-
readable.destroy();
|
|
150
|
-
logger.info(`App log stream terminated for project ${projectId}`);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
const logStr = chunk.toString();
|
|
154
|
-
const message = {
|
|
155
|
-
messageType: keyMirrors.agentMessageType.app_logs,
|
|
156
|
-
appLogs: {
|
|
157
|
-
projectId,
|
|
158
|
-
logChunk: logStr,
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
const packet = this.buildMessagePacket(
|
|
162
|
-
this.getClientId(),
|
|
163
|
-
this.toClientTopic,
|
|
164
|
-
message
|
|
165
|
-
);
|
|
166
|
-
this.publishMessage(this.toClientTopic, JSON.stringify(packet));
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
readable.on("error", (error) => {
|
|
170
|
-
logger.error(
|
|
171
|
-
`App log stream terminated for project ${projectId}: ${error}`
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
readable.on("finished", () => {
|
|
176
|
-
logger.info(`App logs finished piping for project ${projectId}`);
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// must contain app release hash
|
|
181
|
-
private initAppInstallStatus(installationStatus: AppInstallStatusPacket) {
|
|
182
|
-
this.appInstallStatus = installationStatus;
|
|
183
|
-
}
|
|
42
|
+
private shadowHandler: ShadowHandler;
|
|
43
|
+
private publisher: Publisher;
|
|
44
|
+
private liveUpdatesHandler: LiveUpdatesHandler;
|
|
45
|
+
private appInstallStatusMgr: AppInstallStatusManager;
|
|
46
|
+
private device = awsIot.device;
|
|
184
47
|
|
|
185
|
-
private
|
|
186
|
-
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
private getAppInstallStatus(): AppInstallStatusPacket {
|
|
193
|
-
return this.appInstallStatus;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Message Builders
|
|
197
|
-
private buildMessagePacket(
|
|
198
|
-
deviceId: string,
|
|
199
|
-
topic: string,
|
|
200
|
-
payload: DeviceAgentMessagePayload
|
|
201
|
-
): DeviceAgentMessage {
|
|
202
|
-
const packet = {
|
|
203
|
-
timestamp: new Date().toUTCString(),
|
|
204
|
-
deviceId,
|
|
205
|
-
topic,
|
|
206
|
-
payload,
|
|
207
|
-
};
|
|
208
|
-
return packet;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
private async getAppStateMessage(): Promise<AppStateMessage> {
|
|
212
|
-
const appStateMessage: AppStatePacket[] = [];
|
|
213
|
-
const apps = await AgentConfigFile().getReadyApps();
|
|
214
|
-
for (const app of apps) {
|
|
215
|
-
const projectId = app.projectId;
|
|
216
|
-
const status = await getAppStatus({ projectId });
|
|
217
|
-
appStateMessage.push(status);
|
|
218
|
-
}
|
|
219
|
-
const appStatePackage = {
|
|
220
|
-
messageType: keyMirrors.agentMessageType.app_state,
|
|
221
|
-
appState: appStateMessage,
|
|
222
|
-
};
|
|
223
|
-
return appStatePackage;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
private async getDeviceStatsMessage(): Promise<DeviceStatsMessage> {
|
|
227
|
-
const cpuUsage = await getCpuUtil();
|
|
228
|
-
const diskUtil = await getDiskUtil();
|
|
229
|
-
const memUtil = await getMemUtil();
|
|
230
|
-
|
|
231
|
-
const deviceStatsMessage = {
|
|
232
|
-
messageType: keyMirrors.agentMessageType.device_stats,
|
|
233
|
-
deviceStats: {
|
|
234
|
-
cpuUsage,
|
|
235
|
-
diskUtil,
|
|
236
|
-
usedMemoryPercentage: memUtil,
|
|
237
|
-
},
|
|
238
|
-
};
|
|
239
|
-
return deviceStatsMessage;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// must be arrow function due to this context when function is passed as param
|
|
243
|
-
private getAppInstallStatusMessage =
|
|
244
|
-
async (): Promise<AppInstallStatusMessage> => {
|
|
245
|
-
const appInstallStatus = this.getAppInstallStatus();
|
|
246
|
-
const appInstallStatusMessage = {
|
|
247
|
-
messageType: keyMirrors.agentMessageType.app_install_status,
|
|
248
|
-
appInstallStatus,
|
|
249
|
-
};
|
|
250
|
-
return appInstallStatusMessage;
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
private async startPublishingLiveUpdates(
|
|
254
|
-
topic: string,
|
|
255
|
-
messageType: string,
|
|
256
|
-
getMessageData: () => Promise<DeviceAgentMessagePayload>
|
|
257
|
-
) {
|
|
258
|
-
while (true) {
|
|
259
|
-
try {
|
|
260
|
-
const message = await getMessageData();
|
|
261
|
-
const packet = this.buildMessagePacket(
|
|
262
|
-
this.getClientId(),
|
|
263
|
-
topic,
|
|
264
|
-
message
|
|
265
|
-
);
|
|
266
|
-
this.publishMessage(topic, JSON.stringify(packet));
|
|
267
|
-
} catch (e) {
|
|
268
|
-
logger.error(
|
|
269
|
-
`Error publishing live updates for ${messageType}: ${e.message}`
|
|
270
|
-
);
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
if (!this.continuePublishing(messageType)) {
|
|
274
|
-
logger.info(`Turned off live updates for ${messageType}`);
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
277
|
-
await sleep(this.getLiveUpdatesInterval(messageType));
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
private continuePublishing(flag: string): boolean {
|
|
282
|
-
switch (flag) {
|
|
283
|
-
case keyMirrors.agentMessageType.device_stats:
|
|
284
|
-
case keyMirrors.agentMessageType.app_state:
|
|
285
|
-
return this.liveUpdatesAlive[flag];
|
|
286
|
-
case keyMirrors.agentMessageType.app_install_status:
|
|
287
|
-
return (
|
|
288
|
-
this.appInstallStatus.status ===
|
|
289
|
-
keyMirrors.appInstallStatus.in_progress
|
|
290
|
-
);
|
|
291
|
-
default:
|
|
292
|
-
logger.error(`Unrecognized publishable flag ${flag}`);
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
private getLiveUpdatesInterval(flag: string): number {
|
|
298
|
-
const exists = this.liveUpdatesSleepIntervals[flag];
|
|
299
|
-
if (exists) {
|
|
300
|
-
return exists;
|
|
301
|
-
}
|
|
302
|
-
logger.error(`Unrecognized live updates flag ${flag}`);
|
|
303
|
-
return -1;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
private setLiveUpdates(toggles: LiveUpdatesToggles) {
|
|
307
|
-
if (toggles.deviceStats) {
|
|
308
|
-
this.liveUpdatesAlive.device_stats = toggles.deviceStats;
|
|
309
|
-
}
|
|
310
|
-
if (toggles.appState) {
|
|
311
|
-
this.liveUpdatesAlive.app_state = toggles.appState;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
48
|
+
private clientId = getDeviceUuid();
|
|
49
|
+
private host = getIoTCoreEndpointUrl();
|
|
50
|
+
private readonly toDeviceTopic = getDeviceTopic(this.clientId);
|
|
51
|
+
// FIXME: Add support for multiple simultaneous project updates
|
|
52
|
+
private newAppCfgQueue: AppConfig[] = [];
|
|
314
53
|
|
|
315
54
|
private handleAppStateControl(payload: AppStateControlPacket) {
|
|
316
55
|
const { baseCommand, projectId } = payload;
|
|
@@ -332,7 +71,7 @@ export class DeviceAgentCloudConnection {
|
|
|
332
71
|
const signedUrlsRequest = { projectId, appReleaseHash };
|
|
333
72
|
this.publishCloudRequest({
|
|
334
73
|
messageType: keyMirrors.agentMessageType.signed_urls_request,
|
|
335
|
-
signedUrlsRequest
|
|
74
|
+
signedUrlsRequest
|
|
336
75
|
});
|
|
337
76
|
}
|
|
338
77
|
|
|
@@ -343,7 +82,7 @@ export class DeviceAgentCloudConnection {
|
|
|
343
82
|
private handleAgentCommand(message: LiveUpdatesToggleMessage) {
|
|
344
83
|
switch (message.messageType) {
|
|
345
84
|
case keyMirrors.clientMessageType.live_state_updates:
|
|
346
|
-
this.
|
|
85
|
+
this.liveUpdatesHandler.update(message.liveUpdatesToggles);
|
|
347
86
|
break;
|
|
348
87
|
default:
|
|
349
88
|
logger.error(
|
|
@@ -352,91 +91,110 @@ export class DeviceAgentCloudConnection {
|
|
|
352
91
|
}
|
|
353
92
|
}
|
|
354
93
|
|
|
355
|
-
private
|
|
356
|
-
|
|
357
|
-
this.liveUpdatesTimeout = setTimeout(() => {
|
|
358
|
-
this.setLiveUpdates({
|
|
359
|
-
deviceStats: false,
|
|
360
|
-
appState: false,
|
|
361
|
-
});
|
|
362
|
-
this.appLogStreams.clear();
|
|
363
|
-
// TODO: Make constant, not hard coded
|
|
364
|
-
}, 600000); // 10 min
|
|
94
|
+
private async publishCloudRequest(payload: SignedUrlsRequestMessage) {
|
|
95
|
+
this.publisher.publishToCloud(payload);
|
|
365
96
|
}
|
|
366
97
|
|
|
367
|
-
private
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}: {
|
|
372
|
-
deviceStats?: boolean;
|
|
373
|
-
appState?: boolean;
|
|
374
|
-
appLogs?: {
|
|
375
|
-
projectId: string;
|
|
376
|
-
toggle: boolean;
|
|
377
|
-
};
|
|
378
|
-
}) {
|
|
379
|
-
this.restartLiveUpdatesTimeout();
|
|
380
|
-
if (deviceStats !== undefined) {
|
|
381
|
-
this.liveUpdatesAlive.device_stats = deviceStats;
|
|
382
|
-
if (deviceStats) {
|
|
383
|
-
this.startPublishingLiveUpdates(
|
|
384
|
-
this.toClientTopic,
|
|
385
|
-
keyMirrors.agentMessageType.device_stats,
|
|
386
|
-
this.getDeviceStatsMessage
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
98
|
+
private subscribe(topic: string) {
|
|
99
|
+
logger.info(`Subscribing to ${topic}`);
|
|
100
|
+
this.device.subscribe(topic);
|
|
101
|
+
}
|
|
390
102
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
103
|
+
// eslint-disable-next-line
|
|
104
|
+
private async atomicApplicationUpdate<T extends any[], R extends any>(
|
|
105
|
+
func: (...args: T) => R,
|
|
106
|
+
args: T,
|
|
107
|
+
projectId: string,
|
|
108
|
+
appReleaseHash: string
|
|
109
|
+
) {
|
|
110
|
+
this.appInstallStatusMgr.update(
|
|
111
|
+
appReleaseHash,
|
|
112
|
+
keyMirrors.appInstallStatus.in_progress
|
|
113
|
+
);
|
|
401
114
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
115
|
+
this.liveUpdatesHandler.update({
|
|
116
|
+
appInstallStatus: { toggle: true, appReleaseHash }
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Install the app and models
|
|
120
|
+
try {
|
|
121
|
+
const out: R = await func(...args);
|
|
122
|
+
this.appInstallStatusMgr.update(
|
|
123
|
+
appReleaseHash,
|
|
124
|
+
keyMirrors.appInstallStatus.success
|
|
125
|
+
);
|
|
126
|
+
this.liveUpdatesHandler.update({
|
|
127
|
+
appInstallStatus: { toggle: false, appReleaseHash }
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// update app config shadow for project
|
|
131
|
+
await this.shadowHandler.publishAppState(projectId);
|
|
132
|
+
return out;
|
|
133
|
+
} catch (e) {
|
|
134
|
+
logger.error(e);
|
|
135
|
+
const message: string = e.message;
|
|
136
|
+
|
|
137
|
+
// uninstall the failed app to put system back in good state
|
|
138
|
+
await uninstallApp({ projectId });
|
|
139
|
+
this.appInstallStatusMgr.update(
|
|
140
|
+
appReleaseHash,
|
|
141
|
+
keyMirrors.appInstallStatus.failure,
|
|
142
|
+
message
|
|
143
|
+
);
|
|
144
|
+
this.liveUpdatesHandler.update({
|
|
145
|
+
appInstallStatus: { toggle: false, appReleaseHash }
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// delete shadow for project
|
|
149
|
+
// FIXME: Why do we delete the shadow? Doesn't this delete it for all projects?
|
|
150
|
+
this.shadowHandler.deleteProjectShadow();
|
|
408
151
|
}
|
|
409
152
|
}
|
|
410
153
|
|
|
411
|
-
private async
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
154
|
+
private async handleAppConfigUpdates(appConfgUpdates: AppConfigUpdate[]) {
|
|
155
|
+
for (const appConfigUpdate of appConfgUpdates) {
|
|
156
|
+
const { projectId, newAppCfg, updatedModels } = appConfigUpdate;
|
|
157
|
+
if (updatedModels && Object.keys(updatedModels).length) {
|
|
158
|
+
// Publish request for model urls
|
|
159
|
+
this.newAppCfgQueue.push(newAppCfg);
|
|
160
|
+
|
|
161
|
+
logger.debug(
|
|
162
|
+
`Requesting presigned urls from cloud for model versions: ${JSON.stringify(
|
|
163
|
+
updatedModels
|
|
164
|
+
)}`
|
|
165
|
+
);
|
|
166
|
+
this.publisher.publishToCloud({
|
|
167
|
+
messageType: keyMirrors.agentMessageType.signed_urls_request,
|
|
168
|
+
modelsOnlyUrlsRequest: {
|
|
169
|
+
projectId,
|
|
170
|
+
models: updatedModels
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
} else {
|
|
174
|
+
// FIXME: do we need to send this up to the cloud?
|
|
175
|
+
// should it be something other than appReleaseHash?
|
|
176
|
+
const appReleaseHash = await AgentConfigFile().getAppVersion({
|
|
177
|
+
projectId
|
|
178
|
+
});
|
|
425
179
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
180
|
+
await this.atomicApplicationUpdate(
|
|
181
|
+
updateAppCfg,
|
|
182
|
+
[
|
|
183
|
+
{
|
|
184
|
+
projectId,
|
|
185
|
+
appReleaseHash,
|
|
186
|
+
newAppCfg
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
projectId,
|
|
190
|
+
appReleaseHash
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
434
194
|
}
|
|
435
195
|
|
|
436
196
|
// Public Methods
|
|
437
197
|
|
|
438
|
-
public device = awsIot.device;
|
|
439
|
-
|
|
440
198
|
constructor() {
|
|
441
199
|
this.device = awsIot.device({
|
|
442
200
|
keyPath: getPrivateKeyFilePath(),
|
|
@@ -445,25 +203,28 @@ export class DeviceAgentCloudConnection {
|
|
|
445
203
|
clientId: this.clientId,
|
|
446
204
|
host: this.host,
|
|
447
205
|
port: 8883,
|
|
206
|
+
keepalive: 1 // time before re-connect attempt on dropped connection, default is 400 seconds
|
|
448
207
|
});
|
|
208
|
+
this.publisher = new Publisher(this.device, this.clientId);
|
|
209
|
+
this.shadowHandler = new ShadowHandler(this.clientId, this.publisher);
|
|
210
|
+
this.appInstallStatusMgr = new AppInstallStatusManager();
|
|
211
|
+
this.liveUpdatesHandler = new LiveUpdatesHandler(
|
|
212
|
+
this.publisher,
|
|
213
|
+
this.appInstallStatusMgr
|
|
214
|
+
);
|
|
449
215
|
|
|
450
|
-
this.
|
|
451
|
-
this.
|
|
452
|
-
this.
|
|
216
|
+
this.subscribe(this.toDeviceTopic);
|
|
217
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.getAccepted);
|
|
218
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.updateDelta);
|
|
453
219
|
}
|
|
454
220
|
|
|
455
221
|
public getClientId(): string {
|
|
456
222
|
return this.clientId;
|
|
457
223
|
}
|
|
458
224
|
|
|
459
|
-
public publishMessage(topic: string, message: string) {
|
|
460
|
-
// TODO: topic validation
|
|
461
|
-
this.device.publish(topic, message, (err: any) => {});
|
|
462
|
-
}
|
|
463
|
-
|
|
464
225
|
public async handleClientMessage({
|
|
465
226
|
topic,
|
|
466
|
-
message
|
|
227
|
+
message
|
|
467
228
|
}: {
|
|
468
229
|
topic: string;
|
|
469
230
|
message: ClientMessage;
|
|
@@ -487,175 +248,145 @@ export class DeviceAgentCloudConnection {
|
|
|
487
248
|
projectId,
|
|
488
249
|
appReleaseHash,
|
|
489
250
|
appInstallPayload,
|
|
490
|
-
modelsInstallPayload
|
|
251
|
+
modelsInstallPayload
|
|
491
252
|
} = payload.appInstallCloudResponse;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
this.getAppInstallStatusMessage
|
|
253
|
+
const signedUrlsPayload = {
|
|
254
|
+
appInstallPayload,
|
|
255
|
+
modelsInstallPayload
|
|
256
|
+
};
|
|
257
|
+
await this.atomicApplicationUpdate(
|
|
258
|
+
installApp,
|
|
259
|
+
[{ projectId, appReleaseHash, signedUrlsPayload }],
|
|
260
|
+
projectId,
|
|
261
|
+
appReleaseHash
|
|
502
262
|
);
|
|
503
263
|
|
|
504
|
-
// Install the app and models
|
|
505
|
-
try {
|
|
506
|
-
const signedUrlsPayload = {
|
|
507
|
-
appInstallPayload,
|
|
508
|
-
modelsInstallPayload,
|
|
509
|
-
};
|
|
510
|
-
await installApp({
|
|
511
|
-
projectId,
|
|
512
|
-
appReleaseHash,
|
|
513
|
-
signedUrlsPayload,
|
|
514
|
-
});
|
|
515
|
-
this.updateAppInstallStatus({
|
|
516
|
-
status: keyMirrors.appInstallStatus.success,
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
// update app config shadow for project
|
|
520
|
-
await this.publishReportedState(projectId);
|
|
521
|
-
} catch (e) {
|
|
522
|
-
logger.error(e);
|
|
523
|
-
const message: string = e.message;
|
|
524
|
-
|
|
525
|
-
// uninstall the failed app to put system back in good state
|
|
526
|
-
await uninstallApp({ projectId });
|
|
527
|
-
this.updateAppInstallStatus({
|
|
528
|
-
status: keyMirrors.appInstallStatus.failure,
|
|
529
|
-
message,
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
// delete shadow for project
|
|
533
|
-
this.publishMessage(`${this.shadowPrefix}${projectId}/delete`, "");
|
|
534
|
-
}
|
|
535
264
|
break;
|
|
536
265
|
}
|
|
537
266
|
case keyMirrors.clientMessageType.models_install_cloud_response: {
|
|
538
267
|
const { projectId, newModels } = payload.modelsInstallCloudResponse;
|
|
268
|
+
const appReleaseHash = await AgentConfigFile().getAppVersion({
|
|
269
|
+
projectId
|
|
270
|
+
});
|
|
539
271
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
logger.error(e);
|
|
272
|
+
const newAppCfg = this.newAppCfgQueue.shift();
|
|
273
|
+
if (newAppCfg === undefined) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
'Unknown error while updating models via application config! No config present for model update.'
|
|
276
|
+
);
|
|
546
277
|
}
|
|
278
|
+
|
|
279
|
+
await this.atomicApplicationUpdate(
|
|
280
|
+
updateModelsWithPresignedUrls,
|
|
281
|
+
[
|
|
282
|
+
{
|
|
283
|
+
projectId,
|
|
284
|
+
modelInstallPayloads: newModels,
|
|
285
|
+
newAppCfg,
|
|
286
|
+
appReleaseHash
|
|
287
|
+
}
|
|
288
|
+
],
|
|
289
|
+
projectId,
|
|
290
|
+
appReleaseHash
|
|
291
|
+
);
|
|
292
|
+
|
|
547
293
|
break;
|
|
548
294
|
}
|
|
549
295
|
default:
|
|
550
|
-
logger.error(
|
|
296
|
+
logger.error(
|
|
297
|
+
`Invalid client message: '${JSON.stringify(
|
|
298
|
+
{ topic, message },
|
|
299
|
+
null,
|
|
300
|
+
2
|
|
301
|
+
)}'`
|
|
302
|
+
);
|
|
551
303
|
}
|
|
552
304
|
}
|
|
553
305
|
|
|
554
|
-
public async
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}: {
|
|
558
|
-
topic: string;
|
|
559
|
-
payload: string;
|
|
560
|
-
}) {
|
|
561
|
-
const shadowName = topic.split("/")[5];
|
|
562
|
-
const message = JSON.parse(payload);
|
|
563
|
-
if (topic === this.shadowTopics.projects.updateDelta) {
|
|
564
|
-
this.handleNamedShadowUpdate({ payload });
|
|
565
|
-
} else if (topic === this.shadowTopics.projects.getAccepted) {
|
|
566
|
-
if (message.delta) {
|
|
567
|
-
this.handleNamedShadowUpdate({
|
|
568
|
-
payload: JSON.stringify(message.delta),
|
|
569
|
-
});
|
|
570
|
-
} else {
|
|
571
|
-
logger.info(`No delta updates in shadow ${shadowName}`);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
}
|
|
306
|
+
public async setupHandlers() {
|
|
307
|
+
this.device.on('connect', (connack: any) => {
|
|
308
|
+
logger.info('Device Agent has connected to the cloud');
|
|
576
309
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
{
|
|
581
|
-
const deviceAgent = new DeviceAgentCloudConnection();
|
|
582
|
-
|
|
583
|
-
deviceAgent.device.on("connect", function (connack: any) {
|
|
584
|
-
logger.info("Device Agent has connected to the cloud");
|
|
585
|
-
|
|
586
|
-
// Get shadow updates
|
|
587
|
-
deviceAgent.publishMessage(
|
|
588
|
-
`${deviceAgent.getShadowPrefix()}projects/get`,
|
|
589
|
-
""
|
|
590
|
-
);
|
|
591
|
-
});
|
|
310
|
+
// Get shadow updates
|
|
311
|
+
this.shadowHandler.getShadowUpdates();
|
|
312
|
+
});
|
|
592
313
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
314
|
+
this.device.on('disconnect', () => {
|
|
315
|
+
logger.warn('Device Agent has been disconnected from the cloud');
|
|
316
|
+
});
|
|
596
317
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
});
|
|
609
|
-
} else {
|
|
610
|
-
const valid = validateClientMessage(jsonPacket);
|
|
611
|
-
if (!valid) {
|
|
612
|
-
console.error(JSON.stringify(validateClientMessage.errors));
|
|
613
|
-
} else {
|
|
614
|
-
deviceAgent.handleClientMessage({
|
|
615
|
-
topic,
|
|
616
|
-
message: jsonPacket,
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
} catch (error) {
|
|
621
|
-
logger.error(error);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
318
|
+
this.device.on('reconnect', () => {
|
|
319
|
+
logger.info(
|
|
320
|
+
`Device Agent attempting to re-connect ${new Date().toLocaleString()}`
|
|
321
|
+
);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
this.device.on('message', async (topic: string, payload: string) => {
|
|
325
|
+
try {
|
|
326
|
+
const jsonPacket = JSON.parse(payload);
|
|
327
|
+
logger.debug(
|
|
328
|
+
`Received message: ${JSON.stringify({ topic, jsonPacket }, null, 2)}`
|
|
624
329
|
);
|
|
625
330
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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
|
+
}
|
|
630
342
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
+
}
|
|
365
|
+
} catch (error) {
|
|
366
|
+
logger.error(`Error parsing message: ${error}`);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
651
369
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
370
|
+
this.device.on('offline', () => {
|
|
371
|
+
logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
655
375
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
376
|
+
export async function runDeviceAgentCloudInterface() {
|
|
377
|
+
// FIXME: Check for KeyPath as well
|
|
378
|
+
if (existsSync(getCertificateFilePath())) {
|
|
379
|
+
const deviceAgent = new DeviceAgentCloudConnection();
|
|
380
|
+
await deviceAgent.setupHandlers();
|
|
381
|
+
} else if (existsSync(BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH())) {
|
|
382
|
+
bootstrapProvision();
|
|
383
|
+
} else if (existsSync(BOOTSTRAP_CERTIFICATES_DIR_PATH())) {
|
|
384
|
+
throw new Error(
|
|
385
|
+
"Device has not been created using 'aai-agent device init' or there has been an issue with device initialization"
|
|
386
|
+
);
|
|
387
|
+
} else {
|
|
388
|
+
throw new Error(
|
|
389
|
+
"Set device agent to local mode and retry the 'aai-agent device init' command"
|
|
390
|
+
);
|
|
660
391
|
}
|
|
661
392
|
}
|