@hippy/debug-server-next
Version:
Debug server for hippy.
184 lines (183 loc) • 7.94 kB
JavaScript
;
/*
* 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);
};