@alwaysai/device-agent 0.0.15 → 0.0.17
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.d.ts.map +1 -1
- package/lib/application-control/config.js +4 -4
- 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 +2 -1
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/models.js +1 -1
- package/lib/application-control/status.d.ts.map +1 -1
- package/lib/application-control/status.js +8 -13
- package/lib/application-control/status.js.map +1 -1
- package/lib/application-control/utils.d.ts.map +1 -1
- package/lib/application-control/utils.js +3 -3
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +28 -15
- 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 +9 -8
- package/lib/cloud-connection/live-updates-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.d.ts +9 -5
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +25 -10
- package/lib/cloud-connection/shadow-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.test.js +24 -14
- package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
- package/lib/cloud-connection/shadow.js +1 -1
- package/lib/cloud-connection/shadow.js.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/subcommands/app/env-vars.d.ts +8 -0
- package/lib/subcommands/app/env-vars.d.ts.map +1 -0
- package/lib/subcommands/app/env-vars.js +43 -0
- package/lib/subcommands/app/env-vars.js.map +1 -0
- package/lib/subcommands/app/index.d.ts.map +1 -1
- package/lib/subcommands/app/index.js +20 -19
- package/lib/subcommands/app/index.js.map +1 -1
- package/lib/subcommands/app/models.d.ts +20 -0
- package/lib/subcommands/app/models.d.ts.map +1 -0
- package/lib/subcommands/app/models.js +114 -0
- package/lib/subcommands/app/models.js.map +1 -0
- package/lib/subcommands/app/status.d.ts +17 -0
- package/lib/subcommands/app/status.d.ts.map +1 -0
- package/lib/subcommands/app/status.js +103 -0
- package/lib/subcommands/app/status.js.map +1 -0
- package/lib/subcommands/app/version.d.ts +12 -0
- package/lib/subcommands/app/version.d.ts.map +1 -0
- package/lib/subcommands/app/version.js +103 -0
- package/lib/subcommands/app/version.js.map +1 -0
- package/lib/util/get-device-id.js +1 -1
- package/lib/util/get-device-id.js.map +1 -1
- package/lib/util/http-client.js +1 -1
- package/lib/util/http-client.js.map +1 -1
- package/package.json +1 -1
- package/src/application-control/config.ts +8 -4
- package/src/application-control/install.ts +6 -2
- package/src/application-control/models.ts +1 -1
- package/src/application-control/status.ts +10 -16
- package/src/application-control/utils.ts +3 -4
- package/src/cloud-connection/device-agent-cloud-connection.ts +33 -21
- package/src/cloud-connection/live-updates-handler.ts +14 -13
- package/src/cloud-connection/shadow-handler.test.ts +24 -14
- package/src/cloud-connection/shadow-handler.ts +36 -19
- package/src/cloud-connection/shadow.ts +1 -1
- package/src/index.ts +4 -1
- package/src/subcommands/app/env-vars.ts +46 -0
- package/src/subcommands/app/index.ts +16 -17
- package/src/subcommands/app/models.ts +129 -0
- package/src/subcommands/app/status.ts +92 -0
- package/src/subcommands/app/version.ts +103 -0
- package/src/util/get-device-id.ts +1 -1
- package/src/util/http-client.ts +1 -1
- package/lib/subcommands/app/app.d.ts +0 -60
- package/lib/subcommands/app/app.d.ts.map +0 -1
- package/lib/subcommands/app/app.js +0 -370
- package/lib/subcommands/app/app.js.map +0 -1
- package/src/subcommands/app/app.ts +0 -390
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rollbackAppCliLeaf = exports.uninstallAppCliLeaf = exports.installAppCliLeaf = exports.listAppsCliLeaf = void 0;
|
|
4
|
+
const alwayscli_1 = require("@alwaysai/alwayscli");
|
|
5
|
+
const device_agent_schemas_1 = require("@alwaysai/device-agent-schemas");
|
|
6
|
+
const application_control_1 = require("../../application-control");
|
|
7
|
+
const device_agent_cloud_connection_1 = require("../../cloud-connection/device-agent-cloud-connection");
|
|
8
|
+
const agent_config_1 = require("../../infrastructure/agent-config");
|
|
9
|
+
const sleep_1 = require("../../util/sleep");
|
|
10
|
+
exports.listAppsCliLeaf = (0, alwayscli_1.CliLeaf)({
|
|
11
|
+
name: 'list',
|
|
12
|
+
description: 'List all installed apps',
|
|
13
|
+
namedInputs: {},
|
|
14
|
+
async action(_, opts) {
|
|
15
|
+
const apps = await (0, agent_config_1.AgentConfigFile)().getApps();
|
|
16
|
+
console.table(apps);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
exports.installAppCliLeaf = (0, alwayscli_1.CliLeaf)({
|
|
20
|
+
name: 'install',
|
|
21
|
+
description: 'Install an alwaysAI app from a project',
|
|
22
|
+
namedInputs: {
|
|
23
|
+
project: (0, alwayscli_1.CliStringInput)({
|
|
24
|
+
description: 'Project ID',
|
|
25
|
+
required: true
|
|
26
|
+
}),
|
|
27
|
+
releaseHash: (0, alwayscli_1.CliStringInput)({
|
|
28
|
+
description: 'Release Hash',
|
|
29
|
+
required: true
|
|
30
|
+
})
|
|
31
|
+
},
|
|
32
|
+
async action(_, opts) {
|
|
33
|
+
const { project, releaseHash } = opts;
|
|
34
|
+
const deviceAgent = new device_agent_cloud_connection_1.DeviceAgentCloudConnection();
|
|
35
|
+
await deviceAgent.setupHandlers();
|
|
36
|
+
const topic = deviceAgent.getToDeviceTopic();
|
|
37
|
+
const message = {
|
|
38
|
+
timestamp: '',
|
|
39
|
+
topic,
|
|
40
|
+
payload: {
|
|
41
|
+
messageType: device_agent_schemas_1.keyMirrors.clientMessageType.app_version_control,
|
|
42
|
+
appVersionControl: {
|
|
43
|
+
baseCommand: device_agent_schemas_1.keyMirrors.appVersionControl.install,
|
|
44
|
+
projectId: project,
|
|
45
|
+
appReleaseHash: releaseHash
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
await deviceAgent.handleMessage(topic, message);
|
|
50
|
+
while (deviceAgent.isCmdInProgress(project)) {
|
|
51
|
+
await (0, sleep_1.default)(1000);
|
|
52
|
+
}
|
|
53
|
+
deviceAgent.stop();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
exports.uninstallAppCliLeaf = (0, alwayscli_1.CliLeaf)({
|
|
57
|
+
name: 'uninstall',
|
|
58
|
+
description: 'Remove an alwaysAI app',
|
|
59
|
+
namedInputs: {
|
|
60
|
+
project: (0, alwayscli_1.CliStringInput)({
|
|
61
|
+
description: 'Project ID',
|
|
62
|
+
required: true
|
|
63
|
+
})
|
|
64
|
+
},
|
|
65
|
+
async action(_, opts) {
|
|
66
|
+
const { project } = opts;
|
|
67
|
+
const deviceAgent = new device_agent_cloud_connection_1.DeviceAgentCloudConnection();
|
|
68
|
+
await deviceAgent.setupHandlers();
|
|
69
|
+
const topic = deviceAgent.getToDeviceTopic();
|
|
70
|
+
const message = {
|
|
71
|
+
timestamp: '',
|
|
72
|
+
topic,
|
|
73
|
+
payload: {
|
|
74
|
+
messageType: device_agent_schemas_1.keyMirrors.clientMessageType.app_version_control,
|
|
75
|
+
appVersionControl: {
|
|
76
|
+
baseCommand: device_agent_schemas_1.keyMirrors.appVersionControl.uninstall,
|
|
77
|
+
projectId: project
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
await deviceAgent.handleMessage(topic, message);
|
|
82
|
+
while (deviceAgent.isCmdInProgress(project)) {
|
|
83
|
+
await (0, sleep_1.default)(1000);
|
|
84
|
+
}
|
|
85
|
+
deviceAgent.stop();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
exports.rollbackAppCliLeaf = (0, alwayscli_1.CliLeaf)({
|
|
89
|
+
name: 'rollback',
|
|
90
|
+
description: 'Rollback an alwaysAI app to the previous version',
|
|
91
|
+
namedInputs: {
|
|
92
|
+
project: (0, alwayscli_1.CliStringInput)({
|
|
93
|
+
description: 'Project ID',
|
|
94
|
+
required: true
|
|
95
|
+
})
|
|
96
|
+
},
|
|
97
|
+
hidden: true,
|
|
98
|
+
async action(_, opts) {
|
|
99
|
+
const { project } = opts;
|
|
100
|
+
await (0, application_control_1.rollbackApp)({ projectId: project });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/subcommands/app/version.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-device-id.js","sourceRoot":"","sources":["../../src/util/get-device-id.ts"],"names":[],"mappings":";;;AAAA,qDAA4D;AAE5D,SAAgB,aAAa;IAC3B,MAAM,aAAa,GAAG,IAAA,yBAAgB,GAAE,CAAC;IACzC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;KACpD;IACD,IAAI;QACF,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;QACjC,OAAO,GAAG,CAAC,UAAU,CAAC;KACvB;IAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"get-device-id.js","sourceRoot":"","sources":["../../src/util/get-device-id.ts"],"names":[],"mappings":";;;AAAA,qDAA4D;AAE5D,SAAgB,aAAa;IAC3B,MAAM,aAAa,GAAG,IAAA,yBAAgB,GAAE,CAAC;IACzC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;KACpD;IACD,IAAI;QACF,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;QACjC,OAAO,GAAG,CAAC,UAAU,CAAC;KACvB;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,CAAC,SAAS,CACpD,aAAa,CAAC,SAAS,EAAE,EACzB,IAAI,EACJ,CAAC,CACF,EAAE,CACJ,CAAC;KACH;AACH,CAAC;AAjBD,sCAiBC"}
|
package/lib/util/http-client.js
CHANGED
|
@@ -18,7 +18,7 @@ async function httpClient(url, method, headers, data) {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
catch (e) {
|
|
21
|
-
logger_1.logger.error(`HTTP Client error for ${url}: ${e}`);
|
|
21
|
+
logger_1.logger.error(`HTTP Client error for ${url}: ${e.message}`);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
exports.httpClient = httpClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/util/http-client.ts"],"names":[],"mappings":";;;AAAA,2CAA+B;AAC/B,4CAAsD;AACtD,gEAAsE;AACtE,2CAAwC;AAEjC,KAAK,UAAU,UAAU,CAC9B,GAAW,EACX,MAAc,EACd,OAAY,EACZ,IAAa;IAEb,MAAM,OAAO,mBACX,MAAM,IACH,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAClD,CAAC;IACF,IAAI;QACF,MAAM,QAAQ,GAAG,MAAM,IAAA,oBAAK,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACzD,IAAI,WAAW,KAAK,kBAAkB,EAAE;YACtC,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;SAC9B;QACD,IAAI,WAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;YACvC,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;SAC9B;KACF;IAAC,OAAO,CAAC,EAAE;QACV,eAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/util/http-client.ts"],"names":[],"mappings":";;;AAAA,2CAA+B;AAC/B,4CAAsD;AACtD,gEAAsE;AACtE,2CAAwC;AAEjC,KAAK,UAAU,UAAU,CAC9B,GAAW,EACX,MAAc,EACd,OAAY,EACZ,IAAa;IAEb,MAAM,OAAO,mBACX,MAAM,IACH,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAClD,CAAC;IACF,IAAI;QACF,MAAM,QAAQ,GAAG,MAAM,IAAA,oBAAK,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACzD,IAAI,WAAW,KAAK,kBAAkB,EAAE;YACtC,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;SAC9B;QACD,IAAI,WAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;YACvC,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;SAC9B;KACF;IAAC,OAAO,CAAC,EAAE;QACV,eAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;KAC5D;AACH,CAAC;AAtBD,gCAsBC;AAEM,KAAK,UAAU,sBAAsB,CAC1C,OAAe,EACf,IAAY,EACZ,MAAc,EACd,IAAa;IAEb,MAAM,QAAQ,GAAG,IAAA,kCAAsB,EAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvD,MAAM,EAAE,wBAAwB,EAAE,GAAG,IAAA,wCAAuB,GAAE,CAAC;IAC/D,MAAM,mBAAmB,GAAG,MAAM,wBAAwB,EAAE,CAAC;IAC7D,OAAO,MAAM,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,IAAI,CAAC,CAAC;AACvE,CAAC;AAVD,wDAUC"}
|
package/package.json
CHANGED
|
@@ -23,9 +23,11 @@ export async function readAppCfgFile(props: {
|
|
|
23
23
|
}
|
|
24
24
|
try {
|
|
25
25
|
return appJson.read();
|
|
26
|
-
} catch (
|
|
26
|
+
} catch (e) {
|
|
27
27
|
throw new Error(
|
|
28
|
-
`Error reading app config for ${projectId}:\n${
|
|
28
|
+
`Error reading app config for ${projectId}:\n${
|
|
29
|
+
e.message
|
|
30
|
+
}\n${appJson.getErrors()}`
|
|
29
31
|
);
|
|
30
32
|
}
|
|
31
33
|
}
|
|
@@ -42,9 +44,11 @@ export async function writeAppCfgFile(props: {
|
|
|
42
44
|
const appJson = AppJsonFile(appDir);
|
|
43
45
|
try {
|
|
44
46
|
appJson.write(appCfg);
|
|
45
|
-
} catch (
|
|
47
|
+
} catch (e) {
|
|
46
48
|
throw new Error(
|
|
47
|
-
`Error writing app config for ${projectId}:\n${
|
|
49
|
+
`Error writing app config for ${projectId}:\n${
|
|
50
|
+
e.message
|
|
51
|
+
}\n${appJson.getErrors()}`
|
|
48
52
|
);
|
|
49
53
|
}
|
|
50
54
|
}
|
|
@@ -6,7 +6,7 @@ import { JsSpawner, Spawner } from 'alwaysai/lib/util';
|
|
|
6
6
|
import { getAppDir, downloadPackageUsingPresignedUrl, buildApp } from './utils';
|
|
7
7
|
import { AppDetailsPacket } from '@alwaysai/device-agent-schemas';
|
|
8
8
|
import { BACKUP_EXT } from './backup';
|
|
9
|
-
import { stopApp } from './status';
|
|
9
|
+
import { startApp, stopApp } from './status';
|
|
10
10
|
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
11
11
|
import { ProjectJsonFile } from 'alwaysai/lib/core/project';
|
|
12
12
|
import {
|
|
@@ -107,6 +107,8 @@ export async function installApp(props: {
|
|
|
107
107
|
version: appReleaseHash
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
await startApp({ projectId });
|
|
111
|
+
|
|
110
112
|
logger.info(`Completed installing ${projectId}:${appReleaseHash}`);
|
|
111
113
|
}
|
|
112
114
|
|
|
@@ -199,7 +201,9 @@ export async function uninstallApp(props: {
|
|
|
199
201
|
try {
|
|
200
202
|
await stopApp({ projectId });
|
|
201
203
|
} catch (e) {
|
|
202
|
-
logger.warn(
|
|
204
|
+
logger.warn(
|
|
205
|
+
`Failed to stop ${projectId}, may be left running...\n${e.message}`
|
|
206
|
+
);
|
|
203
207
|
}
|
|
204
208
|
await AgentConfigFile().setAppUninstalled({ projectId });
|
|
205
209
|
// Delete application directory and backup
|
|
@@ -213,7 +213,7 @@ export async function updateModelsWithPresignedUrls(props: {
|
|
|
213
213
|
} catch (e) {
|
|
214
214
|
logger.error(
|
|
215
215
|
'Error updating app models from presigned URL, restoring models.',
|
|
216
|
-
e
|
|
216
|
+
e.message
|
|
217
217
|
);
|
|
218
218
|
await spawner.rimraf(ogDir);
|
|
219
219
|
await copyDir({ srcPath: restoreDir, destPath: ogDir });
|
|
@@ -135,8 +135,7 @@ export async function startApp(props: {
|
|
|
135
135
|
logger.debug(`docker login: ${result}`);
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
//
|
|
139
|
-
// Start app
|
|
138
|
+
// Always call `docker-compose up` regardless of application state
|
|
140
139
|
const upOut = await compose.upAll({ cwd: appDir });
|
|
141
140
|
logger.debug(`docker-compose up: ${JSON.stringify(upOut, null, 2)}`);
|
|
142
141
|
if (upOut.exitCode !== 0) {
|
|
@@ -152,21 +151,16 @@ export async function stopApp(props: { projectId: string }): Promise<void> {
|
|
|
152
151
|
await requireAppInstalled({ projectId });
|
|
153
152
|
|
|
154
153
|
const appDir = getAppDir(projectId);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (output.exitCode !== 0) {
|
|
164
|
-
throw new Error(
|
|
165
|
-
`Failed to stop application! stdout=${output.out} stderr=${output.err}`
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
logger.info(`Stopped ${projectId}`);
|
|
154
|
+
// Always call `docker-compose down` regardless of application state to ensure
|
|
155
|
+
// containers are cleaned up
|
|
156
|
+
const output = await compose.down({ cwd: appDir });
|
|
157
|
+
logger.debug(`docker-compose down: ${JSON.stringify(output, null, 2)}`);
|
|
158
|
+
if (output.exitCode !== 0) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`Failed to stop application! stdout=${output.out} stderr=${output.err}`
|
|
161
|
+
);
|
|
169
162
|
}
|
|
163
|
+
logger.info(`Stopped ${projectId}`);
|
|
170
164
|
}
|
|
171
165
|
|
|
172
166
|
export async function restartApp(props: { projectId: string }): Promise<void> {
|
|
@@ -104,11 +104,10 @@ export async function downloadPackageUsingPresignedUrl(props: {
|
|
|
104
104
|
let response: any;
|
|
105
105
|
try {
|
|
106
106
|
response = await fetchWithTimeout(presignedUrl);
|
|
107
|
-
} catch (
|
|
108
|
-
const errorBody =
|
|
109
|
-
error.type === 'aborted' ? error : await error.response.text();
|
|
107
|
+
} catch (e) {
|
|
108
|
+
const errorBody = e.type === 'aborted' ? e : await e.response.text();
|
|
110
109
|
throw new Error(
|
|
111
|
-
`downloadPackageUsingPresignedUrl: Error=${
|
|
110
|
+
`downloadPackageUsingPresignedUrl: Error=${e}\n${errorBody}`
|
|
112
111
|
);
|
|
113
112
|
}
|
|
114
113
|
|
|
@@ -138,7 +138,7 @@ export class DeviceAgentCloudConnection {
|
|
|
138
138
|
});
|
|
139
139
|
try {
|
|
140
140
|
await uninstallApp({ projectId });
|
|
141
|
-
this.shadowHandler.
|
|
141
|
+
this.shadowHandler.clearAppConfig(projectId);
|
|
142
142
|
|
|
143
143
|
await this.cmdStatusMgr.stop(projectId);
|
|
144
144
|
await this.liveUpdatesHandler.disableAppInstallStatus({
|
|
@@ -153,7 +153,7 @@ export class DeviceAgentCloudConnection {
|
|
|
153
153
|
)
|
|
154
154
|
);
|
|
155
155
|
} catch (e) {
|
|
156
|
-
logger.error(`Failed to uninstall ${projectId}: ${e}`);
|
|
156
|
+
logger.error(`Failed to uninstall ${projectId}: ${e.message}`);
|
|
157
157
|
const message: string = e.message;
|
|
158
158
|
await this.cmdStatusMgr.stop(projectId);
|
|
159
159
|
await this.liveUpdatesHandler.disableAppInstallStatus({
|
|
@@ -200,29 +200,32 @@ export class DeviceAgentCloudConnection {
|
|
|
200
200
|
);
|
|
201
201
|
|
|
202
202
|
// update app config shadow for project
|
|
203
|
-
await this.shadowHandler.
|
|
203
|
+
await this.shadowHandler.publishAppConfig(projectId);
|
|
204
204
|
return out;
|
|
205
205
|
} catch (e) {
|
|
206
|
-
logger.error(`Failed to install ${projectId}: ${e}`);
|
|
206
|
+
logger.error(`Failed to install ${projectId}: ${e.message}`);
|
|
207
207
|
const message: string = e.message;
|
|
208
208
|
|
|
209
209
|
// uninstall the failed app to put system back in good state
|
|
210
210
|
// TODO: Replace this with rollback
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
try {
|
|
212
|
+
await uninstallApp({ projectId });
|
|
213
|
+
} finally {
|
|
214
|
+
this.shadowHandler.clearAppConfig(projectId);
|
|
213
215
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
216
|
+
await this.cmdStatusMgr.stop(projectId);
|
|
217
|
+
await this.liveUpdatesHandler.disableAppInstallStatus({
|
|
218
|
+
projectId
|
|
219
|
+
});
|
|
220
|
+
// Send final status message
|
|
221
|
+
this.publisher.publishToClient(
|
|
222
|
+
await getAppInstallStatusMessage(
|
|
223
|
+
keyMirrors.appInstallStatus.failure,
|
|
224
|
+
message,
|
|
225
|
+
appReleaseHash
|
|
226
|
+
)
|
|
227
|
+
);
|
|
228
|
+
}
|
|
226
229
|
}
|
|
227
230
|
}
|
|
228
231
|
|
|
@@ -298,7 +301,10 @@ export class DeviceAgentCloudConnection {
|
|
|
298
301
|
|
|
299
302
|
this.subscribe(this.toDeviceTopic);
|
|
300
303
|
this.subscribe(this.shadowHandler.shadowTopics.projects.getAccepted);
|
|
304
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.getRejected);
|
|
301
305
|
this.subscribe(this.shadowHandler.shadowTopics.projects.updateDelta);
|
|
306
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.updateAccepted);
|
|
307
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.updateRejected);
|
|
302
308
|
}
|
|
303
309
|
|
|
304
310
|
public getClientId(): string {
|
|
@@ -419,11 +425,17 @@ export class DeviceAgentCloudConnection {
|
|
|
419
425
|
case this.shadowHandler.shadowTopics.projects.updateDelta: {
|
|
420
426
|
const appConfigUpdates = await this.shadowHandler.handleShadowTopic({
|
|
421
427
|
topic,
|
|
422
|
-
payload: message.state
|
|
428
|
+
payload: message.state,
|
|
429
|
+
clientToken: message.clientToken
|
|
423
430
|
});
|
|
424
431
|
await this.handleAppConfigUpdates(appConfigUpdates);
|
|
425
432
|
break;
|
|
426
433
|
}
|
|
434
|
+
case this.shadowHandler.shadowTopics.projects.getRejected:
|
|
435
|
+
case this.shadowHandler.shadowTopics.projects.updateAccepted:
|
|
436
|
+
case this.shadowHandler.shadowTopics.projects.updateRejected:
|
|
437
|
+
// Not handling these for now
|
|
438
|
+
break;
|
|
427
439
|
case this.toDeviceTopic:
|
|
428
440
|
await this.handleClientMessage({
|
|
429
441
|
topic,
|
|
@@ -461,8 +473,8 @@ export class DeviceAgentCloudConnection {
|
|
|
461
473
|
try {
|
|
462
474
|
const jsonPacket = JSON.parse(payload);
|
|
463
475
|
await this.handleMessage(topic, jsonPacket);
|
|
464
|
-
} catch (
|
|
465
|
-
logger.error(`Error parsing message: ${
|
|
476
|
+
} catch (e) {
|
|
477
|
+
logger.error(`Error parsing message: ${e.message}`);
|
|
466
478
|
}
|
|
467
479
|
});
|
|
468
480
|
|
|
@@ -132,16 +132,15 @@ export class LiveUpdatesHandler {
|
|
|
132
132
|
while (true) {
|
|
133
133
|
try {
|
|
134
134
|
const message = await getMessageData(...args);
|
|
135
|
+
if (!this.continuePublishing(messageType, projectId)) {
|
|
136
|
+
logger.info(`Turned off live updates for ${messageType}`);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
135
139
|
this.publisher.publishToClient(message);
|
|
136
140
|
} catch (e) {
|
|
137
141
|
logger.error(
|
|
138
142
|
`Error publishing live updates for ${messageType}: ${e.message}`
|
|
139
143
|
);
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
if (!this.continuePublishing(messageType, projectId)) {
|
|
143
|
-
logger.info(`Turned off live updates for ${messageType}`);
|
|
144
|
-
break;
|
|
145
144
|
}
|
|
146
145
|
await sleep(this.getLiveUpdatesInterval(messageType));
|
|
147
146
|
}
|
|
@@ -161,14 +160,16 @@ export class LiveUpdatesHandler {
|
|
|
161
160
|
}) {
|
|
162
161
|
const { projectId, appReleaseHash } = props;
|
|
163
162
|
this.liveUpdatesAlive.app_install_status = true;
|
|
164
|
-
this.appInstallStatuses.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
163
|
+
if (!this.appInstallStatuses.has(projectId)) {
|
|
164
|
+
this.appInstallStatuses.add(projectId);
|
|
165
|
+
// Don't wait for this call to finish since it loops until disabled
|
|
166
|
+
void this.startPublishingLiveUpdates(
|
|
167
|
+
keyMirrors.agentMessageType.app_install_status,
|
|
168
|
+
getAppInstallStatusMessage,
|
|
169
|
+
[keyMirrors.appInstallStatus.in_progress, '', appReleaseHash],
|
|
170
|
+
projectId
|
|
171
|
+
);
|
|
172
|
+
}
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
public async disableAppInstallStatus(props: { projectId: string }) {
|
|
@@ -24,7 +24,8 @@ describe('Test Shadow Handler', () => {
|
|
|
24
24
|
expect(async () => {
|
|
25
25
|
await shadowHandler.handleShadowTopic({
|
|
26
26
|
topic: shadowHandler.shadowTopics.projects.updateDelta,
|
|
27
|
-
payload: Buffer.from('test-payload')
|
|
27
|
+
payload: Buffer.from('test-payload'),
|
|
28
|
+
clientToken: ''
|
|
28
29
|
});
|
|
29
30
|
}).toThrow(Error);
|
|
30
31
|
});
|
|
@@ -51,13 +52,13 @@ describe('Test Shadow Handler', () => {
|
|
|
51
52
|
const payload = {
|
|
52
53
|
[projectId1]: {
|
|
53
54
|
appConfig: JSON.stringify(appCfg1)
|
|
54
|
-
}
|
|
55
|
-
clientToken: clientId
|
|
55
|
+
}
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
const appCfgUpdates = await shadowHandler.handleShadowTopic({
|
|
59
59
|
topic: shadowHandler.shadowTopics.projects.updateDelta,
|
|
60
|
-
payload
|
|
60
|
+
payload,
|
|
61
|
+
clientToken: clientId
|
|
61
62
|
});
|
|
62
63
|
expect(appCfgUpdates.length).toBe(0);
|
|
63
64
|
});
|
|
@@ -92,7 +93,8 @@ describe('Test Shadow Handler', () => {
|
|
|
92
93
|
|
|
93
94
|
const appCfgUpdates = await shadowHandler.handleShadowTopic({
|
|
94
95
|
topic: shadowHandler.shadowTopics.projects.getAccepted,
|
|
95
|
-
payload
|
|
96
|
+
payload,
|
|
97
|
+
clientToken: ''
|
|
96
98
|
});
|
|
97
99
|
expect(appCfgUpdates.length).toBe(1);
|
|
98
100
|
expect(appCfgUpdates[0]).toEqual({
|
|
@@ -121,7 +123,8 @@ describe('Test Shadow Handler', () => {
|
|
|
121
123
|
|
|
122
124
|
const appCfgUpdates = await shadowHandler.handleShadowTopic({
|
|
123
125
|
topic: shadowHandler.shadowTopics.projects.updateDelta,
|
|
124
|
-
payload
|
|
126
|
+
payload,
|
|
127
|
+
clientToken: ''
|
|
125
128
|
});
|
|
126
129
|
expect(appCfgUpdates.length).toBe(0);
|
|
127
130
|
});
|
|
@@ -155,7 +158,8 @@ describe('Test Shadow Handler', () => {
|
|
|
155
158
|
|
|
156
159
|
const appCfgUpdates = await shadowHandler.handleShadowTopic({
|
|
157
160
|
topic: shadowHandler.shadowTopics.projects.updateDelta,
|
|
158
|
-
payload
|
|
161
|
+
payload,
|
|
162
|
+
clientToken: ''
|
|
159
163
|
});
|
|
160
164
|
expect(appCfgUpdates.length).toBe(1);
|
|
161
165
|
expect(appCfgUpdates[0]).toEqual({
|
|
@@ -217,7 +221,8 @@ describe('Test Shadow Handler', () => {
|
|
|
217
221
|
|
|
218
222
|
const appCfgUpdates = await shadowHandler.handleShadowTopic({
|
|
219
223
|
topic: shadowHandler.shadowTopics.projects.updateDelta,
|
|
220
|
-
payload
|
|
224
|
+
payload,
|
|
225
|
+
clientToken: ''
|
|
221
226
|
});
|
|
222
227
|
expect(appCfgUpdates.length).toBe(2);
|
|
223
228
|
expect(appCfgUpdates[0]).toEqual({
|
|
@@ -264,7 +269,8 @@ describe('Test Shadow Handler', () => {
|
|
|
264
269
|
|
|
265
270
|
const appCfgUpdates = await shadowHandler.handleShadowTopic({
|
|
266
271
|
topic: shadowHandler.shadowTopics.projects.updateDelta,
|
|
267
|
-
payload
|
|
272
|
+
payload,
|
|
273
|
+
clientToken: ''
|
|
268
274
|
});
|
|
269
275
|
expect(appCfgUpdates.length).toBe(1);
|
|
270
276
|
expect(appCfgUpdates[0]).toEqual({
|
|
@@ -302,12 +308,13 @@ describe('Test Shadow Handler', () => {
|
|
|
302
308
|
|
|
303
309
|
const appCfgUpdates = await shadowHandler.handleShadowTopic({
|
|
304
310
|
topic: shadowHandler.shadowTopics.projects.updateDelta,
|
|
305
|
-
payload
|
|
311
|
+
payload,
|
|
312
|
+
clientToken: ''
|
|
306
313
|
});
|
|
307
314
|
expect(appCfgUpdates.length).toBe(0);
|
|
308
315
|
});
|
|
309
316
|
|
|
310
|
-
test.skip('publish app
|
|
317
|
+
test.skip('publish app config', async () => {
|
|
311
318
|
// FIXME: For some reason publisher is not being called...
|
|
312
319
|
const testAppCfg: AppConfig = {
|
|
313
320
|
scripts: {
|
|
@@ -317,7 +324,7 @@ describe('Test Shadow Handler', () => {
|
|
|
317
324
|
};
|
|
318
325
|
jest.mocked(readAppCfgFile).mockResolvedValue(testAppCfg);
|
|
319
326
|
|
|
320
|
-
await shadowHandler.
|
|
327
|
+
await shadowHandler.publishAppConfig(projectId1);
|
|
321
328
|
expect(jest.mocked(readAppCfgFile)).toBeCalledWith({ projectId1 });
|
|
322
329
|
const packet = {
|
|
323
330
|
state: {
|
|
@@ -343,10 +350,13 @@ describe('Test Shadow Handler', () => {
|
|
|
343
350
|
);
|
|
344
351
|
});
|
|
345
352
|
|
|
346
|
-
test('
|
|
347
|
-
shadowHandler.
|
|
353
|
+
test('clear project shadow', async () => {
|
|
354
|
+
shadowHandler.clearAppConfig(projectId1);
|
|
348
355
|
const packet = {
|
|
349
356
|
state: {
|
|
357
|
+
desired: {
|
|
358
|
+
[projectId1]: null
|
|
359
|
+
},
|
|
350
360
|
reported: {
|
|
351
361
|
[projectId1]: null
|
|
352
362
|
}
|
|
@@ -9,10 +9,13 @@ import { AppConfigModels, getAppCfgModelsDiff } from './shadow';
|
|
|
9
9
|
|
|
10
10
|
export interface ShadowTopics {
|
|
11
11
|
projects: {
|
|
12
|
-
update: string;
|
|
13
12
|
get: string;
|
|
14
|
-
updateDelta: string;
|
|
15
13
|
getAccepted: string;
|
|
14
|
+
getRejected: string;
|
|
15
|
+
update: string;
|
|
16
|
+
updateDelta: string;
|
|
17
|
+
updateAccepted: string;
|
|
18
|
+
updateRejected: string;
|
|
16
19
|
delete: string;
|
|
17
20
|
};
|
|
18
21
|
}
|
|
@@ -35,10 +38,13 @@ export class ShadowHandler {
|
|
|
35
38
|
this.shadowPrefix = `$aws/things/${this.clientId}/shadow/name/`;
|
|
36
39
|
this.shadowTopics = {
|
|
37
40
|
projects: {
|
|
38
|
-
update: `${this.shadowPrefix}projects/update`,
|
|
39
41
|
get: `${this.shadowPrefix}projects/get`,
|
|
40
|
-
updateDelta: `${this.shadowPrefix}projects/update/delta`,
|
|
41
42
|
getAccepted: `${this.shadowPrefix}projects/get/accepted`,
|
|
43
|
+
getRejected: `${this.shadowPrefix}projects/get/rejected`,
|
|
44
|
+
update: `${this.shadowPrefix}projects/update`,
|
|
45
|
+
updateDelta: `${this.shadowPrefix}projects/update/delta`,
|
|
46
|
+
updateAccepted: `${this.shadowPrefix}projects/update/accepted`,
|
|
47
|
+
updateRejected: `${this.shadowPrefix}projects/update/rejected`,
|
|
42
48
|
delete: `${this.shadowPrefix}projects/delete`
|
|
43
49
|
}
|
|
44
50
|
};
|
|
@@ -92,16 +98,18 @@ export class ShadowHandler {
|
|
|
92
98
|
|
|
93
99
|
public async handleShadowTopic({
|
|
94
100
|
topic,
|
|
95
|
-
payload
|
|
101
|
+
payload,
|
|
102
|
+
clientToken
|
|
96
103
|
}: {
|
|
97
104
|
topic: string;
|
|
98
105
|
payload: any;
|
|
106
|
+
clientToken: string;
|
|
99
107
|
}): Promise<AppConfigUpdate[]> {
|
|
100
108
|
// TODO: make use a function like the other topic getters
|
|
101
109
|
const shadowName = topic.split('/')[5];
|
|
102
110
|
switch (topic) {
|
|
103
111
|
case this.shadowTopics.projects.updateDelta:
|
|
104
|
-
if (
|
|
112
|
+
if (clientToken === this.clientId) {
|
|
105
113
|
logger.debug(
|
|
106
114
|
`Ignoring message sent from self: ${JSON.stringify(
|
|
107
115
|
{ topic, payload },
|
|
@@ -133,7 +141,7 @@ export class ShadowHandler {
|
|
|
133
141
|
return [];
|
|
134
142
|
}
|
|
135
143
|
|
|
136
|
-
public async
|
|
144
|
+
public async publishAppConfig(projectId: string) {
|
|
137
145
|
const appCfg = await readAppCfgFile({ projectId });
|
|
138
146
|
const packet = {
|
|
139
147
|
state: {
|
|
@@ -143,33 +151,42 @@ export class ShadowHandler {
|
|
|
143
151
|
},
|
|
144
152
|
clientToken: this.clientId
|
|
145
153
|
};
|
|
146
|
-
this.
|
|
147
|
-
|
|
148
|
-
JSON.stringify(packet)
|
|
154
|
+
const topic = this.shadowTopics.projects.update;
|
|
155
|
+
logger.debug(
|
|
156
|
+
`Publishing message:\n${JSON.stringify({ topic, packet }, null, 2)}`
|
|
149
157
|
);
|
|
158
|
+
this.publisher.publish(topic, JSON.stringify(packet));
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
public getShadowUpdates() {
|
|
153
|
-
this.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
const topic = this.shadowTopics.projects.get;
|
|
163
|
+
const packet = {
|
|
164
|
+
clientToken: this.clientId
|
|
165
|
+
};
|
|
166
|
+
logger.debug(
|
|
167
|
+
`Publishing message:\n${JSON.stringify({ topic, packet }, null, 2)}`
|
|
158
168
|
);
|
|
169
|
+
this.publisher.publish(topic, JSON.stringify(packet));
|
|
159
170
|
}
|
|
160
171
|
|
|
161
|
-
public
|
|
172
|
+
public clearAppConfig(projectId: string) {
|
|
173
|
+
const topic = this.shadowTopics.projects.update;
|
|
174
|
+
// TODO: We should actually send only desired and handle the delta
|
|
175
|
+
// to update reported
|
|
162
176
|
const packet = {
|
|
163
177
|
state: {
|
|
178
|
+
desired: {
|
|
179
|
+
[projectId]: null
|
|
180
|
+
},
|
|
164
181
|
reported: {
|
|
165
182
|
[projectId]: null
|
|
166
183
|
}
|
|
167
184
|
},
|
|
168
185
|
clientToken: this.clientId
|
|
169
186
|
};
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
JSON.stringify(packet)
|
|
187
|
+
logger.debug(
|
|
188
|
+
`Publishing message:\n${JSON.stringify({ topic, packet }, null, 2)}`
|
|
173
189
|
);
|
|
190
|
+
this.publisher.publish(topic, JSON.stringify(packet));
|
|
174
191
|
}
|
|
175
192
|
}
|