@alwaysai/device-agent 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/application-control/environment-variables.d.ts +1 -0
- package/lib/application-control/environment-variables.d.ts.map +1 -1
- package/lib/application-control/environment-variables.js +22 -20
- package/lib/application-control/environment-variables.js.map +1 -1
- package/lib/application-control/environment-variables.test.js +37 -2
- package/lib/application-control/environment-variables.test.js.map +1 -1
- package/lib/application-control/install.js +1 -1
- package/lib/application-control/install.js.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +2 -2
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +116 -99
- package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
- package/lib/cloud-connection/live-updates-handler.js +30 -25
- package/lib/cloud-connection/live-updates-handler.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.test.js +15 -0
- package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
- package/lib/cloud-connection/messages.d.ts +1 -3
- package/lib/cloud-connection/messages.d.ts.map +1 -1
- package/lib/cloud-connection/messages.js +1 -9
- package/lib/cloud-connection/messages.js.map +1 -1
- 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 +3 -0
- package/lib/cloud-connection/publisher.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +10 -3
- package/lib/cloud-connection/shadow-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.test.js +79 -28
- package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.d.ts +26 -6
- package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
- package/lib/cloud-connection/transaction-manager.js +103 -22
- package/lib/cloud-connection/transaction-manager.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.test.js +179 -13
- package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
- package/lib/subcommands/app/analytics.d.ts +10 -0
- package/lib/subcommands/app/analytics.d.ts.map +1 -0
- package/lib/subcommands/app/analytics.js +83 -0
- package/lib/subcommands/app/analytics.js.map +1 -0
- package/lib/subcommands/app/index.d.ts.map +1 -1
- package/lib/subcommands/app/index.js +3 -1
- package/lib/subcommands/app/index.js.map +1 -1
- package/lib/subcommands/app/models.d.ts +0 -5
- package/lib/subcommands/app/models.d.ts.map +1 -1
- package/lib/subcommands/app/models.js +11 -47
- package/lib/subcommands/app/models.js.map +1 -1
- package/lib/subcommands/app/status.d.ts +1 -0
- package/lib/subcommands/app/status.d.ts.map +1 -1
- package/lib/subcommands/app/status.js +14 -3
- package/lib/subcommands/app/status.js.map +1 -1
- package/lib/subcommands/app/version.d.ts +2 -1
- package/lib/subcommands/app/version.d.ts.map +1 -1
- package/lib/subcommands/app/version.js +16 -3
- package/lib/subcommands/app/version.js.map +1 -1
- package/lib/util/parsing.d.ts +2 -0
- package/lib/util/parsing.d.ts.map +1 -0
- package/lib/util/parsing.js +17 -0
- package/lib/util/parsing.js.map +1 -0
- package/package.json +4 -6
- package/readme.md +146 -92
- package/src/application-control/environment-variables.test.ts +43 -3
- package/src/application-control/environment-variables.ts +29 -19
- package/src/application-control/install.ts +1 -1
- package/src/cloud-connection/device-agent-cloud-connection.ts +155 -141
- package/src/cloud-connection/live-updates-handler.test.ts +20 -0
- package/src/cloud-connection/live-updates-handler.ts +45 -52
- package/src/cloud-connection/messages.ts +1 -14
- package/src/cloud-connection/publisher.ts +4 -0
- package/src/cloud-connection/shadow-handler.test.ts +88 -28
- package/src/cloud-connection/shadow-handler.ts +13 -3
- package/src/cloud-connection/transaction-manager.test.ts +193 -18
- package/src/cloud-connection/transaction-manager.ts +174 -26
- package/src/subcommands/app/analytics.ts +99 -0
- package/src/subcommands/app/index.ts +4 -3
- package/src/subcommands/app/models.ts +13 -49
- package/src/subcommands/app/status.ts +20 -3
- package/src/subcommands/app/version.ts +19 -4
- package/src/util/parsing.ts +11 -0
- package/lib/cloud-connection/cmd-status.d.ts +0 -8
- package/lib/cloud-connection/cmd-status.d.ts.map +0 -1
- package/lib/cloud-connection/cmd-status.js +0 -62
- package/lib/cloud-connection/cmd-status.js.map +0 -1
- package/lib/cloud-connection/message-builder.d.ts +0 -7
- package/lib/cloud-connection/message-builder.d.ts.map +0 -1
- package/lib/cloud-connection/message-builder.js +0 -63
- package/lib/cloud-connection/message-builder.js.map +0 -1
- package/src/cloud-connection/cmd-status.ts +0 -71
- package/src/cloud-connection/message-builder.ts +0 -117
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AppLogsPayload,
|
|
3
|
-
ToClientMessagePayload,
|
|
4
3
|
keyMirrors,
|
|
5
4
|
LiveStateUpdatesTogglePayload,
|
|
6
|
-
ToClientMessage
|
|
5
|
+
ToClientMessage,
|
|
6
|
+
buildAppLogsMessage,
|
|
7
|
+
buildAppStateMessage,
|
|
8
|
+
buildDeviceStatsMessage,
|
|
9
|
+
StatusResponsePayload,
|
|
10
|
+
buildToClientStatusResponseMessage
|
|
7
11
|
} from '@alwaysai/device-agent-schemas';
|
|
8
12
|
import { getAppLogs } from '../application-control';
|
|
9
13
|
import { logger } from '../util/logger';
|
|
10
14
|
import sleep from '../util/sleep';
|
|
11
15
|
import { Publisher } from './publisher';
|
|
12
|
-
import {
|
|
13
|
-
getStatusResponsePayload,
|
|
14
|
-
getAppStatePayload,
|
|
15
|
-
getDeviceStatsPayload
|
|
16
|
-
} from './messages';
|
|
16
|
+
import { getAppStatePayload, getDeviceStatsPayload } from './messages';
|
|
17
17
|
import { ToClientMessageTypeValue } from '@alwaysai/device-agent-schemas';
|
|
18
18
|
import { ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS } from '../environment';
|
|
19
|
-
import {
|
|
20
|
-
buildAppLogsMessage,
|
|
21
|
-
buildAppStateMessage,
|
|
22
|
-
buildDeviceStatsMessage,
|
|
23
|
-
buildStatusResponseMessage
|
|
24
|
-
} from './message-builder';
|
|
25
19
|
|
|
26
20
|
const LIVE_UPDATES_TIMEOUT = ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS
|
|
27
21
|
? parseInt(ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS)
|
|
@@ -48,8 +42,9 @@ export class LiveUpdatesHandler {
|
|
|
48
42
|
private appLogStreams = new Set<string>();
|
|
49
43
|
private transactionStatuses = new Set<string>();
|
|
50
44
|
|
|
51
|
-
private async startAppLogStream(projectId: string) {
|
|
45
|
+
private async startAppLogStream(projectId: string, txId: string) {
|
|
52
46
|
logger.info(`Starting log stream for ${projectId}`);
|
|
47
|
+
|
|
53
48
|
this.appLogStreams.add(projectId);
|
|
54
49
|
const readable = await getAppLogs({
|
|
55
50
|
projectId,
|
|
@@ -68,7 +63,7 @@ export class LiveUpdatesHandler {
|
|
|
68
63
|
projectId,
|
|
69
64
|
logChunk: logStr
|
|
70
65
|
};
|
|
71
|
-
const message =
|
|
66
|
+
const message = buildAppLogsMessage(this.clientId, payload, txId);
|
|
72
67
|
this.publisher.publishToClient(message, logger.silly);
|
|
73
68
|
});
|
|
74
69
|
|
|
@@ -117,7 +112,7 @@ export class LiveUpdatesHandler {
|
|
|
117
112
|
this.liveUpdatesAlive.device_stats = toggles.deviceStats;
|
|
118
113
|
}
|
|
119
114
|
if (toggles.appState !== undefined) {
|
|
120
|
-
this.liveUpdatesAlive.
|
|
115
|
+
this.liveUpdatesAlive.app_state = toggles.appState;
|
|
121
116
|
}
|
|
122
117
|
}
|
|
123
118
|
|
|
@@ -132,36 +127,25 @@ export class LiveUpdatesHandler {
|
|
|
132
127
|
}, LIVE_UPDATES_TIMEOUT);
|
|
133
128
|
}
|
|
134
129
|
|
|
135
|
-
private async startPublishingLiveUpdates
|
|
130
|
+
private async startPublishingLiveUpdates(
|
|
136
131
|
messageType: ToClientMessageTypeValue,
|
|
137
|
-
|
|
138
|
-
messageBuilderFunction: (
|
|
139
|
-
payload: ToClientMessagePayload,
|
|
140
|
-
txId: string
|
|
141
|
-
) => Promise<ToClientMessage>,
|
|
142
|
-
args: T,
|
|
132
|
+
getMessage: () => Promise<ToClientMessage>,
|
|
143
133
|
txId: string
|
|
144
134
|
) {
|
|
145
135
|
logger.info(`Turned on live updates for ${messageType}`);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (!this.continuePublishing(messageType, txId)) {
|
|
150
|
-
logger.info(`Turned off live updates for ${messageType}`);
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
const payload: ToClientMessagePayload = await payloadBuilderFunction(
|
|
154
|
-
...args
|
|
155
|
-
);
|
|
156
|
-
const message = await messageBuilderFunction(payload, txId);
|
|
136
|
+
try {
|
|
137
|
+
while (this.continuePublishing(messageType, txId)) {
|
|
138
|
+
const message = await getMessage();
|
|
157
139
|
this.publisher.publishToClient(message, logger.silly);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
`Error publishing live updates for ${messageType}: ${e.message}`
|
|
161
|
-
);
|
|
140
|
+
|
|
141
|
+
await sleep(this.getLiveUpdatesInterval(messageType));
|
|
162
142
|
}
|
|
163
|
-
|
|
143
|
+
} catch (e) {
|
|
144
|
+
logger.error(
|
|
145
|
+
`Error publishing live updates for ${messageType}: ${e.message}`
|
|
146
|
+
);
|
|
164
147
|
}
|
|
148
|
+
logger.info(`Turned off live updates for ${messageType}`);
|
|
165
149
|
}
|
|
166
150
|
|
|
167
151
|
/*=================================================================
|
|
@@ -196,9 +180,16 @@ export class LiveUpdatesHandler {
|
|
|
196
180
|
// Don't wait for this call to finish since it loops until disabled
|
|
197
181
|
void this.startPublishingLiveUpdates(
|
|
198
182
|
keyMirrors.toClientMessageType.status_response,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
183
|
+
async () => {
|
|
184
|
+
const payload: StatusResponsePayload = {
|
|
185
|
+
status: keyMirrors.statusResponse.in_progress
|
|
186
|
+
};
|
|
187
|
+
return buildToClientStatusResponseMessage(
|
|
188
|
+
this.clientId,
|
|
189
|
+
payload,
|
|
190
|
+
txId
|
|
191
|
+
);
|
|
192
|
+
},
|
|
202
193
|
txId
|
|
203
194
|
);
|
|
204
195
|
}
|
|
@@ -220,41 +211,43 @@ export class LiveUpdatesHandler {
|
|
|
220
211
|
const { deviceStats, appState, appLogs } = toggles;
|
|
221
212
|
this.restartLiveUpdatesTimeout();
|
|
222
213
|
|
|
223
|
-
const currentDeviceStats = this.getDeviceStatsLiveUpdates();
|
|
224
214
|
if (deviceStats !== undefined) {
|
|
215
|
+
const currentDeviceStats = this.getDeviceStatsLiveUpdates();
|
|
225
216
|
this.liveUpdatesAlive.device_stats = deviceStats;
|
|
226
217
|
if (deviceStats && currentDeviceStats !== true) {
|
|
227
218
|
// Don't wait for this call to finish since it loops until disabled
|
|
228
219
|
void this.startPublishingLiveUpdates(
|
|
229
220
|
keyMirrors.toClientMessageType.device_stats,
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
221
|
+
async () => {
|
|
222
|
+
const payload = await getDeviceStatsPayload();
|
|
223
|
+
return buildDeviceStatsMessage(this.clientId, payload, txId);
|
|
224
|
+
},
|
|
233
225
|
txId
|
|
234
226
|
);
|
|
235
227
|
}
|
|
236
228
|
}
|
|
237
229
|
|
|
238
|
-
const currentAppState = this.getAppStateLiveUpdates();
|
|
239
230
|
if (appState !== undefined) {
|
|
231
|
+
const currentAppState = this.getAppStateLiveUpdates();
|
|
240
232
|
this.liveUpdatesAlive.app_state = appState;
|
|
241
233
|
if (appState && currentAppState !== true) {
|
|
242
234
|
// Don't wait for this call to finish since it loops until disabled
|
|
243
235
|
void this.startPublishingLiveUpdates(
|
|
244
236
|
keyMirrors.toClientMessageType.app_state,
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
237
|
+
async () => {
|
|
238
|
+
const payload = await getAppStatePayload();
|
|
239
|
+
return buildAppStateMessage(this.clientId, payload, txId);
|
|
240
|
+
},
|
|
248
241
|
txId
|
|
249
242
|
);
|
|
250
243
|
}
|
|
251
244
|
}
|
|
252
245
|
|
|
253
|
-
const currentAppLogs = this.getAppLogsLiveUpdates();
|
|
254
246
|
if (appLogs !== undefined) {
|
|
247
|
+
const currentAppLogs = this.getAppLogsLiveUpdates();
|
|
255
248
|
if (appLogs.toggle && currentAppLogs !== true) {
|
|
256
249
|
// Don't wait for this call to finish since it loops until disabled
|
|
257
|
-
void this.startAppLogStream(appLogs.projectId);
|
|
250
|
+
void this.startAppLogStream(appLogs.projectId, txId);
|
|
258
251
|
} else {
|
|
259
252
|
this.appLogStreams.delete(appLogs.projectId);
|
|
260
253
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AppState,
|
|
3
3
|
AppStatePayload,
|
|
4
|
-
DeviceStatsPayload
|
|
5
|
-
StatusResponsePayload
|
|
4
|
+
DeviceStatsPayload
|
|
6
5
|
} from '@alwaysai/device-agent-schemas';
|
|
7
|
-
import { StatusResponseValue } from '@alwaysai/device-agent-schemas/lib/constants';
|
|
8
6
|
import { getAppState } from '../application-control';
|
|
9
7
|
import {
|
|
10
8
|
getCpuDetails,
|
|
@@ -27,17 +25,6 @@ export async function getAppStatePayload(): Promise<AppStatePayload> {
|
|
|
27
25
|
return appStatePayload;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
export async function getStatusResponsePayload(
|
|
31
|
-
status: StatusResponseValue,
|
|
32
|
-
message: string
|
|
33
|
-
): Promise<StatusResponsePayload> {
|
|
34
|
-
const statusResponsePayload: StatusResponsePayload = {
|
|
35
|
-
status,
|
|
36
|
-
message
|
|
37
|
-
};
|
|
38
|
-
return statusResponsePayload;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
28
|
export async function getDeviceStatsPayload(): Promise<DeviceStatsPayload> {
|
|
42
29
|
const cpuDetails = await getCpuDetails();
|
|
43
30
|
const diskDetails = await getDiskDetails();
|
|
@@ -2,6 +2,8 @@ import { AppConfig } from '@alwaysai/app-configuration-schemas';
|
|
|
2
2
|
import { readAppCfgFile } from '../application-control';
|
|
3
3
|
import { Publisher } from './publisher';
|
|
4
4
|
import { ShadowHandler } from './shadow-handler';
|
|
5
|
+
import { Logger } from 'winston';
|
|
6
|
+
import { logger } from '../util/logger';
|
|
5
7
|
|
|
6
8
|
jest.mock('../application-control');
|
|
7
9
|
jest.mock('./publisher');
|
|
@@ -23,7 +25,7 @@ describe('Test Shadow Handler', () => {
|
|
|
23
25
|
//FIXME: Invalid input is silently ignored, need input validation
|
|
24
26
|
expect(async () => {
|
|
25
27
|
await shadowHandler.handleShadowTopic({
|
|
26
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
28
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
27
29
|
payload: Buffer.from('test-payload'),
|
|
28
30
|
clientToken: ''
|
|
29
31
|
});
|
|
@@ -56,7 +58,7 @@ describe('Test Shadow Handler', () => {
|
|
|
56
58
|
};
|
|
57
59
|
|
|
58
60
|
const updates = await shadowHandler.handleShadowTopic({
|
|
59
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
61
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
60
62
|
payload,
|
|
61
63
|
clientToken: clientId
|
|
62
64
|
});
|
|
@@ -65,11 +67,13 @@ describe('Test Shadow Handler', () => {
|
|
|
65
67
|
|
|
66
68
|
test('handle project shadow empty delta', async () => {
|
|
67
69
|
const payload = {
|
|
68
|
-
|
|
70
|
+
desired: {
|
|
71
|
+
[projectId1]: {}
|
|
72
|
+
}
|
|
69
73
|
};
|
|
70
74
|
|
|
71
75
|
const updates = await shadowHandler.handleShadowTopic({
|
|
72
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
76
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
73
77
|
payload,
|
|
74
78
|
clientToken: ''
|
|
75
79
|
});
|
|
@@ -145,13 +149,15 @@ describe('Test Shadow Handler', () => {
|
|
|
145
149
|
};
|
|
146
150
|
|
|
147
151
|
const payload = {
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
desired: {
|
|
153
|
+
[projectId1]: {
|
|
154
|
+
appConfig: JSON.stringify(appCfg1)
|
|
155
|
+
}
|
|
150
156
|
}
|
|
151
157
|
};
|
|
152
158
|
|
|
153
159
|
const updates = await shadowHandler.handleShadowTopic({
|
|
154
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
160
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
155
161
|
payload,
|
|
156
162
|
clientToken: ''
|
|
157
163
|
});
|
|
@@ -208,16 +214,18 @@ describe('Test Shadow Handler', () => {
|
|
|
208
214
|
}
|
|
209
215
|
};
|
|
210
216
|
const payload = {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
217
|
+
desired: {
|
|
218
|
+
[projectId1]: {
|
|
219
|
+
appConfig: JSON.stringify(appCfg1)
|
|
220
|
+
},
|
|
221
|
+
[projectId2]: {
|
|
222
|
+
appConfig: JSON.stringify(appCfg2)
|
|
223
|
+
}
|
|
216
224
|
}
|
|
217
225
|
};
|
|
218
226
|
|
|
219
227
|
const updates = await shadowHandler.handleShadowTopic({
|
|
220
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
228
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
221
229
|
payload,
|
|
222
230
|
clientToken: ''
|
|
223
231
|
});
|
|
@@ -265,13 +273,15 @@ describe('Test Shadow Handler', () => {
|
|
|
265
273
|
};
|
|
266
274
|
|
|
267
275
|
const payload = {
|
|
268
|
-
|
|
269
|
-
|
|
276
|
+
desired: {
|
|
277
|
+
[projectId1]: {
|
|
278
|
+
appConfig: JSON.stringify(appCfg1)
|
|
279
|
+
}
|
|
270
280
|
}
|
|
271
281
|
};
|
|
272
282
|
|
|
273
283
|
const updates = await shadowHandler.handleShadowTopic({
|
|
274
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
284
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
275
285
|
payload,
|
|
276
286
|
clientToken: ''
|
|
277
287
|
});
|
|
@@ -307,17 +317,63 @@ describe('Test Shadow Handler', () => {
|
|
|
307
317
|
};
|
|
308
318
|
|
|
309
319
|
const payload = {
|
|
310
|
-
|
|
311
|
-
|
|
320
|
+
desired: {
|
|
321
|
+
[projectId1]: {
|
|
322
|
+
appConfig: JSON.stringify(appCfg1)
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const updates = await shadowHandler.handleShadowTopic({
|
|
328
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
329
|
+
payload,
|
|
330
|
+
clientToken: ''
|
|
331
|
+
});
|
|
332
|
+
expect(updates.length).toBe(0);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test('handles an unparsable object in a project shadow appCfg delta', async () => {
|
|
336
|
+
const ogAppCfg1: AppConfig = {
|
|
337
|
+
scripts: {
|
|
338
|
+
start: 'python app.py'
|
|
339
|
+
},
|
|
340
|
+
models: {}
|
|
341
|
+
};
|
|
342
|
+
jest.mocked(readAppCfgFile).mockResolvedValue(ogAppCfg1);
|
|
343
|
+
|
|
344
|
+
// This appCfg is invalid on it's own (see values below)
|
|
345
|
+
const appCfg1 = {
|
|
346
|
+
scripts: {
|
|
347
|
+
start: 'python app.py'
|
|
348
|
+
},
|
|
349
|
+
models: {
|
|
350
|
+
'alwaysai/mobilenet_ssd': '3', // string instead of int
|
|
351
|
+
'alwaysai/yolo_v4': '5' // string instead of int
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const payload = {
|
|
356
|
+
desired: {
|
|
357
|
+
[projectId1]: {
|
|
358
|
+
appConfig: appCfg1 // This is missing JSON.stringify() making this an unparsable object.
|
|
359
|
+
}
|
|
312
360
|
}
|
|
313
361
|
};
|
|
314
362
|
|
|
363
|
+
const loggerSpy = jest
|
|
364
|
+
.spyOn(logger, 'error')
|
|
365
|
+
.mockReturnValue({} as unknown as Logger);
|
|
366
|
+
|
|
315
367
|
const updates = await shadowHandler.handleShadowTopic({
|
|
316
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
368
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
317
369
|
payload,
|
|
318
370
|
clientToken: ''
|
|
319
371
|
});
|
|
372
|
+
|
|
320
373
|
expect(updates.length).toBe(0);
|
|
374
|
+
expect(loggerSpy).toHaveBeenCalledWith(
|
|
375
|
+
expect.stringContaining('Could not parse the appConfig')
|
|
376
|
+
);
|
|
321
377
|
});
|
|
322
378
|
});
|
|
323
379
|
|
|
@@ -354,13 +410,15 @@ describe('Test Shadow Handler', () => {
|
|
|
354
410
|
VAR1: 'value1'
|
|
355
411
|
};
|
|
356
412
|
const payload = {
|
|
357
|
-
|
|
358
|
-
|
|
413
|
+
desired: {
|
|
414
|
+
[projectId1]: {
|
|
415
|
+
envVars: envVars1
|
|
416
|
+
}
|
|
359
417
|
}
|
|
360
418
|
};
|
|
361
419
|
|
|
362
420
|
const updates = await shadowHandler.handleShadowTopic({
|
|
363
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
421
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
364
422
|
payload,
|
|
365
423
|
clientToken: ''
|
|
366
424
|
});
|
|
@@ -382,16 +440,18 @@ describe('Test Shadow Handler', () => {
|
|
|
382
440
|
VAR2: null
|
|
383
441
|
};
|
|
384
442
|
const payload = {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
443
|
+
desired: {
|
|
444
|
+
[projectId1]: {
|
|
445
|
+
envVars: envVars1
|
|
446
|
+
},
|
|
447
|
+
[projectId2]: {
|
|
448
|
+
envVars: envVars2
|
|
449
|
+
}
|
|
390
450
|
}
|
|
391
451
|
};
|
|
392
452
|
|
|
393
453
|
const updates = await shadowHandler.handleShadowTopic({
|
|
394
|
-
topic: shadowHandler.shadowTopics.projects.
|
|
454
|
+
topic: shadowHandler.shadowTopics.projects.updateAccepted,
|
|
395
455
|
payload,
|
|
396
456
|
clientToken: ''
|
|
397
457
|
});
|
|
@@ -84,7 +84,15 @@ export class ShadowHandler {
|
|
|
84
84
|
const shadowUpdate: ShadowUpdate = { projectId, txId };
|
|
85
85
|
|
|
86
86
|
if (projectShadow.appConfig) {
|
|
87
|
-
|
|
87
|
+
let newAppCfg: any;
|
|
88
|
+
try {
|
|
89
|
+
newAppCfg = JSON.parse(projectShadow.appConfig);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logger.error(
|
|
92
|
+
`Could not parse the appConfig for transaction ${txId}!\n${error}`
|
|
93
|
+
);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
88
96
|
if (!validateAppConfig(newAppCfg)) {
|
|
89
97
|
// FIXME: Raise an exception to be handled at higher layer
|
|
90
98
|
logger.error(
|
|
@@ -124,6 +132,7 @@ export class ShadowHandler {
|
|
|
124
132
|
updates.push(shadowUpdate);
|
|
125
133
|
}
|
|
126
134
|
}
|
|
135
|
+
|
|
127
136
|
return updates;
|
|
128
137
|
}
|
|
129
138
|
|
|
@@ -141,7 +150,7 @@ export class ShadowHandler {
|
|
|
141
150
|
// TODO: make use a function like the other topic getters
|
|
142
151
|
const shadowName = topic.split('/')[5];
|
|
143
152
|
switch (topic) {
|
|
144
|
-
case this.shadowTopics.projects.
|
|
153
|
+
case this.shadowTopics.projects.updateAccepted:
|
|
145
154
|
if (clientToken === this.clientId) {
|
|
146
155
|
logger.debug(
|
|
147
156
|
`Ignoring delta caused by Device Agent: ${JSON.stringify(
|
|
@@ -152,7 +161,7 @@ export class ShadowHandler {
|
|
|
152
161
|
);
|
|
153
162
|
break;
|
|
154
163
|
}
|
|
155
|
-
return await this.handleNamedShadowUpdate({ delta: payload });
|
|
164
|
+
return await this.handleNamedShadowUpdate({ delta: payload.desired });
|
|
156
165
|
case this.shadowTopics.projects.getAccepted:
|
|
157
166
|
if (payload['delta']) {
|
|
158
167
|
return await this.handleNamedShadowUpdate({
|
|
@@ -189,6 +198,7 @@ export class ShadowHandler {
|
|
|
189
198
|
public async updateProjectShadow(projectId: string) {
|
|
190
199
|
const appCfg = await readAppCfgFile({ projectId });
|
|
191
200
|
const envVars = await getAllEnvs({ projectId });
|
|
201
|
+
|
|
192
202
|
const packet = {
|
|
193
203
|
state: {
|
|
194
204
|
reported: {
|