mirror of
https://github.com/foomo/sesamy-go.git
synced 2025-10-16 12:35:43 +00:00
197 lines
4.7 KiB
Go
197 lines
4.7 KiB
Go
package collect
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/foomo/sesamy-go/pkg/encoding/gtag"
|
|
"github.com/foomo/sesamy-go/pkg/encoding/mpv2"
|
|
gtaghttp "github.com/foomo/sesamy-go/pkg/http/gtag"
|
|
mpv2http "github.com/foomo/sesamy-go/pkg/http/mpv2"
|
|
"github.com/pkg/errors"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type (
|
|
Collect struct {
|
|
l *zap.Logger
|
|
taggingURL string
|
|
taggingClient *http.Client
|
|
gtagHTTPMiddlewares []gtaghttp.Middleware
|
|
mpv2HTTPMiddlewares []mpv2http.Middleware
|
|
}
|
|
Option func(*Collect) error
|
|
)
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ~ Options
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
func WithTagging(v string) Option {
|
|
return func(c *Collect) error {
|
|
c.taggingURL = v
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func WithTaggingClient(v *http.Client) Option {
|
|
return func(c *Collect) error {
|
|
c.taggingClient = v
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func WithGTagHTTPMiddlewares(v ...gtaghttp.Middleware) Option {
|
|
return func(c *Collect) error {
|
|
c.gtagHTTPMiddlewares = append(c.gtagHTTPMiddlewares, v...)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func WithMPv2HTTPMiddlewares(v ...mpv2http.Middleware) Option {
|
|
return func(c *Collect) error {
|
|
c.mpv2HTTPMiddlewares = append(c.mpv2HTTPMiddlewares, v...)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ~ Constructor
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
func New(l *zap.Logger, opts ...Option) (*Collect, error) {
|
|
inst := &Collect{
|
|
l: l,
|
|
taggingClient: http.DefaultClient,
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
if opt != nil {
|
|
if err := opt(inst); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
|
|
return inst, nil
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ~ Public methods
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
func (c *Collect) GTagHTTPHandler(w http.ResponseWriter, r *http.Request) {
|
|
// retrieve payload
|
|
payload := gtaghttp.Handler(w, r)
|
|
if payload == nil {
|
|
http.Error(w, "failed to decode payload", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// compose middlewares
|
|
next := c.gtagHandler
|
|
for _, middleware := range c.gtagHTTPMiddlewares {
|
|
next = middleware(next)
|
|
}
|
|
|
|
// run handler
|
|
if err := next(c.l, w, r, payload); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (c *Collect) MPv2HTTPHandler(w http.ResponseWriter, r *http.Request) {
|
|
// retrieve payload
|
|
payload := mpv2http.Handler(w, r)
|
|
|
|
// compose middlewares
|
|
next := c.mpv2Handler
|
|
for _, middleware := range c.mpv2HTTPMiddlewares {
|
|
next = middleware(next)
|
|
}
|
|
|
|
// run handler
|
|
if err := next(c.l, w, r, payload); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ~ Private methods
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
func (c *Collect) gtagHandler(l *zap.Logger, w http.ResponseWriter, r *http.Request, payload *gtag.Payload) error {
|
|
values, body, err := gtag.Encode(payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(r.Context(), http.MethodPost, fmt.Sprintf("%s%s?%s", c.taggingURL, "/g/collect", gtag.EncodeValues(values)), body)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to create request")
|
|
}
|
|
|
|
// copy headers
|
|
req.Header = r.Header.Clone()
|
|
|
|
resp, err := c.taggingClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// copy headers
|
|
for key, values := range resp.Header {
|
|
for _, value := range values {
|
|
w.Header().Add(key, value)
|
|
}
|
|
}
|
|
|
|
if _, err := io.Copy(w, resp.Body); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Collect) mpv2Handler(l *zap.Logger, w http.ResponseWriter, r *http.Request, payload *mpv2.Payload[any]) error {
|
|
body, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(r.Context(), http.MethodPost, fmt.Sprintf("%s%s", c.taggingURL, "/mp/collect"), bytes.NewReader(body))
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to create request")
|
|
}
|
|
|
|
// copy headers
|
|
req.Header = r.Header.Clone()
|
|
// copy raw query
|
|
req.URL.RawQuery = r.URL.RawQuery
|
|
|
|
resp, err := c.taggingClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
// copy headers
|
|
for key, values := range resp.Header {
|
|
for _, value := range values {
|
|
w.Header().Add(key, value)
|
|
}
|
|
}
|
|
|
|
if _, err := io.Copy(w, resp.Body); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|