package holder import ( "context" "errors" "github.com/robfig/cron/v3" "github.com/spf13/cast" "github.com/zeromicro/go-zero/core/logx" "nova_task/internal/model" "nova_task/internal/svc" "time" ) type Cron struct { ctx context.Context svcCtx *svc.ServiceContext } func NewCron(ctx context.Context, svcCtx *svc.ServiceContext) cron.Job { pg := &Cron{ ctx: ctx, svcCtx: svcCtx, } if svcCtx.Config.NftTaskCron.HolderCheckRunOnStart { pg.Run() } return pg } func (c *Cron) Spec() string { return c.svcCtx.Config.NftTaskCron.HolderSpec } func (c *Cron) Run() { logx.Debugw("run Cron cron task") ols, err := GetOwnerList() if err != nil { logx.Errorw("get owner list error", logx.Field("error", err)) return } updateSeq := int(time.Now().Unix()) for _, o := range ols.Owners { for _, tk := range o.TokenBalances { balance := cast.ToInt(tk.Balance) logx.Debugw("owner token", logx.Field("address", o.OwnerAddress), logx.Field("token", tk.TokenID), logx.Field("balance", tk.Balance)) nft, err := c.svcCtx.NftHolderModel.FindOneByTokenId(c.ctx, tk.TokenID) if err != nil { if errors.Is(err, model.ErrNotFound) { nft = &model.NhNftHolder{ Address: o.OwnerAddress, TokenId: tk.TokenID, Balance: balance, UpdateSeq: updateSeq, } } else { logx.Errorw("find nft holder error", logx.Field("error", err), logx.Field("address", o.OwnerAddress), logx.Field("token", tk.TokenID)) continue } } var value int if nft.Id == 0 { // 新增 _, err = c.svcCtx.NftHolderModel.Insert(c.ctx, nft) value = balance } else { // 持有数量变化 value = balance - nft.Balance if value != 0 { nft.Balance = balance nft.UpdateSeq = updateSeq err = c.svcCtx.NftHolderModel.Update(c.ctx, nft) } } if err != nil { logx.Errorw("insert or update nft holder error", logx.Field("error", err), logx.Field("address", o.OwnerAddress), logx.Field("token", tk.TokenID), logx.Field("balance", balance)) } // 余额有变化,记录变化日志 if value != 0 { _, err = c.svcCtx.NftHolderChangeLogModel.Insert(c.ctx, &model.NhNftHolderChangeLog{ Address: o.OwnerAddress, TokenId: tk.TokenID, Value: balance, Balance: balance, }) if err != nil { logx.Errorw("insert nft holder change log error", logx.Field("error", err), logx.Field("address", o.OwnerAddress), logx.Field("token", tk.TokenID)) } } } } // 删除已经不持有的地址,且添加变化日志 nfts, err := c.svcCtx.NftHolderModel.FindOtherUpdateSeq(c.ctx, updateSeq) if err != nil { logx.Errorw("find other update seq error", logx.Field("error", err)) return } for _, nft := range nfts { _, err = c.svcCtx.NftHolderChangeLogModel.Insert(c.ctx, &model.NhNftHolderChangeLog{ Address: nft.Address, TokenId: nft.TokenId, Value: -nft.Balance, Balance: 0, }) if err != nil { logx.Errorw("delete nft holder error", logx.Field("error", err), logx.Field("address", nft.Address), logx.Field("token", nft.TokenId)) } uid, err := c.svcCtx.WalletModel.FindUidByAddress(c.ctx, nft.Address) if err != nil { logx.Errorw("find uid by address error", logx.Field("error", err), logx.Field("address", nft.Address)) continue } err = c.svcCtx.StakeNftModel.UnStakeNft(c.ctx, uid, nft.TokenId, true) if err != nil { logx.Errorw("un stake nft error", logx.Field("error", err), logx.Field("address", nft.Address), logx.Field("token", nft.TokenId)) } } err = c.svcCtx.NftHolderModel.DeleteOtherUpdateSeq(c.ctx, updateSeq) if err != nil { logx.Errorw("delete other update seq error", logx.Field("error", err), logx.Field("update_seq", updateSeq)) } }