sesamy-go/pkg/collect/collect.go
Kevin Franklin Kim a58dfafaef
feat: add collect
2024-11-20 13:48:00 +01:00

188 lines
4.8 KiB
Go

package collect
import (
"net/http"
"net/http/httputil"
"net/url"
"github.com/foomo/sesamy-go/pkg/encoding/gtag"
"github.com/foomo/sesamy-go/pkg/encoding/gtagencode"
"github.com/foomo/sesamy-go/pkg/encoding/mpv2"
"github.com/foomo/sesamy-go/pkg/encoding/mpv2encode"
sesamyhttp "github.com/foomo/sesamy-go/pkg/http"
gtaghttp "github.com/foomo/sesamy-go/pkg/http/gtag"
mpv2http "github.com/foomo/sesamy-go/pkg/http/mpv2"
"github.com/foomo/sesamy-go/pkg/sesamy"
"github.com/pkg/errors"
"go.uber.org/zap"
)
type (
Collect struct {
l *zap.Logger
gtagProxy *httputil.ReverseProxy
mpv2Proxy *httputil.ReverseProxy
gtagMiddlewares []gtaghttp.Middleware
mpv2Middlewares []mpv2http.Middleware
eventHandlers []sesamyhttp.EventHandler
}
Option func(*Collect) error
)
// ------------------------------------------------------------------------------------------------
// ~ Options
// ------------------------------------------------------------------------------------------------
func WithGTag(endpoint string) Option {
return func(c *Collect) error {
target, err := url.Parse(endpoint)
if err != nil {
return err
}
proxy := httputil.NewSingleHostReverseProxy(target)
c.gtagProxy = proxy
return nil
}
}
func WithMPv2(endpoint string) Option {
return func(c *Collect) error {
target, err := url.Parse(endpoint)
if err != nil {
return err
}
proxy := httputil.NewSingleHostReverseProxy(target)
c.mpv2Proxy = proxy
return nil
}
}
func WithGTagMiddlewares(v ...gtaghttp.Middleware) Option {
return func(c *Collect) error {
c.gtagMiddlewares = append(c.gtagMiddlewares, v...)
return nil
}
}
func WithMPv2Middlewares(v ...mpv2http.Middleware) Option {
return func(c *Collect) error {
c.mpv2Middlewares = append(c.mpv2Middlewares, v...)
return nil
}
}
func WithEventHandlers(v ...sesamyhttp.EventHandler) Option {
return func(c *Collect) error {
c.eventHandlers = append(c.eventHandlers, v...)
return nil
}
}
// ------------------------------------------------------------------------------------------------
// ~ Constructor
// ------------------------------------------------------------------------------------------------
func New(l *zap.Logger, opts ...Option) (*Collect, error) {
inst := &Collect{
l: l,
}
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)
// compose middlewares
next := c.gtagHandler
for _, middleware := range c.gtagMiddlewares {
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.mpv2Middlewares {
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 {
var mpv2Payload *mpv2.Payload[any]
if err := gtagencode.MPv2(*payload, &mpv2Payload); err != nil {
return errors.Wrap(err, "failed to encode gtag to mpv2")
}
for i, event := range mpv2Payload.Events {
if err := c.mpv2EventHandler(r, &event); err != nil {
return err
}
mpv2Payload.Events[i] = event
}
if err := mpv2encode.GTag[any](*mpv2Payload, &payload); err != nil {
return errors.Wrap(err, "failed to encode mpv2 to gtag")
}
if c.gtagProxy == nil {
c.gtagProxy.ServeHTTP(w, r)
}
return nil
}
func (c *Collect) mpv2Handler(l *zap.Logger, w http.ResponseWriter, r *http.Request, payload *mpv2.Payload[any]) error {
for i, event := range payload.Events {
if err := c.mpv2EventHandler(r, &event); err != nil {
return err
}
payload.Events[i] = event
}
if c.mpv2Proxy == nil {
c.mpv2Proxy.ServeHTTP(w, r)
}
return nil
}
func (c *Collect) mpv2EventHandler(r *http.Request, event *sesamy.Event[any]) error {
for _, handler := range c.eventHandlers {
if err := handler(r, event); err != nil {
return err
}
}
return nil
}