static server with basic options
This commit is contained in:
parent
717a4bcbb3
commit
c768866991
|
@ -1,3 +1,5 @@
|
||||||
|
/goserv
|
||||||
|
|
||||||
*_vfsdata.go
|
*_vfsdata.go
|
||||||
*.env
|
*.env
|
||||||
.env
|
.env
|
||||||
|
|
11
README.md
11
README.md
|
@ -1,3 +1,14 @@
|
||||||
# goserv
|
# goserv
|
||||||
|
|
||||||
> Boilerplate for how I like to write a backend web service
|
> 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
|
||||||
|
```
|
||||||
|
|
|
@ -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
|
|
@ -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")
|
|
@ -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
|
||||||
|
)
|
|
@ -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=
|
|
@ -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 <command>'")
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Hello, World!
|
|
@ -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"
|
||||||
|
)
|
Loading…
Reference in New Issue