UNPKG

@rdfc/http-utils-processor-ts

Version:
131 lines (130 loc) 4.56 kB
import { Processor } from "@rdfc/js-runner"; import { HttpUtilsError } from "./error.js"; import { timeout } from "./util/timeout.js"; import { statusCodeAccepted } from "./util/status.js"; import { parseHeaders } from "./util/headers.js"; import { Auth } from "./auth/index.js"; import { cronify } from "./util/cronify.js"; import { readResponseAsStream } from "./util/response.js"; class HttpFetchArguments { method = "GET"; headers = []; acceptStatusCodes = ["200-300"]; closeOnEnd = true; bodyCanBeEmpty = false; timeOutMilliseconds = null; auth = null; cron = null; runOnInit = false; errorsAreFatal = true; outputAsBuffer = false; outputAsStream = false; constructor(partial) { Object.assign(this, partial); if (!partial.bodyCanBeEmpty && partial.method == "HEAD") { throw HttpUtilsError.illegalParameters("Cannot use HEAD method with bodyCanBeEmpty set to false"); } if (partial.closeOnEnd && partial.cron) { throw HttpUtilsError.illegalParameters("Cannot close stream when using cron."); } if (this.acceptStatusCodes.length === 0) { this.acceptStatusCodes.push("200-300"); } statusCodeAccepted(0, this.acceptStatusCodes); } getAuth() { return this.auth ? Auth.from(this.auth) : null; } } export class HttpFetch extends Processor { arguments; auth = null; requests = []; async init() { this.url = (Array.isArray(this.url) ? this.url : [this.url]); this.arguments = new HttpFetchArguments(this.options || {}); this.auth = this.arguments.getAuth(); const headers = parseHeaders(this.arguments.headers); this.requests = this.url.map((x) => { return new Request(x, { method: this.arguments.method, headers, }); }); } async transform() { } async produce() { let executeAllRequests = async () => { const promises = this.requests .map((req) => this.executeRequest(req)) .map((promise) => promise.catch((err) => { if (this.arguments.errorsAreFatal) { throw err; } else { console.error(err); } })); await Promise.all(promises); if (this.arguments.closeOnEnd) { await this.writer.close(); } }; if (this.arguments.cron) { executeAllRequests = cronify(executeAllRequests, this.arguments.cron, this.arguments.runOnInit); } return await executeAllRequests(); } async executeRequest(req) { this.logger.debug(`Executing request to '${req.url}'...`); if (this.auth) { await this.auth.authorize(req); } const fetchPromise = fetch(req).catch((err) => { throw HttpUtilsError.genericFetchError(err); }); const res = await timeout(this.arguments.timeOutMilliseconds, fetchPromise).catch((err) => { if (err === "timeout") { throw HttpUtilsError.timeOutError(this.arguments.timeOutMilliseconds); } else { throw err; } }); if (!statusCodeAccepted(res.status, this.arguments.acceptStatusCodes)) { if (res.status === 401 && this.auth) { throw HttpUtilsError.credentialIssue(); } else if (res.status === 401) { throw HttpUtilsError.unauthorizedError(); } else { throw HttpUtilsError.statusCodeNotAccepted(res.status); } } if (!res.body) { if (!this.arguments.bodyCanBeEmpty) { throw HttpUtilsError.noBodyInResponse(); } if (!this.arguments.cron && this.arguments.closeOnEnd) { await this.writer.close(); } return; } try { if (this.arguments.outputAsStream) { await this.writer.stream(readResponseAsStream(res)); } else { const body = this.arguments.outputAsBuffer ? { buffer: Buffer.from(await res.arrayBuffer()) } : { string: await res.text() }; await this.writer.any(body); } } catch (e) { console.error(e); } } }