master
wujianhua 2 years ago
commit 6c7a2eb6b2
  1. 91
      api.go
  2. 38
      client.go
  3. 105
      client_test.go
  4. 11
      go.mod
  5. 19
      go.sum
  6. 30
      model.go
  7. 53
      option.go
  8. 71
      sign.go

@ -0,0 +1,91 @@
package risk
import (
"context"
"fmt"
"github.com/go-resty/resty/v2"
)
const (
writeLogUri = "/v1/metric/counter/write/v2"
syncUri = "/v1/config/database/sync"
)
type api struct {
http *resty.Client
appId string
appSecret string
}
func NewApi(opts clientOptions) *api {
client := resty.New()
client.SetBaseURL(opts.host)
client.SetTimeout(opts.timeOut)
client.SetRetryCount(2)
client.SetDebug(opts.debug)
client.SetHeader("Content-Type", "application/json")
return &api{
http: client,
appId: opts.appId,
appSecret: opts.appSecret,
}
}
// SyncDatabase 写入访问日志,访问/v1/metric/counter/write/v2接口
func (a *api) WriteLog(ctx context.Context, data *LogData) error {
sign, random, ts := Sign(a.appId, a.appSecret, data)
req := Request{
AppID: a.appId,
Time: int64(ts),
Data: data,
Sign: sign,
Random: random,
}
res, err := a.http.R().
SetBody(req).
Post(writeLogUri)
if err != nil {
return err
}
if res.StatusCode() != 200 {
return fmt.Errorf("write log has error, status_code: %d, response: %s", res.StatusCode(), res.Body())
}
return nil
}
// SyncDatabase 同步数据库数据,访问/v1/config/database/sync接口
func (a *api) SyncDatabase(ctx context.Context, data []*SyncData) error {
sign, random, ts := Sign(a.appId, a.appSecret, data)
req := Request{
AppID: a.appId,
Time: int64(ts),
Data: data,
Sign: sign,
Random: random,
}
res, err := a.http.R().
SetBody(req).
Post(syncUri)
if err != nil {
return err
}
if res.StatusCode() != 200 {
return fmt.Errorf("write log has error, status_code: %d, response: %s", res.StatusCode(), res.Body())
}
return nil
}

@ -0,0 +1,38 @@
package risk
import "context"
type API interface {
WriteLog(ctx context.Context, data *LogData) error
SyncDatabase(ctx context.Context, data []*SyncData) error
}
type Client struct {
opts clientOptions
apis API
}
// NewClient 创建一个客户端
func NewClient(opt ...ClientOption) *Client {
opts := defaultClientOptions
for _, o := range opt {
o(&opts)
}
apis := NewApi(opts)
return &Client{
opts: opts,
apis: apis,
}
}
// SyncDatabase 写入访问日志,访问/v1/metric/counter/write/v2接口
func (cli *Client) WriteLog(ctx context.Context, data *LogData) error {
return cli.apis.WriteLog(ctx, data)
}
// SyncDatabase 同步数据库数据,访问/v1/config/database/sync接口
func (cli *Client) SyncDatabase(ctx context.Context, data []*SyncData) error {
return cli.apis.SyncDatabase(ctx, data)
}

@ -0,0 +1,105 @@
package risk
import (
"context"
"testing"
"time"
)
var client = NewClient(
WithAppID("01b60cd2aacaf411"),
WithAppSecret("2D6MDRfFg7EudhW90UXOFrEI9td"),
WithServerHost("http://risk-sensor.drugeyes.vip:7031/"),
WithTimeOut(time.Second*30),
WithDebug(true),
)
func TestClient_WriteLog(t *testing.T) {
type args struct {
ctx context.Context
data *LogData
}
tests := []struct {
name string
cli *Client
args args
wantErr bool
}{
{
name: "普通测试",
cli: client,
args: args{
ctx: context.Background(),
data: &LogData{
Organize: "测试",
User: "1",
Ip: "127.0.0.1",
UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
PageType: "LIST",
Value: 12,
Request: "测试库dd",
DbCount: []*DBCount{
{
UniqueKey: "00014",
DB: "db1",
},
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.cli.WriteLog(tt.args.ctx, tt.args.data); (err != nil) != tt.wantErr {
t.Errorf("Client.WriteLog() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestClient_SyncDatabase(t *testing.T) {
type args struct {
ctx context.Context
data []*SyncData
}
tests := []struct {
name string
cli *Client
args args
wantErr bool
}{
{
name: "普通测试",
cli: client,
args: args{
ctx: context.Background(),
data: []*SyncData{
{
DbKey: "db1",
DbName: "测试库aa",
DbCount: 255,
},
{
DbKey: "db2",
DbName: "测试库bb",
DbCount: 255,
},
{
DbKey: "db3",
DbName: "测试库cc",
DbCount: 255,
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.cli.SyncDatabase(tt.args.ctx, tt.args.data); (err != nil) != tt.wantErr {
t.Errorf("Client.SyncDatabase() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

@ -0,0 +1,11 @@
module gitea.drugeyes.vip/pharnexbase/risk-sdk-go
go 1.19
require (
github.com/go-resty/resty/v2 v2.7.0
github.com/google/uuid v1.3.0
github.com/spf13/cast v1.5.0
)
require golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect

@ -0,0 +1,19 @@
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

@ -0,0 +1,30 @@
package risk
type Request struct {
AppID string `json:"app_id"`
Time int64 `json:"time"`
Data interface{} `json:"data"`
Random string `json:"random"`
Sign string `json:"sign"`
}
type LogData struct {
Organize string `json:"organize"`
User string `json:"user"`
Ip string `json:"ip"`
UserAgent string `json:"user_agent"`
PageType string `json:"page_type"`
Value int64 `json:"value"`
Request string `json:"request"`
DbCount []*DBCount `json:"db_count"`
}
type DBCount struct {
DB string `json:"db"`
UniqueKey string `json:"unique_key"`
}
type SyncData struct {
DbKey string `json:"db_key"`
DbName string `json:"db_name"`
DbCount int64 `json:"db_count"`
}

@ -0,0 +1,53 @@
package risk
import "time"
type ClientOption func(c *clientOptions)
var defaultClientOptions = clientOptions{
host: "http://risk-monitor-api.drugeyes.vip:7031/",
timeOut: 30 * time.Second,
}
type clientOptions struct {
appId string
appSecret string
host string
timeOut time.Duration
debug bool
}
// WithAppID 设置APPID
func WithAppID(appId string) ClientOption {
return func(c *clientOptions) {
c.appId = appId
}
}
// WithAppSecret 设置AppSecret
func WithAppSecret(secret string) ClientOption {
return func(c *clientOptions) {
c.appSecret = secret
}
}
// WithHost 设置服务器域名,例如http://risk-monitor-api.drugeyes.vip:7031/
func WithServerHost(host string) ClientOption {
return func(c *clientOptions) {
c.host = host
}
}
// WithTimeOut 设置请求过期时间
func WithTimeOut(timeout time.Duration) ClientOption {
return func(c *clientOptions) {
c.timeOut = timeout
}
}
// WithDebug 设置debug调试模式,打印请求相关内容
func WithDebug(debug bool) ClientOption {
return func(c *clientOptions) {
c.debug = debug
}
}

@ -0,0 +1,71 @@
package risk
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"strings"
"time"
"github.com/google/uuid"
"github.com/spf13/cast"
)
func CheckSign(appID, appKey, random, sign string, ts int, data interface{}) bool {
if int(time.Now().Unix())-ts > 120 {
return false
}
v, _ := json.Marshal(data)
m := md5.New()
sb := strings.Builder{}
sb.WriteString(appID)
sb.WriteByte('-')
sb.WriteString(cast.ToString(ts))
sb.WriteByte('-')
sb.Write(v)
sb.WriteByte('-')
sb.WriteString(random)
sb.WriteByte('-')
sb.WriteString(appKey)
m.Write([]byte(sb.String()))
md5str1 := hex.EncodeToString(m.Sum(nil))
return md5str1 == sign
}
func Sign(appID, appKey string, data interface{}) (sign string, random string, ts int) {
random = newRandom()
ts = int(time.Now().Unix())
v, _ := json.Marshal(data)
m := md5.New()
sb := strings.Builder{}
sb.WriteString(appID)
sb.WriteByte('-')
sb.WriteString(cast.ToString(ts))
sb.WriteByte('-')
sb.Write(v)
sb.WriteByte('-')
sb.WriteString(random)
sb.WriteByte('-')
sb.WriteString(appKey)
m.Write([]byte(sb.String()))
sign = hex.EncodeToString(m.Sum(nil))
return
}
func newRandom() string {
uuid := uuid.Must(uuid.NewRandom())
random := uuid.String()
return strings.ReplaceAll(random, "-", "")
}
Loading…
Cancel
Save