diff --git a/examples/sse-with-state/.dockerignore b/examples/sse-with-state/.dockerignore new file mode 100644 index 0000000..fb47686 --- /dev/null +++ b/examples/sse-with-state/.dockerignore @@ -0,0 +1,11 @@ +# Project exclude paths +/tmp/ +node_modules/ +dist/ +js/dist +js/node_modules +go.work +go.work.sum +.idea +!framework/assets/dist +__htmgo \ No newline at end of file diff --git a/examples/sse-with-state/.gitignore b/examples/sse-with-state/.gitignore new file mode 100644 index 0000000..3d6a979 --- /dev/null +++ b/examples/sse-with-state/.gitignore @@ -0,0 +1,6 @@ +/assets/dist +tmp +node_modules +.idea +__htmgo +dist \ No newline at end of file diff --git a/examples/sse-with-state/Dockerfile b/examples/sse-with-state/Dockerfile new file mode 100644 index 0000000..a522f64 --- /dev/null +++ b/examples/sse-with-state/Dockerfile @@ -0,0 +1,38 @@ +# Stage 1: Build the Go binary +FROM golang:1.23-alpine AS builder + +RUN apk update +RUN apk add git +RUN apk add curl + +# Set the working directory inside the container +WORKDIR /app + +# Copy go.mod and go.sum files +COPY go.mod go.sum ./ + +# Download and cache the Go modules +RUN go mod download + +# Copy the source code into the container +COPY . . + +# Build the Go binary for Linux +RUN GOPRIVATE=github.com/maddalax GOPROXY=direct go run github.com/maddalax/htmgo/cli/htmgo@latest build + + +# Stage 2: Create the smallest possible image +FROM gcr.io/distroless/base-debian11 + +# Set the working directory inside the container +WORKDIR /app + +# Copy the Go binary from the builder stage +COPY --from=builder /app/dist . + +# Expose the necessary port (replace with your server port) +EXPOSE 3000 + + +# Command to run the binary +CMD ["./sse-with-state"] diff --git a/examples/sse-with-state/Taskfile.yml b/examples/sse-with-state/Taskfile.yml new file mode 100644 index 0000000..695006f --- /dev/null +++ b/examples/sse-with-state/Taskfile.yml @@ -0,0 +1,20 @@ +version: '3' + +tasks: + run: + cmds: + - go run github.com/maddalax/htmgo/cli/htmgo@latest run + silent: true + + build: + cmds: + - go run github.com/maddalax/htmgo/cli/htmgo@latest build + + docker: + cmds: + - docker build . + + watch: + cmds: + - go run github.com/maddalax/htmgo/cli/htmgo@latest watch + silent: true \ No newline at end of file diff --git a/examples/sse-with-state/assets.go b/examples/sse-with-state/assets.go new file mode 100644 index 0000000..63021d1 --- /dev/null +++ b/examples/sse-with-state/assets.go @@ -0,0 +1,13 @@ +//go:build !prod +// +build !prod + +package main + +import ( + "io/fs" + "sse-with-state/internal/embedded" +) + +func GetStaticAssets() fs.FS { + return embedded.NewOsFs() +} diff --git a/examples/sse-with-state/assets/css/input.css b/examples/sse-with-state/assets/css/input.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/examples/sse-with-state/assets/css/input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/examples/sse-with-state/assets_prod.go b/examples/sse-with-state/assets_prod.go new file mode 100644 index 0000000..f0598e1 --- /dev/null +++ b/examples/sse-with-state/assets_prod.go @@ -0,0 +1,16 @@ +//go:build prod +// +build prod + +package main + +import ( + "embed" + "io/fs" +) + +//go:embed assets/dist/* +var staticAssets embed.FS + +func GetStaticAssets() fs.FS { + return staticAssets +} diff --git a/examples/sse-with-state/go.mod b/examples/sse-with-state/go.mod new file mode 100644 index 0000000..f10fa8a --- /dev/null +++ b/examples/sse-with-state/go.mod @@ -0,0 +1,14 @@ +module sse-with-state + +go 1.23.0 + +require github.com/maddalax/htmgo/framework v0.0.0-20241006162137-150c87b4560b + +require ( + github.com/go-chi/chi/v5 v5.1.0 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.4.0 // indirect + github.com/google/uuid v1.6.0 // indirect + golang.org/x/sys v0.6.0 // indirect +) diff --git a/examples/sse-with-state/go.sum b/examples/sse-with-state/go.sum new file mode 100644 index 0000000..94d5634 --- /dev/null +++ b/examples/sse-with-state/go.sum @@ -0,0 +1,24 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= +github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/maddalax/htmgo/framework v0.0.0-20241006162137-150c87b4560b h1:LzZTNwIGe0RHiEJZlpnpN8GRnKg2lCZppMX+JIyeF/g= +github.com/maddalax/htmgo/framework v0.0.0-20241006162137-150c87b4560b/go.mod h1:HYKI49Pb6oyY2opSJdTt145B1vWgfWIDohvlolynv80= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/sse-with-state/internal/embedded/os.go b/examples/sse-with-state/internal/embedded/os.go new file mode 100644 index 0000000..ddfd55f --- /dev/null +++ b/examples/sse-with-state/internal/embedded/os.go @@ -0,0 +1,17 @@ +package embedded + +import ( + "io/fs" + "os" +) + +type OsFs struct { +} + +func (receiver OsFs) Open(name string) (fs.File, error) { + return os.Open(name) +} + +func NewOsFs() OsFs { + return OsFs{} +} diff --git a/examples/sse-with-state/internal/random.go b/examples/sse-with-state/internal/random.go new file mode 100644 index 0000000..cdd5416 --- /dev/null +++ b/examples/sse-with-state/internal/random.go @@ -0,0 +1,13 @@ +package internal + +import "math/rand" + +var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func RandSeq(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/examples/sse-with-state/main.go b/examples/sse-with-state/main.go new file mode 100644 index 0000000..3213f4f --- /dev/null +++ b/examples/sse-with-state/main.go @@ -0,0 +1,47 @@ +package main + +import ( + "encoding/json" + "github.com/maddalax/htmgo/framework/h" + "github.com/maddalax/htmgo/framework/service" + "io/fs" + "net/http" + "sse-with-state/__htmgo" + "sse-with-state/event" + "sse-with-state/sse" +) + +func main() { + locator := service.NewLocator() + + service.Set[sse.SocketManager](locator, service.Singleton, func() *sse.SocketManager { + return sse.NewSocketManager() + }) + + event.StartListener(locator) + + h.Start(h.AppOpts{ + ServiceLocator: locator, + LiveReload: true, + Register: func(app *h.App) { + sub, err := fs.Sub(GetStaticAssets(), "assets/dist") + + if err != nil { + panic(err) + } + + http.FileServerFS(sub) + + app.Router.Handle("/public/*", http.StripPrefix("/public", http.FileServerFS(sub))) + app.Router.Handle("/ws/test", sse.HandleWs()) + app.Router.Get("/metrics", func(writer http.ResponseWriter, request *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + metrics := event.GetMetrics() + serialized, _ := json.Marshal(metrics) + _, _ = writer.Write(serialized) + }) + __htmgo.Register(app.Router) + }, + }) +} diff --git a/examples/sse-with-state/tailwind.config.js b/examples/sse-with-state/tailwind.config.js new file mode 100644 index 0000000..b18125c --- /dev/null +++ b/examples/sse-with-state/tailwind.config.js @@ -0,0 +1,5 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["**/*.go"], + plugins: [], +};