@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,92 +1,114 @@
1
1
  import * as rimraf from 'rimraf';
2
2
  import * as fs from 'fs';
3
- import { join } from 'path';
3
+ import * as path from 'path';
4
+ import nodeFetch, { Response } from 'node-fetch';
5
+ import { JsSpawner } from 'alwaysai/lib/util';
4
6
 
5
7
  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';
8
+ import { buildApp, getAppDir } from './utils';
9
+ import { AppDetails } from '@alwaysai/device-agent-schemas';
16
10
  import { BACKUP_EXT, createAppBackup } from './backup';
17
11
  import { stopApp } from './status';
12
+ import { AgentConfigFile } from '../infrastructure/agent-config';
18
13
 
19
14
  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
-
15
+ const apps = await AgentConfigFile().getApps();
30
16
  const appDetails: AppDetails[] = [];
31
- for (const projectId of projectIds) {
32
- const appDir = getAppDir(projectId);
33
- const version = await getAppVersion({ appDir });
17
+ for (const app of apps) {
18
+ const { projectId, version } = app;
34
19
  appDetails.push({ projectId, version });
35
20
  }
36
21
  return appDetails;
37
22
  }
38
23
 
39
- export async function installApp(props: {
24
+ export type InstallAppProps = {
40
25
  projectId: string;
41
26
  releaseHash: string;
42
- }): Promise<void> {
43
- const { projectId, releaseHash } = props;
44
- console.log(`Installing ${projectId}`);
27
+ presignedAppUrl?: string;
28
+ };
29
+
30
+ export async function installAppPackage({ localDest, presignedUrl }): Promise<void> {
31
+ const response = await nodeFetch(presignedUrl);
32
+ if (response.status !== 200) {
33
+ // If the URL is invalid; I think we shouldn't get here with the new changes
34
+ throw new Error(
35
+ `Status Code: ${response.status}, ${response.statusText}. Response: ${response.body}`,
36
+ );
37
+ }
38
+
39
+ /**
40
+ * Write the app package to the hash directory
41
+ */
42
+ const stream = response.body.pipe(fs.createWriteStream(localDest));
43
+ await new Promise((resolve, reject) => {
44
+ stream.on('finish', resolve);
45
+ stream.on('error', reject);
46
+ });
47
+ }
48
+
49
+ export async function installApp(props: InstallAppProps): Promise<void> {
50
+ const { projectId, releaseHash, presignedAppUrl } = props;
45
51
  const appDir = getAppDir(projectId);
46
- const TEMP_DIR = join(APP_ROOT, 'temp');
47
52
  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 })) {
53
+ if (await AgentConfigFile().isAppPresent({ projectId })) {
54
+ if (!(await AgentConfigFile().isAppReady({ projectId }))) {
55
+ throw new Error('Application already has installation in progress!');
56
+ }
57
+ await AgentConfigFile().setAppInstalling({ projectId, version: releaseHash });
52
58
  console.log('Application is already installed, updating');
53
59
  await createAppBackup({ projectId });
54
60
  await spawner.rimraf(appDir);
61
+ } else {
62
+ await AgentConfigFile().setAppInstalling({ projectId, version: releaseHash });
55
63
  }
56
- // Create app directory
57
- await spawner.mkdirp(appDir);
58
64
 
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
- });
65
+ /**
66
+ * Prep directory and fetch the app package
67
+ */
68
+ await spawner.mkdirp(appDir);
69
+ const localDest = path.join(appDir, `${path.basename(releaseHash)}.tgz`);
70
+ if (!presignedAppUrl) {
71
+ // Download the application using the CLI
72
+ await runCliCmd({
73
+ cmd: [
74
+ 'release',
75
+ 'pull',
76
+ '--yes',
77
+ '--project',
78
+ projectId,
79
+ '--releaseHash',
80
+ releaseHash,
81
+ ],
82
+ cwd: appDir,
83
+ });
84
+ } else {
85
+ await installAppPackage({ localDest, presignedUrl: presignedAppUrl });
86
+ }
72
87
 
73
- // Unpack app package and move to install dir
74
- await spawner.untar(fs.createReadStream(join(TEMP_DIR, `${releaseHash}.tgz`)), appDir);
88
+ /**
89
+ * Unpack app package
90
+ */
91
+ await spawner.untar(fs.createReadStream(localDest), appDir);
75
92
  console.log(`Unpacked application to ${appDir}`);
76
93
 
77
- await setAppVersion({ appDir, version: releaseHash });
78
-
94
+ /**
95
+ * Build app
96
+ * ToDo: migrate the model pull to use MQTT workflow
97
+ */
79
98
  await buildApp({ appDir });
80
99
 
81
- await spawner.rimraf(TEMP_DIR);
100
+ /**
101
+ * Remove tar file
102
+ */
103
+ await spawner.rimraf(localDest);
82
104
 
105
+ await AgentConfigFile().setAppInstalled({ projectId, version: releaseHash });
83
106
  console.log(`Installed ${projectId} to ${appDir}`);
84
107
  }
85
108
 
86
109
  export async function uninstallApp(props: { projectId: string }): Promise<void> {
87
110
  const { projectId } = props;
88
- const appDir = getAppDir(projectId);
89
- if (!(await isAppInstalled({ appDir }))) {
111
+ if (!(await AgentConfigFile().isAppPresent({ projectId }))) {
90
112
  console.log(`Application ${projectId} not installed`);
91
113
  return;
92
114
  }
@@ -95,7 +117,9 @@ export async function uninstallApp(props: { projectId: string }): Promise<void>
95
117
  } catch {
96
118
  console.log('Failed to stop app, may be left running...');
97
119
  }
120
+ await AgentConfigFile().setAppUninstalled({ projectId });
98
121
  // Delete application directory and backup
122
+ const appDir = getAppDir(projectId);
99
123
  rimraf.sync(appDir);
100
124
  rimraf.sync(`${appDir}${BACKUP_EXT}`);
101
125
  console.log('Uninstalled', projectId);
@@ -1,17 +1,16 @@
1
+ import { JsSpawner } from 'alwaysai/lib/util';
1
2
  import { existsSync } from 'fs';
2
3
  import { join } from 'path';
3
4
 
4
5
  import { runCliCmd } from '../util/run-cli-cmd';
5
- import { JsSpawner } from '../util/spawner/js-spawner';
6
6
  import { ModelDetails } from './types';
7
- import { buildApp, getAppDir, isAppInstalled } from './utils';
7
+ import { buildApp, getAppDir, requireAppInstalled } from './utils';
8
8
 
9
9
  export async function getAppModels(props: { projectId: string }) {
10
10
  const { projectId } = props;
11
+ await requireAppInstalled({ projectId });
12
+
11
13
  const appDir = getAppDir(projectId);
12
- if (!(await isAppInstalled({ appDir }))) {
13
- throw new Error('Application is not installed');
14
- }
15
14
  const appCfgPath = join(appDir, 'alwaysai.app.json');
16
15
  if (!existsSync(appCfgPath)) {
17
16
  throw new Error('Application config not found!');
@@ -29,10 +28,9 @@ export async function getAppModels(props: { projectId: string }) {
29
28
 
30
29
  export async function addModel(props: { projectId: string; modelId: string }) {
31
30
  const { projectId, modelId } = props;
31
+ await requireAppInstalled({ projectId });
32
+
32
33
  const appDir = getAppDir(projectId);
33
- if (!(await isAppInstalled({ appDir }))) {
34
- throw new Error('Application is not installed');
35
- }
36
34
  await runCliCmd({
37
35
  cmd: ['app', 'models', 'add', modelId],
38
36
  cwd: appDir,
@@ -42,10 +40,9 @@ export async function addModel(props: { projectId: string; modelId: string }) {
42
40
 
43
41
  export async function removeModel(props: { projectId: string; modelId: string }) {
44
42
  const { projectId, modelId } = props;
43
+ await requireAppInstalled({ projectId });
44
+
45
45
  const appDir = getAppDir(projectId);
46
- if (!(await isAppInstalled({ appDir }))) {
47
- throw new Error('Application is not installed');
48
- }
49
46
  await runCliCmd({
50
47
  cmd: ['app', 'models', 'remove', modelId, '--purge'],
51
48
  cwd: appDir,
@@ -54,10 +51,9 @@ export async function removeModel(props: { projectId: string; modelId: string })
54
51
 
55
52
  export async function replaceModels(props: { projectId: string; modelIds: string[] }) {
56
53
  const { projectId, modelIds } = props;
54
+ await requireAppInstalled({ projectId });
55
+
57
56
  const appDir = getAppDir(projectId);
58
- if (!(await isAppInstalled({ appDir }))) {
59
- throw new Error('Application is not installed');
60
- }
61
57
  await runCliCmd({
62
58
  cmd: ['app', 'models', 'remove-all', '--purge'],
63
59
  cwd: appDir,
@@ -73,10 +69,9 @@ export async function replaceModels(props: { projectId: string; modelIds: string
73
69
 
74
70
  export async function updateModels(props: { projectId: string }) {
75
71
  const { projectId } = props;
72
+ await requireAppInstalled({ projectId });
73
+
76
74
  const appDir = getAppDir(projectId);
77
- if (!(await isAppInstalled({ appDir }))) {
78
- throw new Error('Application is not installed');
79
- }
80
75
  await runCliCmd({
81
76
  cmd: ['app', 'models', 'update'],
82
77
  cwd: appDir,
@@ -1,10 +1,11 @@
1
1
  import compose from 'docker-compose';
2
- import { fetchAppReleaseHistory } from 'alwaysai';
2
+ import { fetchAppReleaseHistory } from 'alwaysai/lib/infrastructure';
3
+ import { JsSpawner } from 'alwaysai/lib/util';
3
4
 
4
5
  import { runDockerLogin } from '../docker/docker-cmd';
5
- import { JsSpawner } from '../util/spawner/js-spawner';
6
- import { getAppDir, getAppVersion, isAppInstalled } from './utils';
7
- import { AppStatus, ServiceState, ServiceStatus } from './types';
6
+ import { getAppDir, requireAppInstalled } from './utils';
7
+ import { AppStateValue, ServiceStatus, AppState } from '@alwaysai/device-agent-schemas';
8
+ import { AgentConfigFile } from '../infrastructure/agent-config';
8
9
 
9
10
  export async function listAppReleases(props: { projectId: string }) {
10
11
  const { projectId } = props;
@@ -21,14 +22,23 @@ export async function listAppLatestRelease(props: { projectId: string }) {
21
22
  return undefined;
22
23
  }
23
24
 
24
- export async function getAppStatus(props: { projectId: string }): Promise<AppStatus> {
25
+ export async function getAppStatus(props: { projectId: string }): Promise<AppState> {
25
26
  const { projectId } = props;
26
- const appDir = getAppDir(projectId);
27
-
28
- if (!(await isAppInstalled({ appDir }))) {
27
+ if (!(await AgentConfigFile().isAppPresent({ projectId }))) {
29
28
  throw new Error('Application is not installed');
30
29
  }
31
30
 
31
+ const appDetails = {
32
+ projectId,
33
+ version: await AgentConfigFile().getAppVersion({ projectId }),
34
+ };
35
+ if (!(await AgentConfigFile().isAppReady({ projectId }))) {
36
+ // App is being installed or updated
37
+ return { appDetails, services: [] };
38
+ }
39
+
40
+ const appDir = getAppDir(projectId);
41
+
32
42
  // Check if app is running
33
43
  const output = await compose.ps({ cwd: appDir });
34
44
 
@@ -38,7 +48,6 @@ export async function getAppStatus(props: { projectId: string }): Promise<AppSta
38
48
  );
39
49
  }
40
50
 
41
- const appDetails = { projectId, version: await getAppVersion({ appDir }) };
42
51
  const services: ServiceStatus[] = [];
43
52
  if (output.data.services.length === 0) {
44
53
  // If the app has never been started (or has an empty docker-compose.yaml)
@@ -54,7 +63,7 @@ export async function getAppStatus(props: { projectId: string }): Promise<AppSta
54
63
  .replace(/\d+$/, '')
55
64
  .replace(/_/g, '');
56
65
 
57
- let state: ServiceState;
66
+ let state: AppStateValue;
58
67
  if (service.state.includes('Up')) {
59
68
  state = 'Up';
60
69
  } else if (service.state.includes('Stopped') || service.state.includes('Exit')) {
@@ -75,15 +84,13 @@ export async function getAppLogs(props: {
75
84
  services?: string[];
76
85
  }): Promise<NodeJS.ReadableStream> {
77
86
  const { projectId, services } = props;
78
- const appDir = getAppDir(projectId);
87
+ await requireAppInstalled({ projectId });
79
88
 
80
- if (!(await isAppInstalled({ appDir }))) {
81
- throw new Error('Application is not installed');
82
- }
89
+ const appDir = getAppDir(projectId);
83
90
 
84
91
  const serviceList = services
85
92
  ? services
86
- : await (async function() {
93
+ : await (async function () {
87
94
  const appStatus = await getAppStatus({ projectId });
88
95
  const services: string[] = [];
89
96
  for (const service of appStatus.services) {
@@ -105,11 +112,9 @@ export async function startApp(props: {
105
112
  dockerLoginToken?: string;
106
113
  }): Promise<void> {
107
114
  const { projectId, dockerLoginToken } = props;
115
+ await requireAppInstalled({ projectId });
116
+
108
117
  const appDir = getAppDir(projectId);
109
- // Check if app is installed
110
- if (!(await isAppInstalled({ appDir }))) {
111
- throw new Error('Application is not installed');
112
- }
113
118
  if (dockerLoginToken !== undefined) {
114
119
  const result = await runDockerLogin({ token: dockerLoginToken });
115
120
  console.log(result);
@@ -129,12 +134,9 @@ export async function startApp(props: {
129
134
 
130
135
  export async function stopApp(props: { projectId: string }): Promise<void> {
131
136
  const { projectId } = props;
137
+ await requireAppInstalled({ projectId });
138
+
132
139
  const appDir = getAppDir(projectId);
133
- // Check if app is installed
134
- if (!(await isAppInstalled({ appDir }))) {
135
- console.log('Application is not installed');
136
- return;
137
- }
138
140
  // TODO: Check if app is running
139
141
  // Stop app
140
142
  const output = await compose.down({ cwd: appDir });
@@ -1,5 +1 @@
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
1
  export type ModelDetails = { modelId: string; version: number };
@@ -1,41 +1,27 @@
1
1
  import compose from 'docker-compose';
2
2
  import * as path from 'path';
3
3
  import * as fs from 'fs';
4
+ import { AAI_DIR } from 'alwaysai/lib/constants';
4
5
 
5
- import { JsSpawner } from '../util/spawner/js-spawner';
6
- import { AAI_DIR } from 'alwaysai';
7
6
  import { runCliCmd } from '../util/run-cli-cmd';
7
+ import { AgentConfigFile } from '../infrastructure/agent-config';
8
8
 
9
9
  export const APP_ROOT = path.join(AAI_DIR, 'applications');
10
- const RELEASE_FILENAME = 'alwaysai.release.json';
11
10
  const DOCKER_COMPOSE_FILENAME = 'docker-compose.yaml';
12
11
 
13
12
  export function getAppDir(projectId: string): string {
14
13
  return path.join(APP_ROOT, projectId);
15
14
  }
16
15
 
17
- export async function isAppInstalled(props: { appDir: string }): Promise<boolean> {
18
- const { appDir } = props;
19
- // TODO: Could do more sophisticated check
20
- if (fs.existsSync(appDir)) {
21
- return true;
16
+ export async function requireAppInstalled(props: { projectId: string }) {
17
+ const { projectId } = props;
18
+ // Ensure an app that is being installed or updated is not modified
19
+ if (!(await AgentConfigFile().isAppPresent({ projectId }))) {
20
+ throw new Error('Application is not installed');
21
+ }
22
+ if (!(await AgentConfigFile().isAppReady({ projectId }))) {
23
+ throw new Error('Application is not done installing or updating');
22
24
  }
23
- return false;
24
- }
25
-
26
- export async function setAppVersion(props: { appDir: string; version: string }) {
27
- const { appDir, version } = props;
28
- // TODO: Switch to node-config
29
- const versionPath = path.join(appDir, RELEASE_FILENAME);
30
- const versionData = { version };
31
- await JsSpawner().writeFile(versionPath, JSON.stringify(versionData, null, 2));
32
- }
33
-
34
- export async function getAppVersion(props: { appDir: string }) {
35
- const { appDir } = props;
36
- const versionPath = path.join(appDir, RELEASE_FILENAME);
37
- const releaseData = JSON.parse(await JsSpawner().readFile(versionPath));
38
- return releaseData.version;
39
25
  }
40
26
 
41
27
  export async function buildApp(props: { appDir: string }) {
@@ -55,7 +41,6 @@ export async function buildApp(props: { appDir: string }) {
55
41
  }
56
42
 
57
43
  const buildOut = await compose.buildAll({ cwd: appDir });
58
- console.log(buildOut);
59
44
  if (buildOut.exitCode !== 0) {
60
45
  throw new Error(
61
46
  `Failed to build application! stdout=${buildOut.out} stderr=${buildOut.err}`,