@zombienet/utils
Version:
Useful utilities for ZombieNet Framework
95 lines (94 loc) • 4.21 kB
JavaScript
;
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());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRandomPort = getRandomPort;
exports.getHostIp = getHostIp;
exports.downloadFile = downloadFile;
const dns_1 = __importDefault(require("dns"));
const fs_1 = __importDefault(require("fs"));
const net_1 = require("net");
const os_1 = __importDefault(require("os"));
const stream_1 = require("stream");
const promises_1 = require("stream/promises");
const colors_1 = require("./colors");
const usedPorts = new Map();
/**
* Get a random available TCP port.
*
* Note that this function is prone to race conditions: a different process can start using the
* returned port before the caller of this function can start their server. However, in-process
* race conditions are prevented by storing the returned ports, so that a quick succession of
* calls to this function never returns a duplicate port.
*/
function getRandomPort(options) {
return __awaiter(this, void 0, void 0, function* () {
const inner = () => __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
const server = (0, net_1.createServer)();
server.unref();
server.on("error", reject);
server.listen(0, () => {
const { port } = server.address();
server.close(() => {
resolve(port);
});
});
});
});
let retries = 0;
const maxRetries = (options === null || options === void 0 ? void 0 : options.maxRetries) || 10;
const timeout = (options === null || options === void 0 ? void 0 : options.timeout) || 10 * 60 * 1000; // 10 minutes
while (retries < maxRetries) {
retries++;
const port = (yield inner());
const portUsedTimestamp = usedPorts.get(port);
const now = Date.now();
if (portUsedTimestamp === undefined || portUsedTimestamp < now) {
usedPorts.set(port, now + timeout);
return port;
}
else {
// Warning: port already used previously
console.error(`Warning: port ${port} already used, retrying`);
}
}
throw new Error(`Couldn't find an available TCP port after ${maxRetries} tries`);
});
}
function getHostIp() {
return __awaiter(this, void 0, void 0, function* () {
return yield new Promise((resolve) => {
dns_1.default.lookup(os_1.default.hostname(), (_err, addr) => {
resolve(addr);
});
});
});
}
function downloadFile(url, dest) {
return __awaiter(this, void 0, void 0, function* () {
try {
const response = yield fetch(url);
if (!response.ok) {
console.warn(`Fail to download file from url: ${url}, response: ${response.statusText}`);
}
const { body } = response;
const writable = fs_1.default.createWriteStream(dest);
const readable = stream_1.Readable.fromWeb(body);
yield (0, promises_1.finished)(readable.pipe(writable));
}
catch (err) {
console.log(`\n ${colors_1.decorators.red("Unexpected error: ")} \t ${colors_1.decorators.bright(err)}\n`);
}
});
}