mirror of
https://github.com/hanzoai/insights-go.git
synced 2026-09-30 22:46:12 +00:00
93 lines
3.1 KiB
Go
93 lines
3.1 KiB
Go
package insights
|
|
|
|
import (
|
|
"time"
|
|
|
|
json "github.com/goccy/go-json"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// Values implementing this interface are used by insights clients to notify
|
|
// the application when a message send succeeded or failed.
|
|
//
|
|
// Callback methods are called by a client's internal goroutines. There are no
|
|
// guarantees about which goroutine triggers the callbacks, whether calls are
|
|
// made sequentially or in parallel, or whether callback order matches enqueue order.
|
|
//
|
|
// Callback methods must return quickly and avoid long blocking operations so
|
|
// they do not interfere with the client's internal workflow.
|
|
type Callback interface {
|
|
|
|
// Success is called for every message that was successfully sent to the API.
|
|
Success(APIMessage)
|
|
|
|
// Failure is called for every message that failed to be sent to the API and
|
|
// will be discarded by the client. The error describes the send or serialization failure.
|
|
Failure(APIMessage, error)
|
|
}
|
|
|
|
// This interface is used to represent insights objects that can be sent via
|
|
// a client.
|
|
//
|
|
// Types like insights.Capture, insights.Alias, etc... implement this interface
|
|
// and therefore can be passed to the insights.Client.Enqueue method.
|
|
type Message interface {
|
|
|
|
// Validate checks the internal structure of the message. It returns nil when
|
|
// the message is valid or an error describing the invalid field.
|
|
Validate() error
|
|
// APIfy converts the message into its PostHog batch API representation.
|
|
APIfy() APIMessage
|
|
|
|
// internal prevents external packages from satisfying Message. Calling it panics.
|
|
internal()
|
|
}
|
|
|
|
// Returns the time value passed as first argument, unless it's the zero-value,
|
|
// in that case the default value passed as second argument is returned.
|
|
func makeTimestamp(t time.Time, def time.Time) time.Time {
|
|
if t == (time.Time{}) {
|
|
return def
|
|
}
|
|
return t
|
|
}
|
|
|
|
// makeUUID returns the UUID passed as first argument if non-empty,
|
|
// otherwise generates and returns a new random UUID (v4).
|
|
func makeUUID(u string) string {
|
|
if u != "" {
|
|
return u
|
|
}
|
|
return uuid.New().String()
|
|
}
|
|
|
|
// batch represents objects sent to the /batch/ endpoint with pre-serialized messages.
|
|
// Messages are pre-serialized as json.RawMessage for efficient batch building -
|
|
// json.Marshal embeds them directly without re-encoding.
|
|
type batch struct {
|
|
ApiKey string `json:"api_key"`
|
|
HistoricalMigration bool `json:"historical_migration,omitempty"`
|
|
Messages []json.RawMessage `json:"batch"`
|
|
}
|
|
|
|
// APIMessage is a wire-format message produced by Message.APIfy and passed to callbacks.
|
|
type APIMessage interface{}
|
|
|
|
// prepareForSend creates the API message and serializes it to JSON.
|
|
// Returns pre-serialized JSON for efficient batch building, the original
|
|
// APIMessage for callbacks, and any serialization error.
|
|
// Size is derived from len(json.RawMessage) when needed - O(1) operation.
|
|
func prepareForSend(msg Message) (json.RawMessage, APIMessage, error) {
|
|
apiMsg := msg.APIfy()
|
|
data, err := json.Marshal(apiMsg)
|
|
if err != nil {
|
|
return nil, apiMsg, err
|
|
}
|
|
return json.RawMessage(data), apiMsg, nil
|
|
}
|
|
|
|
const (
|
|
maxBatchBytes = 500000
|
|
maxMessageBytes = 500000
|
|
)
|