@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.
Files changed (191) hide show
  1. package/lib/application-control/backup.d.ts.map +1 -1
  2. package/lib/application-control/backup.js +10 -6
  3. package/lib/application-control/backup.js.map +1 -1
  4. package/lib/application-control/environment-variables.d.ts +9 -0
  5. package/lib/application-control/environment-variables.d.ts.map +1 -0
  6. package/lib/application-control/environment-variables.js +82 -0
  7. package/lib/application-control/environment-variables.js.map +1 -0
  8. package/lib/application-control/index.d.ts +9 -0
  9. package/lib/application-control/index.d.ts.map +1 -0
  10. package/lib/application-control/index.js +27 -0
  11. package/lib/application-control/index.js.map +1 -0
  12. package/lib/application-control/install.d.ts +8 -2
  13. package/lib/application-control/install.d.ts.map +1 -1
  14. package/lib/application-control/install.js +72 -42
  15. package/lib/application-control/install.js.map +1 -1
  16. package/lib/application-control/models.d.ts.map +1 -1
  17. package/lib/application-control/models.js +7 -17
  18. package/lib/application-control/models.js.map +1 -1
  19. package/lib/application-control/status.d.ts +3 -3
  20. package/lib/application-control/status.d.ts.map +1 -1
  21. package/lib/application-control/status.js +19 -20
  22. package/lib/application-control/status.js.map +1 -1
  23. package/lib/application-control/types.d.ts +0 -13
  24. package/lib/application-control/types.d.ts.map +1 -1
  25. package/lib/application-control/utils.d.ts +2 -9
  26. package/lib/application-control/utils.d.ts.map +1 -1
  27. package/lib/application-control/utils.js +13 -28
  28. package/lib/application-control/utils.js.map +1 -1
  29. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +15 -2
  30. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  31. package/lib/cloud-connection/device-agent-cloud-connection.js +200 -27
  32. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  33. package/lib/docker/docker-cmd.js +2 -2
  34. package/lib/docker/docker-cmd.js.map +1 -1
  35. package/lib/docker/docker-compose-cmd.js +2 -2
  36. package/lib/docker/docker-compose-cmd.js.map +1 -1
  37. package/lib/environment.d.ts +2 -0
  38. package/lib/environment.d.ts.map +1 -1
  39. package/lib/environment.js +3 -1
  40. package/lib/environment.js.map +1 -1
  41. package/lib/index.js +10 -8
  42. package/lib/index.js.map +1 -1
  43. package/lib/infrastructure/agent-config.d.ts +73 -0
  44. package/lib/infrastructure/agent-config.d.ts.map +1 -0
  45. package/lib/infrastructure/agent-config.js +186 -0
  46. package/lib/infrastructure/agent-config.js.map +1 -0
  47. package/lib/infrastructure/agent-config.test.d.ts +2 -0
  48. package/lib/infrastructure/agent-config.test.d.ts.map +1 -0
  49. package/lib/infrastructure/agent-config.test.js +135 -0
  50. package/lib/infrastructure/agent-config.test.js.map +1 -0
  51. package/lib/infrastructure/certificates-and-tokens.d.ts +6 -0
  52. package/lib/infrastructure/certificates-and-tokens.d.ts.map +1 -0
  53. package/lib/infrastructure/certificates-and-tokens.js +69 -0
  54. package/lib/infrastructure/certificates-and-tokens.js.map +1 -0
  55. package/lib/{util → infrastructure}/urls.d.ts +0 -0
  56. package/lib/infrastructure/urls.d.ts.map +1 -0
  57. package/lib/{util → infrastructure}/urls.js +3 -3
  58. package/lib/infrastructure/urls.js.map +1 -0
  59. package/lib/root.js +3 -3
  60. package/lib/root.js.map +1 -1
  61. package/lib/subcommands/app/app.d.ts +8 -1
  62. package/lib/subcommands/app/app.d.ts.map +1 -1
  63. package/lib/subcommands/app/app.js +58 -24
  64. package/lib/subcommands/app/app.js.map +1 -1
  65. package/lib/subcommands/app/index.d.ts.map +1 -1
  66. package/lib/subcommands/app/index.js +2 -0
  67. package/lib/subcommands/app/index.js.map +1 -1
  68. package/lib/subcommands/device/device.d.ts +6 -0
  69. package/lib/subcommands/device/device.d.ts.map +1 -0
  70. package/lib/subcommands/device/device.js +62 -0
  71. package/lib/subcommands/device/device.js.map +1 -0
  72. package/lib/subcommands/device/index.d.ts +2 -0
  73. package/lib/subcommands/device/index.d.ts.map +1 -0
  74. package/lib/subcommands/device/index.js +11 -0
  75. package/lib/subcommands/device/index.js.map +1 -0
  76. package/lib/subcommands/get-model-package.d.ts +5 -0
  77. package/lib/subcommands/get-model-package.d.ts.map +1 -0
  78. package/lib/subcommands/get-model-package.js +51 -0
  79. package/lib/subcommands/get-model-package.js.map +1 -0
  80. package/lib/subcommands/index.d.ts +8 -1
  81. package/lib/subcommands/index.d.ts.map +1 -1
  82. package/lib/subcommands/index.js +9 -3
  83. package/lib/subcommands/index.js.map +1 -1
  84. package/lib/subcommands/login.d.ts +3 -2
  85. package/lib/subcommands/login.d.ts.map +1 -1
  86. package/lib/subcommands/login.js +11 -4
  87. package/lib/subcommands/login.js.map +1 -1
  88. package/lib/util/copy-dir.js +3 -3
  89. package/lib/util/copy-dir.js.map +1 -1
  90. package/lib/util/directories.js +5 -5
  91. package/lib/util/directories.js.map +1 -1
  92. package/package.json +19 -14
  93. package/readme.md +176 -79
  94. package/src/application-control/backup.ts +10 -6
  95. package/src/application-control/environment-variables.ts +81 -0
  96. package/src/application-control/index.ts +40 -0
  97. package/src/application-control/install.ts +79 -55
  98. package/src/application-control/models.ts +12 -17
  99. package/src/application-control/status.ts +26 -24
  100. package/src/application-control/types.ts +0 -4
  101. package/src/application-control/utils.ts +10 -25
  102. package/src/cloud-connection/device-agent-cloud-connection.ts +243 -40
  103. package/src/docker/docker-cmd.ts +1 -1
  104. package/src/docker/docker-compose-cmd.ts +1 -1
  105. package/src/environment.ts +2 -0
  106. package/src/index.ts +10 -7
  107. package/src/infrastructure/agent-config.test.ts +143 -0
  108. package/src/infrastructure/agent-config.ts +217 -0
  109. package/src/infrastructure/certificates-and-tokens.ts +71 -0
  110. package/src/{util → infrastructure}/urls.ts +1 -1
  111. package/src/root.ts +3 -3
  112. package/src/subcommands/app/app.ts +57 -19
  113. package/src/subcommands/app/index.ts +4 -0
  114. package/src/subcommands/device/device.ts +63 -0
  115. package/src/subcommands/device/index.ts +8 -0
  116. package/src/subcommands/get-model-package.ts +60 -0
  117. package/src/subcommands/index.ts +9 -3
  118. package/src/subcommands/login.ts +11 -4
  119. package/src/util/copy-dir.ts +1 -1
  120. package/src/util/directories.ts +8 -8
  121. package/lib/constants.d.ts +0 -13
  122. package/lib/constants.d.ts.map +0 -1
  123. package/lib/constants.js +0 -18
  124. package/lib/constants.js.map +0 -1
  125. package/lib/subcommands/device-control.d.ts +0 -2
  126. package/lib/subcommands/device-control.d.ts.map +0 -1
  127. package/lib/subcommands/device-control.js +0 -19
  128. package/lib/subcommands/device-control.js.map +0 -1
  129. package/lib/util/spawner/gnu-spawner.d.ts +0 -9
  130. package/lib/util/spawner/gnu-spawner.d.ts.map +0 -1
  131. package/lib/util/spawner/gnu-spawner.js +0 -102
  132. package/lib/util/spawner/gnu-spawner.js.map +0 -1
  133. package/lib/util/spawner/js-spawner.d.ts +0 -5
  134. package/lib/util/spawner/js-spawner.d.ts.map +0 -1
  135. package/lib/util/spawner/js-spawner.js +0 -89
  136. package/lib/util/spawner/js-spawner.js.map +0 -1
  137. package/lib/util/spawner/types.d.ts +0 -28
  138. package/lib/util/spawner/types.d.ts.map +0 -1
  139. package/lib/util/spawner/types.js +0 -3
  140. package/lib/util/spawner/types.js.map +0 -1
  141. package/lib/util/spawner-base/index.d.ts +0 -17
  142. package/lib/util/spawner-base/index.d.ts.map +0 -1
  143. package/lib/util/spawner-base/index.js +0 -30
  144. package/lib/util/spawner-base/index.js.map +0 -1
  145. package/lib/util/spawner-base/run-foreground-sync.d.ts +0 -3
  146. package/lib/util/spawner-base/run-foreground-sync.d.ts.map +0 -1
  147. package/lib/util/spawner-base/run-foreground-sync.js +0 -18
  148. package/lib/util/spawner-base/run-foreground-sync.js.map +0 -1
  149. package/lib/util/spawner-base/run-foreground.d.ts +0 -3
  150. package/lib/util/spawner-base/run-foreground.d.ts.map +0 -1
  151. package/lib/util/spawner-base/run-foreground.js +0 -49
  152. package/lib/util/spawner-base/run-foreground.js.map +0 -1
  153. package/lib/util/spawner-base/run-streaming.d.ts +0 -4
  154. package/lib/util/spawner-base/run-streaming.d.ts.map +0 -1
  155. package/lib/util/spawner-base/run-streaming.js +0 -35
  156. package/lib/util/spawner-base/run-streaming.js.map +0 -1
  157. package/lib/util/spawner-base/run.d.ts +0 -4
  158. package/lib/util/spawner-base/run.d.ts.map +0 -1
  159. package/lib/util/spawner-base/run.js +0 -56
  160. package/lib/util/spawner-base/run.js.map +0 -1
  161. package/lib/util/urls.d.ts.map +0 -1
  162. package/lib/util/urls.js.map +0 -1
  163. package/lib/web/index.html +0 -229
  164. package/lib/web/static/Karla.css +0 -18
  165. package/lib/web/static/bootstrap-4.3.1.min.css +0 -7
  166. package/lib/web/static/bootstrap-4.3.1.min.js +0 -7
  167. package/lib/web/static/favicon.ico +0 -0
  168. package/lib/web/static/jquery-3.3.1.slim.min.js +0 -2
  169. package/lib/web/static/popper-1.14.7.min.js +0 -5
  170. package/lib/web/web-interface.d.ts +0 -2
  171. package/lib/web/web-interface.d.ts.map +0 -1
  172. package/lib/web/web-interface.js +0 -75
  173. package/lib/web/web-interface.js.map +0 -1
  174. package/src/constants.ts +0 -22
  175. package/src/subcommands/device-control.ts +0 -16
  176. package/src/util/spawner/gnu-spawner.ts +0 -114
  177. package/src/util/spawner/js-spawner.ts +0 -110
  178. package/src/util/spawner/types.ts +0 -28
  179. package/src/util/spawner-base/index.ts +0 -28
  180. package/src/util/spawner-base/run-foreground-sync.ts +0 -16
  181. package/src/util/spawner-base/run-foreground.ts +0 -49
  182. package/src/util/spawner-base/run-streaming.ts +0 -40
  183. package/src/util/spawner-base/run.ts +0 -60
  184. package/src/web/index.html +0 -229
  185. package/src/web/static/Karla.css +0 -18
  186. package/src/web/static/bootstrap-4.3.1.min.css +0 -7
  187. package/src/web/static/bootstrap-4.3.1.min.js +0 -7
  188. package/src/web/static/favicon.ico +0 -0
  189. package/src/web/static/jquery-3.3.1.slim.min.js +0 -2
  190. package/src/web/static/popper-1.14.7.min.js +0 -5
  191. 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 '../util/urls';
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 { getAppStatus } from '../application-control/status';
9
- import { getInstalledApps } from '../application-control/install';
10
- import { AppStatus } from '../application-control/types';
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 publishInterval = 1000;
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
- // TODO: subscribe to topics here
30
- this.device.subscribe('command');
31
- this.publishInterval = this.publishInterval;
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 getClientId() {
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 getAppStateMessage() {
52
- const appStateMessage: AppStatus[] = [];
53
- const installedApps = await getInstalledApps();
54
- for (const app of installedApps) {
55
- const projectId = app['projectId'];
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
- const topic = `device/${deviceAgent.getClientId()}/topic/application-management`;
67
- const appStateMessage = await getAppStateMessage();
68
- const appStatePackage = {
69
- timestamp: new Date().toUTCString(),
70
- deviceId: deviceAgent.getClientId(),
71
- topic,
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
- freeMemoryPercentage: memUtil,
182
+ usedMemoryPercentage: memUtil,
87
183
  },
88
184
  };
89
185
  return deviceStatsMessage;
90
186
  }
91
187
 
92
- const publishDeviceStats = setInterval(async function() {
93
- const topic = `device/${deviceAgent.getClientId()}/topic/device-management`;
94
- const deviceStatsMessage = await getDeviceStatsMessage();
95
- const deviceStatsPackage = {
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(topic, JSON.stringify({ deviceStatsPackage }));
102
- }, deviceAgent.getPublishInterval());
206
+ deviceAgent.publishMessage(
207
+ topic,
208
+ JSON.stringify({ device_request: deviceRequestPackage }),
209
+ );
210
+ };
103
211
 
104
- deviceAgent.device.on('connect', function() {
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
- // TODO: parse/determine action based on topic/payload here
115
- console.log('message', topic, payload.toString());
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
  }
@@ -1,4 +1,4 @@
1
- import { JsSpawner } from '../util/spawner/js-spawner';
1
+ import { JsSpawner } from 'alwaysai/lib/util';
2
2
 
3
3
  export async function runDockerLogin(props: { token: string }) {
4
4
  const { token } = props;
@@ -1,4 +1,4 @@
1
- import { JsSpawner } from '../util/spawner/js-spawner';
1
+ import { JsSpawner } from 'alwaysai/lib/util';
2
2
 
3
3
  export async function runDockerComposeCmd(props: { args: string[]; dir: string }) {
4
4
  const { args, dir } = props;
@@ -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
- // This file is the entry point for when this package is run as a CLI. Though
4
- // 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.
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 (process.env.ALWAYSAI_DEVICE_AGENT_MODE === 'cloud') {
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
+ });