Last active
September 30, 2025 18:11
-
-
Save buddy-sandidge/68f526ea54a98941ee1755a0a4dbbafd to your computer and use it in GitHub Desktop.
Data-star SSE no reconnect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module gist.github.com/buddy-sandidge/68f526ea54a98941ee1755a0a4dbbafd.git | |
| go 1.25.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"/> | |
| <title>No SSE Reconnect</title> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"/> | |
| <script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/[email protected]/bundles/datastar.js"></script> | |
| </head> | |
| <body> | |
| <main> | |
| <p>From Datastar</p> | |
| <div data-on-load="@get('/now')"></div> | |
| <div id=ts></div> | |
| <hr/> | |
| <p>From SSE</p> | |
| <div id=sse_ts></div> | |
| </main> | |
| <script> | |
| const sse = new EventSource('/now'); | |
| sse.addEventListener("datastar-patch-elements", function (e) { | |
| const el = document.createElement("div") | |
| el.innerHTML = e.data.substring('elements '.length) | |
| document.getElementById("sse_ts").innerHTML = el.firstChild.innerHTML | |
| }) | |
| </script> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "context" | |
| _ "embed" | |
| "errors" | |
| "flag" | |
| "fmt" | |
| "net/http" | |
| "os" | |
| "os/signal" | |
| "time" | |
| ) | |
| //go:embed index.html | |
| var indexHtml string | |
| func main() { | |
| ctx, cancel := context.WithCancel(context.Background()) | |
| err := run(ctx) | |
| cancel() | |
| if err != nil { | |
| os.Stderr.WriteString("ERROR: " + err.Error() + "\n") | |
| os.Exit(1) | |
| } | |
| } | |
| func run(ctx context.Context) error { | |
| var port int | |
| flag.IntVar(&port, "port", 8081, "port to listen on") | |
| flag.Parse() | |
| ctx, cancel := context.WithCancel(ctx) | |
| shutdown := make(chan struct{}) | |
| mux := http.NewServeMux() | |
| mux.HandleFunc("/now", func(resp http.ResponseWriter, req *http.Request) { | |
| fmt.Println("handling /now") | |
| resp.Header().Set("Cache-Control", "no-cache") | |
| resp.Header().Set("Content-Type", "text/event-stream") | |
| if req.ProtoMajor == 1 { | |
| resp.Header().Set("Connection", "keep-alive") | |
| } | |
| rc := http.NewResponseController(resp) | |
| resp.Write([]byte("event: datastar-patch-elements\n")) | |
| resp.Write([]byte("data: elements <div id=ts>" + time.Now().Round(time.Second).Format(time.RFC3339) + "</div>\n\n")) | |
| rc.Flush() | |
| t := time.NewTicker(1 * time.Second) | |
| defer t.Stop() | |
| for { | |
| select { | |
| case <-shutdown: | |
| fmt.Println("shutting down") | |
| return | |
| case <-req.Context().Done(): | |
| fmt.Println("request cancelled") | |
| return | |
| case <-t.C: | |
| ts := time.Now().Round(time.Second).Format(time.RFC3339) | |
| resp.Write([]byte("event: datastar-patch-elements\n")) | |
| resp.Write([]byte("data: elements <div id=ts>" + ts + "</div>\n\n")) | |
| rc.Flush() | |
| } | |
| } | |
| }) | |
| mux.HandleFunc("/", func(resp http.ResponseWriter, req *http.Request) { | |
| if req.URL.Path == "/" { | |
| resp.Write([]byte(indexHtml)) | |
| } else { | |
| http.NotFound(resp, req) | |
| } | |
| }) | |
| server := &http.Server{ | |
| Addr: fmt.Sprintf(":%d", port), | |
| Handler: mux, | |
| } | |
| server.RegisterOnShutdown(func() { | |
| close(shutdown) | |
| }) | |
| ret := make(chan error) | |
| go func() { | |
| fmt.Printf("starting http server: http://localhost%s/\n", server.Addr) | |
| if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { | |
| cancel() | |
| ret <- fmt.Errorf("running server: %w", err) | |
| } else { | |
| ret <- nil | |
| cancel() | |
| } | |
| }() | |
| sig := make(chan os.Signal, 1) | |
| signal.Notify(sig, os.Interrupt) | |
| select { | |
| case <-ctx.Done(): | |
| case <-sig: | |
| } | |
| if err := server.Shutdown(ctx); err != nil { | |
| return fmt.Errorf("shutting down server: %w", err) | |
| } | |
| return <-ret | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment