serverless-spy
Version:
CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.
160 lines (158 loc) • 6.97 kB
JavaScript
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.js');
const require_listener_iot_connection = require('../listener/iot-connection.js');
const require_listener_topic = require('../listener/topic.js');
let fs = require("fs");
fs = require_rolldown_runtime.__toESM(fs);
let path = require("path");
path = require_rolldown_runtime.__toESM(path);
let http = require("http");
http = require_rolldown_runtime.__toESM(http);
let util = require("util");
util = require_rolldown_runtime.__toESM(util);
let caporal = require("caporal");
caporal = require_rolldown_runtime.__toESM(caporal);
let open = require("open");
open = require_rolldown_runtime.__toESM(open);
let ws = require("ws");
ws = require_rolldown_runtime.__toESM(ws);
//#region cli/cli.ts
const readFileAsync = (0, util.promisify)(fs.readFile);
let opener = open;
if (open.default) opener = open.default;
async function run() {
let stackList;
let cdkOutput;
let options;
caporal.description("ServerlessSpy web console").option("--ws <ws>", "Websocket link").option("--cdkoutput <cdkoutput>", "CDK output file that contains IoT Endpoint link in a property ServerlessSpyWsUrl").option("--cdkstack <cdkstack>", "CDK stack in cdk output file. If not specified the first one is picked.").option("--open <open>", "Open browser", caporal.BOOL, true).option("--port <p>", `A port on localhost where ServerlessSpy web console is accessible.`, caporal.INT, "3456").option("--wsport <wsp>", `A port on localhost where ServerlessSpy websocket is accessible.`, caporal.INT, "3457").action((_args, opt, _logger) => {
options = opt;
});
caporal.parse(process.argv);
if (!options.ws && !options.cdkoutput) throw new Error("--ws or --cdkoutput parameter not specified");
if (options.cdkoutput) {
const rawdata = fs.readFileSync(options.cdkoutput);
cdkOutput = JSON.parse(rawdata.toString());
stackList = Object.keys(cdkOutput);
}
const wss = new ws.WebSocketServer({ port: options.wsport });
let connection = void 0;
wss.on("close", async () => {
if (connection) connection.end(true);
});
wss.on("connection", async function connect(ws$1) {
console.log("Connection");
ws$1.on("message", function message(data) {
console.log("received: %s", data);
});
let wsUrl;
if (options.ws) wsUrl = options.ws;
else if (cdkOutput) {
if (cdkOutput[options.cdkstack]) wsUrl = cdkOutput[options.cdkstack].ServerlessSpyWsUrl;
else if (cdkOutput[Object.keys(cdkOutput)[0]]) wsUrl = cdkOutput[Object.keys(cdkOutput)[0]].ServerlessSpyWsUrl;
}
if (!wsUrl) throw new Error("Missing IoT endpoint url");
const wsUrlWithoutScope = wsUrl.split("/")[0];
connection = await require_listener_iot_connection.getConnection(true, wsUrlWithoutScope);
const topic = require_listener_topic.getTopic("#");
console.log(`Subscribing to ${topic}`);
connection.on("connect", () => {
console.log("Connection opened");
if (connection) connection.subscribe(topic);
});
connection.on("message", (topic$1, data) => {
ws$1.send(JSON.stringify({
...JSON.parse(JSON.parse(data.toString()).data),
topic: topic$1
}));
});
});
http.createServer((request, response) => {
(async () => {
try {
let filePath = `.${request.url}`;
filePath = filePath.split("?")[0];
let rootFolder = __dirname;
if (request.url?.startsWith("/webServerlessSpy.js")) rootFolder = getCompiledJsPath();
else if (request.url?.startsWith("/bootstrap/")) {
filePath = filePath.substring(11);
rootFolder = await getNpmModuleInstalledPath("bootstrap");
} else if (request.url?.startsWith("/bootstrap-icons/")) {
filePath = filePath.substring(17);
rootFolder = await getNpmModuleInstalledPath("bootstrap-icons");
} else if (filePath === "./") filePath = "./index.html";
filePath = path.join(rootFolder, filePath);
const extname = String(path.extname(filePath)).toLowerCase();
const contentType = {
".html": "text/html",
".js": "text/javascript",
".css": "text/css",
".json": "application/json",
".png": "image/png",
".jpg": "image/jpg",
".gif": "image/gif",
".svg": "image/svg+xml",
".wav": "audio/wav",
".mp4": "video/mp4",
".woff": "application/font-woff",
".ttf": "application/font-ttf",
".eot": "application/vnd.ms-fontobject",
".otf": "application/font-otf",
".wasm": "application/wasm"
}[extname] || "application/octet-stream";
if (request.url === "/stackList") {
response.writeHead(200, { "Content-Type": "application/json" });
response.end(JSON.stringify(stackList), "utf-8");
} else if (request.url === "/stackTopicMappings") {
response.writeHead(200, { "Content-Type": "application/json" });
const mappings = {};
if (cdkOutput) {
for (const [stackName, stack] of Object.entries(cdkOutput)) if (stack.ServerlessSpyWsUrl) {
const [_, scope] = stack.ServerlessSpyWsUrl.split("/");
if (scope) mappings[stackName] = scope;
}
}
response.end(JSON.stringify(mappings), "utf-8");
} else if (request.url?.match("^/wsUrl")) {
response.writeHead(200, { "Content-Type": "text/html" });
response.end(`ws:localhost:${options.wsport}`, "utf-8");
} else try {
const content = await readFileAsync(filePath);
response.writeHead(200, { "Content-Type": contentType });
response.end(content, "utf-8");
} catch (error) {
if (error.code === "ENOENT") {
response.writeHead(404, { "Content-Type": "text/html" });
response.end(`No such file or directory ${request.url}`, "utf-8");
} else {
response.writeHead(500);
response.end(`Error: ${error.code} ..\n`);
}
}
} catch (err) {
response.writeHead(500, { "Content-Type": "text/html" });
response.end(err.message, "utf-8");
}
})();
}).listen(options.port);
console.log(`ServerlessSpy console runing at http://localhost:${options.port}`);
if (options.open) await opener(`http://localhost:${options.port}`);
}
run().catch(console.error);
function getNpmModuleInstalledPath(npm) {
let folder = path.join(__dirname, "../", "node_modules", npm);
if (fs.existsSync(folder)) return folder;
let folderAsPackage = path.join(__dirname, "../../", "node_modules", npm);
if (fs.existsSync(folderAsPackage)) return folderAsPackage;
folderAsPackage = path.join(__dirname, "../../../../", "node_modules", npm);
if (fs.existsSync(folderAsPackage)) return folderAsPackage;
throw new Error(`Can not find package in folder ${folder} and ${folderAsPackage}`);
}
function getCompiledJsPath() {
let folder = path.join(__dirname, "../", "lib/cli");
if (fs.existsSync(folder)) return folder;
let folderAsPackage = path.join(__dirname, "../../", "lib/cli");
if (fs.existsSync(folderAsPackage)) return folderAsPackage;
throw new Error(`Can not find compiled files in folder ${folder} and ${folderAsPackage}`);
}
//#endregion
//# sourceMappingURL=cli.js.map