@constellation-network/node-pilot 0.0.8 → 0.0.10

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 (90) hide show
  1. package/README.md +26 -15
  2. package/bin/dev.js +1 -6
  3. package/bin/run.js +1 -1
  4. package/dist/base-command.d.ts +9 -0
  5. package/dist/base-command.js +20 -0
  6. package/dist/checks/check-hardware.js +3 -3
  7. package/dist/checks/check-initial-setup.js +2 -0
  8. package/dist/checks/check-layers.js +7 -7
  9. package/dist/checks/check-network.d.ts +2 -0
  10. package/dist/checks/check-network.js +46 -11
  11. package/dist/checks/check-node-ctl.js +4 -4
  12. package/dist/checks/check-project.d.ts +1 -0
  13. package/dist/checks/check-project.js +15 -4
  14. package/dist/checks/check-wallet.d.ts +3 -0
  15. package/dist/checks/check-wallet.js +37 -0
  16. package/dist/clm.d.ts +1 -0
  17. package/dist/clm.js +3 -0
  18. package/dist/commands/config/get.d.ts +6 -0
  19. package/dist/commands/config/get.js +57 -11
  20. package/dist/commands/config/set.d.ts +0 -1
  21. package/dist/commands/config/set.js +13 -11
  22. package/dist/commands/config.js +17 -22
  23. package/dist/commands/info.js +3 -2
  24. package/dist/commands/logs.d.ts +1 -1
  25. package/dist/commands/logs.js +7 -3
  26. package/dist/commands/restart.d.ts +10 -2
  27. package/dist/commands/restart.js +65 -9
  28. package/dist/commands/shutdown.js +3 -3
  29. package/dist/commands/status.js +4 -0
  30. package/dist/commands/test.js +10 -3
  31. package/dist/config-store.d.ts +47 -31
  32. package/dist/config-store.js +98 -42
  33. package/dist/helpers/config-helper.js +2 -2
  34. package/dist/helpers/env-templates.d.ts +4 -3
  35. package/dist/helpers/env-templates.js +28 -20
  36. package/dist/helpers/key-file-helper.d.ts +2 -0
  37. package/dist/helpers/key-file-helper.js +51 -16
  38. package/dist/helpers/project-helper.d.ts +2 -2
  39. package/dist/helpers/project-helper.js +37 -38
  40. package/dist/helpers/prompt-helper.d.ts +0 -1
  41. package/dist/helpers/prompt-helper.js +15 -15
  42. package/dist/services/archiver-service.d.ts +17 -0
  43. package/dist/services/archiver-service.js +104 -0
  44. package/dist/services/cluster-service.d.ts +10 -6
  45. package/dist/services/cluster-service.js +45 -45
  46. package/dist/services/docker-service.d.ts +9 -0
  47. package/dist/{helpers/docker-helper.js → services/docker-service.js} +11 -9
  48. package/dist/services/fastforward-service.js +3 -3
  49. package/dist/services/get-random-node.js +1 -1
  50. package/dist/{helpers/github-helper.d.ts → services/github-service.d.ts} +1 -1
  51. package/dist/{helpers/github-helper.js → services/github-service.js} +1 -1
  52. package/dist/services/node-service.js +14 -14
  53. package/dist/services/notify-service.d.ts +1 -0
  54. package/dist/services/notify-service.js +1 -0
  55. package/dist/services/systemd-service.d.ts +3 -0
  56. package/dist/services/systemd-service.js +45 -0
  57. package/dist/test.d.ts +1 -0
  58. package/dist/test.js +50 -0
  59. package/dist/types.d.ts +6 -0
  60. package/install-dependencies.sh +0 -2
  61. package/oclif.manifest.json +33 -4
  62. package/package.json +9 -8
  63. package/projects/custom/pilot.json +9 -0
  64. package/projects/hypergraph/Dockerfile +24 -18
  65. package/projects/hypergraph/docker-compose.yml +14 -14
  66. package/projects/hypergraph/networks/integrationnet/gl0.env +4 -0
  67. package/projects/hypergraph/networks/integrationnet/gl1.env +4 -0
  68. package/projects/hypergraph/networks/integrationnet/network.env +8 -0
  69. package/projects/hypergraph/networks/{integrationnet.env → integrationnet/source-nodes.env} +1 -9
  70. package/projects/hypergraph/networks/mainnet/gl0.env +4 -0
  71. package/projects/hypergraph/networks/mainnet/gl1.env +4 -0
  72. package/projects/hypergraph/networks/mainnet/network.env +8 -0
  73. package/projects/hypergraph/networks/{mainnet.env → mainnet/source-nodes.env} +0 -8
  74. package/projects/hypergraph/networks/testnet/gl0.env +5 -0
  75. package/projects/hypergraph/networks/testnet/gl1.env +4 -0
  76. package/projects/hypergraph/networks/testnet/network.env +8 -0
  77. package/projects/hypergraph/networks/{testnet.env → testnet/source-nodes.env} +0 -8
  78. package/projects/hypergraph/scripts/check-version.sh +31 -0
  79. package/projects/hypergraph/scripts/install.sh +30 -25
  80. package/projects/hypergraph/seedlist +268 -0
  81. package/scripts/autoheal.sh +8 -0
  82. package/scripts/restart_logger.sh +3 -0
  83. package/scripts/services/io.constellationnetwork.nodepilot.Updater.plist +16 -0
  84. package/scripts/services/node-pilot-autoheal.service +12 -0
  85. package/scripts/services/node-pilot-restarter.service +11 -0
  86. package/scripts/services/node-pilot-updater.service +13 -0
  87. package/scripts/update_logger.sh +3 -0
  88. package/dist/helpers/docker-helper.d.ts +0 -7
  89. package/projects/hypergraph/layers/gl1.env +0 -3
  90. package/projects/scripts/docker-cleanup.sh +0 -64
@@ -15,12 +15,12 @@ class ConfigStore {
15
15
  constructor() {
16
16
  const appDir = path.join(os.homedir(), '.node-pilot');
17
17
  if (!fs.existsSync(appDir)) {
18
- fs.mkdirSync(appDir, { recursive: true });
18
+ fs.mkdirSync(path.join(appDir, 'logs'), { recursive: true });
19
19
  }
20
20
  this.pilotStore = new JSONStorage(path.join(appDir, 'config'));
21
21
  const appInfo = this.pilotStore.getItem('pilot');
22
22
  if (!appInfo) {
23
- this.pilotStore.setItem('pilot', { appDir, project: 'undefined', projects: [] });
23
+ this.pilotStore.setItem('pilot', { appDir, project: 'undefined', projects: [], running: [] });
24
24
  }
25
25
  const { project } = this.pilotStore.getItem('pilot');
26
26
  this.projectStore = project === 'undefined' ? new EmptyStorage() : new JSONStorage(path.join(appDir, project, 'config'));
@@ -41,83 +41,106 @@ class ConfigStore {
41
41
  }
42
42
  }
43
43
  else {
44
- this.pilotStore.setItem('pilot', { appDir, project: name, projects: [...projects, name] });
44
+ this.setPilotInfo({ project: name, projects: [...projects, name] });
45
45
  }
46
46
  fs.mkdirSync(path.join(projectDir, 'config'), { recursive: true });
47
47
  this.projectStore = new JSONStorage(path.join(projectDir, 'config'));
48
48
  this.setDockerEnvInfo({ DOCKER_IMAGE_VERSION: 'test' });
49
49
  this.setProjectInfo({ name, projectDir });
50
- this.setEnvInfo({ common: { CL_GLOBAL_L0_PEER_HTTP_PORT: '9000' }, layers: { gl0: { CL_PUBLIC_HTTP_PORT: "9000" } } });
51
50
  }
52
- changeProjectStore(name) {
53
- const { appDir, projects } = this.pilotStore.getItem('pilot');
54
- if (projects && projects.includes(name)) {
55
- this.projectStore = new JSONStorage(path.join(appDir, name, 'config'));
56
- }
57
- else {
58
- throw new Error(`Project ${name} doesn't exist.`);
59
- }
51
+ getActiveProject() {
52
+ const { project } = this.pilotStore.getItem('pilot');
53
+ return project;
54
+ }
55
+ getAppDir() {
56
+ const { appDir } = this.pilotStore.getItem('pilot');
57
+ return appDir;
60
58
  }
61
59
  getDockerEnvInfo() {
62
60
  return this.projectStore.getItem('docker');
63
61
  }
64
- getEnvCommonInfo() {
65
- return this.projectStore.getItem('env')?.common;
66
- }
67
62
  getEnvInfo() {
68
- return this.projectStore.getItem('env');
63
+ return this.projectStore.getItem('env') || {};
64
+ }
65
+ getEnvLayerInfo(network, layer) {
66
+ const envInfo = this.projectStore.getItem('layer-env');
67
+ if (!envInfo)
68
+ return { [network]: {} };
69
+ return envInfo[network][layer] || {};
69
70
  }
70
- getEnvLayerInfo(layer) {
71
- const envInfo = this.projectStore.getItem('env');
71
+ getEnvNetworkInfo(network) {
72
+ const envInfo = this.projectStore.getItem('network-env');
72
73
  if (!envInfo)
73
74
  return {};
74
- return { ...envInfo.common, ...envInfo.layers[layer] };
75
+ return envInfo[network];
75
76
  }
76
77
  getLayerPortInfo(layer) {
77
- const layerInfo = this.getEnvLayerInfo(layer);
78
+ const { type: network } = this.getNetworkInfo();
79
+ const layerInfo = this.getEnvLayerInfo(network, layer);
78
80
  return { CLI: layerInfo.CL_CLI_HTTP_PORT, P2P: layerInfo.CL_P2P_HTTP_PORT, PUBLIC: layerInfo.CL_PUBLIC_HTTP_PORT };
79
81
  }
80
- getNetworkEnvInfo(network) {
81
- const info = this.projectStore.getItem('network-env');
82
- return info ? info[network] : {};
83
- }
84
82
  getNetworkInfo() {
85
83
  return this.projectStore.getItem('network');
86
84
  }
87
85
  getProjectInfo() {
88
86
  return this.projectStore.getItem('project');
89
87
  }
88
+ getProjects() {
89
+ const { projects } = this.pilotStore.getItem('pilot');
90
+ return projects;
91
+ }
92
+ getRunningProjects() {
93
+ const { running } = this.pilotStore.getItem('pilot');
94
+ return running;
95
+ }
90
96
  getSystemInfo() {
91
97
  return this.pilotStore.getItem('system');
92
98
  }
93
99
  hasProjectFlag(name) {
94
100
  const flags = this.projectStore.getItem('flags') || {};
95
- return flags[name] !== undefined;
101
+ return flags[name] || false;
96
102
  }
97
103
  hasProjects() {
98
104
  const { projects } = this.pilotStore.getItem('pilot');
99
105
  return projects.length > 0;
100
106
  }
107
+ setActiveProject(name) {
108
+ const { appDir, project, projects } = this.pilotStore.getItem('pilot');
109
+ if (projects && projects.includes(name)) {
110
+ if (project === name)
111
+ return;
112
+ this.projectStore = new JSONStorage(path.join(appDir, name, 'config'));
113
+ this.setPilotInfo({ project: name });
114
+ }
115
+ else {
116
+ throw new Error(`Project ${name} doesn't exist.`);
117
+ }
118
+ }
119
+ setClusterStats(info) {
120
+ const oldInfo = this.projectStore.getItem('cluster-stats');
121
+ this.projectStore.setItem('cluster-stats', { ...oldInfo, ...info });
122
+ }
101
123
  setDockerEnvInfo(info) {
102
124
  const oldInfo = this.projectStore.getItem('docker');
103
125
  this.projectStore.setItem('docker', { ...oldInfo, ...info });
104
126
  }
105
- setEnvCommonInfo(info) {
106
- const oldInfo = this.projectStore.getItem('env');
107
- this.projectStore.setItem('env', { common: { ...oldInfo.common, ...info }, layers: oldInfo.layers });
108
- }
109
127
  setEnvInfo(info) {
110
128
  const oldInfo = this.projectStore.getItem('env');
111
129
  this.projectStore.setItem('env', { ...oldInfo, ...info });
112
130
  }
113
- setEnvLayerInfo(layer, info) {
114
- const envInfo = this.projectStore.getItem('env');
115
- const { common, layers } = envInfo;
116
- this.projectStore.setItem('env', { common, layers: { ...layers, [layer]: { ...layers[layer], ...info } } });
131
+ setEnvLayerInfo(network, layer, info) {
132
+ let layers = this.projectStore.getItem('layer-env');
133
+ if (!layers)
134
+ layers = {};
135
+ if (!layers[network])
136
+ layers[network] = {};
137
+ this.projectStore.setItem('layer-env', { ...layers, [network]: { ...layers[network], [layer]: { ...layers[network][layer], ...info } } });
117
138
  }
118
- setNetworkEnvInfo(info) {
119
- const oldInfo = this.projectStore.getItem('network-env');
120
- this.projectStore.setItem('network-env', { ...oldInfo, ...info });
139
+ setEnvNetworkInfo(network, info) {
140
+ let networks = this.projectStore.getItem('network-env');
141
+ if (!networks)
142
+ networks = {};
143
+ this.projectStore.setItem('network-env', { ...networks, [network]: { ...networks[network], ...info } });
121
144
  }
122
145
  setNetworkInfo(info) {
123
146
  const oldInfo = this.projectStore.getItem('network');
@@ -133,29 +156,62 @@ class ConfigStore {
133
156
  const oldInfo = this.projectStore.getItem('project');
134
157
  this.projectStore.setItem('project', { ...oldInfo, ...info });
135
158
  }
159
+ setProjectStatusToRunning(isRunning) {
160
+ const { project, running } = this.pilotStore.getItem('pilot');
161
+ if (isRunning) {
162
+ if (running.includes(project))
163
+ return;
164
+ this.setPilotInfo({ running: [...running, project] });
165
+ }
166
+ else {
167
+ if (!running.includes(project))
168
+ return;
169
+ running.splice(running.indexOf(project), 1);
170
+ this.setPilotInfo({ running });
171
+ }
172
+ }
136
173
  setSystemInfo(info) {
137
174
  const oldInfo = this.projectStore.getItem('system');
138
175
  this.pilotStore.setItem('system', { ...oldInfo, ...info });
139
176
  }
177
+ getPilotInfo() {
178
+ return this.pilotStore.getItem('pilot');
179
+ }
180
+ setPilotInfo(info) {
181
+ const oldInfo = this.pilotStore.getItem('pilot');
182
+ this.pilotStore.setItem('pilot', { ...oldInfo, ...info });
183
+ }
140
184
  }
141
185
  export const configStore = new ConfigStore();
142
- export const commonEnvNames = {
143
- CL_APP_ENV: 1,
186
+ export const envNames = {
144
187
  CL_EXTERNAL_IP: 1,
188
+ CL_KEYALIAS: 1,
189
+ CL_KEYSTORE: 1,
190
+ CL_PASSWORD: 1
191
+ };
192
+ export const networkEnvNames = {
193
+ CL_APP_ENV: 1,
145
194
  CL_GLOBAL_L0_PEER_HOST: 1,
146
195
  CL_GLOBAL_L0_PEER_HTTP_PORT: 1,
147
196
  CL_GLOBAL_L0_PEER_ID: 1,
148
- CL_KEYALIAS: 1,
149
- CL_KEYSTORE: 1,
150
197
  CL_L0_PEER_HTTP_HOST: 1,
151
198
  CL_L0_PEER_HTTP_PORT: 1,
152
199
  CL_L0_PEER_ID: 1,
200
+ CL_L0_PEER_P2P_PORT: 1,
153
201
  CL_L0_TOKEN_IDENTIFIER: 1,
154
- CL_PASSWORD: 1
155
202
  };
203
+ // NETWORK LAYER
156
204
  export const layerEnvNames = {
157
205
  CL_CLI_HTTP_PORT: 1,
158
206
  CL_DOCKER_JAVA_OPTS: 1,
207
+ CL_GLOBAL_L0_PEER_HOST: 1,
208
+ CL_GLOBAL_L0_PEER_HTTP_PORT: 1,
209
+ CL_GLOBAL_L0_PEER_ID: 1,
210
+ CL_L0_PEER_HTTP_HOST: 1,
211
+ CL_L0_PEER_HTTP_PORT: 1,
212
+ CL_L0_PEER_ID: 1,
213
+ CL_L0_PEER_P2P_PORT: 1,
214
+ CL_LB: 1,
159
215
  CL_P2P_HTTP_PORT: 1,
160
- CL_PUBLIC_HTTP_PORT: 1,
216
+ CL_PUBLIC_HTTP_PORT: 1
161
217
  };
@@ -18,8 +18,8 @@ export const configHelper = {
18
18
  }
19
19
  const versionObj = this.parseEnvFile(lastInstallVersion);
20
20
  return {
21
- network: versionObj.RELEASE_NETWORK_TYPE,
22
- version: versionObj.RELEASE_NETWORK_VERSION
21
+ network: versionObj.INSTALLED_NETWORK_TYPE,
22
+ version: versionObj.INSTALLED_NETWORK_VERSION
23
23
  };
24
24
  },
25
25
  parseEnvFile(filePath) {
@@ -1,4 +1,5 @@
1
- import { EnvCommonInfo, EnvLayerInfo, NetworkType } from "../config-store.js";
1
+ import { EnvCombinedInfo, EnvInfo } from "../config-store.js";
2
2
  import { TessellationLayer } from "../types.js";
3
- export declare function getLayerEnvFileContent(layer: TessellationLayer, network: NetworkType, commonInfo: EnvCommonInfo, layerInfo: EnvLayerInfo): string;
4
- export declare function getKeyFileContent(commonInfo: EnvCommonInfo): string;
3
+ export declare function getLayerEnvFileContent(layer: TessellationLayer, env: EnvCombinedInfo): string;
4
+ export declare function getKeyFileContent(env: EnvInfo): string;
5
+ export declare function getObjectToEnvContent(obj: object): string;
@@ -1,33 +1,41 @@
1
- export function getLayerEnvFileContent(layer, network, commonInfo, layerInfo) {
1
+ export function getLayerEnvFileContent(layer, env) {
2
2
  return `
3
+ DEBUG=${process.env.DEBUG || ''}
4
+ NODE_PILOT_SESSION=${Date.now()}
5
+
3
6
  # Node
4
- CL_EXTERNAL_IP=${commonInfo.CL_EXTERNAL_IP}
5
- CL_DOCKER_JAVA_OPTS='${layerInfo.CL_DOCKER_JAVA_OPTS}'
7
+ CL_ARCHIVE_NODE=${env.CL_ARCHIVE_NODE || ''}
8
+ CL_EXTERNAL_IP=${env.CL_EXTERNAL_IP}
9
+ CL_DOCKER_JAVA_OPTS='${env.CL_DOCKER_JAVA_OPTS}'
6
10
  CL_KEYSTORE='/app/key.p12'
7
- CL_KEYALIAS='${commonInfo.CL_KEYALIAS}'
8
- CL_PASSWORD='${commonInfo.CL_PASSWORD}'
11
+ CL_KEYALIAS='${env.CL_KEYALIAS}'
12
+ CL_PASSWORD='${env.CL_PASSWORD}'
9
13
  CL_TESSELATION_LAYER=${layer}
10
14
 
11
15
  # NETWORK
12
- CL_APP_ENV=${commonInfo.CL_APP_ENV}
13
- CL_COLLATERAL=${network === 'mainnet' ? 25000000000000 : 0}
14
- CL_L0_PEER_HTTP_PORT=${commonInfo.CL_L0_PEER_HTTP_PORT}
15
- CL_L0_PEER_HTTP_HOST=${commonInfo.CL_L0_PEER_HTTP_HOST}
16
- CL_L0_PEER_ID=${commonInfo.CL_L0_PEER_ID}
17
- CL_GLOBAL_L0_PEER_HTTP_PORT=${commonInfo.CL_GLOBAL_L0_PEER_HTTP_PORT}
18
- CL_GLOBAL_L0_PEER_HOST=${commonInfo.CL_GLOBAL_L0_PEER_HOST}
19
- CL_GLOBAL_L0_PEER_ID=${commonInfo.CL_GLOBAL_L0_PEER_ID}
16
+ CL_LB=${env.CL_LB}
17
+ CL_APP_ENV=${env.CL_APP_ENV}
18
+ CL_COLLATERAL=${env.CL_COLLATERAL}
19
+ CL_L0_PEER_HTTP_PORT=${env.CL_L0_PEER_HTTP_PORT}
20
+ CL_L0_PEER_HTTP_HOST=${env.CL_L0_PEER_HTTP_HOST}
21
+ CL_L0_PEER_ID=${env.CL_L0_PEER_ID}
22
+ CL_GLOBAL_L0_PEER_HTTP_PORT=${env.CL_GLOBAL_L0_PEER_HTTP_PORT}
23
+ CL_GLOBAL_L0_PEER_HOST=${env.CL_GLOBAL_L0_PEER_HOST}
24
+ CL_GLOBAL_L0_PEER_ID=${env.CL_GLOBAL_L0_PEER_ID}
20
25
 
21
26
  # LAYER
22
- CL_PUBLIC_HTTP_PORT=${layerInfo.CL_PUBLIC_HTTP_PORT}
23
- CL_P2P_HTTP_PORT=${layerInfo.CL_P2P_HTTP_PORT}
24
- CL_CLI_HTTP_PORT=${layerInfo.CL_CLI_HTTP_PORT}
27
+ CL_PUBLIC_HTTP_PORT=${env.CL_PUBLIC_HTTP_PORT}
28
+ CL_P2P_HTTP_PORT=${env.CL_P2P_HTTP_PORT}
29
+ CL_CLI_HTTP_PORT=${env.CL_CLI_HTTP_PORT}
25
30
  `;
26
31
  }
27
- export function getKeyFileContent(commonInfo) {
32
+ export function getKeyFileContent(env) {
28
33
  return `
29
- export CL_KEYSTORE='${commonInfo.CL_KEYSTORE}'
30
- export CL_KEYALIAS='${commonInfo.CL_KEYALIAS}'
31
- export CL_PASSWORD='${commonInfo.CL_PASSWORD}'
34
+ export CL_KEYSTORE='${env.CL_KEYSTORE}'
35
+ export CL_KEYALIAS='${env.CL_KEYALIAS}'
36
+ export CL_PASSWORD='${env.CL_PASSWORD}'
32
37
  `;
33
38
  }
39
+ export function getObjectToEnvContent(obj) {
40
+ return Object.entries(obj).map(([k, v]) => `${k}='${v}'`).join('\n') + '\n';
41
+ }
@@ -1,9 +1,11 @@
1
1
  export declare const keyFileHelper: {
2
+ changePassword(newPassword: string): Promise<void>;
2
3
  generate(): Promise<void>;
3
4
  getAddress(): Promise<string>;
4
5
  getId(): Promise<string>;
5
6
  importKeyFile(): Promise<void>;
6
7
  promptForKeyFile(): Promise<void>;
7
8
  promptIfNoKeyFile(): Promise<void>;
9
+ promptSaveBackup(env: object): Promise<void>;
8
10
  showKeyFileInfo(prompt4ShowPassword?: boolean): Promise<void>;
9
11
  };
@@ -7,12 +7,27 @@ import { clm } from "../clm.js";
7
7
  import { configStore } from "../config-store.js";
8
8
  import { shellService } from "../services/shell-service.js";
9
9
  import { configHelper } from "./config-helper.js";
10
- import { getKeyFileContent } from "./env-templates.js";
10
+ import { getObjectToEnvContent } from "./env-templates.js";
11
11
  export const keyFileHelper = {
12
+ async changePassword(newPassword) {
13
+ const { projectDir } = configStore.getProjectInfo();
14
+ const keyFilePath = path.join(projectDir, "key.p12");
15
+ if (!fs.existsSync(keyFilePath)) {
16
+ clm.error('No key file found. Please generate a new key file first.');
17
+ }
18
+ const { CL_PASSWORD: currentPassword } = configStore.getEnvInfo();
19
+ if (currentPassword === newPassword) {
20
+ clm.error('The new password is the same as the current password. Please try again with a different password.');
21
+ }
22
+ await shellService.runCommand(`keytool -importkeystore -srckeystore ${keyFilePath} -srcstoretype PKCS12 -srcstorepass '${currentPassword}' -destkeystore ${path.join(projectDir, "temp.p12")} -deststoretype PKCS12 -deststorepass '${newPassword}' -destkeypass '${newPassword}'`);
23
+ await this.promptSaveBackup({ CL_KEYALIAS: 'alias', CL_KEYSTORE: keyFilePath, CL_PASSWORD: newPassword });
24
+ },
12
25
  async generate() {
13
26
  const { projectDir } = configStore.getProjectInfo();
14
27
  const keyFilePath = path.join(projectDir, "key.p12");
28
+ let modifier = '';
15
29
  if (fs.existsSync(keyFilePath)) {
30
+ modifier = 'new ';
16
31
  const answer = await input({ default: 'n', message: 'A key file already exists. Do you want to overwrite it? (y/n): ' });
17
32
  if (answer.toLowerCase() === 'y') {
18
33
  fs.rmSync(keyFilePath, { force: true });
@@ -22,31 +37,26 @@ export const keyFileHelper = {
22
37
  process.exit(0);
23
38
  }
24
39
  }
25
- const keyPassword = await password({ message: 'Enter the key file password:', validate: value => value.length > 0 });
40
+ const keyPassword = await password({ message: `Enter the ${modifier}key file password:`, validate: value => value.length > 0 });
26
41
  const env = {
27
42
  CL_KEYALIAS: "alias", CL_KEYSTORE: keyFilePath, CL_PASSWORD: keyPassword
28
43
  };
29
44
  await shellService.runCommand(`java -jar ${projectDir}/dist/keytool.jar generate`, env);
30
- configStore.setEnvCommonInfo(env);
45
+ configStore.setEnvInfo(env);
31
46
  const dagAddress = await this.getAddress();
32
47
  const nodeId = await this.getId();
33
48
  configStore.setProjectInfo({ dagAddress, nodeId });
34
49
  clm.postStep('Key file generated successfully.\n');
35
- const answer = await input({ default: 'y', message: 'Would you like to save a backup of the key file to your home directory? (y/n): ' });
36
- if (answer.toLowerCase() === 'y') {
37
- fs.cpSync(keyFilePath, path.join(os.homedir(), 'key.p12'));
38
- fs.writeFileSync(path.join(os.homedir(), 'key-env.sh'), getKeyFileContent({ ...env, CL_KEYSTORE: 'key.p12' }));
39
- clm.postStep(`A copy of the Key file has been saved to your home directory - ${chalk.cyan(path.join(os.homedir(), 'key.p12'))}`);
40
- }
50
+ await this.promptSaveBackup(env);
41
51
  },
42
52
  async getAddress() {
43
53
  const { projectDir } = configStore.getProjectInfo();
44
- const env = configStore.getEnvCommonInfo();
54
+ const env = configStore.getEnvInfo();
45
55
  return shellService.runCommandWithOutput(`java -jar ${projectDir}/dist/wallet.jar show-address`, env);
46
56
  },
47
57
  async getId() {
48
58
  const { projectDir } = configStore.getProjectInfo();
49
- const env = configStore.getEnvCommonInfo();
59
+ const env = configStore.getEnvInfo();
50
60
  return shellService.runCommandWithOutput(`java -jar ${projectDir}/dist/wallet.jar show-id`, env);
51
61
  },
52
62
  async importKeyFile() {
@@ -72,17 +82,17 @@ export const keyFileHelper = {
72
82
  // prompt for password
73
83
  const keyPassword = await password({ message: 'Enter the key file password:' });
74
84
  const keyAlias = await input({ message: 'Enter the key file alias:' });
75
- configStore.setEnvCommonInfo({ CL_KEYALIAS: keyAlias, CL_KEYSTORE: keyStorePath, CL_PASSWORD: keyPassword });
85
+ configStore.setEnvInfo({ CL_KEYALIAS: keyAlias, CL_KEYSTORE: keyStorePath, CL_PASSWORD: keyPassword });
76
86
  try {
77
87
  const dagAddress = await this.getAddress();
78
88
  const nodeId = await this.getId();
79
89
  configStore.setProjectInfo({ dagAddress, nodeId });
80
90
  }
81
91
  catch {
82
- clm.warn('Failed to unlock the key file. Please check your key file information and try again.');
83
92
  fs.rmSync(keyStorePath);
84
- await this.promptForKeyFile();
85
- return;
93
+ clm.error('Failed to unlock the key file. Please check your key file information and try again.');
94
+ // await this.promptForKeyFile();
95
+ // return;
86
96
  }
87
97
  clm.postStep('Key file imported successfully.\n');
88
98
  },
@@ -108,6 +118,8 @@ export const keyFileHelper = {
108
118
  await this.importKeyFile();
109
119
  await this.showKeyFileInfo(false);
110
120
  }
121
+ configStore.setProjectFlag('duplicateNodeIdChecked', false);
122
+ configStore.setProjectFlag('seedListChecked', false);
111
123
  },
112
124
  async promptIfNoKeyFile() {
113
125
  const { projectDir } = configStore.getProjectInfo();
@@ -117,12 +129,35 @@ export const keyFileHelper = {
117
129
  }
118
130
  await this.promptForKeyFile();
119
131
  },
132
+ async promptSaveBackup(env) {
133
+ const { projectDir } = configStore.getProjectInfo();
134
+ const keyFilePath = path.join(projectDir, "key.p12");
135
+ const { dagAddress, nodeId } = configStore.getProjectInfo();
136
+ const answer = await input({ default: 'y', message: 'Would you like to save a backup of the key file to your home directory? (y/n): ' });
137
+ if (answer.toLowerCase() === 'y') {
138
+ const homeKeyPath = path.join(os.homedir(), 'key.p12');
139
+ const homeKeyInfoPath = path.join(os.homedir(), 'key-info');
140
+ if (fs.existsSync(homeKeyPath)) {
141
+ const backupUniqueName = new Date().toISOString().replaceAll(':', '-');
142
+ const backupKeyName = `key-${backupUniqueName}.p12`;
143
+ const backupKeyPath = path.join(os.homedir(), backupKeyName);
144
+ fs.renameSync(homeKeyPath, backupKeyPath);
145
+ clm.postStep(`An existing key file was found in your home directory and has been renamed to ${chalk.cyan(backupKeyName)}`);
146
+ if (fs.existsSync(homeKeyInfoPath)) {
147
+ fs.renameSync(homeKeyInfoPath, path.join(os.homedir(), `key-info-${backupUniqueName}`));
148
+ }
149
+ }
150
+ fs.cpSync(keyFilePath, homeKeyPath);
151
+ fs.writeFileSync(path.join(os.homedir(), 'key-info'), getObjectToEnvContent({ ...env, CL_KEYSTORE: 'key.p12', CL_PASSWORD: '****', NODE_ADDRESS: dagAddress, NODE_ID: nodeId }));
152
+ clm.postStep(`A copy of the Key file has been saved to your home directory - ${chalk.cyan(homeKeyPath)}`);
153
+ }
154
+ },
120
155
  async showKeyFileInfo(prompt4ShowPassword = true) {
121
156
  clm.preStep('Current key file information:');
122
157
  const { dagAddress, nodeId } = configStore.getProjectInfo();
123
158
  configHelper.showEnvInfo('Node ID', nodeId);
124
159
  configHelper.showEnvInfo('DAG Address', dagAddress);
125
- const { CL_KEYALIAS, CL_KEYSTORE, CL_PASSWORD } = configStore.getEnvCommonInfo();
160
+ const { CL_KEYALIAS, CL_KEYSTORE, CL_PASSWORD } = configStore.getEnvInfo();
126
161
  configHelper.showEnvInfo('CL_KEYSTORE', CL_KEYSTORE || '');
127
162
  configHelper.showEnvInfo('CL_KEYALIAS', CL_KEYALIAS || '');
128
163
  configHelper.showEnvInfo('CL_PASSWORD', '*********');
@@ -1,10 +1,10 @@
1
1
  import { TessellationLayer } from "../types.js";
2
2
  export declare const projectHelper: {
3
3
  generateLayerEnvFiles(layers?: TessellationLayer[]): Promise<void>;
4
- importLayerEnvFiles(): Promise<void>;
5
- importNetworkEnvFiles(): Promise<void>;
4
+ importEnvFiles(): void;
6
5
  installEmbedded(name: string): Promise<void>;
7
6
  installFromGithub(_repo: string): Promise<never>;
8
7
  installHypergraph(): Promise<void>;
8
+ installProject(name: string, projectFolder: string): Promise<void>;
9
9
  selectProject(): Promise<void>;
10
10
  };
@@ -5,50 +5,46 @@ import path from "node:path";
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { clm } from "../clm.js";
7
7
  import { configStore } from "../config-store.js";
8
+ import { githubService } from "../services/github-service.js";
8
9
  import { configHelper } from "./config-helper.js";
9
10
  import { getLayerEnvFileContent } from "./env-templates.js";
10
- import { githubHelper } from "./github-helper.js";
11
11
  export const projectHelper = {
12
12
  async generateLayerEnvFiles(layers) {
13
13
  const { layersToRun, projectDir } = configStore.getProjectInfo();
14
- const { type } = configStore.getNetworkInfo();
15
- const commonInfo = configStore.getEnvCommonInfo();
14
+ const { type: network } = configStore.getNetworkInfo();
15
+ const envInfo = configStore.getEnvInfo();
16
+ const envNetworkInfo = configStore.getEnvNetworkInfo(network);
16
17
  layers = layers || layersToRun;
17
- for (const n of layers) {
18
- const filePath = path.join(projectDir, `${n}.env`);
19
- const envInfo = configStore.getEnvLayerInfo(n);
20
- const fileContents = getLayerEnvFileContent(n, type, commonInfo, envInfo);
18
+ for (const layer of layers) {
19
+ const filePath = path.join(projectDir, `${layer}.env`);
20
+ const envLayerInfo = configStore.getEnvLayerInfo(network, layer);
21
+ const fileContents = getLayerEnvFileContent(layer, { ...envInfo, ...envNetworkInfo, ...envLayerInfo });
21
22
  clm.debug(`Writing layer env file: ${filePath}`);
22
23
  fs.writeFileSync(filePath, fileContents);
23
24
  }
24
25
  },
25
- async importLayerEnvFiles() {
26
- const { projectDir } = configStore.getProjectInfo();
27
- const possibleLayers = ['gl0', 'gl1', 'ml0', 'cl1', 'dl1'];
28
- for (const n of possibleLayers) {
29
- const filePath = path.join(projectDir, 'layers', `${n}.env`);
30
- if (fs.existsSync(filePath)) {
31
- configStore.setEnvLayerInfo(n, configHelper.parseEnvFile(filePath));
32
- }
33
- }
34
- },
35
- async importNetworkEnvFiles() {
26
+ importEnvFiles() {
36
27
  const { projectDir } = configStore.getProjectInfo();
37
28
  const possibleNetworks = ['mainnet', 'testnet', 'integrationnet'];
29
+ const possibleLayers = ['gl0', 'gl1', 'ml0', 'cl1', 'dl1'];
38
30
  const supportedTypes = [];
39
- const networkEnvInfo = {};
40
- for (const n of possibleNetworks) {
41
- const filePath = path.join(projectDir, 'networks', `${n}.env`);
31
+ for (const network of possibleNetworks) {
32
+ const filePath = path.join(projectDir, 'networks', network, 'network.env');
42
33
  if (fs.existsSync(filePath)) {
43
- supportedTypes.push(n);
44
- networkEnvInfo[n] = configHelper.parseEnvFile(filePath);
34
+ supportedTypes.push(network);
35
+ configStore.setEnvNetworkInfo(network, configHelper.parseEnvFile(filePath));
36
+ }
37
+ for (const layer of possibleLayers) {
38
+ const filePath = path.join(projectDir, 'networks', network, `${layer}.env`);
39
+ if (fs.existsSync(filePath)) {
40
+ configStore.setEnvLayerInfo(network, layer, configHelper.parseEnvFile(filePath));
41
+ }
45
42
  }
46
43
  }
47
44
  if (supportedTypes.length === 0) {
48
45
  clm.error('No supported networks found in the project folder.');
49
46
  }
50
47
  configStore.setNetworkInfo({ supportedTypes });
51
- configStore.setNetworkEnvInfo(networkEnvInfo);
52
48
  // eslint-disable-next-line no-warning-comments
53
49
  // TODO: verify all required env variables are present
54
50
  },
@@ -57,10 +53,7 @@ export const projectHelper = {
57
53
  if (!fs.existsSync(projectFolder)) {
58
54
  clm.error(`Project folder not found: ${projectFolder}`);
59
55
  }
60
- await configStore.applyNewProjectStore(name);
61
- const { projectDir } = configStore.getProjectInfo();
62
- clm.debug(`Installing project from ${projectFolder} to ${projectDir}`);
63
- fs.cpSync(projectFolder, projectDir, { recursive: true });
56
+ await this.installProject(name, projectFolder);
64
57
  },
65
58
  // curl -s https://api.github.com/repos/Constellation-Labs/pacaswap-metagraph/releases/latest | jq -r '.assets[] | select(.name | contains("node-pilot"))'
66
59
  // use .tag_name for the release version
@@ -75,15 +68,21 @@ export const projectHelper = {
75
68
  fs.mkdirSync(path.join(gl0DataDir, 'incremental_snapshot'), { recursive: true });
76
69
  fs.mkdirSync(path.join(gl0DataDir, 'snapshot_info'));
77
70
  fs.mkdirSync(path.join(gl0DataDir, 'tmp'));
78
- // Set hypergraph layer defaults
79
- configStore.setEnvLayerInfo('gl0', {
80
- CL_CLI_HTTP_PORT: '9002', CL_DOCKER_JAVA_OPTS: '-Xms1024M -Xmx7G -Xss256K', CL_P2P_HTTP_PORT: '9001', CL_PUBLIC_HTTP_PORT: '9000'
81
- });
82
- configStore.setEnvLayerInfo('gl1', {
83
- CL_CLI_HTTP_PORT: '9102', CL_DOCKER_JAVA_OPTS: '-Xms1024M -Xmx3G -Xss256K', CL_P2P_HTTP_PORT: '9101', CL_PUBLIC_HTTP_PORT: '9100'
84
- });
85
- await this.importNetworkEnvFiles();
86
- await this.importLayerEnvFiles();
71
+ this.importEnvFiles();
72
+ },
73
+ async installProject(name, projectFolder) {
74
+ if (!configStore.hasProjects()) {
75
+ // On first install, copy scripts
76
+ const scriptsFolder = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../scripts`);
77
+ const projectDir = path.join(configStore.getAppDir(), 'scripts');
78
+ clm.debug(`Installing node pilot scripts from ${scriptsFolder} to ${projectDir}`);
79
+ fs.mkdirSync(projectDir, { recursive: true });
80
+ fs.cpSync(scriptsFolder, projectDir, { recursive: true });
81
+ }
82
+ await configStore.applyNewProjectStore(name);
83
+ const { projectDir } = configStore.getProjectInfo();
84
+ clm.debug(`Installing project from ${projectFolder} to ${projectDir}`);
85
+ fs.cpSync(projectFolder, projectDir, { recursive: true });
87
86
  },
88
87
  async selectProject() {
89
88
  // prompt user to install hypergraph or metagraph
@@ -124,7 +123,7 @@ export const projectHelper = {
124
123
  const m = repo.trim().match(ghRepoRegex);
125
124
  const userRepo = `${m[1]}/${m[2]}`; // owner/repo
126
125
  clm.preStep(`Installing from Github repository: ${chalk.cyan(userRepo)}`);
127
- if (await githubHelper.hasAssetInRelease('node-pilot', userRepo)) {
126
+ if (await githubService.hasAssetInRelease('node-pilot', userRepo)) {
128
127
  await this.installFromGithub(userRepo);
129
128
  }
130
129
  else {
@@ -1,5 +1,4 @@
1
1
  export declare const promptHelper: {
2
- configureAutoRestart(): Promise<void>;
3
2
  configureJavaMemoryArguments(): Promise<void>;
4
3
  doYouWishToContinue(defaultAnswer?: "n" | "y"): Promise<void>;
5
4
  selectLayers(): Promise<void>;