commit 70507a82b398a79c522f54f04dc1a7fd4cd49877 Author: tamsin johnson Date: Sat Feb 24 12:39:58 2024 -0800 bootstrap a go application planning to make this some kind of unhinged microfrontend hotwired mess. this is basically the setup walked through in "Lets Go", but pared down. since we plan to ship this in k8s behind nginx and cert-manager, there's no need to do TLS termination in go. i like httprouter and alice, so i'm including them here early. use `go:embed` to get our templates and static assets (neither of which exist yet) into the binary so we can ship this whole thing to a commodity `go` container. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..92d354c --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +replication.systems +=================== + +it's a [`go`][golang] + [`hotwire`][hotwire] mess! + +[wtf.replication.tech][wtf] +--------------------------- + +TK: planning to put some stuff about how this made and deployed at the above +address. + + +[golang]: https://go.dev/ +[hotwire]: https://hotwired.dev/ +[wtf]: wtf.replication.tech diff --git a/cmd/web/handlers.go b/cmd/web/handlers.go new file mode 100644 index 0000000..476bc7d --- /dev/null +++ b/cmd/web/handlers.go @@ -0,0 +1,15 @@ +package main + +import ( + "net/http" +) + +// home ... +func (app *application) home(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.NotFound(w, r) + return + } + + w.Write([]byte("Hello from replication.systems")) +} diff --git a/cmd/web/logger.go b/cmd/web/logger.go new file mode 100644 index 0000000..f466c00 --- /dev/null +++ b/cmd/web/logger.go @@ -0,0 +1,26 @@ +package main + +import ( + "log/slog" + "os" +) + +// loggerBuilder ... +func loggerBuilder(logfmt *string, loglevel *string) *slog.Logger { + var logger *slog.Logger + var handler_options slog.HandlerOptions + + switch *loglevel { + case "DEBUG": handler_options = slog.HandlerOptions{Level: slog.LevelDebug} + case "INFO": handler_options = slog.HandlerOptions{Level: slog.LevelInfo} + case "WARN": handler_options = slog.HandlerOptions{Level: slog.LevelWarn} + case "ERROR": handler_options = slog.HandlerOptions{Level: slog.LevelError} + } + + switch *logfmt { + case "json": logger = slog.New(slog.NewJSONHandler(os.Stdout, &handler_options)) + default: logger = slog.New(slog.NewTextHandler(os.Stdout, &handler_options)) + } + + return logger +} diff --git a/cmd/web/main.go b/cmd/web/main.go new file mode 100644 index 0000000..5bfe849 --- /dev/null +++ b/cmd/web/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "flag" + "log/slog" + "net/http" + "os" + "time" +) + +type application struct { + logger *slog.Logger +} + +// main run the webserverrrrr +func main() { + // configuration + addr := flag.String("addr", ":4000", "HTTP network address") + logfmt := flag.String("logfmt", "text", "Log output format") + loglevel := flag.String("loglevel", "INFO", "Log level: DEBUG, INFO, WARN, or ERROR") + flag.Parse() + + // setup the application + app := &application{ + logger: loggerBuilder(logfmt, loglevel), + } + + + srv := &http.Server{ + Addr: *addr, + Handler: app.routes(), + ErrorLog: slog.NewLogLogger(app.logger.Handler(), slog.LevelError), + IdleTimeout: time.Minute, + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + } + + app.logger.Info("starting server", slog.String("addr", *addr)) + + err := srv.ListenAndServe() + + app.logger.Error(err.Error()) + os.Exit(1) +} diff --git a/cmd/web/routes.go b/cmd/web/routes.go new file mode 100644 index 0000000..ed8b9ce --- /dev/null +++ b/cmd/web/routes.go @@ -0,0 +1,25 @@ +package main + +import ( + "net/http" + + "github.com/julienschmidt/httprouter" + "github.com/justinas/alice" + + "replication-systems.estradiol.cloud/ui" +) + +// routes ... +func (app *application) routes() http.Handler { + router := httprouter.New() + + // setup server for static files + fileServer := http.FileServer(http.FS(ui.Files)) + router.Handler(http.MethodGet, "/static/*filepath", fileServer) + + router.HandlerFunc(http.MethodGet, "/", app.home) + + standard := alice.New() + + return standard.Then(router) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e2be010 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module replication-systems.estradiol.cloud + +go 1.21.4 + +require ( + github.com/julienschmidt/httprouter v1.3.0 + github.com/justinas/alice v1.2.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bdc18c1 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= +github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= diff --git a/ui/efs.go b/ui/efs.go new file mode 100644 index 0000000..9acafcd --- /dev/null +++ b/ui/efs.go @@ -0,0 +1,8 @@ +package ui + +import ( + "embed" +) + +//go:embed "html" "static" +var Files embed.FS diff --git a/ui/html/base.tmpl b/ui/html/base.tmpl new file mode 100644 index 0000000..e69de29 diff --git a/ui/static/index.html b/ui/static/index.html new file mode 100644 index 0000000..e69de29