@@ -43,15 +43,14 @@ import (
4343 "bytes"
4444 "encoding/json"
4545 "fmt"
46+ "io"
4647 "net/http"
4748 "os"
4849 "path/filepath"
4950 "strconv"
5051 "strings"
5152 "time"
5253
53- "github.com/gorilla/websocket"
54-
5554 "github.com/arl/statsviz/internal/plot"
5655 "github.com/arl/statsviz/internal/static"
5756)
@@ -82,7 +81,7 @@ func Register(mux *http.ServeMux, opts ...Option) error {
8281// updates metrics data and provides two essential HTTP handlers:
8382// - the Index handler serves Statsviz user interface, allowing you to
8483// visualize runtime metrics on your browser.
85- // - The Ws handler establishes a WebSocket connection allowing the connected
84+ // - The Ws handler establishes a data connection allowing the connected
8685// browser to receive metrics updates from the server.
8786//
8887// The zero value is not a valid Server, use NewServer to create a valid one.
@@ -161,20 +160,34 @@ func (s *Server) Register(mux *http.ServeMux) {
161160// intercept is a middleware that intercepts requests for plotsdef.js, which is
162161// generated dynamically based on the plots configuration. Other requests are
163162// forwarded as-is.
164- func intercept (h http.Handler , cfg * plot.Config ) http.HandlerFunc {
165- buf := bytes.Buffer {}
166- buf .WriteString ("export default " )
167- enc := json .NewEncoder (& buf )
168- enc .SetIndent ("" , " " )
169- if err := enc .Encode (cfg ); err != nil {
170- panic ("unexpected failure to encode plot definitions: " + err .Error ())
163+ func intercept (h http.Handler , cfg * plot.Config , extraConfig map [string ]any ) http.HandlerFunc {
164+ var plotsdefjs []byte
165+ //Using parentheses helps gc
166+ {
167+ buf := bytes.Buffer {}
168+ buf .WriteString ("export default " )
169+ enc := json .NewEncoder (& buf )
170+ enc .SetIndent ("" , " " )
171+ var encodeValue any = cfg
172+ if len (extraConfig ) > 0 {
173+ encodeValue1 := map [string ]any {
174+ "series" : cfg .Series ,
175+ "events" : cfg .Events ,
176+ }
177+ for k , v := range extraConfig {
178+ encodeValue1 [k ] = v
179+ }
180+ encodeValue = encodeValue1
181+ }
182+ if err := enc .Encode (encodeValue ); err != nil {
183+ panic ("unexpected failure to encode plot definitions: " + err .Error ())
184+ }
185+ buf .WriteString (";" )
186+ plotsdefjs = buf .Bytes ()
171187 }
172- buf .WriteString (";" )
173- plotsdefjs := buf .Bytes ()
174-
175188 return func (w http.ResponseWriter , r * http.Request ) {
176189 if r .URL .Path == "js/plotsdef.js" {
177- w .Header ().Add ("Content-Length" , strconv .Itoa (buf . Len ( )))
190+ w .Header ().Add ("Content-Length" , strconv .Itoa (len ( plotsdefjs )))
178191 w .Header ().Add ("Content-Type" , "text/javascript; charset=utf-8" )
179192 w .Write (plotsdefjs )
180193 return
@@ -228,7 +241,9 @@ func assetsFS() http.FileSystem {
228241func (s * Server ) Index () http.HandlerFunc {
229242 prefix := strings .TrimSuffix (s .root , "/" ) + "/"
230243 assets := http .FileServer (assetsFS ())
231- handler := intercept (assets , s .plots .Config ())
244+ handler := intercept (assets , s .plots .Config (), map [string ]any {
245+ "sendFrequency" : s .intv .Milliseconds (),
246+ })
232247
233248 return http .StripPrefix (prefix , handler ).ServeHTTP
234249}
@@ -238,46 +253,51 @@ func (s *Server) Index() http.HandlerFunc {
238253// connection to the WebSocket protocol.
239254func (s * Server ) Ws () http.HandlerFunc {
240255 return func (w http.ResponseWriter , r * http.Request ) {
241- var upgrader = websocket.Upgrader {
242- ReadBufferSize : 1024 ,
243- WriteBufferSize : 1024 ,
244- }
245-
246- ws , err := upgrader .Upgrade (w , r , nil )
247- if err != nil {
256+ if strings .Contains (r .Header .Get ("Accept" ), "/event-stream" ) {
257+ // If the connection is initiated by an already open web UI
258+ // (started by a previous process, for example), then plotsdef.js won't be
259+ // requested. Call plots.Config() manually to ensure that s.plots internals
260+ // are correctly initialized.
261+ s .plots .Config ()
262+
263+ w .Header ().Set ("Content-Type" , "text/event-stream" )
264+ w .Header ().Set ("Cache-Control" , "no-cache" )
265+ w .Header ().Set ("Connection" , "keep-alive" )
266+ s .startTransfer (w )
248267 return
249268 }
250- defer ws .Close ()
251-
252- // Ignore this error. This happens when the other end connection closes,
253- // for example. We can't handle it in any meaningful way anyways.
254- _ = s .sendStats (ws , s .intv )
269+ w .WriteHeader (http .StatusBadRequest )
270+ w .Write ([]byte ("This endpoint only supports text/event-stream requests" ))
255271 }
256272}
257273
258- // sendStats sends runtime statistics over the WebSocket connection.
259- func (s * Server ) sendStats (conn * websocket.Conn , frequency time.Duration ) error {
260- tick := time .NewTicker (frequency )
261- defer tick .Stop ()
262-
263- // If the WebSocket connection is initiated by an already open web UI
264- // (started by a previous process, for example), then plotsdef.js won't be
265- // requested. Call plots.Config() manually to ensure that s.plots internals
266- // are correctly initialized.
267- s .plots .Config ()
268-
269- for range tick .C {
270- w , err := conn .NextWriter (websocket .TextMessage )
271- if err != nil {
274+ func (s * Server ) startTransfer (w io.Writer ) {
275+ buffer := bytes.Buffer {}
276+ buffer .WriteString ("data: " )
277+ callData := func () error {
278+ if err := s .plots .WriteValues (& buffer ); err == nil {
279+ _ , err = w .Write (buffer .Bytes ())
280+ if err != nil {
281+ return err
282+ }
283+ if f , ok := w .(http.Flusher ); ok {
284+ f .Flush ()
285+ }
286+ } else {
272287 return err
273288 }
274- if err := s .plots .WriteValues (w ); err != nil {
275- return err
276- }
277- if err := w .Close (); err != nil {
278- return err
289+ return nil
290+ }
291+ //the first time it was sent immediately
292+ err := callData ()
293+ if err != nil {
294+ return
295+ }
296+ tick := time .NewTicker (s .intv )
297+ defer tick .Stop ()
298+ for range tick .C {
299+ if callData () != nil {
300+ return
279301 }
280302 }
281-
282- panic ("unreachable" )
283303}
0 commit comments