This commit is contained in:
hu xiaotong
2025-07-02 16:12:52 +08:00
commit 0246bc7060
48 changed files with 460639 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
package service
import (
"context"
"fmt"
"sync"
"time"
"equipment-analyzer/internal/capture"
"equipment-analyzer/internal/config"
"equipment-analyzer/internal/model"
"equipment-analyzer/internal/utils"
)
type CaptureService struct {
config *config.Config
logger *utils.Logger
packetCapture *capture.PacketCapture
processor *capture.TCPProcessor
mutex sync.RWMutex
isCapturing bool
dataChan chan *model.CaptureResult
errorChan chan error
}
func NewCaptureService(cfg *config.Config, logger *utils.Logger) *CaptureService {
return &CaptureService{
config: cfg,
logger: logger,
packetCapture: capture.NewPacketCapture(),
processor: capture.NewTCPProcessor(),
dataChan: make(chan *model.CaptureResult, 100),
errorChan: make(chan error, 100),
}
}
// StartCapture 开始抓包
func (cs *CaptureService) StartCapture(ctx context.Context, config capture.Config) error {
cs.mutex.Lock()
defer cs.mutex.Unlock()
if cs.isCapturing {
return fmt.Errorf("capture already running")
}
if err := cs.packetCapture.Start(config); err != nil {
return fmt.Errorf("failed to start capture: %w", err)
}
cs.isCapturing = true
cs.logger.Info("Packet capture started", "interface", config.InterfaceName)
// 启动数据处理协程
go cs.processData(ctx)
return nil
}
// StopCapture 停止抓包
func (cs *CaptureService) StopCapture() error {
cs.mutex.Lock()
defer cs.mutex.Unlock()
if !cs.isCapturing {
return fmt.Errorf("capture not running")
}
cs.packetCapture.Stop()
cs.isCapturing = false
cs.logger.Info("Packet capture stopped")
return nil
}
// GetCapturedData 获取抓包数据
func (cs *CaptureService) GetCapturedData() []string {
return cs.packetCapture.GetCapturedData()
}
// ProcessAllData 处理所有数据
func (cs *CaptureService) ProcessAllData() {
cs.packetCapture.ProcessAllData()
}
// IsCapturing 检查是否正在抓包
func (cs *CaptureService) IsCapturing() bool {
cs.mutex.RLock()
defer cs.mutex.RUnlock()
return cs.isCapturing
}
// processData 处理抓包数据
func (cs *CaptureService) processData(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
// 这里可以添加实时数据处理逻辑
time.Sleep(100 * time.Millisecond)
}
}
}

View File

@@ -0,0 +1,168 @@
package service
import (
"context"
"encoding/json"
"fmt"
"time"
"equipment-analyzer/internal/capture"
"equipment-analyzer/internal/config"
"equipment-analyzer/internal/model"
"equipment-analyzer/internal/utils"
)
type App struct {
config *config.Config
logger *utils.Logger
captureService *CaptureService
parserService *ParserService
}
func NewApp(cfg *config.Config, logger *utils.Logger) *App {
return &App{
config: cfg,
logger: logger,
captureService: NewCaptureService(cfg, logger),
parserService: NewParserService(cfg, logger),
}
}
func (a *App) Startup(ctx context.Context) {
a.logger.Info("应用启动")
}
func (a *App) DomReady(ctx context.Context) {
a.logger.Info("DOM准备就绪")
}
func (a *App) BeforeClose(ctx context.Context) (prevent bool) {
a.logger.Info("应用即将关闭")
return false
}
func (a *App) Shutdown(ctx context.Context) {
a.logger.Info("应用关闭")
}
// GetNetworkInterfaces 获取网络接口列表
func (a *App) GetNetworkInterfaces() ([]model.NetworkInterface, error) {
interfaces, err := capture.GetNetworkInterfaces()
if err != nil {
a.logger.Error("获取网络接口失败", "error", err)
return nil, err
}
return interfaces, nil
}
// StartCapture 开始抓包
func (a *App) StartCapture(interfaceName string) error {
if a.captureService.IsCapturing() {
return fmt.Errorf("抓包已在进行中")
}
config := capture.Config{
InterfaceName: interfaceName,
Filter: a.config.Capture.DefaultFilter,
Timeout: time.Duration(a.config.Capture.DefaultTimeout) * time.Millisecond,
BufferSize: a.config.Capture.BufferSize,
}
err := a.captureService.StartCapture(context.Background(), config)
if err != nil {
a.logger.Error("开始抓包失败", "error", err)
return err
}
a.logger.Info("抓包开始", "interface", interfaceName)
return nil
}
// StopCapture 停止抓包
func (a *App) StopCapture() error {
if !a.captureService.IsCapturing() {
return fmt.Errorf("没有正在进行的抓包")
}
err := a.captureService.StopCapture()
if err != nil {
a.logger.Error("停止抓包失败", "error", err)
return err
}
// 处理所有收集的数据
a.captureService.ProcessAllData()
a.logger.Info("抓包停止")
return nil
}
// GetCapturedData 获取抓包数据
func (a *App) GetCapturedData() ([]string, error) {
return a.captureService.GetCapturedData(), nil
}
// ParseData 解析数据为JSON
func (a *App) ParseData(hexDataList []string) (string, error) {
result, 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
}
// ExportData 导出数据到文件
func (a *App) ExportData(hexDataList []string, filename string) error {
result, 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))
// 简单示例:写入到当前目录
err = utils.WriteFile(filename, jsonData)
if err != nil {
a.logger.Error("写入文件失败", "error", err)
return err
}
return nil
}
// GetCaptureStatus 获取抓包状态
func (a *App) GetCaptureStatus() model.CaptureStatus {
return model.CaptureStatus{
IsCapturing: a.captureService.IsCapturing(),
Status: a.getStatusMessage(),
}
}
func (a *App) getStatusMessage() string {
if a.captureService.IsCapturing() {
return "正在抓包..."
}
return "准备就绪"
}
// ReadRawJsonFile 供前端调用读取output_raw.json内容
func (a *App) ReadRawJsonFile() (string, error) {
return a.parserService.ReadRawJsonFile()
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,516 @@
package service
import (
"bytes"
"encoding/json"
"equipment-analyzer/internal/config"
"equipment-analyzer/internal/model"
"equipment-analyzer/internal/parser"
"equipment-analyzer/internal/utils"
"fmt"
"io/ioutil"
"net/http"
"time"
)
type ParserService struct {
config *config.Config
logger *utils.Logger
hexParser *parser.HexParser
}
func NewParserService(cfg *config.Config, logger *utils.Logger) *ParserService {
return &ParserService{
config: cfg,
logger: logger,
hexParser: parser.NewHexParser(),
}
}
// ParseHexData 解析十六进制数据
func (ps *ParserService) ParseHexData(hexDataList []string) (*model.CaptureResult, error) {
if len(hexDataList) == 0 {
ps.logger.Warn("没有数据需要解析")
return &model.CaptureResult{
Data: make([]model.Equipment, 0),
Units: make([]interface{}, 0),
}, nil
}
ps.logger.Info("开始远程解析数据", "count", len(hexDataList))
// 远程接口解析
url := "https://krivpfvxi0.execute-api.us-west-2.amazonaws.com/dev/getItems"
reqBody := map[string]interface{}{
"data": hexDataList,
}
jsonBytes, _ := json.Marshal(reqBody)
client := &http.Client{Timeout: 15 * time.Second}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes))
if err == nil {
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err == nil && resp.StatusCode == 200 {
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
// 直接写入本地文件
fileErr := ioutil.WriteFile("output_raw.json", body, 0644)
if fileErr != nil {
ps.logger.Error("写入原始json文件失败", "error", fileErr)
}
ps.logger.Info("远程原始数据已写入output_raw.json")
// 返回空集合,保证前端不报错
return &model.CaptureResult{
Data: make([]model.Equipment, 0),
Units: make([]interface{}, 0),
}, nil
} else if err != nil {
ps.logger.Error("远程解析请求失败", "error", err)
return nil, fmt.Errorf("远程解析请求失败: %v", err)
} else {
ps.logger.Error("远程解析响应码异常", "status", resp.StatusCode)
return nil, fmt.Errorf("远程解析响应码异常: %d", resp.StatusCode)
}
} else {
ps.logger.Error("远程解析请求构建失败", "error", 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数据
var rawData map[string]interface{}
if err := json.Unmarshal(data, &rawData); err != nil {
ps.logger.Error("解析JSON失败", "error", err)
return "", err
}
// 提取装备和英雄数据
equips, _ := rawData["data"].([]interface{})
// 修正units 取最大长度的那组
var rawUnits []interface{}
if unitsRaw, ok := rawData["units"].([]interface{}); ok && len(unitsRaw) > 0 {
maxLen := 0
for _, u := range unitsRaw {
if arr, ok := u.([]interface{}); ok && len(arr) > maxLen {
maxLen = len(arr)
rawUnits = arr
}
}
}
// 1. 原始装备总数
fmt.Println("原始装备总数:", len(equips))
// 过滤有效装备 (x => !!x.f)
var validEquips []interface{}
for _, equip := range equips {
if equipMap, ok := equip.(map[string]interface{}); ok {
if f, exists := equipMap["f"]; exists && f != nil && f != "" {
validEquips = append(validEquips, equip)
}
}
}
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,
}
// 序列化为JSON字符串
resultJSON, err := json.Marshal(result)
if err != nil {
ps.logger.Error("序列化结果失败", "error", err)
return "", err
}
return string(resultJSON), nil
}
// convertItems 转换装备数据
func (ps *ParserService) convertItems(rawItems []interface{}) []map[string]interface{} {
var convertedItems []map[string]interface{}
for _, rawItem := range rawItems {
if itemMap, ok := rawItem.(map[string]interface{}); ok {
convertedItem := ps.convertSingleItem(itemMap)
if convertedItem != nil {
convertedItems = append(convertedItems, convertedItem)
}
}
}
var filteredItems []map[string]interface{}
for _, item := range convertedItems {
filteredItems = append(filteredItems, item)
}
return filteredItems
}
// convertSingleItem 转换单个装备
func (ps *ParserService) convertSingleItem(item map[string]interface{}) map[string]interface{} {
converted := make(map[string]interface{})
// 复制基本字段
for key, value := range item {
converted[key] = value
}
// 转换装备类型
ps.convertGear(converted)
// 转换等级
ps.convertRank(converted)
// 转换套装
ps.convertSet(converted)
// 转换名称
ps.convertName(converted)
// 转换等级
ps.convertLevel(converted)
// 转换增强
ps.convertEnhance(converted)
// 转换主属性
ps.convertMainStat(converted)
// 转换副属性
ps.convertSubStats(converted)
// 转换ID
ps.convertId(converted)
// 转换装备ID
ps.convertEquippedId(converted)
return converted
}
// convertUnits 转换英雄数据
func (ps *ParserService) convertUnits(rawUnits []interface{}) []map[string]interface{} {
var convertedUnits []map[string]interface{}
for _, rawUnit := range rawUnits {
if unitMap, ok := rawUnit.(map[string]interface{}); ok {
if name, exists := unitMap["name"]; exists && name != nil && name != "" {
if id, exists := unitMap["id"]; exists && id != nil {
convertedUnit := make(map[string]interface{})
for key, value := range unitMap {
convertedUnit[key] = value
}
// 转换星星和觉醒
if g, exists := unitMap["g"]; exists {
convertedUnit["stars"] = g
}
if z, exists := unitMap["z"]; exists {
convertedUnit["awaken"] = z
}
convertedUnits = append(convertedUnits, convertedUnit)
}
}
}
}
return convertedUnits
}
// 转换函数实现
func (ps *ParserService) convertGear(item map[string]interface{}) {
if _, exists := item["type"]; !exists {
if code, exists := item["code"].(string); exists {
baseCode := code
if idx := len(baseCode) - 1; idx >= 0 {
gearLetter := string(baseCode[idx])
item["gear"] = gearByGearLetter[gearLetter]
}
}
} else {
if itemType, exists := item["type"].(string); exists {
item["gear"] = gearByIngameType[itemType]
}
}
}
func (ps *ParserService) convertRank(item map[string]interface{}) {
if g, exists := item["g"].(float64); exists {
rankIndex := int(g)
if rankIndex >= 0 && rankIndex < len(rankByIngameGrade) {
item["rank"] = rankByIngameGrade[rankIndex]
}
}
}
func (ps *ParserService) convertSet(item map[string]interface{}) {
if f, exists := item["f"].(string); exists {
item["set"] = setsByIngameSet[f]
}
}
func (ps *ParserService) convertName(item map[string]interface{}) {
if _, exists := item["name"]; !exists {
item["name"] = "Unknown"
}
}
func (ps *ParserService) convertLevel(item map[string]interface{}) {
if _, exists := item["level"]; !exists {
item["level"] = 0
}
}
func (ps *ParserService) convertEnhance(item map[string]interface{}) {
rank, rankExists := item["rank"].(string)
op, opExists := item["op"].([]interface{})
if rankExists && opExists {
countByRank := map[string]int{
"Normal": 5,
"Good": 6,
"Rare": 7,
"Heroic": 8,
"Epic": 9,
}
offsetByRank := map[string]int{
"Normal": 0,
"Good": 1,
"Rare": 2,
"Heroic": 3,
"Epic": 4,
}
count := countByRank[rank]
offset := offsetByRank[rank]
subsCount := len(op) - 1
if subsCount > count {
subsCount = count
}
enhance := (subsCount - offset) * 3
if enhance < 0 {
enhance = 0
}
item["enhance"] = enhance
}
}
func (ps *ParserService) convertMainStat(item map[string]interface{}) {
op, opExists := item["op"].([]interface{})
mainStatValue, mainStatExists := item["mainStatValue"].(float64)
if opExists && len(op) > 0 && mainStatExists {
if mainOp, ok := op[0].([]interface{}); ok && len(mainOp) > 0 {
if mainOpType, ok := mainOp[0].(string); ok {
mainType := statByIngameStat[mainOpType]
var mainValue float64
if ps.isFlat(mainOpType) {
mainValue = mainStatValue
} else {
mainValue = mainStatValue * 100
}
if mainValue == 0 || mainValue != mainValue { // NaN check
mainValue = 0
}
item["main"] = map[string]interface{}{
"type": mainType,
"value": mainValue,
}
}
}
}
}
func (ps *ParserService) convertSubStats(item map[string]interface{}) {
op, opExists := item["op"].([]interface{})
if !opExists || len(op) <= 1 {
item["substats"] = []interface{}{}
return
}
statAcc := make(map[string]map[string]interface{})
// 处理副属性 (从索引1开始)
for i := 1; i < len(op); i++ {
if opItem, ok := op[i].([]interface{}); ok && len(opItem) >= 2 {
opType, _ := opItem[0].(string)
opValue, _ := opItem[1].(float64)
annotation := ""
if len(opItem) > 2 {
annotation, _ = opItem[2].(string)
}
statType := statByIngameStat[opType]
var value float64
if ps.isFlat(opType) {
value = opValue
} else {
value = opValue * 100
}
if existingStat, exists := statAcc[statType]; exists {
existingStat["value"] = existingStat["value"].(float64) + value
if annotation == "c" {
existingStat["modified"] = true
} else if annotation != "u" {
rolls := existingStat["rolls"].(int) + 1
existingStat["rolls"] = rolls
existingStat["ingameRolls"] = rolls
}
} else {
rolls := 1
if annotation == "u" {
rolls = 0
}
statAcc[statType] = map[string]interface{}{
"value": value,
"rolls": rolls,
"ingameRolls": rolls,
"modified": annotation == "c",
}
}
}
}
// 转换为最终格式
var substats []interface{}
for statType, statData := range statAcc {
substat := map[string]interface{}{
"type": statType,
"value": statData["value"],
"rolls": statData["rolls"],
"ingameRolls": statData["ingameRolls"],
"modified": statData["modified"],
}
substats = append(substats, substat)
}
item["substats"] = substats
}
func (ps *ParserService) convertId(item map[string]interface{}) {
if id, exists := item["id"]; exists {
item["ingameId"] = id
}
}
func (ps *ParserService) convertEquippedId(item map[string]interface{}) {
if p, exists := item["p"]; exists {
item["ingameEquippedId"] = fmt.Sprintf("%v", p)
}
}
func (ps *ParserService) isFlat(text string) bool {
return text == "max_hp" || text == "speed" || text == "att" || text == "def"
}
// 映射常量
var (
rankByIngameGrade = []string{
"Unknown",
"Normal",
"Good",
"Rare",
"Heroic",
"Epic",
}
gearByIngameType = map[string]string{
"weapon": "Weapon",
"helm": "Helmet",
"armor": "Armor",
"neck": "Necklace",
"ring": "Ring",
"boot": "Boots",
}
gearByGearLetter = map[string]string{
"w": "Weapon",
"h": "Helmet",
"a": "Armor",
"n": "Necklace",
"r": "Ring",
"b": "Boots",
}
setsByIngameSet = map[string]string{
"set_acc": "HitSet",
"set_att": "AttackSet",
"set_coop": "UnitySet",
"set_counter": "CounterSet",
"set_cri_dmg": "DestructionSet",
"set_cri": "CriticalSet",
"set_def": "DefenseSet",
"set_immune": "ImmunitySet",
"set_max_hp": "HealthSet",
"set_penetrate": "PenetrationSet",
"set_rage": "RageSet",
"set_res": "ResistSet",
"set_revenge": "RevengeSet",
"set_scar": "InjurySet",
"set_speed": "SpeedSet",
"set_vampire": "LifestealSet",
"set_shield": "ProtectionSet",
"set_torrent": "TorrentSet",
}
statByIngameStat = map[string]string{
"att_rate": "AttackPercent",
"max_hp_rate": "HealthPercent",
"def_rate": "DefensePercent",
"att": "Attack",
"max_hp": "Health",
"def": "Defense",
"speed": "Speed",
"res": "EffectResistancePercent",
"cri": "CriticalHitChancePercent",
"cri_dmg": "CriticalHitDamagePercent",
"acc": "EffectivenessPercent",
"coop": "DualAttackChancePercent",
}
)
// 新增不做enhance过滤的convertItems
func (ps *ParserService) convertItemsAllWithLog(rawItems []interface{}) []map[string]interface{} {
var convertedItems []map[string]interface{}
for _, rawItem := range rawItems {
if itemMap, ok := rawItem.(map[string]interface{}); ok {
convertedItem := ps.convertSingleItem(itemMap)
if convertedItem != nil {
convertedItems = append(convertedItems, convertedItem)
}
}
}
return convertedItems
}

View File

@@ -0,0 +1,85 @@
package service
import (
"encoding/json"
"equipment-analyzer/internal/config"
"equipment-analyzer/internal/utils"
"fmt"
"testing"
)
func TestReadRawJsonFile(t *testing.T) {
// 创建测试用的配置和日志器
config := &config.Config{}
logger := utils.NewLogger()
// 创建ParserService实例
ps := NewParserService(config, logger)
// 调用ReadRawJsonFile方法
result, err := ps.ReadRawJsonFile()
if err != nil {
t.Fatalf("ReadRawJsonFile failed: %v", err)
}
fmt.Printf("Raw result length: %d\n", len(result))
fmt.Printf("Raw result preview: %s\n", result[:min(200, len(result))])
// 解析JSON结果
var parsedData map[string]interface{}
if err := json.Unmarshal([]byte(result), &parsedData); err != nil {
t.Fatalf("Failed to parse JSON result: %v", err)
}
// 检查数据结构
fmt.Printf("Parsed data keys: %v\n", getKeys(parsedData))
// 检查items字段
if items, exists := parsedData["items"]; exists {
if itemsArray, ok := items.([]interface{}); ok {
fmt.Printf("Items count: %d\n", len(itemsArray))
if len(itemsArray) > 0 {
fmt.Printf("First item: %+v\n", itemsArray[0])
}
} else {
fmt.Printf("Items is not an array: %T\n", items)
}
} else {
fmt.Println("Items field not found")
}
// 检查heroes字段
if heroes, exists := parsedData["heroes"]; exists {
if heroesArray, ok := heroes.([]interface{}); ok {
fmt.Printf("Heroes count: %d\n", len(heroesArray))
if len(heroesArray) > 0 {
fmt.Printf("First hero: %+v\n", heroesArray[0])
}
} else {
fmt.Printf("Heroes is not an array: %T\n", heroes)
}
} else {
fmt.Println("Heroes field not found")
}
// 如果没有数据,输出更多调试信息
if len(result) < 100 {
fmt.Printf("Result seems empty or very short: %q\n", result)
}
}
// 辅助函数
func min(a, b int) int {
if a < b {
return a
}
return b
}
func getKeys(m map[string]interface{}) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}