refactor(frontend): 重构数据解析逻辑
- 新增 StopAndParseCapture 函数,整合停止抓包和解析数据流程 -重构 ReadRawJsonFile 函数,返回解析后的 ParsedResult 对象 - 优化数据解析流程,提高代码可读性和性能 - 调整前端 CapturePage组件,使用新的解析接口
This commit is contained in:
@@ -4,12 +4,10 @@ import {DownloadOutlined, PlayCircleOutlined, SettingOutlined, StopOutlined} fro
|
||||
import '../App.css';
|
||||
import {
|
||||
ExportData,
|
||||
GetCapturedData,
|
||||
GetNetworkInterfaces,
|
||||
ParseData,
|
||||
ReadRawJsonFile,
|
||||
StartCapture,
|
||||
StopCapture
|
||||
StopAndParseCapture
|
||||
} from '../../wailsjs/go/service/App';
|
||||
import {useCaptureStore} from '../store/useCaptureStore';
|
||||
|
||||
@@ -146,68 +144,24 @@ function CapturePage() {
|
||||
setCapturedData([]);
|
||||
try {
|
||||
setLoading(true);
|
||||
const stopResult = await safeApiCall(
|
||||
() => StopCapture(),
|
||||
'停止抓包失败'
|
||||
// 新接口:直接停止抓包并解析
|
||||
const parsedData = await safeApiCall(
|
||||
() => StopAndParseCapture(),
|
||||
'停止抓包并解析数据失败'
|
||||
);
|
||||
if (stopResult === undefined) {
|
||||
setIsCapturing(false);
|
||||
return;
|
||||
}
|
||||
setIsCapturing(false);
|
||||
const data = await safeApiCall(
|
||||
() => GetCapturedData(),
|
||||
'获取抓包数据失败'
|
||||
);
|
||||
if (!data || data.length === 0) {
|
||||
setCapturedData([]);
|
||||
showMessage('warning', '未捕获到数据');
|
||||
return;
|
||||
}
|
||||
setCapturedData(data);
|
||||
if (data && data.length > 0) {
|
||||
data.forEach((item, idx) => {
|
||||
let hexStr = '';
|
||||
if (/^[0-9a-fA-F\s]+$/.test(item)) {
|
||||
hexStr = item;
|
||||
} else {
|
||||
hexStr = Array.from(item).map(c => c.charCodeAt(0).toString(16).padStart(2, '0')).join(' ');
|
||||
}
|
||||
console.log(`抓包数据[${idx}]:`, hexStr);
|
||||
});
|
||||
}
|
||||
if (data.length > 0) {
|
||||
const parsed = await safeApiCall(
|
||||
() => ParseData(data),
|
||||
'解析数据失败'
|
||||
);
|
||||
if (!parsed) {
|
||||
setParsedData({ items: [], heroes: [] });
|
||||
console.log("解析数据:"+JSON.stringify(parsedData))
|
||||
if (!parsedData || !Array.isArray((parsedData as CaptureResult).items)) {
|
||||
setParsedData({ items: [], heroes: [] } as CaptureResult);
|
||||
showMessage('error', '解析数据失败');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const parsedData = JSON.parse(parsed);
|
||||
if (!parsedData || !Array.isArray(parsedData.items)) {
|
||||
setParsedData({ items: [], heroes: [] });
|
||||
showMessage('error', '解析数据失败');
|
||||
return;
|
||||
}
|
||||
setParsedData(parsedData);
|
||||
setParsedData(parsedData as CaptureResult);
|
||||
showMessage('success', '数据处理完成');
|
||||
} catch (parseError) {
|
||||
console.error('解析JSON失败:', parseError);
|
||||
setParsedData({ items: [], heroes: [] });
|
||||
showMessage('error', '解析数据失败');
|
||||
}
|
||||
} else {
|
||||
showMessage('warning', '未捕获到数据');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('停止抓包时发生未知错误:', error);
|
||||
setIsCapturing(false);
|
||||
setCapturedData([]);
|
||||
setParsedData({ items: [], heroes: [] });
|
||||
setParsedData({ items: [], heroes: [] } as CaptureResult);
|
||||
setLoading(false);
|
||||
showMessage('error', '抓包失败,已重置状态');
|
||||
return;
|
||||
@@ -269,8 +223,7 @@ function CapturePage() {
|
||||
const fetchParsedDataFromBackend = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const raw = await ReadRawJsonFile();
|
||||
const json = JSON.parse(raw);
|
||||
const json = await ReadRawJsonFile();
|
||||
console.log('已加载本地解析数据:', json);
|
||||
const safeData = {
|
||||
items: Array.isArray(json.items) ? json.items : [],
|
||||
|
||||
@@ -34,6 +34,20 @@ export namespace model {
|
||||
this.is_loopback = source["is_loopback"];
|
||||
}
|
||||
}
|
||||
export class ParsedResult {
|
||||
items: any[];
|
||||
heroes: any[];
|
||||
|
||||
static createFrom(source: any = {}) {
|
||||
return new ParsedResult(source);
|
||||
}
|
||||
|
||||
constructor(source: any = {}) {
|
||||
if ('string' === typeof source) source = JSON.parse(source);
|
||||
this.items = source["items"];
|
||||
this.heroes = source["heroes"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
4
frontend/wailsjs/go/service/App.d.ts
vendored
4
frontend/wailsjs/go/service/App.d.ts
vendored
@@ -12,8 +12,10 @@ export function GetNetworkInterfaces():Promise<Array<model.NetworkInterface>>;
|
||||
|
||||
export function ParseData(arg1:Array<string>):Promise<string>;
|
||||
|
||||
export function ReadRawJsonFile():Promise<string>;
|
||||
export function ReadRawJsonFile():Promise<model.ParsedResult>;
|
||||
|
||||
export function StartCapture(arg1:string):Promise<void>;
|
||||
|
||||
export function StopAndParseCapture():Promise<model.ParsedResult>;
|
||||
|
||||
export function StopCapture():Promise<void>;
|
||||
|
||||
@@ -30,6 +30,10 @@ export function StartCapture(arg1) {
|
||||
return window['go']['service']['App']['StartCapture'](arg1);
|
||||
}
|
||||
|
||||
export function StopAndParseCapture() {
|
||||
return window['go']['service']['App']['StopAndParseCapture']();
|
||||
}
|
||||
|
||||
export function StopCapture() {
|
||||
return window['go']['service']['App']['StopCapture']();
|
||||
}
|
||||
|
||||
@@ -29,3 +29,9 @@ type CaptureStatus struct {
|
||||
Status string `json:"status"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ParsedResult 解析结果
|
||||
type ParsedResult struct {
|
||||
Items []interface{} `json:"items"`
|
||||
Heroes []interface{} `json:"heroes"`
|
||||
}
|
||||
|
||||
@@ -101,3 +101,33 @@ func (cs *CaptureService) processData(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StopAndParseCapture 停止抓包并解析数据
|
||||
func (cs *CaptureService) StopAndParseCapture(parser *ParserService) (*model.ParsedResult, error) {
|
||||
cs.mutex.Lock()
|
||||
defer cs.mutex.Unlock()
|
||||
|
||||
if !cs.isCapturing {
|
||||
return nil, fmt.Errorf("capture not running")
|
||||
}
|
||||
|
||||
cs.packetCapture.Stop()
|
||||
cs.isCapturing = false
|
||||
cs.logger.Info("Packet capture stopped (StopAndParseCapture)")
|
||||
|
||||
// 处理所有收集的数据
|
||||
cs.packetCapture.ProcessAllData()
|
||||
|
||||
// 获取抓包数据
|
||||
rawData := cs.packetCapture.GetCapturedData()
|
||||
if len(rawData) == 0 {
|
||||
return nil, fmt.Errorf("no captured data")
|
||||
}
|
||||
|
||||
// 解析数据
|
||||
result, _, err := parser.ParseHexData(rawData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析数据失败: %v", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"equipment-analyzer/internal/capture"
|
||||
@@ -104,46 +104,29 @@ func (a *App) GetCapturedData() ([]string, error) {
|
||||
|
||||
// ParseData 解析数据为JSON
|
||||
func (a *App) ParseData(hexDataList []string) (string, error) {
|
||||
result, err := a.parserService.ParseHexData(hexDataList)
|
||||
_, rawJson, err := a.parserService.ParseHexData(hexDataList)
|
||||
if err != nil {
|
||||
a.logger.Error("解析数据失败", "error", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
jsonData, err := json.MarshalIndent(result, "", " ")
|
||||
if err != nil {
|
||||
a.logger.Error("JSON序列化失败", "error", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
a.logger.Info("数据解析完成", "count", len(result.Data))
|
||||
return string(jsonData), nil
|
||||
return rawJson, nil
|
||||
}
|
||||
|
||||
// ExportData 导出数据到文件
|
||||
func (a *App) ExportData(hexDataList []string, filename string) error {
|
||||
result, err := a.parserService.ParseHexData(hexDataList)
|
||||
result, rawJson, err := a.parserService.ParseHexData(hexDataList)
|
||||
if err != nil {
|
||||
a.logger.Error("解析数据失败", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
jsonData, err := json.MarshalIndent(result, "", " ")
|
||||
if err != nil {
|
||||
a.logger.Error("JSON序列化失败", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 这里可以添加文件写入逻辑
|
||||
a.logger.Info("导出数据", "filename", filename, "count", len(result.Data))
|
||||
|
||||
a.logger.Info("导出数据", "filename", filename, "count", len(result.Items))
|
||||
// 简单示例:写入到当前目录
|
||||
err = utils.WriteFile(filename, jsonData)
|
||||
err = utils.WriteFile(filename, []byte(rawJson))
|
||||
if err != nil {
|
||||
a.logger.Error("写入文件失败", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -163,6 +146,20 @@ func (a *App) getStatusMessage() string {
|
||||
}
|
||||
|
||||
// ReadRawJsonFile 供前端调用,读取output_raw.json内容
|
||||
func (a *App) ReadRawJsonFile() (string, error) {
|
||||
return a.parserService.ReadRawJsonFile()
|
||||
func (a *App) ReadRawJsonFile() (*model.ParsedResult, error) {
|
||||
data, err := ioutil.ReadFile("output_raw.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return a.parserService.ReadRawJsonFile(string(data))
|
||||
}
|
||||
|
||||
// StopAndParseCapture 停止抓包并解析数据,供前端调用
|
||||
func (a *App) StopAndParseCapture() (*model.ParsedResult, error) {
|
||||
result, err := a.captureService.StopAndParseCapture(a.parserService)
|
||||
if err != nil {
|
||||
a.logger.Error("停止抓包并解析数据失败", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -28,19 +28,17 @@ func NewParserService(cfg *config.Config, logger *utils.Logger) *ParserService {
|
||||
}
|
||||
|
||||
// ParseHexData 解析十六进制数据
|
||||
func (ps *ParserService) ParseHexData(hexDataList []string) (*model.CaptureResult, error) {
|
||||
func (ps *ParserService) ParseHexData(hexDataList []string) (*model.ParsedResult, string, error) {
|
||||
if len(hexDataList) == 0 {
|
||||
ps.logger.Warn("没有数据需要解析")
|
||||
return &model.CaptureResult{
|
||||
Data: make([]model.Equipment, 0),
|
||||
Units: make([]interface{}, 0),
|
||||
}, nil
|
||||
return &model.ParsedResult{
|
||||
Items: make([]interface{}, 0),
|
||||
Heroes: make([]interface{}, 0),
|
||||
}, "", nil
|
||||
}
|
||||
|
||||
ps.logger.Info("开始远程解析数据", "count", len(hexDataList))
|
||||
|
||||
// 远程接口解析
|
||||
//fmt.Println("开始远程解析数据", len(hexDataList))
|
||||
url := "https://krivpfvxi0.execute-api.us-west-2.amazonaws.com/dev/getItems"
|
||||
reqBody := map[string]interface{}{
|
||||
"data": hexDataList,
|
||||
@@ -55,45 +53,51 @@ func (ps *ParserService) ParseHexData(hexDataList []string) (*model.CaptureResul
|
||||
defer resp.Body.Close()
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
// 直接写入本地文件
|
||||
// 新校验逻辑:校验data和units字段
|
||||
var raw map[string]interface{}
|
||||
if err := json.Unmarshal(body, &raw); err != nil {
|
||||
ps.logger.Error("远程json解析失败", "error", err)
|
||||
return nil, "", fmt.Errorf("远程json解析失败: %v", err)
|
||||
}
|
||||
|
||||
// 校验data字段
|
||||
dataArr, dataOk := raw["data"].([]interface{})
|
||||
if !dataOk || len(dataArr) == 0 {
|
||||
ps.logger.Error("远程json校验失败,data字段缺失或为空")
|
||||
return nil, "", fmt.Errorf("远程json校验失败,data字段缺失或为空")
|
||||
}
|
||||
|
||||
// 校验通过再写入本地文件
|
||||
fileErr := ioutil.WriteFile("output_raw.json", body, 0644)
|
||||
if fileErr != nil {
|
||||
ps.logger.Error("写入原始json文件失败", "error", fileErr)
|
||||
}
|
||||
|
||||
ps.logger.Info("远程原始数据已写入output_raw.json")
|
||||
parsedResult, err := ps.ReadRawJsonFile(string(body))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// 返回空集合,保证前端不报错
|
||||
return &model.CaptureResult{
|
||||
Data: make([]model.Equipment, 0),
|
||||
Units: make([]interface{}, 0),
|
||||
}, nil
|
||||
return parsedResult, "", nil
|
||||
} else if err != nil {
|
||||
ps.logger.Error("远程解析请求失败", "error", err)
|
||||
return nil, fmt.Errorf("远程解析请求失败: %v", err)
|
||||
return nil, "", fmt.Errorf("远程解析请求失败: %v", err)
|
||||
} else {
|
||||
ps.logger.Error("远程解析响应码异常", "status", resp.StatusCode)
|
||||
return nil, fmt.Errorf("远程解析响应码异常: %d", resp.StatusCode)
|
||||
return nil, "", fmt.Errorf("远程解析响应码异常: %d", resp.StatusCode)
|
||||
}
|
||||
} else {
|
||||
ps.logger.Error("远程解析请求构建失败", "error", err)
|
||||
return nil, fmt.Errorf("远程解析请求构建失败: %v", err)
|
||||
return nil, "", fmt.Errorf("远程解析请求构建失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadRawJsonFile 读取output_raw.json文件内容并进行数据转换
|
||||
func (ps *ParserService) ReadRawJsonFile() (string, error) {
|
||||
data, err := ioutil.ReadFile("output_raw.json")
|
||||
if err != nil {
|
||||
ps.logger.Error("读取output_raw.json失败", "error", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 解析原始JSON数据
|
||||
// ReadRawJsonFile 读取rawJson内容并进行数据转换,返回ParsedResult对象
|
||||
func (ps *ParserService) ReadRawJsonFile(rawJson string) (*model.ParsedResult, error) {
|
||||
var rawData map[string]interface{}
|
||||
if err := json.Unmarshal(data, &rawData); err != nil {
|
||||
if err := json.Unmarshal([]byte(rawJson), &rawData); err != nil {
|
||||
ps.logger.Error("解析JSON失败", "error", err)
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 提取装备和英雄数据
|
||||
@@ -110,9 +114,6 @@ func (ps *ParserService) ReadRawJsonFile() (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 原始装备总数
|
||||
//fmt.Println("原始装备总数:", len(equips))
|
||||
|
||||
// 过滤有效装备 (x => !!x.f)
|
||||
var validEquips []interface{}
|
||||
for _, equip := range equips {
|
||||
@@ -122,29 +123,24 @@ func (ps *ParserService) ReadRawJsonFile() (string, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
//fmt.Println("过滤f字段后装备数:", len(validEquips))
|
||||
|
||||
// 转换装备数据
|
||||
convertedItems := ps.convertItemsAllWithLog(validEquips)
|
||||
//fmt.Println("转换后装备数:", len(convertedItems))
|
||||
|
||||
// 转换英雄数据(只对最大组)
|
||||
convertedHeroes := ps.convertUnits(rawUnits)
|
||||
|
||||
// 构建最终结果
|
||||
result := map[string]interface{}{
|
||||
"items": convertedItems,
|
||||
"heroes": convertedHeroes,
|
||||
result := &model.ParsedResult{
|
||||
Items: make([]interface{}, len(convertedItems)),
|
||||
Heroes: make([]interface{}, len(convertedHeroes)),
|
||||
}
|
||||
for i, v := range convertedItems {
|
||||
result.Items[i] = v
|
||||
}
|
||||
for i, v := range convertedHeroes {
|
||||
result.Heroes[i] = v
|
||||
}
|
||||
|
||||
// 序列化为JSON字符串
|
||||
resultJSON, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
ps.logger.Error("序列化结果失败", "error", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(resultJSON), nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// convertItems 转换装备数据
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user