--- WebSocket watcher ---
(w http.ResponseWriter, r *http.Request)
| 925 | // --- WebSocket watcher --- |
| 926 | |
| 927 | func (s *Server) watchWS(w http.ResponseWriter, r *http.Request) { |
| 928 | origin := strings.TrimSpace(r.Header.Get("Origin")) |
| 929 | if origin != "" && !s.isAllowedOrigin(r, origin) { |
| 930 | if !s.wsRejectLimiter.allow(s.clientAddressKey(r)) { |
| 931 | http.Error(w, "too many invalid websocket origins", http.StatusTooManyRequests) |
| 932 | return |
| 933 | } |
| 934 | http.Error(w, "forbidden origin", http.StatusForbidden) |
| 935 | return |
| 936 | } |
| 937 | ws, err := websocket.Accept(w, r, &websocket.AcceptOptions{ |
| 938 | InsecureSkipVerify: true, |
| 939 | }) |
| 940 | if err != nil { |
| 941 | log.Printf("ws accept failed: %v", err) |
| 942 | return |
| 943 | } |
| 944 | defer ws.Close(websocket.StatusNormalClosure, "") |
| 945 | ctx, cancel := context.WithCancel(r.Context()) |
| 946 | defer cancel() |
| 947 | |
| 948 | events, unsubscribe := s.currentWatcher().Subscribe() |
| 949 | defer unsubscribe() |
| 950 | |
| 951 | pingTicker := time.NewTicker(25 * time.Second) |
| 952 | defer pingTicker.Stop() |
| 953 | |
| 954 | for { |
| 955 | select { |
| 956 | case <-ctx.Done(): |
| 957 | return |
| 958 | case ev, ok := <-events: |
| 959 | if !ok { |
| 960 | return |
| 961 | } |
| 962 | payload, _ := json.Marshal(ev) |
| 963 | if err := ws.Write(ctx, websocket.MessageText, payload); err != nil { |
| 964 | return |
| 965 | } |
| 966 | case <-pingTicker.C: |
| 967 | if err := ws.Ping(ctx); err != nil { |
| 968 | return |
| 969 | } |
| 970 | } |
| 971 | } |
| 972 | } |
| 973 | |
| 974 | // --- Static / PWA fallback --- |
| 975 |
nothing calls this directly
no test coverage detected