"use strict";
/*
 * Tencent is pleased to support the open source community by making
 * Hippy available.
 *
 * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateDebugTarget = exports.removeDebugTarget = exports.decreaseRefAndSave = exports.patchRefAndSave = exports.wsUrlWithoutProtocol = exports.patchDebugTarget = exports.createTargetByIWDPPage = exports.createTargetByWsUrlParams = exports.createTargetByDeviceInfo = void 0;
const enum_1 = require("@debug-server-next/@types/enum");
const url_1 = require("@debug-server-next/utils/url");
const config_1 = require("@debug-server-next/config");
const iwdp_1 = require("@debug-server-next/utils/iwdp");
const db_1 = require("@debug-server-next/db");
const log_1 = require("@debug-server-next/utils/log");
const log = new log_1.Logger('debug-target-util');
const createTargetByDeviceInfo = (device) => {
    // TODO tunnel doesn't support multiple device, so we use device name as debug target clientId
    const clientId = device.devicename;
    const wsUrl = url_1.makeUrl(`${config_1.config.wsDomain}${config_1.config.wsPath}`, {
        clientId,
        role: enum_1.ClientRole.Devtools,
    });
    const devtoolsFrontendUrl = url_1.makeUrl(`${config_1.config.domain}/front_end/inspector.html`, {
        remoteFrontend: true,
        experiments: true,
        [config_1.config.wsProtocol]: wsUrlWithoutProtocol(wsUrl),
        env: global.debugAppArgv.env,
    });
    const title = device.platform === enum_1.DevicePlatform.IOS ? clientId : 'Hippy debug tools for V8';
    return {
        clientId,
        devtoolsFrontendUrl,
        thumbnailUrl: '',
        title,
        url: '',
        description: '',
        webSocketDebuggerUrl: wsUrl,
        platform: device.platform,
        type: enum_1.ChromePageType.Page,
        appClientTypeList: ["TunnelAppClient" /* Tunnel */],
        deviceId: device.deviceid,
        deviceName: device.devicename,
        deviceOSVersion: device.osVersion,
        ref: 1,
        ts: Date.now(),
    };
};
exports.createTargetByDeviceInfo = createTargetByDeviceInfo;
const createTargetByWsUrlParams = (wsUrlParams, host) => {
    const { clientId, clientRole, contextName, deviceName, hash } = wsUrlParams;
    // if node server is in remote cluster
    // domain maybe devtools.qq.com or tdf-devtools.woa.com
    // so get domain from host
    const domain = config_1.config.isCluster ? `https://${host}` : config_1.config.domain;
    const wsDomain = domain.replace('https://', 'wss://').replace('http://', 'ws://');
    let platform;
    if (clientRole === enum_1.ClientRole.Android)
        platform = enum_1.DevicePlatform.Android;
    if (clientRole === enum_1.ClientRole.IOS)
        platform = enum_1.DevicePlatform.IOS;
    const wsUrl = url_1.makeUrl(`${wsDomain}${config_1.config.wsPath}`, {
        clientId,
        role: enum_1.ClientRole.Devtools,
        hash,
    });
    const devtoolsFrontendUrl = url_1.makeUrl(`${domain}/front_end/inspector.html`, {
        remoteFrontend: true,
        experiments: true,
        [config_1.config.wsProtocol]: wsUrlWithoutProtocol(wsUrl),
        env: global.debugAppArgv.env,
        hash,
    });
    return {
        hash,
        clientId,
        devtoolsFrontendUrl,
        thumbnailUrl: '',
        title: contextName,
        url: '',
        description: '',
        webSocketDebuggerUrl: wsUrl,
        platform,
        type: enum_1.ChromePageType.Page,
        deviceName,
        appClientTypeList: ["WSAppClient" /* WS */],
        ref: 1,
        ts: Date.now(),
    };
};
exports.createTargetByWsUrlParams = createTargetByWsUrlParams;
const createTargetByIWDPPage = (iWDPPage) => {
    const iWDPWsUrl = iWDPPage.webSocketDebuggerUrl;
    const wsUrl = url_1.makeUrl(`${config_1.config.wsDomain}${config_1.config.wsPath}`, {
        clientId: iWDPWsUrl,
        role: enum_1.ClientRole.Devtools,
    });
    const devtoolsFrontendUrl = url_1.makeUrl(`${config_1.config.domain}/front_end/inspector.html`, {
        remoteFrontend: true,
        experiments: true,
        [config_1.config.wsProtocol]: wsUrlWithoutProtocol(wsUrl),
        env: global.debugAppArgv.env,
    });
    return {
        clientId: iWDPWsUrl,
        iWDPWsUrl,
        devtoolsFrontendUrl,
        title: iWDPPage.title,
        thumbnailUrl: '',
        url: '',
        description: '',
        webSocketDebuggerUrl: wsUrl,
        platform: enum_1.DevicePlatform.IOS,
        type: enum_1.ChromePageType.Page,
        deviceId: iWDPPage.device.deviceId,
        deviceName: iWDPPage.device.deviceName,
        deviceOSVersion: iWDPPage.device.deviceOSVersion,
        appClientTypeList: ["IWDPAppClient" /* IWDP */],
        ref: 1,
        ts: Date.now(),
    };
};
exports.createTargetByIWDPPage = createTargetByIWDPPage;
/**
 * append IWDP info to debugTarget
 */
const patchDebugTarget = async (debugTarget) => {
    if (debugTarget.platform === enum_1.DevicePlatform.IOS) {
        const iOSPages = await iwdp_1.getIWDPPages(global.debugAppArgv.iWDPPort);
        return iwdp_1.patchIOSTarget(debugTarget, iOSPages);
    }
    return debugTarget;
};
exports.patchDebugTarget = patchDebugTarget;
function wsUrlWithoutProtocol(wsUrl) {
    return wsUrl.replace('wss://', '').replace('ws://', '');
}
exports.wsUrlWithoutProtocol = wsUrlWithoutProtocol;
const patchRefAndSave = async (newDebugTarget) => {
    const { DB } = db_1.getDBOperator();
    const { clientId } = newDebugTarget;
    const db = new DB(config_1.config.redis.debugTargetTable);
    const oldDebugTarget = await db.get(clientId);
    const debugTarget = newDebugTarget;
    if (oldDebugTarget) {
        debugTarget.ref = oldDebugTarget.ref + 1;
        log.info('increase debugTarget ref, clientId: %s, ref: %s', clientId, debugTarget.ref);
    }
    const patched = await exports.patchDebugTarget(debugTarget);
    await db.upsert(clientId, patched);
    return patched;
};
exports.patchRefAndSave = patchRefAndSave;
const decreaseRefAndSave = async (clientId) => {
    const { DB } = db_1.getDBOperator();
    const db = new DB(config_1.config.redis.debugTargetTable);
    const debugTarget = await db.get(clientId);
    if (!debugTarget)
        return;
    debugTarget.ref -= 1;
    log.verbose('decrease debugTarget ref, clientId: %s, ref: %s', clientId, debugTarget.ref);
    if (debugTarget.ref <= 0) {
        await db.delete(clientId);
        log.verbose('debugTarget ref is 0, should delete, clientId: %s', clientId);
        return;
    }
    await db.upsert(clientId, debugTarget);
    return debugTarget;
};
exports.decreaseRefAndSave = decreaseRefAndSave;
const removeDebugTarget = async (clientId) => {
    const { DB } = db_1.getDBOperator();
    const db = new DB(config_1.config.redis.debugTargetTable);
    return db.delete(clientId);
};
exports.removeDebugTarget = removeDebugTarget;
const updateDebugTarget = async (clientId, partialDebugTarget) => {
    const { DB } = db_1.getDBOperator();
    const db = new DB(config_1.config.redis.debugTargetTable);
    const oldDebugTarget = await db.get(clientId);
    const updated = {
        ...oldDebugTarget,
        ...partialDebugTarget,
    };
    await db.upsert(clientId, updated);
    return updated;
};
exports.updateDebugTarget = updateDebugTarget;
