149 lines
5.1 KiB
Go
149 lines
5.1 KiB
Go
package statisticsclient
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type ActivityTemplateDataQuery struct {
|
|
AppCode string
|
|
TemplateID string
|
|
PublishedVersion int64
|
|
RegionID int64
|
|
StartMS int64
|
|
EndMS int64
|
|
}
|
|
|
|
type ActivityTemplateOverview struct {
|
|
TemplateID string `json:"template_id"`
|
|
TemplateCode string `json:"template_code"`
|
|
PublishedVersion int64 `json:"published_version"`
|
|
Participants int64 `json:"participants"`
|
|
VisitCount int64 `json:"visit_count"`
|
|
GiftUsers int64 `json:"gift_users"`
|
|
TaskUsers int64 `json:"task_users"`
|
|
GiftEventCount int64 `json:"gift_event_count"`
|
|
GiftCount int64 `json:"gift_count"`
|
|
CoinAmount int64 `json:"coin_amount"`
|
|
TaskProgress int64 `json:"task_progress"`
|
|
TaskCompleted int64 `json:"task_completed"`
|
|
TaskClaimed int64 `json:"task_claimed"`
|
|
}
|
|
|
|
type ActivityTemplateTrendPoint struct {
|
|
StatDay string `json:"stat_day"`
|
|
Participants int64 `json:"participants"`
|
|
VisitCount int64 `json:"visit_count"`
|
|
GiftUsers int64 `json:"gift_users"`
|
|
TaskUsers int64 `json:"task_users"`
|
|
GiftEventCount int64 `json:"gift_event_count"`
|
|
GiftCount int64 `json:"gift_count"`
|
|
CoinAmount int64 `json:"coin_amount"`
|
|
TaskProgress int64 `json:"task_progress"`
|
|
TaskCompleted int64 `json:"task_completed"`
|
|
TaskClaimed int64 `json:"task_claimed"`
|
|
}
|
|
|
|
type ActivityTemplateGiftStat struct {
|
|
GiftID string `json:"gift_id"`
|
|
GiftUsers int64 `json:"gift_users"`
|
|
GiftEventCount int64 `json:"gift_event_count"`
|
|
GiftCount int64 `json:"gift_count"`
|
|
CoinAmount int64 `json:"coin_amount"`
|
|
}
|
|
|
|
type ActivityTemplateTaskStat struct {
|
|
TaskKey string `json:"task_key"`
|
|
TaskType string `json:"task_type"`
|
|
TaskUsers int64 `json:"task_users"`
|
|
TaskProgress int64 `json:"task_progress"`
|
|
TaskCompleted int64 `json:"task_completed"`
|
|
TaskClaimed int64 `json:"task_claimed"`
|
|
}
|
|
|
|
// ActivityTemplateData mirrors statistics-service's aggregate-only read model.
|
|
// Admin intentionally does not reconstruct any of these counters from activity owner tables.
|
|
type ActivityTemplateData struct {
|
|
Overview ActivityTemplateOverview `json:"overview"`
|
|
Trend []ActivityTemplateTrendPoint `json:"trend"`
|
|
Gifts []ActivityTemplateGiftStat `json:"gifts"`
|
|
Tasks []ActivityTemplateTaskStat `json:"tasks"`
|
|
Granularity string `json:"granularity"`
|
|
Timezone string `json:"timezone"`
|
|
StartMS int64 `json:"start_ms"`
|
|
EndMS int64 `json:"end_ms"`
|
|
RegionID int64 `json:"region_id"`
|
|
DimensionLimit int `json:"dimension_limit"`
|
|
GiftSort string `json:"gift_sort"`
|
|
TaskSort string `json:"task_sort"`
|
|
ServerTimeMS int64 `json:"server_time_ms"`
|
|
}
|
|
|
|
type ActivityTemplateDataClient interface {
|
|
ActivityTemplateData(context.Context, ActivityTemplateDataQuery) (ActivityTemplateData, error)
|
|
}
|
|
|
|
type HTTPClient struct {
|
|
baseURL string
|
|
client *http.Client
|
|
}
|
|
|
|
func NewHTTP(baseURL string, timeout time.Duration) *HTTPClient {
|
|
if timeout <= 0 {
|
|
timeout = 3 * time.Second
|
|
}
|
|
return &HTTPClient{
|
|
baseURL: strings.TrimRight(strings.TrimSpace(baseURL), "/"),
|
|
client: &http.Client{Timeout: timeout},
|
|
}
|
|
}
|
|
|
|
func (c *HTTPClient) ActivityTemplateData(ctx context.Context, query ActivityTemplateDataQuery) (ActivityTemplateData, error) {
|
|
values := url.Values{}
|
|
values.Set("app_code", strings.TrimSpace(query.AppCode))
|
|
values.Set("template_id", strings.TrimSpace(query.TemplateID))
|
|
values.Set("published_version", strconv.FormatInt(query.PublishedVersion, 10))
|
|
values.Set("start_ms", strconv.FormatInt(query.StartMS, 10))
|
|
values.Set("end_ms", strconv.FormatInt(query.EndMS, 10))
|
|
if query.RegionID > 0 {
|
|
values.Set("region_id", strconv.FormatInt(query.RegionID, 10))
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.baseURL+"/internal/v1/statistics/activity-templates/data?"+values.Encode(), nil)
|
|
if err != nil {
|
|
return ActivityTemplateData{}, err
|
|
}
|
|
resp, err := c.client.Do(req)
|
|
if err != nil {
|
|
return ActivityTemplateData{}, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
|
|
var body struct {
|
|
Error string `json:"error"`
|
|
}
|
|
_ = json.NewDecoder(resp.Body).Decode(&body)
|
|
return ActivityTemplateData{}, fmt.Errorf("statistics service returned status %d: %s", resp.StatusCode, strings.TrimSpace(body.Error))
|
|
}
|
|
var out ActivityTemplateData
|
|
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
|
|
return ActivityTemplateData{}, err
|
|
}
|
|
// Arrays must remain arrays for dense table/chart clients; nil would serialize as null and force needless branches.
|
|
if out.Trend == nil {
|
|
out.Trend = []ActivityTemplateTrendPoint{}
|
|
}
|
|
if out.Gifts == nil {
|
|
out.Gifts = []ActivityTemplateGiftStat{}
|
|
}
|
|
if out.Tasks == nil {
|
|
out.Tasks = []ActivityTemplateTaskStat{}
|
|
}
|
|
return out, nil
|
|
}
|