From c76886699130133d6e0f8205047419cdb6f38e32 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 28 Sep 2020 01:26:16 -0600 Subject: [PATCH] static server with basic options --- .gitignore | 2 + README.md | 11 ++++ assets/assets.go | 4 ++ assets/assets_dev.go | 8 +++ go.mod | 10 ++++ go.sum | 28 +++++++++ main.go | 131 +++++++++++++++++++++++++++++++++++++++++++ public/index.html | 1 + tools/tools.go | 10 ++++ 9 files changed, 205 insertions(+) create mode 100644 assets/assets.go create mode 100644 assets/assets_dev.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 public/index.html create mode 100644 tools/tools.go diff --git a/.gitignore b/.gitignore index 5e2df66..ce640d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/goserv + *_vfsdata.go *.env .env diff --git a/README.md b/README.md index e4d9287..3774d95 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ # goserv > Boilerplate for how I like to write a backend web service + +```bash +go mod tidy +go mod vendor +go generate -mod=vendor ./... +go build -mod=vendor . +``` + +```bash +./goserv run --listen :3000 --serve-path ./overrides +``` diff --git a/assets/assets.go b/assets/assets.go new file mode 100644 index 0000000..8d82144 --- /dev/null +++ b/assets/assets.go @@ -0,0 +1,4 @@ +// +build !dev +//go:generate go run -mod vendor github.com/shurcooL/vfsgen/cmd/vfsgendev -source="git.coolaj86.com/coolaj86/goserv/assets".Assets + +package assets diff --git a/assets/assets_dev.go b/assets/assets_dev.go new file mode 100644 index 0000000..bb152d1 --- /dev/null +++ b/assets/assets_dev.go @@ -0,0 +1,8 @@ +// +build dev + +package assets + +import "net/http" + +// Assets is the public file system which should be served by http +var Assets http.FileSystem = http.Dir("../public") diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..99feffa --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module git.coolaj86.com/coolaj86/goserv + +go 1.15 + +require ( + github.com/go-chi/chi v4.1.2+incompatible + github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect + github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 + golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2a52997 --- /dev/null +++ b/go.sum @@ -0,0 +1,28 @@ +github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= +github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 h1:hzJjkvxUIF3bSt+v8N5tBQNx/605vszZJ+3XsIamzZo= +golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/main.go b/main.go new file mode 100644 index 0000000..f8e63ed --- /dev/null +++ b/main.go @@ -0,0 +1,131 @@ +package main + +import ( + "compress/flate" + "flag" + "fmt" + "net/http" + "os" + + "git.coolaj86.com/coolaj86/goserv/assets" + "github.com/go-chi/chi" + "github.com/go-chi/chi/middleware" +) + +var ( + name = "goserv" + version = "0.0.0" + date = "0001-01-01T00:00:00Z" + commit = "0000000" +) + +func usage() { + ver() + fmt.Println("") + fmt.Println("Use 'help '") + fmt.Println(" help") + fmt.Println(" init") + fmt.Println(" run") +} + +func ver() { + fmt.Printf("%s v%s %s (%s)\n", name, version, commit[:7], date) +} + +type runOptions struct { + listen string + trustProxy bool + compress bool + static string +} + +var runFlags *flag.FlagSet +var runOpts runOptions +var initFlags *flag.FlagSet + +func init() { + runOpts = runOptions{} + runFlags = flag.NewFlagSet("run", flag.ExitOnError) + runFlags.StringVar(&runOpts.listen, "listen", ":3000", "the address and port on which to listen") + runFlags.BoolVar(&runOpts.trustProxy, "trust-proxy", false, "trust X-Forwarded-For header") + runFlags.BoolVar(&runOpts.compress, "compress", true, "enable compression for text,html,js,css,etc") + runFlags.StringVar(&runOpts.static, "serve-path", "", "path to serve, falls back to built-in web app") +} + +func main() { + args := os.Args[:] + if 1 == len(args) { + // "run" should be the default + args = append(args, "run") + } + + if "help" == args[1] { + // top-level help + if 2 == len(args) { + usage() + os.Exit(0) + return + } + // move help to subcommand argument + self := args[0] + args = append([]string{self}, args[2:]...) + args = append(args, "--help") + } + + switch args[1] { + case "version": + ver() + os.Exit(0) + return + case "init": + initFlags.Parse(args[2:]) + case "run": + runFlags.Parse(args[2:]) + serve() + default: + usage() + os.Exit(1) + return + } +} + +func serve() { + r := chi.NewRouter() + + // A good base middleware stack + if runOpts.trustProxy { + r.Use(middleware.RealIP) + } + if runOpts.compress { + r.Use(middleware.Compress(flate.DefaultCompression)) + } + r.Use(middleware.Logger) + r.Use(middleware.Recoverer) + + pub := http.FileServer(assets.Assets) + + var dev http.Handler + var devFS http.FileSystem + if len(runOpts.static) > 0 { + devFS = http.Dir(runOpts.static) + dev = http.FileServer(devFS) + r.Get("/*", func(w http.ResponseWriter, r *http.Request) { + if _, err := devFS.Open(r.URL.Path); nil != err { + pub.ServeHTTP(w, r) + return + } + dev.ServeHTTP(w, r) + }) + } else { + r.Get("/*", func(w http.ResponseWriter, r *http.Request) { + pub.ServeHTTP(w, r) + }) + } + + fmt.Println("Listening for http on", runOpts.listen) + if err := http.ListenAndServe(runOpts.listen, r); nil != err { + fmt.Fprintf(os.Stderr, "%s", err) + os.Exit(1) + return + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..8ab686e --- /dev/null +++ b/public/index.html @@ -0,0 +1 @@ +Hello, World! diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..1b28f7c --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,10 @@ +// +build tools + +// Package tools is a faux package for tracking dependencies that don't make it into the code +package tools + +import ( + // these are 'go generate' tooling dependencies, not including in the binary + _ "github.com/shurcooL/vfsgen" + _ "github.com/shurcooL/vfsgen/cmd/vfsgendev" +)