diff --git a/packages/contentstack-config/src/commands/config/set/rate-limit.ts b/packages/contentstack-config/src/commands/config/set/rate-limit.ts new file mode 100644 index 0000000000..ab6d503b60 --- /dev/null +++ b/packages/contentstack-config/src/commands/config/set/rate-limit.ts @@ -0,0 +1,89 @@ +import { flags, isAuthenticated, FlagInput, managementSDKClient, cliux } from '@contentstack/cli-utilities'; +import { RateLimitHandler } from '../../../utils/rate-limit-handler'; +import { BaseCommand } from '../../../base-command'; +import { askOrgID } from '../../../utils/interactive'; +import { SetRateLimitConfig } from '../../../interfaces'; +import { limitNamesConfig } from '../../../utils/common-utilities'; + +export default class RateLimitSetCommand extends BaseCommand { + static description = 'Set rate-limit for CLI'; + + static flags: FlagInput = { + org: flags.string({ + description: 'Provide the organization UID', + }), + + utilize: flags.string({ + description: 'Provide the utilization percentages for rate limit, separated by commas', + default: '50', + }), + + 'limit-name': flags.string({ + description: "[Optional] Provide the limit names separated by commas ['limit', 'getLimit', 'bulkLimit']", + multiple: true, + }), + + default: flags.boolean({ + default: false, + description: 'Reset to default rate limit', + }), + }; + + static examples = [ + '$ csdx config:set:rate-limit --org <>', + '$ csdx config:set:rate-limit --org <> --utilize 70,80 --limit-name getLimit,limit', + '$ csdx config:set:rate-limit --org <> --default', + ]; + + public async run(): Promise { + if (!isAuthenticated()) { + const err = { errorMessage: 'You are not logged in. Please login with command $ csdx auth:login' }; + cliux.print(err.errorMessage, { color: 'red' }); + this.exit(1); + } + + const { flags } = await this.parse(RateLimitSetCommand); + let { org, utilize, 'limit-name': limitName } = flags; + const config: SetRateLimitConfig = { org: '', limitName: limitNamesConfig }; + + if (!org) { + org = await askOrgID(); + } + config.org = org; + config.default = flags.default; + if (utilize) { + const utilizeValues = utilize?.split(',')?.map((u: string) => Number(u.trim())); + if (utilizeValues.some((u: number) => isNaN(u) || u < 0 || u > 100)) { + cliux.error('Utilize percentages must be numbers between 0 and 100.'); + return; + } + if (limitName?.length > 0 && limitName[0]?.split(',')?.length !== utilizeValues.length) { + cliux.error('The number of utilization percentages must match the number of limit names provided.'); + return; + } else { + config.utilize = utilize.split(',').map((v: string) => v.trim()); + } + } + + if (limitName) { + const invalidLimitNames = limitName[0].split(',').map((name: string) => name.trim()); + + if (!limitNamesConfig.includes(invalidLimitNames)) { + cliux.error(`Invalid limit names provided: ${invalidLimitNames.join(', ')}`); + return; + } else { + config['limit-name'] = limitName[0].split(',').map((n) => n.trim()); + } + } + + const limitHandler = new RateLimitHandler(); + const managementAPIClient = await managementSDKClient(config); + limitHandler.setClient(managementAPIClient); + cliux.success(`Rate limit has been set successfully for org: ${config.org}`); + try { + await limitHandler.setRateLimit(config); + } catch (error) { + cliux.error(`Error: Something went wrong while setting rate limit for org: ${org}`, error); + } + } +} diff --git a/packages/contentstack-config/src/interfaces/index.ts b/packages/contentstack-config/src/interfaces/index.ts index d33b7010df..37cfcf5a0b 100644 --- a/packages/contentstack-config/src/interfaces/index.ts +++ b/packages/contentstack-config/src/interfaces/index.ts @@ -20,7 +20,6 @@ export interface Region { launchHubUrl: string; } - export interface RateLimitConfig { getLimit?: { value: number; @@ -34,4 +33,11 @@ export interface RateLimitConfig { value: number; utilize: number; }; -} \ No newline at end of file +} + +export interface SetRateLimitConfig { + org: string; + utilize?: number; + limitName?: string[]; + default?: boolean; +} diff --git a/packages/contentstack-config/src/utils/common-utilities.ts b/packages/contentstack-config/src/utils/common-utilities.ts new file mode 100644 index 0000000000..1dcead8f66 --- /dev/null +++ b/packages/contentstack-config/src/utils/common-utilities.ts @@ -0,0 +1,7 @@ +export const limitNamesConfig = ['getLimit', 'limit', 'bulkLimit']; + +export const defaultRalteLimitConfig = { + getLimit: { value: 10, utilize: 50 }, + limit: { value: 10, utilize: 50 }, + bulkLimit: { value: 1, utilize: 50 }, +}; diff --git a/packages/contentstack-config/src/utils/rate-limit-handler.ts b/packages/contentstack-config/src/utils/rate-limit-handler.ts new file mode 100644 index 0000000000..1a618d4262 --- /dev/null +++ b/packages/contentstack-config/src/utils/rate-limit-handler.ts @@ -0,0 +1,52 @@ +import { cliux, configHandler } from '@contentstack/cli-utilities'; +import { limitNamesConfig, defaultRalteLimitConfig } from '../utils/common-utilities'; + +let client: any; + +export class RateLimitHandler { + setClient(managementSDKClient) { + client = managementSDKClient; + } + + async setRateLimit(config) { + const rateLimit = configHandler.get('rateLimit'); + rateLimit.default = { ...defaultRalteLimitConfig }; + + if (config.default) { + rateLimit[config.org] = { ...defaultRalteLimitConfig }; + configHandler.set('rateLimit', rateLimit); + cliux.success(`Rate limit reset to default for org: ${config.org}`); + return; + } + + if (!rateLimit[config.org]) { + rateLimit[config.org] = { ...rateLimit.default }; + } + const limitNames = Array.isArray(config['limit-name']) ? config['limit-name'] : []; + const utilizeValues = Array.isArray(config.utilize) ? config.utilize.map((v) => Number(v)) : []; + + try { + const organizations = await client.organization(config.org).fetch({ include_plan: true }); + const features = organizations.plan?.features || []; + + const limitsToUpdate = { ...rateLimit[config.org] }; + + limitNames.forEach((limitName, index) => { + if (limitNamesConfig.includes(limitName)) { + const feature = features.find((f: { uid: string }) => f.uid === limitName); + if (feature) { + limitsToUpdate[limitName] = { + value: rateLimit[config.org][limitName]?.value || rateLimit.default[limitName]?.value, + utilize: utilizeValues[index] || Number(config.utilize[0]), + }; + } + } + }); + + rateLimit[config.org] = limitsToUpdate; + configHandler.set('rateLimit', rateLimit); + } catch (error) { + cliux.error(`Error: Unable to set the rate limit`, error?.errorMessage || error?.message || error); + } + } +}