go-common/app/job/main/vip/dao/business.go
2019-04-22 18:49:16 +08:00

471 lines
13 KiB
Go

package dao
import (
"bytes"
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
xtime "time"
"go-common/app/job/main/vip/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/time"
"go-common/library/xstr"
"github.com/google/uuid"
"github.com/pkg/errors"
)
const (
_cleanCache = "/notify/cleanCache"
_payOrder = "/payplatform/pay/pay"
_message = "/api/notify/send.user.notify.do"
_addBcoin = "/api/coupon/regular/add"
_sendVipbuyTicket = "/mall-marketing/coupon_code/create"
_sendMedal = "/api/nameplate/get/v2"
_pushData = "/x/internal/push-strategy/task/add"
_retry = 3
_minRead = 1024 * 64
_alreadySend = -804
_alreadyGet = -663
_alreadySendVipbuy = 83110005
_ok = 1
//push
appID = 1
)
//PushData http push data
func (d *Dao) PushData(c context.Context, mids []int64, pushData *model.VipPushData, curtime string) (rel *model.VipPushResq, err error) {
var (
pushTime xtime.Time
expireTime xtime.Time
params = url.Values{}
)
rel = new(model.VipPushResq)
if pushTime, err = xtime.ParseInLocation("2006-01-02 15:04:05", fmt.Sprintf("%v %v", curtime, pushData.PushStartTime), xtime.Local); err != nil {
err = errors.WithStack(err)
return
}
if expireTime, err = xtime.ParseInLocation("2006-01-02 15:04:05", fmt.Sprintf("%v %v", curtime, pushData.PushEndTime), xtime.Local); err != nil {
err = errors.WithStack(err)
return
}
page := len(mids) / d.c.Property.SplitPush
if len(mids)%d.c.Property.SplitPush != 0 {
page++
}
for i := 0; i < page; i++ {
startID := i * d.c.Property.SplitPush
endID := (i + 1) * d.c.Property.SplitPush
if endID > len(mids) {
endID = len(mids)
}
tempMids := mids[startID:endID]
params.Set("app_id", fmt.Sprintf("%v", appID))
params.Set("business_id", fmt.Sprintf("%v", d.c.Property.BusinessID))
params.Set("alert_title", pushData.Title)
params.Set("alert_body", pushData.Content)
params.Set("mids", xstr.JoinInts(tempMids))
params.Set("link_type", fmt.Sprintf("%v", pushData.LinkType))
params.Set("link_value", pushData.LinkURL)
params.Set("builds", pushData.Platform)
params.Set("group", pushData.GroupName)
params.Set("uuid", uuid.New().String())
params.Set("push_time", fmt.Sprintf("%v", pushTime.Unix()))
params.Set("expire_time", fmt.Sprintf("%v", expireTime.Unix()))
header := make(map[string]string)
header["Authorization"] = fmt.Sprintf("token=%v", d.c.Property.PushToken)
header["Content-Type"] = "application/x-www-form-urlencoded"
for i := 0; i < _retry; i++ {
if err = d.doNomalSend(c, d.c.URLConf.APICoURL, _pushData, "127.0.0.1", header, params, rel); err != nil {
log.Error("send error(%v) url(%v)", err, d.c.URLConf.APICoURL+_pushData)
return
}
if rel.Code == int64(ecode.OK.Code()) {
log.Info("send url:%v params:%+v return:%+v error(%+v)", d.c.URLConf.APICoURL+_pushData, params, rel, err)
break
}
}
}
return
}
//SendMedal send medal
func (d *Dao) SendMedal(c context.Context, mid, medalID int64) (status int64) {
var (
err error
)
params := url.Values{}
params.Set("mid", fmt.Sprintf("%v", mid))
params.Set("nid", fmt.Sprintf("%v", medalID))
rel := new(struct {
Code int64 `json:"code"`
Data string `json:"data"`
})
defer func() {
if err == nil {
log.Info("send url:%+v params:%+v return:%+v", d.c.URLConf.AccountURL+_sendMedal, params, rel)
}
}()
for i := 0; i < _retry; i++ {
if err = d.client.Get(c, d.c.URLConf.AccountURL+_sendMedal, "127.0.0.1", params, rel); err != nil {
log.Error("send error(%v) url(%v)", err, d.c.URLConf.AccountURL+_sendMedal)
continue
}
if rel.Code == int64(ecode.OK.Code()) || rel.Code == _alreadyGet {
status = 1
if rel.Code == _alreadyGet {
status = 2
}
return
}
}
return
}
//SendVipBuyTicket send vipbuy ticket
func (d *Dao) SendVipBuyTicket(c context.Context, mid int64, couponID string) (status int64) {
var (
err error
)
header := make(map[string]string)
header["Content-Type"] = "application/json"
params := make(map[string]string)
params["mid"] = fmt.Sprintf("%v", mid)
params["couponId"] = fmt.Sprintf("%v", couponID)
for i := 0; i < _retry; i++ {
repl := new(struct {
Code int64 `json:"code"`
Message string `json:"message"`
})
if err = d.doSend(c, d.c.URLConf.MallURL, _sendVipbuyTicket, "127.0.0.1", header, params, repl); err != nil {
log.Error("send vip buy ticket(%+v) error(%+v)", params, err)
continue
}
if repl.Code == int64(ecode.OK.Code()) || repl.Code == _alreadySendVipbuy {
status = 1
if repl.Code == _alreadySendVipbuy {
status = 2
}
return
}
}
return
}
//SendCleanCache clean cache
func (d *Dao) SendCleanCache(c context.Context, hv *model.HandlerVip) (err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(int64(hv.Mid), 10))
if err = d.client.Get(c, d.c.VipURI+_cleanCache, "127.0.0.1", params, nil); err != nil {
log.Error("SendCleanCache error(%v) url(%v)", err, d.c.VipURI+_cleanCache)
return
}
return
}
//SendBcoin send bcoin http
func (d *Dao) SendBcoin(c context.Context, mids []int64, money int32, dueTime time.Time, ip string) (err error) {
if len(mids) <= 0 {
return
}
var midStrs []string
for _, v := range mids {
midStrs = append(midStrs, fmt.Sprintf("%v", v))
}
params := url.Values{}
params.Add("activity_id", fmt.Sprintf("%v", d.c.Property.ActivityID))
params.Add("mids", strings.Join(midStrs, ","))
params.Add("money", fmt.Sprintf("%v", money*100))
params.Add("due_time", dueTime.Time().Format("2006-01-02"))
res := new(struct {
Code int64 `json:"code"`
Message string `json:"message"`
TS int64 `json:"ts"`
Data struct {
CouponMoney int64 `json:"coupon_money"`
Status int8 `json:"status"`
} `json:"data"`
})
if err = d.client.Post(c, d.c.URLConf.PayCoURL+_addBcoin, ip, params, res); err != nil {
err = errors.WithStack(err)
return
}
if res.Code == int64(_alreadySend) {
return
}
if int(res.Code) != ecode.OK.Code() {
err = fmt.Errorf("发放B币失败 message: %s mid: %s resp(%+v)", res.Message, strings.Join(midStrs, ","), res)
return
}
if res.Data.Status != _ok {
err = fmt.Errorf("发放B币失败 message: %s mid: %s resp(%+v)", res.Message, strings.Join(midStrs, ","), res)
return
}
log.Info("发放B币成功 mids %v resp(%+v)", mids, res)
return
}
//SendAppCleanCache notice app clean cache
func (d *Dao) SendAppCleanCache(c context.Context, hv *model.HandlerVip, app *model.VipAppInfo) (err error) {
params := url.Values{}
params.Set("modifiedAttr", "updateVip")
params.Set("mid", fmt.Sprintf("%v", hv.Mid))
params.Set("status", fmt.Sprintf("%v", hv.Type))
params.Set("buyMonths", fmt.Sprintf("%v", hv.Months))
params.Set("days", fmt.Sprintf("%v", hv.Days))
if err = d.client.Get(c, app.PurgeURL, "127.0.0.1", params, nil); err != nil {
log.Error("SendAppCleanCache error(%v) url(%v) params(%v)", err, app.PurgeURL, params)
return
}
return
}
//SendMultipMsg send multip msg
func (d *Dao) SendMultipMsg(c context.Context, mids, content, title, mc string, dataType int) (err error) {
params := url.Values{}
params.Set("mc", mc)
params.Set("title", title)
params.Set("context", content)
params.Set("data_type", strconv.FormatInt(int64(dataType), 10))
params.Set("mid_list", mids)
defer func() {
log.Info("SendMultipMsg(%v) params(%+v) error(%+v)", d.c.URLConf.MsgURL+_message, params, err)
}()
if err = d.client.Post(c, d.c.URLConf.MsgURL+_message, "127.0.0.1", params, nil); err != nil {
log.Error("SendMultipMsg params(%+v) error(%v)", err, params)
return
}
log.Info("cur send mid(%+v)", mids)
return
}
// PayOrder pay order.
func (d *Dao) PayOrder(c context.Context, paramsMap map[string]interface{}) (err error) {
params := make(map[string]string)
for k, v := range paramsMap {
params[k] = fmt.Sprintf("%v", v)
}
header := make(map[string]string)
header["Content-Type"] = "application/json"
success := false
for i := 0; i < 3; i++ {
repl := new(struct {
ErrNo int64 `json:"errno"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
})
if err = d.doPaySend(c, d.c.URLConf.PayURL, _payOrder, "127.0.0.1", header, params, repl); err != nil {
continue
}
if repl.ErrNo == 0 {
success = true
break
}
}
if !success {
err = fmt.Errorf("下单失败")
}
return
}
func (d *Dao) sortParamsKey(v map[string]string) string {
if v == nil {
return ""
}
var buf bytes.Buffer
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
vs := v[k]
prefix := k + "="
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(prefix)
buf.WriteString(vs)
}
return buf.String()
}
//PaySign pay sign
func (d *Dao) PaySign(params map[string]string, token string) (sign string) {
tmp := d.sortParamsKey(params)
var b bytes.Buffer
b.WriteString(tmp)
b.WriteString(fmt.Sprintf("&token=%s", token))
log.Info("sign params:%v ", b.String())
mh := md5.Sum(b.Bytes())
// query
var qb bytes.Buffer
qb.WriteString(tmp)
qb.WriteString("&sign=")
qb.WriteString(hex.EncodeToString(mh[:]))
sign = hex.EncodeToString(mh[:])
log.Info("sign params(%v) and sign(%v)", b.String(), sign)
return
}
func (d *Dao) doNomalSend(c context.Context, basePath, path, ip string, header map[string]string, params url.Values, data interface{}) (err error) {
var (
req *http.Request
client = new(http.Client)
resp *http.Response
bs []byte
marshal string
)
url := basePath + path
if req, err = d.client.NewRequest(http.MethodPost, url, ip, params); err != nil {
err = errors.WithStack(err)
return
}
for k, v := range header {
req.Header.Add(k, v)
}
if resp, err = client.Do(req); err != nil {
log.Error("call url:%v params:%v", basePath+path, string(marshal))
err = errors.WithStack(err)
return
}
defer resp.Body.Close()
defer func() {
log.Info("call url:%v params:(%v) result:(%+v) header:(%+v)", url, string(marshal), data, header)
}()
if resp.StatusCode >= http.StatusBadRequest {
err = errors.Errorf("incorrect http status:%d host:%s, url:%s", resp.StatusCode, req.URL.Host, req.URL.String())
return
}
if bs, err = readAll(resp.Body, _minRead); err != nil {
err = errors.Wrapf(err, "host:%s, url:%s", req.URL.Host, req.URL.String())
return
}
if err = json.Unmarshal(bs, data); err != nil {
err = errors.WithStack(err)
return
}
return
}
func (d *Dao) doSend(c context.Context, basePath, path, IP string, header map[string]string, params map[string]string, data interface{}) (err error) {
var (
req *http.Request
client = new(http.Client)
resp *http.Response
bs []byte
)
url := basePath + path
marshal, _ := json.Marshal(params)
if req, err = http.NewRequest(http.MethodPost, url, strings.NewReader(string(marshal))); err != nil {
err = errors.WithStack(err)
return
}
for k, v := range header {
req.Header.Add(k, v)
}
if resp, err = client.Do(req); err != nil {
log.Error("call url:%v params:%v", basePath+path, string(marshal))
err = errors.WithStack(err)
return
}
defer resp.Body.Close()
defer func() {
log.Info("call url:%v params:(%v) result:(%+v) header:(%+v)", url, string(marshal), data, header)
}()
if resp.StatusCode >= http.StatusBadRequest {
err = errors.Errorf("incorrect http status:%d host:%s, url:%s", resp.StatusCode, req.URL.Host, req.URL.String())
return
}
if bs, err = readAll(resp.Body, _minRead); err != nil {
err = errors.Wrapf(err, "host:%s, url:%s", req.URL.Host, req.URL.String())
return
}
if err = json.Unmarshal(bs, data); err != nil {
err = errors.WithStack(err)
return
}
return
}
func (d *Dao) doPaySend(c context.Context, basePath, path, IP string, header map[string]string, params map[string]string, data interface{}) (err error) {
sign := d.PaySign(params, d.c.PayConf.Token)
params["sign"] = sign
return d.doSend(c, basePath, path, IP, header, params, data)
}
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
buf := bytes.NewBuffer(make([]byte, 0, capacity))
// If the buffer overflows, we will get bytes.ErrTooLarge.
// Return that as an error. Any other panic remains.
defer func() {
e := recover()
if e == nil {
return
}
if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
err = panicErr
} else {
panic(e)
}
}()
_, err = buf.ReadFrom(r)
return buf.Bytes(), err
}
// SalaryCoupon salary coupon.
func (d *Dao) SalaryCoupon(c context.Context, mid int64, couponType int8, count int64, token string) (err error) {
params := url.Values{}
params.Set("mid", fmt.Sprintf("%d", mid))
params.Set("type", fmt.Sprintf("%d", couponType))
params.Set("count", fmt.Sprintf("%d", count))
params.Set("batch_no", token)
var resp struct {
Code int64 `json:"code"`
}
if err = d.client.Post(c, d.c.Property.SalaryCouponURL, "", params, &resp); err != nil {
log.Error("message url(%s) error(%v)", d.c.Property.SalaryCouponURL+"?"+params.Encode(), err)
return
}
if resp.Code != 0 {
err = fmt.Errorf("POST SalaryCoupon url resp(%v)", resp)
return
}
return
}