mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-11 02:44:57 +08:00
1062 lines
36 KiB
HTML
1062 lines
36 KiB
HTML
<%+cbi/valueheader%>
|
|
<%
|
|
local fs = require "luci.openclash"
|
|
local plugin_version = fs.oc_version()
|
|
%>
|
|
<script src="/luci-static/resources/openclash/js/oc-icons.js?v=<%=plugin_version%>"></script>
|
|
<body>
|
|
<div id="tab" class="oc">
|
|
<div id="tab-header">
|
|
<ul class="oc-tabmenu">
|
|
<li name="tab-header" class="oc-tab"><a href="#"><svg width="14" height="14"><use href="#oc-icon-package"/></svg><span><%:Plugin Logs%></span></a></li>
|
|
<li name="tab-header" class="oc-tab-disabled"><a href="#"><svg width="14" height="14"><use href="#oc-icon-cpu"/></svg><span><%:Core Logs%></span></a></li>
|
|
<li name="tab-header" class="oc-tab-disabled"><a href="#"><svg width="14" height="14"><use href="#oc-icon-bug"/></svg><span><%:Debug Logs%></span></a></li>
|
|
</ul>
|
|
</div>
|
|
<div id="tab-content">
|
|
<div class="dom" style="display: block;">
|
|
<textarea id="cbid.openclash.config.clog" class="oc-input-textarea" style="display:inline" data-update="change" rows="32" cols="60" readonly="readonly" ></textarea>
|
|
</div>
|
|
<div class="dom">
|
|
<textarea id="core_log" class="oc-input-textarea" style="display:inline" data-update="change" rows="32" cols="60" readonly="readonly" ></textarea>
|
|
<div class="radio-button">
|
|
<input type="radio" id="info" name="radios" value="info" checked onclick="return switch_log_level(this.value)"/>
|
|
<label for="info"><%:Info%></label>
|
|
<input type="radio" id="warning" name="radios" value="warning" onclick="return switch_log_level(this.value)"/>
|
|
<label for="warning"><%:Warning%></label>
|
|
<input type="radio" id="error" name="radios" value="error" onclick="return switch_log_level(this.value)"/>
|
|
<label for="error"><%:Error%></label>
|
|
<input type="radio" id="debug" name="radios" value="debug" onclick="return switch_log_level(this.value)"/>
|
|
<label for="debug"><%:Debug%></label>
|
|
<input type="radio" id="silent" name="radios" value="silent" onclick="return switch_log_level(this.value)"/>
|
|
<label for="silent"><%:Silent%></label>
|
|
</div>
|
|
</div>
|
|
<div class="dom">
|
|
<textarea id="debug_log" class="oc-input-textarea oc-hidden" data-update="change" rows="32" cols="60" readonly="readonly" ></textarea>
|
|
<div id="debug-render-wrapper">
|
|
<div id="debug-rendered"></div>
|
|
<div class="oc-usage-help-float" id="debug-copy-source" onclick="copyDebugSource()" title="<%:Copy Debug%>"><svg width="20" height="20"><use href="#oc-icon-copy"/></svg></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="oc oc-text-center oc-w100">
|
|
<div class="select-popup-footer log-footer">
|
|
<button type="button" class="footer-btn" id="stop_refresh_button" onclick="return stop_refresh()"><svg width="14" height="14"><use href="#oc-icon-player-pause"/></svg><span><%:Stop Refresh%></span></button>
|
|
<button type="button" class="footer-btn" id="start_refresh_button" onclick="return start_refresh()"><svg width="14" height="14"><use href="#oc-icon-player-play"/></svg><span><%:Start Refresh%></span></button>
|
|
<button type="button" class="footer-btn" id="del_log_button" onclick="return del_log()"><svg width="14" height="14"><use href="#oc-icon-trash"/></svg><span><%:Clean%></span></button>
|
|
<button type="button" class="footer-btn" id="down_log_button" onclick="return download_log()"><svg width="14" height="14"><use href="#oc-icon-download"/></svg><span><%:Download Log%></span></button>
|
|
<button type="button" class="footer-btn" id="gen_debug_button" onclick="return gen_debug_logs()"><svg width="14" height="14"><use href="#oc-icon-play-bugs"/></svg><span><%:Generate Logs%></span></button>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
|
|
<script type="text/javascript">//<![CDATA[
|
|
window.levelTranslations = {
|
|
'info': '<%:Info%>',
|
|
'warning': '<%:Warning%>',
|
|
'error': '<%:Error%>',
|
|
'debug': '<%:Debug%>',
|
|
'tip': '<%:Tip%>',
|
|
'watchdog': '<%:Watchdog%>',
|
|
'fatal': '<%:Fatal%>'
|
|
};
|
|
var r;
|
|
var s;
|
|
var log_len = 0;
|
|
var lv = document.getElementById('cbid.openclash.config.clog');
|
|
var cl = document.getElementById('core_log');
|
|
var dl = document.getElementById('debug_log');
|
|
var animatingOC = false;
|
|
var animatingCore = false;
|
|
var animatingDebug = false;
|
|
var coreWebSocket = null;
|
|
var coreLogBuffer = [];
|
|
var currentLogLevel = 'info';
|
|
var wsRetryDelay = 2000;
|
|
var wsRetryTimer = null;
|
|
var isPolling = false;
|
|
var core_refresh = true;
|
|
var wsHasData = false;
|
|
var coreEditorInitialized = false;
|
|
var editor_oc;
|
|
var editor_core;
|
|
var editor_debug;
|
|
var coreLogAccumulator = '';
|
|
var pollInterval = 1000;
|
|
|
|
function accumulateCoreLog(linesArr) {
|
|
var reversed = linesArr.slice().reverse();
|
|
var batchStr = '';
|
|
for (var k = 0; k < reversed.length; k++) {
|
|
batchStr += reversed[k] + '\n';
|
|
}
|
|
if (coreLogAccumulator) {
|
|
var accFirstLineEnd = coreLogAccumulator.indexOf('\n');
|
|
var accFirstLine = accFirstLineEnd > 0 ? coreLogAccumulator.substring(0, accFirstLineEnd) : coreLogAccumulator;
|
|
var batchTrimmed = batchStr.slice(0, -1);
|
|
var batchLastLineStart = batchTrimmed.lastIndexOf('\n');
|
|
var batchLastLine = batchLastLineStart > 0 ? batchTrimmed.substring(batchLastLineStart + 1) : batchTrimmed;
|
|
if (accFirstLine === batchLastLine) {
|
|
batchStr = batchLastLineStart > 0 ? batchStr.substring(0, batchLastLineStart + 1) : '';
|
|
}
|
|
}
|
|
coreLogAccumulator = batchStr + coreLogAccumulator;
|
|
var accLines = coreLogAccumulator.split('\n');
|
|
if (accLines.length > 2000) {
|
|
accLines = accLines.slice(0, 1999);
|
|
accLines.push('...');
|
|
coreLogAccumulator = accLines.join('\n');
|
|
}
|
|
cl.value = coreLogAccumulator;
|
|
}
|
|
|
|
function setLogTab(log_level) {
|
|
var radio = document.getElementsByName("radios");
|
|
for (i=0; i<radio.length; i++) {
|
|
if (radio[i].value == log_level && ! radio[i].checked) {
|
|
radio[i].checked = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
function get_log_level() {
|
|
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "log_level")%>', null, function(x, status) {
|
|
if (x && x.status == 200 && status.log_level != "") {
|
|
currentLogLevel = status.log_level;
|
|
setLogTab(currentLogLevel);
|
|
coreLogWebSocket();
|
|
}
|
|
});
|
|
};
|
|
|
|
function switch_log_level(value)
|
|
{
|
|
if (!coreWebSocket || coreWebSocket.readyState !== WebSocket.OPEN) {
|
|
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_log")%>', {log_level: value}, function(x, status) {
|
|
if (!x || x.status != 200) {
|
|
alert(' <%:Log Level%>: ' + value + ' <%:switching failed!%>');
|
|
return
|
|
}
|
|
});
|
|
}
|
|
|
|
currentLogLevel = value;
|
|
setLogTab(currentLogLevel);
|
|
coreLogWebSocket();
|
|
};
|
|
|
|
function stop_refresh() {
|
|
clearTimeout(r);
|
|
coreLogWebSocketStop();
|
|
return
|
|
};
|
|
|
|
function start_refresh() {
|
|
clearTimeout(r);
|
|
coreLogWebSocket();
|
|
r=setTimeout("poll_log()",1000);
|
|
return
|
|
};
|
|
|
|
function createAndDownloadFile(fileName, content) {
|
|
var aTag = document.createElement('a');
|
|
var blob = new Blob([content]);
|
|
aTag.download = fileName;
|
|
aTag.href = URL.createObjectURL(blob);
|
|
aTag.click();
|
|
URL.revokeObjectURL(blob);
|
|
};
|
|
|
|
function download_log(){
|
|
var dt = new Date();
|
|
var timestamp = dt.getFullYear()+"-"+(dt.getMonth()+1)+"-"+dt.getDate()+"-"+dt.getHours()+"-"+dt.getMinutes()+"-"+dt.getSeconds();
|
|
|
|
var activeTabId = 0;
|
|
var titles = document.getElementsByName('tab-header');
|
|
for(var i=0; i<titles.length; i++){
|
|
if(titles[i].className === 'oc-tab') {
|
|
activeTabId = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
var downloadContent = "";
|
|
|
|
if (activeTabId === 2) {
|
|
var debug_content = dl.value || '';
|
|
if (!debug_content.trim()) return;
|
|
downloadContent += debug_content;
|
|
createAndDownloadFile("OpenClash-Debug-"+timestamp+".log", downloadContent);
|
|
return;
|
|
}
|
|
|
|
var oc_content = "";
|
|
if (typeof editor_oc !== 'undefined' && editor_oc) {
|
|
oc_content = editor_oc.getValue();
|
|
} else if (lv && lv.value) {
|
|
oc_content = lv.value;
|
|
} else if (lv && lv.innerHTML) {
|
|
oc_content = lv.innerHTML;
|
|
}
|
|
|
|
oc_content = oc_content.split('\n').filter(function(line) {
|
|
return line.indexOf("】<%:Downloading URL%>【") === -1;
|
|
}).join('\n');
|
|
|
|
var core_content = "";
|
|
if (typeof editor_core !== 'undefined' && editor_core) {
|
|
core_content = editor_core.getValue();
|
|
} else if (cl && cl.value) {
|
|
core_content = cl.value;
|
|
} else if (cl && cl.innerHTML) {
|
|
core_content = cl.innerHTML;
|
|
}
|
|
|
|
if (!oc_content.trim() && !core_content.trim()) {
|
|
return;
|
|
}
|
|
|
|
if (oc_content.trim()) {
|
|
downloadContent += "<%:Plugin Logs%>:\n" + oc_content + "\n\n";
|
|
}
|
|
if (core_content.trim()) {
|
|
downloadContent += "<%:Core Logs%>:\n" + core_content;
|
|
}
|
|
|
|
createAndDownloadFile("OpenClash-"+timestamp+".log", downloadContent);
|
|
return;
|
|
};
|
|
|
|
function restoreDebugEditor() {
|
|
var wrapper = document.getElementById('debug-render-wrapper');
|
|
var rendered = document.getElementById('debug-rendered');
|
|
if (wrapper) { wrapper.style.display = 'none'; }
|
|
if (rendered) { rendered.innerHTML = ''; }
|
|
dl.value = "";
|
|
if (typeof editor_debug !== 'undefined' && editor_debug) {
|
|
editor_debug.setValue("");
|
|
if (editor_debug.dom) {
|
|
editor_debug.dom.style.setProperty('display', '', 'important');
|
|
}
|
|
editor_debug.refresh();
|
|
}
|
|
}
|
|
|
|
function del_log() {
|
|
var activeTabId = 0;
|
|
var titles = document.getElementsByName('tab-header');
|
|
for(var i=0; i<titles.length; i++){
|
|
if(titles[i].className === 'oc-tab') {
|
|
activeTabId = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (activeTabId === 2) {
|
|
restoreDebugEditor();
|
|
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "del_log")%>', {type: "debug"}, function(x, data){
|
|
if (typeof editor_debug === 'undefined' || !editor_debug) {
|
|
if (typeof markdown_editor === 'function' && dl) {
|
|
markdown_editor(dl, 'debug', true, '100%', '540px');
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "del_log")%>', null, function(x, data){
|
|
lv.value = "";
|
|
cl.value = "";
|
|
coreLogBuffer = [];
|
|
coreLogAccumulator = '';
|
|
log_len = 0;
|
|
if (typeof editor_oc !== 'undefined' && editor_oc) {
|
|
editor_oc.setValue(lv.value);
|
|
}
|
|
if (typeof editor_core !== 'undefined' && editor_core) {
|
|
editor_core.setValue(cl.value);
|
|
}
|
|
});
|
|
}
|
|
return
|
|
};
|
|
|
|
function p(s) {
|
|
return s < 10 ? '0' + s: s;
|
|
};
|
|
|
|
function getWebSocketConnectionInfo(callback) {
|
|
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "conn_status")%>', null, function(x, status) {
|
|
if (x && x.status == 200 && status) {
|
|
callback(status);
|
|
} else {
|
|
callback(null);
|
|
}
|
|
});
|
|
}
|
|
|
|
function coreLogWebSocketStop() {
|
|
if (wsRetryTimer) {
|
|
clearTimeout(wsRetryTimer);
|
|
wsRetryTimer = null;
|
|
}
|
|
|
|
var ws = coreWebSocket;
|
|
coreWebSocket = null;
|
|
|
|
if (!ws) return;
|
|
|
|
["onopen", "onmessage", "onerror", "onclose"].forEach(function(event) {
|
|
try {
|
|
ws[event] = null;
|
|
} catch (e) {}
|
|
});
|
|
|
|
try {
|
|
if (ws.readyState !== WebSocket.CLOSED && ws.readyState !== WebSocket.CLOSING) {
|
|
ws.close();
|
|
}
|
|
} catch (e) {}
|
|
|
|
coreLogBuffer = [];
|
|
wsHasData = false;
|
|
}
|
|
|
|
function coreLogWebSocketRetry() {
|
|
wsRetryTimer = setTimeout(function() {
|
|
coreLogWebSocket();
|
|
}, wsRetryDelay);
|
|
}
|
|
|
|
function coreLogWebSocket() {
|
|
coreLogWebSocketStop();
|
|
|
|
getWebSocketConnectionInfo(function(status) {
|
|
if (!status || !status.daip || !status.cn_port || !status.clash) {
|
|
return;
|
|
}
|
|
|
|
var protocol = window.location.protocol === "https:" ? "wss://" : "ws://";
|
|
var host, port;
|
|
|
|
if (status.daip && window.location.hostname === status.daip) {
|
|
host = status.daip;
|
|
port = status.cn_port;
|
|
} else if (status.daip && window.location.hostname !== status.daip &&
|
|
status.db_foward_domain && status.db_foward_port) {
|
|
host = status.db_foward_domain;
|
|
port = status.db_foward_port;
|
|
} else {
|
|
host = status.daip;
|
|
port = status.cn_port;
|
|
}
|
|
|
|
var token = status.dase;
|
|
var level = currentLogLevel;
|
|
var wsUrl = protocol + host + ":" + port + "/logs?token=" + token + "&level=" + level;
|
|
|
|
try {
|
|
coreWebSocket = new WebSocket(wsUrl);
|
|
coreWebSocket.onopen = function() {
|
|
coreLogBuffer = [];
|
|
wsHasData = false;
|
|
};
|
|
|
|
coreWebSocket.onmessage = function(event) {
|
|
if (event.data) {
|
|
try {
|
|
var msgData = JSON.parse(event.data);
|
|
if (msgData && msgData.payload) {
|
|
wsHasData = true;
|
|
var now = new Date();
|
|
var timestamp = now.getFullYear() + "-" + p(now.getMonth() + 1) + "-" + p(now.getDate()) + " " +
|
|
p(now.getHours()) + ":" + p(now.getMinutes()) + ":" + p(now.getSeconds());
|
|
var type = msgData.type || 'info';
|
|
var translatedType = levelTranslations[type] || type;
|
|
coreLogBuffer.push(timestamp + " [" + translatedType + "] " + msgData.payload);
|
|
}
|
|
} catch (e) {
|
|
coreLogWebSocketRetry();
|
|
}
|
|
}
|
|
};
|
|
|
|
coreWebSocket.onerror = function(error) {
|
|
coreLogWebSocketRetry();
|
|
};
|
|
|
|
coreWebSocket.onclose = function(event) {
|
|
coreWebSocket = null;
|
|
if (!event.wasClean) {
|
|
coreLogWebSocketRetry();
|
|
}
|
|
};
|
|
} catch (e) {
|
|
coreLogWebSocketRetry();
|
|
}
|
|
});
|
|
}
|
|
|
|
function gen_debug_logs()
|
|
{
|
|
var btn = document.getElementById('gen_debug_button');
|
|
var btnText = btn ? btn.querySelector('span') : null;
|
|
var btnSvg = btn ? btn.querySelector('svg') : null;
|
|
var originalText = btnText ? btnText.textContent : '';
|
|
var originalSvg = btnSvg ? btnSvg.outerHTML : '';
|
|
if (btn) {
|
|
if (btnText) { btnText.textContent = '<%:Generating...%>'; }
|
|
btn.disabled = true;
|
|
if (btnSvg) {
|
|
var spinner = document.createElement('span');
|
|
spinner.className = 'loading-spinner oc-btn-spinner';
|
|
btnSvg.replaceWith(spinner);
|
|
}
|
|
}
|
|
|
|
function restoreGenerateBtn() {
|
|
if (!btn) return;
|
|
if (btnText) { btnText.textContent = originalText; }
|
|
btn.disabled = false;
|
|
var sp = btn.querySelector('.loading-spinner');
|
|
if (sp) { sp.outerHTML = originalSvg; }
|
|
}
|
|
|
|
restoreDebugEditor();
|
|
|
|
var titles = document.getElementsByName('tab-header');
|
|
if (titles.length > 2 && titles[2].className !== 'oc-tab') {
|
|
titles[2].click();
|
|
}
|
|
|
|
if (typeof editor_debug === 'undefined' || !editor_debug) {
|
|
if (typeof markdown_editor === 'function' && dl) {
|
|
markdown_editor(dl, 'debug', true, '100%', '540px');
|
|
}
|
|
}
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.timeout = 0;
|
|
xhr.open('GET', '<%=luci.dispatcher.build_url("admin", "services", "openclash", "gen_debug_logs")%>', true);
|
|
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
|
|
|
var lastLen = 0;
|
|
xhr.onprogress = function() {
|
|
var text = xhr.responseText;
|
|
if (text.length <= lastLen) return;
|
|
lastLen = text.length;
|
|
var lines = text.split('\n');
|
|
lines.pop();
|
|
if (lines.length > 0 && lines[0].length === 8192 && /^ +$/.test(lines[0])) {
|
|
lines.shift();
|
|
}
|
|
var preview = lines.join('\n');
|
|
if (editor_debug && editor_debug.setValue) {
|
|
editor_debug.setValue(preview);
|
|
if (editor_debug.scrollDOM) editor_debug.scrollDOM.scrollTop = editor_debug.scrollDOM.scrollHeight;
|
|
} else {
|
|
dl.value = preview;
|
|
}
|
|
};
|
|
|
|
xhr.onload = function() {
|
|
restoreGenerateBtn();
|
|
var finalText = xhr.responseText || '';
|
|
|
|
if (xhr.status != 200 && finalText == "") {
|
|
if (editor_debug && editor_debug.setValue) {
|
|
editor_debug.setValue('<%:Some error occurred!%>');
|
|
} else {
|
|
dl.value = '<%:Some error occurred!%>';
|
|
}
|
|
return;
|
|
}
|
|
|
|
// reload after sed, because log changed
|
|
load_debug_log();
|
|
};
|
|
|
|
xhr.ontimeout = function() {
|
|
restoreGenerateBtn();
|
|
if (xhr.responseText == "") {
|
|
if (editor_debug && editor_debug.setValue) {
|
|
editor_debug.setValue('<%:Request Timeout...%>');
|
|
} else {
|
|
dl.value = '<%:Request Timeout...%>';
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function() {
|
|
restoreGenerateBtn();
|
|
if (xhr.responseText == "") {
|
|
if (editor_debug && editor_debug.setValue) {
|
|
editor_debug.setValue('<%:Some error occurred!%>');
|
|
} else {
|
|
dl.value = '<%:Some error occurred!%>';
|
|
}
|
|
}
|
|
};
|
|
|
|
xhr.send();
|
|
return;
|
|
};
|
|
|
|
function load_debug_log()
|
|
{
|
|
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "get_debug_logs")%>', null, function(x, status) {
|
|
if (x && x.status == 200 && x.responseText != "")
|
|
{
|
|
dl.value = x.responseText;
|
|
if (typeof editor_debug !== 'undefined' && editor_debug && editor_debug.setValue) {
|
|
editor_debug.setValue(x.responseText);
|
|
setCursorToFirstLineEnd(editor_debug);
|
|
}
|
|
renderDebugView();
|
|
}
|
|
else
|
|
{
|
|
if (typeof markdown_editor === 'function' && dl) {
|
|
markdown_editor(dl, 'debug', true, '100%', '540px');
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
function line_tolocal(input) {
|
|
var trans_local = new Array();
|
|
var local_count = 0;
|
|
var lines;
|
|
|
|
if (Array.isArray(input)) {
|
|
lines = input;
|
|
} else {
|
|
lines = input.trim().split('\n');
|
|
}
|
|
|
|
for (var i = 0; i < lines.length; i++) {
|
|
var v = lines[i];
|
|
if (!v) continue;
|
|
|
|
try {
|
|
if (v.indexOf('time=') >= 0) {
|
|
var regex = /(time=)"([^"]*)"/g;
|
|
var res = regex.exec(v);
|
|
|
|
if (res) {
|
|
var dt = new Date(res[2]);
|
|
|
|
if (!isNaN(dt.getTime())) {
|
|
var timestamp = dt.getFullYear() + "-" + p(dt.getMonth() + 1) + "-" + p(dt.getDate()) + " " +
|
|
p(dt.getHours()) + ":" + p(dt.getMinutes()) + ":" + p(dt.getSeconds());
|
|
var levelMatch = v.match(/level=(\w+)/);
|
|
var level = levelMatch ? levelMatch[1] : 'info';
|
|
var translatedLevel = levelTranslations[level] || level;
|
|
var msgMatch = v.match(/msg="(.*)"/);
|
|
var msg = msgMatch ? msgMatch[1] : '';
|
|
trans_local[local_count] = timestamp + " [" + translatedLevel + "] " + msg;
|
|
local_count++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
var dtt = new Date(v.substring(0, 19));
|
|
|
|
if (!isNaN(dtt.getTime()) && v.substring(0, 19).match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)) {
|
|
trans_local[local_count] = v;
|
|
local_count++;
|
|
} else {
|
|
trans_local[local_count] = v;
|
|
local_count++;
|
|
}
|
|
} catch (e) {
|
|
trans_local[local_count] = v;
|
|
local_count++;
|
|
}
|
|
} catch (e) {
|
|
trans_local[local_count] = v;
|
|
local_count++;
|
|
}
|
|
}
|
|
|
|
return trans_local;
|
|
};
|
|
|
|
function setCursorToFirstLineEnd(editor) {
|
|
if (!editor || !editor.state) return;
|
|
var doc = editor.state.doc;
|
|
if (doc.lines >= 1) {
|
|
var fl = doc.line(1);
|
|
editor.dispatch({ selection: { anchor: fl.to }, scrollIntoView: true });
|
|
}
|
|
}
|
|
|
|
function smoothlyDisplayLogs(newLines, target, isEditor, currentContent, isActiveTab) {
|
|
var scrollPosition = null;
|
|
var isAtTop = false;
|
|
var cursorPos = null;
|
|
var selectionRange = null;
|
|
|
|
if (isEditor && target) {
|
|
scrollPosition = target.getScrollInfo();
|
|
isAtTop = (scrollPosition.top < 20);
|
|
|
|
if (target.hasFocus()) {
|
|
cursorPos = target.getCursor();
|
|
|
|
if (cursorPos.line === 0) {
|
|
cursorPos = null;
|
|
selectionRange = null;
|
|
} else if (target.somethingSelected()) {
|
|
selectionRange = {
|
|
from: target.getCursor(true),
|
|
to: target.getCursor(false)
|
|
};
|
|
} else {
|
|
selectionRange = null;
|
|
}
|
|
} else {
|
|
cursorPos = null;
|
|
selectionRange = null;
|
|
}
|
|
} else if (!isEditor && target) {
|
|
scrollPosition = target.scrollTop;
|
|
isAtTop = (target.scrollTop < 20);
|
|
}
|
|
|
|
if ((target === editor_oc && animatingOC) || (target === editor_core && animatingCore) || (target === editor_debug && animatingDebug) || !isActiveTab) {
|
|
var lines = newLines.slice().reverse();
|
|
var content = lines.join('\n') + (lines.length > 0 ? '\n' : '') + (currentContent || '');
|
|
var allLines = content.split("\n");
|
|
if (allLines.length > 2000) {
|
|
allLines = allLines.slice(0, 1999);
|
|
allLines.push("...");
|
|
content = allLines.join("\n");
|
|
}
|
|
|
|
if (isEditor) {
|
|
var addedLines = lines.length;
|
|
target.setValue(content);
|
|
|
|
if (!isAtTop && scrollPosition) {
|
|
if (cursorPos) {
|
|
cursorPos.line += addedLines;
|
|
target.setCursor(cursorPos);
|
|
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
|
|
} else {
|
|
target.scrollTo(scrollPosition.left, scrollPosition.top);
|
|
}
|
|
|
|
if (selectionRange) {
|
|
selectionRange.from.line += addedLines;
|
|
selectionRange.to.line += addedLines;
|
|
target.setSelection(selectionRange.from, selectionRange.to);
|
|
target.scrollIntoView({
|
|
from: selectionRange.from,
|
|
to: selectionRange.to
|
|
}, 300);
|
|
}
|
|
} else if (isAtTop) {
|
|
target.scrollTo(0, 0);
|
|
if (!cursorPos) {
|
|
var firstLineLen = target.state.doc.line(1).length;
|
|
target.setCursor({line: 0, ch: firstLineLen});
|
|
}
|
|
}
|
|
} else {
|
|
var oldScrollTop = scrollPosition;
|
|
target.innerHTML = content;
|
|
if (!isAtTop && oldScrollTop) {
|
|
target.scrollTop = oldScrollTop;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (target === editor_oc || target === lv) {
|
|
animatingOC = true;
|
|
} else if (target === editor_debug) {
|
|
animatingDebug = true;
|
|
} else {
|
|
animatingCore = true;
|
|
}
|
|
|
|
var totalLines = newLines.length;
|
|
var batchSize, interval;
|
|
|
|
if (totalLines <= 10) {
|
|
batchSize = 5;
|
|
interval = 80;
|
|
} else if (totalLines <= 50) {
|
|
batchSize = 25;
|
|
interval = 50;
|
|
} else if (totalLines <= 200) {
|
|
batchSize = 60;
|
|
interval = 30;
|
|
} else if (totalLines <= 500) {
|
|
batchSize = 150;
|
|
interval = 20;
|
|
} else if (totalLines <= 1000) {
|
|
batchSize = 300;
|
|
interval = 12;
|
|
} else if (totalLines <= 1500) {
|
|
batchSize = 400;
|
|
interval = 8;
|
|
} else {
|
|
batchSize = 500;
|
|
interval = 5;
|
|
}
|
|
|
|
var displayedContent = currentContent || "";
|
|
var logLines = newLines.slice();
|
|
var currentBatchCount = 0;
|
|
var accumulatedContent = "";
|
|
|
|
function displayNextBatch() {
|
|
if (currentBatchCount >= logLines.length) {
|
|
if (target === editor_oc || target === lv) {
|
|
animatingOC = false;
|
|
} else if (target === editor_debug) {
|
|
animatingDebug = false;
|
|
} else {
|
|
animatingCore = false;
|
|
}
|
|
|
|
if (isEditor && !isAtTop && cursorPos) {
|
|
cursorPos.line += logLines.length;
|
|
target.setCursor(cursorPos);
|
|
|
|
if (selectionRange) {
|
|
selectionRange.from.line += logLines.length;
|
|
selectionRange.to.line += logLines.length;
|
|
target.setSelection(selectionRange.from, selectionRange.to);
|
|
|
|
target.scrollIntoView({
|
|
from: selectionRange.from,
|
|
to: selectionRange.to
|
|
}, 300);
|
|
} else {
|
|
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
|
|
}
|
|
}
|
|
if (isEditor && !cursorPos) {
|
|
setCursorToFirstLineEnd(target);
|
|
}
|
|
return;
|
|
}
|
|
|
|
var nextBatchSize = Math.min(batchSize, logLines.length - currentBatchCount);
|
|
|
|
var batchLines = logLines.slice(currentBatchCount, currentBatchCount + nextBatchSize).reverse();
|
|
currentBatchCount += nextBatchSize;
|
|
|
|
if (accumulatedContent) {
|
|
accumulatedContent = batchLines.join("\n") + "\n" + accumulatedContent;
|
|
} else {
|
|
accumulatedContent = batchLines.join("\n");
|
|
}
|
|
|
|
var content = accumulatedContent + (displayedContent ? "\n" + displayedContent : "");
|
|
|
|
if (isEditor) {
|
|
var currentScrollInfo = isAtTop ? null : target.getScrollInfo();
|
|
target.setValue(content);
|
|
|
|
if (!isAtTop && currentScrollInfo) {
|
|
target.scrollTo(currentScrollInfo.left, currentScrollInfo.top);
|
|
}
|
|
} else {
|
|
var currentScrollTop = isAtTop ? null : target.scrollTop;
|
|
target.innerHTML = content;
|
|
if (!isAtTop && currentScrollTop !== null) {
|
|
target.scrollTop = currentScrollTop;
|
|
}
|
|
}
|
|
|
|
if (currentBatchCount < logLines.length) {
|
|
setTimeout(displayNextBatch, interval);
|
|
} else {
|
|
if (target === editor_oc || target === lv) {
|
|
animatingOC = false;
|
|
} else if (target === editor_debug) {
|
|
animatingDebug = false;
|
|
} else {
|
|
animatingCore = false;
|
|
}
|
|
|
|
if (isEditor && !isAtTop && cursorPos) {
|
|
cursorPos.line += logLines.length;
|
|
target.setCursor(cursorPos);
|
|
|
|
if (selectionRange) {
|
|
selectionRange.from.line += logLines.length;
|
|
selectionRange.to.line += logLines.length;
|
|
target.setSelection(selectionRange.from, selectionRange.to);
|
|
|
|
target.scrollIntoView({
|
|
from: selectionRange.from,
|
|
to: selectionRange.to
|
|
}, 300);
|
|
} else {
|
|
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
|
|
}
|
|
}
|
|
if (isEditor && !cursorPos) {
|
|
setCursorToFirstLineEnd(target);
|
|
}
|
|
|
|
if (isEditor) {
|
|
var finalContent = target.getValue();
|
|
var finalLines = finalContent.split("\n");
|
|
if (finalLines.length > 2000) {
|
|
finalLines = finalLines.slice(0, 1999);
|
|
finalLines.push("...");
|
|
target.setValue(finalLines.join("\n"));
|
|
if (!cursorPos) {
|
|
setCursorToFirstLineEnd(target);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
displayNextBatch();
|
|
}
|
|
|
|
function poll_log(){
|
|
var activeTabId = 0;
|
|
var titles = document.getElementsByName('tab-header');
|
|
var core_logs = [];
|
|
var oc_logs = [];
|
|
var currentCoreContent = "";
|
|
var currentContent = "";
|
|
var bufferToProcess = [];
|
|
|
|
clearTimeout(r);
|
|
|
|
for(var i=0; i<titles.length; i++){
|
|
if(titles[i].className === 'oc-tab') {
|
|
activeTabId = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (coreWebSocket && coreWebSocket.readyState == WebSocket.OPEN) {
|
|
core_refresh = !wsHasData;
|
|
if (coreLogBuffer.length > 0) {
|
|
bufferToProcess = coreLogBuffer;
|
|
coreLogBuffer = [];
|
|
core_logs = line_tolocal(bufferToProcess);
|
|
if (editor_core && activeTabId === 1) {
|
|
currentCoreContent = editor_core.getValue();
|
|
smoothlyDisplayLogs(core_logs, editor_core, true, currentCoreContent, true);
|
|
} else {
|
|
accumulateCoreLog(core_logs);
|
|
}
|
|
}
|
|
} else {
|
|
core_refresh = true;
|
|
}
|
|
|
|
if (isPolling) {
|
|
r = setTimeout("poll_log()", pollInterval);
|
|
return;
|
|
}
|
|
|
|
if (activeTabId === 2) {
|
|
return;
|
|
}
|
|
|
|
isPolling = true;
|
|
|
|
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "refresh_log")%>',
|
|
{
|
|
log_len: log_len, core_refresh: core_refresh
|
|
},
|
|
function(x, status) {
|
|
if (x && x.status == 200) {
|
|
if (status) {
|
|
if (!status.update) {
|
|
isPolling = false;
|
|
r = setTimeout("poll_log()", pollInterval);
|
|
return;
|
|
}
|
|
|
|
if (status.len) {
|
|
log_len = status.len;
|
|
}
|
|
|
|
if (status.oc_log && status.oc_log !== "") {
|
|
oc_logs = line_tolocal(status.oc_log);
|
|
|
|
if (oc_logs.length > 0) {
|
|
if (editor_oc) {
|
|
currentContent = editor_oc.getValue();
|
|
smoothlyDisplayLogs(oc_logs, editor_oc, true, currentContent, activeTabId === 0);
|
|
} else if (lv) {
|
|
currentContent = lv.innerHTML;
|
|
smoothlyDisplayLogs(oc_logs, lv, false, currentContent, activeTabId === 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (status.core_log && status.core_log !== "") {
|
|
core_logs = line_tolocal(status.core_log);
|
|
|
|
if (core_logs.length > 0) {
|
|
if (editor_core && activeTabId === 1) {
|
|
currentCoreContent = editor_core.getValue();
|
|
smoothlyDisplayLogs(core_logs, editor_core, true, currentCoreContent, true);
|
|
} else {
|
|
accumulateCoreLog(core_logs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
isPolling = false;
|
|
r = setTimeout("poll_log()", pollInterval);
|
|
}
|
|
);
|
|
};
|
|
|
|
window.onload = function(){
|
|
var titles = document.getElementsByName('tab-header');
|
|
var divs = document.getElementsByClassName('dom');
|
|
if(titles.length != divs.length) return;
|
|
|
|
var tc = document.getElementById('tab-content');
|
|
if (tc) tc.style.position = 'relative';
|
|
|
|
divs[0].classList.add('active');
|
|
|
|
for(var i=0; i<titles.length; i++){
|
|
var li = titles[i];
|
|
li.id = i;
|
|
function handleTabSwitch(tab) {
|
|
return function(e) {
|
|
if (tab.className === 'oc-tab') return;
|
|
var prevTabId = -1;
|
|
for(var j=0; j<titles.length; j++){
|
|
if (titles[j].className === 'oc-tab') prevTabId = j;
|
|
titles[j].className = 'oc-tab-disabled';
|
|
divs[j].classList.remove('active');
|
|
}
|
|
tab.className = 'oc-tab';
|
|
divs[tab.id].classList.add('active');
|
|
|
|
if (prevTabId == 1 && editor_core) {
|
|
coreLogAccumulator = editor_core.getValue();
|
|
cl.value = coreLogAccumulator;
|
|
}
|
|
|
|
if (tab.id == 0 && typeof editor_oc !== 'undefined' && editor_oc) {
|
|
setCursorToFirstLineEnd(editor_oc);
|
|
}
|
|
|
|
if (tab.id == 1 && !coreEditorInitialized) {
|
|
coreEditorInitialized = true;
|
|
if (typeof log_editor === 'function' && cl) {
|
|
cl.value = coreLogAccumulator.replace(/\n+$/, '');
|
|
log_editor(cl, 'core', true, '100%', '540px');
|
|
}
|
|
} else if (tab.id == 1 && editor_core) {
|
|
editor_core.setValue(coreLogAccumulator.replace(/\n+$/, ''));
|
|
editor_core.refresh();
|
|
setCursorToFirstLineEnd(editor_core);
|
|
}
|
|
|
|
if (tab.id == 2 && typeof editor_debug !== 'undefined' && editor_debug) {
|
|
setCursorToFirstLineEnd(editor_debug);
|
|
}
|
|
|
|
pollInterval = (tab.id == 1) ? 5000 : 1000;
|
|
clearTimeout(r);
|
|
poll_log();
|
|
};
|
|
}
|
|
|
|
li.onclick = handleTabSwitch(li);
|
|
li.ontouchstart = handleTabSwitch(li);
|
|
}
|
|
get_log_level();
|
|
poll_log();
|
|
setTimeout(function() {
|
|
load_debug_log();
|
|
}, 500);
|
|
};
|
|
|
|
function renderDebugView(src) {
|
|
var wrapper = document.getElementById('debug-render-wrapper');
|
|
var rendered = document.getElementById('debug-rendered');
|
|
if (!wrapper || !rendered) return;
|
|
if (!src) {
|
|
if (typeof editor_debug !== 'undefined' && editor_debug) {
|
|
src = editor_debug.getValue();
|
|
} else if (dl) {
|
|
src = dl.value || '';
|
|
}
|
|
}
|
|
if (!src) return;
|
|
|
|
if (typeof editor_debug !== 'undefined' && editor_debug && editor_debug.dom) {
|
|
editor_debug.dom.style.setProperty('display', 'none', 'important');
|
|
}
|
|
var cms = dl.parentNode.querySelectorAll('.cm-editor');
|
|
for (var i = 0; i < cms.length; i++) {
|
|
cms[i].style.setProperty('display', 'none', 'important');
|
|
}
|
|
|
|
if (typeof CM6 !== 'undefined' && CM6.renderMarkdown) {
|
|
rendered.innerHTML = CM6.renderMarkdown(src);
|
|
} else {
|
|
rendered.innerHTML = src.replace(/</g,'<').replace(/>/g,'>').replace(/\n/g,'<br>');
|
|
}
|
|
|
|
var pres = rendered.querySelectorAll('pre');
|
|
var copyIcon = '<svg width="14" height="14"><use href="#oc-icon-copy"/></svg>';
|
|
for (var i = 0; i < pres.length; i++) {
|
|
(function(pre) {
|
|
if (pre.parentNode && pre.parentNode.classList.contains('pre-copy-wrap')) return;
|
|
var btn = document.createElement('div');
|
|
btn.className = 'pre-copy-btn';
|
|
btn.title = '<%:Copy%>';
|
|
btn.innerHTML = copyIcon;
|
|
btn.onclick = function(e) {
|
|
e.stopPropagation();
|
|
var text = pre.textContent || '';
|
|
ocCopyToClipboard(text, btn);
|
|
};
|
|
var wrap = document.createElement('div');
|
|
wrap.className = 'pre-copy-wrap';
|
|
pre.parentNode.insertBefore(wrap, pre);
|
|
wrap.appendChild(pre);
|
|
wrap.appendChild(btn);
|
|
})(pres[i]);
|
|
}
|
|
|
|
wrapper.style.display = 'block';
|
|
dl.style.display = 'none';
|
|
if (dl.parentNode && dl.parentNode.className.indexOf('oc') < 0) {
|
|
dl.parentNode.classList.add('oc');
|
|
}
|
|
}
|
|
|
|
function copyDebugSource() {
|
|
var src = '';
|
|
if (typeof editor_debug !== 'undefined' && editor_debug) {
|
|
src = editor_debug.getValue();
|
|
} else if (dl) {
|
|
src = dl.value || '';
|
|
}
|
|
if (!src) return;
|
|
ocCopyToClipboard(src, document.getElementById('debug-copy-source'));
|
|
}
|
|
|
|
//]]>
|
|
</script>
|
|
<%+cbi/valuefooter%>
|