

$ make migration name=create_example_table

run:
go run ./cmd/api
psql:
psql ${GREENLIGHT_DB_DSN}
migration:
@echo 'Creating migration files for ${name}...'
migrate create -seq -ext=.sql -dir=./migrations ${name}
up:
@echo 'Running up migrations...'
migrate -path ./migrations -database ${GREENLIGHT_DB_DSN} up

run/api:
go run ./cmd/api
db/psql:
psql ${GREENLIGHT_DB_DSN}
db/migrations/new:
@echo 'Creating migration files for ${name}...'
migrate create -seq -ext=.sql -dir=./migrations ${name}
db/migrations/up:
@echo 'Running up migrations...'
migrate -path ./migrations -database ${GREENLIGHT_DB_DSN} up



# Create the new confirm target.
confirm:
@echo -n 'Are you sure? [y/N] ' && read ans && [ $${ans:-N} = y ]
# Include it as prerequisite.
db/migrations/up: confirm
@echo 'Running up migrations...'
migrate -path ./migrations -database ${GREENLIGHT_DB_DSN} up


## help: print this help message
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
confirm:
@echo -n 'Are you sure? [y/N] ' && read ans && [ $${ans:-N} = y ]
## run/api: run the cmd/api application
run/api:
go run ./cmd/api
## db/psql: connect to the database using psql
db/psql:
psql ${GREENLIGHT_DB_DSN}
## db/migrations/new name=$1: create a new database migration
db/migrations/new:
@echo 'Creating migration files for ${name}...'
migrate create -seq -ext=.sql -dir=./migrations ${name}
## db/migrations/up: apply all up database migrations
db/migrations/up: confirm
@echo 'Running up migrations...'
migrate -path ./migrations -database ${GREENLIGHT_DB_DSN} up




## help: print this help message
.PHONY: help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
.PHONY: confirm:
@echo -n 'Are you sure? [y/N] ' && read ans && [ $${ans:-N} = y ]
## run/api: run the cmd/api application
.PHONY: run/api:
go run ./cmd/api
## db/psql: connect to the database using psql
.PHONY: db/psql:
psql ${GREENLIGHT_DB_DSN}
## db/migrations/new name=$1: create a new database migration
.PHONY: db/migrations/new:
@echo 'Creating migration files for ${name}...'
migrate create -seq -ext=.sql -dir=./migrations ${name}
## db/migrations/up: apply all up database migrations
.PHONY: db/migrations/up: confirm
@echo 'Running up migrations...'
migrate -path ./migrations -database ${GREENLIGHT_DB_DSN} up






zzh@ZZHPC:/zdata/Github/greenlight$ go install honnef.co/go/tools/cmd/staticcheck@latest zzh@ZZHPC:/zdata/Github/greenlight$ which staticcheck /home/zzh/.goenv/shims/staticcheck
The /home/zzh/.goenv/shims/staticcheck was installed by goenv.

The staticcheck installed by the above 'go install' command is here:
zzh@ZZHPC:~/.goenv/shims$ go env GOPATH /home/zzh/go/1.23.0 zzh@ZZHPC:~/.goenv/shims$ cd /home/zzh/go/1.23.0/bin zzh@ZZHPC:~/go/1.23.0/bin$ lh staticcheck -rwxrwxr-x 1 zzh zzh 14M Nov 29 18:41 staticcheck
# ==================================================================================== # # QUALITY CONTROL # ==================================================================================== # ## tidy: format all .go files and tidy module dependencies # @echo 'Formatting .go files ...' # go fmt ./... tidy: @echo 'Tidying module dependencies ...' go mod tidy ## audit: run quality control checks audit: @echo 'Checking module dependencies' go mod tidy -diff go mod verify @echo 'Vetting code ...' go vet ./... staticcheck ./... @echo 'Running tests ...' go test -race -vet=off ./... .PHONY: tidy audit
zzh@ZZHPC:~/zd/Github/greenlight$ make tidy Tidying module dependencies ... go mod tidy zzh@ZZHPC:~/zd/Github/greenlight$ make audit Checking module dependencies go mod tidy -diff go mod verify all modules verified Vetting code ... go vet ./... staticcheck ./... Running tests ... go test -race -vet=off ./... ? greenlight.zzh.net/cmd/api [no test files] ? greenlight.zzh.net/cmd/examples/cors/preflight [no test files] ? greenlight.zzh.net/cmd/examples/cors/simple [no test files] ? greenlight.zzh.net/internal/config [no test files] ? greenlight.zzh.net/internal/data [no test files] ? greenlight.zzh.net/internal/mail [no test files] ? greenlight.zzh.net/internal/validator [no test files]

zzh@ZZHPC:~/zd/Github/greenlight$ go env GO111MODULE='on' GOARCH='amd64' GOBIN='' GOCACHE='/home/zzh/.cache/go-build' GOENV='/home/zzh/.config/go/env' GOEXE='' GOEXPERIMENT='' GOFLAGS='' GOHOSTARCH='amd64' GOHOSTOS='linux' GOINSECURE='' GOMODCACHE='/home/zzh/go/1.23.0/pkg/mod' GONOPROXY='' GONOSUMDB='' GOOS='linux' GOPATH='/home/zzh/go/1.23.0' GOPRIVATE='' GOPROXY='https://goproxy.io,direct' GOROOT='/home/zzh/.goenv/versions/1.23.0' GOSUMDB='sum.golang.org' GOTMPDIR='' GOTOOLCHAIN='auto' GOTOOLDIR='/home/zzh/.goenv/versions/1.23.0/pkg/tool/linux_amd64' GOVCS='' GOVERSION='go1.23.0' GODEBUG='' GOTELEMETRY='local' GOTELEMETRYDIR='/home/zzh/.config/go/telemetry' GCCGO='gccgo' GOAMD64='v1' AR='ar' CC='gcc' CXX='g++' CGO_ENABLED='1' GOMOD='/home/zzh/zd/Github/greenlight/go.mod' GOWORK='/home/zzh/zd/Github/go.work' CGO_CFLAGS='-O2 -g' CGO_CPPFLAGS='' CGO_CXXFLAGS='-O2 -g' CGO_FFLAGS='-O2 -g' CGO_LDFLAGS='-O2 -g' PKG_CONFIG='pkg-config' GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build506883647=/tmp/go-build -gno-record-gcc-switches'





## tidy: format all .go files and tidy module dependencies # @echo 'Formatting .go files ...' # go fmt ./... tidy: @echo 'Tidying module dependencies ...' go mod tidy @echo 'Verifying and vendoring module dependencies ...' go mod verify go mod vendor







func (app *application) rateLimit(next http.Handler) http.Handler { type client struct { limiter *rate.Limiter lastSeen time.Time } var ( mu sync.Mutex clients = make(map[string]*client) ) // Launch a background goroutine which removes old entries from the clients map // once every minute. go func() { for { time.Sleep(time.Minute) mu.Lock() for ip, client := range clients { if time.Since(client.lastSeen) > 3*time.Minute { delete(clients, ip) } } mu.Unlock() } }() return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if app.config.limiter.Enabled { // Use the realip.FromRequest() function to ge the client's real IP address. ip := realip.FromRequest(r) mu.Lock() if _, found := clients[ip]; !found { clients[ip] = &client{ limiter: rate.NewLimiter(rate.Limit(app.config.limiter.Rps), app.config.limiter.Burst), } } clients[ip].lastSeen = time.Now() if !clients[ip].limiter.Allow() { mu.Unlock() app.rateLimitExceededResponse(w, r) return } mu.Unlock() } next.ServeHTTP(w, r) }) }

due to any problems that might exist within those vendored packages.

# ==================================================================================== # # BUILD # ==================================================================================== # ## build/api: build the cmd/api application build/api: @echo 'Building cmd/api ...' go build -o=./bin/api ./cmd/api
zzh@ZZHPC:~/zd/Github/greenlight$ make build/api Building cmd/api ... go build -o=./bin/api ./cmd/api zzh@ZZHPC:~/zd/Github/greenlight$ ./bin/api time=2024-11-30T12:08:43.077+08:00 level=INFO msg="database connection pool established" time=2024-11-30T12:08:43.077+08:00 level=INFO msg="starting server" addr=:4000 env=development

zzh@ZZHPC:~/zd/Github/greenlight$ lh bin/api -rwxrwxr-x 1 zzh zzh 19M Nov 30 12:08 bin/api

build/api: @echo 'Building cmd/api ...' go build -ldflags='-s' -o=./bin/api ./cmd/api
zzh@ZZHPC:~/zd/Github/greenlight$ make build/api Building cmd/api ... go build -ldflags='-s' -o=./bin/api ./cmd/api zzh@ZZHPC:~/zd/Github/greenlight$ lh bin/api -rwxrwxr-x 1 zzh zzh 13M Nov 30 12:15 bin/api


zzh@ZZHPC:~/zd/Github/greenlight$ go tool dist list aix/ppc64 android/386 android/amd64 android/arm android/arm64 darwin/amd64 darwin/arm64 dragonfly/amd64 freebsd/386 freebsd/amd64 freebsd/arm freebsd/arm64 freebsd/riscv64 illumos/amd64 ios/amd64 ios/arm64 js/wasm linux/386 linux/amd64 linux/arm linux/arm64 linux/loong64 linux/mips linux/mips64 linux/mips64le linux/mipsle linux/ppc64 linux/ppc64le linux/riscv64 linux/s390x netbsd/386 netbsd/amd64 netbsd/arm netbsd/arm64 openbsd/386 openbsd/amd64 openbsd/arm openbsd/arm64 openbsd/ppc64 openbsd/riscv64 plan9/386 plan9/amd64 plan9/arm solaris/amd64 wasip1/wasm windows/386 windows/amd64 windows/arm windows/arm64




zzh@ZZHPC:~/zd/Github/greenlight$ go env GOCACHE /home/zzh/.cache/go-build


zzh@ZZHPC:~/zd/Github/greenlight$ make build/api Building cmd/api ... go build -ldflags='-s' -o=./bin/api ./cmd/api zzh@ZZHPC:~/zd/Github/greenlight$ ./bin/api -version Version: 1.0.0

zzh@ZZHPC:~/zd/Github/greenlight$ go version -m ./bin/api
./bin/api: go1.23.0
path greenlight.zzh.net/cmd/api
mod greenlight.zzh.net (devel)
dep github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
dep github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
dep github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
dep github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
dep github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
dep github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
dep github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
dep github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
dep github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
dep github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
dep github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
dep github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
dep github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
dep github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
dep github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
dep github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
dep github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
dep github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
dep golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
dep golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
dep golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
dep golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
dep golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
dep gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
dep gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
build -buildmode=exe
build -compiler=gc
build -ldflags=-s
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1
build vcs=git
build vcs.revision=2b72058b2f98710bbd13cba86a60a30f95cc0ab5
build vcs.time=2024-11-29T06:43:10Z
build vcs.modified=true



package vcs import ( "fmt" "runtime/debug" ) // Version returns the vcs.revision of the build, adding a '-dirty' suffix // if the vcs.modified is true. func Version() string { var revision string var modified bool bi, ok := debug.ReadBuildInfo() if ok { for _, s := range bi.Settings { switch s.Key { case "vcs.revision": revision = s.Value case "vcs.modified": modified = true } } } if modified { return fmt.Sprintf("%s-dirty", revision) } return revision }

... var version = vcs.Version() ... func main() { ...
zzh@ZZHPC:~/zd/Github/greenlight$ make build/api Building cmd/api ... go build -ldflags='-s' -o=./bin/api ./cmd/api zzh@ZZHPC:~/zd/Github/greenlight$ ./bin/api -version Version: 2b72058b2f98710bbd13cba86a60a30f95cc0ab5-dirty


package vcs import ( "fmt" "runtime/debug" ) // Version returns the vcs.revision of the build, adding a '-dirty' suffix // if the vcs.modified is true. func Version() string { var ( time string revision string modified bool ) bi, ok := debug.ReadBuildInfo() if ok { for _, s := range bi.Settings { switch s.Key { case "vcs.time": time = s.Value case "vcs.revision": revision = s.Value case "vcs.modified": if s.Value == "true" { modified = true } } } } if modified { return fmt.Sprintf("%s-%s-dirty", time, revision) } return fmt.Sprintf("%s-%s", time, revision) }
zzh@ZZHPC:~/zd/Github/greenlight$ make build/api Building cmd/api ... go build -ldflags='-s' -o=./bin/api ./cmd/api zzh@ZZHPC:~/zd/Github/greenlight$ ./bin/api -version Version: 2024-11-29T06:43:10Z-2b72058b2f98710bbd13cba86a60a30f95cc0ab5-dirty



浙公网安备 33010602011771号