@constellation-network/node-pilot 0.18.0-testnet → 0.18.1-testnet
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -16
- package/dist/base-command.d.ts +1 -1
- package/dist/base-command.js +13 -4
- package/dist/checks/check-hardware.js +2 -2
- package/dist/checks/check-initial-setup.js +2 -1
- package/dist/checks/check-network.js +0 -7
- package/dist/checks/check-project.js +6 -4
- package/dist/clm.js +2 -2
- package/dist/commands/config/get.js +8 -0
- package/dist/commands/config/set.js +5 -1
- package/dist/commands/config.js +8 -0
- package/dist/commands/info.js +6 -0
- package/dist/commands/project.d.ts +12 -0
- package/dist/commands/project.js +46 -0
- package/dist/commands/restart.d.ts +2 -2
- package/dist/commands/restart.js +15 -16
- package/dist/commands/shutdown.js +2 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/config-store.d.ts +12 -20
- package/dist/config-store.js +9 -116
- package/dist/helpers/config-helper.js +2 -1
- package/dist/helpers/pilot-manager.d.ts +23 -0
- package/dist/helpers/pilot-manager.js +170 -0
- package/dist/helpers/project-helper.d.ts +3 -2
- package/dist/helpers/project-helper.js +39 -17
- package/dist/helpers/prompt-helper.d.ts +1 -0
- package/dist/helpers/prompt-helper.js +15 -3
- package/dist/helpers/service-log.js +2 -2
- package/dist/helpers/status-table.js +5 -4
- package/dist/services/cluster-service.d.ts +2 -1
- package/dist/services/cluster-service.js +28 -7
- package/dist/services/docker-service.js +3 -2
- package/dist/services/node-service.js +3 -2
- package/oclif.manifest.json +42 -13
- package/package.json +1 -1
- package/projects/hypergraph/docker-compose.yml +8 -4
- package/projects/hypergraph/networks/integrationnet/gl0.env +2 -1
- package/projects/hypergraph/networks/integrationnet/gl1.env +4 -3
- package/projects/hypergraph/networks/mainnet/gl0.env +2 -1
- package/projects/hypergraph/networks/mainnet/gl1.env +2 -1
- package/projects/hypergraph/networks/testnet/gl0.env +1 -0
- package/projects/hypergraph/networks/testnet/gl1.env +1 -0
- package/projects/hypergraph/scripts/install-dependencies.sh +2 -2
package/dist/config-store.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import { input } from "@inquirer/prompts";
|
|
2
1
|
import { JSONStorage } from "node-localstorage";
|
|
3
2
|
import fs from "node:fs";
|
|
4
|
-
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
3
|
import packageJson from '../package.json' with { type: 'json' };
|
|
7
|
-
import { clm } from "./clm.js";
|
|
8
4
|
const pilotReleaseInfo = { name: packageJson.name, version: packageJson.version };
|
|
9
5
|
class EmptyStorage extends JSONStorage {
|
|
10
6
|
constructor() { super("/tmp"); }
|
|
@@ -12,52 +8,7 @@ class EmptyStorage extends JSONStorage {
|
|
|
12
8
|
setItem(_key, _value) { }
|
|
13
9
|
}
|
|
14
10
|
class ConfigStore {
|
|
15
|
-
|
|
16
|
-
projectStore;
|
|
17
|
-
constructor() {
|
|
18
|
-
const appDir = path.join(os.homedir(), '.node-pilot');
|
|
19
|
-
if (!fs.existsSync(appDir)) {
|
|
20
|
-
fs.mkdirSync(path.join(appDir, 'logs'), { recursive: true });
|
|
21
|
-
}
|
|
22
|
-
this.pilotStore = new JSONStorage(path.join(appDir, 'config'));
|
|
23
|
-
const appInfo = this.pilotStore.getItem('pilot');
|
|
24
|
-
if (!appInfo) {
|
|
25
|
-
this.pilotStore.setItem('pilot', { appDir, project: 'undefined', projects: [], restarting: 0, running: [] });
|
|
26
|
-
}
|
|
27
|
-
const { project } = this.pilotStore.getItem('pilot');
|
|
28
|
-
this.projectStore = project === 'undefined' ? new EmptyStorage() : new JSONStorage(path.join(appDir, project, 'config'));
|
|
29
|
-
}
|
|
30
|
-
async applyNewProjectStore(name) {
|
|
31
|
-
const { appDir, projects } = this.pilotStore.getItem('pilot');
|
|
32
|
-
const projectDir = path.join(appDir, name);
|
|
33
|
-
if (projects.includes(name)) {
|
|
34
|
-
const answer = await input({ default: 'n', message: `Project ${name} already exists. Do you want to reinstall? (y/n):` });
|
|
35
|
-
if (answer === 'y') {
|
|
36
|
-
this.projectStore = new JSONStorage(path.join(projectDir, 'config'));
|
|
37
|
-
this.projectStore.clear();
|
|
38
|
-
fs.rmSync(projectDir, { force: true, recursive: true });
|
|
39
|
-
this.pilotStore.setItem('pilot', { appDir, project: name, projects });
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
clm.error(`Project ${name} already exists.`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
this.setPilotInfo({ project: name, projects: [...projects, name] });
|
|
47
|
-
}
|
|
48
|
-
fs.mkdirSync(path.join(projectDir, 'config'), { recursive: true });
|
|
49
|
-
this.projectStore = new JSONStorage(path.join(projectDir, 'config'));
|
|
50
|
-
this.setDockerEnvInfo({ DOCKER_IMAGE_VERSION: 'test' });
|
|
51
|
-
this.setProjectInfo({ name, projectDir });
|
|
52
|
-
}
|
|
53
|
-
getActiveProject() {
|
|
54
|
-
const { project } = this.pilotStore.getItem('pilot');
|
|
55
|
-
return project;
|
|
56
|
-
}
|
|
57
|
-
getAppDir() {
|
|
58
|
-
const { appDir } = this.pilotStore.getItem('pilot');
|
|
59
|
-
return appDir;
|
|
60
|
-
}
|
|
11
|
+
projectStore = new EmptyStorage();
|
|
61
12
|
getDockerEnvInfo() {
|
|
62
13
|
return this.projectStore.getItem('docker');
|
|
63
14
|
}
|
|
@@ -82,7 +33,7 @@ class ConfigStore {
|
|
|
82
33
|
return { CLI: layerInfo.CL_CLI_HTTP_PORT, P2P: layerInfo.CL_P2P_HTTP_PORT, PUBLIC: layerInfo.CL_PUBLIC_HTTP_PORT };
|
|
83
34
|
}
|
|
84
35
|
getNetworkInfo() {
|
|
85
|
-
return this.projectStore.getItem('network');
|
|
36
|
+
return this.projectStore.getItem('network') || {};
|
|
86
37
|
}
|
|
87
38
|
getPilotReleaseInfo() {
|
|
88
39
|
return pilotReleaseInfo;
|
|
@@ -90,45 +41,10 @@ class ConfigStore {
|
|
|
90
41
|
getProjectInfo() {
|
|
91
42
|
return this.projectStore.getItem('project') || {};
|
|
92
43
|
}
|
|
93
|
-
getProjects() {
|
|
94
|
-
const { projects } = this.pilotStore.getItem('pilot');
|
|
95
|
-
return projects;
|
|
96
|
-
}
|
|
97
|
-
getRunningProjects() {
|
|
98
|
-
const { running } = this.pilotStore.getItem('pilot');
|
|
99
|
-
return running;
|
|
100
|
-
}
|
|
101
|
-
getSystemInfo() {
|
|
102
|
-
return this.pilotStore.getItem('system');
|
|
103
|
-
}
|
|
104
44
|
hasProjectFlag(name) {
|
|
105
45
|
const flags = this.projectStore.getItem('flags') || {};
|
|
106
46
|
return flags[name] || false;
|
|
107
47
|
}
|
|
108
|
-
hasProjects() {
|
|
109
|
-
const { projects } = this.pilotStore.getItem('pilot');
|
|
110
|
-
return projects.length > 0;
|
|
111
|
-
}
|
|
112
|
-
isRestarting() {
|
|
113
|
-
const { restarting } = this.pilotStore.getItem('pilot');
|
|
114
|
-
if (restarting && restarting + 1000 * 60 * 5 < Date.now()) {
|
|
115
|
-
this.setIsRestarting(0);
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
return restarting > 0;
|
|
119
|
-
}
|
|
120
|
-
setActiveProject(name) {
|
|
121
|
-
const { appDir, project, projects } = this.pilotStore.getItem('pilot');
|
|
122
|
-
if (projects && projects.includes(name)) {
|
|
123
|
-
if (project === name)
|
|
124
|
-
return;
|
|
125
|
-
this.projectStore = new JSONStorage(path.join(appDir, name, 'config'));
|
|
126
|
-
this.setPilotInfo({ project: name });
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
throw new Error(`Project ${name} doesn't exist.`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
48
|
setClusterStats(info) {
|
|
133
49
|
const oldInfo = this.projectStore.getItem('cluster-stats');
|
|
134
50
|
this.projectStore.setItem('cluster-stats', { ...oldInfo, ...info });
|
|
@@ -155,13 +71,14 @@ class ConfigStore {
|
|
|
155
71
|
networks = {};
|
|
156
72
|
this.projectStore.setItem('network-env', { ...networks, [network]: { ...networks[network], ...info } });
|
|
157
73
|
}
|
|
158
|
-
setIsRestarting(val) {
|
|
159
|
-
this.setPilotInfo({ restarting: val });
|
|
160
|
-
}
|
|
161
74
|
setNetworkInfo(info) {
|
|
162
75
|
const oldInfo = this.projectStore.getItem('network');
|
|
163
76
|
this.projectStore.setItem('network', { ...oldInfo, ...info });
|
|
164
77
|
}
|
|
78
|
+
setProjectConfig(config) {
|
|
79
|
+
const projectExists = fs.existsSync(config);
|
|
80
|
+
this.projectStore = projectExists ? new JSONStorage(config) : new EmptyStorage();
|
|
81
|
+
}
|
|
165
82
|
setProjectFlag(name, value) {
|
|
166
83
|
const flags = this.projectStore.getItem('flags') || {};
|
|
167
84
|
flags[name] = value;
|
|
@@ -172,31 +89,6 @@ class ConfigStore {
|
|
|
172
89
|
const oldInfo = this.projectStore.getItem('project');
|
|
173
90
|
this.projectStore.setItem('project', { ...oldInfo, ...info });
|
|
174
91
|
}
|
|
175
|
-
setProjectStatusToRunning(isRunning) {
|
|
176
|
-
const { project, running } = this.pilotStore.getItem('pilot');
|
|
177
|
-
if (isRunning) {
|
|
178
|
-
if (running.includes(project))
|
|
179
|
-
return;
|
|
180
|
-
this.setPilotInfo({ running: [...running, project] });
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
if (!running.includes(project))
|
|
184
|
-
return;
|
|
185
|
-
running.splice(running.indexOf(project), 1);
|
|
186
|
-
this.setPilotInfo({ running });
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
setSystemInfo(info) {
|
|
190
|
-
const oldInfo = this.projectStore.getItem('system');
|
|
191
|
-
this.pilotStore.setItem('system', { ...oldInfo, ...info });
|
|
192
|
-
}
|
|
193
|
-
getPilotInfo() {
|
|
194
|
-
return this.pilotStore.getItem('pilot');
|
|
195
|
-
}
|
|
196
|
-
setPilotInfo(info) {
|
|
197
|
-
const oldInfo = this.pilotStore.getItem('pilot');
|
|
198
|
-
this.pilotStore.setItem('pilot', { ...oldInfo, ...info });
|
|
199
|
-
}
|
|
200
92
|
}
|
|
201
93
|
export const configStore = new ConfigStore();
|
|
202
94
|
export const envNames = {
|
|
@@ -214,7 +106,7 @@ export const networkEnvNames = {
|
|
|
214
106
|
CL_L0_PEER_HTTP_PORT: 1,
|
|
215
107
|
CL_L0_PEER_ID: 1,
|
|
216
108
|
CL_L0_PEER_P2P_PORT: 1,
|
|
217
|
-
CL_L0_TOKEN_IDENTIFIER: 1
|
|
109
|
+
CL_L0_TOKEN_IDENTIFIER: 1
|
|
218
110
|
};
|
|
219
111
|
// NETWORK LAYER
|
|
220
112
|
export const layerEnvNames = {
|
|
@@ -229,5 +121,6 @@ export const layerEnvNames = {
|
|
|
229
121
|
CL_L0_PEER_P2P_PORT: 1,
|
|
230
122
|
CL_LB: 1,
|
|
231
123
|
CL_P2P_HTTP_PORT: 1,
|
|
232
|
-
CL_PUBLIC_HTTP_PORT: 1
|
|
124
|
+
CL_PUBLIC_HTTP_PORT: 1,
|
|
125
|
+
CL_SOURCE_HTTP_PORT: 1
|
|
233
126
|
};
|
|
@@ -4,9 +4,10 @@ import fs from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { clm } from "../clm.js";
|
|
6
6
|
import { configStore } from "../config-store.js";
|
|
7
|
+
import { pilotManager } from "./pilot-manager.js";
|
|
7
8
|
export const configHelper = {
|
|
8
9
|
assertProject(prefix = '') {
|
|
9
|
-
if (
|
|
10
|
+
if (pilotManager.hasProjects())
|
|
10
11
|
return;
|
|
11
12
|
clm.error(prefix + 'Please create a new project first.');
|
|
12
13
|
},
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SystemInfo } from "../config-store.js";
|
|
2
|
+
export declare class PilotManager {
|
|
3
|
+
private pilotStore;
|
|
4
|
+
constructor();
|
|
5
|
+
applyNewProjectStore(name: string, type: 'hypergraph' | 'metagraph'): Promise<void>;
|
|
6
|
+
getActiveProject(): string;
|
|
7
|
+
getAppDir(): string;
|
|
8
|
+
getProjectDir(project: string): string;
|
|
9
|
+
getProjects(): string[];
|
|
10
|
+
getRunningProjects(): string[];
|
|
11
|
+
getSystemInfo(): SystemInfo;
|
|
12
|
+
hasProjects(): boolean;
|
|
13
|
+
isProjectInstalled(): boolean;
|
|
14
|
+
isRestarting(): boolean;
|
|
15
|
+
removeProject(name: string): Promise<void>;
|
|
16
|
+
setActiveProject(name: string, isNewProject?: boolean): void;
|
|
17
|
+
setIsRestarting(val: number): void;
|
|
18
|
+
setProjectStatusToRunning(isRunning: boolean): void;
|
|
19
|
+
setSystemInfo(info: Partial<SystemInfo>): void;
|
|
20
|
+
private getPilotInfo;
|
|
21
|
+
private setPilotInfo;
|
|
22
|
+
}
|
|
23
|
+
export declare const pilotManager: PilotManager;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { input } from "@inquirer/prompts";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { JSONStorage } from "node-localstorage";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { clm } from "../clm.js";
|
|
8
|
+
import { configStore } from "../config-store.js";
|
|
9
|
+
import { shellService } from "../services/shell-service.js";
|
|
10
|
+
import { promptHelper } from "./prompt-helper.js";
|
|
11
|
+
export class PilotManager {
|
|
12
|
+
pilotStore;
|
|
13
|
+
constructor() {
|
|
14
|
+
const appDir = path.join(os.homedir(), '.node-pilot');
|
|
15
|
+
if (!fs.existsSync(appDir)) {
|
|
16
|
+
fs.mkdirSync(path.join(appDir, 'logs'), { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
this.pilotStore = new JSONStorage(path.join(appDir, 'config'));
|
|
19
|
+
const appInfo = this.pilotStore.getItem('pilot');
|
|
20
|
+
if (!appInfo) {
|
|
21
|
+
this.pilotStore.setItem('pilot', { appDir, project: 'undefined', projects: [], restarting: 0, running: [] });
|
|
22
|
+
}
|
|
23
|
+
const { project } = this.pilotStore.getItem('pilot');
|
|
24
|
+
const projectPath = path.join(appDir, project, 'config');
|
|
25
|
+
configStore.setProjectConfig(projectPath);
|
|
26
|
+
}
|
|
27
|
+
async applyNewProjectStore(name, type) {
|
|
28
|
+
const { appDir, projects } = this.pilotStore.getItem('pilot');
|
|
29
|
+
const projectDir = path.join(appDir, name);
|
|
30
|
+
if (projects.includes(name)) {
|
|
31
|
+
if (fs.existsSync(projectDir)) {
|
|
32
|
+
const answer = await input({
|
|
33
|
+
default: 'n',
|
|
34
|
+
message: `Project ${name} already exists. Do you want to reinstall? (y/n):`
|
|
35
|
+
});
|
|
36
|
+
if (answer === 'y') {
|
|
37
|
+
// this.projectStore = new JSONStorage(path.join(projectDir,'config'));
|
|
38
|
+
// this.projectStore.clear();
|
|
39
|
+
fs.rmSync(projectDir, { force: true, recursive: true });
|
|
40
|
+
this.setPilotInfo({ project: name });
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
clm.error(`Project ${name} already exists.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.setPilotInfo({ project: name });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.setPilotInfo({ project: name, projects: [...projects, name] });
|
|
52
|
+
}
|
|
53
|
+
fs.mkdirSync(path.join(projectDir, 'config'), { recursive: true });
|
|
54
|
+
// this.projectStore = new JSONStorage(path.join(projectDir,'config'));
|
|
55
|
+
configStore.setProjectConfig(path.join(projectDir, 'config'));
|
|
56
|
+
configStore.setDockerEnvInfo({ DOCKER_IMAGE_VERSION: 'test' });
|
|
57
|
+
configStore.setProjectInfo({ name, projectDir, type });
|
|
58
|
+
}
|
|
59
|
+
getActiveProject() {
|
|
60
|
+
const { project } = this.pilotStore.getItem('pilot');
|
|
61
|
+
return project;
|
|
62
|
+
}
|
|
63
|
+
getAppDir() {
|
|
64
|
+
const { appDir } = this.pilotStore.getItem('pilot');
|
|
65
|
+
return appDir;
|
|
66
|
+
}
|
|
67
|
+
getProjectDir(project) {
|
|
68
|
+
const { appDir } = this.pilotStore.getItem('pilot');
|
|
69
|
+
const dir = path.join(appDir, project);
|
|
70
|
+
if (fs.existsSync(dir))
|
|
71
|
+
return dir;
|
|
72
|
+
throw new Error(`Project ${project} doesn't exist.`);
|
|
73
|
+
}
|
|
74
|
+
getProjects() {
|
|
75
|
+
const { projects } = this.pilotStore.getItem('pilot');
|
|
76
|
+
return projects;
|
|
77
|
+
}
|
|
78
|
+
getRunningProjects() {
|
|
79
|
+
const { running } = this.pilotStore.getItem('pilot');
|
|
80
|
+
return running;
|
|
81
|
+
}
|
|
82
|
+
getSystemInfo() {
|
|
83
|
+
return this.pilotStore.getItem('system');
|
|
84
|
+
}
|
|
85
|
+
hasProjects() {
|
|
86
|
+
const { projects } = this.pilotStore.getItem('pilot');
|
|
87
|
+
return projects.length > 0;
|
|
88
|
+
}
|
|
89
|
+
isProjectInstalled() {
|
|
90
|
+
const { appDir, projects } = this.pilotStore.getItem('pilot');
|
|
91
|
+
const activeProject = this.getActiveProject();
|
|
92
|
+
return projects.includes(activeProject) && fs.existsSync(path.join(appDir, activeProject));
|
|
93
|
+
}
|
|
94
|
+
isRestarting() {
|
|
95
|
+
const { restarting } = this.pilotStore.getItem('pilot');
|
|
96
|
+
if (restarting && restarting + 1000 * 60 * 5 < Date.now()) {
|
|
97
|
+
this.setIsRestarting(0);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return restarting > 0;
|
|
101
|
+
}
|
|
102
|
+
async removeProject(name) {
|
|
103
|
+
let { project, projects } = this.pilotStore.getItem('pilot');
|
|
104
|
+
projects.splice(projects.indexOf(name), 1);
|
|
105
|
+
if (projects.length === 0) {
|
|
106
|
+
clm.error(`Project ${name} cannot be removed as it is the only active project.`);
|
|
107
|
+
}
|
|
108
|
+
if (project === name) {
|
|
109
|
+
project = projects[0];
|
|
110
|
+
if (project) {
|
|
111
|
+
clm.postStep(`Active project has been changed to ${project}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const projectDir = this.getProjectDir(name);
|
|
116
|
+
clm.warn(`WARNING: This will remove all data and logs associated with the project ${chalk.cyan(name)}. Use with caution.`);
|
|
117
|
+
await promptHelper.doYouWishToContinue();
|
|
118
|
+
clm.warn('Running with "sudo" which may request your password...');
|
|
119
|
+
await shellService.runCommand(`sudo rm -rf ${projectDir}`);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
clm.warn(`Project ${name} not found.`);
|
|
123
|
+
}
|
|
124
|
+
this.setPilotInfo({ project, projects });
|
|
125
|
+
}
|
|
126
|
+
setActiveProject(name, isNewProject = false) {
|
|
127
|
+
const { appDir, project, projects } = this.pilotStore.getItem('pilot');
|
|
128
|
+
if (projects && projects.includes(name)) {
|
|
129
|
+
if (project === name)
|
|
130
|
+
return;
|
|
131
|
+
configStore.setProjectConfig(path.join(appDir, name, 'config'));
|
|
132
|
+
this.setPilotInfo({ project: name });
|
|
133
|
+
}
|
|
134
|
+
else if (isNewProject) {
|
|
135
|
+
this.setPilotInfo({ project: name });
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
throw new Error(`Project ${name} doesn't exist.`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
setIsRestarting(val) {
|
|
142
|
+
this.setPilotInfo({ restarting: val });
|
|
143
|
+
}
|
|
144
|
+
setProjectStatusToRunning(isRunning) {
|
|
145
|
+
const { project, running } = this.pilotStore.getItem('pilot');
|
|
146
|
+
if (isRunning) {
|
|
147
|
+
if (running.includes(project))
|
|
148
|
+
return;
|
|
149
|
+
this.setPilotInfo({ running: [...running, project] });
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
if (!running.includes(project))
|
|
153
|
+
return;
|
|
154
|
+
running.splice(running.indexOf(project), 1);
|
|
155
|
+
this.setPilotInfo({ running });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
setSystemInfo(info) {
|
|
159
|
+
const oldInfo = this.pilotStore.getItem('system');
|
|
160
|
+
this.pilotStore.setItem('system', { ...oldInfo, ...info });
|
|
161
|
+
}
|
|
162
|
+
getPilotInfo() {
|
|
163
|
+
return this.pilotStore.getItem('pilot');
|
|
164
|
+
}
|
|
165
|
+
setPilotInfo(info) {
|
|
166
|
+
const oldInfo = this.pilotStore.getItem('pilot');
|
|
167
|
+
this.pilotStore.setItem('pilot', { ...oldInfo, ...info });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
export const pilotManager = new PilotManager();
|
|
@@ -3,12 +3,13 @@ export declare const projectHelper: {
|
|
|
3
3
|
cleanup(layers: TessellationLayer[], deleteData: boolean, deleteLogs: boolean, deleteJars: boolean): Promise<void>;
|
|
4
4
|
generateLayerEnvFiles(layers?: TessellationLayer[]): Promise<void>;
|
|
5
5
|
importEnvFiles(): void;
|
|
6
|
-
installEmbedded(
|
|
6
|
+
installEmbedded(embeddedName: string, projectName: string, projectType: "hypergraph" | "metagraph"): Promise<void>;
|
|
7
7
|
installFromGithub(_repo: string): Promise<never>;
|
|
8
8
|
installHypergraph(): Promise<void>;
|
|
9
|
-
installProject(name: string, projectFolder: string): Promise<void>;
|
|
9
|
+
installProject(name: string, type: "hypergraph" | "metagraph", projectFolder: string): Promise<void>;
|
|
10
10
|
prepareDataFolder(): void;
|
|
11
11
|
selectProject(): Promise<void>;
|
|
12
|
+
updateDockerEnv(): void;
|
|
12
13
|
upgradeEmbedded(name: string): void;
|
|
13
14
|
upgradeHypergraph(): void;
|
|
14
15
|
upgradeProject(name: string, projectFolder: string): void;
|
|
@@ -9,6 +9,7 @@ import { githubService } from "../services/github-service.js";
|
|
|
9
9
|
import { shellService } from "../services/shell-service.js";
|
|
10
10
|
import { configHelper } from "./config-helper.js";
|
|
11
11
|
import { getLayerEnvFileContent } from "./env-templates.js";
|
|
12
|
+
import { pilotManager } from "./pilot-manager.js";
|
|
12
13
|
import { promptHelper } from "./prompt-helper.js";
|
|
13
14
|
export const projectHelper = {
|
|
14
15
|
async cleanup(layers, deleteData, deleteLogs, deleteJars) {
|
|
@@ -73,12 +74,12 @@ export const projectHelper = {
|
|
|
73
74
|
// eslint-disable-next-line no-warning-comments
|
|
74
75
|
// TODO: verify all required env variables are present
|
|
75
76
|
},
|
|
76
|
-
async installEmbedded(
|
|
77
|
-
const projectFolder = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../projects/${
|
|
77
|
+
async installEmbedded(embeddedName, projectName, projectType) {
|
|
78
|
+
const projectFolder = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../projects/${embeddedName}`);
|
|
78
79
|
if (!fs.existsSync(projectFolder)) {
|
|
79
80
|
clm.error(`Project folder not found: ${projectFolder}`);
|
|
80
81
|
}
|
|
81
|
-
await this.installProject(
|
|
82
|
+
await this.installProject(projectName, projectType, projectFolder);
|
|
82
83
|
// Set the project version to match the latest Pilot version. This prevents previous migration scripts from running.
|
|
83
84
|
configStore.setProjectInfo({ version: configStore.getPilotReleaseInfo().version });
|
|
84
85
|
},
|
|
@@ -88,28 +89,21 @@ export const projectHelper = {
|
|
|
88
89
|
throw new Error('installFromGithub - Not implemented');
|
|
89
90
|
},
|
|
90
91
|
async installHypergraph() {
|
|
91
|
-
|
|
92
|
+
const name = pilotManager.getActiveProject() || 'hypergraph';
|
|
93
|
+
await this.installEmbedded('hypergraph', name, 'hypergraph');
|
|
92
94
|
this.prepareDataFolder();
|
|
93
|
-
// const {projectDir} = configStore.getProjectInfo();
|
|
94
|
-
// const {platform} = configStore.getSystemInfo();
|
|
95
|
-
//
|
|
96
|
-
// if (platform === 'linux') {
|
|
97
|
-
// const layerDir = path.join(projectDir,'gl0');
|
|
98
|
-
// // set permission for group "docker" on the layer folder and any subfolders created later
|
|
99
|
-
// await shellService.runCommand(`sudo setfacl -Rm g:docker:rwX -dm g:docker:rwX ${layerDir}`)
|
|
100
|
-
// }
|
|
101
95
|
this.importEnvFiles();
|
|
102
96
|
},
|
|
103
|
-
async installProject(name, projectFolder) {
|
|
104
|
-
if (!
|
|
97
|
+
async installProject(name, type, projectFolder) {
|
|
98
|
+
if (!pilotManager.hasProjects()) {
|
|
105
99
|
// On first install, copy scripts
|
|
106
100
|
const scriptsFolder = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../scripts`);
|
|
107
|
-
const projectDir = path.join(
|
|
101
|
+
const projectDir = path.join(pilotManager.getAppDir(), 'scripts');
|
|
108
102
|
clm.debug(`Installing node pilot scripts from ${scriptsFolder} to ${projectDir}`);
|
|
109
103
|
fs.mkdirSync(projectDir, { recursive: true });
|
|
110
104
|
fs.cpSync(scriptsFolder, projectDir, { recursive: true });
|
|
111
105
|
}
|
|
112
|
-
await
|
|
106
|
+
await pilotManager.applyNewProjectStore(name, type);
|
|
113
107
|
const { projectDir } = configStore.getProjectInfo();
|
|
114
108
|
clm.debug(`Installing project from ${projectFolder} to ${projectDir}`);
|
|
115
109
|
fs.cpSync(projectFolder, projectDir, { recursive: true });
|
|
@@ -146,7 +140,7 @@ export const projectHelper = {
|
|
|
146
140
|
});
|
|
147
141
|
const ghRepoRegex = /^https?:\/\/(?:www\.)?github\.com\/([A-Za-z0-9](?:-?[A-Za-z0-9]){0,38})\/([A-Za-z0-9._-]+)(?:\.git)?\/?$/;
|
|
148
142
|
if (project === 'dor') {
|
|
149
|
-
await this.installEmbedded('dor');
|
|
143
|
+
await this.installEmbedded('dor', 'dor', 'metagraph');
|
|
150
144
|
}
|
|
151
145
|
else if (project === 'custom') {
|
|
152
146
|
let repo = await input({
|
|
@@ -173,6 +167,33 @@ export const projectHelper = {
|
|
|
173
167
|
}
|
|
174
168
|
}
|
|
175
169
|
},
|
|
170
|
+
updateDockerEnv() {
|
|
171
|
+
const { type: network } = configStore.getNetworkInfo();
|
|
172
|
+
let CL_GL0_PUBLIC_PORT = '';
|
|
173
|
+
let CL_GL0_P2P_PORT = '';
|
|
174
|
+
let CL_GL1_PUBLIC_PORT = '';
|
|
175
|
+
let CL_GL1_P2P_PORT = '';
|
|
176
|
+
const { layersToRun } = configStore.getProjectInfo();
|
|
177
|
+
for (const layer of layersToRun) {
|
|
178
|
+
const info = configStore.getEnvLayerInfo(network, layer);
|
|
179
|
+
switch (layer) {
|
|
180
|
+
case 'gl0': {
|
|
181
|
+
CL_GL0_P2P_PORT = info.CL_P2P_HTTP_PORT;
|
|
182
|
+
CL_GL0_PUBLIC_PORT = info.CL_PUBLIC_HTTP_PORT;
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case 'gl1': {
|
|
186
|
+
CL_GL1_P2P_PORT = info.CL_P2P_HTTP_PORT;
|
|
187
|
+
CL_GL1_PUBLIC_PORT = info.CL_PUBLIC_HTTP_PORT;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
configStore.setDockerEnvInfo({
|
|
193
|
+
CL_GL0_P2P_PORT, CL_GL0_PUBLIC_PORT,
|
|
194
|
+
CL_GL1_P2P_PORT, CL_GL1_PUBLIC_PORT
|
|
195
|
+
});
|
|
196
|
+
},
|
|
176
197
|
upgradeEmbedded(name) {
|
|
177
198
|
const projectFolder = path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../projects/${name}`);
|
|
178
199
|
if (!fs.existsSync(projectFolder)) {
|
|
@@ -183,6 +204,7 @@ export const projectHelper = {
|
|
|
183
204
|
upgradeHypergraph() {
|
|
184
205
|
this.upgradeEmbedded('hypergraph');
|
|
185
206
|
this.importEnvFiles();
|
|
207
|
+
this.updateDockerEnv();
|
|
186
208
|
},
|
|
187
209
|
upgradeProject(name, projectFolder) {
|
|
188
210
|
const { projectDir } = configStore.getProjectInfo();
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
import { checkbox, input, select } from "@inquirer/prompts";
|
|
1
|
+
import { checkbox, input, number, select } from "@inquirer/prompts";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { clm } from "../clm.js";
|
|
4
4
|
import { configStore } from "../config-store.js";
|
|
5
5
|
import { dockerService } from "../services/docker-service.js";
|
|
6
6
|
import { nodeService } from "../services/node-service.js";
|
|
7
7
|
export const promptHelper = {
|
|
8
|
+
async configurePorts() {
|
|
9
|
+
const defaults = { cl1: [9300, 9301], dl1: [9400, 9401], gl0: [9000, 9001], gl1: [9100, 9101], ml0: [9200, 9201] };
|
|
10
|
+
const { layersToRun } = configStore.getProjectInfo();
|
|
11
|
+
const { type: network } = configStore.getNetworkInfo();
|
|
12
|
+
for (const layer of layersToRun) {
|
|
13
|
+
// eslint-disable-next-line no-await-in-loop
|
|
14
|
+
const port1 = await number({ default: defaults[layer][0], message: `${layer} Public Port:`, required: true, validate: v => v !== undefined && v > 0 && v <= 65_535 });
|
|
15
|
+
// eslint-disable-next-line no-await-in-loop
|
|
16
|
+
const port2 = await number({ default: defaults[layer][1], message: `${layer} P2P Port:`, required: true, validate: v => v !== undefined && v > 0 && v <= 65_535 });
|
|
17
|
+
configStore.setEnvLayerInfo(network, layer, { CL_P2P_HTTP_PORT: port2.toString(), CL_PUBLIC_HTTP_PORT: port1.toString() });
|
|
18
|
+
}
|
|
19
|
+
},
|
|
8
20
|
async confirmPrompt(msg) {
|
|
9
21
|
const result = await input({
|
|
10
22
|
default: 'y',
|
|
@@ -34,8 +46,8 @@ export const promptHelper = {
|
|
|
34
46
|
}
|
|
35
47
|
},
|
|
36
48
|
async selectLayers() {
|
|
37
|
-
const { name } = configStore.getProjectInfo();
|
|
38
|
-
const choices =
|
|
49
|
+
const { name, type } = configStore.getProjectInfo();
|
|
50
|
+
const choices = type === 'hypergraph' ? ['gl0', 'gl1'] : ['ml0', 'cl1', 'dl1'];
|
|
39
51
|
const result = await checkbox({ choices, message: `Select network layers to run for ${chalk.cyan(name)}:`, validate: v => v.length > 0 });
|
|
40
52
|
configStore.setProjectInfo({ layersToRun: result });
|
|
41
53
|
},
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { pilotManager } from "./pilot-manager.js";
|
|
4
4
|
export const serviceLog = {
|
|
5
5
|
error(s) {
|
|
6
6
|
this.log(s);
|
|
7
7
|
},
|
|
8
8
|
log(s) {
|
|
9
|
-
const appDir =
|
|
9
|
+
const appDir = pilotManager.getAppDir();
|
|
10
10
|
const logFile = path.join(appDir, 'logs', 'service.log');
|
|
11
11
|
fs.appendFileSync(logFile, s + '\n');
|
|
12
12
|
},
|
|
@@ -5,6 +5,7 @@ import os from "node:os";
|
|
|
5
5
|
import ttyTable from "tty-table";
|
|
6
6
|
import { clm } from "../clm.js";
|
|
7
7
|
import { configStore } from "../config-store.js";
|
|
8
|
+
import { pilotManager } from "./pilot-manager.js";
|
|
8
9
|
import { formatTimeAgo, glHeader1, glHeader2, statusTableHeader } from "./status-table-helper.js";
|
|
9
10
|
export class StatusTable {
|
|
10
11
|
alreadyRendered = false;
|
|
@@ -35,21 +36,21 @@ export class StatusTable {
|
|
|
35
36
|
}
|
|
36
37
|
getProjectInfo() {
|
|
37
38
|
const appPath = os.homedir() + '/.node-pilot';
|
|
38
|
-
const activeProject =
|
|
39
|
-
const projects =
|
|
39
|
+
const activeProject = pilotManager.getActiveProject();
|
|
40
|
+
const projects = pilotManager.getRunningProjects();
|
|
40
41
|
if (!activeProject || projects.length === 0) {
|
|
41
42
|
clm.error("No projects are running.");
|
|
42
43
|
}
|
|
43
44
|
const info = [];
|
|
44
45
|
for (const project of projects) {
|
|
45
|
-
|
|
46
|
+
pilotManager.setActiveProject(project);
|
|
46
47
|
const { layersToRun } = configStore.getProjectInfo();
|
|
47
48
|
const { type: network } = configStore.getNetworkInfo();
|
|
48
49
|
for (const layer of layersToRun) {
|
|
49
50
|
info.push({ layer, network, path: `${appPath}/${project}/${layer}/data/health-check/node`, project });
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
+
pilotManager.setActiveProject(activeProject);
|
|
53
54
|
return info;
|
|
54
55
|
}
|
|
55
56
|
async monitorNarrow() {
|
|
@@ -10,8 +10,9 @@ export declare const clusterService: {
|
|
|
10
10
|
getSourceNodeInfo(layer: TessellationLayer): Promise<NodeInfo>;
|
|
11
11
|
getSourceNodeLatestOrdinal(layer: TessellationLayer): Promise<number>;
|
|
12
12
|
getSourceNodeOrdinalHash(layer: TessellationLayer, ordinal: number): Promise<string>;
|
|
13
|
-
makeClusterRequestGet(path: string, layer?: TessellationLayer): Promise<any>;
|
|
13
|
+
makeClusterRequestGet(path: string, layer?: TessellationLayer, params?: string): Promise<any>;
|
|
14
14
|
makeClusterRequestPost(path: string, body: string, layer?: TessellationLayer): Promise<any>;
|
|
15
|
+
makeRandomSourceNodeRequest(path: string, layer: TessellationLayer): Promise<any>;
|
|
15
16
|
makeSourceNodeRequest(path: string, layer: TessellationLayer): Promise<any>;
|
|
16
17
|
postNodeParams(body: string, layer?: TessellationLayer): Promise<string>;
|
|
17
18
|
};
|