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.
This commit is contained in:
commit
70507a82b3
0
.gitignore
vendored
Normal file
0
.gitignore
vendored
Normal file
15
README.md
Normal file
15
README.md
Normal file
@ -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
|
15
cmd/web/handlers.go
Normal file
15
cmd/web/handlers.go
Normal file
@ -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"))
|
||||
}
|
26
cmd/web/logger.go
Normal file
26
cmd/web/logger.go
Normal file
@ -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
|
||||
}
|
44
cmd/web/main.go
Normal file
44
cmd/web/main.go
Normal file
@ -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)
|
||||
}
|
25
cmd/web/routes.go
Normal file
25
cmd/web/routes.go
Normal file
@ -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)
|
||||
}
|
8
go.mod
Normal file
8
go.mod
Normal file
@ -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
|
||||
)
|
4
go.sum
Normal file
4
go.sum
Normal file
@ -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=
|
8
ui/efs.go
Normal file
8
ui/efs.go
Normal file
@ -0,0 +1,8 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
)
|
||||
|
||||
//go:embed "html" "static"
|
||||
var Files embed.FS
|
0
ui/html/base.tmpl
Normal file
0
ui/html/base.tmpl
Normal file
0
ui/static/index.html
Normal file
0
ui/static/index.html
Normal file
Loading…
Reference in New Issue
Block a user