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.
334 lines
7.9 KiB
334 lines
7.9 KiB
package service |
|
|
|
import ( |
|
"context" |
|
"encoding/json" |
|
"fmt" |
|
"sync" |
|
"time" |
|
|
|
"go-common/app/job/main/point/conf" |
|
"go-common/app/job/main/point/dao" |
|
"go-common/app/job/main/point/model" |
|
rpcmdl "go-common/app/service/main/point/model" |
|
"go-common/app/service/main/point/rpc/client" |
|
xsql "go-common/library/database/sql" |
|
"go-common/library/log" |
|
"go-common/library/queue/databus" |
|
xtime "go-common/library/time" |
|
) |
|
|
|
const ( |
|
_vipPointChange = "vip_point_change_history" |
|
_pointChange = "point_change_history" |
|
_insert = "insert" |
|
) |
|
|
|
// Service struct |
|
type Service struct { |
|
c *conf.Config |
|
dao *dao.Dao |
|
oldVipPointDatabus *databus.Databus |
|
pointDatabus *databus.Databus |
|
pointUpdate *databus.Databus |
|
waiter sync.WaitGroup |
|
closed bool |
|
pointRPC *client.Service |
|
} |
|
|
|
// New init |
|
func New(c *conf.Config) (s *Service) { |
|
s = &Service{ |
|
c: c, |
|
dao: dao.New(c), |
|
pointRPC: client.New(c.PointRPC), |
|
} |
|
if c.DataBus.OldVipBinlog != nil { |
|
s.oldVipPointDatabus = databus.New(c.DataBus.OldVipBinlog) |
|
s.waiter.Add(1) |
|
go s.syncoldpointdataproc() |
|
} |
|
if c.DataBus.PointBinlog != nil { |
|
s.pointDatabus = databus.New(c.DataBus.PointBinlog) |
|
s.waiter.Add(1) |
|
go s.pointbinlogproc() |
|
} |
|
if c.DataBus.PointUpdate != nil { |
|
s.pointUpdate = databus.New(c.DataBus.PointUpdate) |
|
s.waiter.Add(1) |
|
go s.pointupdateproc() |
|
} |
|
return s |
|
} |
|
|
|
// Ping Service |
|
func (s *Service) Ping(c context.Context) (err error) { |
|
return s.dao.Ping(c) |
|
} |
|
|
|
// Close Service |
|
func (s *Service) Close() (err error) { |
|
defer s.waiter.Wait() |
|
s.closed = true |
|
s.dao.Close() |
|
if err = s.oldVipPointDatabus.Close(); err != nil { |
|
log.Error("s.oldVipPointDatabus.Close() error(%v)", err) |
|
return |
|
} |
|
if err = s.pointDatabus.Close(); err != nil { |
|
log.Error("s.pointDatabus.Close() error(%v)", err) |
|
return |
|
} |
|
if err = s.pointUpdate.Close(); err != nil { |
|
log.Error("s.pointUpdate.Close() error(%v)", err) |
|
return |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) syncoldpointdataproc() { |
|
defer s.waiter.Done() |
|
var ( |
|
err error |
|
msg *databus.Message |
|
msgChan = s.oldVipPointDatabus.Messages() |
|
ok bool |
|
c = context.Background() |
|
) |
|
for { |
|
msg, ok = <-msgChan |
|
if s.closed || !ok { |
|
log.Info("syncoldpointdataproc msgChan closed") |
|
return |
|
} |
|
if err = msg.Commit(); err != nil { |
|
log.Error("msg.Commit err(%v)", err) |
|
} |
|
message := &model.MsgCanal{} |
|
if err = json.Unmarshal([]byte(msg.Value), message); err != nil { |
|
log.Error("json.Unmarshal(%v) err(%v)", message, err) |
|
continue |
|
} |
|
if message.Table == _vipPointChange { |
|
history := new(model.VipPointChangeHistoryMsg) |
|
if err = json.Unmarshal(message.New, history); err != nil { |
|
log.Error("json.Unmarshal val(%v) error(%v)", string(message.New), err) |
|
continue |
|
} |
|
if message.Action == _insert { |
|
var count int64 |
|
if count, err = s.dao.HistoryCount(c, history.Mid, history.OrderID); err != nil { |
|
log.Error("update point(%v) history(%v)", err, history) |
|
continue |
|
} |
|
if count > 0 { |
|
log.Error("update point change history had repeat record(%v)", history) |
|
continue |
|
} |
|
changeTime, err := time.ParseInLocation("2006-01-02 15:04:05", history.ChangeTime, time.Local) |
|
if err != nil { |
|
log.Error("update point time.ParseInLocation(%s) error(%v)", history.ChangeTime, err) |
|
continue |
|
} |
|
ph := &model.PointHistory{ |
|
Mid: history.Mid, |
|
Point: history.Point, |
|
OrderID: history.OrderID, |
|
ChangeType: int(history.ChangeType), |
|
ChangeTime: xtime.Time(changeTime.Unix()), |
|
RelationID: history.RelationID, |
|
PointBalance: history.PointBalance, |
|
Remark: history.Remark, |
|
Operator: history.Operator, |
|
} |
|
s.updatePointWithHistory(c, ph) |
|
} |
|
} |
|
} |
|
} |
|
|
|
func (s *Service) pointbinlogproc() { |
|
defer s.waiter.Done() |
|
var ( |
|
err error |
|
msg *databus.Message |
|
msgChan = s.pointDatabus.Messages() |
|
ok bool |
|
c = context.Background() |
|
) |
|
for { |
|
msg, ok = <-msgChan |
|
if s.closed || !ok { |
|
log.Info("pointbinlogproc msgChan closed") |
|
return |
|
} |
|
if err = msg.Commit(); err != nil { |
|
log.Error("msg.Commit err(%v)", err) |
|
} |
|
v := &model.MsgCanal{} |
|
if err = json.Unmarshal([]byte(msg.Value), v); err != nil { |
|
log.Error("json.Unmarshal(%v) err(%v)", v, err) |
|
continue |
|
} |
|
if v.Table != _pointChange || v.Action != _insert { |
|
continue |
|
} |
|
h := new(model.VipPointChangeHistoryMsg) |
|
if err = json.Unmarshal(v.New, h); err != nil { |
|
log.Error("json.Unmarshal val(%v) error(%v)", string(v.New), err) |
|
continue |
|
} |
|
log.Info("point change log %+v", h) |
|
s.Notify(c, h) |
|
} |
|
} |
|
|
|
func (s *Service) updatePointWithHistory(c context.Context, ph *model.PointHistory) (pointBalance int64, activePoint int64, err error) { |
|
var ( |
|
tx *xsql.Tx |
|
) |
|
if tx, err = s.dao.BeginTran(c); err != nil { |
|
log.Error("update point mid(%d) %+v record(%v)", ph.Mid, err, ph) |
|
return |
|
} |
|
defer func() { |
|
if err == nil { |
|
if err = tx.Commit(); err != nil { |
|
log.Error("update point tx.Commit %+v record(%v)", err, ph) |
|
tx.Rollback() |
|
} |
|
} else { |
|
tx.Rollback() |
|
} |
|
}() |
|
if pointBalance, err = s.updatePoint(c, tx, ph.Mid, ph.Point, ph); err != nil { |
|
log.Error("update point mid(%d) %+v record(%v)", ph.Mid, err, ph) |
|
return |
|
} |
|
if _, err = s.dao.InsertPointHistory(c, tx, ph); err != nil { |
|
log.Error("update point mid(%d) %+v record(%v)", ph.Mid, err, ph) |
|
return |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) updatePoint(c context.Context, tx *xsql.Tx, mid, point int64, ph *model.PointHistory) (pb int64, err error) { |
|
var ( |
|
pi *model.PointInfo |
|
ver int64 |
|
a int64 |
|
) |
|
if pi, err = s.dao.TxPointInfo(c, tx, mid); err != nil { |
|
log.Error("%+v", err) |
|
return |
|
} |
|
if point == 0 { |
|
return |
|
} |
|
if pi == nil { |
|
if point < 0 { |
|
point = 0 |
|
log.Error("update point<0 mid(%d) (%v)", mid, ph) |
|
} |
|
pb = point |
|
pi = new(model.PointInfo) |
|
pi.Ver = 1 |
|
pi.PointBalance = point |
|
pi.Mid = mid |
|
if a, err = s.dao.InsertPoint(c, tx, pi); err != nil { |
|
log.Error("%v", err) |
|
return |
|
} |
|
if a != 1 { |
|
err = fmt.Errorf("operation failed") |
|
return |
|
} |
|
|
|
} else { |
|
pb = pi.PointBalance + point |
|
if pb < 0 { |
|
pb = 0 |
|
log.Error("update point<0 mid(%d)(%v)", mid, ph) |
|
} |
|
pi.PointBalance = pb |
|
ver = pi.Ver |
|
pi.Ver++ |
|
if a, err = s.dao.UpdatePointInfo(c, tx, pi, ver); err != nil { |
|
log.Error("%v", err) |
|
return |
|
} |
|
if a != 1 { |
|
err = fmt.Errorf("operation failed") |
|
return |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) fixdata(mtimeStr string) (err error) { |
|
var ( |
|
pis []*model.PointInfo |
|
c = context.TODO() |
|
mtime time.Time |
|
) |
|
log.Info("fixdata start ") |
|
if mtime, err = time.ParseInLocation("2006-01-02 15:04:05", mtimeStr, time.Local); err != nil { |
|
log.Error("fixdata ParseInLocation error(%v)", err) |
|
return |
|
} |
|
if pis, err = s.dao.MidsByMtime(c, mtime); err != nil { |
|
log.Error("fixdata err %+v ", err) |
|
return |
|
} |
|
log.Info("fixdata count %d ", len(pis)) |
|
for _, pi := range pis { |
|
log.Info("fixdata ing %v ", pi) |
|
var point int64 |
|
if point, err = s.dao.LastOneHistory(c, pi.Mid); err != nil { |
|
log.Error("fixdata history err %+v ", err) |
|
return |
|
} |
|
if point == pi.PointBalance { |
|
continue |
|
} |
|
log.Info("fixdata mid(%d) %+v ", pi.Mid, err) |
|
var af int64 |
|
if af, err = s.dao.FixPointInfo(c, pi.Mid, point); err != nil { |
|
log.Error("fixdata FixPointInfo mid(%d) %+v ", pi.Mid, err) |
|
return |
|
} |
|
if af != 1 { |
|
log.Error("fixdata af!=1 mid(%d)", pi.Mid) |
|
return |
|
} |
|
} |
|
log.Info("fixdata end ") |
|
return |
|
} |
|
|
|
func (s *Service) pointupdateproc() { |
|
defer s.waiter.Done() |
|
var ( |
|
err error |
|
msg *databus.Message |
|
msgChan = s.pointUpdate.Messages() |
|
ok bool |
|
c = context.Background() |
|
) |
|
for { |
|
msg, ok = <-msgChan |
|
if !ok { |
|
log.Info("pointupdateproc msgChan closed") |
|
return |
|
} |
|
if err = msg.Commit(); err != nil { |
|
log.Error("msg.Commit err(%v)", err) |
|
} |
|
v := &rpcmdl.ArgPointAdd{} |
|
if err = json.Unmarshal([]byte(msg.Value), v); err != nil { |
|
log.Error("json.Unmarshal(%v) err(%v)", v, err) |
|
continue |
|
} |
|
s.pointRPC.PointAddByBp(c, v) |
|
} |
|
}
|
|
|