mirror of
https://github.com/foomo/sesamy-go.git
synced 2025-10-16 12:35:43 +00:00
feat: refactor event creation and move clients
This commit is contained in:
parent
5cb6719df0
commit
a4fa86a8f3
@ -8,9 +8,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func MessageHandler(handler func(payload *mpv2.Payload[any], msg *message.Message) error) func(msg *message.Message) ([]*message.Message, error) {
|
||||
func MessageHandler(handler func(payload *mpv2.Payload[map[string]any], msg *message.Message) error) func(msg *message.Message) ([]*message.Message, error) {
|
||||
return func(msg *message.Message) ([]*message.Message, error) {
|
||||
var payload *mpv2.Payload[any]
|
||||
var payload *mpv2.Payload[map[string]any]
|
||||
|
||||
// unmarshal payload
|
||||
if err := json.Unmarshal(msg.Payload, &payload); err != nil {
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
package gtag
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/sesamy-go/pkg/encoding/gtag"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
Client struct {
|
||||
GTag struct {
|
||||
l *zap.Logger
|
||||
path string
|
||||
host string
|
||||
@ -18,37 +19,37 @@ type (
|
||||
trackingID string
|
||||
protocolVersion string
|
||||
httpClient *http.Client
|
||||
middlewares []ClientMiddleware
|
||||
middlewares []GTagMiddleware
|
||||
}
|
||||
ClientOption func(*Client)
|
||||
ClientHandler func(r *http.Request, event *Payload) error
|
||||
ClientMiddleware func(next ClientHandler) ClientHandler
|
||||
GTagOption func(*GTag)
|
||||
GTagHandler func(r *http.Request, payload *gtag.Payload) error
|
||||
GTagMiddleware func(next GTagHandler) GTagHandler
|
||||
)
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ~ Options
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
func ClientWithHTTPClient(v *http.Client) ClientOption {
|
||||
return func(o *Client) {
|
||||
func GTagWithHTTPClient(v *http.Client) GTagOption {
|
||||
return func(o *GTag) {
|
||||
o.httpClient = v
|
||||
}
|
||||
}
|
||||
|
||||
func ClientWithPath(v string) ClientOption {
|
||||
return func(o *Client) {
|
||||
func GTagWithPath(v string) GTagOption {
|
||||
return func(o *GTag) {
|
||||
o.path = v
|
||||
}
|
||||
}
|
||||
|
||||
func ClientWithCookies(v ...string) ClientOption {
|
||||
return func(o *Client) {
|
||||
func GTagWithCookies(v ...string) GTagOption {
|
||||
return func(o *GTag) {
|
||||
o.cookies = append(o.cookies, v...)
|
||||
}
|
||||
}
|
||||
|
||||
func ClientWithMiddlewares(v ...ClientMiddleware) ClientOption {
|
||||
return func(o *Client) {
|
||||
func GTagWithMiddlewares(v ...GTagMiddleware) GTagOption {
|
||||
return func(o *GTag) {
|
||||
o.middlewares = append(o.middlewares, v...)
|
||||
}
|
||||
}
|
||||
@ -57,8 +58,8 @@ func ClientWithMiddlewares(v ...ClientMiddleware) ClientOption {
|
||||
// ~ Constructor
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
func NewClient(l *zap.Logger, host, trackingID string, opts ...ClientOption) *Client {
|
||||
inst := &Client{
|
||||
func NewGTag(l *zap.Logger, host, trackingID string, opts ...GTagOption) *GTag {
|
||||
inst := >ag{
|
||||
l: l,
|
||||
host: host,
|
||||
path: "/g/collect",
|
||||
@ -71,14 +72,12 @@ func NewClient(l *zap.Logger, host, trackingID string, opts ...ClientOption) *Cl
|
||||
opt(inst)
|
||||
}
|
||||
inst.middlewares = append(inst.middlewares,
|
||||
MiddlewareRichsstsse,
|
||||
MiddlewareTrackingID(inst.trackingID),
|
||||
// MiddlewarIgnoreReferrer("1"),
|
||||
MiddlewarProtocolVersion("2"),
|
||||
// MiddlewarDebug,
|
||||
MiddlewarClientID,
|
||||
MiddlewarSessionID(inst.trackingID),
|
||||
MiddlewarDocument,
|
||||
GTagMiddlewareRichsstsse,
|
||||
GTagMiddlewareTrackingID(inst.trackingID),
|
||||
GTagMiddlewarProtocolVersion("2"),
|
||||
GTagMiddlewarIsDebug,
|
||||
GTagMiddlewarClientID,
|
||||
GTagMiddlewarSessionID(inst.trackingID),
|
||||
)
|
||||
return inst
|
||||
}
|
||||
@ -87,7 +86,7 @@ func NewClient(l *zap.Logger, host, trackingID string, opts ...ClientOption) *Cl
|
||||
// ~ Getter
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
func (c *Client) HTTPClient() *http.Client {
|
||||
func (c *GTag) HTTPClient() *http.Client {
|
||||
return c.httpClient
|
||||
}
|
||||
|
||||
@ -95,32 +94,24 @@ func (c *Client) HTTPClient() *http.Client {
|
||||
// ~ Public methods
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
func (c *Client) Send(r *http.Request, event Marshler) error {
|
||||
e, err := event.MarshalMPv2()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.SendEvent(r, e)
|
||||
}
|
||||
|
||||
func (c *Client) SendEvent(r *http.Request, event *Payload) error {
|
||||
next := c.SendRawEvent
|
||||
func (c *GTag) Send(r *http.Request, payload *gtag.Payload) error {
|
||||
next := c.SendRaw
|
||||
for _, middleware := range c.middlewares {
|
||||
next = middleware(next)
|
||||
}
|
||||
return next(r, event)
|
||||
return next(r, payload)
|
||||
}
|
||||
|
||||
func (c *Client) SendRawEvent(r *http.Request, event *Payload) error {
|
||||
values, body, err := Encode(event)
|
||||
func (c *GTag) SendRaw(r *http.Request, payload *gtag.Payload) error {
|
||||
values, body, err := gtag.Encode(payload)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to encode event")
|
||||
return errors.Wrap(err, "failed to encode payload")
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(
|
||||
r.Context(),
|
||||
http.MethodPost,
|
||||
fmt.Sprintf("%s%s?%s", c.host, c.path, EncodeValues(values)),
|
||||
fmt.Sprintf("%s%s?%s", c.host, c.path, gtag.EncodeValues(values)),
|
||||
body,
|
||||
)
|
||||
if err != nil {
|
||||
35
pkg/client/gtag_test.go
Normal file
35
pkg/client/gtag_test.go
Normal file
@ -0,0 +1,35 @@
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/http/httputil"
|
||||
"testing"
|
||||
|
||||
"github.com/foomo/sesamy-go/pkg/client"
|
||||
"github.com/foomo/sesamy-go/pkg/encoding/gtag"
|
||||
"github.com/foomo/sesamy-go/pkg/sesamy"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap/zaptest"
|
||||
)
|
||||
|
||||
func TestNewGtag(t *testing.T) {
|
||||
l := zaptest.NewLogger(t)
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Helper()
|
||||
out, err := httputil.DumpRequest(r, true)
|
||||
require.NoError(t, err)
|
||||
t.Log(string(out))
|
||||
}))
|
||||
|
||||
c := client.NewGTag(l, s.URL, "GA-XXXXXX")
|
||||
incomingReq, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, "/foo/bar", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = c.Send(incomingReq, >ag.Payload{
|
||||
EventName: gtag.Set(sesamy.EventName("page_view")),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
75
pkg/client/gtagmiddleware.go
Normal file
75
pkg/client/gtagmiddleware.go
Normal file
@ -0,0 +1,75 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/foomo/sesamy-go/pkg/encoding/gtag"
|
||||
"github.com/foomo/sesamy-go/pkg/session"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func GTagMiddlewareRichsstsse(next GTagHandler) GTagHandler {
|
||||
v := ""
|
||||
return func(r *http.Request, payload *gtag.Payload) error {
|
||||
payload.Richsstsse = &v
|
||||
return next(r, payload)
|
||||
}
|
||||
}
|
||||
|
||||
func GTagMiddlewareTrackingID(v string) GTagMiddleware {
|
||||
return func(next GTagHandler) GTagHandler {
|
||||
return func(r *http.Request, payload *gtag.Payload) error {
|
||||
payload.TrackingID = &v
|
||||
return next(r, payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GTagMiddlewarProtocolVersion(v string) GTagMiddleware {
|
||||
return func(next GTagHandler) GTagHandler {
|
||||
return func(r *http.Request, payload *gtag.Payload) error {
|
||||
payload.ProtocolVersion = &v
|
||||
return next(r, payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GTagMiddlewarIsDebug(next GTagHandler) GTagHandler {
|
||||
v := "1"
|
||||
return func(r *http.Request, payload *gtag.Payload) error {
|
||||
if session.IsGTMDebug(r) {
|
||||
payload.IsDebug = &v
|
||||
}
|
||||
return next(r, payload)
|
||||
}
|
||||
}
|
||||
|
||||
func GTagMiddlewarClientID(next GTagHandler) GTagHandler {
|
||||
return func(r *http.Request, payload *gtag.Payload) error {
|
||||
value, err := session.ParseGAClientID(r)
|
||||
if err != nil && !errors.Is(err, http.ErrNoCookie) {
|
||||
return errors.Wrap(err, "failed to parse client cookie")
|
||||
}
|
||||
if value != "" {
|
||||
payload.ClientID = &value
|
||||
}
|
||||
return next(r, payload)
|
||||
}
|
||||
}
|
||||
|
||||
func GTagMiddlewarSessionID(trackingID string) GTagMiddleware {
|
||||
trackingID = strings.Split(trackingID, "-")[1]
|
||||
return func(next GTagHandler) GTagHandler {
|
||||
return func(r *http.Request, payload *gtag.Payload) error {
|
||||
value, err := session.ParseGASessionID(r, trackingID)
|
||||
if err != nil && !errors.Is(err, http.ErrNoCookie) {
|
||||
return errors.Wrap(err, "failed to parse session cookie")
|
||||
}
|
||||
if value != "" {
|
||||
payload.SessionID = &value
|
||||
}
|
||||
return next(r, payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
161
pkg/client/mpv2.go
Normal file
161
pkg/client/mpv2.go
Normal file
@ -0,0 +1,161 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/sesamy-go/pkg/encoding/mpv2"
|
||||
"github.com/foomo/sesamy-go/pkg/sesamy"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
MPv2 struct {
|
||||
l *zap.Logger
|
||||
path string
|
||||
host string
|
||||
cookies []string
|
||||
protocolVersion string
|
||||
httpClient *http.Client
|
||||
middlewares []MPv2Middleware
|
||||
}
|
||||
MPv2Option func(*MPv2)
|
||||
MPv2Handler func(r *http.Request, payload *mpv2.Payload[any]) error
|
||||
MPv2Middleware func(next MPv2Handler) MPv2Handler
|
||||
)
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ~ Options
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
func MPv2WithHTTPClient(v *http.Client) MPv2Option {
|
||||
return func(o *MPv2) {
|
||||
o.httpClient = v
|
||||
}
|
||||
}
|
||||
|
||||
func MPv2WithPath(v string) MPv2Option {
|
||||
return func(o *MPv2) {
|
||||
o.path = v
|
||||
}
|
||||
}
|
||||
|
||||
func MPv2WithCookies(v ...string) MPv2Option {
|
||||
return func(o *MPv2) {
|
||||
o.cookies = append(o.cookies, v...)
|
||||
}
|
||||
}
|
||||
|
||||
func MPv2WithMiddlewares(v ...MPv2Middleware) MPv2Option {
|
||||
return func(o *MPv2) {
|
||||
o.middlewares = append(o.middlewares, v...)
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ~ Constructor
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
func NewMPv2(l *zap.Logger, host string, opts ...MPv2Option) *MPv2 {
|
||||
inst := &MPv2{
|
||||
l: l,
|
||||
host: host,
|
||||
path: "/mp/collect",
|
||||
cookies: []string{"gtm_auth", "gtm_debug", "gtm_preview"},
|
||||
protocolVersion: "2",
|
||||
httpClient: http.DefaultClient,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(inst)
|
||||
}
|
||||
inst.middlewares = append(inst.middlewares,
|
||||
MPv2MiddlewarClientID,
|
||||
)
|
||||
return inst
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ~ Getter
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
func (c *MPv2) HTTPClient() *http.Client {
|
||||
return c.httpClient
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ~ Public methods
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
func (c *MPv2) Collect(r *http.Request, events ...sesamy.AnyEvent) error {
|
||||
anyEvents := make([]sesamy.Event[any], len(events))
|
||||
for i, event := range events {
|
||||
fmt.Println("-----------")
|
||||
t := reflect.TypeOf(event)
|
||||
x := reflect.New(t)
|
||||
fmt.Println(x)
|
||||
fmt.Println("-----------")
|
||||
anyEvents[i] = event.AnyEvent()
|
||||
}
|
||||
|
||||
payload := &mpv2.Payload[any]{
|
||||
Events: anyEvents,
|
||||
TimestampMicros: time.Now().UnixMicro(),
|
||||
}
|
||||
|
||||
next := c.SendRaw
|
||||
for _, middleware := range c.middlewares {
|
||||
next = middleware(next)
|
||||
}
|
||||
return next(r, payload)
|
||||
}
|
||||
|
||||
func (c *MPv2) SendRaw(r *http.Request, payload *mpv2.Payload[any]) error {
|
||||
jsonPayload, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to encode payload")
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(
|
||||
r.Context(),
|
||||
http.MethodPost,
|
||||
fmt.Sprintf("%s%s", c.host, c.path),
|
||||
bytes.NewReader(jsonPayload),
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create request")
|
||||
}
|
||||
|
||||
// TODO valiate: copy headers
|
||||
req.Header = r.Header.Clone()
|
||||
|
||||
// forward cookies
|
||||
for _, cookie := range c.cookies {
|
||||
if value, _ := r.Cookie(cookie); value != nil {
|
||||
req.AddCookie(value)
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to send request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
var body string
|
||||
if out, err := io.ReadAll(resp.Body); err != nil {
|
||||
c.l.With(zap.Error(err)).Warn(err.Error())
|
||||
} else {
|
||||
body = string(out)
|
||||
}
|
||||
return errors.Errorf("unexpected response status: %d (%s)", resp.StatusCode, body)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
36
pkg/client/mpv2_test.go
Normal file
36
pkg/client/mpv2_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/http/httputil"
|
||||
"testing"
|
||||
|
||||
"github.com/foomo/sesamy-go/pkg/client"
|
||||
"github.com/foomo/sesamy-go/pkg/event"
|
||||
"github.com/foomo/sesamy-go/pkg/event/params"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap/zaptest"
|
||||
)
|
||||
|
||||
func TestNewMPv2(t *testing.T) {
|
||||
l := zaptest.NewLogger(t)
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Helper()
|
||||
out, err := httputil.DumpRequest(r, true)
|
||||
require.NoError(t, err)
|
||||
t.Log(string(out))
|
||||
}))
|
||||
|
||||
c := client.NewMPv2(l, s.URL)
|
||||
incomingReq, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, "/foo/bar", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = c.Collect(incomingReq, event.NewPageView(params.PageView{
|
||||
PageTitle: "foo",
|
||||
PageLocation: "bar",
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
22
pkg/client/mpv2middleware.go
Normal file
22
pkg/client/mpv2middleware.go
Normal file
@ -0,0 +1,22 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/sesamy-go/pkg/encoding/mpv2"
|
||||
"github.com/foomo/sesamy-go/pkg/session"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func MPv2MiddlewarClientID(next MPv2Handler) MPv2Handler {
|
||||
return func(r *http.Request, payload *mpv2.Payload[any]) error {
|
||||
value, err := session.ParseGAClientID(r)
|
||||
if err != nil && !errors.Is(err, http.ErrNoCookie) {
|
||||
return errors.Wrap(err, "failed to parse client cookie")
|
||||
}
|
||||
if value != "" {
|
||||
payload.ClientID = value
|
||||
}
|
||||
return next(r, payload)
|
||||
}
|
||||
}
|
||||
@ -29,12 +29,12 @@ func TestDecode(t *testing.T) {
|
||||
{
|
||||
name: "add_to_cart",
|
||||
args: "v=2&tid=G-123456>m=45je42s0v9175354889z89175348963za200&_p=1709297934217&_dbg=1&gcd=13l3l3l3l1&npa=0&dma_cps=sypham&dma=1&cid=1220643501.1708014725&ul=en-us&sr=3840x1600&_fplc=0&ur=DE-BY&uaa=arm&uab=64&uafvl=Chromium&uamb=0&uam=&uap=macOS&uapv=14.3.1&uaw=0&are=1&pscdl=noapi&_eu=IA&sst.uc=DE&sst.etld=google.de&sst.gcsub=region1&sst.gcd=13l3l3l3l1&sst.tft=1709297934217&_s=8&cu=USD&sid=1709296380&sct=7&seg=1&dl=https%3A%2F%2Fsniffer.cloud.bestbytes.net%2F%3Fgtm_debug%3D1709297933868&dr=https%3A%2F%2Ftagassistant.google.com%2F&dt=Server%20Side%20Tracking%20Prototype%20(codename%3A%20sniffer)&en=add_to_cart&pr1=idSKU_12345~nmStan%20and%20Friends%20Tee~afGoogle%20Store~cpSUMMER_FUN~ds2.22~lp5~brGoogle~caApparel~c2Adult~c3Shirts~c4Crew~c5Short%20sleeve~lirelated_products~lnRelated%20products~vagreen~loChIJIQBpAG2ahYAR_6128GcTUEo~pr10.01~qt3&epn.value=30.03&tfd=15129&richsstsse",
|
||||
want: `{"consent":{"google_consent_default":"13l3l3l3l1"},"campaign":{},"ecommerce":{"currency":"USD","items":[{"affiliation":"Google Store","coupon":"SUMMER_FUN","discount":"2.22","item_brand":"Google","item_category":"Apparel","item_category2":"Adult","item_category3":"Shirts","item_category4":"Crew","item_category5":"Short sleeve","item_id":"SKU_12345","item_list_id":"related_products","item_list_name":"Related products","item_name":"Stan and Friends Tee","item_variant":"green","item_list_position":"5","location_id":"ChIJIQBpAG2ahYAR_6128GcTUEo","price":"10.01","quantity":"3"}]},"client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.3.1","user_agent_wow_64":"0","user_region":"DE-BY"},"protocol_version":"2","tracking_id":"G-123456","gtmhash_info":"45je42s0v9175354889z89175348963za200","client_id":"1220643501.1708014725","richsstsse":"","document_location":"https://sniffer.cloud.bestbytes.net/?gtm_debug=1709297933868","document_title":"Server Side Tracking Prototype (codename: sniffer)","document_referrer":"https://tagassistant.google.com/","event_name":"add_to_cart","event_parameter_number":{"value":"30.03"},"session_id":"1709296380","non_personalized_ads":"0","sst":{"etld":"google.de","gcsub":"region1","uc":"DE","tft":"1709297934217","gcd":"13l3l3l3l1"}}`,
|
||||
want: `{"consent":{"google_consent_default":"13l3l3l3l1"},"campaign":{},"ecommerce":{"currency":"USD","items":[{"affiliation":"Google Store","coupon":"SUMMER_FUN","discount":"2.22","item_brand":"Google","item_category":"Apparel","item_category2":"Adult","item_category3":"Shirts","item_category4":"Crew","item_category5":"Short sleeve","item_id":"SKU_12345","item_list_id":"related_products","item_list_name":"Related products","item_name":"Stan and Friends Tee","item_variant":"green","item_list_position":"5","location_id":"ChIJIQBpAG2ahYAR_6128GcTUEo","price":"10.01","quantity":"3"}]},"client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.3.1","user_agent_wow_64":"0","user_region":"DE-BY"},"protocol_version":"2","tracking_id":"G-123456","gtmhash_info":"45je42s0v9175354889z89175348963za200","is_debug":"1","client_id":"1220643501.1708014725","richsstsse":"","document_location":"https://sniffer.cloud.bestbytes.net/?gtm_debug=1709297933868","document_title":"Server Side Tracking Prototype (codename: sniffer)","document_referrer":"https://tagassistant.google.com/","event_name":"add_to_cart","event_parameter_number":{"value":"30.03"},"session_id":"1709296380","non_personalized_ads":"0","sst":{"etld":"google.de","gcsub":"region1","uc":"DE","tft":"1709297934217","gcd":"13l3l3l3l1"}}`,
|
||||
},
|
||||
{
|
||||
name: "select_item",
|
||||
args: "v=2&tid=G-F9XM71K45T>m=45he4580v9184715813z89184708445za200&_p=1715430403224&_dbg=1&gcd=13l3l3l2l1&npa=1&dma_cps=sypham&dma=1&cid=179294588.1715353601&ecid=251283723&ul=en-us&sr=3840x1600&_fplc=0&ur=&uaa=arm&uab=64&uafvl=Chromium%3B124.0.6367.119%7CGoogle%2520Chrome%3B124.0.6367.119%7CNot-A.Brand%3B99.0.0.0&uamb=0&uam=&uap=macOS&uapv=14.4.1&uaw=0&are=1&frm=0&pscdl=noapi&sst.gcd=13l3l3l2l1&sst.tft=1715430403224&sst.ude=0&_s=3&sid=1715428762&sct=2&seg=1&dl=https%3A%2F%2Fsesamy.local.bestbytes.net%2F%3Fgtm_debug%3D1715430402906&dr=https%3A%2F%2Ftagassistant.google.com%2F&dt=Home&en=select_item&pr1=idSKU_12345~nmStan%20and%20Friends%20Tee~afGoogle%20Merchandise%20Store~cpSUMMER_FUN~ds2.22~lp0~brGoogle~caApparel~c2Adult~c3Shirts~c4Crew~c5Short%20sleeve~lirelated_products~lnRelated%20Products~vagreen~loChIJIQBpAG2ahYAR_6128GcTUEo~pr10.01~qt3&ep.enable_page_views=false&ep.item_list_id=related_products&ep.item_list_name=Related%20products&_et=89&tfd=8618&richsstsse",
|
||||
want: `{"consent":{"google_consent_default":"13l3l3l2l1"},"campaign":{},"ecommerce":{"items":[{"affiliation":"Google Merchandise Store","coupon":"SUMMER_FUN","discount":"2.22","item_brand":"Google","item_category":"Apparel","item_category2":"Adult","item_category3":"Shirts","item_category4":"Crew","item_category5":"Short sleeve","item_id":"SKU_12345","item_list_id":"related_products","item_list_name":"Related Products","item_name":"Stan and Friends Tee","item_variant":"green","item_list_position":"0","location_id":"ChIJIQBpAG2ahYAR_6128GcTUEo","price":"10.01","quantity":"3"}]},"client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium;124.0.6367.119|Google%20Chrome;124.0.6367.119|Not-A.Brand;99.0.0.0","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.4.1","user_agent_wow_64":"0","user_region":""},"protocol_version":"2","tracking_id":"G-F9XM71K45T","gtmhash_info":"45he4580v9184715813z89184708445za200","client_id":"179294588.1715353601","richsstsse":"","document_location":"https://sesamy.local.bestbytes.net/?gtm_debug=1715430402906","document_title":"Home","document_referrer":"https://tagassistant.google.com/","event_name":"select_item","event_parameter":{"enable_page_views":"false","item_list_id":"related_products","item_list_name":"Related products"},"session_id":"1715428762","non_personalized_ads":"1","sst":{"tft":"1715430403224", "ude":"0", "gcd":"13l3l3l2l1"}}`,
|
||||
want: `{"consent":{"google_consent_default":"13l3l3l2l1"},"campaign":{},"ecommerce":{"items":[{"affiliation":"Google Merchandise Store","coupon":"SUMMER_FUN","discount":"2.22","item_brand":"Google","item_category":"Apparel","item_category2":"Adult","item_category3":"Shirts","item_category4":"Crew","item_category5":"Short sleeve","item_id":"SKU_12345","item_list_id":"related_products","item_list_name":"Related Products","item_name":"Stan and Friends Tee","item_variant":"green","item_list_position":"0","location_id":"ChIJIQBpAG2ahYAR_6128GcTUEo","price":"10.01","quantity":"3"}]},"client_hints":{"screen_resolution":"3840x1600","user_language":"en-us","user_agent_architecture":"arm","user_agent_bitness":"64","user_agent_full_version_list":"Chromium;124.0.6367.119|Google%20Chrome;124.0.6367.119|Not-A.Brand;99.0.0.0","user_agent_mobile":"0","user_agent_model":"","user_agent_platform":"macOS","user_agent_platform_version":"14.4.1","user_agent_wow_64":"0","user_region":""},"protocol_version":"2","tracking_id":"G-F9XM71K45T","gtmhash_info":"45he4580v9184715813z89184708445za200","is_debug":"1","client_id":"179294588.1715353601","richsstsse":"","document_location":"https://sesamy.local.bestbytes.net/?gtm_debug=1715430402906","document_title":"Home","document_referrer":"https://tagassistant.google.com/","event_name":"select_item","event_parameter":{"enable_page_views":"false","item_list_id":"related_products","item_list_name":"Related products"},"session_id":"1715428762","non_personalized_ads":"1","sst":{"tft":"1715430403224", "ude":"0", "gcd":"13l3l3l2l1"}}`,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
package gtag
|
||||
|
||||
type Marshler interface {
|
||||
MarshalMPv2() (*Payload, error)
|
||||
}
|
||||
@ -1,89 +0,0 @@
|
||||
package gtag
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func MiddlewareRichsstsse(next ClientHandler) ClientHandler {
|
||||
v := ""
|
||||
return func(r *http.Request, event *Payload) error {
|
||||
event.Richsstsse = &v
|
||||
return next(r, event)
|
||||
}
|
||||
}
|
||||
|
||||
func MiddlewareTrackingID(v string) ClientMiddleware {
|
||||
return func(next ClientHandler) ClientHandler {
|
||||
return func(r *http.Request, event *Payload) error {
|
||||
event.TrackingID = &v
|
||||
return next(r, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MiddlewarProtocolVersion(v string) ClientMiddleware {
|
||||
return func(next ClientHandler) ClientHandler {
|
||||
return func(r *http.Request, event *Payload) error {
|
||||
event.ProtocolVersion = &v
|
||||
return next(r, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func MiddlewarIgnoreReferrer(v string) ClientMiddleware {
|
||||
// return func(next ClientHandler) ClientHandler {
|
||||
// return func(r *http.Request, event *Event) error {
|
||||
// event.IgnoreReferrer = &v
|
||||
// return next(r, event)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// func MiddlewarDebug(next ClientHandler) ClientHandler {
|
||||
// v := "1"
|
||||
// return func(r *http.Request, event *Event) error {
|
||||
// if value, _ := r.Cookie("gtm_debug"); value != nil {
|
||||
// event.IsDebug = &v
|
||||
// }
|
||||
// return next(r, event)
|
||||
// }
|
||||
// }
|
||||
|
||||
func MiddlewarClientID(next ClientHandler) ClientHandler {
|
||||
return func(r *http.Request, event *Payload) error {
|
||||
if value, _ := r.Cookie("_ga"); value != nil {
|
||||
clientID := strings.TrimPrefix(value.Value, "GA1.1.")
|
||||
event.ClientID = &clientID
|
||||
}
|
||||
return next(r, event)
|
||||
}
|
||||
}
|
||||
|
||||
func MiddlewarSessionID(trackingID string) ClientMiddleware {
|
||||
trackingID = strings.Split(trackingID, "-")[1]
|
||||
return func(next ClientHandler) ClientHandler {
|
||||
return func(r *http.Request, event *Payload) error {
|
||||
if value, _ := r.Cookie("_ga_" + trackingID); value != nil {
|
||||
if value := strings.Split(value.Value, "."); len(value) > 3 {
|
||||
event.SessionID = &value[2]
|
||||
}
|
||||
}
|
||||
return next(r, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MiddlewarDocument(next ClientHandler) ClientHandler {
|
||||
return func(r *http.Request, event *Payload) error {
|
||||
if referrer, err := url.Parse(r.Referer()); err != nil {
|
||||
return err
|
||||
} else {
|
||||
location := referrer.String()
|
||||
event.DocumentLocation = &location
|
||||
// event.DocumentHostname = &referrer.Host
|
||||
}
|
||||
return next(r, event)
|
||||
}
|
||||
}
|
||||
@ -56,7 +56,7 @@ type Payload struct {
|
||||
// EventDebugID *string `json:"event_debug_id,omitempty" gtag:"edid,omitempty"`
|
||||
// If an event contains this parameters it won't be processed and it will show on on the debug View in GA4
|
||||
// Example: 1
|
||||
// IsDebug *string `json:"is_debug,omitempty" gtag:"_dbg,omitempty"`
|
||||
IsDebug *string `json:"is_debug,omitempty" gtag:"_dbg,omitempty"`
|
||||
// If the current request has a referrer, it will be ignored at processing level
|
||||
// Example: 1
|
||||
// IgnoreReferrer *string `json:"ignore_referrer,omitempty" gtag:"ir,omitempty"`
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type AddPaymentInfo sesamy.Event[params.AddPaymentInfo[params.Item]]
|
||||
|
||||
func NewAddPaymentInfo(p params.AddPaymentInfo[params.Item]) AddPaymentInfo {
|
||||
return AddPaymentInfo(sesamy.NewEvent(sesamy.EventNameAddPaymentInfo, p))
|
||||
func NewAddPaymentInfo(p params.AddPaymentInfo[params.Item]) sesamy.Event[params.AddPaymentInfo[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameAddPaymentInfo, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type AddShippingInfo sesamy.Event[params.AddShippingInfo[params.Item]]
|
||||
|
||||
func NewAddShippingInfo(p params.AddShippingInfo[params.Item]) AddShippingInfo {
|
||||
return AddShippingInfo(sesamy.NewEvent(sesamy.EventNameAddShippingInfo, p))
|
||||
func NewAddShippingInfo(p params.AddShippingInfo[params.Item]) sesamy.Event[params.AddShippingInfo[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameAddShippingInfo, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type AddToCart sesamy.Event[params.AddToCart[params.Item]]
|
||||
|
||||
func NewAddToCart(p params.AddToCart[params.Item]) AddToCart {
|
||||
return AddToCart(sesamy.NewEvent(sesamy.EventNameAddToCart, p))
|
||||
func NewAddToCart(p params.AddToCart[params.Item]) sesamy.Event[params.AddToCart[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameAddToCart, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type AddToWishlist sesamy.Event[params.AddToWishlist[params.Item]]
|
||||
|
||||
func NewAddToWishlist(p params.AddToWishlist[params.Item]) AddToWishlist {
|
||||
return AddToWishlist(sesamy.NewEvent(sesamy.EventNameAddToWishlist, p))
|
||||
func NewAddToWishlist(p params.AddToWishlist[params.Item]) sesamy.Event[params.AddToWishlist[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameAddToWishlist, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type AdImpression sesamy.Event[params.AdImpression]
|
||||
|
||||
func NewAdImpression(p params.AdImpression) AdImpression {
|
||||
return AdImpression(sesamy.NewEvent(sesamy.EventNameAdImpression, p))
|
||||
func NewAdImpression(p params.AdImpression) sesamy.Event[params.AdImpression] {
|
||||
return sesamy.NewEvent(sesamy.EventNameAdImpression, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type BeginCheckout sesamy.Event[params.BeginCheckout[params.Item]]
|
||||
|
||||
func NewBeginCheckout(p params.BeginCheckout[params.Item]) BeginCheckout {
|
||||
return BeginCheckout(sesamy.NewEvent(sesamy.EventNameBeginCheckout, p))
|
||||
func NewBeginCheckout(p params.BeginCheckout[params.Item]) sesamy.Event[params.BeginCheckout[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameBeginCheckout, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type CampaignDetails sesamy.Event[params.CampaignDetails]
|
||||
|
||||
func NewCampaignDetails(p params.CampaignDetails) CampaignDetails {
|
||||
return CampaignDetails(sesamy.NewEvent(sesamy.EventNameCampaignDetails, p))
|
||||
func NewCampaignDetails(p params.CampaignDetails) sesamy.Event[params.CampaignDetails] {
|
||||
return sesamy.NewEvent(sesamy.EventNameCampaignDetails, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type Click sesamy.Event[params.Click]
|
||||
|
||||
func NewClick(p params.Click) Click {
|
||||
return Click(sesamy.NewEvent(sesamy.EventNameClick, p))
|
||||
func NewClick(p params.Click) sesamy.Event[params.Click] {
|
||||
return sesamy.NewEvent(sesamy.EventNameClick, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type EarnVirtualMoney sesamy.Event[params.EarnVirtualMoney]
|
||||
|
||||
func NewEarnVirtualMoney(p params.EarnVirtualMoney) EarnVirtualMoney {
|
||||
return EarnVirtualMoney(sesamy.NewEvent(sesamy.EventNameEarnVirtualMoney, p))
|
||||
func NewEarnVirtualMoney(p params.EarnVirtualMoney) sesamy.Event[params.EarnVirtualMoney] {
|
||||
return sesamy.NewEvent(sesamy.EventNameEarnVirtualMoney, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type FileDownload sesamy.Event[params.FileDownload]
|
||||
|
||||
func NewFileDownload(p params.FileDownload) FileDownload {
|
||||
return FileDownload(sesamy.NewEvent(sesamy.EventNameFileDownload, p))
|
||||
func NewFileDownload(p params.FileDownload) sesamy.Event[params.FileDownload] {
|
||||
return sesamy.NewEvent(sesamy.EventNameFileDownload, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type FormStart sesamy.Event[params.FormStart]
|
||||
|
||||
func NewFormStart(p params.FormStart) FormStart {
|
||||
return FormStart(sesamy.NewEvent(sesamy.EventNameFormStart, p))
|
||||
func NewFormStart(p params.FormStart) sesamy.Event[params.FormStart] {
|
||||
return sesamy.NewEvent(sesamy.EventNameFormStart, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type FormSubmit sesamy.Event[params.FormSubmit]
|
||||
|
||||
func NewFormSubmit(p params.FormSubmit) FormSubmit {
|
||||
return FormSubmit(sesamy.NewEvent(sesamy.EventNameFormSubmit, p))
|
||||
func NewFormSubmit(p params.FormSubmit) sesamy.Event[params.FormSubmit] {
|
||||
return sesamy.NewEvent(sesamy.EventNameFormSubmit, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type GenerateLead sesamy.Event[params.GenerateLead]
|
||||
|
||||
func NewGenerateLead(p params.GenerateLead) GenerateLead {
|
||||
return GenerateLead(sesamy.NewEvent(sesamy.EventNameGenerateLead, p))
|
||||
func NewGenerateLead(p params.GenerateLead) sesamy.Event[params.GenerateLead] {
|
||||
return sesamy.NewEvent(sesamy.EventNameGenerateLead, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type JoinGroup sesamy.Event[params.JoinGroup]
|
||||
|
||||
func NewJoinGroup(p params.JoinGroup) JoinGroup {
|
||||
return JoinGroup(sesamy.NewEvent(sesamy.EventNameJoinGroup, p))
|
||||
func NewJoinGroup(p params.JoinGroup) sesamy.Event[params.JoinGroup] {
|
||||
return sesamy.NewEvent(sesamy.EventNameJoinGroup, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type LevelEnd sesamy.Event[params.LevelEnd]
|
||||
|
||||
func NewLevelEnd(p params.LevelEnd) LevelEnd {
|
||||
return LevelEnd(sesamy.NewEvent(sesamy.EventNameLevelEnd, p))
|
||||
func NewLevelEnd(p params.LevelEnd) sesamy.Event[params.LevelEnd] {
|
||||
return sesamy.NewEvent(sesamy.EventNameLevelEnd, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type LevelStart sesamy.Event[params.LevelStart]
|
||||
|
||||
func NewLevelStart(p params.LevelStart) LevelStart {
|
||||
return LevelStart(sesamy.NewEvent(sesamy.EventNameLevelStart, p))
|
||||
func NewLevelStart(p params.LevelStart) sesamy.Event[params.LevelStart] {
|
||||
return sesamy.NewEvent(sesamy.EventNameLevelStart, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type LevelUp sesamy.Event[params.LevelUp]
|
||||
|
||||
func NewLevelUp(p params.LevelUp) LevelUp {
|
||||
return LevelUp(sesamy.NewEvent(sesamy.EventNameLevelUp, p))
|
||||
func NewLevelUp(p params.LevelUp) sesamy.Event[params.LevelUp] {
|
||||
return sesamy.NewEvent(sesamy.EventNameLevelUp, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type Login sesamy.Event[params.Login]
|
||||
|
||||
func NewLogin(p params.Login) Login {
|
||||
return Login(sesamy.NewEvent(sesamy.EventNameLogin, p))
|
||||
func NewLogin(p params.Login) sesamy.Event[params.Login] {
|
||||
return sesamy.NewEvent(sesamy.EventNameLogin, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type PageView sesamy.Event[params.PageView]
|
||||
|
||||
func NewPageView(p params.PageView) PageView {
|
||||
return PageView(sesamy.NewEvent(sesamy.EventNamePageView, p))
|
||||
func NewPageView(p params.PageView) sesamy.Event[params.PageView] {
|
||||
return sesamy.NewEvent(sesamy.EventNamePageView, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type PostScore sesamy.Event[params.PostScore]
|
||||
|
||||
func NewPostScore(p params.PostScore) PostScore {
|
||||
return PostScore(sesamy.NewEvent(sesamy.EventNamePostScore, p))
|
||||
func NewPostScore(p params.PostScore) sesamy.Event[params.PostScore] {
|
||||
return sesamy.NewEvent(sesamy.EventNamePostScore, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type Purchase sesamy.Event[params.Purchase[params.Item]]
|
||||
|
||||
func NewPurchase(p params.Purchase[params.Item]) Purchase {
|
||||
return Purchase(sesamy.NewEvent(sesamy.EventNamePurchase, p))
|
||||
func NewPurchase(p params.Purchase[params.Item]) sesamy.Event[params.Purchase[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNamePurchase, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type Refund sesamy.Event[params.Refund[params.Item]]
|
||||
|
||||
func NewRefund(p params.Refund[params.Item]) Refund {
|
||||
return Refund(sesamy.NewEvent(sesamy.EventNameRefund, p))
|
||||
func NewRefund(p params.Refund[params.Item]) sesamy.Event[params.Refund[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameRefund, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type RemoveFromCart sesamy.Event[params.RemoveFromCart[params.Item]]
|
||||
|
||||
func NewRemoveFromCart(p params.RemoveFromCart[params.Item]) RemoveFromCart {
|
||||
return RemoveFromCart(sesamy.NewEvent(sesamy.EventNameRemoveFromCart, p))
|
||||
func NewRemoveFromCart(p params.RemoveFromCart[params.Item]) sesamy.Event[params.RemoveFromCart[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameRemoveFromCart, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type ScreenView sesamy.Event[params.ScreenView]
|
||||
|
||||
func NewScreenView(p params.ScreenView) ScreenView {
|
||||
return ScreenView(sesamy.NewEvent(sesamy.EventNameScreenView, p))
|
||||
func NewScreenView(p params.ScreenView) sesamy.Event[params.ScreenView] {
|
||||
return sesamy.NewEvent(sesamy.EventNameScreenView, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type Scroll sesamy.Event[params.Scroll]
|
||||
|
||||
func NewScroll(p params.Scroll) Scroll {
|
||||
return Scroll(sesamy.NewEvent(sesamy.EventNameScroll, p))
|
||||
func NewScroll(p params.Scroll) sesamy.Event[params.Scroll] {
|
||||
return sesamy.NewEvent(sesamy.EventNameScroll, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type Search sesamy.Event[params.Search]
|
||||
|
||||
func NewSearch(p params.Search) Search {
|
||||
return Search(sesamy.NewEvent(sesamy.EventNameSearch, p))
|
||||
func NewSearch(p params.Search) sesamy.Event[params.Search] {
|
||||
return sesamy.NewEvent(sesamy.EventNameSearch, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type SelectContent sesamy.Event[params.SelectContent]
|
||||
|
||||
func NewSelectContent(p params.SelectContent) SelectContent {
|
||||
return SelectContent(sesamy.NewEvent(sesamy.EventNameSelectContent, p))
|
||||
func NewSelectContent(p params.SelectContent) sesamy.Event[params.SelectContent] {
|
||||
return sesamy.NewEvent(sesamy.EventNameSelectContent, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type SelectItem sesamy.Event[params.SelectItem[params.Item]]
|
||||
|
||||
func NewSelectItem(p params.SelectItem[params.Item]) SelectItem {
|
||||
return SelectItem(sesamy.NewEvent(sesamy.EventNameSelectItem, p))
|
||||
func NewSelectItem(p params.SelectItem[params.Item]) sesamy.Event[params.SelectItem[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameSelectItem, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type SelectPromotion sesamy.Event[params.SelectPromotion[params.Item]]
|
||||
|
||||
func NewSelectPromotion(p params.SelectPromotion[params.Item]) SelectPromotion {
|
||||
return SelectPromotion(sesamy.NewEvent(sesamy.EventNameSelectPromotion, p))
|
||||
func NewSelectPromotion(p params.SelectPromotion[params.Item]) sesamy.Event[params.SelectPromotion[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameSelectPromotion, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type SessionStart sesamy.Event[params.SessionStart]
|
||||
|
||||
func NewSessionStart(p params.SessionStart) SessionStart {
|
||||
return SessionStart(sesamy.NewEvent(sesamy.EventNameSessionStart, p))
|
||||
func NewSessionStart(p params.SessionStart) sesamy.Event[params.SessionStart] {
|
||||
return sesamy.NewEvent(sesamy.EventNameSessionStart, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type Share sesamy.Event[params.Share]
|
||||
|
||||
func NewShare(p params.Share) Share {
|
||||
return Share(sesamy.NewEvent(sesamy.EventNameShare, p))
|
||||
func NewShare(p params.Share) sesamy.Event[params.Share] {
|
||||
return sesamy.NewEvent(sesamy.EventNameShare, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type SignUp sesamy.Event[params.SignUp]
|
||||
|
||||
func NewSignUp(p params.SignUp) SignUp {
|
||||
return SignUp(sesamy.NewEvent(sesamy.EventNameSignUp, p))
|
||||
func NewSignUp(p params.SignUp) sesamy.Event[params.SignUp] {
|
||||
return sesamy.NewEvent(sesamy.EventNameSignUp, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type SpendVirtualCurrency sesamy.Event[params.SpendVirtualCurrency]
|
||||
|
||||
func NewSpendVirtualCurrency(p params.SpendVirtualCurrency) SpendVirtualCurrency {
|
||||
return SpendVirtualCurrency(sesamy.NewEvent(sesamy.EventNameSpendVirtualCurrency, p))
|
||||
func NewSpendVirtualCurrency(p params.SpendVirtualCurrency) sesamy.Event[params.SpendVirtualCurrency] {
|
||||
return sesamy.NewEvent(sesamy.EventNameSpendVirtualCurrency, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type TutorialBegin sesamy.Event[params.TutorialBegin]
|
||||
|
||||
func NewTutorialBegin(p params.TutorialBegin) TutorialBegin {
|
||||
return TutorialBegin(sesamy.NewEvent(sesamy.EventNameTutorialBegin, p))
|
||||
func NewTutorialBegin(p params.TutorialBegin) sesamy.Event[params.TutorialBegin] {
|
||||
return sesamy.NewEvent(sesamy.EventNameTutorialBegin, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type TutorialComplete sesamy.Event[params.TutorialComplete]
|
||||
|
||||
func NewTutorialComplete(p params.TutorialComplete) TutorialComplete {
|
||||
return TutorialComplete(sesamy.NewEvent(sesamy.EventNameTutorialComplete, p))
|
||||
func NewTutorialComplete(p params.TutorialComplete) sesamy.Event[params.TutorialComplete] {
|
||||
return sesamy.NewEvent(sesamy.EventNameTutorialComplete, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type UnlockAchievement sesamy.Event[params.UnlockAchievement]
|
||||
|
||||
func NewUnlockArchievement(p params.UnlockAchievement) UnlockAchievement {
|
||||
return UnlockAchievement(sesamy.NewEvent(sesamy.EventNameUnlockAchievement, p))
|
||||
func NewUnlockAchievement(p params.UnlockAchievement) sesamy.Event[params.UnlockAchievement] {
|
||||
return sesamy.NewEvent(sesamy.EventNameUnlockAchievement, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type UserEngagement sesamy.Event[params.UserEngagement]
|
||||
|
||||
func NewUserEngagement(p params.UserEngagement) UserEngagement {
|
||||
return UserEngagement(sesamy.NewEvent(sesamy.EventNameUserEngagement, p))
|
||||
func NewUserEngagement(p params.UserEngagement) sesamy.Event[params.UserEngagement] {
|
||||
return sesamy.NewEvent(sesamy.EventNameUserEngagement, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type VideoComplete sesamy.Event[params.VideoComplete]
|
||||
|
||||
func NewVideoComplete(p params.VideoComplete) VideoComplete {
|
||||
return VideoComplete(sesamy.NewEvent(sesamy.EventNameVideoComplete, p))
|
||||
func NewVideoComplete(p params.VideoComplete) sesamy.Event[params.VideoComplete] {
|
||||
return sesamy.NewEvent(sesamy.EventNameVideoComplete, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type VideoProgress sesamy.Event[params.VideoProgress]
|
||||
|
||||
func NewVideoProgress(p params.VideoProgress) VideoProgress {
|
||||
return VideoProgress(sesamy.NewEvent(sesamy.EventNameVideoProgress, p))
|
||||
func NewVideoProgress(p params.VideoProgress) sesamy.Event[params.VideoProgress] {
|
||||
return sesamy.NewEvent(sesamy.EventNameVideoProgress, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type VideoStart sesamy.Event[params.VideoStart]
|
||||
|
||||
func NewVideoStart(p params.VideoStart) VideoStart {
|
||||
return VideoStart(sesamy.NewEvent(sesamy.EventNameVideoStart, p))
|
||||
func NewVideoStart(p params.VideoStart) sesamy.Event[params.VideoStart] {
|
||||
return sesamy.NewEvent(sesamy.EventNameVideoStart, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type ViewCart sesamy.Event[params.ViewCart[params.Item]]
|
||||
|
||||
func NewViewCart(p params.ViewCart[params.Item]) ViewCart {
|
||||
return ViewCart(sesamy.NewEvent(sesamy.EventNameViewCart, p))
|
||||
func NewViewCart(p params.ViewCart[params.Item]) sesamy.Event[params.ViewCart[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameViewCart, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type ViewItem sesamy.Event[params.ViewItem[params.Item]]
|
||||
|
||||
func NewViewItem(p params.ViewItem[params.Item]) ViewItem {
|
||||
return ViewItem(sesamy.NewEvent(sesamy.EventNameViewItem, p))
|
||||
func NewViewItem(p params.ViewItem[params.Item]) sesamy.Event[params.ViewItem[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameViewItem, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type ViewItemList sesamy.Event[params.ViewItemList[params.Item]]
|
||||
|
||||
func NewViewItemList(p params.ViewItemList[params.Item]) ViewItemList {
|
||||
return ViewItemList(sesamy.NewEvent(sesamy.EventNameViewItemList, p))
|
||||
func NewViewItemList(p params.ViewItemList[params.Item]) sesamy.Event[params.ViewItemList[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameViewItemList, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type ViewPromotion sesamy.Event[params.ViewPromotion[params.Item]]
|
||||
|
||||
func NewViewPromotion(p params.ViewPromotion[params.Item]) ViewPromotion {
|
||||
return ViewPromotion(sesamy.NewEvent(sesamy.EventNameViewPromotion, p))
|
||||
func NewViewPromotion(p params.ViewPromotion[params.Item]) sesamy.Event[params.ViewPromotion[params.Item]] {
|
||||
return sesamy.NewEvent(sesamy.EventNameViewPromotion, p)
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ import (
|
||||
|
||||
type ViewSearchResults sesamy.Event[params.ViewSearchResults]
|
||||
|
||||
func NewViewSearchResults(p params.ViewSearchResults) ViewSearchResults {
|
||||
return ViewSearchResults(sesamy.NewEvent(sesamy.EventNameViewSearchResults, p))
|
||||
func NewViewSearchResults(p params.ViewSearchResults) sesamy.Event[params.ViewSearchResults] {
|
||||
return sesamy.NewEvent(sesamy.EventNameViewSearchResults, p)
|
||||
}
|
||||
|
||||
6
pkg/sesamy/anyevent.go
Normal file
6
pkg/sesamy/anyevent.go
Normal file
@ -0,0 +1,6 @@
|
||||
package sesamy
|
||||
|
||||
// AnyEvent casting is required as castings like Event[any](pageView) do not work.
|
||||
type AnyEvent interface {
|
||||
AnyEvent() Event[any]
|
||||
}
|
||||
@ -13,3 +13,10 @@ func NewEvent[P any](name EventName, params P) Event[P] {
|
||||
Params: params,
|
||||
}
|
||||
}
|
||||
|
||||
func (e Event[P]) AnyEvent() Event[any] {
|
||||
return Event[any]{
|
||||
Name: e.Name,
|
||||
Params: e.Params,
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user