@alwaysai/device-agent 0.0.3 → 0.0.4

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 (75) hide show
  1. package/lib/application-control/backup.d.ts +8 -0
  2. package/lib/application-control/backup.d.ts.map +1 -0
  3. package/lib/application-control/backup.js +30 -0
  4. package/lib/application-control/backup.js.map +1 -0
  5. package/lib/application-control/install.d.ts +10 -0
  6. package/lib/application-control/install.d.ts.map +1 -0
  7. package/lib/application-control/install.js +87 -0
  8. package/lib/application-control/install.js.map +1 -0
  9. package/lib/application-control/models.d.ts +8 -0
  10. package/lib/application-control/models.d.ts.map +1 -1
  11. package/lib/application-control/models.js +45 -2
  12. package/lib/application-control/models.js.map +1 -1
  13. package/lib/application-control/{application-control.d.ts → status.d.ts} +3 -23
  14. package/lib/application-control/status.d.ts.map +1 -0
  15. package/lib/application-control/{application-control.js → status.js} +6 -101
  16. package/lib/application-control/status.js.map +1 -0
  17. package/lib/application-control/types.d.ts +18 -0
  18. package/lib/application-control/types.d.ts.map +1 -0
  19. package/lib/application-control/types.js +3 -0
  20. package/lib/application-control/types.js.map +1 -0
  21. package/lib/application-control/utils.d.ts.map +1 -1
  22. package/lib/application-control/utils.js +3 -3
  23. package/lib/application-control/utils.js.map +1 -1
  24. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +2 -0
  25. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  26. package/lib/cloud-connection/device-agent-cloud-connection.js +59 -2
  27. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  28. package/lib/constants.d.ts +2 -6
  29. package/lib/constants.d.ts.map +1 -1
  30. package/lib/constants.js +3 -9
  31. package/lib/constants.js.map +1 -1
  32. package/lib/subcommands/app/app.d.ts +24 -14
  33. package/lib/subcommands/app/app.d.ts.map +1 -1
  34. package/lib/subcommands/app/app.js +89 -68
  35. package/lib/subcommands/app/app.js.map +1 -1
  36. package/lib/subcommands/app/index.d.ts.map +1 -1
  37. package/lib/subcommands/app/index.js +4 -1
  38. package/lib/subcommands/app/index.js.map +1 -1
  39. package/lib/subcommands/index.d.ts.map +1 -1
  40. package/lib/subcommands/index.js +1 -7
  41. package/lib/subcommands/index.js.map +1 -1
  42. package/lib/util/directories.d.ts +1 -1
  43. package/lib/util/directories.d.ts.map +1 -1
  44. package/lib/util/directories.js +8 -13
  45. package/lib/util/directories.js.map +1 -1
  46. package/lib/util/get-device-id.d.ts +2 -0
  47. package/lib/util/get-device-id.d.ts.map +1 -0
  48. package/lib/util/get-device-id.js +24 -0
  49. package/lib/util/get-device-id.js.map +1 -0
  50. package/lib/web/web-interface.d.ts.map +1 -1
  51. package/lib/web/web-interface.js +8 -7
  52. package/lib/web/web-interface.js.map +1 -1
  53. package/package.json +2 -2
  54. package/readme.md +15 -8
  55. package/src/application-control/backup.ts +28 -0
  56. package/src/application-control/install.ts +102 -0
  57. package/src/application-control/models.ts +46 -1
  58. package/src/application-control/{application-control.ts → status.ts} +5 -124
  59. package/src/application-control/types.ts +5 -0
  60. package/src/application-control/utils.ts +3 -3
  61. package/src/cloud-connection/device-agent-cloud-connection.ts +66 -2
  62. package/src/constants.ts +2 -12
  63. package/src/subcommands/app/app.ts +98 -63
  64. package/src/subcommands/app/index.ts +7 -1
  65. package/src/subcommands/index.ts +1 -7
  66. package/src/util/directories.ts +10 -15
  67. package/src/util/get-device-id.ts +22 -0
  68. package/src/web/web-interface.ts +2 -6
  69. package/lib/application-control/application-control.d.ts.map +0 -1
  70. package/lib/application-control/application-control.js.map +0 -1
  71. package/lib/subcommands/test-app.d.ts +0 -2
  72. package/lib/subcommands/test-app.d.ts.map +0 -1
  73. package/lib/subcommands/test-app.js +0 -29
  74. package/lib/subcommands/test-app.js.map +0 -1
  75. package/src/subcommands/test-app.ts +0 -30
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDeviceId = void 0;
4
+ const directories_1 = require("../util/directories");
5
+ const alwayscli_1 = require("@alwaysai/alwayscli");
6
+ const config_nodejs_1 = require("@alwaysai/config-nodejs");
7
+ const t = require("io-ts");
8
+ function getDeviceId() {
9
+ const path = (0, directories_1.getCredentialsFilePath)();
10
+ const codec = t.type({
11
+ deviceId: t.union([t.string, t.undefined]),
12
+ });
13
+ const credentialsJsonFile = (0, config_nodejs_1.ConfigFile)({
14
+ path,
15
+ codec,
16
+ });
17
+ const config = credentialsJsonFile.readIfExists();
18
+ if (!config || !config.deviceId) {
19
+ throw new alwayscli_1.CliTerseError('Invalid device credentials! Please ensure you are using the device agent on a valid device.');
20
+ }
21
+ return config.deviceId;
22
+ }
23
+ exports.getDeviceId = getDeviceId;
24
+ //# sourceMappingURL=get-device-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-device-id.js","sourceRoot":"","sources":["../../src/util/get-device-id.ts"],"names":[],"mappings":";;;AAAA,qDAA6D;AAC7D,mDAAoD;AACpD,2DAAqD;AACrD,2BAA2B;AAE3B,SAAgB,WAAW;IACzB,MAAM,IAAI,GAAG,IAAA,oCAAsB,GAAE,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;KAC3C,CAAC,CAAC;IACH,MAAM,mBAAmB,GAAG,IAAA,0BAAU,EAAC;QACrC,IAAI;QACJ,KAAK;KACN,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,mBAAmB,CAAC,YAAY,EAAE,CAAC;IAClD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;QAC/B,MAAM,IAAI,yBAAa,CACrB,6FAA6F,CAC9F,CAAC;KACH;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC;AACzB,CAAC;AAhBD,kCAgBC"}
@@ -1 +1 @@
1
- {"version":3,"file":"web-interface.d.ts","sourceRoot":"","sources":["../../src/web/web-interface.ts"],"names":[],"mappings":"AAgBA,wBAAsB,eAAe,kBA8CpC"}
1
+ {"version":3,"file":"web-interface.d.ts","sourceRoot":"","sources":["../../src/web/web-interface.ts"],"names":[],"mappings":"AAYA,wBAAsB,eAAe,kBA8CpC"}
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runWebInterface = void 0;
4
- const application_control_1 = require("../application-control/application-control");
4
+ const install_1 = require("../application-control/install");
5
+ const status_1 = require("../application-control/status");
5
6
  const device_control_1 = require("../device-control/device-control");
6
7
  const express = require('express');
7
8
  const app = express();
@@ -31,14 +32,14 @@ async function runWebInterface() {
31
32
  socket.emit('apps-info-rsp', appsInfoRsp);
32
33
  });
33
34
  socket.on('start-app', async (msg) => {
34
- (0, application_control_1.startApp)({ projectId: msg.projectId });
35
+ (0, status_1.startApp)({ projectId: msg.projectId });
35
36
  });
36
37
  socket.on('stop-app', async (msg) => {
37
- (0, application_control_1.stopApp)({ projectId: msg.projectId });
38
+ (0, status_1.stopApp)({ projectId: msg.projectId });
38
39
  });
39
40
  socket.on('restart-app', async (msg) => {
40
- await (0, application_control_1.stopApp)({ projectId: msg.projectId });
41
- setTimeout(() => (0, application_control_1.startApp)({ projectId: msg.projectId }), 2000);
41
+ await (0, status_1.stopApp)({ projectId: msg.projectId });
42
+ setTimeout(() => (0, status_1.startApp)({ projectId: msg.projectId }), 2000);
42
43
  });
43
44
  const appsInfoRsp = await buildAppsInfoRsp();
44
45
  socket.emit('apps-info-rsp', appsInfoRsp);
@@ -59,10 +60,10 @@ async function buildDeviceInfoRsp() {
59
60
  }
60
61
  async function buildAppsInfoRsp() {
61
62
  const apps = [];
62
- const installedApps = await (0, application_control_1.getInstalledApps)();
63
+ const installedApps = await (0, install_1.getInstalledApps)();
63
64
  console.log(installedApps);
64
65
  for (const appDetails of installedApps) {
65
- const app = await (0, application_control_1.getAppStatus)({ projectId: appDetails.projectId });
66
+ const app = await (0, status_1.getAppStatus)({ projectId: appDetails.projectId });
66
67
  console.log(app);
67
68
  // FIXME: only reads first service
68
69
  apps.push({ projectId: appDetails.projectId, status: app.services[0].state });
@@ -1 +1 @@
1
- {"version":3,"file":"web-interface.js","sourceRoot":"","sources":["../../src/web/web-interface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web-interface.js","sourceRoot":"","sources":["../../src/web/web-interface.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alwaysai/device-agent",
3
3
  "description": "The alwaysAI Device Agent",
4
- "version": "0.0.3",
4
+ "version": "0.0.4",
5
5
  "main": "lib/exports.js",
6
6
  "types": "lib/exports.d.ts",
7
7
  "bin": {
@@ -34,7 +34,7 @@
34
34
  "@types/signal-exit": "3.0.1",
35
35
  "@types/tar": "6.1.1",
36
36
  "aws-iot-device-sdk": "2.2.12",
37
- "alwaysai": "1.5.1",
37
+ "alwaysai": "1.6.0",
38
38
  "docker-compose": "0.23.17",
39
39
  "express": "4.17.3",
40
40
  "fp-ts": "2.11.5",
package/readme.md CHANGED
@@ -47,14 +47,21 @@ Usage: aai-agent <subcommand> ...
47
47
 
48
48
  Subcommands:
49
49
 
50
- get-device-info : Get device info
51
- install-test-app : Install an empty test application
52
- get-installed-apps : List all installed apps
53
- install-app : Install an alwaysAI app from a project
54
- get-app-status : Get the status of an installed alwaysAI app
55
- start-app : Start an installed alwaysAI app
56
- stop-app : Stop a running alwaysAI app
57
- uninstall-app : Remove an alwaysAI app
50
+ login : Login to alwaysAI (this is meant for scripted environments)
51
+ app list : List all installed apps
52
+ app list-releases : List all releases for a given app
53
+ app list-latest-release : List the latest release hash for a given app
54
+ app install : Install an alwaysAI app from a project
55
+ app status : Get the status of an installed alwaysAI app
56
+ app start : Start an installed alwaysAI app
57
+ app logs : Get logs for an application
58
+ app stop : Stop a running alwaysAI app
59
+ app uninstall : Remove an alwaysAI app
60
+ app rollback : Rollback an alwaysAI app to the previous version
61
+ app add-model : Add a model to an alwaysAI app
62
+ app remove-model : Remove a model from an alwaysAI app
63
+ app update-models : Update all models for an alwaysAI app
64
+ get-device-info : Get device info
58
65
  ```
59
66
 
60
67
  To install a test app, run:
@@ -0,0 +1,28 @@
1
+ import * as rimraf from 'rimraf';
2
+ import * as fs from 'fs';
3
+
4
+ import { copyDir } from '../util/copy-dir';
5
+ import { buildApp, getAppDir } from './utils';
6
+
7
+ export const BACKUP_EXT = '.bak';
8
+
9
+ export async function createAppBackup(props: { projectId: string }) {
10
+ const { projectId } = props;
11
+ const appDir = getAppDir(projectId);
12
+ const backupAppDir = `${appDir}${BACKUP_EXT}`;
13
+ await copyDir({ srcPath: appDir, destPath: backupAppDir });
14
+ console.log(`Backed up app ${projectId} to ${backupAppDir}`);
15
+ }
16
+
17
+ export async function rollbackApp(props: { projectId: string }) {
18
+ const { projectId } = props;
19
+ const appDir = getAppDir(projectId);
20
+ const backupAppDir = `${appDir}${BACKUP_EXT}`;
21
+ if (!fs.existsSync(backupAppDir)) {
22
+ throw new Error(`Backup doesn't exist for ${projectId}`);
23
+ }
24
+ rimraf.sync(appDir);
25
+ await copyDir({ srcPath: `${appDir}${BACKUP_EXT}`, destPath: appDir });
26
+ await buildApp({ appDir });
27
+ console.log(`Rolled back app ${projectId} to previous version`);
28
+ }
@@ -0,0 +1,102 @@
1
+ import * as rimraf from 'rimraf';
2
+ import * as fs from 'fs';
3
+ import { join } from 'path';
4
+
5
+ import { runCliCmd } from '../util/run-cli-cmd';
6
+ import { JsSpawner } from '../util/spawner/js-spawner';
7
+ import {
8
+ APP_ROOT,
9
+ buildApp,
10
+ getAppDir,
11
+ getAppVersion,
12
+ isAppInstalled,
13
+ setAppVersion,
14
+ } from './utils';
15
+ import { AppDetails } from './types';
16
+ import { BACKUP_EXT, createAppBackup } from './backup';
17
+ import { stopApp } from './status';
18
+
19
+ export async function getInstalledApps(): Promise<AppDetails[]> {
20
+ if (!fs.existsSync(APP_ROOT)) {
21
+ return [];
22
+ }
23
+
24
+ const projectIds = fs.readdirSync(APP_ROOT).filter(file => {
25
+ const isDir = fs.statSync(`${APP_ROOT}/${file}`).isDirectory();
26
+ const isBak = `${APP_ROOT}/${file}`.includes(BACKUP_EXT);
27
+ return isDir && !isBak;
28
+ });
29
+
30
+ const appDetails: AppDetails[] = [];
31
+ for (const projectId of projectIds) {
32
+ const appDir = getAppDir(projectId);
33
+ const version = await getAppVersion({ appDir });
34
+ appDetails.push({ projectId, version });
35
+ }
36
+ return appDetails;
37
+ }
38
+
39
+ export async function installApp(props: {
40
+ projectId: string;
41
+ releaseHash: string;
42
+ }): Promise<void> {
43
+ const { projectId, releaseHash } = props;
44
+ console.log(`Installing ${projectId}`);
45
+ const appDir = getAppDir(projectId);
46
+ const TEMP_DIR = join(APP_ROOT, 'temp');
47
+ const spawner = JsSpawner();
48
+ await spawner.mkdirp(TEMP_DIR);
49
+ // TODO Check valid projectId
50
+ // Check if app is installed
51
+ if (await isAppInstalled({ appDir })) {
52
+ console.log('Application is already installed, updating');
53
+ await createAppBackup({ projectId });
54
+ await spawner.rimraf(appDir);
55
+ }
56
+ // Create app directory
57
+ await spawner.mkdirp(appDir);
58
+
59
+ // download the application
60
+ await runCliCmd({
61
+ cmd: [
62
+ 'release',
63
+ 'pull',
64
+ '--yes',
65
+ '--project',
66
+ projectId,
67
+ '--releaseHash',
68
+ releaseHash,
69
+ ],
70
+ cwd: TEMP_DIR,
71
+ });
72
+
73
+ // Unpack app package and move to install dir
74
+ await spawner.untar(fs.createReadStream(join(TEMP_DIR, `${releaseHash}.tgz`)), appDir);
75
+ console.log(`Unpacked application to ${appDir}`);
76
+
77
+ await setAppVersion({ appDir, version: releaseHash });
78
+
79
+ await buildApp({ appDir });
80
+
81
+ await spawner.rimraf(TEMP_DIR);
82
+
83
+ console.log(`Installed ${projectId} to ${appDir}`);
84
+ }
85
+
86
+ export async function uninstallApp(props: { projectId: string }): Promise<void> {
87
+ const { projectId } = props;
88
+ const appDir = getAppDir(projectId);
89
+ if (!(await isAppInstalled({ appDir }))) {
90
+ console.log(`Application ${projectId} not installed`);
91
+ return;
92
+ }
93
+ try {
94
+ await stopApp({ projectId });
95
+ } catch {
96
+ console.log('Failed to stop app, may be left running...');
97
+ }
98
+ // Delete application directory and backup
99
+ rimraf.sync(appDir);
100
+ rimraf.sync(`${appDir}${BACKUP_EXT}`);
101
+ console.log('Uninstalled', projectId);
102
+ }
@@ -1,6 +1,32 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+
1
4
  import { runCliCmd } from '../util/run-cli-cmd';
5
+ import { JsSpawner } from '../util/spawner/js-spawner';
6
+ import { ModelDetails } from './types';
2
7
  import { buildApp, getAppDir, isAppInstalled } from './utils';
3
8
 
9
+ export async function getAppModels(props: { projectId: string }) {
10
+ const { projectId } = props;
11
+ const appDir = getAppDir(projectId);
12
+ if (!(await isAppInstalled({ appDir }))) {
13
+ throw new Error('Application is not installed');
14
+ }
15
+ const appCfgPath = join(appDir, 'alwaysai.app.json');
16
+ if (!existsSync(appCfgPath)) {
17
+ throw new Error('Application config not found!');
18
+ }
19
+ const appCfg = JSON.parse(await JsSpawner().readFile(appCfgPath));
20
+ const modelDetails: ModelDetails[] = [];
21
+ if (!('models' in appCfg)) {
22
+ return modelDetails;
23
+ }
24
+ for (const model in appCfg['models']) {
25
+ modelDetails.push({ modelId: model, version: appCfg['models'][model] });
26
+ }
27
+ return modelDetails;
28
+ }
29
+
4
30
  export async function addModel(props: { projectId: string; modelId: string }) {
5
31
  const { projectId, modelId } = props;
6
32
  const appDir = getAppDir(projectId);
@@ -21,11 +47,30 @@ export async function removeModel(props: { projectId: string; modelId: string })
21
47
  throw new Error('Application is not installed');
22
48
  }
23
49
  await runCliCmd({
24
- cmd: ['app', 'models', 'remove', modelId],
50
+ cmd: ['app', 'models', 'remove', modelId, '--purge'],
25
51
  cwd: appDir,
26
52
  });
27
53
  }
28
54
 
55
+ export async function replaceModels(props: { projectId: string; modelIds: string[] }) {
56
+ const { projectId, modelIds } = props;
57
+ const appDir = getAppDir(projectId);
58
+ if (!(await isAppInstalled({ appDir }))) {
59
+ throw new Error('Application is not installed');
60
+ }
61
+ await runCliCmd({
62
+ cmd: ['app', 'models', 'remove-all', '--purge'],
63
+ cwd: appDir,
64
+ });
65
+ for (const modelId of modelIds) {
66
+ await runCliCmd({
67
+ cmd: ['app', 'models', 'add', modelId],
68
+ cwd: appDir,
69
+ });
70
+ }
71
+ await buildApp({ appDir });
72
+ }
73
+
29
74
  export async function updateModels(props: { projectId: string }) {
30
75
  const { projectId } = props;
31
76
  const appDir = getAppDir(projectId);
@@ -1,66 +1,10 @@
1
1
  import compose from 'docker-compose';
2
- import * as rimraf from 'rimraf';
3
- import * as fs from 'fs';
4
2
  import { fetchAppReleaseHistory } from 'alwaysai';
5
- import { join } from 'path';
6
3
 
7
- import { runCliCmd } from '../util/run-cli-cmd';
8
4
  import { runDockerLogin } from '../docker/docker-cmd';
9
5
  import { JsSpawner } from '../util/spawner/js-spawner';
10
- import { copyDir } from '../util/copy-dir';
11
- import {
12
- APP_ROOT,
13
- buildApp,
14
- getAppDir,
15
- getAppVersion,
16
- isAppInstalled,
17
- setAppVersion,
18
- } from './utils';
19
-
20
- const BACKUP_EXT = '.bak';
21
-
22
- export type AppDetails = { projectId: string; version: string };
23
-
24
- export async function getInstalledApps(): Promise<AppDetails[]> {
25
- if (!fs.existsSync(APP_ROOT)) {
26
- return [];
27
- }
28
-
29
- const projectIds = fs.readdirSync(APP_ROOT).filter(file => {
30
- const isDir = fs.statSync(`${APP_ROOT}/${file}`).isDirectory();
31
- const isBak = `${APP_ROOT}/${file}`.includes(BACKUP_EXT);
32
- return isDir && !isBak;
33
- });
34
-
35
- const appDetails: AppDetails[] = [];
36
- for (const projectId of projectIds) {
37
- const appDir = getAppDir(projectId);
38
- const version = await getAppVersion({ appDir });
39
- appDetails.push({ projectId, version });
40
- }
41
- return appDetails;
42
- }
43
-
44
- async function createAppBackup(props: { projectId: string }) {
45
- const { projectId } = props;
46
- const appDir = getAppDir(projectId);
47
- const backupAppDir = `${appDir}${BACKUP_EXT}`;
48
- await copyDir({ srcPath: appDir, destPath: backupAppDir });
49
- console.log(`Backed up app ${projectId} to ${backupAppDir}`);
50
- }
51
-
52
- export async function rollbackApp(props: { projectId: string }) {
53
- const { projectId } = props;
54
- const appDir = getAppDir(projectId);
55
- const backupAppDir = `${appDir}${BACKUP_EXT}`;
56
- if (!fs.existsSync(backupAppDir)) {
57
- throw new Error(`Backup doesn't exist for ${projectId}`);
58
- }
59
- rimraf.sync(appDir);
60
- await copyDir({ srcPath: `${appDir}${BACKUP_EXT}`, destPath: appDir });
61
- await buildApp({ appDir });
62
- console.log(`Rolled back app ${projectId} to previous version`);
63
- }
6
+ import { getAppDir, getAppVersion, isAppInstalled } from './utils';
7
+ import { AppStatus, ServiceState, ServiceStatus } from './types';
64
8
 
65
9
  export async function listAppReleases(props: { projectId: string }) {
66
10
  const { projectId } = props;
@@ -77,57 +21,6 @@ export async function listAppLatestRelease(props: { projectId: string }) {
77
21
  return undefined;
78
22
  }
79
23
 
80
- export async function installApp(props: {
81
- projectId: string;
82
- releaseHash: string;
83
- }): Promise<void> {
84
- const { projectId, releaseHash } = props;
85
- console.log(`Installing ${projectId}`);
86
- const appDir = getAppDir(projectId);
87
- const TEMP_DIR = join(APP_ROOT, 'temp');
88
- const spawner = JsSpawner();
89
- await spawner.mkdirp(TEMP_DIR);
90
- // TODO Check valid projectId
91
- // Check if app is installed
92
- if (await isAppInstalled({ appDir })) {
93
- console.log('Application is already installed, updating');
94
- await createAppBackup({ projectId });
95
- await spawner.rimraf(appDir);
96
- }
97
- // Create app directory
98
- await spawner.mkdirp(appDir);
99
-
100
- // download the application
101
- await runCliCmd({
102
- cmd: [
103
- 'release',
104
- 'pull',
105
- '--yes',
106
- '--project',
107
- projectId,
108
- '--releaseHash',
109
- releaseHash,
110
- ],
111
- cwd: TEMP_DIR,
112
- });
113
-
114
- // Unpack app package and move to install dir
115
- await spawner.untar(fs.createReadStream(join(TEMP_DIR, `${releaseHash}.tgz`)), appDir);
116
- console.log(`Unpacked application to ${appDir}`);
117
-
118
- await setAppVersion({ appDir, version: releaseHash });
119
-
120
- await buildApp({ appDir });
121
-
122
- await spawner.rimraf(TEMP_DIR);
123
-
124
- console.log(`Installed ${projectId} to ${appDir}`);
125
- }
126
-
127
- export type ServiceState = 'Stopped' | 'Up' | 'Restarting';
128
- export type ServiceStatus = { name: string; state: ServiceState };
129
- export type AppStatus = { appDetails: AppDetails; services: ServiceStatus[] };
130
-
131
24
  export async function getAppStatus(props: { projectId: string }): Promise<AppStatus> {
132
25
  const { projectId } = props;
133
26
  const appDir = getAppDir(projectId);
@@ -254,20 +147,8 @@ export async function stopApp(props: { projectId: string }): Promise<void> {
254
147
  console.log('Stopped', projectId);
255
148
  }
256
149
 
257
- export async function uninstallApp(props: { projectId: string }): Promise<void> {
150
+ export async function restartApp(props: { projectId: string }): Promise<void> {
258
151
  const { projectId } = props;
259
- const appDir = getAppDir(projectId);
260
- if (!(await isAppInstalled({ appDir }))) {
261
- console.log(`Application ${projectId} not installed`);
262
- return;
263
- }
264
- try {
265
- await stopApp({ projectId });
266
- } catch {
267
- console.log('Failed to stop app, may be left running...');
268
- }
269
- // Delete application directory and backup
270
- rimraf.sync(appDir);
271
- rimraf.sync(`${appDir}${BACKUP_EXT}`);
272
- console.log('Uninstalled', projectId);
152
+ await stopApp({ projectId });
153
+ await startApp({ projectId });
273
154
  }
@@ -0,0 +1,5 @@
1
+ export type AppDetails = { projectId: string; version: string };
2
+ export type ServiceState = 'Stopped' | 'Up' | 'Restarting';
3
+ export type ServiceStatus = { name: string; state: ServiceState };
4
+ export type AppStatus = { appDetails: AppDetails; services: ServiceStatus[] };
5
+ export type ModelDetails = { modelId: string; version: number };
@@ -3,10 +3,10 @@ import * as path from 'path';
3
3
  import * as fs from 'fs';
4
4
 
5
5
  import { JsSpawner } from '../util/spawner/js-spawner';
6
- import { DOT_ALWAYSAI_DIR } from '../constants';
6
+ import { AAI_DIR } from 'alwaysai';
7
7
  import { runCliCmd } from '../util/run-cli-cmd';
8
8
 
9
- export const APP_ROOT = path.join(DOT_ALWAYSAI_DIR, 'applications');
9
+ export const APP_ROOT = path.join(AAI_DIR, 'applications');
10
10
  const RELEASE_FILENAME = 'alwaysai.release.json';
11
11
  const DOCKER_COMPOSE_FILENAME = 'docker-compose.yaml';
12
12
 
@@ -41,7 +41,7 @@ export async function getAppVersion(props: { appDir: string }) {
41
41
  export async function buildApp(props: { appDir: string }) {
42
42
  const { appDir } = props;
43
43
  await runCliCmd({
44
- cmd: ['app', 'configure', '--yes', '--protocol', 'docker:'],
44
+ cmd: ['app', 'configure', '--yes', '--protocol', 'docker:', '--skip-model-sync'],
45
45
  cwd: appDir,
46
46
  });
47
47
  await runCliCmd({ cmd: ['app', 'install', '--yes', '--clean', '--pull'], cwd: appDir });
@@ -5,11 +5,17 @@ import {
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';
11
+ import { getCpuUtil, getDiskUtil, getMemUtil } from '../device-control/device-control';
12
+ import { getDeviceId } from '../util/get-device-id';
8
13
 
9
14
  export class DeviceAgentCloudConnection {
10
15
  public device = awsIot.device;
11
- private clientId = 'DEVICE_AGENT'; // TODO: use CLI to get either the username or the device ID? how do we determine the device ID in this case?
16
+ private clientId = getDeviceId();
12
17
  private host = getIoTCoreEndpointUrl();
18
+ private publishInterval = 1000;
13
19
 
14
20
  constructor() {
15
21
  this.device = awsIot.device({
@@ -22,6 +28,11 @@ export class DeviceAgentCloudConnection {
22
28
 
23
29
  // TODO: subscribe to topics here
24
30
  this.device.subscribe('command');
31
+ this.publishInterval = this.publishInterval;
32
+ }
33
+
34
+ public getPublishInterval() {
35
+ return this.publishInterval;
25
36
  }
26
37
 
27
38
  public getClientId() {
@@ -30,13 +41,66 @@ export class DeviceAgentCloudConnection {
30
41
 
31
42
  public publishMessage(topic: string, message: string) {
32
43
  console.log('publishing message ', message);
33
- this.device.publish(topic, JSON.stringify({ message }));
44
+ this.device.publish(topic, message);
34
45
  }
35
46
  }
36
47
 
37
48
  export function runDeviceAgentCloudInterface() {
38
49
  const deviceAgent = new DeviceAgentCloudConnection();
39
50
 
51
+ async function getAppStateMessage() {
52
+ const appStateMessage: AppStatus[] = [];
53
+ const installedApps = await getInstalledApps();
54
+ for (const app of installedApps) {
55
+ const projectId = app['projectId'];
56
+ const status = await getAppStatus({ projectId });
57
+ appStateMessage.push(status);
58
+ }
59
+ const applicationStatePackage = {
60
+ applicationState: appStateMessage,
61
+ };
62
+ return applicationStatePackage;
63
+ }
64
+
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 }));
75
+ }, deviceAgent.getPublishInterval());
76
+
77
+ async function getDeviceStatsMessage() {
78
+ const cpuUsage = await getCpuUtil();
79
+ const diskUtil = await getDiskUtil();
80
+ const memUtil = await getMemUtil();
81
+
82
+ const deviceStatsMessage = {
83
+ deviceStats: {
84
+ cpuUsage,
85
+ diskUtil,
86
+ freeMemoryPercentage: memUtil,
87
+ },
88
+ };
89
+ return deviceStatsMessage;
90
+ }
91
+
92
+ const publishDeviceStats = setInterval(async function() {
93
+ const topic = `device/${deviceAgent.getClientId()}/topic/device-management`;
94
+ const deviceStatsMessage = await getDeviceStatsMessage();
95
+ const deviceStatsPackage = {
96
+ timestamp: new Date().toUTCString(),
97
+ deviceId: deviceAgent.getClientId(),
98
+ topic,
99
+ payload: deviceStatsMessage,
100
+ };
101
+ deviceAgent.publishMessage(topic, JSON.stringify({ deviceStatsPackage }));
102
+ }, deviceAgent.getPublishInterval());
103
+
40
104
  deviceAgent.device.on('connect', function() {
41
105
  deviceAgent.publishMessage('connection', deviceAgent.getClientId());
42
106
  console.log('Device Agent has connected to the cloud');
package/src/constants.ts CHANGED
@@ -1,23 +1,13 @@
1
1
  import { join, posix } from 'path';
2
2
  import { homedir } from 'os';
3
- const os = require('os');
4
- const path = require('path');
5
3
 
6
4
  export const ALWAYSAI_CLI_EXECUTABLE_NAME = 'aai-agent';
7
- export const DOT_ALWAYSAI_DIR = join(homedir(), '.alwaysai');
8
- export const AAI_DIR = path.join(os.homedir(), '.alwaysai');
9
5
 
10
6
  export const DEVICE_TOKEN_FILE_NAME = 'alwaysai.credentials.json';
11
7
  export const DEVICE_CONFIG_FILE_NAME = 'alwaysai.config.json';
12
8
 
13
- export const DEV_HOST_TOKEN_DIR = join(homedir(), '.config', 'alwaysai');
14
- export const DEVICE_TOKEN_DIR_LINUX = posix.join('~', '.config', 'alwaysai');
15
-
16
- export const DEV_HOST_CERT_AND_KEY_DIR = join(DEV_HOST_TOKEN_DIR, 'certificates');
17
- export const DEVICE_CERT_AND_KEY_DIR_LINUX = posix.join(
18
- DEVICE_TOKEN_DIR_LINUX,
19
- 'certificates',
20
- );
9
+ export const TOKEN_DIR = join(homedir(), '.config', 'alwaysai');
10
+ export const CERT_AND_KEY_DIR = join(TOKEN_DIR, 'certificates');
21
11
 
22
12
  export const DEVICE_CERTIFICATE_FILE_NAME = 'alwaysai.certificate.pem.crt';
23
13
  export const DEVICE_PRIVATE_KEY_FILE_NAME = 'alwaysai.private.pem.key';