mirror of
https://github.com/raseels-repos/golang-saas-starter-kit.git
synced 2025-06-06 23:46:29 +02:00
91 lines
2.4 KiB
Go
91 lines
2.4 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/dimfeld/httptreemux"
|
|
)
|
|
|
|
// ctxKey represents the type of value for the context key.
|
|
type ctxKey int
|
|
|
|
// KeyValues is how request values or stored/retrieved.
|
|
const KeyValues ctxKey = 1
|
|
|
|
// Values represent state for each request.
|
|
type Values struct {
|
|
Now time.Time
|
|
TraceID uint64
|
|
SpanID uint64
|
|
StatusCode int
|
|
}
|
|
|
|
// A Handler is a type that handles an http request within our own little mini
|
|
// framework.
|
|
type Handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error
|
|
|
|
// App is the entrypoint into our application and what configures our context
|
|
// object for each of our http handlers. Feel free to add any configuration
|
|
// data/logic on this App struct
|
|
type App struct {
|
|
*httptreemux.TreeMux
|
|
shutdown chan os.Signal
|
|
log *log.Logger
|
|
mw []Middleware
|
|
}
|
|
|
|
// NewApp creates an App value that handle a set of routes for the application.
|
|
func NewApp(shutdown chan os.Signal, log *log.Logger, mw ...Middleware) *App {
|
|
app := App{
|
|
TreeMux: httptreemux.New(),
|
|
shutdown: shutdown,
|
|
log: log,
|
|
mw: mw,
|
|
}
|
|
|
|
return &app
|
|
}
|
|
|
|
// SignalShutdown is used to gracefully shutdown the app when an integrity
|
|
// issue is identified.
|
|
func (a *App) SignalShutdown() {
|
|
a.log.Println("error returned from handler indicated integrity issue, shutting down service")
|
|
a.shutdown <- syscall.SIGSTOP
|
|
}
|
|
|
|
// Handle is our mechanism for mounting Handlers for a given HTTP verb and path
|
|
// pair, this makes for really easy, convenient routing.
|
|
func (a *App) Handle(verb, path string, handler Handler, mw ...Middleware) {
|
|
|
|
// First wrap handler specific middleware around this handler.
|
|
handler = wrapMiddleware(mw, handler)
|
|
|
|
// Add the application's general middleware to the handler chain.
|
|
handler = wrapMiddleware(a.mw, handler)
|
|
|
|
// The function to execute for each request.
|
|
h := func(w http.ResponseWriter, r *http.Request, params map[string]string) {
|
|
// Set the context with the required values to
|
|
// process the request.
|
|
v := Values{
|
|
Now: time.Now(),
|
|
}
|
|
ctx := context.WithValue(r.Context(), KeyValues, &v)
|
|
|
|
// Call the wrapped handler functions.
|
|
if err := handler(ctx, w, r, params); err != nil {
|
|
a.log.Printf("*****> critical shutdown error: %v", err)
|
|
a.SignalShutdown()
|
|
return
|
|
}
|
|
}
|
|
|
|
// Add this handler for the specified verb and route.
|
|
a.TreeMux.Handle(verb, path, h)
|
|
}
|