Reconnect logs web socket on log level change

This commit is contained in:
Haishan 2021-06-05 18:50:41 +08:00
parent 297fb101e7
commit 8c2af7a813
5 changed files with 41 additions and 39 deletions

View file

@ -1,5 +1,6 @@
import { pad0 } from 'src/misc/utils';
import { Log, LogsAPIConfig } from 'src/types';
import { Log } from 'src/store/types';
import { LogsAPIConfig } from 'src/types';
import { buildLogsWebSocketURL, getURLAndInit } from '../misc/request-helper';
@ -15,6 +16,8 @@ const getRandomStr = () => {
let even = false;
let fetched = false;
let decoded = '';
let ws: WebSocket;
let prevAppendLogFn: AppendLogFn;
function appendData(s: string, callback: AppendLogFn) {
let o: Partial<Log>;
@ -31,7 +34,7 @@ function appendData(s: string, callback: AppendLogFn) {
o.time = time;
o.id = +now - 0 + getRandomStr();
o.even = even = !even;
callback(o);
callback(o as Log);
}
function formatDate(d: Date) {
@ -73,7 +76,14 @@ function pump(reader: ReadableStreamDefaultReader, appendLog: AppendLogFn) {
});
}
let apiConfigSnapshot: LogsAPIConfig;
/** loose hashing of the connection configuration */
function makeConnStr(c: LogsAPIConfig) {
const keys = Object.keys(c);
keys.sort();
return keys.map((k) => c[k]).join('|');
}
let prevConnStr: string;
let controller: AbortController;
// 1 OPEN
@ -84,11 +94,11 @@ let wsState: number;
export function fetchLogs(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) {
if (apiConfig.logLevel === 'uninit') return;
if (fetched || wsState === 1) return;
prevAppendLogFn = appendLog;
wsState = 1;
const url = buildLogsWebSocketURL(apiConfig, endpoint);
const ws = new WebSocket(url);
ws.addEventListener('error', () => (wsState = 3));
ws.addEventListener('close', function (_ev) {
ws = new WebSocket(url);
ws.addEventListener('error', () => {
wsState = 3;
fetchLogsWithFetch(apiConfig, appendLog);
});
@ -97,20 +107,23 @@ export function fetchLogs(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) {
});
}
export function reconnect(apiConfig: LogsAPIConfig) {
if (!prevAppendLogFn || !ws) return;
ws.close();
wsState = 3;
fetched = false;
fetchLogs(apiConfig, prevAppendLogFn);
}
function fetchLogsWithFetch(apiConfig: LogsAPIConfig, appendLog: AppendLogFn) {
if (
controller &&
(apiConfigSnapshot.baseURL !== apiConfig.baseURL ||
apiConfigSnapshot.secret !== apiConfig.secret ||
apiConfigSnapshot.logLevel !== apiConfig.logLevel)
) {
if (controller && makeConnStr(apiConfig) !== prevConnStr) {
controller.abort();
} else if (fetched) {
return;
}
fetched = true;
apiConfigSnapshot = { ...apiConfig };
prevConnStr = makeConnStr(apiConfig);
controller = new AbortController();
const signal = controller.signal;

View file

@ -1,6 +1,7 @@
import * as React from 'react';
import { LogOut } from 'react-feather';
import { useTranslation } from 'react-i18next';
import * as logsApi from 'src/api/logs';
import Select from 'src/components/shared/Select';
import { ClashGeneralConfig, DispatchFn, State } from 'src/store/types';
import { ClashAPIConfig } from 'src/types';
@ -103,10 +104,7 @@ function ConfigImpl({
const setConfigState = useCallback(
(name, val) => {
setConfigStateInternal({
...configState,
[name]: val,
});
setConfigStateInternal({ ...configState, [name]: val });
},
[configState]
);
@ -128,6 +126,9 @@ function ConfigImpl({
case 'log-level':
setConfigState(name, value);
dispatch(updateConfigs(apiConfig, { [name]: value }));
if (name === 'log-level') {
logsApi.reconnect({ ...apiConfig, logLevel: value });
}
break;
case 'redir-port':
case 'socks-port':

View file

@ -23,8 +23,7 @@ const { useCallback, memo, useEffect } = React;
const paddingBottom = 30;
const colors = {
debug: 'none',
// debug: '#8a8a8a',
debug: '#28792c',
info: 'var(--bg-log-info-tag)',
warning: '#b99105',
error: '#c11c1c',
@ -66,9 +65,7 @@ const Row = memo(
function Logs({ dispatch, logLevel, apiConfig, logs }) {
const appendLogInternal = useCallback(
(log) => {
dispatch(appendLog(log));
},
(log) => dispatch(appendLog(log)),
[dispatch]
);
useEffect(() => {

View file

@ -4,7 +4,6 @@ import Loading from 'src/components/Loading';
import Button from './Button';
import Input from './Input';
import { LoadingDot } from './shared/Basic';
import SwitchThemed from './SwitchThemed';
import ToggleSwitch from './ToggleSwitch';
@ -17,18 +16,9 @@ const paneStyle = {
};
const optionsRule = [
{
label: 'Global',
value: 'Global',
},
{
label: 'Rule',
value: 'Rule',
},
{
label: 'Direct',
value: 'Direct',
},
{ label: 'Global', value: 'Global' },
{ label: 'Rule', value: 'Rule' },
{ label: 'Direct', value: 'Direct' },
];
const Pane = ({ children, style }) => (

View file

@ -1,6 +1,5 @@
import { createSelector } from 'reselect';
import { DispatchFn, GetStateFn, Log, State } from './types';
import { DispatchFn, GetStateFn, Log, State } from 'src/store/types';
const LogSize = 300;
@ -44,7 +43,9 @@ export function appendLog(log: Log) {
// mutate intentionally for performance
logs[tail] = log;
dispatch('logsAppendLog', (s: State) => (s.logs.tail = tail));
dispatch('logsAppendLog', (s: State) => {
s.logs.tail = tail;
});
};
}