You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
470 lines
13 KiB
470 lines
13 KiB
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 |
|
}
|
|
|