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"
|
"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) {
|
return func(msg *message.Message) ([]*message.Message, error) {
|
||||||
var payload *mpv2.Payload[any]
|
var payload *mpv2.Payload[map[string]any]
|
||||||
|
|
||||||
// unmarshal payload
|
// unmarshal payload
|
||||||
if err := json.Unmarshal(msg.Payload, &payload); err != nil {
|
if err := json.Unmarshal(msg.Payload, &payload); err != nil {
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
package gtag
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/foomo/sesamy-go/pkg/encoding/gtag"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Client struct {
|
GTag struct {
|
||||||
l *zap.Logger
|
l *zap.Logger
|
||||||
path string
|
path string
|
||||||
host string
|
host string
|
||||||
@ -18,37 +19,37 @@ type (
|
|||||||
trackingID string
|
trackingID string
|
||||||
protocolVersion string
|
protocolVersion string
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
middlewares []ClientMiddleware
|
middlewares []GTagMiddleware
|
||||||
}
|
}
|
||||||
ClientOption func(*Client)
|
GTagOption func(*GTag)
|
||||||
ClientHandler func(r *http.Request, event *Payload) error
|
GTagHandler func(r *http.Request, payload *gtag.Payload) error
|
||||||
ClientMiddleware func(next ClientHandler) ClientHandler
|
GTagMiddleware func(next GTagHandler) GTagHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// ~ Options
|
// ~ Options
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
func ClientWithHTTPClient(v *http.Client) ClientOption {
|
func GTagWithHTTPClient(v *http.Client) GTagOption {
|
||||||
return func(o *Client) {
|
return func(o *GTag) {
|
||||||
o.httpClient = v
|
o.httpClient = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClientWithPath(v string) ClientOption {
|
func GTagWithPath(v string) GTagOption {
|
||||||
return func(o *Client) {
|
return func(o *GTag) {
|
||||||
o.path = v
|
o.path = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClientWithCookies(v ...string) ClientOption {
|
func GTagWithCookies(v ...string) GTagOption {
|
||||||
return func(o *Client) {
|
return func(o *GTag) {
|
||||||
o.cookies = append(o.cookies, v...)
|
o.cookies = append(o.cookies, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClientWithMiddlewares(v ...ClientMiddleware) ClientOption {
|
func GTagWithMiddlewares(v ...GTagMiddleware) GTagOption {
|
||||||
return func(o *Client) {
|
return func(o *GTag) {
|
||||||
o.middlewares = append(o.middlewares, v...)
|
o.middlewares = append(o.middlewares, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,8 +58,8 @@ func ClientWithMiddlewares(v ...ClientMiddleware) ClientOption {
|
|||||||
// ~ Constructor
|
// ~ Constructor
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
func NewClient(l *zap.Logger, host, trackingID string, opts ...ClientOption) *Client {
|
func NewGTag(l *zap.Logger, host, trackingID string, opts ...GTagOption) *GTag {
|
||||||
inst := &Client{
|
inst := >ag{
|
||||||
l: l,
|
l: l,
|
||||||
host: host,
|
host: host,
|
||||||
path: "/g/collect",
|
path: "/g/collect",
|
||||||
@ -71,14 +72,12 @@ func NewClient(l *zap.Logger, host, trackingID string, opts ...ClientOption) *Cl
|
|||||||
opt(inst)
|
opt(inst)
|
||||||
}
|
}
|
||||||
inst.middlewares = append(inst.middlewares,
|
inst.middlewares = append(inst.middlewares,
|
||||||
MiddlewareRichsstsse,
|
GTagMiddlewareRichsstsse,
|
||||||
MiddlewareTrackingID(inst.trackingID),
|
GTagMiddlewareTrackingID(inst.trackingID),
|
||||||
// MiddlewarIgnoreReferrer("1"),
|
GTagMiddlewarProtocolVersion("2"),
|
||||||
MiddlewarProtocolVersion("2"),
|
GTagMiddlewarIsDebug,
|
||||||
// MiddlewarDebug,
|
GTagMiddlewarClientID,
|
||||||
MiddlewarClientID,
|
GTagMiddlewarSessionID(inst.trackingID),
|
||||||
MiddlewarSessionID(inst.trackingID),
|
|
||||||
MiddlewarDocument,
|
|
||||||
)
|
)
|
||||||
return inst
|
return inst
|
||||||
}
|
}
|
||||||
@ -87,7 +86,7 @@ func NewClient(l *zap.Logger, host, trackingID string, opts ...ClientOption) *Cl
|
|||||||
// ~ Getter
|
// ~ Getter
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
func (c *Client) HTTPClient() *http.Client {
|
func (c *GTag) HTTPClient() *http.Client {
|
||||||
return c.httpClient
|
return c.httpClient
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,32 +94,24 @@ func (c *Client) HTTPClient() *http.Client {
|
|||||||
// ~ Public methods
|
// ~ Public methods
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
func (c *Client) Send(r *http.Request, event Marshler) error {
|
func (c *GTag) Send(r *http.Request, payload *gtag.Payload) error {
|
||||||
e, err := event.MarshalMPv2()
|
next := c.SendRaw
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return c.SendEvent(r, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) SendEvent(r *http.Request, event *Payload) error {
|
|
||||||
next := c.SendRawEvent
|
|
||||||
for _, middleware := range c.middlewares {
|
for _, middleware := range c.middlewares {
|
||||||
next = middleware(next)
|
next = middleware(next)
|
||||||
}
|
}
|
||||||
return next(r, event)
|
return next(r, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) SendRawEvent(r *http.Request, event *Payload) error {
|
func (c *GTag) SendRaw(r *http.Request, payload *gtag.Payload) error {
|
||||||
values, body, err := Encode(event)
|
values, body, err := gtag.Encode(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to encode event")
|
return errors.Wrap(err, "failed to encode payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(
|
req, err := http.NewRequestWithContext(
|
||||||
r.Context(),
|
r.Context(),
|
||||||
http.MethodPost,
|
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,
|
body,
|
||||||
)
|
)
|
||||||
if err != nil {
|
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",
|
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",
|
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",
|
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",
|
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 {
|
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"`
|
// 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
|
// If an event contains this parameters it won't be processed and it will show on on the debug View in GA4
|
||||||
// Example: 1
|
// 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
|
// If the current request has a referrer, it will be ignored at processing level
|
||||||
// Example: 1
|
// Example: 1
|
||||||
// IgnoreReferrer *string `json:"ignore_referrer,omitempty" gtag:"ir,omitempty"`
|
// IgnoreReferrer *string `json:"ignore_referrer,omitempty" gtag:"ir,omitempty"`
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type AddPaymentInfo sesamy.Event[params.AddPaymentInfo[params.Item]]
|
type AddPaymentInfo sesamy.Event[params.AddPaymentInfo[params.Item]]
|
||||||
|
|
||||||
func NewAddPaymentInfo(p params.AddPaymentInfo[params.Item]) AddPaymentInfo {
|
func NewAddPaymentInfo(p params.AddPaymentInfo[params.Item]) sesamy.Event[params.AddPaymentInfo[params.Item]] {
|
||||||
return AddPaymentInfo(sesamy.NewEvent(sesamy.EventNameAddPaymentInfo, p))
|
return sesamy.NewEvent(sesamy.EventNameAddPaymentInfo, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type AddShippingInfo sesamy.Event[params.AddShippingInfo[params.Item]]
|
type AddShippingInfo sesamy.Event[params.AddShippingInfo[params.Item]]
|
||||||
|
|
||||||
func NewAddShippingInfo(p params.AddShippingInfo[params.Item]) AddShippingInfo {
|
func NewAddShippingInfo(p params.AddShippingInfo[params.Item]) sesamy.Event[params.AddShippingInfo[params.Item]] {
|
||||||
return AddShippingInfo(sesamy.NewEvent(sesamy.EventNameAddShippingInfo, p))
|
return sesamy.NewEvent(sesamy.EventNameAddShippingInfo, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type AddToCart sesamy.Event[params.AddToCart[params.Item]]
|
type AddToCart sesamy.Event[params.AddToCart[params.Item]]
|
||||||
|
|
||||||
func NewAddToCart(p params.AddToCart[params.Item]) AddToCart {
|
func NewAddToCart(p params.AddToCart[params.Item]) sesamy.Event[params.AddToCart[params.Item]] {
|
||||||
return AddToCart(sesamy.NewEvent(sesamy.EventNameAddToCart, p))
|
return sesamy.NewEvent(sesamy.EventNameAddToCart, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type AddToWishlist sesamy.Event[params.AddToWishlist[params.Item]]
|
type AddToWishlist sesamy.Event[params.AddToWishlist[params.Item]]
|
||||||
|
|
||||||
func NewAddToWishlist(p params.AddToWishlist[params.Item]) AddToWishlist {
|
func NewAddToWishlist(p params.AddToWishlist[params.Item]) sesamy.Event[params.AddToWishlist[params.Item]] {
|
||||||
return AddToWishlist(sesamy.NewEvent(sesamy.EventNameAddToWishlist, p))
|
return sesamy.NewEvent(sesamy.EventNameAddToWishlist, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type AdImpression sesamy.Event[params.AdImpression]
|
type AdImpression sesamy.Event[params.AdImpression]
|
||||||
|
|
||||||
func NewAdImpression(p params.AdImpression) AdImpression {
|
func NewAdImpression(p params.AdImpression) sesamy.Event[params.AdImpression] {
|
||||||
return AdImpression(sesamy.NewEvent(sesamy.EventNameAdImpression, p))
|
return sesamy.NewEvent(sesamy.EventNameAdImpression, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type BeginCheckout sesamy.Event[params.BeginCheckout[params.Item]]
|
type BeginCheckout sesamy.Event[params.BeginCheckout[params.Item]]
|
||||||
|
|
||||||
func NewBeginCheckout(p params.BeginCheckout[params.Item]) BeginCheckout {
|
func NewBeginCheckout(p params.BeginCheckout[params.Item]) sesamy.Event[params.BeginCheckout[params.Item]] {
|
||||||
return BeginCheckout(sesamy.NewEvent(sesamy.EventNameBeginCheckout, p))
|
return sesamy.NewEvent(sesamy.EventNameBeginCheckout, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type CampaignDetails sesamy.Event[params.CampaignDetails]
|
type CampaignDetails sesamy.Event[params.CampaignDetails]
|
||||||
|
|
||||||
func NewCampaignDetails(p params.CampaignDetails) CampaignDetails {
|
func NewCampaignDetails(p params.CampaignDetails) sesamy.Event[params.CampaignDetails] {
|
||||||
return CampaignDetails(sesamy.NewEvent(sesamy.EventNameCampaignDetails, p))
|
return sesamy.NewEvent(sesamy.EventNameCampaignDetails, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type Click sesamy.Event[params.Click]
|
type Click sesamy.Event[params.Click]
|
||||||
|
|
||||||
func NewClick(p params.Click) Click {
|
func NewClick(p params.Click) sesamy.Event[params.Click] {
|
||||||
return Click(sesamy.NewEvent(sesamy.EventNameClick, p))
|
return sesamy.NewEvent(sesamy.EventNameClick, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type EarnVirtualMoney sesamy.Event[params.EarnVirtualMoney]
|
type EarnVirtualMoney sesamy.Event[params.EarnVirtualMoney]
|
||||||
|
|
||||||
func NewEarnVirtualMoney(p params.EarnVirtualMoney) EarnVirtualMoney {
|
func NewEarnVirtualMoney(p params.EarnVirtualMoney) sesamy.Event[params.EarnVirtualMoney] {
|
||||||
return EarnVirtualMoney(sesamy.NewEvent(sesamy.EventNameEarnVirtualMoney, p))
|
return sesamy.NewEvent(sesamy.EventNameEarnVirtualMoney, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type FileDownload sesamy.Event[params.FileDownload]
|
type FileDownload sesamy.Event[params.FileDownload]
|
||||||
|
|
||||||
func NewFileDownload(p params.FileDownload) FileDownload {
|
func NewFileDownload(p params.FileDownload) sesamy.Event[params.FileDownload] {
|
||||||
return FileDownload(sesamy.NewEvent(sesamy.EventNameFileDownload, p))
|
return sesamy.NewEvent(sesamy.EventNameFileDownload, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type FormStart sesamy.Event[params.FormStart]
|
type FormStart sesamy.Event[params.FormStart]
|
||||||
|
|
||||||
func NewFormStart(p params.FormStart) FormStart {
|
func NewFormStart(p params.FormStart) sesamy.Event[params.FormStart] {
|
||||||
return FormStart(sesamy.NewEvent(sesamy.EventNameFormStart, p))
|
return sesamy.NewEvent(sesamy.EventNameFormStart, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type FormSubmit sesamy.Event[params.FormSubmit]
|
type FormSubmit sesamy.Event[params.FormSubmit]
|
||||||
|
|
||||||
func NewFormSubmit(p params.FormSubmit) FormSubmit {
|
func NewFormSubmit(p params.FormSubmit) sesamy.Event[params.FormSubmit] {
|
||||||
return FormSubmit(sesamy.NewEvent(sesamy.EventNameFormSubmit, p))
|
return sesamy.NewEvent(sesamy.EventNameFormSubmit, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type GenerateLead sesamy.Event[params.GenerateLead]
|
type GenerateLead sesamy.Event[params.GenerateLead]
|
||||||
|
|
||||||
func NewGenerateLead(p params.GenerateLead) GenerateLead {
|
func NewGenerateLead(p params.GenerateLead) sesamy.Event[params.GenerateLead] {
|
||||||
return GenerateLead(sesamy.NewEvent(sesamy.EventNameGenerateLead, p))
|
return sesamy.NewEvent(sesamy.EventNameGenerateLead, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type JoinGroup sesamy.Event[params.JoinGroup]
|
type JoinGroup sesamy.Event[params.JoinGroup]
|
||||||
|
|
||||||
func NewJoinGroup(p params.JoinGroup) JoinGroup {
|
func NewJoinGroup(p params.JoinGroup) sesamy.Event[params.JoinGroup] {
|
||||||
return JoinGroup(sesamy.NewEvent(sesamy.EventNameJoinGroup, p))
|
return sesamy.NewEvent(sesamy.EventNameJoinGroup, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type LevelEnd sesamy.Event[params.LevelEnd]
|
type LevelEnd sesamy.Event[params.LevelEnd]
|
||||||
|
|
||||||
func NewLevelEnd(p params.LevelEnd) LevelEnd {
|
func NewLevelEnd(p params.LevelEnd) sesamy.Event[params.LevelEnd] {
|
||||||
return LevelEnd(sesamy.NewEvent(sesamy.EventNameLevelEnd, p))
|
return sesamy.NewEvent(sesamy.EventNameLevelEnd, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type LevelStart sesamy.Event[params.LevelStart]
|
type LevelStart sesamy.Event[params.LevelStart]
|
||||||
|
|
||||||
func NewLevelStart(p params.LevelStart) LevelStart {
|
func NewLevelStart(p params.LevelStart) sesamy.Event[params.LevelStart] {
|
||||||
return LevelStart(sesamy.NewEvent(sesamy.EventNameLevelStart, p))
|
return sesamy.NewEvent(sesamy.EventNameLevelStart, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type LevelUp sesamy.Event[params.LevelUp]
|
type LevelUp sesamy.Event[params.LevelUp]
|
||||||
|
|
||||||
func NewLevelUp(p params.LevelUp) LevelUp {
|
func NewLevelUp(p params.LevelUp) sesamy.Event[params.LevelUp] {
|
||||||
return LevelUp(sesamy.NewEvent(sesamy.EventNameLevelUp, p))
|
return sesamy.NewEvent(sesamy.EventNameLevelUp, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type Login sesamy.Event[params.Login]
|
type Login sesamy.Event[params.Login]
|
||||||
|
|
||||||
func NewLogin(p params.Login) Login {
|
func NewLogin(p params.Login) sesamy.Event[params.Login] {
|
||||||
return Login(sesamy.NewEvent(sesamy.EventNameLogin, p))
|
return sesamy.NewEvent(sesamy.EventNameLogin, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type PageView sesamy.Event[params.PageView]
|
type PageView sesamy.Event[params.PageView]
|
||||||
|
|
||||||
func NewPageView(p params.PageView) PageView {
|
func NewPageView(p params.PageView) sesamy.Event[params.PageView] {
|
||||||
return PageView(sesamy.NewEvent(sesamy.EventNamePageView, p))
|
return sesamy.NewEvent(sesamy.EventNamePageView, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type PostScore sesamy.Event[params.PostScore]
|
type PostScore sesamy.Event[params.PostScore]
|
||||||
|
|
||||||
func NewPostScore(p params.PostScore) PostScore {
|
func NewPostScore(p params.PostScore) sesamy.Event[params.PostScore] {
|
||||||
return PostScore(sesamy.NewEvent(sesamy.EventNamePostScore, p))
|
return sesamy.NewEvent(sesamy.EventNamePostScore, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type Purchase sesamy.Event[params.Purchase[params.Item]]
|
type Purchase sesamy.Event[params.Purchase[params.Item]]
|
||||||
|
|
||||||
func NewPurchase(p params.Purchase[params.Item]) Purchase {
|
func NewPurchase(p params.Purchase[params.Item]) sesamy.Event[params.Purchase[params.Item]] {
|
||||||
return Purchase(sesamy.NewEvent(sesamy.EventNamePurchase, p))
|
return sesamy.NewEvent(sesamy.EventNamePurchase, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type Refund sesamy.Event[params.Refund[params.Item]]
|
type Refund sesamy.Event[params.Refund[params.Item]]
|
||||||
|
|
||||||
func NewRefund(p params.Refund[params.Item]) Refund {
|
func NewRefund(p params.Refund[params.Item]) sesamy.Event[params.Refund[params.Item]] {
|
||||||
return Refund(sesamy.NewEvent(sesamy.EventNameRefund, p))
|
return sesamy.NewEvent(sesamy.EventNameRefund, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type RemoveFromCart sesamy.Event[params.RemoveFromCart[params.Item]]
|
type RemoveFromCart sesamy.Event[params.RemoveFromCart[params.Item]]
|
||||||
|
|
||||||
func NewRemoveFromCart(p params.RemoveFromCart[params.Item]) RemoveFromCart {
|
func NewRemoveFromCart(p params.RemoveFromCart[params.Item]) sesamy.Event[params.RemoveFromCart[params.Item]] {
|
||||||
return RemoveFromCart(sesamy.NewEvent(sesamy.EventNameRemoveFromCart, p))
|
return sesamy.NewEvent(sesamy.EventNameRemoveFromCart, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type ScreenView sesamy.Event[params.ScreenView]
|
type ScreenView sesamy.Event[params.ScreenView]
|
||||||
|
|
||||||
func NewScreenView(p params.ScreenView) ScreenView {
|
func NewScreenView(p params.ScreenView) sesamy.Event[params.ScreenView] {
|
||||||
return ScreenView(sesamy.NewEvent(sesamy.EventNameScreenView, p))
|
return sesamy.NewEvent(sesamy.EventNameScreenView, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type Scroll sesamy.Event[params.Scroll]
|
type Scroll sesamy.Event[params.Scroll]
|
||||||
|
|
||||||
func NewScroll(p params.Scroll) Scroll {
|
func NewScroll(p params.Scroll) sesamy.Event[params.Scroll] {
|
||||||
return Scroll(sesamy.NewEvent(sesamy.EventNameScroll, p))
|
return sesamy.NewEvent(sesamy.EventNameScroll, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type Search sesamy.Event[params.Search]
|
type Search sesamy.Event[params.Search]
|
||||||
|
|
||||||
func NewSearch(p params.Search) Search {
|
func NewSearch(p params.Search) sesamy.Event[params.Search] {
|
||||||
return Search(sesamy.NewEvent(sesamy.EventNameSearch, p))
|
return sesamy.NewEvent(sesamy.EventNameSearch, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type SelectContent sesamy.Event[params.SelectContent]
|
type SelectContent sesamy.Event[params.SelectContent]
|
||||||
|
|
||||||
func NewSelectContent(p params.SelectContent) SelectContent {
|
func NewSelectContent(p params.SelectContent) sesamy.Event[params.SelectContent] {
|
||||||
return SelectContent(sesamy.NewEvent(sesamy.EventNameSelectContent, p))
|
return sesamy.NewEvent(sesamy.EventNameSelectContent, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type SelectItem sesamy.Event[params.SelectItem[params.Item]]
|
type SelectItem sesamy.Event[params.SelectItem[params.Item]]
|
||||||
|
|
||||||
func NewSelectItem(p params.SelectItem[params.Item]) SelectItem {
|
func NewSelectItem(p params.SelectItem[params.Item]) sesamy.Event[params.SelectItem[params.Item]] {
|
||||||
return SelectItem(sesamy.NewEvent(sesamy.EventNameSelectItem, p))
|
return sesamy.NewEvent(sesamy.EventNameSelectItem, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type SelectPromotion sesamy.Event[params.SelectPromotion[params.Item]]
|
type SelectPromotion sesamy.Event[params.SelectPromotion[params.Item]]
|
||||||
|
|
||||||
func NewSelectPromotion(p params.SelectPromotion[params.Item]) SelectPromotion {
|
func NewSelectPromotion(p params.SelectPromotion[params.Item]) sesamy.Event[params.SelectPromotion[params.Item]] {
|
||||||
return SelectPromotion(sesamy.NewEvent(sesamy.EventNameSelectPromotion, p))
|
return sesamy.NewEvent(sesamy.EventNameSelectPromotion, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type SessionStart sesamy.Event[params.SessionStart]
|
type SessionStart sesamy.Event[params.SessionStart]
|
||||||
|
|
||||||
func NewSessionStart(p params.SessionStart) SessionStart {
|
func NewSessionStart(p params.SessionStart) sesamy.Event[params.SessionStart] {
|
||||||
return SessionStart(sesamy.NewEvent(sesamy.EventNameSessionStart, p))
|
return sesamy.NewEvent(sesamy.EventNameSessionStart, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type Share sesamy.Event[params.Share]
|
type Share sesamy.Event[params.Share]
|
||||||
|
|
||||||
func NewShare(p params.Share) Share {
|
func NewShare(p params.Share) sesamy.Event[params.Share] {
|
||||||
return Share(sesamy.NewEvent(sesamy.EventNameShare, p))
|
return sesamy.NewEvent(sesamy.EventNameShare, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type SignUp sesamy.Event[params.SignUp]
|
type SignUp sesamy.Event[params.SignUp]
|
||||||
|
|
||||||
func NewSignUp(p params.SignUp) SignUp {
|
func NewSignUp(p params.SignUp) sesamy.Event[params.SignUp] {
|
||||||
return SignUp(sesamy.NewEvent(sesamy.EventNameSignUp, p))
|
return sesamy.NewEvent(sesamy.EventNameSignUp, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type SpendVirtualCurrency sesamy.Event[params.SpendVirtualCurrency]
|
type SpendVirtualCurrency sesamy.Event[params.SpendVirtualCurrency]
|
||||||
|
|
||||||
func NewSpendVirtualCurrency(p params.SpendVirtualCurrency) SpendVirtualCurrency {
|
func NewSpendVirtualCurrency(p params.SpendVirtualCurrency) sesamy.Event[params.SpendVirtualCurrency] {
|
||||||
return SpendVirtualCurrency(sesamy.NewEvent(sesamy.EventNameSpendVirtualCurrency, p))
|
return sesamy.NewEvent(sesamy.EventNameSpendVirtualCurrency, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type TutorialBegin sesamy.Event[params.TutorialBegin]
|
type TutorialBegin sesamy.Event[params.TutorialBegin]
|
||||||
|
|
||||||
func NewTutorialBegin(p params.TutorialBegin) TutorialBegin {
|
func NewTutorialBegin(p params.TutorialBegin) sesamy.Event[params.TutorialBegin] {
|
||||||
return TutorialBegin(sesamy.NewEvent(sesamy.EventNameTutorialBegin, p))
|
return sesamy.NewEvent(sesamy.EventNameTutorialBegin, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type TutorialComplete sesamy.Event[params.TutorialComplete]
|
type TutorialComplete sesamy.Event[params.TutorialComplete]
|
||||||
|
|
||||||
func NewTutorialComplete(p params.TutorialComplete) TutorialComplete {
|
func NewTutorialComplete(p params.TutorialComplete) sesamy.Event[params.TutorialComplete] {
|
||||||
return TutorialComplete(sesamy.NewEvent(sesamy.EventNameTutorialComplete, p))
|
return sesamy.NewEvent(sesamy.EventNameTutorialComplete, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type UnlockAchievement sesamy.Event[params.UnlockAchievement]
|
type UnlockAchievement sesamy.Event[params.UnlockAchievement]
|
||||||
|
|
||||||
func NewUnlockArchievement(p params.UnlockAchievement) UnlockAchievement {
|
func NewUnlockAchievement(p params.UnlockAchievement) sesamy.Event[params.UnlockAchievement] {
|
||||||
return UnlockAchievement(sesamy.NewEvent(sesamy.EventNameUnlockAchievement, p))
|
return sesamy.NewEvent(sesamy.EventNameUnlockAchievement, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type UserEngagement sesamy.Event[params.UserEngagement]
|
type UserEngagement sesamy.Event[params.UserEngagement]
|
||||||
|
|
||||||
func NewUserEngagement(p params.UserEngagement) UserEngagement {
|
func NewUserEngagement(p params.UserEngagement) sesamy.Event[params.UserEngagement] {
|
||||||
return UserEngagement(sesamy.NewEvent(sesamy.EventNameUserEngagement, p))
|
return sesamy.NewEvent(sesamy.EventNameUserEngagement, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type VideoComplete sesamy.Event[params.VideoComplete]
|
type VideoComplete sesamy.Event[params.VideoComplete]
|
||||||
|
|
||||||
func NewVideoComplete(p params.VideoComplete) VideoComplete {
|
func NewVideoComplete(p params.VideoComplete) sesamy.Event[params.VideoComplete] {
|
||||||
return VideoComplete(sesamy.NewEvent(sesamy.EventNameVideoComplete, p))
|
return sesamy.NewEvent(sesamy.EventNameVideoComplete, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type VideoProgress sesamy.Event[params.VideoProgress]
|
type VideoProgress sesamy.Event[params.VideoProgress]
|
||||||
|
|
||||||
func NewVideoProgress(p params.VideoProgress) VideoProgress {
|
func NewVideoProgress(p params.VideoProgress) sesamy.Event[params.VideoProgress] {
|
||||||
return VideoProgress(sesamy.NewEvent(sesamy.EventNameVideoProgress, p))
|
return sesamy.NewEvent(sesamy.EventNameVideoProgress, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type VideoStart sesamy.Event[params.VideoStart]
|
type VideoStart sesamy.Event[params.VideoStart]
|
||||||
|
|
||||||
func NewVideoStart(p params.VideoStart) VideoStart {
|
func NewVideoStart(p params.VideoStart) sesamy.Event[params.VideoStart] {
|
||||||
return VideoStart(sesamy.NewEvent(sesamy.EventNameVideoStart, p))
|
return sesamy.NewEvent(sesamy.EventNameVideoStart, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type ViewCart sesamy.Event[params.ViewCart[params.Item]]
|
type ViewCart sesamy.Event[params.ViewCart[params.Item]]
|
||||||
|
|
||||||
func NewViewCart(p params.ViewCart[params.Item]) ViewCart {
|
func NewViewCart(p params.ViewCart[params.Item]) sesamy.Event[params.ViewCart[params.Item]] {
|
||||||
return ViewCart(sesamy.NewEvent(sesamy.EventNameViewCart, p))
|
return sesamy.NewEvent(sesamy.EventNameViewCart, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type ViewItem sesamy.Event[params.ViewItem[params.Item]]
|
type ViewItem sesamy.Event[params.ViewItem[params.Item]]
|
||||||
|
|
||||||
func NewViewItem(p params.ViewItem[params.Item]) ViewItem {
|
func NewViewItem(p params.ViewItem[params.Item]) sesamy.Event[params.ViewItem[params.Item]] {
|
||||||
return ViewItem(sesamy.NewEvent(sesamy.EventNameViewItem, p))
|
return sesamy.NewEvent(sesamy.EventNameViewItem, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type ViewItemList sesamy.Event[params.ViewItemList[params.Item]]
|
type ViewItemList sesamy.Event[params.ViewItemList[params.Item]]
|
||||||
|
|
||||||
func NewViewItemList(p params.ViewItemList[params.Item]) ViewItemList {
|
func NewViewItemList(p params.ViewItemList[params.Item]) sesamy.Event[params.ViewItemList[params.Item]] {
|
||||||
return ViewItemList(sesamy.NewEvent(sesamy.EventNameViewItemList, p))
|
return sesamy.NewEvent(sesamy.EventNameViewItemList, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type ViewPromotion sesamy.Event[params.ViewPromotion[params.Item]]
|
type ViewPromotion sesamy.Event[params.ViewPromotion[params.Item]]
|
||||||
|
|
||||||
func NewViewPromotion(p params.ViewPromotion[params.Item]) ViewPromotion {
|
func NewViewPromotion(p params.ViewPromotion[params.Item]) sesamy.Event[params.ViewPromotion[params.Item]] {
|
||||||
return ViewPromotion(sesamy.NewEvent(sesamy.EventNameViewPromotion, p))
|
return sesamy.NewEvent(sesamy.EventNameViewPromotion, p)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ import (
|
|||||||
|
|
||||||
type ViewSearchResults sesamy.Event[params.ViewSearchResults]
|
type ViewSearchResults sesamy.Event[params.ViewSearchResults]
|
||||||
|
|
||||||
func NewViewSearchResults(p params.ViewSearchResults) ViewSearchResults {
|
func NewViewSearchResults(p params.ViewSearchResults) sesamy.Event[params.ViewSearchResults] {
|
||||||
return ViewSearchResults(sesamy.NewEvent(sesamy.EventNameViewSearchResults, p))
|
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,
|
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