feat: PCAP文件解析功能页面优化
This commit is contained in:
@@ -31,11 +31,11 @@ type StateType = {
|
|||||||
/**当前选中的帧编号 */
|
/**当前选中的帧编号 */
|
||||||
selectedFrame: number;
|
selectedFrame: number;
|
||||||
/**当前选中的帧数据 */
|
/**当前选中的帧数据 */
|
||||||
selectedPacket: { tree: any[]; data_sources: any[] };
|
packetFrame: { tree: any[]; data_sources: any[] };
|
||||||
/**pcap包帧数据 */
|
/**pcap包帧数据 */
|
||||||
packetFrameData: Map<string, any> | null;
|
packetFrameTreeMap: Map<string, any> | null;
|
||||||
/**当前选中的帧数据-空占位 */
|
/**当前选中的帧数据 */
|
||||||
selectedTreeEntry: typeof NO_SELECTION;
|
selectedTree: typeof NO_SELECTION;
|
||||||
/**选择帧的Dump数据标签 */
|
/**选择帧的Dump数据标签 */
|
||||||
selectedDataSourceIndex: number;
|
selectedDataSourceIndex: number;
|
||||||
/**处理完成状态 */
|
/**处理完成状态 */
|
||||||
@@ -69,11 +69,11 @@ export function usePCAP() {
|
|||||||
filter: '',
|
filter: '',
|
||||||
filterError: null,
|
filterError: null,
|
||||||
currentFilter: '',
|
currentFilter: '',
|
||||||
selectedFrame: 1,
|
selectedFrame: 0,
|
||||||
/**当前选中的帧数据 */
|
/**当前选中的帧数据 */
|
||||||
selectedPacket: { tree: [], data_sources: [] },
|
packetFrame: { tree: [], data_sources: [] },
|
||||||
packetFrameData: null, // 注意:Map 需要额外处理
|
packetFrameTreeMap: null, // 注意:Map 需要额外处理
|
||||||
selectedTreeEntry: NO_SELECTION, // NO_SELECTION 需要定义
|
selectedTree: NO_SELECTION, // NO_SELECTION 需要定义
|
||||||
/**选择帧的Dump数据标签 */
|
/**选择帧的Dump数据标签 */
|
||||||
selectedDataSourceIndex: 0,
|
selectedDataSourceIndex: 0,
|
||||||
/**处理完成状态 */
|
/**处理完成状态 */
|
||||||
@@ -91,9 +91,9 @@ export function usePCAP() {
|
|||||||
state.nextPageNum = 1;
|
state.nextPageNum = 1;
|
||||||
// 选择帧的数据
|
// 选择帧的数据
|
||||||
state.selectedFrame = 0;
|
state.selectedFrame = 0;
|
||||||
state.selectedPacket = { tree: [], data_sources: [] };
|
state.packetFrame = { tree: [], data_sources: [] };
|
||||||
state.packetFrameData = null;
|
state.packetFrameTreeMap = null;
|
||||||
state.selectedTreeEntry = NO_SELECTION;
|
state.selectedTree = NO_SELECTION;
|
||||||
state.selectedDataSourceIndex = 0;
|
state.selectedDataSourceIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,23 +121,23 @@ export function usePCAP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**帧数据点击选中 */
|
/**帧数据点击选中 */
|
||||||
function handleSelectedTreeEntry(e: any) {
|
function handleSelectedTree(e: any) {
|
||||||
console.log('fnSelectedTreeEntry', e);
|
// console.log('fnSelectedTree', e);
|
||||||
state.selectedTreeEntry = e;
|
state.selectedTree = e;
|
||||||
}
|
}
|
||||||
/**报文数据点击选中 */
|
/**报文数据点击选中 */
|
||||||
function handleSelectedFindSelection(src_idx: number, pos: number) {
|
function handleSelectedFindSelection(src_idx: number, pos: number) {
|
||||||
console.log('fnSelectedFindSelection', pos);
|
// console.log('fnSelectedFindSelection', pos);
|
||||||
if (state.packetFrameData == null) return;
|
if (state.packetFrameTreeMap == null) return;
|
||||||
// find the smallest one
|
// find the smallest one
|
||||||
let current = null;
|
let current = null;
|
||||||
for (let [k, pp] of state.packetFrameData) {
|
for (let [k, pp] of state.packetFrameTreeMap) {
|
||||||
if (pp.idx !== src_idx) continue;
|
if (pp.idx !== src_idx) continue;
|
||||||
|
|
||||||
if (pos >= pp.start && pos <= pp.start + pp.length) {
|
if (pos >= pp.start && pos <= pp.start + pp.length) {
|
||||||
if (
|
if (
|
||||||
current != null &&
|
current != null &&
|
||||||
state.packetFrameData.get(current).length > pp.length
|
state.packetFrameTreeMap.get(current).length > pp.length
|
||||||
) {
|
) {
|
||||||
current = k;
|
current = k;
|
||||||
} else {
|
} else {
|
||||||
@@ -146,19 +146,19 @@ export function usePCAP() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (current != null) {
|
if (current != null) {
|
||||||
state.selectedTreeEntry = state.packetFrameData.get(current);
|
state.selectedTree = state.packetFrameTreeMap.get(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**包数据表点击选中 */
|
/**包数据表点击选中 */
|
||||||
function handleSelectedFrame(no: number) {
|
function handleSelectedFrame(no: number) {
|
||||||
console.log('fnSelectedFrame', no, state.totalFrames);
|
// console.log('fnSelectedFrame', no, state.totalFrames);
|
||||||
state.selectedFrame = no;
|
state.selectedFrame = no;
|
||||||
wk.send({ type: 'select', number: state.selectedFrame });
|
wk.send({ type: 'select', number: state.selectedFrame });
|
||||||
}
|
}
|
||||||
/**包数据表滚动底部加载 */
|
/**包数据表滚动底部加载 */
|
||||||
function handleScrollBottom() {
|
function handleScrollBottom() {
|
||||||
const totalFetched = state.packetFrames.length;
|
const totalFetched = state.packetFrames.length;
|
||||||
console.log('fnScrollBottom', totalFetched);
|
// console.log('fnScrollBottom', totalFetched);
|
||||||
if (!state.nextPageLoad && totalFetched < state.totalFrames) {
|
if (!state.nextPageLoad && totalFetched < state.totalFrames) {
|
||||||
state.nextPageLoad = true;
|
state.nextPageLoad = true;
|
||||||
state.nextPageNum++;
|
state.nextPageNum++;
|
||||||
@@ -167,7 +167,7 @@ export function usePCAP() {
|
|||||||
}
|
}
|
||||||
/**包数据表过滤 */
|
/**包数据表过滤 */
|
||||||
function handleFilterFrames() {
|
function handleFilterFrames() {
|
||||||
console.log('fnFilterFinish', state.filter);
|
// console.log('fnFilterFinish', state.filter);
|
||||||
wk.send({ type: 'check-filter', filter: state.filter });
|
wk.send({ type: 'check-filter', filter: state.filter });
|
||||||
}
|
}
|
||||||
/**包数据表加载 */
|
/**包数据表加载 */
|
||||||
@@ -254,9 +254,9 @@ export function usePCAP() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'selected':
|
case 'selected':
|
||||||
state.selectedPacket = res.data;
|
state.packetFrame = res.data;
|
||||||
state.packetFrameData = parseFrameData('root', res.data);
|
state.packetFrameTreeMap = parseFrameData('root', res.data);
|
||||||
state.selectedTreeEntry = NO_SELECTION;
|
state.selectedTree = NO_SELECTION;
|
||||||
state.selectedDataSourceIndex = 0;
|
state.selectedDataSourceIndex = 0;
|
||||||
break;
|
break;
|
||||||
case 'processed':
|
case 'processed':
|
||||||
@@ -306,7 +306,7 @@ export function usePCAP() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
state,
|
state,
|
||||||
handleSelectedTreeEntry,
|
handleSelectedTree,
|
||||||
handleSelectedFindSelection,
|
handleSelectedFindSelection,
|
||||||
handleSelectedFrame,
|
handleSelectedFrame,
|
||||||
handleScrollBottom,
|
handleScrollBottom,
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ import DissectionDump from './components/DissectionDump.vue';
|
|||||||
import PacketTable from './components/PacketTable.vue';
|
import PacketTable from './components/PacketTable.vue';
|
||||||
import { usePCAP, NO_SELECTION } from './hooks/usePCAP';
|
import { usePCAP, NO_SELECTION } from './hooks/usePCAP';
|
||||||
import { parseSizeFromFile } from '@/utils/parse-utils';
|
import { parseSizeFromFile } from '@/utils/parse-utils';
|
||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const {
|
const {
|
||||||
state,
|
state,
|
||||||
handleSelectedTreeEntry,
|
handleSelectedTree,
|
||||||
handleSelectedFindSelection,
|
handleSelectedFindSelection,
|
||||||
handleSelectedFrame,
|
handleSelectedFrame,
|
||||||
handleScrollBottom,
|
handleScrollBottom,
|
||||||
@@ -49,8 +50,9 @@ function fnUpload(up: UploadRequestOption) {
|
|||||||
:loading="!state.initialized"
|
:loading="!state.initialized"
|
||||||
:body-style="{ padding: '12px' }"
|
:body-style="{ padding: '12px' }"
|
||||||
>
|
>
|
||||||
<div class="toolbar">
|
<!-- 插槽-卡片左侧侧 -->
|
||||||
<a-space :size="8" class="toolbar-oper">
|
<template #title>
|
||||||
|
<a-space :size="8" align="center">
|
||||||
<a-upload
|
<a-upload
|
||||||
name="file"
|
name="file"
|
||||||
list-type="picture"
|
list-type="picture"
|
||||||
@@ -64,14 +66,14 @@ function fnUpload(up: UploadRequestOption) {
|
|||||||
</a-upload>
|
</a-upload>
|
||||||
<a-button @click="handleLoadExample()">Example</a-button>
|
<a-button @click="handleLoadExample()">Example</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
|
</template>
|
||||||
<div class="toolbar-info">
|
<!-- 插槽-卡片右侧 -->
|
||||||
|
<template #extra>
|
||||||
|
<a-space :size="8" align="center">
|
||||||
<a-tag color="green" v-show="!!state.currentFilter">
|
<a-tag color="green" v-show="!!state.currentFilter">
|
||||||
{{ state.currentFilter }}
|
{{ state.currentFilter }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
<span> Matched Frame: {{ state.totalFrames }} </span>
|
<span> Matched Frame: {{ state.totalFrames }} </span>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 包信息 -->
|
<!-- 包信息 -->
|
||||||
<a-popover
|
<a-popover
|
||||||
trigger="click"
|
trigger="click"
|
||||||
@@ -86,7 +88,9 @@ function fnUpload(up: UploadRequestOption) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="summary-item">
|
<div class="summary-item">
|
||||||
<span>Size:</span>
|
<span>Size:</span>
|
||||||
<span>{{ parseSizeFromFile(state.summary.file_length) }}</span>
|
<span>{{
|
||||||
|
parseSizeFromFile(state.summary.file_length)
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-item">
|
<div class="summary-item">
|
||||||
<span>Encapsulation:</span>
|
<span>Encapsulation:</span>
|
||||||
@@ -96,6 +100,28 @@ function fnUpload(up: UploadRequestOption) {
|
|||||||
<span>Packets:</span>
|
<span>Packets:</span>
|
||||||
<span>{{ state.summary.packet_count }}</span>
|
<span>{{ state.summary.packet_count }}</span>
|
||||||
</div>
|
</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">
|
<div class="summary-item">
|
||||||
<span>Duration:</span>
|
<span>Duration:</span>
|
||||||
<span>{{ Math.round(state.summary.elapsed_time) }}s</span>
|
<span>{{ Math.round(state.summary.elapsed_time) }}s</span>
|
||||||
@@ -104,21 +130,30 @@ function fnUpload(up: UploadRequestOption) {
|
|||||||
</template>
|
</template>
|
||||||
<InfoCircleOutlined />
|
<InfoCircleOutlined />
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</div>
|
</a-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- 包数据表过滤 -->
|
<!-- 包数据表过滤 -->
|
||||||
<a-input-group compact>
|
<a-input-group compact>
|
||||||
<a-input
|
<a-auto-complete
|
||||||
v-model:value="state.filter"
|
v-model:value="state.filter"
|
||||||
placeholder="display filter, example: tcp"
|
:options="[
|
||||||
:allow-clear="true"
|
{ 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)"
|
style="width: calc(100% - 100px)"
|
||||||
|
:allow-clear="true"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
placeholder="display filter, example: tcp"
|
||||||
@pressEnter="handleFilterFrames"
|
@pressEnter="handleFilterFrames"
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<FilterOutlined />
|
<FilterOutlined />
|
||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
|
</a-auto-complete>
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
html-type="submit"
|
html-type="submit"
|
||||||
@@ -143,14 +178,18 @@ function fnUpload(up: UploadRequestOption) {
|
|||||||
:onScrollBottom="handleScrollBottom"
|
:onScrollBottom="handleScrollBottom"
|
||||||
></PacketTable>
|
></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">
|
<a-col :lg="12" :md="12" :xs="24" class="tree">
|
||||||
<!-- 帧数据 -->
|
<!-- 帧数据 -->
|
||||||
<DissectionTree
|
<DissectionTree
|
||||||
id="root"
|
id="root"
|
||||||
:select="handleSelectedTreeEntry"
|
:select="handleSelectedTree"
|
||||||
:selected="state.selectedTreeEntry"
|
:selected="state.selectedTree"
|
||||||
:tree="state.selectedPacket.tree"
|
:tree="state.packetFrame.tree"
|
||||||
/>
|
/>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="12" :md="12" :xs="24" class="dump">
|
<a-col :lg="12" :md="12" :xs="24" class="dump">
|
||||||
@@ -163,15 +202,15 @@ function fnUpload(up: UploadRequestOption) {
|
|||||||
<a-tab-pane
|
<a-tab-pane
|
||||||
:key="idx"
|
:key="idx"
|
||||||
:tab="v.name"
|
:tab="v.name"
|
||||||
v-for="(v, idx) in state.selectedPacket.data_sources"
|
v-for="(v, idx) in state.packetFrame.data_sources"
|
||||||
style="overflow: auto"
|
style="overflow: auto"
|
||||||
>
|
>
|
||||||
<DissectionDump
|
<DissectionDump
|
||||||
:base64="v.data"
|
:base64="v.data"
|
||||||
:select="(pos:number)=>handleSelectedFindSelection(idx, pos)"
|
:select="(pos:number)=>handleSelectedFindSelection(idx, pos)"
|
||||||
:selected="
|
:selected="
|
||||||
idx === state.selectedTreeEntry.idx
|
idx === state.selectedTree.idx
|
||||||
? state.selectedTreeEntry
|
? state.selectedTree
|
||||||
: NO_SELECTION
|
: NO_SELECTION
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
@@ -184,17 +223,6 @@ function fnUpload(up: UploadRequestOption) {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.toolbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
.toolbar-info {
|
|
||||||
flex: 1;
|
|
||||||
text-align: right;
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary {
|
.summary {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Reference in New Issue
Block a user