mindee
Version:
Mindee Client Library for Node.js
99 lines (98 loc) • 4.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.UrlInput = void 0;
const inputSource_1 = require("./inputSource");
const url_1 = require("url");
const path_1 = require("path");
const crypto_1 = require("crypto");
const promises_1 = require("fs/promises");
const https_1 = require("https");
const bytesInput_1 = require("./bytesInput");
class UrlInput extends inputSource_1.InputSource {
constructor({ url }) {
super();
this.url = url;
}
async init() {
if (!this.url.toLowerCase().startsWith("https")) {
throw new Error("URL must be HTTPS");
}
this.fileObject = this.url;
}
async fetchFileContent(options) {
const { username, password, token, headers = {}, maxRedirects = 3 } = options;
if (token) {
headers["Authorization"] = `Bearer ${token}`;
}
const auth = username && password ? `${username}:${password}` : undefined;
return await this.makeRequest(this.url, auth, headers, 0, maxRedirects);
}
async saveToFile(options) {
const { filepath, filename, ...fetchOptions } = options;
const { content, finalUrl } = await this.fetchFileContent(fetchOptions);
const finalFilename = this.fillFilename(filename, finalUrl);
const fullPath = `${filepath}/${finalFilename}`;
await (0, promises_1.writeFile)(fullPath, content);
return fullPath;
}
async asLocalInputSource(options = {}) {
const { filename, ...fetchOptions } = options;
const { content, finalUrl } = await this.fetchFileContent(fetchOptions);
const finalFilename = this.fillFilename(filename, finalUrl);
return new bytesInput_1.BytesInput({ inputBytes: content, filename: finalFilename });
}
static extractFilenameFromUrl(uri) {
return (0, path_1.basename)(new url_1.URL(uri).pathname || "");
}
static generateFileName(extension = ".tmp") {
const randomString = (0, crypto_1.randomBytes)(4).toString("hex");
const timestamp = new Date().toISOString().replace(/[-:]/g, "").split(".")[0];
return `mindee_temp_${timestamp}_${randomString}${extension}`;
}
static getFileExtension(filename) {
const ext = (0, path_1.extname)(filename);
return ext ? ext.toLowerCase() : null;
}
fillFilename(filename, finalUrl) {
if (!filename) {
filename = finalUrl ? UrlInput.extractFilenameFromUrl(finalUrl) : UrlInput.extractFilenameFromUrl(this.url);
}
if (!filename || !(0, path_1.extname)(filename)) {
filename = UrlInput.generateFileName(UrlInput.getFileExtension(filename || "") || undefined);
}
return filename;
}
async makeRequest(url, auth, headers, redirects, maxRedirects) {
const parsedUrl = new url_1.URL(url);
const options = {
hostname: parsedUrl.hostname,
path: parsedUrl.pathname + parsedUrl.search,
method: "GET",
headers: headers,
auth: auth,
};
const response = await new Promise((resolve, reject) => {
const req = (0, https_1.request)(options, resolve);
req.on("error", reject);
req.end();
});
if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400) {
if (redirects === maxRedirects) {
throw new Error(`Can't reach URL after ${redirects} out of ${maxRedirects} redirects, aborting operation.`);
}
if (response.headers.location) {
return await this.makeRequest(response.headers.location, auth, headers, redirects + 1, maxRedirects);
}
throw new Error("Redirect location not found");
}
if (!response.statusCode || response.statusCode >= 400 || response.statusCode < 200) {
throw new Error(`Couldn't retrieve file from server, error code ${response.statusCode}.`);
}
const chunks = [];
for await (const chunk of response) {
chunks.push(chunk);
}
return { content: Buffer.concat(chunks), finalUrl: url };
}
}
exports.UrlInput = UrlInput;