package common import ( "context" "fmt" "io" "net/http" "sync" "git.optclblast.xyz/draincloud/draincloud-core/internal/logger" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" "github.com/google/uuid" ) type RequestPool struct { sp sync.Pool } func (p *RequestPool) Get() *Request { r, _ := p.sp.Get().(*Request) return r } func (p *RequestPool) Put(r *Request) { r.ID = "" r.Metadata = &sync.Map{} r.ResolveValues = &sync.Map{} r.Session = nil r.User = nil r.Body = nil p.sp.Put(r) } func NewRequestPool() *RequestPool { return &RequestPool{ sp: sync.Pool{ New: func() any { return &Request{ ResolveValues: &sync.Map{}, Metadata: &sync.Map{}, } }, }, } } type Request struct { ID string Session *models.Session User *models.User // ResolveValues - data required to process request. ResolveValues *sync.Map // Metadata - an additional data, usually added with preprocessing. Metadata *sync.Map // Request body Body []byte RawReq *http.Request } // NewRequestFromHttp builds a new *Request struct from raw http Request. No auth data validated. func NewRequestFromHttp(pool *RequestPool, req *http.Request) *Request { out := pool.sp.Get().(*Request) cookies := req.Cookies() headers := req.Header out.Metadata = &sync.Map{} out.RawReq = req for _, cookie := range cookies { out.Metadata.Store(cookie.Name, cookie.Value) } for hname, hval := range headers { out.Metadata.Store(hname, hval) } body, err := io.ReadAll(req.Body) if err != nil { logger.Error(context.TODO(), "failed to read request body", logger.Err(err)) } out.Body = body reqID := uuid.NewString() out.ID = reqID return out } func GetValue[T any](vals *sync.Map, key string) (T, error) { var out T if vals == nil { return out, fmt.Errorf("nil vals map") } rawVal, ok := vals.Load(key) if !ok { return out, fmt.Errorf("value not found in resolve values set") } out, ok = rawVal.(T) if !ok { return out, fmt.Errorf("type of a value is unexpected") } return out, nil }