Files
go-tower/tower.go

141 lines
3.4 KiB
Go

package tower
import (
"context"
"io/fs"
"log"
"net/http"
"path"
"github.com/julienschmidt/httprouter"
)
type Tower struct {
router *httprouter.Router
errorHandler ErrorHandler
globalMiddlewares []Middleware
server *http.Server
}
func New() *Tower {
t := &Tower{
router: httprouter.New(),
errorHandler: defaultErrorHandler,
globalMiddlewares: []Middleware{},
}
t.server = &http.Server{
Handler: t.router,
}
return t
}
func (t *Tower) Start(listenAddr string) error {
t.server.Addr = listenAddr
return t.server.ListenAndServe()
}
func (t *Tower) StartTLS(listenAddr, certFile, keyFile string) error {
t.server.Addr = listenAddr
return t.server.ListenAndServeTLS(certFile, keyFile)
}
func (t *Tower) Shutdown(ctx context.Context) error {
return t.server.Shutdown(ctx)
}
func (t *Tower) SetErrorHandler(errorHandler ErrorHandler) {
t.errorHandler = errorHandler
}
func (t *Tower) Use(globalMiddlewares ...Middleware) {
t.globalMiddlewares = append(t.globalMiddlewares, globalMiddlewares...)
}
func (t *Tower) Group(prefix string, groupMiddlewares ...Middleware) *Group {
return &Group{
prefix: normalizePath(prefix),
parent: t,
groupMiddlewares: groupMiddlewares,
}
}
func (t *Tower) Static(prefix, dir string) {
prefix = normalizePath(prefix)
prefix += "/*filepath"
t.router.ServeFiles(prefix, http.Dir(dir))
}
func (t *Tower) StaticFS(prefix string, fsys fs.FS) {
fileServer := http.FileServer(http.FS(fsys))
handler := func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
fp := p.ByName("filepath")
if fp == "" {
fp = "/"
}
fp = path.Clean("/" + fp)
req := r.Clone(r.Context())
req.URL.Path = fp
fileServer.ServeHTTP(w, req)
}
t.router.Handle(http.MethodGet, buildFullPath(prefix, "/*filepath"), handler)
t.router.Handle(http.MethodHead, buildFullPath(prefix, "/*filepath"), handler)
}
func (t *Tower) GET(path string, h Handler, routeMiddlewares ...Middleware) {
t.Handle(http.MethodGet, path, h, routeMiddlewares...)
}
func (t *Tower) POST(path string, h Handler, routeMiddlewares ...Middleware) {
t.Handle(http.MethodPost, path, h, routeMiddlewares...)
}
func (t *Tower) PUT(path string, h Handler, routeMiddlewares ...Middleware) {
t.Handle(http.MethodPut, path, h, routeMiddlewares...)
}
func (t *Tower) PATCH(path string, h Handler, routeMiddlewares ...Middleware) {
t.Handle(http.MethodPatch, path, h, routeMiddlewares...)
}
func (t *Tower) DELETE(path string, h Handler, routeMiddlewares ...Middleware) {
t.Handle(http.MethodDelete, path, h, routeMiddlewares...)
}
func (t *Tower) Handle(method string, path string, h Handler, routeMiddlewares ...Middleware) {
t.router.Handle(method, path, t.buildHTTPRouterHandle(h, routeMiddlewares...))
}
func (t *Tower) buildHTTPRouterHandle(h Handler, routeMiddlewares ...Middleware) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
ctx := Context{
request: r,
response: &responseWriter{ResponseWriter: w},
params: p,
}
wrappedHandler := h
for i := len(routeMiddlewares) - 1; i >= 0; i-- {
wrappedHandler = routeMiddlewares[i](wrappedHandler)
}
for i := len(t.globalMiddlewares) - 1; i >= 0; i-- {
wrappedHandler = t.globalMiddlewares[i](wrappedHandler)
}
if err := wrappedHandler(&ctx); err != nil {
if err := t.errorHandler(&ctx, err); err != nil {
log.Printf("[Error] %v", err)
}
}
}
}