UNPKG

6.78 kBJavaScriptView Raw
1const { CustomSmapiClientBuilder } = require('ask-smapi-sdk');
2const os = require('os');
3const path = require('path');
4const fs = require('fs-extra');
5const R = require('ramda');
6
7const AppConfig = require('@src/model/app-config');
8const AuthorizationController = require('@src/controllers/authorization-controller');
9const CONSTANTS = require('@src/utils/constants');
10const { resolveProviderChain } = require('@src/utils/provider-chain-utils');
11const jsonView = require('@src/view/json-view');
12const Messenger = require('@src/view/messenger');
13const profileHelper = require('@src/utils/profile-helper');
14const unflatten = require('@src/utils/unflatten');
15const { getParamNames, standardize, canParseAsJson } = require('@src/utils/string-utils');
16
17const BeforeSendProcessor = require('./before-send-processor');
18const { BODY_PATH_DELIMITER, ARRAY_SPLIT_DELIMITER } = require('./cli-customization-processor');
19
20const configFilePath = path.join(os.homedir(), CONSTANTS.FILE_PATH.ASK.HIDDEN_FOLDER, CONSTANTS.FILE_PATH.ASK.PROFILE_FILE);
21
22const _mapToArgs = (params, paramsObject) => {
23 const res = [];
24 params.forEach(param => {
25 let value = null;
26 Object.keys(paramsObject).forEach(k => {
27 if (standardize(k) === standardize(param)) {
28 value = paramsObject[k];
29 }
30 });
31 res.push(value);
32 });
33 return res;
34};
35
36const _loadValue = (param, value) => {
37 let result = value;
38 if (param.json) {
39 const filePrefix = 'file:';
40 if (value.startsWith(filePrefix)) {
41 const filePath = value.split(filePrefix).pop();
42 const fileContent = fs.readFileSync(filePath, { encoding: 'utf8' });
43 result = canParseAsJson(fileContent) ? JSON.parse(fileContent) : fileContent;
44 } else {
45 result = canParseAsJson(value) ? JSON.parse(value) : value;
46 }
47 }
48 return result;
49};
50
51const _mapToParams = (optionsValues, flatParamsMap, commanderToApiCustomizationMap) => {
52 const res = {};
53 Object.keys(optionsValues).forEach(key => {
54 const apiName = commanderToApiCustomizationMap.get(key) || key;
55 const param = flatParamsMap.get(standardize(apiName));
56 if (param) {
57 let value = optionsValues[key];
58 value = param.isArray ? value.split(ARRAY_SPLIT_DELIMITER) : value;
59 value = param.isNumber ? Number(value) : value;
60 value = param.isBoolean ? Boolean(value) : value;
61 if (param.rootName) {
62 if (!res[param.rootName]) {
63 res[param.rootName] = {};
64 }
65 let mergeObject = {};
66 mergeObject[param.bodyPath] = _loadValue(param, value);
67 mergeObject = unflatten(mergeObject, BODY_PATH_DELIMITER);
68 res[param.rootName] = R.mergeDeepRight(res[param.rootName], mergeObject);
69 } else {
70 res[param.name] = _loadValue(param, value);
71 }
72 }
73 });
74 return res;
75};
76
77const _sdkFunctionName = (swaggerApiOperationName) => `call${swaggerApiOperationName.charAt(0).toUpperCase() + swaggerApiOperationName.slice(1)}`;
78
79/**
80 * Parses response from smapi
81 * @param {Object} response object
82 */
83const parseSmapiResponse = (response) => {
84 let result = '';
85 const { body, headers } = response;
86 const contentType = headers.find((h) => h.key === 'content-type');
87 // json if no content type or content type is application/json
88 const isJson = !contentType || contentType.value.includes('application/json');
89 if (body && Object.keys(body).length) {
90 result = isJson ? jsonView.toString(body) : body;
91 } else {
92 result = 'Command executed successfully!';
93 }
94 return result;
95};
96
97/**
98 * Handles smapi command request
99 * @param {string} swaggerApiOperationName Swagger operation name.
100 * @param {Array} swaggerParams Parameters for operation from the Swagger model.
101 * @param {Map} flatParamsMap Flattened parameters.
102 * @param {Map} commanderToApiCustomizationMap Map of commander options to custom options
103 * for api properties.
104 * @param {Boolean} doDebug
105 * @param {Object} cmdObj Commander object with passed values.
106 */
107const smapiCommandHandler = (swaggerApiOperationName, flatParamsMap, commanderToApiCustomizationMap, inputCmdObj, modelIntrospector) => {
108 new AppConfig(configFilePath);
109 const inputOpts = inputCmdObj.opts();
110 const authorizationController = new AuthorizationController({
111 auth_client_type: 'LWA',
112 doDebug: inputOpts.debug
113 });
114 const profile = profileHelper.runtimeProfile(inputOpts.profile);
115 const refreshTokenConfig = {
116 clientId: authorizationController.oauthClient.config.clientId,
117 clientSecret: authorizationController.oauthClient.config.clientConfirmation,
118 refreshToken: AppConfig.getInstance().getToken(profile).refresh_token
119 };
120 const authEndpoint = resolveProviderChain([process.env.ASK_LWA_TOKEN_HOST, CONSTANTS.LWA.DEFAULT_TOKEN_HOST]);
121 const smapiEndpoint = resolveProviderChain([process.env.ASK_SMAPI_SERVER_BASE_URL, CONSTANTS.SMAPI.ENDPOINT]);
122
123 const client = new CustomSmapiClientBuilder()
124 .withAuthEndpoint(authEndpoint)
125 .withApiEndpoint(smapiEndpoint)
126 .withRefreshTokenConfig(refreshTokenConfig)
127 .client();
128
129 const paramsObject = _mapToParams(inputOpts, flatParamsMap, commanderToApiCustomizationMap);
130
131 const beforeSendProcessor = new BeforeSendProcessor(inputCmdObj._name, paramsObject, modelIntrospector, profile);
132 beforeSendProcessor.processAll();
133
134 const functionName = _sdkFunctionName(swaggerApiOperationName);
135 const params = getParamNames(client[functionName]);
136 const args = _mapToArgs(params, paramsObject);
137
138 if (inputOpts.debug) {
139 const payload = {};
140 params.forEach((k, i) => {
141 payload[k] = args[i];
142 });
143 Messenger.getInstance().info(`Operation: ${swaggerApiOperationName}`);
144 Messenger.getInstance().info('Payload:');
145 Messenger.getInstance().info(`${jsonView.toString(payload)}\n`);
146 }
147
148 return client[functionName](...args)
149 .then(response => {
150 const { body, headers, statusCode } = response;
151 let result = '';
152 if (inputOpts.debug) {
153 Messenger.getInstance().info('Response:');
154 Messenger.getInstance().info(jsonView.toString({ body, headers, statusCode }));
155 } else if (inputOpts.fullResponse) {
156 result = jsonView.toString({ body, headers, statusCode });
157 } else {
158 result = parseSmapiResponse(response);
159 }
160 return result;
161 });
162};
163
164module.exports = { smapiCommandHandler, parseSmapiResponse };