// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.randomPortNotInUse = exports.getProcessIdsForPort = exports.isPortInUse = void 0; const childProcess = require("child_process"); const crypto = require("crypto"); const net = require("net"); const office_addin_usage_data_1 = require("office-addin-usage-data"); /* global process */ /** * Determines whether a port is in use. * @param port port number (0 - 65535) * @returns true if port is in use; false otherwise. */ function isPortInUse(port) { validatePort(port); return new Promise((resolve) => { const server = net .createServer() .once("error", () => { resolve(true); }) .once("listening", () => { server.close(); resolve(false); }) .listen(port); }); } exports.isPortInUse = isPortInUse; /** * Parse the port from a string which ends with colon and a number. * @param text string to parse * @example "127.0.0.1:3000" returns 3000 * @example "[::1]:1900" returns 1900 * @example "Local Address" returns undefined */ function parsePort(text) { const result = text.match(/:(\d+)$/); return result ? parseInt(result[1], 10) : undefined; } /** * Return the process ids using the port. * @param port port number (0 - 65535) * @returns Promise to array containing process ids, or empty if none. */ function getProcessIdsForPort(port) { validatePort(port); return new Promise((resolve, reject) => { const isWin32 = process.platform === "win32"; const isLinux = process.platform === "linux"; const command = isWin32 ? `netstat -ano | findstr :${port}` : isLinux ? `netstat -tlpna | grep :${port}` : `lsof -n -i:${port}`; childProcess.exec(command, (error, stdout) => { if (error) { if (error.code === 1) { // no processes are using the port resolve([]); } else { reject(error); } } else { const processIds = new Set(); const lines = stdout.trim().split("\n"); if (isWin32) { lines.forEach((line) => { /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ const [protocol, localAddress, foreignAddress, status, processId] = line.trim().split(" ").filter((text) => text); if (processId !== undefined && processId.trim() !== '0') { const localAddressPort = parsePort(localAddress); if (localAddressPort === port) { processIds.add(parseInt(processId, 10)); } } }); } else if (isLinux) { lines.forEach((line) => { /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ const [proto, recv, send, local_address, remote_address, state, program] = line .trim() .split(" ") .filter((text) => text); if (local_address !== undefined && local_address.endsWith(`:${port}`) && program !== undefined) { const pid = parseInt(program, 10); if (!isNaN(pid)) { processIds.add(pid); } } }); } else { lines.forEach((line) => { /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ const [process, processId, user, fd, type, device, size, node, name] = line .trim() .split(" ") .filter((text) => text); if (processId !== undefined && processId !== "PID") { processIds.add(parseInt(processId, 10)); } }); } resolve(Array.from(processIds)); } }); }); } exports.getProcessIdsForPort = getProcessIdsForPort; /** * Returns a random port number which is not in use. * @returns Promise to number from 0 to 65535 */ function randomPortNotInUse() { return __awaiter(this, void 0, void 0, function* () { let port; do { port = randomPortNumber(); } while (yield isPortInUse(port)); return port; }); } exports.randomPortNotInUse = randomPortNotInUse; /** * Returns a random number between 0 and 65535 */ function randomPortNumber() { return crypto.randomBytes(2).readUInt16LE(0); } /** * Throw an error if the port is not a valid number. * @param port port number * @throws Error if port is not a number from 0 to 65535. */ function validatePort(port) { if (typeof port !== "number" || port < 0 || port > 65535) { throw new office_addin_usage_data_1.ExpectedError("Port should be a number from 0 to 65535."); } } //# sourceMappingURL=port.js.map