"use strict";
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.Curl = exports.browsers = void 0;
const child_process_1 = require("child_process");
const __1 = require("..");
const path_1 = __importDefault(require("path"));
const lodash_1 = __importDefault(require("lodash"));
const qs_1 = __importDefault(require("qs"));
const shell = (cmd) => {
    return new Promise((resolve) => {
        let stdout = null;
        let err = null;
        let stderr = null;
        let workerProcess = (0, child_process_1.spawn)('/bin/sh', ['-c', cmd]);
        workerProcess.stdout.on('data', function (data) {
            stdout = data;
        });
        workerProcess.stderr.on('data', function (data) {
            stderr = data;
        });
        workerProcess.on('close', function (code) {
            resolve({
                stdout: stdout.toString(),
                stderr: stderr.toString(),
                code: code ? code : 0,
                error: err,
            });
        });
    });
};
exports.browsers = [
    {
        name: "chrome110",
        browser: {
            name: "chrome",
            version: "110.0.5481.177",
            os: "win10",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_chrome110",
    },
    {
        name: "chrome99",
        browser: {
            name: "chrome",
            version: "99.0.4844.51",
            os: "win10",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_chrome99",
    },
    {
        name: "chrome100",
        browser: {
            name: "chrome",
            version: "100.0.4896.127",
            os: "win10",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_chrome100",
    },
    {
        name: "chrome101",
        browser: {
            name: "chrome",
            version: "101.0.4951.67",
            os: "win10",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_chrome101",
    },
    {
        name: "chrome104",
        browser: {
            name: "chrome",
            version: "104.0.5112.81",
            os: "win10",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_chrome104",
    },
    {
        name: "chrome107",
        browser: {
            name: "chrome",
            version: "107.0.5304.107",
            os: "win10",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_chrome107",
    },
    {
        name: "edge99",
        browser: {
            name: "edge",
            version: "99.0.1150.30",
            os: "win10",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_edge99",
    },
    {
        name: "edge101",
        browser: {
            name: "edge",
            version: "101.0.1210.47",
            os: "win10",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_edge101",
    },
    {
        name: "ff91esr",
        browser: {
            name: "firefox",
            version: "91.6.0esr",
            os: "win10",
        },
        binary: "curl-impersonate-ff",
        wrapper_script: "curl_ff91esr",
    },
    {
        name: "ff95",
        browser: {
            name: "firefox",
            version: "95.0.2",
            os: "win10",
        },
        binary: "curl-impersonate-ff",
        wrapper_script: "curl_ff95",
    },
    {
        name: "ff98",
        browser: {
            name: "firefox",
            version: "98.0",
            os: "win10",
        },
        binary: "curl-impersonate-ff",
        wrapper_script: "curl_ff98",
    },
    {
        name: "ff100",
        browser: {
            name: "firefox",
            version: "100.0",
            os: "win10",
        },
        binary: "curl-impersonate-ff",
        wrapper_script: "curl_ff100",
    },
    {
        name: "ff102",
        browser: {
            name: "firefox",
            version: "102.0",
            os: "win10",
        },
        binary: "curl-impersonate-ff",
        wrapper_script: "curl_ff102",
    },
    {
        name: "safari15_3",
        browser: {
            name: "safari",
            version: "15.3",
            os: "macos11.6.4",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_safari15_3",
    },
    {
        name: "safari15_5",
        browser: {
            name: "safari",
            version: "15.5",
            os: "macos12.4",
        },
        binary: "curl-impersonate-chrome",
        wrapper_script: "curl_safari15_5",
    },
];
class Curl {
    constructor(browser, curlPath) {
        this._getCurlExec = () => {
            return path_1.default.join(this.curlPath, `${this.browser.wrapper_script}`);
        };
        if (curlPath) {
            this.curlPath = curlPath;
        }
        else if (process.platform === "darwin") {
            this.curlPath = path_1.default.join(__dirname, "./core/mac");
        }
        else {
            this.curlPath = path_1.default.join(__dirname, "./core");
        }
        if (browser) {
            this.browser = browser;
        }
        else {
            const index = lodash_1.default.random(0, exports.browsers.length - 1, false);
            this.browser = exports.browsers[index];
        }
    }
    _stdErrorToOutPut(std) {
        return std;
    }
    _stdToOutPut(std) {
        let payload = std.split(/\r\n/);
        payload = lodash_1.default.reverse(payload);
        const body = payload[0];
        const headers = {};
        let status;
        let isPage = 0;
        for (let i = 0; i < payload.length; i++) {
            if (payload[i] === "" && i > 0) {
                isPage = isPage + 1;
            }
            if (isPage === 1 && payload[i] !== "") {
                const header = payload[i];
                if (header.toLowerCase().includes("http/")) {
                    const [__, stt] = header.split(" ");
                    status = Number(stt.trim());
                }
                else {
                    const [field, value] = header.split(": ");
                    headers[field] = value;
                }
            }
            if (isPage === 2) {
                break;
            }
        }
        return {
            body,
            headers,
            status,
        };
    }
    fetch(url, opts) {
        return __awaiter(this, void 0, void 0, function* () {
            if (opts.method.toLowerCase() === 'get') {
                return this.get(url, opts);
            }
            return this.post(url, opts.body, opts);
        });
    }
    get(url, opts) {
        return __awaiter(this, void 0, void 0, function* () {
            let headerString = "";
            if (opts.headers) {
                Object.keys(opts.headers).forEach((key) => {
                    headerString = headerString += `-H '${key}: ${opts.headers[key]}' `;
                });
            }
            if (opts.params) {
                const query = qs_1.default.stringify(opts.params);
                url = `${url}?${query}`;
            }
            let timeout = 30;
            if (opts.timeout) {
                timeout = opts.timeout;
            }
            const curlString = `${this._getCurlExec()} ${headerString} -i -L ${this.proxy ? ` -x ${this.proxy}` : ""} --connect-timeout ${timeout} --max-time ${timeout} -k ${url}`;
            const { stdout, stderr, code, error } = yield shell(curlString);
            if (code === 0) {
                const payload = this._stdToOutPut(stdout);
                try {
                    payload.body = JSON.parse(payload.body);
                }
                catch (err) { }
                if ([200, 201, 301].includes(payload.status)) {
                    return {
                        data: payload.body,
                        headers: payload.headers,
                        status: payload.status,
                    };
                }
                else {
                    throw new __1.ScraperRequestError({
                        data: payload.body,
                        headers: payload.headers,
                        status: payload.status,
                    });
                }
            }
            else {
                throw new __1.ScraperError(`${this._stdErrorToOutPut(stderr)}  ${error ? `- ${error}` : ""}`);
            }
        });
    }
    getCurl(url, opts) {
        return __awaiter(this, void 0, void 0, function* () {
            let headerString = "";
            if (opts.headers) {
                Object.keys(opts.headers).forEach((key) => {
                    headerString = headerString += `-H '${key}: ${opts.headers[key]}' `;
                });
            }
            if (opts.params) {
                const query = qs_1.default.stringify(opts.params);
                url = `${url}?${query}`;
            }
            let timeout = 30;
            if (opts.timeout) {
                timeout = opts.timeout;
            }
            const curlString = `${this._getCurlExec()} ${headerString} ${this.proxy ? ` -x ${this.proxy}` : ""} --connect-timeout ${timeout} --max-time ${timeout} -k ${url}`;
            const { stdout, stderr, code, error } = yield shell(curlString);
            if (code === 0) {
                return stdout;
            }
            else {
                throw new __1.ScraperError(`${this._stdErrorToOutPut(stderr)}  ${error ? `- ${error}` : ""}`);
            }
        });
    }
    post(url, data, opts) {
        return __awaiter(this, void 0, void 0, function* () {
            let headerString = "";
            if (opts.headers) {
                Object.keys(opts.headers).forEach((key) => {
                    headerString = headerString += `-H '${key}: ${opts.headers[key]}' `;
                });
            }
            if (opts.params) {
                const query = qs_1.default.stringify(opts.params);
                url = `${url}?${query}`;
            }
            let timeout = 30;
            if (opts.timeout) {
                timeout = opts.timeout;
            }
            const curlString = `${this._getCurlExec()} ${headerString} -i -L -X POST -d '${data}'${this.proxy ? ` -x ${this.proxy}` : ""} --connect-timeout ${timeout} --max-time ${timeout} -k ${url}`;
            const { stdout, stderr, code, error } = yield shell(curlString);
            if (code === 0) {
                const payload = this._stdToOutPut(stdout);
                try {
                    payload.body = JSON.parse(payload.body);
                }
                catch (err) { }
                if ([200, 201, 301].includes(payload.status)) {
                    return {
                        data: payload.body,
                        headers: payload.headers,
                        status: payload.status,
                    };
                }
                else {
                    throw new __1.ScraperRequestError({
                        data: payload.body,
                        headers: payload.headers,
                        status: payload.status,
                    });
                }
            }
            else {
                throw new __1.ScraperError(`${this._stdErrorToOutPut(stderr)}  ${error ? `- ${error}` : ""}`);
            }
        });
    }
    getBrowser() {
        return this.browser;
    }
    setBrowser(browser) {
        this.browser = browser;
    }
}
exports.Curl = Curl;
//# sourceMappingURL=index.js.map