UNPKG

serpapi

Version:

Scrape and parse search engine results using SerpApi.

98 lines (97 loc) 3.34 kB
import { version } from "../version.js"; import https from "https"; import qs from "querystring"; import process from "process"; import { RequestTimeoutError } from "./errors.js"; import { config } from "./config.js"; /** * This `_internals` object is needed to support stubbing/spying of * certain functions in this file. * https://deno.land/manual@v1.28.3/basics/testing/mocking * * It's also useful to encapsulate functions that are polyfilled. */ export const _internals = { execute: execute, getHostnameAndPort: getHostnameAndPort, }; /** Facilitates stubbing in tests */ function getHostnameAndPort() { return { hostname: "serpapi.com", port: 443, }; } export function getSource() { var _a, _b; const moduleSource = `serpapi@${version}`; if (typeof Deno == "object") { const denoVersion = (_a = Deno.version) === null || _a === void 0 ? void 0 : _a.deno; if (denoVersion) { return `deno@${denoVersion},${moduleSource}`; } } else if (typeof process == "object") { const nodeVersion = (_b = process.versions) === null || _b === void 0 ? void 0 : _b.node; if (nodeVersion) { return `nodejs@${nodeVersion},${moduleSource}`; } } return `nodejs,${moduleSource}`; } export function buildRequestOptions(path, parameters) { const clonedParams = Object.assign({}, parameters); for (const k in clonedParams) { if (k === "requestOptions" || k === "timeout" || clonedParams[k] === undefined) { delete clonedParams[k]; } } const basicOptions = Object.assign(Object.assign({}, _internals.getHostnameAndPort()), { path: `${path}?${qs.stringify(clonedParams)}`, method: "GET" }); return Object.assign(Object.assign(Object.assign({}, config.requestOptions), parameters.requestOptions), basicOptions); } export function execute(path, parameters, timeout) { const options = buildRequestOptions(path, Object.assign(Object.assign({}, parameters), { source: getSource() })); return new Promise((resolve, reject) => { let timer; const handleResponse = (resp) => { resp.setEncoding("utf8"); let data = ""; // A chunk of data has been received resp.on("data", (chunk) => { data += chunk; }); // The whole response has been received resp.on("end", () => { try { if (resp.statusCode == 200) { resolve(data); } else { reject(data); } } catch (e) { reject(e); } finally { if (timer) clearTimeout(timer); } }); }; const handleError = (err) => { reject(err); if (timer) clearTimeout(timer); }; const req = https.get(options, handleResponse).on("error", handleError); if (timeout > 0) { timer = setTimeout(() => { reject(new RequestTimeoutError()); req.destroy(); }, timeout); } }); }