package main import ( "bufio" "encoding/json" "log" "net/url" "os" "strings" "sync" "time" "SimpleArmaAdmin/internal/crypto" "SimpleArmaAdmin/internal/parser" "github.com/gorilla/websocket" ) var mockLogs = []string{ "12:30:01.122 SCRIPT : [RJSSupport][Chat] [Global] Zauberklöte: hi, leute kurze frage. zock seit monaten wieder mal arma, was ist aus dem gtg#4 und #5 geworden, da ist ja nix los", "09:37:50.865 DEFAULT : BattlEye Server: 'Player #0 Mike1Delta (92.209.175.19:6679) connected'", "13:29:19.727 SCRIPT : [RJSSupport][Chat] [Global] 纱雾.: WHAT", "09:38:53.842 DEFAULT : BattlEye Server: 'Player #0 Mike1Delta disconnected'", "14:56:34.622 SCRIPT : [RJSSupport][Chat] [Global] Toope: help?", "15:04:22.868 SCRIPT : [RJSSupport][Chat] [Global] vatrano: Transpo 5-10min abwesend", } // extractPlayerName extracts the player name from event content func extractPlayerName(content string) string { // For JOIN/LEAVE: "Mike1Delta connected to server" if strings.Contains(content, "connected to server") { parts := strings.Split(content, " connected") if len(parts) > 0 { return strings.TrimSpace(parts[0]) } } if strings.Contains(content, "left the server") { parts := strings.Split(content, " left") if len(parts) > 0 { return strings.TrimSpace(parts[0]) } } // For CHAT: "PlayerName: message" if strings.Contains(content, ":") { parts := strings.SplitN(content, ":", 2) if len(parts) > 0 { return strings.TrimSpace(parts[0]) } } return "" } func main() { gatewayURL := os.Getenv("GATEWAY_URL") logFilePath := os.Getenv("LOG_FILE_PATH") mockMode := os.Getenv("MOCK_MODE") == "true" if logFilePath == "" { logFilePath = "arma_server.rpt" } masterKey := []byte("this-is-a-32-byte-master-key-xyz") communityID := "comm-123-abc" // TODO: Initialize SQLite buffer for offline mode // offlineBuffer, err := initOfflineBuffer("worker_buffer.db") // if err != nil { // log.Fatalf("Failed to init offline buffer: %v", err) // } // defer offlineBuffer.Close() u, _ := url.Parse(gatewayURL) log.Printf("Worker starting for community %s. MockMode: %v, Offline-Buffer: enabled", communityID, mockMode) for { c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { log.Printf("Dial failed: %v. Retrying in 5s...", err) time.Sleep(5 * time.Second) continue } log.Println("Connected to gateway") var mu sync.Mutex // 1. Telemetry Loop go func() { for { telemetry := map[string]interface{}{ "type": "TELEMETRY", "community_id": communityID, "fps": 45.5 + float64(time.Now().Unix()%5), "players": 12, "ai_count": 142 + (time.Now().Unix() % 10), "vehicle_count": 24, } data, _ := json.Marshal(telemetry) mu.Lock() err := c.WriteMessage(websocket.TextMessage, data) mu.Unlock() if err != nil { return } time.Sleep(5 * time.Second) } }() // 2. Log Tailing / Mocking go func() { if mockMode { i := 0 for { line := mockLogs[i%len(mockLogs)] event := parser.ParseLine(line) if event != nil { // Enrich event with blind index for player names if event.Type == "JOIN" || event.Type == "LEAVE" || event.Type == "CHAT" { playerName := extractPlayerName(event.Content) if playerName != "" { blindIndex := crypto.GenerateBlindIndex(playerName, masterKey) event.Content = event.Content + " [BLIND:" + blindIndex + "]" } } payload, _ := json.Marshal(event) encrypted, _ := crypto.Encrypt(payload, masterKey) mu.Lock() err := c.WriteMessage(websocket.BinaryMessage, encrypted) mu.Unlock() if err != nil { return } log.Printf("Sent MOCK event: %s", event.Type) } i++ time.Sleep(10 * time.Second) } } else { file, err := os.Open(logFilePath) if err != nil { log.Printf("Could not open log file: %v", err) return } file.Seek(0, 2) scanner := bufio.NewScanner(file) for { if scanner.Scan() { line := scanner.Text() event := parser.ParseLine(line) if event != nil { payload, _ := json.Marshal(event) encrypted, _ := crypto.Encrypt(payload, masterKey) mu.Lock() err := c.WriteMessage(websocket.BinaryMessage, encrypted) mu.Unlock() if err != nil { return } log.Printf("Sent LIVE event: %s", event.Type) } } time.Sleep(500 * time.Millisecond) } } }() for { if _, _, err := c.ReadMessage(); err != nil { log.Printf("Read error: %v. Reconnecting...", err) break } } c.Close() time.Sleep(2 * time.Second) } }