no message

tags/v0.0.3^0 v0.0.3
zhuxianglong 2 months ago
parent a37ea90246
commit 0a863dd112

@ -0,0 +1,229 @@
# point - TapDB事件上报SDK / TapDB Event Reporting SDK
[中文](#中文) | [English](#english)
---
## 中文
### 📖 简介
`point` 是专为TapDB设计的线程安全事件上报SDK提供简洁的API接口和并发安全机制。采用单例模式设计内置HTTP连接池和自动重试策略适用于高并发场景下的数据上报。
GitHub地址: [gitea.weitiangame.com/sdk/wt-game/point](https://gitea.weitiangame.com/sdk/wt-game/point)
### 📦 安装
```bash
go get gitea.weitiangame.com/sdk/wt-game/point
```
### 🚀 快速开始
#### 初始化上报器
```go
package main
import (
"gitea.weitiangame.com/sdk/wt-game/point"
"go.uber.org/zap"
)
func main() {
logger, _ := zap.NewProduction()
// 创建单例上报实例自动注入client_id
reporter := point.New("your_client_id", logger)
}
```
#### 基础事件上报
```go
func main() {
reporter := point.New("game_123", zap.NewExample())
eventData := map[string]interface{}{
"event": "player_login",
"distinct_id": "user_888",
"properties": map[string]interface{}{
"level": 5,
"region": "cn",
},
}
if resp, err := reporter.Event(eventData); err != nil {
logger.Error("上报失败", zap.Error(err))
} else {
logger.Info("上报成功",
zap.Int("status", resp.StatusCode()),
zap.String("trace_id", resp.Header().Get("X-Trace-Id")))
}
}
```
### 🔧 高级用法
#### 启用调试模式
```go
func main() {
// 初始化时启用调试和CURL输出
reporter := point.New("client_123", logger).
Debug(). // 显示请求详情
Curl() // 生成CURL命令
reporter.Event(map[string]interface{}{
"event": "ad_click",
"properties": map[string]interface{}{
"ad_id": "banner_001",
},
})
}
```
#### 自定义HTTP客户端
```go
func main() {
customClient := ahttp.New(&ahttp.Config{
Timeout: 10 * time.Second,
Retries: 3,
}).Client()
point.New("game_123", logger).
SetClient(customClient). // 注入自定义客户端
Event(eventData)
}
```
### ✨ 核心特性
| 特性 | 描述 |
|---------------------|--------------------------------------------------------------------|
| **单例模式** | 全局唯一实例,避免重复创建资源 |
| **线程安全** | 基于互斥锁保护配置变更内置线程安全HTTP客户端 |
| **调试支持** | 支持请求详情输出和CURL命令生成 |
| **自动重试** | 依赖底层HTTP客户端的重试策略默认3次 |
| **数据隔离** | 自动复制传入数据,防止并发修改 |
### ⚠️ 注意事项
1. `New()` 方法为单例模式,首次调用后配置不可变更
2. `Debug()``Curl()` 建议仅在开发环境使用
3. 事件数据需包含 `event` 字段,建议包含 `distinct_id` 字段
4. HTTP响应状态码非2xx时需要检查请求参数
5. 上报数据量较大时建议批量处理
### 🤝 参与贡献
[贡献指南](CONTRIBUTING.md) | [提交Issue](https://gitea.weitiangame.com/sdk/wt-game/point/issues)
---
## English
### 📖 Introduction
`point` is a thread-safe event reporting SDK designed for TapDB, featuring a clean API and concurrency-safe mechanisms. Built with singleton pattern and HTTP connection pooling, ideal for high-concurrency data reporting scenarios.
GitHub URL: [gitea.weitiangame.com/sdk/wt-game/point](https://gitea.weitiangame.com/sdk/wt-game/point)
### 📦 Installation
```bash
go get gitea.weitiangame.com/sdk/wt-game/point
```
### 🚀 Quick Start
#### Initialize Reporter
```go
package main
import (
"gitea.weitiangame.com/sdk/wt-game/point"
"go.uber.org/zap"
)
func main() {
logger, _ := zap.NewProduction()
// Create singleton instance (auto-injects client_id)
reporter := point.New("your_client_id", logger)
}
```
#### Basic Event Reporting
```go
func main() {
reporter := point.New("game_123", zap.NewExample())
eventData := map[string]interface{}{
"event": "player_login",
"distinct_id": "user_888",
"properties": map[string]interface{}{
"level": 5,
"region": "cn",
},
}
if resp, err := reporter.Event(eventData); err != nil {
logger.Error("Report failed", zap.Error(err))
} else {
logger.Info("Report succeeded",
zap.Int("status", resp.StatusCode()),
zap.String("trace_id", resp.Header().Get("X-Trace-Id")))
}
}
```
### 🔧 Advanced Usage
#### Enable Debug Mode
```go
func main() {
// Enable debug features during initialization
reporter := point.New("client_123", logger).
Debug(). // Show request details
Curl() // Generate CURL commands
reporter.Event(map[string]interface{}{
"event": "ad_click",
"properties": map[string]interface{}{
"ad_id": "banner_001",
},
})
}
```
#### Custom HTTP Client
```go
func main() {
customClient := ahttp.New(&ahttp.Config{
Timeout: 10 * time.Second,
Retries: 3,
}).Client()
point.New("game_123", logger).
SetClient(customClient). // Inject custom client
Event(eventData)
}
```
### ✨ Key Features
| Feature | Description |
|---------------------|-----------------------------------------------------------------|
| **Singleton** | Global single instance prevents resource duplication |
| **Thread-Safe** | Mutex-protected configuration with built-in safe HTTP client |
| **Debug Support** | Request diagnostics and CURL command generation |
| **Auto Retry** | Built-in retry policy (default 3 attempts) |
| **Data Isolation** | Automatic data copying prevents concurrent modification |
### ⚠️ Important Notes
1. `New()` uses singleton pattern, configurations are immutable after first call
2. Use `Debug()` and `Curl()` only in development environments
3. Event data must contain `event` field, `distinct_id` is recommended
4. Check request parameters for non-2xx HTTP responses
5. Implement batch processing for large-scale data reporting
### 🤝 Contributing
[Contribution Guide](CONTRIBUTING.md) | [Open an Issue](https://gitea.weitiangame.com/sdk/wt-game/point/issues)
[⬆ Back to Top](#中文)

@ -12,35 +12,78 @@ var (
once sync.Once
)
// Point 是用于事件上报的核心结构体
// Point is the core structure for event reporting
type Point struct {
clientID string
logger *zap.Logger
ahttp *resty.Request
client *resty.Client // 线程安全的HTTP客户端 / Thread-safe HTTP client
debug bool
curl bool
mu sync.Mutex // 保护并发访问配置字段 / Mutex to protect concurrent access to configuration fields
}
// New returns the singleton instance of Point.
// New 返回Point的单例实例
// New returns the singleton instance of Point
// 注意:首次调用后的参数变更将不会生效(单例模式特性)
// Note: Parameter changes after the first call will not take effect (singleton pattern characteristic)
func New(clientID string, logger *zap.Logger) *Point {
once.Do(func() {
// 初始化线程安全的HTTP客户端
// Initialize thread-safe HTTP client
baseClient := ahttp.New(nil).SetLog(logger).Client()
instance = &Point{
clientID: clientID,
logger: logger,
client: baseClient,
}
if instance.logger == nil {
var err error
instance.logger, err = zap.NewProduction()
if err != nil {
panic(err)
}
}
instance.ahttp = ahttp.New(nil).SetLog(instance.logger).Client()
})
return instance
}
// Event sends an event to the specified URL.
// Debug 启用调试模式(非线程安全,建议初始化阶段调用)
// Debug enables debug mode (not thread-safe, recommended to call during initialization)
func (p *Point) Debug() *Point {
p.mu.Lock()
defer p.mu.Unlock()
p.debug = true
return p
}
// Curl 启用CURL命令生成非线程安全建议初始化阶段调用
// Curl enables CURL command generation (not thread-safe, recommended to call during initialization)
func (p *Point) Curl() *Point {
p.mu.Lock()
defer p.mu.Unlock()
p.curl = true
return p
}
// Event 发送事件到指定端点
// Event sends an event to the specified endpoint
// 参数data会被复制以避免原始数据修改并发安全设计
// The data parameter is copied to avoid original data modification (concurrency-safe design)
func (p *Point) Event(data map[string]interface{}) (*resty.Response, error) {
return p.ahttp.SetBody(data).Post("https://e.tapdb.net/v2/event")
data["client_id"] = p.clientID
// 获取当前配置的调试和CURL设置
// Get current debug and curl configuration
p.mu.Lock()
debugEnabled := p.debug
curlEnabled := p.curl
p.mu.Unlock()
// 创建新的请求实例并配置参数
// Create new request instance and configure parameters
request := p.client.R().
SetBody(data).
SetDebug(debugEnabled)
if curlEnabled {
request.EnableTrace() // 启用跟踪以生成CURL命令 / Enable trace to generate CURL command
}
// 发送请求并返回结果
// Send request and return results
return request.Post("https://e.tapdb.net/v2/event")
}

@ -3,15 +3,28 @@ package test
import (
"fmt"
"gitea.weitiangame.com/sdk/wt-game/point"
"go.uber.org/zap"
"testing"
)
var pointSdk = point.New("your-client-id", nil)
var logger, _ = zap.NewProduction()
var pointSdk = point.New("your-client-id", logger).Debug().Curl()
// TestOrderSign 测试订单签名
func TestPoint(t *testing.T) {
event, err := pointSdk.Event(map[string]interface{}{
"test": "test",
"name": "charge", // 事件名,固定为 charge
"user_id": "your-user-id", // 必需。用户 ID。必须和 SDK 的 setUser 接口传递的 userId 一样,并且该用户已经通过 SDK 接口进行过推送
"type": "track", // 必需。数据类型,请确保传入的值为 track
"properties": map[string]interface{}{
"ip": "8.8.8.8", // 可选。充值用户的 IP
"order_id": "100000", // 可选。长度大于 0 并小于等于 256。订单 ID。
"amount": 100, // 必需。大于 0 并小于等于 100000000000。充值金额。单位分即无论什么币种都需要乘以 100
"virtual_currency_amount": 100, //获赠虚拟币数量,必传,可为 0
"currency_type": "CNY", // 可选。货币类型。国际通行三字母表示法,为空时默认 CNY。参考人民币 CNY美元 USD欧元 EUR
"product": "item1", // 可选。长度大于 0 并小于等于 256。商品名称
"payment": "alipay", // 可选。长度大于 0 并小于等于 256。充值渠道
},
})
fmt.Println(event)

@ -115,6 +115,9 @@ func newTransport(config *Config) *http.Transport {
// SetLog 设置日志记录器 / SetLog sets the logger
func (h *HttpClient) SetLog(logger *zap.Logger) *HttpClient {
if logger == nil {
return h
}
h.logger = logger
h.httpClient.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
logger.Info("Request",
@ -161,7 +164,13 @@ func (h *HttpClient) SetLog(logger *zap.Logger) *HttpClient {
}
// Client 返回 Resty 客户端的请求实例 / Returns a request instance of the Resty client
func (h *HttpClient) Client() *resty.Request {
func (h *HttpClient) Client() *resty.Client {
h.httpClient.SetHeader("User-Agent", "ahttp")
return h.httpClient
}
// Client 返回 Resty 客户端的请求实例 / Returns a request instance of the Resty client
func (h *HttpClient) Request() *resty.Request {
h.httpClient.SetHeader("User-Agent", "ahttp")
return h.httpClient.R()
}

Loading…
Cancel
Save