package main import ( "encoding/json" "fmt" "io/ioutil" "log" "os" "strings" ) type HAR struct { Log struct { Entries []struct { Request struct { Method string `json:"method"` URL string `json:"url"` } `json:"request"` WebSocketMessages []struct { Type string `json:"type"` Data string `json:"data"` Time float64 `json:"time"` } `json:"_webSocketMessages"` } `json:"entries"` } `json:"log"` } type WSMessage struct { ID string `json:"id"` Type string `json:"type"` Payload map[string]interface{} `json:"payload"` } func main() { if len(os.Args) < 2 { log.Fatal("Usage: parse-har ") } data, err := ioutil.ReadFile(os.Args[1]) if err != nil { log.Fatal(err) } var har HAR if err := json.Unmarshal(data, &har); err != nil { log.Fatal(err) } // First pass: collect all responses responses := make(map[string]bool) // ID -> has data for _, entry := range har.Log.Entries { for _, wsMsg := range entry.WebSocketMessages { if wsMsg.Type != "receive" { continue } var msg WSMessage if err := json.Unmarshal([]byte(wsMsg.Data), &msg); err != nil { continue } if msg.Type == "next" { // Check if payload has data if data, ok := msg.Payload["data"].(map[string]interface{}); ok && len(data) > 0 { responses[msg.ID] = true } } } } fmt.Println("=== WebSocket Operations (in order) ===\n") msgCount := 0 for _, entry := range har.Log.Entries { for _, wsMsg := range entry.WebSocketMessages { if wsMsg.Type != "send" { continue } var msg WSMessage if err := json.Unmarshal([]byte(wsMsg.Data), &msg); err != nil { continue } if msg.Type == "connection_init" { fmt.Printf("[%d] connection_init\n", msgCount) msgCount++ continue } if msg.Type == "subscribe" { opName := "" query := "" variables := map[string]interface{}{} extensions := map[string]interface{}{} if payload, ok := msg.Payload["operationName"].(string); ok { opName = payload } if q, ok := msg.Payload["query"].(string); ok { query = q } if v, ok := msg.Payload["variables"].(map[string]interface{}); ok { variables = v } if e, ok := msg.Payload["extensions"].(map[string]interface{}); ok { extensions = e } hasResponse := "" if responses[msg.ID] { hasResponse = " ✅ GOT DATA" } else { hasResponse = " ❌ NO DATA" } fmt.Printf("[%d] %s (ID: %s)%s\n", msgCount, opName, msg.ID, hasResponse) // Show query type if strings.Contains(query, "mutation") { fmt.Printf(" Type: MUTATION\n") } else if strings.Contains(query, "subscription") { fmt.Printf(" Type: SUBSCRIPTION\n") } else if strings.Contains(query, "query") { fmt.Printf(" Type: QUERY\n") } // Show variables if len(variables) > 0 { fmt.Printf(" Variables: %v\n", variables) } // Show extensions if len(extensions) > 0 { fmt.Printf(" Extensions: %v\n", extensions) } fmt.Println() msgCount++ } } } fmt.Printf("\nTotal operations: %d\n", msgCount) }