144 lines
4.8 KiB
Go
144 lines
4.8 KiB
Go
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type AppTrackingEvent struct {
|
|
AppCode string `json:"app_code"`
|
|
EventID string `json:"event_id"`
|
|
EventName string `json:"event_name"`
|
|
EventType string `json:"event_type"`
|
|
Screen string `json:"screen"`
|
|
TargetType string `json:"target_type"`
|
|
TargetID string `json:"target_id"`
|
|
UserID int64 `json:"user_id"`
|
|
DeviceID string `json:"device_id"`
|
|
SessionID string `json:"session_id"`
|
|
Platform string `json:"platform"`
|
|
AppVersion string `json:"app_version"`
|
|
Language string `json:"language"`
|
|
Timezone string `json:"timezone"`
|
|
CountryID int64 `json:"country_id"`
|
|
RegionID int64 `json:"region_id"`
|
|
DurationMS int64 `json:"duration_ms"`
|
|
Success bool `json:"success"`
|
|
ErrorCode string `json:"error_code"`
|
|
Properties json.RawMessage `json:"properties,omitempty"`
|
|
OccurredAtMS int64 `json:"occurred_at_ms"`
|
|
}
|
|
|
|
type AppTrackingReportResult struct {
|
|
Accepted bool `json:"accepted"`
|
|
Received int `json:"received"`
|
|
Stored int `json:"stored"`
|
|
Duplicated int `json:"duplicated"`
|
|
ServerTimeMS int64 `json:"server_time_ms"`
|
|
}
|
|
|
|
type SelfGameH5Event struct {
|
|
AppCode string `json:"app_code"`
|
|
EventID string `json:"event_id"`
|
|
EventName string `json:"event_name"`
|
|
GameID string `json:"game_id"`
|
|
Page string `json:"page"`
|
|
SessionID string `json:"session_id"`
|
|
MatchID string `json:"match_id"`
|
|
UserID int64 `json:"user_id"`
|
|
CountryID int64 `json:"country_id"`
|
|
RegionID int64 `json:"region_id"`
|
|
Language string `json:"language"`
|
|
ClientVersion string `json:"client_version"`
|
|
H5Version string `json:"h5_version"`
|
|
EntrySource string `json:"entry_source"`
|
|
DurationMS int64 `json:"duration_ms"`
|
|
Success bool `json:"success"`
|
|
ErrorCode string `json:"error_code"`
|
|
OccurredAtMS int64 `json:"occurred_at_ms"`
|
|
}
|
|
|
|
type StatisticsClient interface {
|
|
ReportSelfGameH5Event(ctx context.Context, event SelfGameH5Event) error
|
|
ReportAppTrackingEvents(ctx context.Context, events []AppTrackingEvent) (AppTrackingReportResult, error)
|
|
}
|
|
|
|
type HTTPStatisticsClient struct {
|
|
baseURL string
|
|
httpClient *http.Client
|
|
}
|
|
|
|
func NewHTTPStatisticsClient(baseURL string, timeout time.Duration) *HTTPStatisticsClient {
|
|
baseURL = strings.TrimRight(strings.TrimSpace(baseURL), "/")
|
|
if baseURL == "" {
|
|
return nil
|
|
}
|
|
if timeout <= 0 {
|
|
timeout = 2 * time.Second
|
|
}
|
|
return &HTTPStatisticsClient{
|
|
baseURL: baseURL,
|
|
httpClient: &http.Client{Timeout: timeout},
|
|
}
|
|
}
|
|
|
|
func (c *HTTPStatisticsClient) ReportSelfGameH5Event(ctx context.Context, event SelfGameH5Event) error {
|
|
if c == nil || c.httpClient == nil || c.baseURL == "" {
|
|
return fmt.Errorf("statistics client is not configured")
|
|
}
|
|
body, err := json.Marshal(event)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/internal/v1/statistics/self-game/events", bytes.NewReader(body))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := c.httpClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
|
return nil
|
|
}
|
|
payload, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
|
|
return fmt.Errorf("statistics report failed: status=%d body=%s", resp.StatusCode, strings.TrimSpace(string(payload)))
|
|
}
|
|
|
|
func (c *HTTPStatisticsClient) ReportAppTrackingEvents(ctx context.Context, events []AppTrackingEvent) (AppTrackingReportResult, error) {
|
|
if c == nil || c.httpClient == nil || c.baseURL == "" {
|
|
return AppTrackingReportResult{}, fmt.Errorf("statistics client is not configured")
|
|
}
|
|
body, err := json.Marshal(map[string]any{"events": events})
|
|
if err != nil {
|
|
return AppTrackingReportResult{}, err
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/internal/v1/statistics/app/events", bytes.NewReader(body))
|
|
if err != nil {
|
|
return AppTrackingReportResult{}, err
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := c.httpClient.Do(req)
|
|
if err != nil {
|
|
return AppTrackingReportResult{}, err
|
|
}
|
|
defer resp.Body.Close()
|
|
payload, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
return AppTrackingReportResult{}, fmt.Errorf("statistics app event report failed: status=%d body=%s", resp.StatusCode, strings.TrimSpace(string(payload)))
|
|
}
|
|
var result AppTrackingReportResult
|
|
if err := json.Unmarshal(payload, &result); err != nil {
|
|
return AppTrackingReportResult{}, err
|
|
}
|
|
return result, nil
|
|
}
|