diff --git a/package-lock.json b/package-lock.json index 495e09d..22f3b76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "antd": "^4.15.0", "electron-squirrel-startup": "^1.0.0", "js-yaml": "^4.0.0 ", - "mlg-converter": "^0.4.0", + "mlg-converter": "^0.5.0", "parsimmon": "^1.16.0", "react": "^17.0.1", "react-dom": "^17.0.2", @@ -15534,9 +15534,9 @@ } }, "node_modules/mlg-converter": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/mlg-converter/-/mlg-converter-0.4.0.tgz", - "integrity": "sha512-lWO5KYOpGogrW8bqAfFTQU+22g4LnCehGf7ZiFfMOfu/S0Rt5t9ZIlHYAOi3Qh79qoDnD1hk/oMXhKRouagI0w==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mlg-converter/-/mlg-converter-0.5.0.tgz", + "integrity": "sha512-FKqJ0vbbxFZuziwMbih8fRF8JFF2xFSWmYNOylji1IkRPu83dCWCGV4AkG9fkKs/z9ThOqfuSkaUEnWbL33c8g==" }, "node_modules/moment": { "version": "2.29.1", @@ -38513,9 +38513,9 @@ } }, "mlg-converter": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/mlg-converter/-/mlg-converter-0.4.0.tgz", - "integrity": "sha512-lWO5KYOpGogrW8bqAfFTQU+22g4LnCehGf7ZiFfMOfu/S0Rt5t9ZIlHYAOi3Qh79qoDnD1hk/oMXhKRouagI0w==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mlg-converter/-/mlg-converter-0.5.0.tgz", + "integrity": "sha512-FKqJ0vbbxFZuziwMbih8fRF8JFF2xFSWmYNOylji1IkRPu83dCWCGV4AkG9fkKs/z9ThOqfuSkaUEnWbL33c8g==" }, "moment": { "version": "2.29.1", diff --git a/package.json b/package.json index 621c8db..d6c2adf 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "antd": "^4.15.0", "electron-squirrel-startup": "^1.0.0", "js-yaml": "^4.0.0 ", - "mlg-converter": "^0.4.0", + "mlg-converter": "^0.5.0", "parsimmon": "^1.16.0", "react": "^17.0.1", "react-dom": "^17.0.2", diff --git a/public/logs/long.mlg b/public/logs/long.mlg new file mode 100644 index 0000000..e05f5d2 Binary files /dev/null and b/public/logs/long.mlg differ diff --git a/src/components/Log.tsx b/src/components/Log.tsx index 0468da8..68c5a1b 100644 --- a/src/components/Log.tsx +++ b/src/components/Log.tsx @@ -26,7 +26,7 @@ import useBreakpoint from 'antd/lib/grid/hooks/useBreakpoint'; import { connect } from 'react-redux'; import { Field, - Result as ParserResult, + Result as ParserResult, } from 'mlg-converter/dist/types'; import PerfectScrollbar from 'react-perfect-scrollbar'; // eslint-disable-next-line import/no-unresolved @@ -35,13 +35,13 @@ import { loadLogs } from '../utils/api'; import Canvas, { LogEntry } from './Log/Canvas'; import { AppState, - UIState, + UIState, } from '../types/state'; import { Config } from '../types/config'; import store from '../store'; import { formatBytes, - msToTime, + msToTime, } from '../utils/number'; const { TabPane } = Tabs; @@ -89,9 +89,13 @@ const Log = ({ ui, config }: { ui: UIState, config: Config }) => { useEffect(() => { const worker = new MlgParserWorker(); + const controller = new AbortController(); + const { signal } = controller; const loadData = async () => { - const raw = await loadLogs(); - setFileSize(formatBytes(raw.byteLength)); + const raw = await loadLogs((percent, total) => { + setProgress(percent); + setFileSize(formatBytes(total)); + }, signal); worker.postMessage(raw); worker.onmessage = ({ data }) => { @@ -99,15 +103,17 @@ const Log = ({ ui, config }: { ui: UIState, config: Config }) => { case 'progress': setStep(1); setProgress(data.progress); + setParseElapsed(msToTime(data.elapsed)); break; case 'result': - setSamplesCount(data.result.records.length); - setStep(2); setLogs(data.result); setFields(data.result.fields); break; case 'metrics': - setParseElapsed(msToTime(data.metrics.elapsedMs)); + console.log(`Log parsed in ${data.elapsed}ms`); + setParseElapsed(msToTime(data.elapsed)); + setSamplesCount(data.records); + setStep(2); break; default: break; @@ -121,8 +127,9 @@ const Log = ({ ui, config }: { ui: UIState, config: Config }) => { window.addEventListener('resize', calculateCanvasWidth); return () => { - window.removeEventListener('resize', calculateCanvasWidth); + controller.abort(); worker.terminate(); + window.removeEventListener('resize', calculateCanvasWidth); }; }, [calculateCanvasWidth]); diff --git a/src/utils/api.ts b/src/utils/api.ts index 4921548..1b5b0c1 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -3,6 +3,10 @@ import { Config as ConfigType } from '../types/config'; import stdDialogs from '../data/standardDialogs'; import help from '../data/help'; import { divider } from '../data/constants'; +import { + fetchWithProgress, + onProgress as onProgressType, +} from './http'; export const loadAll = async () => { const started = new Date(); @@ -74,4 +78,5 @@ export const loadAll = async () => { }); }; -export const loadLogs = () => fetch('./logs/middle.mlg').then((response) => response.arrayBuffer()); +export const loadLogs = (onProgress?: onProgressType, signal?: AbortSignal) => fetchWithProgress('./logs/long.mlg', onProgress, signal) + .then((response) => response.buffer); diff --git a/src/utils/http.ts b/src/utils/http.ts new file mode 100644 index 0000000..f96ad3f --- /dev/null +++ b/src/utils/http.ts @@ -0,0 +1,34 @@ +export type onProgress = (percent: number, total: number) => void; + +export const fetchWithProgress = async (url: string, onProgress?: onProgress, signal?: AbortSignal): Promise => { + const response = await fetch(url, { signal }); + const contentLength = response.headers.get('Content-Length'); + + if (!contentLength) { + throw new Error('Missing Content-Length while fetching'); + } + + const reader = response.body!.getReader(); + const length = Number(contentLength); + const array = new Uint8Array(length); + + let at = 0; + for (; ;) { + // eslint-disable-next-line no-await-in-loop + const { done, value } = await reader.read(); + + if (done) { + break; + } + + array.set(value as Uint8Array, at); + at += (value as Uint8Array).length; + + if (onProgress) { + // eslint-disable-next-line no-bitwise + onProgress(~~(at / length * 100), length); + } + } + + return array; +}; diff --git a/src/workers/mlgParser.worker.ts b/src/workers/mlgParser.worker.ts index a27d2b6..e363ea6 100644 --- a/src/workers/mlgParser.worker.ts +++ b/src/workers/mlgParser.worker.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-bitwise */ import { Parser } from 'mlg-converter'; // eslint-disable-next-line no-restricted-globals @@ -10,13 +11,13 @@ ctx.addEventListener('message', ({ data }: { data: ArrayBuffer }) => { ctx.postMessage({ type: 'progress', progress, + elapsed: ~~(performance.now() - t0), }); }); ctx.postMessage({ type: 'metrics', - metrics: { - elapsedMs: Math.round(performance.now() - t0), - }, + elapsed: ~~(performance.now() - t0), + records: result.records.length, }); ctx.postMessage({ type: 'result', result }); });