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 '../App.css';
|
||||||
import {
|
import {
|
||||||
ExportData,
|
ExportData,
|
||||||
GetCapturedData,
|
|
||||||
GetNetworkInterfaces,
|
GetNetworkInterfaces,
|
||||||
ParseData,
|
|
||||||
ReadRawJsonFile,
|
ReadRawJsonFile,
|
||||||
StartCapture,
|
StartCapture,
|
||||||
StopCapture
|
StopAndParseCapture
|
||||||
} from '../../wailsjs/go/service/App';
|
} from '../../wailsjs/go/service/App';
|
||||||
import {useCaptureStore} from '../store/useCaptureStore';
|
import {useCaptureStore} from '../store/useCaptureStore';
|
||||||
|
|
||||||
@@ -146,68 +144,24 @@ function CapturePage() {
|
|||||||
setCapturedData([]);
|
setCapturedData([]);
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const stopResult = await safeApiCall(
|
// 新接口:直接停止抓包并解析
|
||||||
() => StopCapture(),
|
const parsedData = await safeApiCall(
|
||||||
'停止抓包失败'
|
() => StopAndParseCapture(),
|
||||||
|
'停止抓包并解析数据失败'
|
||||||
);
|
);
|
||||||
if (stopResult === undefined) {
|
console.log("解析数据:"+JSON.stringify(parsedData))
|
||||||
setIsCapturing(false);
|
if (!parsedData || !Array.isArray((parsedData as CaptureResult).items)) {
|
||||||
|
setParsedData({ items: [], heroes: [] } as CaptureResult);
|
||||||
|
showMessage('error', '解析数据失败');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setIsCapturing(false);
|
setParsedData(parsedData as CaptureResult);
|
||||||
const data = await safeApiCall(
|
showMessage('success', '数据处理完成');
|
||||||
() => 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: [] });
|
|
||||||
showMessage('error', '解析数据失败');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const parsedData = JSON.parse(parsed);
|
|
||||||
if (!parsedData || !Array.isArray(parsedData.items)) {
|
|
||||||
setParsedData({ items: [], heroes: [] });
|
|
||||||
showMessage('error', '解析数据失败');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setParsedData(parsedData);
|
|
||||||
showMessage('success', '数据处理完成');
|
|
||||||
} catch (parseError) {
|
|
||||||
console.error('解析JSON失败:', parseError);
|
|
||||||
setParsedData({ items: [], heroes: [] });
|
|
||||||
showMessage('error', '解析数据失败');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showMessage('warning', '未捕获到数据');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('停止抓包时发生未知错误:', error);
|
console.error('停止抓包时发生未知错误:', error);
|
||||||
setIsCapturing(false);
|
setIsCapturing(false);
|
||||||
setCapturedData([]);
|
setCapturedData([]);
|
||||||
setParsedData({ items: [], heroes: [] });
|
setParsedData({ items: [], heroes: [] } as CaptureResult);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
showMessage('error', '抓包失败,已重置状态');
|
showMessage('error', '抓包失败,已重置状态');
|
||||||
return;
|
return;
|
||||||
@@ -269,8 +223,7 @@ function CapturePage() {
|
|||||||
const fetchParsedDataFromBackend = async () => {
|
const fetchParsedDataFromBackend = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const raw = await ReadRawJsonFile();
|
const json = await ReadRawJsonFile();
|
||||||
const json = JSON.parse(raw);
|
|
||||||
console.log('已加载本地解析数据:', json);
|
console.log('已加载本地解析数据:', json);
|
||||||
const safeData = {
|
const safeData = {
|
||||||
items: Array.isArray(json.items) ? json.items : [],
|
items: Array.isArray(json.items) ? json.items : [],
|
||||||
|
|||||||
@@ -34,6 +34,20 @@ export namespace model {
|
|||||||
this.is_loopback = source["is_loopback"];
|
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 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 StartCapture(arg1:string):Promise<void>;
|
||||||
|
|
||||||
|
export function StopAndParseCapture():Promise<model.ParsedResult>;
|
||||||
|
|
||||||
export function StopCapture():Promise<void>;
|
export function StopCapture():Promise<void>;
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ export function StartCapture(arg1) {
|
|||||||
return window['go']['service']['App']['StartCapture'](arg1);
|
return window['go']['service']['App']['StartCapture'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function StopAndParseCapture() {
|
||||||
|
return window['go']['service']['App']['StopAndParseCapture']();
|
||||||
|
}
|
||||||
|
|
||||||
export function StopCapture() {
|
export function StopCapture() {
|
||||||
return window['go']['service']['App']['StopCapture']();
|
return window['go']['service']['App']['StopCapture']();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,3 +29,9 @@ type CaptureStatus struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Error string `json:"error,omitempty"`
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"equipment-analyzer/internal/capture"
|
"equipment-analyzer/internal/capture"
|
||||||
@@ -104,46 +104,29 @@ func (a *App) GetCapturedData() ([]string, error) {
|
|||||||
|
|
||||||
// ParseData 解析数据为JSON
|
// ParseData 解析数据为JSON
|
||||||
func (a *App) ParseData(hexDataList []string) (string, error) {
|
func (a *App) ParseData(hexDataList []string) (string, error) {
|
||||||
result, err := a.parserService.ParseHexData(hexDataList)
|
_, rawJson, err := a.parserService.ParseHexData(hexDataList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.logger.Error("解析数据失败", "error", err)
|
a.logger.Error("解析数据失败", "error", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
return rawJson, nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportData 导出数据到文件
|
// ExportData 导出数据到文件
|
||||||
func (a *App) ExportData(hexDataList []string, filename string) error {
|
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 {
|
if err != nil {
|
||||||
a.logger.Error("解析数据失败", "error", err)
|
a.logger.Error("解析数据失败", "error", err)
|
||||||
return 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 {
|
if err != nil {
|
||||||
a.logger.Error("写入文件失败", "error", err)
|
a.logger.Error("写入文件失败", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +146,20 @@ func (a *App) getStatusMessage() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReadRawJsonFile 供前端调用,读取output_raw.json内容
|
// ReadRawJsonFile 供前端调用,读取output_raw.json内容
|
||||||
func (a *App) ReadRawJsonFile() (string, error) {
|
func (a *App) ReadRawJsonFile() (*model.ParsedResult, error) {
|
||||||
return a.parserService.ReadRawJsonFile()
|
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 解析十六进制数据
|
// ParseHexData 解析十六进制数据
|
||||||
func (ps *ParserService) ParseHexData(hexDataList []string) (*model.CaptureResult, error) {
|
func (ps *ParserService) ParseHexData(hexDataList []string) (*model.ParsedResult, string, error) {
|
||||||
if len(hexDataList) == 0 {
|
if len(hexDataList) == 0 {
|
||||||
ps.logger.Warn("没有数据需要解析")
|
ps.logger.Warn("没有数据需要解析")
|
||||||
return &model.CaptureResult{
|
return &model.ParsedResult{
|
||||||
Data: make([]model.Equipment, 0),
|
Items: make([]interface{}, 0),
|
||||||
Units: make([]interface{}, 0),
|
Heroes: make([]interface{}, 0),
|
||||||
}, nil
|
}, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ps.logger.Info("开始远程解析数据", "count", len(hexDataList))
|
ps.logger.Info("开始远程解析数据", "count", len(hexDataList))
|
||||||
|
|
||||||
// 远程接口解析
|
|
||||||
//fmt.Println("开始远程解析数据", len(hexDataList))
|
|
||||||
url := "https://krivpfvxi0.execute-api.us-west-2.amazonaws.com/dev/getItems"
|
url := "https://krivpfvxi0.execute-api.us-west-2.amazonaws.com/dev/getItems"
|
||||||
reqBody := map[string]interface{}{
|
reqBody := map[string]interface{}{
|
||||||
"data": hexDataList,
|
"data": hexDataList,
|
||||||
@@ -55,45 +53,51 @@ func (ps *ParserService) ParseHexData(hexDataList []string) (*model.CaptureResul
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
body, _ := ioutil.ReadAll(resp.Body)
|
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)
|
fileErr := ioutil.WriteFile("output_raw.json", body, 0644)
|
||||||
if fileErr != nil {
|
if fileErr != nil {
|
||||||
ps.logger.Error("写入原始json文件失败", "error", fileErr)
|
ps.logger.Error("写入原始json文件失败", "error", fileErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
ps.logger.Info("远程原始数据已写入output_raw.json")
|
ps.logger.Info("远程原始数据已写入output_raw.json")
|
||||||
|
parsedResult, err := ps.ReadRawJsonFile(string(body))
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
// 返回空集合,保证前端不报错
|
return parsedResult, "", nil
|
||||||
return &model.CaptureResult{
|
|
||||||
Data: make([]model.Equipment, 0),
|
|
||||||
Units: make([]interface{}, 0),
|
|
||||||
}, nil
|
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
ps.logger.Error("远程解析请求失败", "error", err)
|
ps.logger.Error("远程解析请求失败", "error", err)
|
||||||
return nil, fmt.Errorf("远程解析请求失败: %v", err)
|
return nil, "", fmt.Errorf("远程解析请求失败: %v", err)
|
||||||
} else {
|
} else {
|
||||||
ps.logger.Error("远程解析响应码异常", "status", resp.StatusCode)
|
ps.logger.Error("远程解析响应码异常", "status", resp.StatusCode)
|
||||||
return nil, fmt.Errorf("远程解析响应码异常: %d", resp.StatusCode)
|
return nil, "", fmt.Errorf("远程解析响应码异常: %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ps.logger.Error("远程解析请求构建失败", "error", err)
|
ps.logger.Error("远程解析请求构建失败", "error", err)
|
||||||
return nil, fmt.Errorf("远程解析请求构建失败: %v", err)
|
return nil, "", fmt.Errorf("远程解析请求构建失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadRawJsonFile 读取output_raw.json文件内容并进行数据转换
|
// ReadRawJsonFile 读取rawJson内容并进行数据转换,返回ParsedResult对象
|
||||||
func (ps *ParserService) ReadRawJsonFile() (string, error) {
|
func (ps *ParserService) ReadRawJsonFile(rawJson string) (*model.ParsedResult, error) {
|
||||||
data, err := ioutil.ReadFile("output_raw.json")
|
|
||||||
if err != nil {
|
|
||||||
ps.logger.Error("读取output_raw.json失败", "error", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析原始JSON数据
|
|
||||||
var rawData map[string]interface{}
|
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)
|
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)
|
// 过滤有效装备 (x => !!x.f)
|
||||||
var validEquips []interface{}
|
var validEquips []interface{}
|
||||||
for _, equip := range equips {
|
for _, equip := range equips {
|
||||||
@@ -122,29 +123,24 @@ func (ps *ParserService) ReadRawJsonFile() (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//fmt.Println("过滤f字段后装备数:", len(validEquips))
|
|
||||||
|
|
||||||
// 转换装备数据
|
// 转换装备数据
|
||||||
convertedItems := ps.convertItemsAllWithLog(validEquips)
|
convertedItems := ps.convertItemsAllWithLog(validEquips)
|
||||||
//fmt.Println("转换后装备数:", len(convertedItems))
|
|
||||||
|
|
||||||
// 转换英雄数据(只对最大组)
|
// 转换英雄数据(只对最大组)
|
||||||
convertedHeroes := ps.convertUnits(rawUnits)
|
convertedHeroes := ps.convertUnits(rawUnits)
|
||||||
|
|
||||||
// 构建最终结果
|
result := &model.ParsedResult{
|
||||||
result := map[string]interface{}{
|
Items: make([]interface{}, len(convertedItems)),
|
||||||
"items": convertedItems,
|
Heroes: make([]interface{}, len(convertedHeroes)),
|
||||||
"heroes": convertedHeroes,
|
}
|
||||||
|
for i, v := range convertedItems {
|
||||||
|
result.Items[i] = v
|
||||||
|
}
|
||||||
|
for i, v := range convertedHeroes {
|
||||||
|
result.Heroes[i] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// 序列化为JSON字符串
|
return result, nil
|
||||||
resultJSON, err := json.Marshal(result)
|
|
||||||
if err != nil {
|
|
||||||
ps.logger.Error("序列化结果失败", "error", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(resultJSON), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertItems 转换装备数据
|
// convertItems 转换装备数据
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user