Compare commits
2 Commits
4e8bd6579f
...
72cf3a46dd
| Author | SHA1 | Date | |
|---|---|---|---|
| 72cf3a46dd | |||
| 2f35803893 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@
|
||||
*.iml
|
||||
out
|
||||
gen
|
||||
.claude
|
||||
|
||||
134
CLAUDE.md
Normal file
134
CLAUDE.md
Normal file
@ -0,0 +1,134 @@
|
||||
# CLAUDE.md
|
||||
|
||||
本文件为 Claude Code (claude.ai/code) 在此仓库中工作时提供指引。
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
# 运行某个 service 的全部测试
|
||||
go test ./services/apk/...
|
||||
|
||||
# 运行单个测试函数
|
||||
go test ./services/apk/... -run TestClient_GetUserInfo -v
|
||||
|
||||
# 编译检查
|
||||
go build ./...
|
||||
```
|
||||
|
||||
## 整体架构
|
||||
|
||||
分两层:
|
||||
|
||||
- `sdk/`:核心框架,处理签名、HTTP 请求、响应解析,不含业务逻辑
|
||||
- `services/<name>/`:各业务服务封装,每个包是一个独立 SDK client
|
||||
|
||||
### sdk/ 核心流程
|
||||
|
||||
```
|
||||
调用方 → Client.DoAction(req, resp)
|
||||
→ auth.Sign(req, signer) # 根据 credential 类型签名
|
||||
→ req.BuildUrl() # RpcRequest 拼接域名+路径+query
|
||||
→ HTTP 请求
|
||||
→ responses.Unmarshal(resp) # JSON 反序列化
|
||||
```
|
||||
|
||||
- `sdk/auth/credentials/`:三种凭证类型(AccessKey、StsToken、AliAppcode)
|
||||
- `sdk/auth/signers/`:对应签名器实现
|
||||
- `sdk/requests/`:`RpcRequest`(主流)和 `RoaRequest` 两种请求风格;字段通过 struct tag `position:"Body|Query|Header"` 和 `field:"xxx"` 声明参数位置
|
||||
- `sdk/config.go`:`Config` 结构体,字段用 `default:"..."` tag 自动初始化
|
||||
|
||||
### services/ 统一模式
|
||||
|
||||
每个服务包含:
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `client.go` | 定义 `Client`(内嵌 `sdk.Client`)、`HOST`、`VERSION` 常量,以及所有对外方法 |
|
||||
| `xxx_action.go` | 每个接口一个文件,包含 Request/Response 结构体和两个工厂函数 |
|
||||
|
||||
## 添加新接口的标准步骤
|
||||
|
||||
**1. 新建 `services/<name>/new_action.go`:**
|
||||
|
||||
```go
|
||||
package <name>
|
||||
|
||||
import (
|
||||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
|
||||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses"
|
||||
)
|
||||
|
||||
type NewActionRequest struct {
|
||||
*requests.RpcRequest
|
||||
Field1 string `position:"Body" field:"field1" default:""`
|
||||
Field2 int64 `position:"Body" field:"field2"`
|
||||
}
|
||||
|
||||
type NewActionResponse struct {
|
||||
*responses.BaseResponse
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
// ...
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func CreateNewActionRequest() *NewActionRequest {
|
||||
req := &NewActionRequest{RpcRequest: &requests.RpcRequest{}}
|
||||
req.InitWithApiInfo(HOST, VERSION, "/api/path/here")
|
||||
req.Method = requests.POST
|
||||
return req
|
||||
}
|
||||
|
||||
func CreateNewActionResponse() *NewActionResponse {
|
||||
return &NewActionResponse{BaseResponse: &responses.BaseResponse{}}
|
||||
}
|
||||
```
|
||||
|
||||
**2. 在 `client.go` 添加方法:**
|
||||
|
||||
```go
|
||||
func (c *Client) NewAction(req *NewActionRequest) (response *NewActionResponse, err error) {
|
||||
response = CreateNewActionResponse()
|
||||
err = c.DoAction(req, response)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
## HOST 两种写法
|
||||
|
||||
```go
|
||||
// 简单写法(内部服务,hostname 由调用方注入)
|
||||
var HOST = requests.Host{Default: "service-name"}
|
||||
|
||||
// 带环境路由写法(外部服务,各环境域名不同)
|
||||
var HOST = requests.Host{
|
||||
Default: "api.example.com",
|
||||
Func: func(env string) string {
|
||||
return map[string]string{
|
||||
requests.RELEASE: "api.example.com",
|
||||
requests.TEST: "test.api.example.com",
|
||||
}[env]
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
环境常量:`requests.RELEASE`、`requests.PRE`、`requests.TEST`
|
||||
|
||||
## Client 初始化两种模式
|
||||
|
||||
```go
|
||||
// 模式一:无需认证(apk、callback 等内部服务)
|
||||
func NewClient() *Client {
|
||||
client := &Client{}
|
||||
client.InitWithAccessKey("", "", "")
|
||||
return client
|
||||
}
|
||||
|
||||
// 模式二:需要认证(sso、pay 等)
|
||||
func NewClient() (*Client, error) {
|
||||
client := new(Client)
|
||||
err := client.Init()
|
||||
return client, err
|
||||
}
|
||||
```
|
||||
@ -191,3 +191,10 @@ func (c *Client) GetGameListExtInfo(req *GetGameListExtInfoReq) (response *GetGa
|
||||
err = c.DoAction(req, response)
|
||||
return
|
||||
}
|
||||
|
||||
// MakeOrder 预下单(线下支付)
|
||||
func (c *Client) MakeOrder(req *MakeOrderReq) (response *MakeOrderResp, err error) {
|
||||
response = CreateMakeOrderResp()
|
||||
err = c.DoAction(req, response)
|
||||
return
|
||||
}
|
||||
|
||||
@ -383,3 +383,30 @@ func TestGetActivityVipUserNewBlacklist(t *testing.T) {
|
||||
fmt.Printf("%#+v\n", *resp.Data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateMakeOrderReq(t *testing.T) {
|
||||
req := CreateMakeOrderReq(MakeOrderParam{
|
||||
Username: "vd22543241",
|
||||
Gid: 123,
|
||||
Sid: "123",
|
||||
RealSid: "123",
|
||||
RoleId: "123",
|
||||
RoleName: "13",
|
||||
Money: 6,
|
||||
ServerName: "333",
|
||||
ProductName: "666",
|
||||
DwId: 666,
|
||||
})
|
||||
|
||||
client, err := NewClient()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
resp, err := client.MakeOrder(req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(resp.Msg)
|
||||
}
|
||||
|
||||
@ -58,3 +58,67 @@ func CreateIsBlockOutIosResp() *IsBlockOutIosResp {
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// MakeOrderReq 预下单请求
|
||||
type MakeOrderReq struct {
|
||||
*requests.RpcRequest
|
||||
Username string `position:"Body" field:"username"`
|
||||
Gid int64 `position:"Body" field:"gid"`
|
||||
Sid string `position:"Body" field:"sid"`
|
||||
RealSid string `position:"Body" field:"real_sid"`
|
||||
RoleId string `position:"Body" field:"role_id"`
|
||||
RoleName string `position:"Body" field:"role_name"`
|
||||
Money float64 `position:"Body" field:"money"`
|
||||
ServerName string `position:"Body" field:"server_name"`
|
||||
ProductName string `position:"Body" field:"product_name"`
|
||||
DwId int64 `position:"Body" field:"dw_id"`
|
||||
}
|
||||
|
||||
type MakeOrderRespData struct {
|
||||
OrderID string `json:"orderID"`
|
||||
}
|
||||
|
||||
type MakeOrderResp struct {
|
||||
*responses.BaseResponse
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data MakeOrderRespData `json:"data"`
|
||||
}
|
||||
|
||||
type MakeOrderParam struct {
|
||||
Username string
|
||||
Gid int64
|
||||
Sid string
|
||||
RealSid string
|
||||
RoleId string
|
||||
RoleName string
|
||||
Money float64
|
||||
ServerName string
|
||||
ProductName string
|
||||
DwId int64
|
||||
}
|
||||
|
||||
func CreateMakeOrderReq(param MakeOrderParam) *MakeOrderReq {
|
||||
req := &MakeOrderReq{
|
||||
RpcRequest: &requests.RpcRequest{},
|
||||
Username: param.Username,
|
||||
Gid: param.Gid,
|
||||
Sid: param.Sid,
|
||||
RealSid: param.RealSid,
|
||||
RoleId: param.RoleId,
|
||||
RoleName: param.RoleName,
|
||||
Money: param.Money,
|
||||
ServerName: param.ServerName,
|
||||
ProductName: param.ProductName,
|
||||
DwId: param.DwId,
|
||||
}
|
||||
req.InitWithApiInfo(HOST, VERSION, "/api/pay/makeOrder")
|
||||
req.Method = requests.POST
|
||||
return req
|
||||
}
|
||||
|
||||
func CreateMakeOrderResp() *MakeOrderResp {
|
||||
return &MakeOrderResp{
|
||||
BaseResponse: &responses.BaseResponse{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,3 +102,10 @@ func (c *Client) GetUserVoucher(req *GetUserVoucherRequest) (response *GetUserVo
|
||||
err = c.DoAction(req, response)
|
||||
return
|
||||
}
|
||||
|
||||
// ManualReplenish 手动补单
|
||||
func (c *Client) ManualReplenish(req *ManualReplenishRequest) (response *ManualReplenishResponse, err error) {
|
||||
response = CreateManualReplenishResponse()
|
||||
err = c.DoAction(req, response)
|
||||
return
|
||||
}
|
||||
|
||||
@ -39,3 +39,25 @@ func TestGetOrderState(t *testing.T) {
|
||||
}
|
||||
t.Log(getOrderStateResponse.GetHttpContentString())
|
||||
}
|
||||
|
||||
func TestManualReplenish(t *testing.T) {
|
||||
client, err := NewClient()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
req := CreateManualReplenishRequest(ManualReplenishParam{
|
||||
GameId: 100,
|
||||
Money: 6,
|
||||
OrderId: "202112060000193551730",
|
||||
UserName: "testuser",
|
||||
PayChannel: 1,
|
||||
PayChannelType: 0,
|
||||
})
|
||||
resp, err := client.ManualReplenish(req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
t.Log(resp.GetHttpContentString())
|
||||
}
|
||||
|
||||
52
services/pay/manual_replenish.go
Normal file
52
services/pay/manual_replenish.go
Normal file
@ -0,0 +1,52 @@
|
||||
package pay
|
||||
|
||||
import (
|
||||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
|
||||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses"
|
||||
)
|
||||
|
||||
type ManualReplenishParam struct {
|
||||
GameId int64
|
||||
Money int64
|
||||
OrderId string
|
||||
UserName string
|
||||
PayChannel int64
|
||||
PayChannelType int64
|
||||
}
|
||||
|
||||
type ManualReplenishRequest struct {
|
||||
*requests.RpcRequest
|
||||
GameId int64 `position:"Body" field:"game_id"`
|
||||
Money int64 `position:"Body" field:"money"`
|
||||
OrderId string `position:"Body" field:"order_id"`
|
||||
UserName string `position:"Body" field:"user_name"`
|
||||
PayChannel int64 `position:"Body" field:"pay_channel"`
|
||||
PayChannelType int64 `position:"Body" field:"pay_channel_type"`
|
||||
}
|
||||
|
||||
type ManualReplenishResponse struct {
|
||||
*responses.BaseResponse
|
||||
State int `json:"state"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func CreateManualReplenishRequest(param ManualReplenishParam) *ManualReplenishRequest {
|
||||
req := &ManualReplenishRequest{
|
||||
RpcRequest: &requests.RpcRequest{},
|
||||
GameId: param.GameId,
|
||||
Money: param.Money,
|
||||
OrderId: param.OrderId,
|
||||
UserName: param.UserName,
|
||||
PayChannel: param.PayChannel,
|
||||
PayChannelType: param.PayChannelType,
|
||||
}
|
||||
req.InitWithApiInfo(HOST, VERSION, "/api/sdk/manualReplenish")
|
||||
req.Method = requests.POST
|
||||
return req
|
||||
}
|
||||
|
||||
func CreateManualReplenishResponse() *ManualReplenishResponse {
|
||||
return &ManualReplenishResponse{
|
||||
BaseResponse: &responses.BaseResponse{},
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user