lib/commands/traffic-converter.ts (137 lines of code) (raw):
// node ./build/cli.js convert --directory ./input-example/ --out ./output-example/
import * as fs from "fs";
import * as path from "path";
import { URL } from "url";
import * as yargs from "yargs";
import { cliSuppressExceptions } from "../cliSuppressExceptions";
import { log } from "../util/logging";
let InputDirectory: string = "";
let OutputDirectory: string = "";
const CONTENT_TYPE_KEY: string = "Content-Type";
interface IndexableAny {
[index: string]: string;
}
interface ProxyPayload {
RequestUri: string;
RequestMethod: string;
RequestHeaders: IndexableAny;
RequestBody: string;
ResponseHeaders: IndexableAny;
ResponseBody: {};
StatusCode: string;
}
interface LiveRequest {
body: any;
method: string;
url: string;
headers: any;
}
interface LiveResponse {
body: any;
statusCode: string;
headers: any;
}
interface ValidationPayload {
liveRequest: LiveRequest;
liveResponse: LiveResponse;
}
function requestBodyConversion(body: string, headers: any) {
if (CONTENT_TYPE_KEY in headers) {
let content: string = headers[CONTENT_TYPE_KEY];
if (content.indexOf("application/json") > -1) {
// if RequestBody is a unicode string, it need JSON.parse to format
// eg. JSON.parse("{\u0022TableName\u0022: \u0022pytablesync70281ff8\u0022}") => {TableName: 'pytablesync70281ff8'}
// else return directly includes Object or Array
try {
return JSON.parse(body);
} catch (ex) {
log.error(ex);
return body;
}
}
}
return body;
}
function requestUriConversion(uri: string, version: string): string {
const parsedUrl = new URL(uri);
if (!parsedUrl.searchParams.get("api-version")) {
parsedUrl.searchParams.set("api-version", version);
}
return parsedUrl.toString();
}
function processFile(file: string, inputJson: any) {
if (inputJson.Entries !== undefined && inputJson.Entries.length > 0) {
const filePrefix = file.substring(0, file.lastIndexOf("."));
inputJson.Entries.forEach((entry: ProxyPayload, idx: number) => {
const outFile = `${filePrefix}_${String(idx).padStart(4, "0")}.json`;
const newEntry: ValidationPayload = {
liveRequest: <LiveRequest>{},
liveResponse: <LiveResponse>{},
};
// manipulate the request URI
newEntry.liveRequest.url = requestUriConversion(
entry.RequestUri,
entry.RequestHeaders["x-ms-version"]
);
newEntry.liveRequest.headers = entry.RequestHeaders;
// the request body is expected to be a JSON entry. Force that conversion if we can.
newEntry.liveRequest.body = requestBodyConversion(entry.RequestBody, entry.RequestHeaders);
newEntry.liveRequest.method = entry.RequestMethod;
newEntry.liveResponse.body = entry.ResponseBody;
// ensure string status code
newEntry.liveResponse.statusCode = entry.StatusCode.toString();
newEntry.liveResponse.headers = entry.ResponseHeaders;
outputFile(outFile, newEntry);
});
}
}
function readFile(file: string) {
const input_location = path.join(InputDirectory, file);
fs.readFile(input_location, "utf8", (err: any, data: any) => {
if (err) {
throw err;
}
let convertedJson: any = {};
try {
// handle byte order mark
convertedJson = JSON.parse(data.charCodeAt(0) === 0xfeff ? data.slice(1) : data);
} catch (ex) {
log.error(ex);
throw ex;
}
processFile(file, convertedJson);
});
}
function outputFile(file: string, outputJson: ValidationPayload) {
const data = JSON.stringify(outputJson, null, 4);
const outputLocation = path.join(OutputDirectory, file);
fs.writeFile(outputLocation, data, (err: any) => {
if (err) {
throw err;
}
});
}
function convert(directory: string, outDirectory: string) {
log.info(`Converting files in folder ${directory} ${outDirectory}`);
log.info(`Input Directory: ${directory}. Output Directory: ${outDirectory}`);
let files: string[] = fs.readdirSync(directory);
log.info(`Operating on ${files.length} files.`);
files.forEach((file: string) => {
readFile(file);
});
}
export const command = "traffic-convert <input-dir> <output-dir>";
export const describe = "Convert a folder files to traffic files";
export const builder: yargs.CommandBuilder = {
inputDir: {
alias: "d",
describe: "The targeted input directory.",
string: true,
},
outputDir: {
alias: "o",
describe: "The targeted output directory.",
string: true,
},
};
export async function handler(argv: yargs.Arguments): Promise<void> {
await cliSuppressExceptions(async () => {
log.debug(argv.toString());
InputDirectory = argv.inputDir;
OutputDirectory = argv.outputDir;
convert(InputDirectory, OutputDirectory);
return 0;
});
}