"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(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 });
const inflation_1 = __importDefault(require("inflation"));
const raw_body_1 = __importDefault(require("raw-body"));
const stream_1 = __importDefault(require("stream"));
const url_1 = __importDefault(require("url"));
exports.endPoint = (httpTrafficService) => {
    return (ctx, next) => __awaiter(this, void 0, void 0, function* () {
        if (ctx.ignore) {
            yield next();
            return;
        }
        const { userID } = ctx;
        const urlObj = url_1.default.parse(ctx.req.url);
        const requestID = httpTrafficService.getRequestId(userID, urlObj);
        if (requestID > 0 && httpTrafficService.hasMonitor(userID)) {
            ctx.requestID = requestID;
            yield httpTrafficService.requestBegin({
                clientIp: ctx.clientIP,
                headers: ctx.req.headers,
                httpVersion: ctx.req.httpVersion,
                id: requestID,
                method: ctx.req.method,
                urlObj,
                userId: userID,
            });
        }
        const receiveRequestTime = Date.now();
        yield next();
        if (requestID > 0 && httpTrafficService.hasMonitor(userID)) {
            const { res, remoteRequestBeginTime, remoteResponseStartTime } = ctx;
            const requestEndTime = Date.now();
            const { statusCode } = res;
            const headers = res._headers;
            getResponseBody(res).then(body => {
                httpTrafficService.serverReturn({
                    id: requestID,
                    toClientResponse: {
                        body,
                        headers,
                        receiveRequestTime,
                        remoteIp: urlObj.host,
                        remoteRequestBeginTime,
                        remoteResponseStartTime,
                        requestEndTime,
                        statusCode,
                    },
                    userId: userID,
                });
            });
        }
    });
};
exports.actualRequest = (httpTrafficService) => {
    return (ctx, next) => __awaiter(this, void 0, void 0, function* () {
        if (ctx.ignore) {
            yield next();
            return;
        }
        const { userID, requestID } = ctx;
        if (requestID > 0 && httpTrafficService.hasMonitor(userID)) {
            const url = url_1.default.parse(ctx.req.url);
            const { headers, method, httpVersion } = ctx.req;
            getRequestBody(ctx.req).then(body => {
                httpTrafficService.actualRequest({
                    id: requestID,
                    originBody: body,
                    requestData: {
                        body,
                        headers,
                        httpVersion,
                        method,
                        path: url.path,
                        port: url.port || 80,
                        protocol: url.protocol,
                    },
                    userId: userID,
                });
            });
        }
        ctx.remoteRequestBeginTime = Date.now();
        yield next();
        ctx.remoteResponseStartTime = Date.now();
    });
};
const getRequestBody = (req) => __awaiter(this, void 0, void 0, function* () {
    if (req.body) {
        return Promise.resolve(req.body);
    }
    return new Promise((resolve, reject) => {
        raw_body_1.default(inflation_1.default(req), 'utf-8', (err, body) => {
            if (err) {
                return reject(err);
            }
            else {
                return resolve(body);
            }
        });
    });
});
const getResponseBody = (res) => __awaiter(this, void 0, void 0, function* () {
    const { body } = res;
    if (!body) {
        return Promise.resolve('');
    }
    if (Buffer.isBuffer(body)) {
        return Promise.resolve(body.toString('utf-8'));
    }
    if ('string' === typeof body) {
        return Promise.resolve(body);
    }
    if (body instanceof stream_1.default) {
        return new Promise((resolve, reject) => {
            raw_body_1.default(inflation_1.default(body), 'utf-8', (err, text) => {
                if (err) {
                    return reject(err);
                }
                else {
                    return resolve(text);
                }
            });
        });
    }
});
//# sourceMappingURL=monitor.js.map