Skip to content

Commit

Permalink
feat: [cli] added support for backend if no config file found on init
Browse files Browse the repository at this point in the history
Signed-off-by: Miguel_LZPF <[email protected]>
  • Loading branch information
MiguelLZPF committed Apr 8, 2024
1 parent 53f1355 commit 75a1afa
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 45 deletions.
1 change: 1 addition & 0 deletions cli/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ build

report.json

.hsca-config*.yaml
hsca-config.yaml
./docs/*
20 changes: 20 additions & 0 deletions cli/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"license": "Apache-2.0",
"devDependencies": {
"@types/colors": "^1.2.1",
"@types/fs-extra": "^11.0.4",
"@types/inquirer": "^8.0.0",
"@types/jest": "^29.2.6",
"@types/node": "^18.11.18",
Expand Down Expand Up @@ -77,4 +78,4 @@
"tslib": "^2.4.1",
"typescript": "4.9.4"
}
}
}
65 changes: 65 additions & 0 deletions cli/src/app/service/configuration/BackendConfigurationService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
*
* Hedera Stablecoin CLI
*
* Copyright (C) 2023 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

import { DEFAULT_BACKEND_ENDPOINT } from '../../../core/Constants';
import { configurationService, language, utilsService } from '../../../index';
import IBackendConfig from '../../../domain/configuration/interfaces/BackendConfig';
import Service from '../Service';

export default class BackendConfigurationService extends Service {
constructor() {
super('Backend Configuration');
}

public async configureBackend(): Promise<IBackendConfig> {
const configuration = configurationService.getConfiguration();
let endpoint: URL | undefined;

// Try to get the endpoint up to 5 times
for (let tries = 0; tries < 5; tries++) {
try {
const answer = configuration.backend?.endpoint
? configuration.backend.endpoint
: await utilsService.defaultSingleAsk(
language.getText('configuration.askBackendUrl'),
DEFAULT_BACKEND_ENDPOINT,
);
endpoint = new URL(answer);
if (endpoint) break; // If we have a valid endpoint, break the loop
} catch (error) {
utilsService.showError(
`${error}\n${language.getText('general.incorrectParam')}`,
);
}
}

// If we still don't have a valid endpoint, use the default one
if (!endpoint) {
endpoint = new URL(DEFAULT_BACKEND_ENDPOINT);
}

// Update the configuration and return it
configuration.backend = {
endpoint: endpoint.toString(),
} as IBackendConfig;
configurationService.setConfiguration(configuration);
return configuration.backend;
}
}
22 changes: 11 additions & 11 deletions cli/src/app/service/configuration/ConfigurationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,26 +184,26 @@ export default class ConfigurationService extends Service {
console.dir(result, { depth: null });
}

/**
* Create default configuration file and override if exists
*/
public createDefaultConfiguration(path?: string): void {
try {
let defaultConfig: IConfiguration;
const defaultConfigPath = `${this.getGlobalPath()}/build/src/resources/config/${
this.configFileName
}`;
if (fs.existsSync(defaultConfigPath)) {
defaultConfig = yaml.load(fs.readFileSync(defaultConfigPath));
} else {
defaultConfig = yaml.load(
fs.readFileSync(`src/resources/config/${this.configFileName}`),
);
}
const fallbackConfigPath = `src/resources/config/${this.configFileName}`;

const configPath = fs.existsSync(defaultConfigPath)
? defaultConfigPath
: fallbackConfigPath;
const defaultConfig: IConfiguration = yaml.load(
fs.readFileSync(configPath, 'utf8'),
);

const filePath = path ?? this.getDefaultConfigurationPath();
this.path = filePath;

fs.ensureFileSync(filePath);
fs.writeFileSync(filePath, yaml.dump(defaultConfig), 'utf8');

this.setConfiguration(defaultConfig, filePath);
} catch (ex) {
utilsService.showError(ex);
Expand Down
36 changes: 26 additions & 10 deletions cli/src/app/service/configuration/SetConfigurationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*
*/

import fs from 'fs-extra';
import colors from 'colors';
import {
configurationService,
language,
Expand All @@ -26,20 +28,19 @@ import {
setMirrorNodeService,
setRPCService,
setFactoryService,
backendConfigurationService,
} from '../../../index.js';
import Service from '../Service.js';
import fs from 'fs-extra';
import { ZERO_ADDRESS } from '../../../core/Constants.js';
import { IAccountConfig } from '../../../domain/configuration/interfaces/IAccountConfig.js';
import { IConsensusNodeConfig } from '../../../domain/configuration/interfaces/IConsensusNodeConfig.js';
import { INetworkConfig } from '../../../domain/configuration/interfaces/INetworkConfig.js';
import { IMirrorsConfig } from 'domain/configuration/interfaces/IMirrorsConfig.js';
import { IRPCsConfig } from 'domain/configuration/interfaces/IRPCsConfig.js';
import { ZERO_ADDRESS } from '../../../core/Constants.js';
import { IMirrorsConfig } from '../../../domain/configuration/interfaces/IMirrorsConfig.js';
import { IRPCsConfig } from '../../../domain/configuration/interfaces/IRPCsConfig.js';
import { AccountType } from '../../../domain/configuration/interfaces/AccountType';
import { IPrivateKey } from '../../../domain/configuration/interfaces/IPrivateKey';
import { IFireblocksAccountConfig } from '../../../domain/configuration/interfaces/IFireblocksAccountConfig';
import { IDfnsAccountConfig } from '../../../domain/configuration/interfaces/IDfnsAccountConfig';
import colors from 'colors';

/**
* Set Configuration Service
Expand All @@ -59,7 +60,7 @@ export default class SetConfigurationService extends Service {
path?: string,
network?: string,
): Promise<void> {
utilsService.showMessage(language.getText('initialConfiguration.title'));
utilsService.showMessage(language.getText('configuration.initialTitle'));
await this.configurePath(path);
await this.configureDefaultNetwork(network);
await this.configureAccounts();
Expand Down Expand Up @@ -87,6 +88,14 @@ export default class SetConfigurationService extends Service {
);
await setRPCService.configureRPCs();
}
// Stablecoin Backend Configuration
const configBackend = await utilsService.defaultConfirmAsk(
language.getText('configuration.askConfigurateBackend'),
true,
);
if (configBackend) {
await backendConfigurationService.configureBackend();
}
}

/**
Expand Down Expand Up @@ -131,11 +140,14 @@ export default class SetConfigurationService extends Service {
}

/**
* Function to configure the default network
* Configures the default network for the application.
* If a network is provided, it sets it as the default network.
* If no network is provided, it prompts the user to select a network from the available options.
* If the selected network is a default network, it prompts the user to select a different network or create a custom one.
* Finally, it sets the selected network as the default network in the configuration and returns it.
*
* @param _network Network to use
*
* @returns The new default network
* @param _network (optional) The network to set as the default. If not provided, the user will be prompted to select a network.
* @returns A Promise that resolves to the selected network.
*/
public async configureDefaultNetwork(_network?: string): Promise<string> {
const networks = configurationService
Expand Down Expand Up @@ -428,6 +440,10 @@ export default class SetConfigurationService extends Service {
await this.manageAccountMenu();
}

/**
* Asks the user for the account type and returns the selected account type.
* @returns A Promise that resolves to the selected AccountType.
*/
public async askForAccountType(): Promise<AccountType> {
let accountType: string;
do {
Expand Down
22 changes: 2 additions & 20 deletions cli/src/core/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,6 @@
*
*/

/*
*
* Hedera Stablecoin SDK
*
* Copyright (C) 2023 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

export const ZERO_ADDRESS = '0.0.0';

export const MIRROR_NODE = 'MIRROR_NODE';
Expand All @@ -55,3 +35,5 @@ export const HEDERA_RPC_NAME = 'HASHIO';
export const HASHIO_RPC_TESTNET_URL = 'https://testnet.hashio.io/api';
export const HASHIO_RPC_PREVIEWNET_URL = 'https://previewnet.hashio.io/api';
export const HASHIO_RPC_MAINNET_URL = 'https://mainnet.hashio.io/api';

export const DEFAULT_BACKEND_ENDPOINT = 'http://localhost:3000';
4 changes: 4 additions & 0 deletions cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ import CommanderService from './app/service/commander/CommanderService.js';
import SetMirrorNodeService from './app/service/configuration/SetMirrorNodeService.js';
import SetRPCService from './app/service/configuration/SetRPCService.js';
import SetFactoryService from './app/service/configuration/SetFactoryService.js';
import BackendConfigurationService from './app/service/configuration/BackendConfigurationService.js';
import SetConfigurationService from './app/service/configuration/SetConfigurationService.js';

export const language: Language = new Language();
export const wizardService: WizardService = new WizardService();
export const networkWizardService: NetworkWizardService =
Expand All @@ -40,6 +42,8 @@ export const setMirrorNodeService: SetMirrorNodeService =
new SetMirrorNodeService();
export const setRPCService: SetRPCService = new SetRPCService();
export const setFactoryService: SetFactoryService = new SetFactoryService();
export const backendConfigurationService: BackendConfigurationService =
new BackendConfigurationService();
export const setConfigurationService: SetConfigurationService =
new SetConfigurationService();

Expand Down
6 changes: 3 additions & 3 deletions cli/src/resources/config/language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,8 @@ export const english = {
continue: '↩️ Press enter to continue',
backOption: backOption,
},
initialConfiguration: {
title: '\n\n\t\tHedera Stablecoin initial configuration\n',
},
configuration: {
initialTitle: '\n\n\t\tHedera Stablecoin configuration\n',
askPath: 'Write your config path',
askCreateConfig:
'No configuration file found at the specified path, would you like to create one? (y/n)',
Expand All @@ -82,6 +80,8 @@ export const english = {
'Do you want to config your factories? Check the documentation for more information : https://github.com/hashgraph/stablecoin-studio#deploying-the-stable-coin-factories',
askConfigurateDefaultMirrorsAndRPCs:
'Do you want to use default mirror node/JSON-RPC-Relay services? (y/n)',
askConfigurateBackend: 'Do you want to configure the backend? (y/n)',
askBackendUrl: 'Enter the backend url',
askNetworkAccount: 'Which network does this account belong to?',
askPrivateKeyType: 'Which type of private key will the account use?',
askAlias: 'Enter an alias for this account',
Expand Down

0 comments on commit 75a1afa

Please sign in to comment.