feat: PCAP文件解析功能页面优化

This commit is contained in:
TsMask
2025-04-18 15:51:24 +08:00
parent 48f8f13bf3
commit 294212620e
2 changed files with 119 additions and 91 deletions

View File

@@ -31,11 +31,11 @@ type StateType = {
/**当前选中的帧编号 */
selectedFrame: number;
/**当前选中的帧数据 */
selectedPacket: { tree: any[]; data_sources: any[] };
packetFrame: { tree: any[]; data_sources: any[] };
/**pcap包帧数据 */
packetFrameData: Map<string, any> | null;
/**当前选中的帧数据-空占位 */
selectedTreeEntry: typeof NO_SELECTION;
packetFrameTreeMap: Map<string, any> | null;
/**当前选中的帧数据 */
selectedTree: typeof NO_SELECTION;
/**选择帧的Dump数据标签 */
selectedDataSourceIndex: number;
/**处理完成状态 */
@@ -69,11 +69,11 @@ export function usePCAP() {
filter: '',
filterError: null,
currentFilter: '',
selectedFrame: 1,
selectedFrame: 0,
/**当前选中的帧数据 */
selectedPacket: { tree: [], data_sources: [] },
packetFrameData: null, // 注意Map 需要额外处理
selectedTreeEntry: NO_SELECTION, // NO_SELECTION 需要定义
packetFrame: { tree: [], data_sources: [] },
packetFrameTreeMap: null, // 注意Map 需要额外处理
selectedTree: NO_SELECTION, // NO_SELECTION 需要定义
/**选择帧的Dump数据标签 */
selectedDataSourceIndex: 0,
/**处理完成状态 */
@@ -91,9 +91,9 @@ export function usePCAP() {
state.nextPageNum = 1;
// 选择帧的数据
state.selectedFrame = 0;
state.selectedPacket = { tree: [], data_sources: [] };
state.packetFrameData = null;
state.selectedTreeEntry = NO_SELECTION;
state.packetFrame = { tree: [], data_sources: [] };
state.packetFrameTreeMap = null;
state.selectedTree = NO_SELECTION;
state.selectedDataSourceIndex = 0;
}
@@ -121,23 +121,23 @@ export function usePCAP() {
}
/**帧数据点击选中 */
function handleSelectedTreeEntry(e: any) {
console.log('fnSelectedTreeEntry', e);
state.selectedTreeEntry = e;
function handleSelectedTree(e: any) {
// console.log('fnSelectedTree', e);
state.selectedTree = e;
}
/**报文数据点击选中 */
function handleSelectedFindSelection(src_idx: number, pos: number) {
console.log('fnSelectedFindSelection', pos);
if (state.packetFrameData == null) return;
// console.log('fnSelectedFindSelection', pos);
if (state.packetFrameTreeMap == null) return;
// find the smallest one
let current = null;
for (let [k, pp] of state.packetFrameData) {
for (let [k, pp] of state.packetFrameTreeMap) {
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
state.packetFrameTreeMap.get(current).length > pp.length
) {
current = k;
} else {
@@ -146,19 +146,19 @@ export function usePCAP() {
}
}
if (current != null) {
state.selectedTreeEntry = state.packetFrameData.get(current);
state.selectedTree = state.packetFrameTreeMap.get(current);
}
}
/**包数据表点击选中 */
function handleSelectedFrame(no: number) {
console.log('fnSelectedFrame', no, state.totalFrames);
// 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);
// console.log('fnScrollBottom', totalFetched);
if (!state.nextPageLoad && totalFetched < state.totalFrames) {
state.nextPageLoad = true;
state.nextPageNum++;
@@ -167,7 +167,7 @@ export function usePCAP() {
}
/**包数据表过滤 */
function handleFilterFrames() {
console.log('fnFilterFinish', state.filter);
// console.log('fnFilterFinish', state.filter);
wk.send({ type: 'check-filter', filter: state.filter });
}
/**包数据表加载 */
@@ -254,9 +254,9 @@ export function usePCAP() {
}
break;
case 'selected':
state.selectedPacket = res.data;
state.packetFrameData = parseFrameData('root', res.data);
state.selectedTreeEntry = NO_SELECTION;
state.packetFrame = res.data;
state.packetFrameTreeMap = parseFrameData('root', res.data);
state.selectedTree = NO_SELECTION;
state.selectedDataSourceIndex = 0;
break;
case 'processed':
@@ -306,7 +306,7 @@ export function usePCAP() {
return {
state,
handleSelectedTreeEntry,
handleSelectedTree,
handleSelectedFindSelection,
handleSelectedFrame,
handleScrollBottom,

View File

@@ -8,11 +8,12 @@ import DissectionDump from './components/DissectionDump.vue';
import PacketTable from './components/PacketTable.vue';
import { usePCAP, NO_SELECTION } from './hooks/usePCAP';
import { parseSizeFromFile } from '@/utils/parse-utils';
import { parseDateToStr } from '@/utils/date-utils';
import useI18n from '@/hooks/useI18n';
const { t } = useI18n();
const {
state,
handleSelectedTreeEntry,
handleSelectedTree,
handleSelectedFindSelection,
handleSelectedFrame,
handleScrollBottom,
@@ -49,8 +50,9 @@ function fnUpload(up: UploadRequestOption) {
:loading="!state.initialized"
:body-style="{ padding: '12px' }"
>
<div class="toolbar">
<a-space :size="8" class="toolbar-oper">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<a-upload
name="file"
list-type="picture"
@@ -64,14 +66,14 @@ function fnUpload(up: UploadRequestOption) {
</a-upload>
<a-button @click="handleLoadExample()">Example</a-button>
</a-space>
<div class="toolbar-info">
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<a-tag color="green" v-show="!!state.currentFilter">
{{ state.currentFilter }}
</a-tag>
<span> Matched Frame: {{ state.totalFrames }} </span>
</div>
<!-- 包信息 -->
<a-popover
trigger="click"
@@ -86,7 +88,9 @@ function fnUpload(up: UploadRequestOption) {
</div>
<div class="summary-item">
<span>Size:</span>
<span>{{ parseSizeFromFile(state.summary.file_length) }}</span>
<span>{{
parseSizeFromFile(state.summary.file_length)
}}</span>
</div>
<div class="summary-item">
<span>Encapsulation:</span>
@@ -96,6 +100,28 @@ function fnUpload(up: UploadRequestOption) {
<span>Packets:</span>
<span>{{ state.summary.packet_count }}</span>
</div>
<div class="summary-item">
<span>Start Time:</span>
<span>
{{
parseDateToStr(
state.summary.start_time * 1000,
'YYYY-MM-DD HH:mm:ss.SSS'
)
}}
</span>
</div>
<div class="summary-item">
<span>Stop Time:</span>
<span>
{{
parseDateToStr(
state.summary.stop_time * 1000,
'YYYY-MM-DD HH:mm:ss.SSS'
)
}}
</span>
</div>
<div class="summary-item">
<span>Duration:</span>
<span>{{ Math.round(state.summary.elapsed_time) }}s</span>
@@ -104,21 +130,30 @@ function fnUpload(up: UploadRequestOption) {
</template>
<InfoCircleOutlined />
</a-popover>
</div>
</a-space>
</template>
<!-- 包数据表过滤 -->
<a-input-group compact>
<a-input
<a-auto-complete
v-model:value="state.filter"
placeholder="display filter, example: tcp"
:allow-clear="true"
:options="[
{ value: 'http || tcp.port == 33030 || http2' },
{ value: 'ip.src== 172.17.0.19 && ip.dst == 172.17.0.77' },
{ value: 'sip || ngap' },
]"
style="width: calc(100% - 100px)"
:allow-clear="true"
>
<a-input
placeholder="display filter, example: tcp"
@pressEnter="handleFilterFrames"
>
<template #prefix>
<FilterOutlined />
</template>
</a-input>
</a-auto-complete>
<a-button
type="primary"
html-type="submit"
@@ -143,14 +178,18 @@ function fnUpload(up: UploadRequestOption) {
:onScrollBottom="handleScrollBottom"
></PacketTable>
<a-row>
<a-row
:gutter="16"
style="border: 2px rgb(217 217 217) solid; border-radius: 6px"
v-show="state.selectedFrame > 0"
>
<a-col :lg="12" :md="12" :xs="24" class="tree">
<!-- 帧数据 -->
<DissectionTree
id="root"
:select="handleSelectedTreeEntry"
:selected="state.selectedTreeEntry"
:tree="state.selectedPacket.tree"
:select="handleSelectedTree"
:selected="state.selectedTree"
:tree="state.packetFrame.tree"
/>
</a-col>
<a-col :lg="12" :md="12" :xs="24" class="dump">
@@ -163,15 +202,15 @@ function fnUpload(up: UploadRequestOption) {
<a-tab-pane
:key="idx"
:tab="v.name"
v-for="(v, idx) in state.selectedPacket.data_sources"
v-for="(v, idx) in state.packetFrame.data_sources"
style="overflow: auto"
>
<DissectionDump
:base64="v.data"
:select="(pos:number)=>handleSelectedFindSelection(idx, pos)"
:selected="
idx === state.selectedTreeEntry.idx
? state.selectedTreeEntry
idx === state.selectedTree.idx
? state.selectedTree
: NO_SELECTION
"
/>
@@ -184,17 +223,6 @@ function fnUpload(up: UploadRequestOption) {
</template>
<style scoped>
.toolbar {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.toolbar-info {
flex: 1;
text-align: right;
padding-right: 8px;
}
.summary {
display: flex;
flex-direction: column;