@apistudio/apim-cli
Version:
CLI for API Management Products
215 lines (175 loc) • 6.79 kB
text/typescript
import path from 'path';
import envPaths from 'env-paths';
import { GatewayResponseAPI } from '../../model/studio/deploy-response-model.js';
import { constructKey } from '../../helpers/apim/test-helper.js';
import { showError, showInfo } from '../../helpers/common/message-helper.js';
import { COMMA, CONFIG_DIRECTORY_NAME, CONFIG_FILE_NAME } from '../../constants/app-constants.js';
import { ALL_ENDPOINTS_FETCHED_FROM_STORE,
APPEND_ENDPOINTS_FAILED, CONFIG, CONFIG_FILE_CREATED,
CONFIG_FILE_CREATION_FAILED,
DEPLOYMENT_DATA_UPDATED,
FAILED_TO_SET_ENDPOINT,
NO_DATA_TO_PROCESS,
NO_ENDPOINTS_IN_STORE,
NO_ENDPOINTS_STORE_CONFIGURED,
NO_UPDATES_NEEDED,
READ_CURRENT_ENDPOINTS_FAILED,
SOME_ENDPOINTS_MISSING_FROM_STORE,
UPDATE_ENDPOINTS_FAILED } from '../../constants/message-constants.js';
import { checkFileExists,
ensureDirectoryExists,
readJsonFromFile,
writeJsonToFile } from '../../helpers/common/fs-helper.js';
import { DebugManager } from '../../debug/debug-manager.js';
interface Deployment {
api: string;
endpoints: string[];
}
export interface GatewayEndpointJson {
deployments: Deployment[];
}
const logIfDebug = (logFn: Function, message: string) => {
if (DebugManager.getInstance().isDebugEnabled()) {
logFn(CONFIG + message);
}
};
const createConfig = async (): Promise<void> => {
const filePath = getConfigFilePath();
try {
await ensureDirectoryExists(path.dirname(filePath));
if (!await checkFileExists(filePath)) {
await writeJsonToFile(filePath, { deployments: [] }, {spaces: 2});
logIfDebug(showInfo, CONFIG_FILE_CREATED); }
} catch (error) {
logIfDebug(showError, `${CONFIG_FILE_CREATION_FAILED} ${(error as Error).message}`);
}
};
const getConfigFilePath = (): string => {
const paths = envPaths(CONFIG_DIRECTORY_NAME);
return path.join(paths.config, CONFIG_FILE_NAME);
};
const formatGatewayResponse = (response: GatewayResponseAPI[]): Deployment[] => {
return response.map(apiResponse => ({
api: constructKey(apiResponse),
endpoints: apiResponse.gatewayEndpoints
}));
};
const getCurrentEndpoints = async (): Promise<GatewayEndpointJson> => {
const filePath = getConfigFilePath();
let currentData: GatewayEndpointJson = { deployments: [] };
try {
if (await checkFileExists(filePath)) {
currentData = await readJsonFromFile(filePath) as GatewayEndpointJson;
}
} catch (error) {
logIfDebug(showError, `${READ_CURRENT_ENDPOINTS_FAILED} ${(error as Error).message}`);
}
return currentData;
};
const updateEndpoints = async (formattedResponse: GatewayEndpointJson): Promise<void> => {
const filePath = getConfigFilePath();
try {
await ensureDirectoryExists(path.dirname(filePath));
await writeJsonToFile(filePath, formattedResponse, { spaces: 2 });
logIfDebug(showInfo, DEPLOYMENT_DATA_UPDATED);
} catch (error) {
logIfDebug(showError, `${UPDATE_ENDPOINTS_FAILED} ${(error as Error).message}`);
}
};
const compareEndpoints = (endpoints1: string[], endpoints2: string[]): boolean => {
const sortedEndpoints1 = [...endpoints1].sort();
const sortedEndpoints2 = [...endpoints2].sort();
if (sortedEndpoints1.length !== sortedEndpoints2.length)
{
return false;
}
return sortedEndpoints1.every((endpoint, index) => endpoint === sortedEndpoints2[index]);
};
const overwriteEndpoints = async (formattedResponse: GatewayEndpointJson): Promise<void> => {
try {
const currentData = await getCurrentEndpoints();
const updatesNeeded = formattedResponse.deployments.some(deployment => {
const existingDeployment = currentData.deployments.find(d => d.api === deployment.api);
return existingDeployment && !compareEndpoints(existingDeployment.endpoints, deployment.endpoints);
});
if (updatesNeeded) {
await updateEndpoints(formattedResponse);
} else {
logIfDebug(showInfo, NO_UPDATES_NEEDED);
}
} catch (error) {
logIfDebug(showError, `${UPDATE_ENDPOINTS_FAILED} ${(error as Error).message}`);
}
};
const appendEndpoints = async (newDeployments: Deployment[]): Promise<void> => {
const filePath = getConfigFilePath();
try {
const currentData = await getCurrentEndpoints();
const deploymentsMap = new Map<string, Deployment>();
currentData.deployments.forEach(deployment => {
deploymentsMap.set(deployment.api, deployment);
});
newDeployments.forEach(deployment => {
deploymentsMap.set(deployment.api, deployment);
});
currentData.deployments = Array.from(deploymentsMap.values());
await writeJsonToFile(filePath, currentData, { spaces: 2 });
logIfDebug(showInfo, DEPLOYMENT_DATA_UPDATED);
} catch (error) {
logIfDebug(showError, `${APPEND_ENDPOINTS_FAILED} ${(error as Error).message}`);
}
};
const setGatewayEndpoint = async (response: GatewayResponseAPI[]): Promise<void> => {
const formattedResponse: GatewayEndpointJson = { deployments: formatGatewayResponse(response) };
if (formattedResponse.deployments.length === 0) {
logIfDebug(showError, NO_DATA_TO_PROCESS);
return;
}
const filePath = getConfigFilePath();
try {
if (!await checkFileExists(filePath)) {
await createConfig();
}
const currentData = await getCurrentEndpoints();
const existingApis = currentData.deployments.map(deployment => deployment.api);
const newDeployments = formattedResponse.deployments.filter(deployment => !existingApis.includes(deployment.api));
await overwriteEndpoints(formattedResponse);
if (newDeployments.length > 0) {
await appendEndpoints(newDeployments);
}
} catch (error) {
logIfDebug(showError, `${FAILED_TO_SET_ENDPOINT} ${(error as Error).message}`);
}
};
const getGatewayEndpoints = async (apiString: string): Promise<{ foundEndpoints: Record<string, string[]>; notFoundApis: string } | null> => {
const filePath = getConfigFilePath();
if (!await checkFileExists(filePath)) {
logIfDebug(showInfo, NO_ENDPOINTS_STORE_CONFIGURED);
return null;
}
const foundEndpoints: Record<string, string[]> = {};
const notFoundApis: string[] = [];
const apis = apiString.split(',').map(api => api.trim());
const data = await readJsonFromFile(filePath) as GatewayEndpointJson;
let allApisFound = true;
for (const api of apis) {
const matchedDeployment = data.deployments.find(deployment => deployment.api === api);
if (matchedDeployment) {
foundEndpoints[api] = matchedDeployment.endpoints;
} else {
notFoundApis.push(api);
allApisFound = false;
}
}
if (Object.keys(foundEndpoints).length > 0) {
if (allApisFound) {
logIfDebug(showInfo, ALL_ENDPOINTS_FETCHED_FROM_STORE);
} else {
logIfDebug(showInfo, SOME_ENDPOINTS_MISSING_FROM_STORE);
}
} else {
logIfDebug(showInfo, NO_ENDPOINTS_IN_STORE);
}
return { foundEndpoints, notFoundApis: notFoundApis.join(COMMA) };
};
export { getGatewayEndpoints, setGatewayEndpoint };