@alwaysai/device-agent 0.0.4 → 0.0.5
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 +10 -6
- package/lib/application-control/backup.js.map +1 -1
- package/lib/application-control/environment-variables.d.ts +9 -0
- package/lib/application-control/environment-variables.d.ts.map +1 -0
- package/lib/application-control/environment-variables.js +82 -0
- package/lib/application-control/environment-variables.js.map +1 -0
- package/lib/application-control/index.d.ts +9 -0
- package/lib/application-control/index.d.ts.map +1 -0
- package/lib/application-control/index.js +27 -0
- package/lib/application-control/index.js.map +1 -0
- package/lib/application-control/install.d.ts +8 -2
- package/lib/application-control/install.d.ts.map +1 -1
- package/lib/application-control/install.js +72 -42
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/models.d.ts.map +1 -1
- package/lib/application-control/models.js +7 -17
- package/lib/application-control/models.js.map +1 -1
- package/lib/application-control/status.d.ts +3 -3
- package/lib/application-control/status.d.ts.map +1 -1
- package/lib/application-control/status.js +19 -20
- package/lib/application-control/status.js.map +1 -1
- package/lib/application-control/types.d.ts +0 -13
- package/lib/application-control/types.d.ts.map +1 -1
- package/lib/application-control/utils.d.ts +2 -9
- package/lib/application-control/utils.d.ts.map +1 -1
- package/lib/application-control/utils.js +13 -28
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +15 -2
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +200 -27
- package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
- package/lib/docker/docker-cmd.js +2 -2
- package/lib/docker/docker-cmd.js.map +1 -1
- package/lib/docker/docker-compose-cmd.js +2 -2
- package/lib/docker/docker-compose-cmd.js.map +1 -1
- package/lib/environment.d.ts +2 -0
- package/lib/environment.d.ts.map +1 -1
- package/lib/environment.js +3 -1
- package/lib/environment.js.map +1 -1
- package/lib/index.js +10 -8
- package/lib/index.js.map +1 -1
- package/lib/infrastructure/agent-config.d.ts +73 -0
- package/lib/infrastructure/agent-config.d.ts.map +1 -0
- package/lib/infrastructure/agent-config.js +186 -0
- package/lib/infrastructure/agent-config.js.map +1 -0
- package/lib/infrastructure/agent-config.test.d.ts +2 -0
- package/lib/infrastructure/agent-config.test.d.ts.map +1 -0
- package/lib/infrastructure/agent-config.test.js +135 -0
- package/lib/infrastructure/agent-config.test.js.map +1 -0
- package/lib/infrastructure/certificates-and-tokens.d.ts +6 -0
- package/lib/infrastructure/certificates-and-tokens.d.ts.map +1 -0
- package/lib/infrastructure/certificates-and-tokens.js +69 -0
- package/lib/infrastructure/certificates-and-tokens.js.map +1 -0
- package/lib/{util → infrastructure}/urls.d.ts +0 -0
- package/lib/infrastructure/urls.d.ts.map +1 -0
- package/lib/{util → infrastructure}/urls.js +3 -3
- package/lib/infrastructure/urls.js.map +1 -0
- package/lib/root.js +3 -3
- package/lib/root.js.map +1 -1
- package/lib/subcommands/app/app.d.ts +8 -1
- package/lib/subcommands/app/app.d.ts.map +1 -1
- package/lib/subcommands/app/app.js +58 -24
- package/lib/subcommands/app/app.js.map +1 -1
- package/lib/subcommands/app/index.d.ts.map +1 -1
- package/lib/subcommands/app/index.js +2 -0
- package/lib/subcommands/app/index.js.map +1 -1
- package/lib/subcommands/device/device.d.ts +6 -0
- package/lib/subcommands/device/device.d.ts.map +1 -0
- package/lib/subcommands/device/device.js +62 -0
- package/lib/subcommands/device/device.js.map +1 -0
- package/lib/subcommands/device/index.d.ts +2 -0
- package/lib/subcommands/device/index.d.ts.map +1 -0
- package/lib/subcommands/device/index.js +11 -0
- package/lib/subcommands/device/index.js.map +1 -0
- package/lib/subcommands/get-model-package.d.ts +5 -0
- package/lib/subcommands/get-model-package.d.ts.map +1 -0
- package/lib/subcommands/get-model-package.js +51 -0
- package/lib/subcommands/get-model-package.js.map +1 -0
- package/lib/subcommands/index.d.ts +8 -1
- package/lib/subcommands/index.d.ts.map +1 -1
- package/lib/subcommands/index.js +9 -3
- package/lib/subcommands/index.js.map +1 -1
- package/lib/subcommands/login.d.ts +3 -2
- package/lib/subcommands/login.d.ts.map +1 -1
- package/lib/subcommands/login.js +11 -4
- package/lib/subcommands/login.js.map +1 -1
- package/lib/util/copy-dir.js +3 -3
- package/lib/util/copy-dir.js.map +1 -1
- package/lib/util/directories.js +5 -5
- package/lib/util/directories.js.map +1 -1
- package/package.json +19 -14
- package/readme.md +176 -79
- package/src/application-control/backup.ts +10 -6
- package/src/application-control/environment-variables.ts +81 -0
- package/src/application-control/index.ts +40 -0
- package/src/application-control/install.ts +79 -55
- package/src/application-control/models.ts +12 -17
- package/src/application-control/status.ts +26 -24
- package/src/application-control/types.ts +0 -4
- package/src/application-control/utils.ts +10 -25
- package/src/cloud-connection/device-agent-cloud-connection.ts +243 -40
- package/src/docker/docker-cmd.ts +1 -1
- package/src/docker/docker-compose-cmd.ts +1 -1
- package/src/environment.ts +2 -0
- package/src/index.ts +10 -7
- package/src/infrastructure/agent-config.test.ts +143 -0
- package/src/infrastructure/agent-config.ts +217 -0
- package/src/infrastructure/certificates-and-tokens.ts +71 -0
- package/src/{util → infrastructure}/urls.ts +1 -1
- package/src/root.ts +3 -3
- package/src/subcommands/app/app.ts +57 -19
- package/src/subcommands/app/index.ts +4 -0
- package/src/subcommands/device/device.ts +63 -0
- package/src/subcommands/device/index.ts +8 -0
- package/src/subcommands/get-model-package.ts +60 -0
- package/src/subcommands/index.ts +9 -3
- package/src/subcommands/login.ts +11 -4
- package/src/util/copy-dir.ts +1 -1
- package/src/util/directories.ts +8 -8
- package/lib/constants.d.ts +0 -13
- package/lib/constants.d.ts.map +0 -1
- package/lib/constants.js +0 -18
- package/lib/constants.js.map +0 -1
- package/lib/subcommands/device-control.d.ts +0 -2
- package/lib/subcommands/device-control.d.ts.map +0 -1
- package/lib/subcommands/device-control.js +0 -19
- package/lib/subcommands/device-control.js.map +0 -1
- package/lib/util/spawner/gnu-spawner.d.ts +0 -9
- package/lib/util/spawner/gnu-spawner.d.ts.map +0 -1
- package/lib/util/spawner/gnu-spawner.js +0 -102
- package/lib/util/spawner/gnu-spawner.js.map +0 -1
- package/lib/util/spawner/js-spawner.d.ts +0 -5
- package/lib/util/spawner/js-spawner.d.ts.map +0 -1
- package/lib/util/spawner/js-spawner.js +0 -89
- package/lib/util/spawner/js-spawner.js.map +0 -1
- package/lib/util/spawner/types.d.ts +0 -28
- package/lib/util/spawner/types.d.ts.map +0 -1
- package/lib/util/spawner/types.js +0 -3
- package/lib/util/spawner/types.js.map +0 -1
- package/lib/util/spawner-base/index.d.ts +0 -17
- package/lib/util/spawner-base/index.d.ts.map +0 -1
- package/lib/util/spawner-base/index.js +0 -30
- package/lib/util/spawner-base/index.js.map +0 -1
- package/lib/util/spawner-base/run-foreground-sync.d.ts +0 -3
- package/lib/util/spawner-base/run-foreground-sync.d.ts.map +0 -1
- package/lib/util/spawner-base/run-foreground-sync.js +0 -18
- package/lib/util/spawner-base/run-foreground-sync.js.map +0 -1
- package/lib/util/spawner-base/run-foreground.d.ts +0 -3
- package/lib/util/spawner-base/run-foreground.d.ts.map +0 -1
- package/lib/util/spawner-base/run-foreground.js +0 -49
- package/lib/util/spawner-base/run-foreground.js.map +0 -1
- package/lib/util/spawner-base/run-streaming.d.ts +0 -4
- package/lib/util/spawner-base/run-streaming.d.ts.map +0 -1
- package/lib/util/spawner-base/run-streaming.js +0 -35
- package/lib/util/spawner-base/run-streaming.js.map +0 -1
- package/lib/util/spawner-base/run.d.ts +0 -4
- package/lib/util/spawner-base/run.d.ts.map +0 -1
- package/lib/util/spawner-base/run.js +0 -56
- package/lib/util/spawner-base/run.js.map +0 -1
- package/lib/util/urls.d.ts.map +0 -1
- package/lib/util/urls.js.map +0 -1
- package/lib/web/index.html +0 -229
- package/lib/web/static/Karla.css +0 -18
- package/lib/web/static/bootstrap-4.3.1.min.css +0 -7
- package/lib/web/static/bootstrap-4.3.1.min.js +0 -7
- package/lib/web/static/favicon.ico +0 -0
- package/lib/web/static/jquery-3.3.1.slim.min.js +0 -2
- package/lib/web/static/popper-1.14.7.min.js +0 -5
- package/lib/web/web-interface.d.ts +0 -2
- package/lib/web/web-interface.d.ts.map +0 -1
- package/lib/web/web-interface.js +0 -75
- package/lib/web/web-interface.js.map +0 -1
- package/src/constants.ts +0 -22
- package/src/subcommands/device-control.ts +0 -16
- package/src/util/spawner/gnu-spawner.ts +0 -114
- package/src/util/spawner/js-spawner.ts +0 -110
- package/src/util/spawner/types.ts +0 -28
- package/src/util/spawner-base/index.ts +0 -28
- package/src/util/spawner-base/run-foreground-sync.ts +0 -16
- package/src/util/spawner-base/run-foreground.ts +0 -49
- package/src/util/spawner-base/run-streaming.ts +0 -40
- package/src/util/spawner-base/run.ts +0 -60
- package/src/web/index.html +0 -229
- package/src/web/static/Karla.css +0 -18
- package/src/web/static/bootstrap-4.3.1.min.css +0 -7
- package/src/web/static/bootstrap-4.3.1.min.js +0 -7
- package/src/web/static/favicon.ico +0 -0
- package/src/web/static/jquery-3.3.1.slim.min.js +0 -2
- package/src/web/static/popper-1.14.7.min.js +0 -5
- package/src/web/web-interface.ts +0 -85
|
@@ -1,21 +1,46 @@
|
|
|
1
1
|
const awsIot = require('aws-iot-device-sdk');
|
|
2
|
-
import { getIoTCoreEndpointUrl } from '../
|
|
2
|
+
import { getIoTCoreEndpointUrl } from '../infrastructure/urls';
|
|
3
3
|
import {
|
|
4
4
|
getPrivateKeyFilePath,
|
|
5
5
|
getCertificateFilePath,
|
|
6
6
|
getRootCertificateFilePath,
|
|
7
7
|
} from '../util/directories';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import {
|
|
9
|
+
startApp,
|
|
10
|
+
stopApp,
|
|
11
|
+
restartApp,
|
|
12
|
+
getAppStatus,
|
|
13
|
+
getAppLogs,
|
|
14
|
+
} from '../application-control/status';
|
|
15
|
+
import { installApp } from '../application-control/install';
|
|
11
16
|
import { getCpuUtil, getDiskUtil, getMemUtil } from '../device-control/device-control';
|
|
17
|
+
import {
|
|
18
|
+
DeviceAgentMessage,
|
|
19
|
+
DeviceStatsMessage,
|
|
20
|
+
AppState,
|
|
21
|
+
AppStateMessage,
|
|
22
|
+
ActionMessage,
|
|
23
|
+
AppLogs,
|
|
24
|
+
AppLogsMessage,
|
|
25
|
+
InstallationStatusMessage,
|
|
26
|
+
InstallationStatus,
|
|
27
|
+
InstallationStatusEnum,
|
|
28
|
+
} from '@alwaysai/device-agent-schemas';
|
|
12
29
|
import { getDeviceId } from '../util/get-device-id';
|
|
30
|
+
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
13
31
|
|
|
14
32
|
export class DeviceAgentCloudConnection {
|
|
15
|
-
public device = awsIot.device;
|
|
16
33
|
private clientId = getDeviceId();
|
|
17
34
|
private host = getIoTCoreEndpointUrl();
|
|
18
|
-
private
|
|
35
|
+
private publishable = false;
|
|
36
|
+
private readonly publishInterval = 1000;
|
|
37
|
+
private readonly installationStatusInterval = 3000;
|
|
38
|
+
private installationStatus: InstallationStatus;
|
|
39
|
+
private publishableTimeout: ReturnType<typeof setTimeout>;
|
|
40
|
+
|
|
41
|
+
public device = awsIot.device;
|
|
42
|
+
public agentTopicPrefix = `destination/agent/device/${this.clientId}/topic/`;
|
|
43
|
+
public cloudTopicPrefix = `destination/cloud/device/${this.clientId}/topic/`;
|
|
19
44
|
|
|
20
45
|
constructor() {
|
|
21
46
|
this.device = awsIot.device({
|
|
@@ -26,21 +51,46 @@ export class DeviceAgentCloudConnection {
|
|
|
26
51
|
host: this.host,
|
|
27
52
|
});
|
|
28
53
|
|
|
29
|
-
|
|
30
|
-
this.device.subscribe(
|
|
31
|
-
|
|
54
|
+
this.device.subscribe(`${this.agentTopicPrefix}command`);
|
|
55
|
+
this.device.subscribe(`${this.agentTopicPrefix}response`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public setInstallationStatus(installationStatus: InstallationStatus) {
|
|
59
|
+
this.installationStatus = installationStatus;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public getInstallationStatus(): InstallationStatus {
|
|
63
|
+
return this.installationStatus;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public getPublishable(): boolean {
|
|
67
|
+
return this.publishable;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public setPublishable(enabled: boolean) {
|
|
71
|
+
this.publishable = enabled;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public restartPublishableTimeout() {
|
|
75
|
+
clearTimeout(this.publishableTimeout);
|
|
76
|
+
this.publishableTimeout = setTimeout(() => {
|
|
77
|
+
this.setPublishable(false);
|
|
78
|
+
}, 600000); // 10 min
|
|
32
79
|
}
|
|
33
80
|
|
|
34
81
|
public getPublishInterval() {
|
|
35
82
|
return this.publishInterval;
|
|
36
83
|
}
|
|
37
84
|
|
|
38
|
-
public
|
|
85
|
+
public getInstallationStatusInterval() {
|
|
86
|
+
return this.installationStatusInterval;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public getClientId(): string {
|
|
39
90
|
return this.clientId;
|
|
40
91
|
}
|
|
41
92
|
|
|
42
93
|
public publishMessage(topic: string, message: string) {
|
|
43
|
-
console.log('publishing message ', message);
|
|
44
94
|
this.device.publish(topic, message);
|
|
45
95
|
}
|
|
46
96
|
}
|
|
@@ -48,11 +98,60 @@ export class DeviceAgentCloudConnection {
|
|
|
48
98
|
export function runDeviceAgentCloudInterface() {
|
|
49
99
|
const deviceAgent = new DeviceAgentCloudConnection();
|
|
50
100
|
|
|
51
|
-
async function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
101
|
+
async function buildMessagePacket(
|
|
102
|
+
topic: string,
|
|
103
|
+
payload:
|
|
104
|
+
| DeviceStatsMessage
|
|
105
|
+
| ActionMessage
|
|
106
|
+
| AppStateMessage
|
|
107
|
+
| AppLogsMessage
|
|
108
|
+
| InstallationStatusMessage,
|
|
109
|
+
): Promise<DeviceAgentMessage> {
|
|
110
|
+
const packet = {
|
|
111
|
+
timestamp: new Date().toUTCString(),
|
|
112
|
+
deviceId: deviceAgent.getClientId(),
|
|
113
|
+
topic,
|
|
114
|
+
payload,
|
|
115
|
+
};
|
|
116
|
+
return packet;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function getAppLogsMessage(): Promise<AppLogsMessage> {
|
|
120
|
+
const appLogsList: AppLogs[] = [];
|
|
121
|
+
const apps = await AgentConfigFile().getReadyApps();
|
|
122
|
+
for (const app of apps) {
|
|
123
|
+
const projectId = app.projectId;
|
|
124
|
+
const readable = await getAppLogs({ projectId });
|
|
125
|
+
const logs: any[] = [];
|
|
126
|
+
readable.setEncoding('utf8');
|
|
127
|
+
for await (const chunk of readable) {
|
|
128
|
+
logs.push(chunk);
|
|
129
|
+
}
|
|
130
|
+
const appLogs = {
|
|
131
|
+
projectId,
|
|
132
|
+
logs,
|
|
133
|
+
};
|
|
134
|
+
appLogsList.push(appLogs);
|
|
135
|
+
}
|
|
136
|
+
const applicationStatePackage = {
|
|
137
|
+
applicationLogs: appLogsList,
|
|
138
|
+
};
|
|
139
|
+
return applicationStatePackage;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const publishAppLogs = setInterval(async function () {
|
|
143
|
+
const appLogsMessage = await getAppLogsMessage();
|
|
144
|
+
const topic = `device/${deviceAgent.getClientId()}/topic/application-management`;
|
|
145
|
+
const appLogsPacket = await buildMessagePacket(topic, appLogsMessage);
|
|
146
|
+
|
|
147
|
+
deviceAgent.publishMessage(topic, JSON.stringify({ appLogsPacket }));
|
|
148
|
+
}, deviceAgent.getPublishInterval());
|
|
149
|
+
|
|
150
|
+
async function getAppStateMessage(): Promise<AppStateMessage> {
|
|
151
|
+
const appStateMessage: AppState[] = [];
|
|
152
|
+
const apps = await AgentConfigFile().getApps();
|
|
153
|
+
for (const app of apps) {
|
|
154
|
+
const projectId = app.projectId;
|
|
56
155
|
const status = await getAppStatus({ projectId });
|
|
57
156
|
appStateMessage.push(status);
|
|
58
157
|
}
|
|
@@ -62,19 +161,16 @@ export function runDeviceAgentCloudInterface() {
|
|
|
62
161
|
return applicationStatePackage;
|
|
63
162
|
}
|
|
64
163
|
|
|
65
|
-
const publishAppState = setInterval(async function() {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
payload: appStateMessage,
|
|
73
|
-
};
|
|
74
|
-
deviceAgent.publishMessage(topic, JSON.stringify({ appStatePackage }));
|
|
164
|
+
const publishAppState = setInterval(async function () {
|
|
165
|
+
if (deviceAgent.getPublishable()) {
|
|
166
|
+
const topic = `${deviceAgent.cloudTopicPrefix}application-management`;
|
|
167
|
+
const appStateMessage = await getAppStateMessage();
|
|
168
|
+
const appStatePacket = await buildMessagePacket(topic, appStateMessage);
|
|
169
|
+
deviceAgent.publishMessage(topic, JSON.stringify({ appStatePacket }));
|
|
170
|
+
}
|
|
75
171
|
}, deviceAgent.getPublishInterval());
|
|
76
172
|
|
|
77
|
-
async function getDeviceStatsMessage() {
|
|
173
|
+
async function getDeviceStatsMessage(): Promise<DeviceStatsMessage> {
|
|
78
174
|
const cpuUsage = await getCpuUtil();
|
|
79
175
|
const diskUtil = await getDiskUtil();
|
|
80
176
|
const memUtil = await getMemUtil();
|
|
@@ -83,35 +179,142 @@ export function runDeviceAgentCloudInterface() {
|
|
|
83
179
|
deviceStats: {
|
|
84
180
|
cpuUsage,
|
|
85
181
|
diskUtil,
|
|
86
|
-
|
|
182
|
+
usedMemoryPercentage: memUtil,
|
|
87
183
|
},
|
|
88
184
|
};
|
|
89
185
|
return deviceStatsMessage;
|
|
90
186
|
}
|
|
91
187
|
|
|
92
|
-
const publishDeviceStats = setInterval(async function() {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
188
|
+
const publishDeviceStats = setInterval(async function () {
|
|
189
|
+
if (deviceAgent.getPublishable()) {
|
|
190
|
+
const topic = `${deviceAgent.cloudTopicPrefix}device-management`;
|
|
191
|
+
const deviceStatsMessage = await getDeviceStatsMessage();
|
|
192
|
+
const deviceStatsPacket = await buildMessagePacket(topic, deviceStatsMessage);
|
|
193
|
+
deviceAgent.publishMessage(topic, JSON.stringify({ deviceStatsPacket }));
|
|
194
|
+
}
|
|
195
|
+
}, deviceAgent.getPublishInterval());
|
|
196
|
+
|
|
197
|
+
const publishDeviceRequest = async ({ projectId }) => {
|
|
198
|
+
const topic = `${deviceAgent.cloudTopicPrefix}request`;
|
|
199
|
+
const deviceRequestPackage = {
|
|
96
200
|
timestamp: new Date().toUTCString(),
|
|
97
201
|
deviceId: deviceAgent.getClientId(),
|
|
202
|
+
projectId,
|
|
203
|
+
releaseHash: '',
|
|
98
204
|
topic,
|
|
99
|
-
payload: deviceStatsMessage,
|
|
100
205
|
};
|
|
101
|
-
deviceAgent.publishMessage(
|
|
102
|
-
|
|
206
|
+
deviceAgent.publishMessage(
|
|
207
|
+
topic,
|
|
208
|
+
JSON.stringify({ device_request: deviceRequestPackage }),
|
|
209
|
+
);
|
|
210
|
+
};
|
|
103
211
|
|
|
104
|
-
|
|
212
|
+
const publishInstallationStatus = async (interval: NodeJS.Timeout) => {
|
|
213
|
+
const topic = `${deviceAgent.cloudTopicPrefix}installation-status`;
|
|
214
|
+
const installationStatus = deviceAgent.getInstallationStatus();
|
|
215
|
+
const installationStatusPacket = await buildMessagePacket(topic, {
|
|
216
|
+
installationStatus,
|
|
217
|
+
});
|
|
218
|
+
deviceAgent.device.publish(topic, JSON.stringify({ installationStatusPacket }));
|
|
219
|
+
if (installationStatus.status !== InstallationStatusEnum.IN_PROGRESS) {
|
|
220
|
+
clearInterval(interval);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const handleMessageTopic = async ({ topic, payload }) => {
|
|
225
|
+
const action = payload['action'];
|
|
226
|
+
const actionPayload: any = payload[action];
|
|
227
|
+
const type = topic.split('/').slice(-1)[0];
|
|
228
|
+
|
|
229
|
+
if (!type) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
switch (action) {
|
|
234
|
+
/**
|
|
235
|
+
* Install app package based on the given project ID
|
|
236
|
+
*/
|
|
237
|
+
case 'install':
|
|
238
|
+
/**
|
|
239
|
+
{
|
|
240
|
+
"action": "install",
|
|
241
|
+
"install": {
|
|
242
|
+
"releaseHash": "7fb2a812f9e7aa193208dac353521965da50d755085162066c125592f1ed760b",
|
|
243
|
+
"projectId": "786e4686-a681-4cff-9e17-1e7d385c0fdb"
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
*/
|
|
247
|
+
if (type === 'response') {
|
|
248
|
+
deviceAgent.setInstallationStatus({
|
|
249
|
+
status: InstallationStatusEnum.IN_PROGRESS,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const installationStatusPing = setInterval(
|
|
253
|
+
() => publishInstallationStatus(installationStatusPing),
|
|
254
|
+
deviceAgent.getInstallationStatusInterval(),
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
// Install the app with the given url
|
|
258
|
+
await (async () => {
|
|
259
|
+
try {
|
|
260
|
+
await installApp(actionPayload);
|
|
261
|
+
deviceAgent.setInstallationStatus({
|
|
262
|
+
status: InstallationStatusEnum.SUCCESS,
|
|
263
|
+
});
|
|
264
|
+
} catch (e) {
|
|
265
|
+
const reason: string = e.message;
|
|
266
|
+
deviceAgent.setInstallationStatus({
|
|
267
|
+
status: InstallationStatusEnum.FAILURE,
|
|
268
|
+
reason,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
})();
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
publishDeviceRequest(actionPayload);
|
|
275
|
+
break;
|
|
276
|
+
case 'start':
|
|
277
|
+
startApp({ projectId: actionPayload.projectId });
|
|
278
|
+
break;
|
|
279
|
+
case 'stop':
|
|
280
|
+
stopApp({ projectId: actionPayload.projectId });
|
|
281
|
+
break;
|
|
282
|
+
case 'restart':
|
|
283
|
+
restartApp({ projectId: actionPayload.projectId });
|
|
284
|
+
break;
|
|
285
|
+
/**
|
|
286
|
+
* Allow/disallow publishing on this device. By default, (publishable = false)
|
|
287
|
+
*/
|
|
288
|
+
case 'publishable':
|
|
289
|
+
/**
|
|
290
|
+
{
|
|
291
|
+
"action": "publishable",
|
|
292
|
+
"publishable": true | false
|
|
293
|
+
}
|
|
294
|
+
*/
|
|
295
|
+
deviceAgent.setPublishable(actionPayload);
|
|
296
|
+
deviceAgent.restartPublishableTimeout();
|
|
297
|
+
break;
|
|
298
|
+
default:
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
deviceAgent.device.on('connect', function () {
|
|
105
304
|
deviceAgent.publishMessage('connection', deviceAgent.getClientId());
|
|
106
305
|
console.log('Device Agent has connected to the cloud');
|
|
107
306
|
});
|
|
108
307
|
|
|
109
|
-
deviceAgent.device.on('disconnect', function() {
|
|
308
|
+
deviceAgent.device.on('disconnect', function () {
|
|
110
309
|
console.log('Device Agent has been disconnected from the cloud');
|
|
111
310
|
});
|
|
112
311
|
|
|
113
|
-
deviceAgent.device.on('message', function(topic, payload) {
|
|
114
|
-
//
|
|
115
|
-
|
|
312
|
+
deviceAgent.device.on('message', function (topic, payload) {
|
|
313
|
+
// ToDo: insert valdiation here for incoming messages. Maybe we will use a JSON schema for the message structure.
|
|
314
|
+
try {
|
|
315
|
+
handleMessageTopic({ topic, payload: JSON.parse(payload) });
|
|
316
|
+
} catch (error) {
|
|
317
|
+
console.error(error);
|
|
318
|
+
}
|
|
116
319
|
});
|
|
117
320
|
}
|
package/src/docker/docker-cmd.ts
CHANGED
package/src/environment.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { platform } from 'os';
|
|
|
2
2
|
|
|
3
3
|
export const ALWAYSAI_OS_PLATFORM = parseOsPlatform(process.env.ALWAYSAI_OS_PLATFORM);
|
|
4
4
|
export const ALWAYSAI_SHOW_HIDDEN = parseBoolean(process.env.ALWAYSAI_SHOW_HIDDEN);
|
|
5
|
+
export const ALWAYSAI_DEVICE_AGENT_MODE = process.env.ALWAYSAI_DEVICE_AGENT_MODE;
|
|
6
|
+
export const ALWAYSAI_LOG_LEVEL = process.env.AAI_LOG_LEVEL;
|
|
5
7
|
|
|
6
8
|
function parseOsPlatform(str: string | undefined): NodeJS.Platform {
|
|
7
9
|
switch (str) {
|
package/src/index.ts
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/*
|
|
4
|
+
Though this file is not executable, the above "shebang" line is necessary as an
|
|
5
|
+
indicator to npm that this file is a Node.js script, not a shell script e.g.
|
|
6
|
+
*/
|
|
6
7
|
|
|
7
8
|
import { runCliAndExit } from '@alwaysai/alwayscli';
|
|
8
9
|
import { root } from './root';
|
|
9
|
-
import { runWebInterface } from './web/web-interface';
|
|
10
10
|
import { runDeviceAgentCloudInterface } from './cloud-connection/device-agent-cloud-connection';
|
|
11
|
+
import { AgentConfigFile } from './infrastructure/agent-config';
|
|
12
|
+
import { ALWAYSAI_DEVICE_AGENT_MODE } from './environment';
|
|
11
13
|
|
|
12
14
|
if (module === require.main) {
|
|
13
15
|
console.log('Starting alwaysAI Device Agent');
|
|
16
|
+
if (!AgentConfigFile().exists()) {
|
|
17
|
+
AgentConfigFile().initialize();
|
|
18
|
+
}
|
|
14
19
|
|
|
15
|
-
if (
|
|
20
|
+
if (ALWAYSAI_DEVICE_AGENT_MODE === 'cloud') {
|
|
16
21
|
runDeviceAgentCloudInterface();
|
|
17
|
-
} else if (process.env.ALWAYSAI_DEVICE_AGENT_MODE === 'web') {
|
|
18
|
-
runWebInterface();
|
|
19
22
|
} else {
|
|
20
23
|
runCliAndExit(root, {});
|
|
21
24
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as tempy from 'tempy';
|
|
2
|
+
import { AgentConfigFile } from './agent-config';
|
|
3
|
+
|
|
4
|
+
const mockAgentModeGetter = jest.fn().mockReturnValue(undefined);
|
|
5
|
+
jest.mock('../environment', () => ({
|
|
6
|
+
get ALWAYSAI_DEVICE_AGENT_MODE() {
|
|
7
|
+
return mockAgentModeGetter();
|
|
8
|
+
},
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const configFile = AgentConfigFile(tempy.directory());
|
|
12
|
+
|
|
13
|
+
describe('Test Agent Config', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
configFile.remove();
|
|
16
|
+
configFile.initialize();
|
|
17
|
+
});
|
|
18
|
+
describe('Test applications', () => {
|
|
19
|
+
test('Commands with no apps', async () => {
|
|
20
|
+
const apps = await configFile.getApps();
|
|
21
|
+
expect(apps).toEqual([]);
|
|
22
|
+
const app = await configFile.getApp({ projectId: 'wrong-id' });
|
|
23
|
+
expect(app).toBeNull();
|
|
24
|
+
const present = await configFile.isAppPresent({ projectId: 'another-id' });
|
|
25
|
+
expect(present).toBeFalsy();
|
|
26
|
+
const ready = await configFile.isAppReady({ projectId: 'yet-another-id' });
|
|
27
|
+
expect(ready).toBeFalsy();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('Indicate app installation in progress', async () => {
|
|
31
|
+
const projectId = 'add-me';
|
|
32
|
+
const version = 'im-a-version';
|
|
33
|
+
|
|
34
|
+
await configFile.setAppInstalling({ projectId, version });
|
|
35
|
+
const apps = await configFile.getApps();
|
|
36
|
+
expect(apps).toEqual([
|
|
37
|
+
{
|
|
38
|
+
projectId,
|
|
39
|
+
version,
|
|
40
|
+
ready: false,
|
|
41
|
+
},
|
|
42
|
+
]);
|
|
43
|
+
const readyApps = await configFile.getReadyApps();
|
|
44
|
+
expect(readyApps).toEqual([]);
|
|
45
|
+
const app = await configFile.getApp({ projectId });
|
|
46
|
+
expect(app).toEqual({
|
|
47
|
+
projectId,
|
|
48
|
+
version,
|
|
49
|
+
ready: false,
|
|
50
|
+
});
|
|
51
|
+
const present = await configFile.isAppPresent({ projectId });
|
|
52
|
+
expect(present).toBeTruthy();
|
|
53
|
+
const ready = await configFile.isAppReady({ projectId });
|
|
54
|
+
expect(ready).toBeFalsy();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('Indicate app installation complete', async () => {
|
|
58
|
+
const projectId = 'add-me';
|
|
59
|
+
const version = 'im-a-version';
|
|
60
|
+
|
|
61
|
+
await configFile.setAppInstalling({ projectId, version });
|
|
62
|
+
await configFile.setAppInstalled({ projectId, version });
|
|
63
|
+
const apps = await configFile.getApps();
|
|
64
|
+
expect(apps).toEqual([
|
|
65
|
+
{
|
|
66
|
+
projectId,
|
|
67
|
+
version,
|
|
68
|
+
ready: true,
|
|
69
|
+
},
|
|
70
|
+
]);
|
|
71
|
+
const readyApps = await configFile.getReadyApps();
|
|
72
|
+
expect(readyApps).toEqual([
|
|
73
|
+
{
|
|
74
|
+
projectId,
|
|
75
|
+
version,
|
|
76
|
+
ready: true,
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
const app = await configFile.getApp({ projectId });
|
|
80
|
+
expect(app).toEqual({
|
|
81
|
+
projectId,
|
|
82
|
+
version,
|
|
83
|
+
ready: true,
|
|
84
|
+
});
|
|
85
|
+
const appVersion = await configFile.getAppVersion({ projectId });
|
|
86
|
+
expect(appVersion).toEqual(version);
|
|
87
|
+
const present = await configFile.isAppPresent({ projectId });
|
|
88
|
+
expect(present).toBeTruthy();
|
|
89
|
+
const ready = await configFile.isAppReady({ projectId });
|
|
90
|
+
expect(ready).toBeTruthy();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('Indicate app uninstalled', async () => {
|
|
94
|
+
const projectId = 'add-me';
|
|
95
|
+
const version = 'im-a-version';
|
|
96
|
+
|
|
97
|
+
await configFile.setAppInstalling({ projectId, version });
|
|
98
|
+
await configFile.setAppInstalled({ projectId, version });
|
|
99
|
+
await configFile.setAppUninstalled({ projectId });
|
|
100
|
+
const apps = await configFile.getApps();
|
|
101
|
+
expect(apps).toEqual([]);
|
|
102
|
+
const app = await configFile.getApp({ projectId: 'wrong-id' });
|
|
103
|
+
expect(app).toBeNull();
|
|
104
|
+
const present = await configFile.isAppPresent({ projectId: 'another-id' });
|
|
105
|
+
expect(present).toBeFalsy();
|
|
106
|
+
const ready = await configFile.isAppReady({ projectId: 'yet-another-id' });
|
|
107
|
+
expect(ready).toBeFalsy();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('Set and get backup', async () => {
|
|
111
|
+
const projectId = 'add-me';
|
|
112
|
+
const version = 'im-a-version';
|
|
113
|
+
|
|
114
|
+
await configFile.setAppInstalling({ projectId, version });
|
|
115
|
+
await configFile.setAppInstalled({ projectId, version });
|
|
116
|
+
const backup1 = await configFile.getAppBackup({ projectId });
|
|
117
|
+
expect(backup1).toBeNull();
|
|
118
|
+
await configFile.setAppBackup({ projectId });
|
|
119
|
+
const apps = await configFile.getApps();
|
|
120
|
+
expect(apps).toEqual([
|
|
121
|
+
{
|
|
122
|
+
projectId,
|
|
123
|
+
version,
|
|
124
|
+
ready: true,
|
|
125
|
+
backup: {
|
|
126
|
+
version,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
]);
|
|
130
|
+
const app = await configFile.getApp({ projectId });
|
|
131
|
+
expect(app).toEqual({
|
|
132
|
+
projectId,
|
|
133
|
+
version,
|
|
134
|
+
ready: true,
|
|
135
|
+
backup: {
|
|
136
|
+
version,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
const backup2 = await configFile.getAppBackup({ projectId });
|
|
140
|
+
expect(backup2).toEqual({ version });
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|