github.com/GuanceCloud/cliutils@v1.1.21/network/http/api_wrap.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 package http 7 8 import ( 9 "errors" 10 "net/http" 11 "time" 12 13 "github.com/gin-gonic/gin" 14 ) 15 16 var ( 17 ErrTooManyRequest = NewErr(errors.New("reach max API rate limit"), http.StatusTooManyRequests) 18 HTTPOK = NewErr(nil, http.StatusOK) //nolint:errname 19 EnableTracing bool 20 ) 21 22 type WrapPlugins struct { 23 Limiter APIRateLimiter 24 Reporter APIMetricReporter 25 } 26 27 type apiHandler func(http.ResponseWriter, *http.Request, ...interface{}) (interface{}, error) 28 29 func HTTPAPIWrapper(p *WrapPlugins, next apiHandler, args ...interface{}) func(*gin.Context) { 30 return func(c *gin.Context) { 31 var start time.Time 32 var m *APIMetric 33 34 if p != nil && p.Reporter != nil { 35 start = time.Now() 36 m = &APIMetric{ 37 API: c.Request.URL.Path + "@" + c.Request.Method, 38 } 39 } 40 41 if p != nil && p.Limiter != nil { 42 if p.Limiter.RequestLimited(c.Request) { 43 HttpErr(c, ErrTooManyRequest) 44 p.Limiter.LimitReadchedCallback(c.Request) 45 if m != nil { 46 m.StatusCode = ErrTooManyRequest.HttpCode 47 m.Limited = true 48 } 49 c.Abort() 50 goto feed 51 } 52 } 53 54 if res, err := next(c.Writer, c.Request, args...); err != nil { 55 HttpErr(c, err) 56 } else { 57 HTTPOK.WriteBody(c, res) 58 } 59 60 if m != nil { 61 m.StatusCode = c.Writer.Status() 62 m.Latency = time.Since(start) 63 } 64 65 feed: 66 if p != nil && m != nil { 67 p.Reporter.Report(m) 68 } 69 } 70 }