@doreamonjs/gate
Version:
gate for doreamonjs
231 lines • 10.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const react_1 = tslib_1.__importStar(require("react"));
const dva_1 = require("dva");
const doreamon_1 = tslib_1.__importDefault(require("@zodash/doreamon"));
const antd_1 = require("antd");
const icons_1 = require("@ant-design/icons");
const components_1 = require("@doreamonjs/components");
const log = tslib_1.__importStar(require("@doreamonjs/plugin-log"));
const fetch_event_source_1 = require("@microsoft/fetch-event-source");
class EventSourceX {
constructor(url, options) {
this._event = new doreamon_1.default.event.Event();
this._ctrl = new AbortController();
const method = (options === null || options === void 0 ? void 0 : options.method) || 'GET';
fetch_event_source_1.fetchEventSource(url, {
method: method,
headers: options === null || options === void 0 ? void 0 : options.headers,
body: options === null || options === void 0 ? void 0 : options.body,
signal: this._ctrl.signal,
onopen: (response) => {
var _a, _b;
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
const error = new Error(`HTTP ${response.status} ${response.statusText}`);
this._event.emit('error', error);
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
return Promise.reject();
}
this._event.emit('open', response);
(_b = this.onopen) === null || _b === void 0 ? void 0 : _b.call(this, response);
return Promise.resolve();
},
onmessage: (event) => {
var _a;
this._event.emit('message', event);
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, event);
return Promise.resolve();
},
onclose: () => {
this._event.emit('close');
// this._ctrl.abort();
return Promise.resolve();
},
onerror: (error) => {
var _a;
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
},
});
}
close() {
this._ctrl.abort();
}
addEventListener(type, listener) {
this._event.on(type, listener);
}
}
const Log = (props) => {
var _a;
const xtermRef = react_1.useRef(null);
// const source = useRef<EventSource | null>(null);
const source = react_1.useRef(null);
const [isWaitingForLog, setIsWaitingForLog] = react_1.useState(false);
const staticLogRef = react_1.useRef(undefined);
const drawerProps = {
// className: styles.drawerform,
width: props.width || 800,
title: props.title || '日志',
// placement: 'right',
visible: props.visible,
onClose: props.onClose,
// closable: false,
maskClosable: false,
};
const onLogDownload = react_1.useCallback(async () => {
try {
await doreamon_1.default.fs.download(props.downloadURL, props.downloadFilename, {
headers: {
'Accept': 'text/plain,text/html,application/octet-stream',
},
});
}
catch (err) {
console.error(err);
antd_1.message.error(`下载失败:${err.message}`);
}
}, [props.downloadURL, props.downloadFilename]);
react_1.useEffect(() => {
var _a, _b;
const terminal = (_a = xtermRef.current) === null || _a === void 0 ? void 0 : _a.terminal;
if (!terminal) {
return;
}
terminal.clear();
if (!!props.sse) {
// source.current = new EventSource(props.sse);
source.current = new EventSourceX(props.sse, props.sseOptions);
// terminal.write('实时日志,等待中 ...\r\n');
setIsWaitingForLog(true);
let isAlreadySet = false;
source.current.onmessage = (event) => {
if (!isAlreadySet) {
isAlreadySet = true;
setIsWaitingForLog(false);
// setTimeout(() => {
// setIsWaitingForLog(false);
// }, 1000);
}
let data;
let log;
try {
data = JSON.parse(event.data);
log = data.log;
}
catch (err) {
console.error(err);
return;
}
// @TODO ignore empty log
if (!log) {
return;
}
if (log == '[DONE]') {
source.current.close();
source.current = null;
return;
}
// const lines = log
// .split('\n')
// // .map(e => {
// // if (!e.trim()) return e;
// // return `[${data.id}][${doreamon.date(data.ts).format('YYYY-MM-DD HH:mm:ss')}] ${e}`;
// // })
// .join('\r\n');
// terminal.write(lines);
// terminal.write(log);
// @TODO why must use '\r\n' ?
terminal.write(log.split('\n').join('\r\n'));
terminal.scrollToBottom();
};
return () => {
if (!!source.current) {
source.current.close();
source.current = null;
}
};
}
(_b = props.log) === null || _b === void 0 ? void 0 : _b.split('\n').forEach((e) => terminal.write(e + '\r\n'));
setTimeout(() => {
terminal.scrollToBottom();
}, 100);
}, [props.log, props.sse]);
react_1.useEffect(() => {
if (!staticLogRef.current) {
return;
}
const div = staticLogRef.current;
div.scrollTop = div.scrollHeight;
}, [props.log, props.sse]);
react_1.useEffect(() => {
// if close drawer, close sse
if (!props.visible && !!source.current) {
source.current.close();
source.current = null;
}
}, [props.visible]);
if (!props.sse) {
return (react_1.default.createElement(antd_1.Drawer, { ...drawerProps, bodyStyle: {
backgroundColor: '#000',
padding: 0,
}, placement: "right" },
react_1.default.createElement("div", { style: {
position: 'relative',
width: '100%',
height: '100%',
overflow: 'hidden',
overflowY: 'auto',
}, ref: staticLogRef },
props.downloadURL && (react_1.default.createElement(antd_1.Button, { style: {
position: 'fixed',
top: 70,
right: 20,
zIndex: 100,
}, icon: react_1.default.createElement(icons_1.CloudDownloadOutlined, null), onClick: onLogDownload }, (_a = props.downloadBtnText) !== null && _a !== void 0 ? _a : '下载')),
react_1.default.createElement("pre", { style: {
color: '#fff',
paddingTop: 10,
paddingLeft: 10,
whiteSpace: 'pre-wrap',
} }, props.log || '无日志'))));
}
return (react_1.default.createElement(antd_1.Drawer, { ...drawerProps, bodyStyle: {
backgroundColor: '#000',
padding: 0,
position: 'relative',
} },
react_1.default.createElement(components_1.Loading.Cover, { style: {
backgroundColor: '#000',
}, loading: isWaitingForLog }),
react_1.default.createElement(components_1.Terminal, { style: {
width: '100%',
// height: 'calc(100vh - 56px)',
height: '100%',
}, ref: xtermRef })));
};
const mapState = (states) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
const state = states[log.NAMESPACE];
const loading = states.loading;
const { nextEffect } = state;
const btnLoading = loading.effects[nextEffect];
return {
loading: btnLoading,
visible: state.visible,
...state.attributes,
values: state.datasets.values,
//
log: (_b = (_a = state.attributes) === null || _a === void 0 ? void 0 : _a.log) !== null && _b !== void 0 ? _b : (_c = state.datasets.values) === null || _c === void 0 ? void 0 : _c.log,
sse: (_e = (_d = state.attributes) === null || _d === void 0 ? void 0 : _d.sse) !== null && _e !== void 0 ? _e : (_f = state.datasets.values) === null || _f === void 0 ? void 0 : _f.sse,
sseOptions: (_h = (_g = state.attributes) === null || _g === void 0 ? void 0 : _g.sseOptions) !== null && _h !== void 0 ? _h : (_j = state.datasets.values) === null || _j === void 0 ? void 0 : _j.sseOptions,
//
downloadURL: (_l = (_k = state.attributes) === null || _k === void 0 ? void 0 : _k.downloadURL) !== null && _l !== void 0 ? _l : (_m = state.datasets.values) === null || _m === void 0 ? void 0 : _m.downloadURL,
downloadFilename: (_p = (_o = state.attributes) === null || _o === void 0 ? void 0 : _o.downloadFilename) !== null && _p !== void 0 ? _p : (_q = state.datasets.values) === null || _q === void 0 ? void 0 : _q.downloadFilename,
downloadBtnText: (_s = (_r = state.attributes) === null || _r === void 0 ? void 0 : _r.downloadBtnText) !== null && _s !== void 0 ? _s : (_t = state.datasets.values) === null || _t === void 0 ? void 0 : _t.downloadBtnText,
};
};
const mapActions = (dispatch) => ({
onClose: () => dispatch({ type: `${log.NAMESPACE}/close` }),
});
exports.default = dva_1.connect(mapState, mapActions)(Log);
//# sourceMappingURL=index.js.map