From fcceaa9b8165e742443856ca84f1b5d4b8dc8539 Mon Sep 17 00:00:00 2001 From: Drew Bednar Date: Sun, 13 Jul 2025 11:33:25 -0400 Subject: [PATCH] Working example --- .air.toml | 52 ++++++++++++++++++++++++++++++++++++++++++ .gitignore | 1 + go.mod | 2 +- main.go | 44 +++++++++++++++++++++++++++++------ ui/html/base.go.tmpl | 6 ++--- ui/html/index.go.tmpl | 5 ++-- ui/static/css/main.css | 4 ++++ ui/static/js/main.js | 8 +++++++ 8 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 .air.toml diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..498951f --- /dev/null +++ b/.air.toml @@ -0,0 +1,52 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + args_bin = [] + bin = "./tmp/main" + cmd = "go build -o ./tmp/main ." + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + post_cmd = [] + pre_cmd = [] + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = false + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + silent = false + time = false + +[misc] + clean_on_exit = false + +[proxy] + app_port = 0 + enabled = false + proxy_port = 0 + +[screen] + clear_on_rebuild = false + keep_scroll = true diff --git a/.gitignore b/.gitignore index adf8f72..26ef082 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ # Go workspace file go.work +tmp/ \ No newline at end of file diff --git a/go.mod b/go.mod index 4c30946..d4bac7c 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module git.runcible.io/androiddrew/learning_sse -go 1.21.0 +go 1.24.1 diff --git a/main.go b/main.go index 51b04e7..362f853 100644 --- a/main.go +++ b/main.go @@ -3,14 +3,39 @@ package main import ( "context" "fmt" - "io" + "html/template" + + //"io" "log/slog" "net/http" - "os" + + //"os" "strings" "time" ) +func IndexHandler(w http.ResponseWriter, r *http.Request) { + + files := []string{ + "./ui/html/base.go.tmpl", + "./ui/html/index.go.tmpl", + } + + ts, err := template.ParseFiles(files...) + if err != nil { + slog.Error("error parsing files", "error", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + err = ts.ExecuteTemplate(w, "base", nil) + if err != nil { + slog.Error("error executing template", "error", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } +} + func SSEHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/event-stream") @@ -23,26 +48,31 @@ func SSEHandler(w http.ResponseWriter, r *http.Request) { } func routes() http.Handler { - // TODO add static server and an HTML index with `new EventSource` JS that writes the data message contents into an element on the page + fileServer := http.FileServer(http.Dir("./ui/static/")) mux := http.NewServeMux() - mux.HandleFunc("/sse", SSEHandler) + mux.Handle("GET /static/", http.StripPrefix("/static", fileServer)) + mux.HandleFunc("GET /sse", SSEHandler) + mux.HandleFunc("GET /{$}", IndexHandler) return mux } -func run(ctx context.Context, w io.Writer, args []string) error { +// TODO add args slice and process flags +// TODO add io.Writer and pass that to the logger +func run(ctx context.Context) error { addr := fmt.Sprintf("%s:%d", "0.0.0.0", 8888) srv := &http.Server{ Addr: addr, Handler: routes(), } - slog.Info("Listing on: http://0.0.0.0:8888") + slog.Info("Listing on: http://0.0.0.0:8888/") return srv.ListenAndServe() } func main() { ctx := context.Background() - if err := run(ctx, os.Stdout, os.Args); err != nil { + // TODO add os.Args + if err := run(ctx); err != nil { slog.Error("an error occurred", "error", err) } } diff --git a/ui/html/base.go.tmpl b/ui/html/base.go.tmpl index 299f4f9..4a17d65 100644 --- a/ui/html/base.go.tmpl +++ b/ui/html/base.go.tmpl @@ -4,8 +4,8 @@ {{template "title" .}} - - + +
@@ -18,4 +18,4 @@
Powered By Go in {{ .CurrentYear }}
-{{ end }} \ No newline at end of file +{{ end }} diff --git a/ui/html/index.go.tmpl b/ui/html/index.go.tmpl index d80126b..d47db45 100644 --- a/ui/html/index.go.tmpl +++ b/ui/html/index.go.tmpl @@ -1,6 +1,5 @@ {{define "title"}}SSE Example{{end}} -{{define "main"-}} -

SSE Content

+{{define "main"}}

-{{end}} \ No newline at end of file +{{end}} diff --git a/ui/static/css/main.css b/ui/static/css/main.css index e69de29..5bc879c 100644 --- a/ui/static/css/main.css +++ b/ui/static/css/main.css @@ -0,0 +1,4 @@ +body { + background-color: slategrey; + text-align: center; +} diff --git a/ui/static/js/main.js b/ui/static/js/main.js index e69de29..e7cd0d2 100644 --- a/ui/static/js/main.js +++ b/ui/static/js/main.js @@ -0,0 +1,8 @@ +const evtSource = new EventSource("/sse"); + + +let content = document.getElementById("stuff") + +evtSource.onmessage = (event) => { + content.innerHTML += event.data + ' '; +}; \ No newline at end of file