package app import ( "net/http" "os" "strings" ) // аккуратный разбор лога autoloop: игнорим "route:", смотрим status func parseAutoloopStatus(lines []string) (word, raw string) { for i := len(lines) - 1; i >= 0; i-- { line := strings.TrimSpace(lines[i]) if line == "" { continue } if idx := strings.Index(line, "autoloop:"); idx >= 0 { line = strings.TrimSpace(line[idx+len("autoloop:"):]) } lower := strings.ToLower(line) // route: default dev ... - нам неинтересно if strings.HasPrefix(lower, "route: ") { continue } switch { case strings.Contains(lower, "status: connected"), strings.Contains(lower, "after connect: connected"): return "CONNECTED", line case strings.Contains(lower, "status: reconnecting"): return "RECONNECTING", line case strings.Contains(lower, "status: disconnected"), strings.Contains(lower, "still disconnected"): return "DISCONNECTED", line case strings.Contains(lower, "timeout"), strings.Contains(lower, "failed"): return "ERROR", line } } return "unknown", "" } func handleVPNAutoloopStatus(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } lines := tailFile(autoloopLogPath, 200) word, raw := parseAutoloopStatus(lines) writeJSON(w, http.StatusOK, map[string]any{ "raw_text": raw, "status_word": word, }) } func handleVPNStatus(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } // desired location loc := "" if data, err := os.ReadFile(desiredLocation); err == nil { loc = parseStoredVPNLocationPrimary(string(data)) } // unit state stdout, _, _, err := runCommand("systemctl", "is-active", adgvpnUnit) unitState := strings.TrimSpace(stdout) if err != nil || unitState == "" { unitState = "unknown" } // автолуп lines := tailFile(autoloopLogPath, 200) word, raw := parseAutoloopStatus(lines) writeJSON(w, http.StatusOK, map[string]any{ "desired_location": loc, "status_word": word, "raw_text": raw, "unit_state": unitState, }) } func parseStoredVPNLocationPrimary(raw string) string { v := strings.TrimSpace(raw) if v == "" { return "" } if p := strings.SplitN(v, "|", 2); len(p) == 2 { return strings.TrimSpace(p[0]) } return v }