feat(logs): fetch logs with correct log level

see also #14
This commit is contained in:
Haishan 2019-05-14 00:30:36 +08:00
parent 882b168082
commit 16e61f1533
20 changed files with 716 additions and 542 deletions

View file

@ -49,8 +49,7 @@
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0",
"regenerator-runtime": "^0.13.2",
"reselect": "^4.0.0",
"whatwg-fetch": "^3.0.0"
"reselect": "^4.0.0"
},
"devDependencies": {
"@babel/core": "^7.1.5",
@ -68,7 +67,7 @@
"css-loader": "^2.0.1",
"cssnano": "^4.1.7",
"eslint": "^5.13.0",
"eslint-config-react-app": "^3.0.8",
"eslint-config-react-app": "^4.0.1",
"eslint-import-resolver-webpack": "^0.11.0",
"eslint-plugin-flowtype": "^3.4.2",
"eslint-plugin-import": "^2.17.2",
@ -78,14 +77,14 @@
"eslint-plugin-react-hooks": "^1.0.1",
"file-loader": "^3.0.0",
"html-webpack-plugin": "^3.2.0",
"husky": "^1.3.0",
"husky": "^2.2.0",
"lint-staged": "^8.1.3",
"mini-css-extract-plugin": "^0.6.0",
"postcss-extend-rule": "^2.0.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"postcss-nested": "^4.1.2",
"prettier": "^1.16.4",
"prettier": "^1.17.1",
"react-hot-loader": "^4.6.3",
"style-loader": "^0.23.0",
"svg-sprite-loader": "^4.1.2",

View file

@ -56,20 +56,49 @@ function pump(reader, appendLog) {
});
}
const apiConfigSnapshot = {};
let controller;
function fetchLogs(apiConfig, appendLog) {
if (fetched) return;
if (
controller &&
(apiConfigSnapshot.hostname !== apiConfig.hostname ||
apiConfigSnapshot.port !== apiConfig.port ||
apiConfigSnapshot.secret !== apiConfig.secret ||
apiConfigSnapshot.logLevel !== apiConfig.logLevel)
) {
controller.abort();
} else if (fetched) {
return;
}
fetched = true;
apiConfigSnapshot.hostname = apiConfig.hostname;
apiConfigSnapshot.port = apiConfig.port;
apiConfigSnapshot.secret = apiConfig.secret;
apiConfigSnapshot.logLevel = apiConfig.logLevel;
controller = new AbortController();
const signal = controller.signal;
const { url, init } = getURLAndInit(apiConfig);
fetch(url + endpoint, init)
.then(response => {
fetch(url + endpoint + '?level=' + apiConfig.logLevel, {
...init,
signal
}).then(
response => {
const reader = response.body.getReader();
pump(reader, appendLog);
})
.catch(err => {
},
err => {
fetched = false;
if (signal.aborted) return;
// eslint-disable-next-line no-console
console.log('GET /logs error', err);
});
console.log('GET /logs error:', err.message);
}
);
}
export { fetchLogs };

View file

@ -7,6 +7,8 @@ import APIConfig from 'c/APIConfig';
import { closeModal } from 'd/modals';
import { fetchConfigs } from 'd/configs';
import { DOES_NOT_SUPPORT_FETCH, errors } from '../misc/errors';
import s0 from './APIDiscovery.module.css';
const mapStateToProps = s => ({
@ -19,11 +21,18 @@ const actions = {
};
export default function APIDiscovery() {
if (!window.fetch) {
const { detail } = errors[DOES_NOT_SUPPORT_FETCH];
const err = new Error(detail);
err.code = DOES_NOT_SUPPORT_FETCH;
throw err;
}
const { modals } = useStoreState(mapStateToProps);
const { closeModal, fetchConfigs } = useActions(actions);
useEffect(() => {
fetchConfigs();
}, []);
}, [fetchConfigs]);
return (
<Modal

View file

@ -74,7 +74,7 @@ export default function ConfigContainer() {
const { configs } = useStoreState(mapStateToProps);
useEffect(() => {
fetchConfigs();
}, []);
}, [fetchConfigs]);
return <Config configs={configs} />;
}

View file

@ -2,6 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { getSentry } from '../misc/sentry';
import ErrorBoundaryFallback from 'c/ErrorBoundaryFallback';
import { deriveMessageFromError } from '../misc/errors';
// XXX this is no Hook equivalents for componentDidCatch
// we have to use class for now
@ -20,13 +21,18 @@ class ErrorBoundary extends Component {
return this.sentry;
};
// static getDerivedStateFromError(error) {
// return { error };
// }
componentDidMount() {
// this.loadSentry();
}
componentDidCatch(error, errorInfo) {
componentDidCatch(error, _info) {
this.setState({ error });
// eslint-disable-next-line no-console
console.log(error, errorInfo);
// console.log(error, errorInfo);
// this.setState({ error });
// this.loadSentry().then(Sentry => {
// Sentry.withScope(scope => {
@ -44,9 +50,9 @@ class ErrorBoundary extends Component {
render() {
if (this.state.error) {
const { message, detail } = deriveMessageFromError(this.state.error);
//render fallback UI
// return <a onClick={this.showReportDialog}>Report feedback</a>;
return <ErrorBoundaryFallback />;
return <ErrorBoundaryFallback message={message} detail={detail} />;
} else {
return this.props.children;
}

View file

@ -1,22 +1,22 @@
import React from 'react';
import Icon from 'c/Icon';
import PropTypes from 'prop-types';
import SvgYacd from './SvgYacd';
import github from 's/github.svg';
import SvgGithub from './SvgGithub';
import s0 from './ErrorBoundaryFallback.module.css';
const yacdRepoIssueUrl = 'https://github.com/haishanh/yacd/issues';
function ErrorBoundaryFallback() {
function ErrorBoundaryFallback({ message, detail }) {
return (
<div className={s0.root}>
<div className={s0.yacd}>
<SvgYacd width={150} height={150} />
</div>
<h1>Oops, something went wrong!</h1>
{message ? <h1>{message}</h1> : null}
{detail ? <p>{detail}</p> : null}
<p>
If you think this is a bug, reporting this at{' '}
<a className={s0.link} href={yacdRepoIssueUrl}>
<Icon id={github.id} width={16} height={16} />
<SvgGithub width={16} height={16} />
haishanh/yacd
</a>
</p>
@ -24,4 +24,8 @@ function ErrorBoundaryFallback() {
);
}
ErrorBoundaryFallback.propTypes = {
message: PropTypes.string
};
export default ErrorBoundaryFallback;

View file

@ -22,9 +22,16 @@
}
.link {
display: inline-flex;
align-items: center;
color: var(--color-text-secondary);
&:hover,
&:active {
color: #387cec;
}
svg {
margin-right: 5px;
}
}

View file

@ -12,6 +12,7 @@ import useRemainingViewPortHeight from '../hooks/useRemainingViewPortHeight';
import { fetchLogs } from '../api/logs';
import LogSearch from './LogSearch';
import { getLogsForDisplay, appendLog } from 'd/logs';
import { getLogLevel } from 'd/configs';
import s0 from 'c/Logs.module.css';
const paddingBottom = 30;
@ -66,10 +67,11 @@ export default function Logs() {
const { hostname, port, secret } = useStoreState(getClashAPIConfig);
const { appendLog } = useActions(actions);
const logs = useStoreState(getLogsForDisplay);
const logLevel = useStoreState(getLogLevel);
useEffect(() => {
fetchLogs({ hostname, port, secret }, appendLog);
}, [hostname, port, secret]);
fetchLogs({ hostname, port, secret, logLevel }, appendLog);
}, [hostname, port, secret, logLevel, appendLog]);
const [refLogsContainer, containerHeight] = useRemainingViewPortHeight();
return (

View file

@ -26,13 +26,12 @@ const actions = {
export default function Proxies() {
const { fetchProxies, requestDelayAll } = useActions(actions);
const fn = async () => {
await fetchProxies();
await requestDelayAll();
};
useEffect(() => {
fn();
}, []);
(async () => {
await fetchProxies();
await requestDelayAll();
})();
}, [fetchProxies, requestDelayAll]);
const { groupNames } = useStoreState(mapStateToProps);
return (

View file

@ -41,7 +41,7 @@ export default function Rules() {
const { rules } = useStoreState(mapStateToProps);
useEffect(() => {
fetchRulesOnce();
}, []);
}, [fetchRulesOnce]);
const [refRulesContainer, containerHeight] = useRemainingViewPortHeight();
return (

View file

@ -0,0 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
export default function SvgGithub({ width = 24, height = 24 } = {}) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width}
height={height}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" />
</svg>
);
}
SvgGithub.propTypes = {
width: PropTypes.number,
height: PropTypes.number
};

View file

@ -35,7 +35,7 @@ export default function TrafficChart({ id }) {
}
]
}),
[]
[id]
);
const eleId = 'chart-' + id;

View file

@ -8,6 +8,7 @@ const OptimisticUpdateConfigs = 'configs/OptimisticUpdateConfigs';
const MarkHaveFetchedConfig = 'configs/MarkHaveFetchedConfig';
export const getConfigs = s => s.configs;
export const getLogLevel = s => s.configs['log-level'];
export function fetchConfigs() {
return async (dispatch, getState) => {
@ -103,7 +104,7 @@ const initialState = {
'redir-port': 0,
'allow-lan': false,
mode: 'Rule',
'log-level': 'info',
'log-level': 'silent',
/////
haveFetchedConfig: false

View file

@ -24,5 +24,5 @@ export default function useLineChart(
unsubscribe && unsubscribe();
c.destroy();
};
}, [Chart, elementId, data, subscription]);
}, [Chart, elementId, data, subscription, extraChartOptions]);
}

View file

@ -21,7 +21,7 @@ export default function useRemainingViewPortHeight() {
return () => {
window.removeEventListener('resize', updateContainerHeight);
};
}, []);
}, [updateContainerHeight]);
return [refRulesContainer, containerHeight];
}

19
src/misc/errors.js Normal file
View file

@ -0,0 +1,19 @@
export const DOES_NOT_SUPPORT_FETCH = 0;
export const errors = {
[DOES_NOT_SUPPORT_FETCH]: {
message: 'Browser not supported!',
detail: 'This browser does not support "fetch", please choose another one.'
},
default: {
message: 'Oops, something went wrong!'
}
};
export function deriveMessageFromError(err) {
const { code } = err;
if (typeof code === 'number') {
return errors[code];
}
return errors.default;
}

View file

@ -35,7 +35,7 @@ function bindActions(actions, dispatch) {
export function useActions(actions) {
const { dispatch } = useStore();
return useMemo(() => bindActions(actions, dispatch), [actions]);
return useMemo(() => bindActions(actions, dispatch), [actions, dispatch]);
}
export function useStoreState(selector) {
@ -52,6 +52,6 @@ export function useStoreState(selector) {
compStateCurr = compStateNext;
setCompState(compStateNext);
});
}, []);
}, [compState, selector, store]);
return compState;
}

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-github"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>

Before

Width:  |  Height:  |  Size: 527 B

View file

@ -27,7 +27,7 @@ const svgSpriteRule = {
// ---- entry
const entry = {
app: ['whatwg-fetch', './src/app.js']
app: ['./src/app.js']
};
// ---- output

1077
yarn.lock

File diff suppressed because it is too large Load diff