maxapi: refactor rewards api

This commit is contained in:
c9s 2022-04-20 16:58:42 +08:00
parent 8b9383ecfa
commit 0410ef1305
8 changed files with 561 additions and 100 deletions

View File

@ -18,7 +18,7 @@ func main() {
ctx := context.Background()
var req *maxapi.RewardsRequest
var req *maxapi.GetRewardsRequest
if len(os.Args) > 1 {
pathType := os.Args[1]
@ -27,9 +27,9 @@ func main() {
log.Fatal(err)
}
req = api.RewardService.NewRewardsByTypeRequest(rewardType)
req = api.RewardService.NewGetRewardsOfTypeRequest(rewardType)
} else {
req = api.RewardService.NewRewardsRequest()
req = api.RewardService.NewGetRewardsRequest()
}
// req.From(1613931192)

View File

@ -900,7 +900,7 @@ func (e *Exchange) QueryRewards(ctx context.Context, startTime time.Time) ([]typ
// an user might get most 14 commission records by currency per day
// limit 1000 / 14 = 71 days
to := from.Add(time.Hour * 24 * 30)
req := e.client.RewardService.NewRewardsRequest()
req := e.client.RewardService.NewGetRewardsRequest()
req.From(from.Unix())
req.To(to.Unix())
req.Limit(1000)

View File

@ -1,22 +0,0 @@
package max
import (
"encoding/json"
"time"
)
type Timestamp time.Time
func (t Timestamp) String() string {
return time.Time(t).String()
}
func (t *Timestamp) UnmarshalJSON(o []byte) error {
var timestamp int64
if err := json.Unmarshal(o, &timestamp); err != nil {
return err
}
*t = Timestamp(time.Unix(timestamp, 0))
return nil
}

View File

@ -0,0 +1,222 @@
// Code generated by "requestgen -method GET -url v2/rewards/:path_type -type GetRewardsOfTypeRequest -responseType []Reward"; DO NOT EDIT.
package max
import (
"context"
"encoding/json"
"fmt"
"net/url"
"reflect"
"regexp"
)
func (g *GetRewardsOfTypeRequest) From(from int64) *GetRewardsOfTypeRequest {
g.from = &from
return g
}
func (g *GetRewardsOfTypeRequest) To(to int64) *GetRewardsOfTypeRequest {
g.to = &to
return g
}
func (g *GetRewardsOfTypeRequest) Page(page int64) *GetRewardsOfTypeRequest {
g.page = &page
return g
}
func (g *GetRewardsOfTypeRequest) Limit(limit int64) *GetRewardsOfTypeRequest {
g.limit = &limit
return g
}
func (g *GetRewardsOfTypeRequest) Offset(offset int64) *GetRewardsOfTypeRequest {
g.offset = &offset
return g
}
func (g *GetRewardsOfTypeRequest) PathType(pathType RewardType) *GetRewardsOfTypeRequest {
g.pathType = &pathType
return g
}
// GetQueryParameters builds and checks the query parameters and returns url.Values
func (g *GetRewardsOfTypeRequest) GetQueryParameters() (url.Values, error) {
var params = map[string]interface{}{}
query := url.Values{}
for k, v := range params {
query.Add(k, fmt.Sprintf("%v", v))
}
return query, nil
}
// GetParameters builds and checks the parameters and return the result in a map object
func (g *GetRewardsOfTypeRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
// check from field -> json key from
if g.from != nil {
from := *g.from
// assign parameter of from
params["from"] = from
} else {
}
// check to field -> json key to
if g.to != nil {
to := *g.to
// assign parameter of to
params["to"] = to
} else {
}
// check page field -> json key page
if g.page != nil {
page := *g.page
// assign parameter of page
params["page"] = page
} else {
}
// check limit field -> json key limit
if g.limit != nil {
limit := *g.limit
// assign parameter of limit
params["limit"] = limit
} else {
}
// check offset field -> json key offset
if g.offset != nil {
offset := *g.offset
// assign parameter of offset
params["offset"] = offset
} else {
}
return params, nil
}
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
func (g *GetRewardsOfTypeRequest) GetParametersQuery() (url.Values, error) {
query := url.Values{}
params, err := g.GetParameters()
if err != nil {
return query, err
}
for k, v := range params {
if g.isVarSlice(v) {
g.iterateSlice(v, func(it interface{}) {
query.Add(k+"[]", fmt.Sprintf("%v", it))
})
} else {
query.Add(k, fmt.Sprintf("%v", v))
}
}
return query, nil
}
// GetParametersJSON converts the parameters from GetParameters into the JSON format
func (g *GetRewardsOfTypeRequest) GetParametersJSON() ([]byte, error) {
params, err := g.GetParameters()
if err != nil {
return nil, err
}
return json.Marshal(params)
}
// GetSlugParameters builds and checks the slug parameters and return the result in a map object
func (g *GetRewardsOfTypeRequest) GetSlugParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
// check pathType field -> json key path_type
if g.pathType != nil {
pathType := *g.pathType
// assign parameter of pathType
params["path_type"] = pathType
}
return params, nil
}
func (g *GetRewardsOfTypeRequest) applySlugsToUrl(url string, slugs map[string]string) string {
for k, v := range slugs {
needleRE := regexp.MustCompile(":" + k + "\\b")
url = needleRE.ReplaceAllString(url, v)
}
return url
}
func (g *GetRewardsOfTypeRequest) iterateSlice(slice interface{}, f func(it interface{})) {
sliceValue := reflect.ValueOf(slice)
for i := 0; i < sliceValue.Len(); i++ {
it := sliceValue.Index(i).Interface()
f(it)
}
}
func (g *GetRewardsOfTypeRequest) isVarSlice(v interface{}) bool {
rt := reflect.TypeOf(v)
switch rt.Kind() {
case reflect.Slice:
return true
}
return false
}
func (g *GetRewardsOfTypeRequest) GetSlugsMap() (map[string]string, error) {
slugs := map[string]string{}
params, err := g.GetSlugParameters()
if err != nil {
return slugs, nil
}
for k, v := range params {
slugs[k] = fmt.Sprintf("%v", v)
}
return slugs, nil
}
func (g *GetRewardsOfTypeRequest) Do(ctx context.Context) ([]Reward, error) {
// empty params for GET operation
var params interface{}
query, err := g.GetParametersQuery()
if err != nil {
return nil, err
}
apiURL := "v2/rewards/:path_type"
slugs, err := g.GetSlugsMap()
if err != nil {
return nil, err
}
apiURL = g.applySlugsToUrl(apiURL, slugs)
req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
if err != nil {
return nil, err
}
response, err := g.client.SendRequest(req)
if err != nil {
return nil, err
}
var apiResponse []Reward
if err := response.DecodeJSON(&apiResponse); err != nil {
return nil, err
}
return apiResponse, nil
}

View File

@ -0,0 +1,216 @@
// Code generated by "requestgen -method GET -url v2/rewards -type GetRewardsRequest -responseType []Reward"; DO NOT EDIT.
package max
import (
"context"
"encoding/json"
"fmt"
"net/url"
"reflect"
"regexp"
)
func (g *GetRewardsRequest) Currency(currency string) *GetRewardsRequest {
g.currency = &currency
return g
}
func (g *GetRewardsRequest) From(from int64) *GetRewardsRequest {
g.from = &from
return g
}
func (g *GetRewardsRequest) To(to int64) *GetRewardsRequest {
g.to = &to
return g
}
func (g *GetRewardsRequest) Page(page int64) *GetRewardsRequest {
g.page = &page
return g
}
func (g *GetRewardsRequest) Limit(limit int64) *GetRewardsRequest {
g.limit = &limit
return g
}
func (g *GetRewardsRequest) Offset(offset int64) *GetRewardsRequest {
g.offset = &offset
return g
}
// GetQueryParameters builds and checks the query parameters and returns url.Values
func (g *GetRewardsRequest) GetQueryParameters() (url.Values, error) {
var params = map[string]interface{}{}
query := url.Values{}
for k, v := range params {
query.Add(k, fmt.Sprintf("%v", v))
}
return query, nil
}
// GetParameters builds and checks the parameters and return the result in a map object
func (g *GetRewardsRequest) GetParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
// check currency field -> json key currency
if g.currency != nil {
currency := *g.currency
// assign parameter of currency
params["currency"] = currency
} else {
}
// check from field -> json key from
if g.from != nil {
from := *g.from
// assign parameter of from
params["from"] = from
} else {
}
// check to field -> json key to
if g.to != nil {
to := *g.to
// assign parameter of to
params["to"] = to
} else {
}
// check page field -> json key page
if g.page != nil {
page := *g.page
// assign parameter of page
params["page"] = page
} else {
}
// check limit field -> json key limit
if g.limit != nil {
limit := *g.limit
// assign parameter of limit
params["limit"] = limit
} else {
}
// check offset field -> json key offset
if g.offset != nil {
offset := *g.offset
// assign parameter of offset
params["offset"] = offset
} else {
}
return params, nil
}
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
func (g *GetRewardsRequest) GetParametersQuery() (url.Values, error) {
query := url.Values{}
params, err := g.GetParameters()
if err != nil {
return query, err
}
for k, v := range params {
if g.isVarSlice(v) {
g.iterateSlice(v, func(it interface{}) {
query.Add(k+"[]", fmt.Sprintf("%v", it))
})
} else {
query.Add(k, fmt.Sprintf("%v", v))
}
}
return query, nil
}
// GetParametersJSON converts the parameters from GetParameters into the JSON format
func (g *GetRewardsRequest) GetParametersJSON() ([]byte, error) {
params, err := g.GetParameters()
if err != nil {
return nil, err
}
return json.Marshal(params)
}
// GetSlugParameters builds and checks the slug parameters and return the result in a map object
func (g *GetRewardsRequest) GetSlugParameters() (map[string]interface{}, error) {
var params = map[string]interface{}{}
return params, nil
}
func (g *GetRewardsRequest) applySlugsToUrl(url string, slugs map[string]string) string {
for k, v := range slugs {
needleRE := regexp.MustCompile(":" + k + "\\b")
url = needleRE.ReplaceAllString(url, v)
}
return url
}
func (g *GetRewardsRequest) iterateSlice(slice interface{}, f func(it interface{})) {
sliceValue := reflect.ValueOf(slice)
for i := 0; i < sliceValue.Len(); i++ {
it := sliceValue.Index(i).Interface()
f(it)
}
}
func (g *GetRewardsRequest) isVarSlice(v interface{}) bool {
rt := reflect.TypeOf(v)
switch rt.Kind() {
case reflect.Slice:
return true
}
return false
}
func (g *GetRewardsRequest) GetSlugsMap() (map[string]string, error) {
slugs := map[string]string{}
params, err := g.GetSlugParameters()
if err != nil {
return slugs, nil
}
for k, v := range params {
slugs[k] = fmt.Sprintf("%v", v)
}
return slugs, nil
}
func (g *GetRewardsRequest) Do(ctx context.Context) ([]Reward, error) {
// empty params for GET operation
var params interface{}
query, err := g.GetParametersQuery()
if err != nil {
return nil, err
}
apiURL := "v2/rewards"
req, err := g.client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
if err != nil {
return nil, err
}
response, err := g.client.SendRequest(req)
if err != nil {
return nil, err
}
var apiResponse []Reward
if err := response.DecodeJSON(&apiResponse); err != nil {
return nil, err
}
return apiResponse, nil
}

View File

@ -1,11 +1,15 @@
package max
//go:generate -command GetRequest requestgen -method GET
//go:generate -command PostRequest requestgen -method POST
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/c9s/requestgen"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
@ -18,6 +22,7 @@ const (
RewardHolding = RewardType("holding_reward")
RewardMining = RewardType("mining_reward")
RewardTrading = RewardType("trading_reward")
RewardRedemption = RewardType("redemption_reward")
RewardVipRebate = RewardType("vip_rebate")
)
@ -35,6 +40,8 @@ func ParseRewardType(s string) (RewardType, error) {
return RewardTrading, nil
case "vip_rebate":
return RewardVipRebate, nil
case "redemption_reward":
return RewardRedemption, nil
}
@ -93,7 +100,7 @@ type Reward struct {
Note string `json:"note"`
// Unix timestamp in seconds
CreatedAt Timestamp `json:"created_at"`
CreatedAt types.Timestamp `json:"created_at"`
}
func (reward Reward) Reward() (*types.Reward, error) {
@ -119,88 +126,44 @@ type RewardService struct {
client *RestClient
}
func (s *RewardService) NewRewardsRequest() *RewardsRequest {
return &RewardsRequest{client: s.client}
func (s *RewardService) NewGetRewardsRequest() *GetRewardsRequest {
return &GetRewardsRequest{client: s.client}
}
func (s *RewardService) NewRewardsByTypeRequest(pathType RewardType) *RewardsRequest {
return &RewardsRequest{client: s.client, pathType: &pathType}
func (s *RewardService) NewGetRewardsOfTypeRequest(pathType RewardType) *GetRewardsOfTypeRequest {
return &GetRewardsOfTypeRequest{client: s.client, pathType: &pathType}
}
type RewardsRequest struct {
client *RestClient
//go:generate GetRequest -url "v2/rewards/:path_type" -type GetRewardsOfTypeRequest -responseType []Reward
type GetRewardsOfTypeRequest struct {
client requestgen.AuthenticatedAPIClient
pathType *RewardType
currency *string
pathType *RewardType `param:"path_type,slug"`
// From Unix-timestamp
from *int64
from *int64 `param:"from"`
// To Unix-timestamp
to *int64
to *int64 `param:"to"`
limit *int
page *int64 `param:"page"`
limit *int64 `param:"limit"`
offset *int64 `param:"offset"`
}
func (r *RewardsRequest) Currency(currency string) *RewardsRequest {
r.currency = &currency
return r
}
func (r *RewardsRequest) From(from int64) *RewardsRequest {
r.from = &from
return r
}
func (r *RewardsRequest) Limit(limit int) *RewardsRequest {
r.limit = &limit
return r
}
func (r *RewardsRequest) To(to int64) *RewardsRequest {
r.to = &to
return r
}
func (r *RewardsRequest) Do(ctx context.Context) (rewards []Reward, err error) {
payload := map[string]interface{}{}
if r.currency != nil {
payload["currency"] = r.currency
}
if r.to != nil {
payload["to"] = r.to
}
if r.from != nil {
payload["from"] = r.from
}
if r.limit != nil {
payload["limit"] = r.limit
}
refURL := "v2/rewards"
if r.pathType != nil {
refURL += "/" + string(*r.pathType)
}
req, err := r.client.newAuthenticatedRequest(context.Background(), "GET", refURL, nil, payload, nil)
if err != nil {
return rewards, err
}
response, err := r.client.SendRequest(req)
if err != nil {
return rewards, err
}
if err := response.DecodeJSON(&rewards); err != nil {
return rewards, err
}
return rewards, err
//go:generate GetRequest -url "v2/rewards" -type GetRewardsRequest -responseType []Reward
type GetRewardsRequest struct {
client requestgen.AuthenticatedAPIClient
currency *string `param:"currency"`
// From Unix-timestamp
from *int64 `param:"from"`
// To Unix-timestamp
to *int64 `param:"to"`
page *int64 `param:"page"`
limit *int64 `param:"limit"`
offset *int64 `param:"offset"`
}

View File

@ -0,0 +1,52 @@
package max
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
)
func TestRewardService_GetRewardsRequest(t *testing.T) {
key, secret, ok := integrationTestConfigured(t, "MAX")
if !ok {
t.SkipNow()
}
ctx := context.Background()
client := NewRestClient(ProductionAPIURL)
client.Auth(key, secret)
req := client.RewardService.NewGetRewardsRequest()
rewards, err := req.Do(ctx)
assert.NoError(t, err)
assert.NotNil(t, rewards)
assert.NotEmpty(t, rewards)
t.Logf("rewards: %+v", rewards)
}
func TestRewardService_GetRewardsOfTypeRequest(t *testing.T) {
key, secret, ok := integrationTestConfigured(t, "MAX")
if !ok {
t.SkipNow()
}
ctx := context.Background()
client := NewRestClient(ProductionAPIURL)
client.Auth(key, secret)
req := client.RewardService.NewGetRewardsOfTypeRequest(RewardCommission)
rewards, err := req.Do(ctx)
assert.NoError(t, err)
assert.NotNil(t, rewards)
assert.NotEmpty(t, rewards)
t.Logf("rewards: %+v", rewards)
for _, reward := range rewards {
assert.Equal(t, RewardCommission, reward.Type)
}
}

View File

@ -269,3 +269,33 @@ func (t *LooseFormatTime) UnmarshalJSON(data []byte) error {
func (t LooseFormatTime) Time() time.Time {
return time.Time(t)
}
// Timestamp is used for parsing unix timestamp (seconds)
type Timestamp time.Time
func (t Timestamp) Format(layout string) string {
return time.Time(t).Format(layout)
}
func (t Timestamp) Time() time.Time {
return time.Time(t)
}
func (t Timestamp) String() string {
return time.Time(t).String()
}
func (t Timestamp) MarshalJSON() ([]byte, error) {
ts := time.Time(t).Unix()
return json.Marshal(ts)
}
func (t *Timestamp) UnmarshalJSON(o []byte) error {
var timestamp int64
if err := json.Unmarshal(o, &timestamp); err != nil {
return err
}
*t = Timestamp(time.Unix(timestamp, 0))
return nil
}