perf: wg优化代码封装hooks

This commit is contained in:
TsMask
2024-09-23 17:24:55 +08:00
parent f7273457e9
commit 909d306942
4 changed files with 338 additions and 304 deletions

View File

@@ -0,0 +1,317 @@
import { onBeforeUnmount, onMounted, reactive } from 'vue';
import { scriptUrl } from '@/assets/js/wiregasm_worker';
import { WK, OptionsType } from '@/plugins/wk-worker';
const wk = new WK();
export const NO_SELECTION = { id: '', idx: 0, start: 0, length: 0 };
type StateType = {
/**初始化 */
initialized: boolean;
/**pcap信息 */
summary: {
filename: string;
file_type: string;
file_length: number;
file_encap_type: string;
packet_count: number;
start_time: number;
stop_time: number;
elapsed_time: number;
};
/**字段 */
columns: string[];
/**过滤条件 */
filter: string;
/**过滤条件错误信息 */
filterError: string | null;
/**当前过滤条件 */
currentFilter: string;
/**当前选中的帧编号 */
selectedFrame: number;
/**当前选中的帧数据 */
selectedPacket: { tree: any[]; data_sources: any[] };
/**pcap包帧数据 */
packetFrameData: Map<string, any> | null;
/**当前选中的帧数据-空占位 */
selectedTreeEntry: typeof NO_SELECTION;
/**选择帧的Dump数据标签 */
selectedDataSourceIndex: number;
/**处理完成状态 */
finishedProcessing: boolean;
/**pcap包帧数匹配帧数 */
totalFrames: number;
/**pcap包帧数据 */
packetFrames: any[];
/**加载帧数 */
nextPageSize: number;
/**加载页数 */
nextPageNum: number;
/**加载下一页 */
nextPageLoad: boolean;
};
export function usePCAP() {
const state = reactive<StateType>({
initialized: false,
summary: {
filename: '',
file_type: 'Wireshark/tcpdump/... - pcap',
file_length: 0,
file_encap_type: 'Ethernet',
packet_count: 0,
start_time: 0,
stop_time: 0,
elapsed_time: 0,
},
columns: [],
filter: '',
filterError: null,
currentFilter: '',
selectedFrame: 1,
/**当前选中的帧数据 */
selectedPacket: { tree: [], data_sources: [] },
packetFrameData: null, // 注意Map 需要额外处理
selectedTreeEntry: NO_SELECTION, // NO_SELECTION 需要定义
/**选择帧的Dump数据标签 */
selectedDataSourceIndex: 0,
/**处理完成状态 */
finishedProcessing: false,
totalFrames: 0,
packetFrames: [],
nextPageNum: 1,
nextPageSize: 40,
nextPageLoad: false,
});
// 清除帧数据和报文信息状态
function handleStateReset() {
// 加载pcap包的数据
state.nextPageNum = 1;
// 选择帧的数据
state.selectedFrame = 0;
state.selectedPacket = { tree: [], data_sources: [] };
state.packetFrameData = null;
state.selectedTreeEntry = NO_SELECTION;
state.selectedDataSourceIndex = 0;
}
/**解析帧数据为简单结构 */
function parseFrameData(id: string, node: Record<string, any>) {
let map = new Map();
if (node.tree && node.tree.length > 0) {
for (let i = 0; i < node.tree.length; i++) {
const subMap = parseFrameData(`${id}-${i}`, node.tree[i]);
subMap.forEach((value, key) => {
map.set(key, value);
});
}
} else if (node.length > 0) {
map.set(id, {
id: id,
idx: node.data_source_idx,
start: node.start,
length: node.length,
});
}
return map;
}
/**帧数据点击选中 */
function handleSelectedTreeEntry(e: any) {
console.log('fnSelectedTreeEntry', e);
state.selectedTreeEntry = e;
}
/**报文数据点击选中 */
function handleSelectedFindSelection(src_idx: number, pos: number) {
console.log('fnSelectedFindSelection', pos);
if (state.packetFrameData == null) return;
// find the smallest one
let current = null;
for (let [k, pp] of state.packetFrameData) {
if (pp.idx !== src_idx) continue;
if (pos >= pp.start && pos <= pp.start + pp.length) {
if (
current != null &&
state.packetFrameData.get(current).length > pp.length
) {
current = k;
} else {
current = k;
}
}
}
if (current != null) {
state.selectedTreeEntry = state.packetFrameData.get(current);
}
}
/**包数据表点击选中 */
function handleSelectedFrame(no: number) {
console.log('fnSelectedFrame', no, state.totalFrames);
state.selectedFrame = no;
wk.send({ type: 'select', number: state.selectedFrame });
}
/**包数据表滚动底部加载 */
function handleScrollBottom() {
const totalFetched = state.packetFrames.length;
console.log('fnScrollBottom', totalFetched);
if (!state.nextPageLoad && totalFetched < state.totalFrames) {
state.nextPageLoad = true;
state.nextPageNum++;
loaldFrames(state.filter, state.nextPageNum);
}
}
/**包数据表过滤 */
function handleFilterFrames() {
console.log('fnFilterFinish', state.filter);
wk.send({ type: 'check-filter', filter: state.filter });
}
/**包数据表加载 */
function loaldFrames(filter: string, page: number = 1) {
if (!(state.initialized && state.finishedProcessing)) return;
const limit = state.nextPageSize;
wk.send({
type: 'frames',
filter: filter,
skip: (page - 1) * limit,
limit: limit,
});
}
/**加载包文件 */
function handleLoadFile(file: File | Blob) {
state.summary = {
filename: '',
file_type: 'Wireshark/tcpdump/... - pcap',
file_length: 0,
file_encap_type: 'Ethernet',
packet_count: 0,
start_time: 0,
stop_time: 0,
elapsed_time: 0,
};
state.finishedProcessing = false;
wk.send({ type: 'process', file: file });
}
/**本地示例文件 */
async function handleLoadExample() {
const name = 'test_ethernet.pcap';
const res = await fetch('/wiregasm/test_ethernet.pcap');
const body = await res.arrayBuffer();
state.summary = {
filename: '',
file_type: 'Wireshark/tcpdump/... - pcap',
file_length: 0,
file_encap_type: 'Ethernet',
packet_count: 0,
start_time: 0,
stop_time: 0,
elapsed_time: 0,
};
state.finishedProcessing = false;
wk.send({ type: 'process-data', name: name, data: body });
}
/**接收数据后回调 */
function wkMessage(res: Record<string, any>) {
switch (res.type) {
case 'status':
console.info(res.status);
break;
case 'error':
console.warn(res.error);
break;
case 'init':
wk.send({ type: 'columns' });
state.initialized = true;
break;
case 'columns':
state.columns = res.data;
break;
case 'frames':
// console.log(res.data);
const { matched, frames } = res.data;
state.totalFrames = matched;
if (state.nextPageNum == 1) {
state.packetFrames = frames;
// 有匹配的选择第一个
if (frames.length > 0) {
state.selectedFrame = frames[0].number;
handleSelectedFrame(state.selectedFrame);
}
} else {
state.packetFrames = state.packetFrames.concat(frames);
state.nextPageLoad = false;
}
break;
case 'selected':
state.selectedPacket = res.data;
state.packetFrameData = parseFrameData('root', res.data);
state.selectedTreeEntry = NO_SELECTION;
state.selectedDataSourceIndex = 0;
break;
case 'processed':
// setStatus(`Error: non-zero return code (${e.data.code})`);
state.finishedProcessing = true;
if (res.data.code === 0) {
state.summary = res.data.summary;
}
// 加载数据
handleStateReset();
loaldFrames(state.filter);
break;
case 'filter':
const filterRes = res.data;
if (filterRes.ok) {
state.currentFilter = state.filter;
state.filterError = null;
// 加载数据
handleStateReset();
loaldFrames(state.filter);
} else {
state.filterError = filterRes.error;
}
break;
default:
console.warn(res);
break;
}
}
onMounted(() => {
// 建立链接
const options: OptionsType = {
url: scriptUrl,
onmessage: wkMessage,
onerror: (ev: any) => {
console.error(ev);
},
};
wk.connect(options);
});
onBeforeUnmount(() => {
wk.close();
});
return {
state,
handleSelectedTreeEntry,
handleSelectedFindSelection,
handleSelectedFrame,
handleScrollBottom,
handleFilterFrames,
handleLoadExample,
handleLoadFile,
};
}
export default usePCAP;

View File

@@ -1,5 +1,4 @@
<script setup lang="ts">
import { reactive, onMounted } from 'vue';
import { message, Upload } from 'ant-design-vue/lib';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { FileType } from 'ant-design-vue/lib/upload/interface';
@@ -7,210 +6,20 @@ import { PageContainer } from 'antdv-pro-layout';
import DissectionTree from './components/DissectionTree.vue';
import DissectionDump from './components/DissectionDump.vue';
import PacketTable from './components/PacketTable.vue';
import { scriptUrl } from '@/assets/js/wiregasm_worker';
import { usePCAP, NO_SELECTION } from './hooks/usePCAP';
import { parseSizeFromFile } from '@/utils/parse-utils';
import { WK, OptionsType } from '@/plugins/wk-worker';
import useI18n from '@/hooks/useI18n';
const { t } = useI18n();
const wk = new WK();
const NO_SELECTION = { id: '', idx: 0, start: 0, length: 0 };
type StateType = {
/**初始化 */
initialized: boolean;
/**pcap信息 */
summary: {
filename: string;
file_type: string;
file_length: number;
file_encap_type: string;
packet_count: number;
start_time: number;
stop_time: number;
elapsed_time: number;
};
/**字段 */
columns: string[];
/**过滤条件 */
filter: string;
/**过滤条件错误信息 */
filterError: string | null;
/**当前过滤条件 */
currentFilter: string;
/**当前选中的帧编号 */
selectedFrame: number;
/**当前选中的帧数据 */
selectedPacket: { tree: any[]; data_sources: any[] };
/**pcap包帧数据 */
packetFrameData: Map<string, any> | null;
/**当前选中的帧数据-空占位 */
selectedTreeEntry: typeof NO_SELECTION;
/**选择帧的Dump数据标签 */
selectedDataSourceIndex: number;
/**处理完成状态 */
finishedProcessing: boolean;
/**pcap包帧数匹配帧数 */
totalFrames: number;
/**pcap包帧数据 */
packetFrames: any[];
/**加载帧数 */
nextPageSize: number;
/**加载页数 */
nextPageNum: number;
/**加载下一页 */
nextPageLoad: boolean;
};
const state = reactive<StateType>({
initialized: false,
summary: {
filename: '',
file_type: 'Wireshark/tcpdump/... - pcap',
file_length: 0,
file_encap_type: 'Ethernet',
packet_count: 0,
start_time: 0,
stop_time: 0,
elapsed_time: 0,
},
columns: [],
filter: '',
filterError: null,
currentFilter: '',
selectedFrame: 1,
/**当前选中的帧数据 */
selectedPacket: { tree: [], data_sources: [] },
packetFrameData: null, // 注意Map 需要额外处理
selectedTreeEntry: NO_SELECTION, // NO_SELECTION 需要定义
/**选择帧的Dump数据标签 */
selectedDataSourceIndex: 0,
/**处理完成状态 */
finishedProcessing: false,
totalFrames: 0,
packetFrames: [],
nextPageNum: 1,
nextPageSize: 40,
nextPageLoad: false,
});
// 清除帧数据和报文信息状态
function fnStateReset() {
// 加载pcap包的数据
state.nextPageNum = 1;
// 选择帧的数据
state.selectedFrame = 0;
state.selectedPacket = { tree: [], data_sources: [] };
state.packetFrameData = null;
state.selectedTreeEntry = NO_SELECTION;
state.selectedDataSourceIndex = 0;
}
/**解析帧数据为简单结构 */
function parseFrameData(id: string, node: Record<string, any>) {
let map = new Map();
if (node.tree && node.tree.length > 0) {
for (let i = 0; i < node.tree.length; i++) {
const subMap = parseFrameData(`${id}-${i}`, node.tree[i]);
subMap.forEach((value, key) => {
map.set(key, value);
});
}
} else if (node.length > 0) {
map.set(id, {
id: id,
idx: node.data_source_idx,
start: node.start,
length: node.length,
});
}
return map;
}
/**帧数据点击选中 */
function fnSelectedTreeEntry(e: any) {
console.log('fnSelectedTreeEntry', e);
state.selectedTreeEntry = e;
}
/**报文数据点击选中 */
function fnSelectedFindSelection(src_idx: number, pos: number) {
console.log('fnSelectedFindSelection', pos);
if (state.packetFrameData == null) return;
// find the smallest one
let current = null;
for (let [k, pp] of state.packetFrameData) {
if (pp.idx !== src_idx) continue;
if (pos >= pp.start && pos <= pp.start + pp.length) {
if (
current != null &&
state.packetFrameData.get(current).length > pp.length
) {
current = k;
} else {
current = k;
}
}
}
if (current != null) {
state.selectedTreeEntry = state.packetFrameData.get(current);
}
}
/**包数据表点击选中 */
function fnSelectedFrame(no: number) {
console.log('fnSelectedFrame', no, state.totalFrames);
state.selectedFrame = no;
wk.send({ type: 'select', number: state.selectedFrame });
}
/**包数据表滚动底部加载 */
function fnScrollBottom() {
const totalFetched = state.packetFrames.length;
console.log('fnScrollBottom', totalFetched);
if (!state.nextPageLoad && totalFetched < state.totalFrames) {
state.nextPageLoad = true;
state.nextPageNum++;
fnLoaldFrames(state.filter, state.nextPageNum);
}
}
/**包数据表过滤 */
function fnFilterFrames() {
console.log('fnFilterFinish', state.filter);
wk.send({ type: 'check-filter', filter: state.filter });
}
/**包数据表记载 */
function fnLoaldFrames(filter: string, page: number = 1) {
if (!(state.initialized && state.finishedProcessing)) return;
const limit = state.nextPageSize;
wk.send({
type: 'frames',
filter: filter,
skip: (page - 1) * limit,
limit: limit,
});
}
/**本地示例文件 */
async function fnLoadExample() {
const name = 'test_ethernet.pcap';
const res = await fetch('/wiregasm/test_ethernet.pcap');
const body = await res.arrayBuffer();
state.summary = {
filename: '',
file_type: 'Wireshark/tcpdump/... - pcap',
file_length: 0,
file_encap_type: 'Ethernet',
packet_count: 0,
start_time: 0,
stop_time: 0,
elapsed_time: 0,
};
state.finishedProcessing = false;
wk.send({ type: 'process-data', name: name, data: body });
}
const {
state,
handleSelectedTreeEntry,
handleSelectedFindSelection,
handleSelectedFrame,
handleScrollBottom,
handleFilterFrames,
handleLoadExample,
handleLoadFile,
} = usePCAP();
/**上传前检查或转换压缩 */
function fnBeforeUpload(file: FileType) {
@@ -229,100 +38,8 @@ function fnBeforeUpload(file: FileType) {
/**表单上传文件 */
function fnUpload(up: UploadRequestOption) {
state.summary = {
filename: '',
file_type: 'Wireshark/tcpdump/... - pcap',
file_length: 0,
file_encap_type: 'Ethernet',
packet_count: 0,
start_time: 0,
stop_time: 0,
elapsed_time: 0,
};
state.finishedProcessing = false;
wk.send({ type: 'process', file: up.file });
handleLoadFile(up.file as File);
}
/**接收数据后回调 */
function wkMessage(res: Record<string, any>) {
switch (res.type) {
case 'status':
console.info(res.status);
break;
case 'error':
console.warn(res.error);
break;
case 'init':
wk.send({ type: 'columns' });
state.initialized = true;
break;
case 'columns':
state.columns = res.data;
break;
case 'frames':
// console.log(res.data);
const { matched, frames } = res.data;
state.totalFrames = matched;
if (state.nextPageNum == 1) {
state.packetFrames = frames;
// 有匹配的选择第一个
if (frames.length > 0) {
state.selectedFrame = frames[0].number;
fnSelectedFrame(state.selectedFrame);
}
} else {
state.packetFrames = state.packetFrames.concat(frames);
state.nextPageLoad = false;
}
break;
case 'selected':
state.selectedPacket = res.data;
state.packetFrameData = parseFrameData('root', res.data);
state.selectedTreeEntry = NO_SELECTION;
state.selectedDataSourceIndex = 0;
break;
case 'processed':
// setStatus(`Error: non-zero return code (${e.data.code})`);
state.finishedProcessing = true;
if (res.data.code === 0) {
state.summary = res.data.summary;
}
// 加载数据
fnStateReset();
fnLoaldFrames(state.filter);
break;
case 'filter':
const filterRes = res.data;
if (filterRes.ok) {
state.currentFilter = state.filter;
state.filterError = null;
// 加载数据
fnStateReset();
fnLoaldFrames(state.filter);
} else {
state.filterError = filterRes.error;
}
break;
default:
console.log(res);
break;
}
}
onMounted(() => {
// 建立链接
const options: OptionsType = {
url: scriptUrl,
onmessage: wkMessage,
onerror: (ev: any) => {
console.error(ev);
},
};
wk.connect(options);
});
</script>
<template>
@@ -345,7 +62,7 @@ onMounted(() => {
>
<a-button type="primary"> Upload </a-button>
</a-upload>
<a-button @click="fnLoadExample">Example</a-button>
<a-button @click="handleLoadExample()">Example</a-button>
</a-space>
<div class="toolbar-info">
@@ -396,7 +113,7 @@ onMounted(() => {
placeholder="display filter, example: tcp"
:allow-clear="true"
style="width: calc(100% - 100px)"
@pressEnter="fnFilterFrames"
@pressEnter="handleFilterFrames"
>
<template #prefix>
<FilterOutlined />
@@ -406,7 +123,7 @@ onMounted(() => {
type="primary"
html-type="submit"
style="width: 100px"
@click="fnFilterFrames"
@click="handleFilterFrames"
>
Filter
</a-button>
@@ -422,8 +139,8 @@ onMounted(() => {
:columns="state.columns"
:data="state.packetFrames"
:selectedFrame="state.selectedFrame"
:onSelectedFrame="fnSelectedFrame"
:onScrollBottom="fnScrollBottom"
:onSelectedFrame="handleSelectedFrame"
:onScrollBottom="handleScrollBottom"
></PacketTable>
<a-row :gutter="20">
@@ -431,7 +148,7 @@ onMounted(() => {
<!-- 帧数据 -->
<DissectionTree
id="root"
:select="fnSelectedTreeEntry"
:select="handleSelectedTreeEntry"
:selected="state.selectedTreeEntry"
:tree="state.selectedPacket.tree"
/>
@@ -451,7 +168,7 @@ onMounted(() => {
>
<DissectionDump
:base64="v.data"
:select="(pos:number)=>fnSelectedFindSelection(idx, pos)"
:select="(pos:number)=>handleSelectedFindSelection(idx, pos)"
:selected="
idx === state.selectedTreeEntry.idx
? state.selectedTreeEntry