"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
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 __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpService = void 0;
// import { uid } from "uid";
var fs = require("fs");
// import * as mkdirp from 'mkdirp'
// import {deleteAsync} from 'del';
var path = require("path");
var nodePath = path;
var net = require("net");
var tls = require("tls");
var url_1 = require("url");
var zlib = require("zlib");
// import * as axios from 'axios'
var axios = require('axios');
var USER_HOME = process.env.HOME || process.env.USERPROFILE;
var yunserFolder = path.resolve(USER_HOME, '.yunser'); // TODO package，npm install cmd-core
// if (!fs.existsSync(yunserFolder)) {
//     // console.log('创建目录')
//     fs.mkdirSync(yunserFolder)
// }
var appFolder = path.resolve(yunserFolder, 'dms-cli'); // TODO package，npm install cmd-core
// if (!fs.existsSync(appFolder)) {
//     fs.mkdirSync(appFolder)
// }
var apiFolder = path.resolve(appFolder, 'apis'); // TODO package，npm install cmd-core
if (!fs.existsSync(apiFolder)) {
    fs.mkdirSync(apiFolder);
}
function parseChunkedData(chunkedData) {
    var results = [];
    var buffer = Buffer.from(chunkedData);
    var pos = 0;
    var chunkSize = -1;
    while (pos < buffer.length) {
        //解析chunk长度
        if (chunkSize === -1) {
            var lineEnd = buffer.indexOf('\r\n', pos);
            chunkSize = parseInt(buffer.slice(pos, lineEnd).toString(), 16);
            pos = lineEnd + 2;
        }
        //拼接chunk数据
        if (pos + chunkSize <= buffer.length) {
            results.push(buffer.slice(pos, pos + chunkSize));
            // results += buffer.slice(pos, pos + chunkSize).toString();
            pos += chunkSize + 2;
            chunkSize = -1;
        }
        else {
            break;
        }
    }
    return Buffer.concat(results);
}
function normalHeaders(headers) {
    var result = {};
    for (var key in headers) {
        result[key.toLowerCase()] = headers[key];
    }
    return result;
}
function getBodyBuff(allData, nHeader) {
    if (nHeader === void 0) { nHeader = {}; }
    var text = allData.toString();
    var _a = text.split('\r\n\r\n'), headersText = _a[0], bodyText = _a[1];
    console.log('split/bodyText.length', headersText.length);
    var bodyStart = headersText.length + 4;
    var bodyBuff;
    if (nHeader['content-length']) {
        var contentLength = parseInt(nHeader['content-length']);
        // console.log('use contentLength', contentLength)
        bodyBuff = allData.slice(bodyStart, bodyStart + contentLength);
    }
    else if (nHeader['transfer-encoding'] == 'chunked') {
        bodyBuff = parseChunkedData(allData.slice(bodyStart));
    }
    else {
        bodyBuff = allData.slice(bodyStart);
    }
    console.log('bodyBuff', bodyBuff);
    console.log('bodyBuff.length', bodyBuff.length);
    // console.log('bodyText', bodyBuff.toString())
    return bodyBuff;
}
function parseHttpRes(allData) {
    var text = allData.toString();
    var _a = text.split('\r\n\r\n'), headersText = _a[0], bodyText = _a[1];
    // console.log('headersText',headersText)
    // console.log('bodyText',bodyText)
    var headLines = headersText.split('\r\n');
    var headerEnd = headLines.indexOf("");
    var headerText = headLines.slice(1, headerEnd);
    var headersList = [];
    var headers = headLines.slice(1).reduce(function (acc, headerLine) {
        var _a = headerLine.split(': '), key = _a[0], value = _a[1];
        acc[key] = value;
        headersList.push({
            key: key,
            value: value,
        });
        return acc;
    }, {});
    var nHeader = normalHeaders(headers);
    console.log('nHeader', nHeader);
    var statusLine = headLines[0].split(' ');
    var bodyBuff = getBodyBuff(allData, nHeader);
    var content;
    if (nHeader['content-encoding']) {
        console.log('bodyText.length', bodyBuff.length);
        console.log('bodyBuff', bodyBuff);
        if (nHeader['content-encoding'] == 'gzip') {
            content = zlib.gunzipSync(bodyBuff).toString();
        }
        else if (nHeader['content-encoding'] == 'deflate') {
            content = zlib.inflateSync(bodyBuff).toString();
        }
        else if (nHeader['content-encoding'] == 'br') {
            var bodyBuff_1 = getBodyBuff(allData);
            content = zlib.brotliDecompressSync(bodyBuff_1).toString();
        }
    }
    else {
        content = bodyBuff.toString();
    }
    return {
        statusCode: parseInt(statusLine[1]),
        statusMessage: statusLine.slice(2).join(" "),
        headers: headersList,
        content: content,
    };
}
function myRequest(opts, reqBody, onData) {
    console.log('myRequest', opts, reqBody);
    var sendContent;
    var headers = __assign(__assign({}, opts.headers), { 'Host': opts.hostname, 'Connection': 'close' });
    var httpVersion = opts['httpVersion'] || '1.1';
    sendContent = __spreadArray(__spreadArray([
        "".concat(opts.method, " ").concat(opts.path, " HTTP/").concat(httpVersion)
    ], Object.keys(headers).map(function (key) { return "".concat(key, ": ").concat(headers[key]); }), true), [
        '',
        '',
    ], false).join('\r\n');
    if (reqBody) {
        sendContent += reqBody;
    }
    function toInt(value) {
        if (typeof value == 'number') {
            return value;
        }
        return parseInt(value);
    }
    function handleResData(allData, socketInfo) {
        onData && onData(__assign(__assign({}, parseHttpRes(allData)), { requestRaw: sendContent, responseRaw: allData.toString(), socket: socketInfo }));
    }
    var _port = toInt(opts.port);
    if (opts.protocol == 'https:') {
        var allData_1 = Buffer.from('');
        var socketInfo_1 = null;
        var socket_1 = net.createConnection(_port, opts.hostname, function () {
            // console.log('创建 TLS 连接', )
            socketInfo_1 = {
                local: {
                    address: socket_1.localAddress,
                    port: socket_1.localPort,
                },
                remote: {
                    address: socket_1.remoteAddress,
                    port: socket_1.remotePort,
                    family: socket_1.remoteFamily,
                }
            };
            // console.log('socketInfo', socketInfo)
            // 创建 TLS 连接
            var tlsSocket = tls.connect({
                socket: socket_1,
                servername: opts.hostname,
            }, function () {
                // console.log('已连接', )
                tlsSocket.write(sendContent);
                // console.log('已发送', sendContent)
            });
            // 监听 TLS 连接数据
            tlsSocket.on('data', function (data) {
                allData_1 = Buffer.concat([allData_1, data]);
                // console.log('data???', data.toString());
                // socket.destroy()
            });
            // 监听 TLS 连接关闭
            tlsSocket.on('end', function () {
                console.log('TLS connection closed');
            });
            // 监听 TLS 连接错误
            tlsSocket.on('error', function (error) {
                console.error(error);
            });
            tlsSocket.on('close', function () {
                console.log('tlsSocket/close');
                // handleResData(allData)
                // console.error(error)
            });
        });
        // 监听 TCP 连接错误
        socket_1.on('error', function (error) {
            console.error(error);
        });
        socket_1.on('close', function () {
            console.log('Connection closed');
            // allB
            handleResData(allData_1, socketInfo_1);
        });
        return socket_1;
    }
    else {
        var client_1 = new net.Socket();
        if (opts.protocol == 'https:') {
            client_1;
        }
        var socketInfo_2 = null;
        client_1.connect(_port, opts.hostname, function () {
            console.log('地址');
            // console.log('client.localAddress', client.localAddress)
            // console.log('client.remoteAddress', client.remoteAddress)
            socketInfo_2 = {
                local: {
                    address: client_1.localAddress,
                    port: client_1.localPort,
                },
                remote: {
                    address: client_1.remoteAddress,
                    port: client_1.remotePort,
                    family: client_1.remoteFamily,
                }
            };
            client_1.write(sendContent);
        });
        var allData_2 = Buffer.from('');
        client_1.on('data', function (data) {
            allData_2 = Buffer.concat([allData_2, data]);
            // console.log('Received: ' + data)
            // client.destroy()
        });
        client_1.on('close', function () {
            console.log('Connection closed');
            // allB
            handleResData(allData_2, socketInfo_2);
        });
        return client_1;
    }
}
var HttpService = /** @class */ (function () {
    function HttpService() {
    }
    HttpService.prototype.apiInfo = function (body) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                return [2 /*return*/, {
                        rootPath: apiFolder,
                    }];
            });
        });
    };
    HttpService.prototype.proxy = function (ctx, body) {
        return __awaiter(this, void 0, void 0, function () {
            var url, res, err_1;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        url = body.url;
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, axios.get(url)];
                    case 2:
                        res = _a.sent();
                        ctx.status = res.status;
                        return [2 /*return*/, res.data];
                    case 3:
                        err_1 = _a.sent();
                        if (err_1.response) {
                            ctx.status = err_1.response.status;
                            return [2 /*return*/, err_1.response.data];
                        }
                        else {
                            ctx.status = 500;
                            return [2 /*return*/, {
                                    message: '未知错误'
                                }];
                        }
                        return [3 /*break*/, 4];
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    HttpService.prototype.proxyAxios = function (ctx, body) {
        return __awaiter(this, void 0, void 0, function () {
            var url, method, _a, headers, reqBody, reqData, res, err_2, _b, status_1, statusText, data, headers_1;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        url = body.url, method = body.method, _a = body.headers, headers = _a === void 0 ? {} : _a, reqBody = body.body;
                        _c.label = 1;
                    case 1:
                        _c.trys.push([1, 3, , 4]);
                        reqData = {
                            url: url,
                            method: method,
                            headers: headers,
                        };
                        if (reqBody) {
                            reqData['data'] = reqBody;
                        }
                        return [4 /*yield*/, axios.request(reqData)
                            // ctx.status = res.status
                        ];
                    case 2:
                        res = _c.sent();
                        // ctx.status = res.status
                        ctx.status = 200;
                        return [2 /*return*/, {
                                status: res.status,
                                statusText: res.statusText,
                                headers: res.headers,
                                data: (typeof res.data == 'string') ? res.data : JSON.stringify(res.data),
                            }];
                    case 3:
                        err_2 = _c.sent();
                        console.log('err.response', err_2.response);
                        if (err_2.response) {
                            _b = err_2.response, status_1 = _b.status, statusText = _b.statusText, data = _b.data, headers_1 = _b.headers;
                            ctx.status = 200;
                            return [2 /*return*/, {
                                    status: status_1,
                                    statusText: statusText,
                                    data: data,
                                    headers: headers_1,
                                    // headers: res.he
                                }];
                        }
                        else {
                            console.error(err_2);
                            ctx.status = 500;
                            return [2 /*return*/, {
                                    message: '未知错误'
                                }];
                        }
                        return [3 /*break*/, 4];
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    HttpService.prototype.httpRequest = function (ctx, body) {
        return __awaiter(this, void 0, void 0, function () {
            // console.log('urlObj', urlObj)
            // console.log(urlObj.protocol); // 输出：example.com
            function _doRequest() {
                return new Promise(function (resolve, reject) {
                    // console.log('urlObj.protocol', urlObj.protocol)
                    var sendHeaders = __assign({}, headers);
                    if (reqBody) {
                        sendHeaders['Content-Length'] = reqBody.length;
                    }
                    var options = {
                        httpVersion: httpVersion,
                        protocol: urlObj.protocol,
                        hostname: urlObj.hostname,
                        port: urlObj.port,
                        method: method,
                        path: "".concat(urlObj.pathname).concat(urlObj.search || '').concat(urlObj.hash || ''),
                        headers: sendHeaders,
                        agent: false,
                        rejectUnauthorized: false, // 用于忽略证书验证
                    };
                    if (!options.port) {
                        if (options.protocol == 'https:') {
                            options.port = '443';
                        }
                        else {
                            options.port = '80';
                        }
                    }
                    console.log('___options', options);
                    // const req = (urlObj.protocol == 'http:' ? http : https).request(options, res => {
                    var req = myRequest(options, reqBody, function (res) {
                        // console.log(`statusCode: ${res.statusCode}`)
                        // let all_data = ''
                        // res.on('data', data => {
                        //     // process.stdout.write(d);
                        //     all_data += data.toString()
                        // })
                        // res.on('end', () => {
                        //     // process.stdout.write(d);
                        //     // console.log('end', all_data)
                        // })
                        console.log('res', res);
                        resolve({
                            status: res.statusCode,
                            statusText: res.statusMessage,
                            data: res.content,
                            headers: res.headers,
                            requestRaw: res.requestRaw,
                            responseRaw: res.responseRaw,
                            socket: res.socket,
                        });
                    });
                    req.on('error', function (error) {
                        console.error('client_error', error);
                        reject(error);
                    });
                    // if (reqBody) {
                    //     req.write(reqBody)
                    // }
                    // req.end()
                });
            }
            var url, method, _a, httpVersion, _b, headers, reqBody, urlObj;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        url = body.url, method = body.method, _a = body.httpVersion, httpVersion = _a === void 0 ? '1.1' : _a, _b = body.headers, headers = _b === void 0 ? {} : _b, reqBody = body.body;
                        urlObj = new url_1.URL(url);
                        return [4 /*yield*/, _doRequest()];
                    case 1: return [2 /*return*/, _c.sent()];
                }
            });
        });
    };
    HttpService.prototype.debug = function (params) {
        return __awaiter(this, void 0, void 0, function () {
            var body, query, url, headers, method;
            return __generator(this, function (_a) {
                body = params.body, query = params.query, url = params.url, headers = params.headers, method = params.method;
                return [2 /*return*/, {
                        body: body,
                        query: query,
                        url: url,
                        headers: headers,
                        method: method,
                    }];
            });
        });
    };
    return HttpService;
}());
exports.HttpService = HttpService;
//# sourceMappingURL=http.service.js.map