"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.onVanillaJSClientConnection = void 0;
const tslib_1 = require("tslib");
const safe_1 = tslib_1.__importDefault(require("colors/safe"));
const enum_1 = require("@debug-server-next/@types/enum");
const log_1 = require("@debug-server-next/utils/log");
const pub_sub_channel_1 = require("@debug-server-next/utils/pub-sub-channel");
const db_1 = require("@debug-server-next/db");
const report_1 = require("@debug-server-next/utils/report");
const debug_targets_1 = require("@debug-server-next/controller/debug-targets");
const global_id_1 = require("@debug-server-next/utils/global-id");
const timer_1 = require("@debug-server-next/utils/timer");
const history_event_protocol_1 = require("@debug-server-next/utils/history-event-protocol");
const constants_1 = require("@debug-server-next/@types/constants");
const label = safe_1.default.yellow('vanilla-js-devtools');
const downwardLog = new log_1.Logger(`↓↓↓ ${label}`, enum_1.WinstonColor.BrightRed);
const upwardLog = new log_1.Logger(`↑↑↑ ${label}`, enum_1.WinstonColor.BrightGreen);
const log = new log_1.Logger(label);
const ENABLE_LOG_PROTOCOL = 'Runtime.enable';
const ENABLE_PROTOCOLS = ['Network.enable', 'DOMStorage.enable'];
// const LOG_EVENT = 'Runtime.consoleAPICalled';
/**
 * Pub/Sub vanilla js devtools msg
 */
const onVanillaJSClientConnection = async (ws, wsUrlParams) => {
    const protocolId = new global_id_1.GlobalId(-20000, -1);
    const { contextName, clientRole, clientId, platform } = wsUrlParams;
    log.info('%s connected', clientRole);
    const { Subscriber, Publisher } = (0, db_1.getDBOperator)();
    const internalChannelId = (0, pub_sub_channel_1.createInternalChannel)(clientId, '');
    const internalSubscriber = new Subscriber(internalChannelId);
    internalSubscriber.subscribe((msg) => {
        if (msg === enum_1.InternalChannelEvent.DevtoolsConnected) {
            // pub enable after devtools connected
            triggerEnableLogForIOS(ws, protocolId, clientId);
            broadcastHistoryLog(clientId, downPublisher, platform);
        }
    });
    // pub enable immediately, support for reload scene
    triggerEnableLogForIOS(ws, protocolId, clientId);
    triggerEnableNetworkAndStorage(ws, protocolId);
    const upwardChannelId = (0, pub_sub_channel_1.createUpwardChannel)(clientId, '*');
    const downwardChannelId = (0, pub_sub_channel_1.createDownwardChannel)(clientId);
    const downPublisher = new Publisher(downwardChannelId);
    const upSubscriber = new Subscriber(upwardChannelId);
    upSubscriber.pSubscribe((msg) => {
        try {
            const msgStr = msg.toString();
            const msgObj = JSON.parse(msgStr);
            if (constants_1.LOG_PROTOCOLS.includes(msgObj.method)) {
                if (!ws.enableLogForIOS)
                    return;
                upwardLog.verbose('sendToApp %j', msgObj);
                report_1.report.event({
                    name: enum_1.ReportEvent.VanillaIOSJSRuntime,
                    ext1: contextName,
                    ext2: msgObj.method,
                });
                return ws.send(msgStr);
            }
            if (constants_1.VANILLA_JS_METHODS.includes(msgObj.method)) {
                upwardLog.verbose('sendToApp %j', msgObj);
                ws.send(msgStr);
                report_1.report.event({
                    name: enum_1.ReportEvent.VanillaJSRuntime,
                    ext1: contextName,
                    ext2: msgObj.method,
                });
            }
        }
        catch (e) { }
    });
    let debugTarget;
    ws.on('message', async (msg) => {
        const msgStr = msg.toString();
        if (!msgStr)
            return;
        try {
            const cmd = JSON.parse(msgStr);
            // network event dispatch from history cache
            // if (!cmd.method?.startsWith('Network.')) {
            downPublisher.publish(msgStr);
            downwardLog.verbose('sendToDevtools %s %s %s', cmd.id || '', cmd.method, 'error' in cmd ? 'not support' : '');
            // }
            if (!debugTarget) {
                await (0, timer_1.sleep)(800);
                debugTarget = await debug_targets_1.DebugTargetManager.findDebugTarget(clientId, undefined, true);
            }
            if (cmd.method && debugTarget && (0, history_event_protocol_1.isHistoryProtocol)(cmd.method, debugTarget.platform)) {
                (0, history_event_protocol_1.saveHistoryProtocol)(clientId, msgStr);
            }
        }
        catch (e) {
            log.error('parse json error: %s', (e === null || e === void 0 ? void 0 : e.stack) || e);
        }
    });
    ws.on('close', async (code, reason) => {
        log.info('%s closed. code: %s, reason: %s', clientRole, code, reason);
        (0, history_event_protocol_1.clearHistoryProtocol)(clientId);
        await upSubscriber.disconnect();
        await downPublisher.disconnect();
        await internalSubscriber.disconnect();
    });
    ws.on('error', (e) => log.error('vanilla js ws error: %s', e.stack || e));
};
exports.onVanillaJSClientConnection = onVanillaJSClientConnection;
async function enableLogForIOS(clientId) {
    /**
     * app ws maybe late connect than vanilla js, so maybe could not find debugTarget
     */
    await (0, timer_1.sleep)(800);
    const debugTarget = await debug_targets_1.DebugTargetManager.findDebugTarget(clientId, undefined, true);
    if (!debugTarget)
        return true;
    return debugTarget.platform === enum_1.DevicePlatform.IOS && !debugTarget.appClientTypeList.includes("IWDPAppClient" /* AppClientType.IWDP */);
}
/**
 * if iOS device not use IWDP, enable log protocol by vanilla js
 */
async function triggerEnableLogForIOS(ws, protocolId, clientId) {
    const enabled = await enableLogForIOS(clientId);
    ws.enableLogForIOS = enabled;
    if (enabled) {
        const event = {
            id: protocolId.create(),
            method: ENABLE_LOG_PROTOCOL,
            params: {},
        };
        ws.send(JSON.stringify(event));
        upwardLog.verbose('sendToApp %j', event);
    }
}
async function triggerEnableNetworkAndStorage(ws, protocolId) {
    // enable sample data when connected
    ENABLE_PROTOCOLS.forEach((protocol) => {
        const event = {
            id: protocolId.create(),
            method: protocol,
            params: {},
        };
        ws.send(JSON.stringify(event));
        upwardLog.verbose('sendToApp %j', event);
    });
}
const broadcastHistoryLog = async (clientId, downPublisher, platform) => {
    const list = await (0, history_event_protocol_1.getHistoryProtocol)(clientId);
    if (!list.length)
        return;
    /**
     * delay to send history log after ConsoleModel of devtools is ready
     */
    setTimeout(async () => {
        /**
         * mock a clear protocol to clear existed history logs in console panel
         */
        if (platform === enum_1.DevicePlatform.IOS)
            await downPublisher.publish({
                method: 'Log.cleared',
                params: {},
            });
        await list.map(downPublisher.publish.bind(downPublisher));
    }, 1500);
};
