diff --git a/context.go b/context.go index 9015159..c603030 100644 --- a/context.go +++ b/context.go @@ -54,11 +54,7 @@ func (c *Context) Next() { } func (c *Context) prepare(ctx *Context) { - // Only parse multipart form if it hasn't been parsed already - // This prevents race conditions when multiple goroutines might access the same request - if ctx.Request.httpRequest.MultipartForm == nil { - ctx.Request.httpRequest.ParseMultipartForm(int64(app.Config.Request.MaxUploadFileSize)) - } + ctx.Request.httpRequest.ParseMultipartForm(int64(app.Config.Request.MaxUploadFileSize)) } func (c *Context) GetPathParam(key string) interface{} { diff --git a/core.go b/core.go index 9afef81..3c80602 100644 --- a/core.go +++ b/core.go @@ -6,7 +6,6 @@ package core import ( - "context" "embed" "fmt" "log" @@ -52,18 +51,12 @@ type configContainer struct { // App is a struct representing the main application container and its core components. type App struct { - t int // for tracking hooks (deprecated - maintained for backward compatibility) + t int // for tracking hooks chain *chain hooks *Hooks Config *configContainer } -// requestContext holds request-specific chain execution state -type requestContext struct { - chainIndex int - chainNodes []interface{} -} - // app is a global instance of the App structure used to manage application configuration and lifecycle. var app *App @@ -111,7 +104,7 @@ func (app *App) Run(router *httprouter.Router) { // check if template engine is enable TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") - if "" == TemplateEnableStr { + if TemplateEnableStr == "" { TemplateEnableStr = "false" } TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) @@ -120,33 +113,13 @@ func (app *App) Run(router *httprouter.Router) { router.ServeFiles("/public/*filepath", http.Dir("storage/public")) } - // check if app engine is enable - AppEnableStr := os.Getenv("APP_ENABLE") - if "" == AppEnableStr { - AppEnableStr = "false" - } - AppEnable, _ := strconv.ParseBool(AppEnableStr) - if AppEnable { - router.ServeFiles("/app/*filepath", http.Dir("storage/app")) - } - - // check if app engine is enable - CDNEnableStr := os.Getenv("CDN_ENABLE") - if "" == CDNEnableStr { - CDNEnableStr = "false" - } - CDNEnable, _ := strconv.ParseBool(CDNEnableStr) - if CDNEnable { - router.ServeFiles("/cdn/*filepath", http.Dir("storage/cdn")) - } - useHttpsStr := os.Getenv("App_USE_HTTPS") if useHttpsStr == "" { useHttpsStr = "false" } useHttps, _ := strconv.ParseBool(useHttpsStr) - if "dev" == runMode { + if runMode == "dev" { fmt.Printf("Welcome to Goffee\n") if useHttps { fmt.Printf("Listening on https \nWaiting for requests...\n") @@ -238,25 +211,10 @@ func (app *App) RegisterRoutes(routes []Route, router *httprouter.Router) *httpr // makeHTTPRouterHandlerFunc creates an httprouter.Handle that handles HTTP requests with the specified controller and hooks. func (app *App) makeHTTPRouterHandlerFunc(h Controller, ms []Hook) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - // Create request-specific chain state - reqCtx := &requestContext{ - chainIndex: 0, - } - - // Prepare the chain nodes for this request - mw := app.hooks.GetHooks() - for _, v := range mw { - reqCtx.chainNodes = append(reqCtx.chainNodes, v) - } - rhs := app.combHandlers(h, ms) - for _, v := range rhs { - reqCtx.chainNodes = append(reqCtx.chainNodes, v) - } - - // Store chain state in request context + ctx := &Context{ Request: &Request{ - httpRequest: r.WithContext(context.WithValue(r.Context(), "goffeeChain", reqCtx)), + httpRequest: r, httpPathParams: ps, }, Response: &Response{ @@ -279,16 +237,10 @@ func (app *App) makeHTTPRouterHandlerFunc(h Controller, ms []Hook) httprouter.Ha } ctx.prepare(ctx) - - // Execute the first handler in the chain - if len(reqCtx.chainNodes) > 0 { - n := reqCtx.chainNodes[0] - if f, ok := n.(Hook); ok { - f(ctx) - } else if ff, ok := n.(Controller); ok { - ff(ctx) - } - } + rhs := app.combHandlers(h, ms) + app.prepareChain(rhs) + app.t = 0 + app.chain.execute(ctx) for _, header := range ctx.Response.headers { w.Header().Add(header.key, header.val) @@ -391,30 +343,16 @@ func UseHook(mw Hook) { // Next advances to the next middleware or controller in the chain and invokes it with the given context if available. func (app *App) Next(c *Context) { - // Get request-specific chain state from context - if reqCtx, ok := c.Request.httpRequest.Context().Value("goffeeChain").(*requestContext); ok { - reqCtx.chainIndex++ - if reqCtx.chainIndex < len(reqCtx.chainNodes) { - n := reqCtx.chainNodes[reqCtx.chainIndex] - if f, ok := n.(Hook); ok { - f(c) - } else if ff, ok := n.(Controller); ok { - ff(c) - } - } - } else { - // Fallback to old behavior (not thread-safe) - app.t = app.t + 1 - n := app.chain.getByIndex(app.t) - if n != nil { - f, ok := n.(Hook) + app.t = app.t + 1 + n := app.chain.getByIndex(app.t) + if n != nil { + f, ok := n.(Hook) + if ok { + f(c) + } else { + ff, ok := n.(Controller) if ok { - f(c) - } else { - ff, ok := n.(Controller) - if ok { - ff(c) - } + ff(c) } } } @@ -452,17 +390,6 @@ func (app *App) prepareChain(hs []interface{}) { } } -// prepareRequestChain prepares a request-specific chain to avoid race conditions -func (app *App) prepareRequestChain(requestChain *chain, hs []interface{}) { - mw := app.hooks.GetHooks() - for _, v := range mw { - requestChain.nodes = append(requestChain.nodes, v) - } - for _, v := range hs { - requestChain.nodes = append(requestChain.nodes, v) - } -} - // execute executes the first node in the chain, invoking it as either a Hook or Controller if applicable. func (cn *chain) execute(ctx *Context) { i := cn.getByIndex(0) diff --git a/go.mod b/go.mod index 9a967b5..c603849 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ replace git.smarteching.com/goffee/core/logger => ./logger replace git.smarteching.com/goffee/core/env => ./env -go 1.24.1 +go 1.23.1 require ( git.smarteching.com/zeni/go-chart/v2 v2.1.4 @@ -23,10 +23,8 @@ require ( ) require ( - git.smarteching.com/zeni/go-charts/v2 v2.6.11 // indirect github.com/SparkPost/gosparkpost v0.2.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/go-chi/chi/v5 v5.0.8 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect diff --git a/go.sum b/go.sum index 9c1a556..8b77517 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ git.smarteching.com/zeni/go-chart/v2 v2.1.4 h1:pF06+F6eqJLIG8uMiTVPR5TygPGMjM/FHMzTxmu5V/Q= git.smarteching.com/zeni/go-chart/v2 v2.1.4/go.mod h1:b3ueW9h3pGGXyhkormZAvilHaG4+mQti+bMNPdQBeOQ= -git.smarteching.com/zeni/go-charts/v2 v2.6.11 h1:9udzlv3uxGXszpplfkL5IaTUrgkNj++KwhbaN1vVEqI= -git.smarteching.com/zeni/go-charts/v2 v2.6.11/go.mod h1:3OpRPSXg7Qx4zcgsmwsC9ZFB9/wAkGSbnXf1wIbHYCg= github.com/SparkPost/gosparkpost v0.2.0 h1:yzhHQT7cE+rqzd5tANNC74j+2x3lrPznqPJrxC1yR8s= github.com/SparkPost/gosparkpost v0.2.0/go.mod h1:S9WKcGeou7cbPpx0kTIgo8Q69WZvUmVeVzbD+djalJ4= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= @@ -21,8 +19,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= @@ -104,7 +100,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= diff --git a/response.go b/response.go index d6202c7..46f31ee 100644 --- a/response.go +++ b/response.go @@ -40,16 +40,6 @@ func (rs *Response) BufferFile(name string, filetype string, b bytes.Buffer) *Re return rs } -// writes the contents of a buffer to the HTTP response with specified file name and type if not terminated. -func (rs *Response) BufferInline(name string, filetype string, b bytes.Buffer) *Response { - - if rs.isTerminated == false { - rs.HttpResponseWriter.Header().Add("Content-Type", filetype) - b.WriteTo(rs.HttpResponseWriter) - } - return rs -} - // sets the response's content type to HTML and assigns the provided body as the response body if not terminated. func (rs *Response) Any(body any) *Response { if rs.isTerminated == false { diff --git a/template/components/content_list.go b/template/components/content_list.go index 62927e6..34bfb49 100644 --- a/template/components/content_list.go +++ b/template/components/content_list.go @@ -1,12 +1,10 @@ package components type ContentList struct { - ID string Items []ContentListItem } type ContentListItem struct { - ID string Text string Description string EndElement string diff --git a/template/components/content_list.html b/template/components/content_list.html index 351bcad..31af60b 100644 --- a/template/components/content_list.html +++ b/template/components/content_list.html @@ -1,10 +1,8 @@ {{define "content_list"}} -
{{.Text}}
{{.EndElement}}