Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+943
View File
@@ -0,0 +1,943 @@
/*
* @Description: In User Settings Edit
* @Author: your name
* @Date: 2019-08-29 19:55:45
* @LastEditTime: 2019-08-30 19:39:56
* @LastEditors: Please set LastEditors
*/
package walletmod
import (
"errors"
"fmt"
"sync"
"time"
"91porn-server/common/db"
"91porn-server/common/log"
"91porn-server/models"
"github.com/shopspring/decimal"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var (
ErrDownloadRequestConflict = errors.New("download request id belongs to another resource")
ErrDownloadCountNotEnough = errors.New("download count is not enough")
ErrDownloadAuthorizationRace = errors.New("download authorization changed concurrently")
)
const maxDownloadRequestHistory = 1000
var mutex sync.Mutex
const table = models.Wallet
func coll(t *db.MongoTool) *db.MongoTool {
if t == nil {
return mdb.Coll(table)
}
return t.Coll(table)
}
func initIndex() {
many := []mongo.IndexModel{
{
Keys: bson.D{{Key: "uid", Value: 1}},
Options: options.Index().SetUnique(true),
},
}
if _, err := coll(nil).CreateIndex(many); err != nil {
panic(fmt.Sprintf("wallet model set index err ==>[%+v]", err))
}
}
func InsertWallet(t *db.MongoTool, w *Wallet) error {
if _, err := coll(t).InsertOne(w); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "InsertWallet", table, "InsertOne", err),
log.Any("w", w),
)
return err
}
return nil
}
// GetWallet 通过uid,查找用户余额
func GetWallet(uid uint64) (w *Wallet, err error) {
w = &Wallet{}
if err = coll(nil).FindOne(w, bson.M{"uid": uid}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetWallet", table, "FindOne", err),
log.Any("uid", uid),
)
}
return
}
func GetWalletMap(uidList []uint64) (map[uint64]Wallet, error) {
if len(uidList) == 0 {
return make(map[uint64]Wallet), nil
}
filter := bson.M{
"uid": bson.M{
"$in": uidList,
},
}
walletList := make([]Wallet, 0, len(uidList))
if err := coll(nil).Find(&walletList, filter); err != nil {
return nil, err
}
walletMap := make(map[uint64]Wallet, len(walletList))
for _, wallet := range walletList {
walletMap[wallet.UID] = wallet
}
return walletMap, nil
}
// CreditAmount 货币增加(虚拟货币)
func CreditAmount(t *db.MongoTool, amt int64, uid uint64) (*Wallet, error) {
w := Wallet{}
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
"$inc": bson.M{"amount": amt},
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditAmount", table, "FindOneAndUpsert", err),
log.Any("amt", amt),
log.Any("uid", uid),
)
return nil, err
}
return &w, nil
}
// DebitAmount 货币扣除(虚拟货币)
func DebitAmount(t *db.MongoTool, amt int64, uid uint64) (*Wallet, error) {
mutex.Lock()
defer mutex.Unlock()
w := Wallet{}
if err := coll(t).FindOneAndUpdate(&w, bson.M{"uid": uid, "amount": bson.M{"$gte": amt}}, bson.M{
"$inc": bson.M{"amount": -amt}}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAmount", table, "FindOneAndUpdate", err),
log.Any("amt", amt),
log.Any("uid", uid),
)
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("not enough balance")
}
return &w, nil
}
// CreditIntegral 新增积分
func CreditIntegral(t *db.MongoTool, integral int64, uid uint64) (*Wallet, error) {
w := Wallet{}
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
"$inc": bson.M{"integral": integral},
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditIntegral", table, "FindOneAndUpsert", err),
log.Any("integral", integral),
log.Any("uid", uid),
)
return nil, err
}
return &w, nil
}
// DebitIntegral 扣除积分
func DebitIntegral(t *db.MongoTool, integral int64, uid uint64) (*Wallet, error) {
mutex.Lock()
defer mutex.Unlock()
w := Wallet{}
if err := coll(t).FindOneAndUpdate(&w, bson.M{"uid": uid, "integral": bson.M{"$gte": integral}}, bson.M{
"$inc": bson.M{"integral": -integral}}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitIntegral", table, "FindOneAndUpdate", err),
log.Any("integral", integral),
log.Any("uid", uid),
)
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("not enough balance")
}
return &w, nil
}
// 扣除金币
// 金币不足则报错
func DebitAmountAndCheck(t *db.MongoTool, uid int64, amt int64) error {
mutex.Lock()
defer mutex.Unlock()
result, err := coll(t).UpdateOne(bson.M{"uid": uid, "amount": bson.M{"$gte": amt}}, bson.M{
"$inc": bson.M{"amount": -amt}})
if err != nil {
return err
}
if result.ModifiedCount != 1 {
return errors.New("金币余额不足")
}
return nil
}
// 扣除金币
// 金币不足则报错
// 包括普通金币和可提现金币
// 先扣除普通金币, 再扣除可提现金币
// t 必须已经开启事务!!!
func DebitAmountDefault(t *db.MongoTool, uid int64, amt int64) error {
mutex.Lock()
defer mutex.Unlock()
var wallet Wallet
if err := coll(t).FindOne(&wallet, bson.M{"uid": uid}); err != nil {
return err
}
if wallet.Amount+wallet.Income < amt {
return errors.New("金币余额不足")
}
if wallet.Amount >= amt {
result, err := coll(t).UpdateOne(bson.M{"uid": uid, "amount": bson.M{"$gte": amt}}, bson.M{
"$inc": bson.M{"amount": -amt}})
if err != nil {
return err
}
if result.ModifiedCount != 1 {
return errors.New("金币余额不足")
}
return nil
}
useIncome := amt - wallet.Amount
result, err := coll(t).UpdateOne(bson.M{"uid": uid, "amount": wallet.Amount, "income": bson.M{"$gte": useIncome}}, bson.M{
"$inc": bson.M{"amount": -wallet.Amount, "income": -useIncome}})
if err != nil {
return err
}
if result.ModifiedCount != 1 {
return errors.New("金币余额不足")
}
return nil
}
// GetAmount 获取金币
func GetAmount(t *db.MongoTool, uid uint64) (int64, error) {
w := &Wallet{}
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetAmount", table, "FindOne", err),
log.Any("uid", uid),
)
return 0, err
}
return w.Amount, nil
}
// GetAmount 获取果币
func GetFruitAmount(t *db.MongoTool, uid uint64) (int64, error) {
w := &Wallet{}
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetAmount", table, "FindOne", err),
log.Any("uid", uid),
)
return 0, err
}
return w.FruitCoin, nil
}
// GetAiMateBalance 获取ai伴侣币余额
func GetAiMateBalance(t *db.MongoTool, uid uint64) (float64, error) {
w := &Wallet{}
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetAmount", table, "FindOne", err),
log.Any("uid", uid),
)
return 0, err
}
return w.AiMateBalance, nil
}
// SetAmount 设置货币(虚拟货币)
func SetAmount(t *db.MongoTool, amt int64, uid uint64) error {
//写入数据库,待完成
if _, err := coll(t).UpdateOne(bson.M{"uid": uid}, bson.M{
"$set": bson.M{"amount": amt},
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "SetAmount", table, "UpdateOne", err),
log.Any("amt", amt),
log.Any("uid", uid),
)
return err
}
return nil
}
// 返回更新前的值 被删除的商人无法更新
func FindUpdate(tool *db.MongoTool, uid uint64, amt int64) (*Wallet, error) {
w := Wallet{}
opt := &options.FindOneAndUpdateOptions{}
opt.SetReturnDocument(options.Before)
if err := coll(tool).FindOneAndUpdate(&w, bson.M{"uid": uid}, bson.M{"$set": bson.M{"amount": amt}}, opt); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindUpdate", table, "FindOneAndUpdate", err))
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("wallet not found")
}
return &w, nil
}
func Debit(t *db.MongoTool, p *DebitPlan, uid uint64) (*Wallet, error) {
if p == nil {
return nil, errors.New("wallet nil DebitPlan")
}
w := &Wallet{}
var err error
if p.Amount != 0 {
w, err = DebitAmount(t, p.Amount, uid)
if err != nil {
return nil, err
}
}
if p.Income != 0 {
w, err = DebitIncome(t, p.Income, uid)
if err != nil {
return nil, err
}
}
if p.Consumption != 0 {
err = CreditConsumption(t, p.Consumption, uid)
if err != nil {
return nil, err
}
}
if p.DownloadCount != 0 {
err = CreditDownloadCount(t, p.DownloadCount, uid)
if err != nil {
return nil, err
}
}
if p.AiUndressFreeTimes != 0 {
w, err = DebitAiFreeTimes(t, p.AiUndressFreeTimes, uid)
if err != nil {
return nil, err
}
}
if p.LotteryTimes != 0 {
w, err = DebitLotteryTimes(t, p.LotteryTimes, uid)
if err != nil {
return nil, err
}
}
if !w.ID.IsZero() {
return w, nil
}
if err = coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("wallet not found")
}
return w, nil
}
// CreditIncomeBasePot
func CreditIncomeBasePot(t *db.MongoTool, incomeInt int64, income float64, pot float64, uid uint64) (*Wallet, error) {
mutex.Lock()
defer mutex.Unlock()
var wallet Wallet
if err := coll(t).FindOneAndUpsert(&wallet, bson.M{"uid": uid}, bson.M{
"$set": bson.M{"incomePot": pot, "vidIncome": income},
"$inc": bson.M{"income": incomeInt},
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditIncome", table, "FindOneAndUpdate", err),
log.Any("income", income),
log.Any("incomePot", pot),
log.Any("uid", uid),
)
return nil, err
}
return &wallet, nil
}
// CreditIncomeBasePotWithReward
func CreditIncomeBasePotWithReward(t *db.MongoTool, incomeInt int64, rewardIncome decimal.Decimal, pot float64, uid uint64) (*Wallet, error) {
var w Wallet
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
"$set": bson.M{"incomePot": pot},
"$inc": bson.M{"income": incomeInt, "rewardIncome": rewardIncome},
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditIncome", table, "FindOneAndUpsert", err),
log.Any("income", incomeInt),
log.Any("incomePot", pot),
log.Any("uid", uid),
)
return nil, err
}
return &w, nil
}
// CreditDebIncome 累计扣量金币 增加
func CreditDebIncome(t *db.MongoTool, income string, uid uint64) error {
debIncr, _ := primitive.ParseDecimal128(income)
//写入数据库,待完成
res, err := coll(t).UpsertOne(bson.M{"uid": uid}, bson.M{
"$inc": bson.M{"dedIncome": debIncr},
})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditDebIncome", table, "UpsertOne", err),
log.Any("income", income),
log.Any("uid", uid),
)
return err
}
if res.UpsertedCount != 1 && res.ModifiedCount != 1 {
return errors.New("Invalid account")
}
return nil
}
// CreditIncome 货币增加
func CreditIncome(t *db.MongoTool, income int64, uid uint64) (*Wallet, error) {
var w Wallet
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
"$inc": bson.M{"income": income},
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditIncome", table, "FindOneAndUpsert", err),
log.Any("income", income),
log.Any("uid", uid),
)
return nil, err
}
return &w, nil
}
// DebitIncome 货币扣除
func DebitIncome(t *db.MongoTool, income int64, uid uint64) (*Wallet, error) {
var w Wallet
if err := coll(t).FindOneAndUpdate(&w, bson.M{"uid": uid, "income": bson.M{"$gte": income}}, bson.M{
"$inc": bson.M{"income": -income},
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitIncome", table, "FindOneAndUpdate", err),
log.Any("income", income),
log.Any("uid", uid),
)
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("wallet not found")
}
return &w, nil
}
// CreditFruitCoin 果币增加
func CreditFruitCoin(t *db.MongoTool, uid uint64, fruitCoin int64) (*Wallet, error) {
var item *Wallet
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$inc": bson.M{"fruitCoin": fruitCoin}}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditFruitCoin", table, "FindOneAndUpsert", err),
log.Any("fruitCoin", fruitCoin),
log.Any("uid", uid),
)
return nil, err
}
return item, nil
}
// UpdateAiMateBalance ai伴侣币修改
func UpdateAiMateBalance(t *db.MongoTool, uid uint64, aiMateBalance float64) (*Wallet, error) {
var item *Wallet
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$set": bson.M{"aiMateBalance": aiMateBalance}}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "UpdateAiMateBalance", table, "FindOneAndUpsert", err),
log.Any("aiMateBalance", aiMateBalance),
log.Any("uid", uid),
)
return nil, err
}
return item, nil
}
// DebitFruitCoin 果币减少
func DebitFruitCoin(t *db.MongoTool, uid uint64, fruitCoin int64) (*Wallet, error) {
var item *Wallet
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$inc": bson.M{"fruitCoin": -fruitCoin}}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitFruitCoin", table, "FindOneAndUpsert", err),
log.Any("fruitCoin", -fruitCoin),
log.Any("uid", uid),
)
return nil, err
}
return item, nil
}
// CreditNudeChatIncome 裸聊收益增加
func CreditNudeChatIncome(t *db.MongoTool, uid uint64, nudeChatIncome int64) (*Wallet, error) {
var item *Wallet
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$inc": bson.M{
"nudeChatIncome": decimal.NewFromInt(nudeChatIncome),
"income": nudeChatIncome,
}}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditNudeChatIncome", table, "FindOneAndUpsert", err),
log.Any("nudeChatIncome", nudeChatIncome),
log.Any("uid", uid),
)
return nil, err
}
return item, nil
}
// DebitNudeChatIncome 裸聊收益减少
func DebitNudeChatIncome(t *db.MongoTool, uid uint64, nudeChatIncome int64) (*Wallet, error) {
var item *Wallet
if err := coll(t).FindOneAndUpsert(&item, bson.M{"uid": uid}, bson.M{"$inc": bson.M{
"nudeChatIncome": decimal.NewFromInt(-nudeChatIncome),
"income": -nudeChatIncome,
}}); err != nil {
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitNudeChatIncome", table, "FindOneAndUpsert", err),
log.Any("nudeChatIncome", nudeChatIncome),
log.Any("uid", uid),
)
return nil, err
}
return item, nil
}
// CreditMoney 货币增加
func CreditMoney(t *db.MongoTool, money int64, uid uint64) error {
//写入数据库,待完成
res, err := coll(t).UpsertOne(bson.M{"uid": uid}, bson.M{
"$inc": bson.M{"money": money},
})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditMoney", table, "UpsertOne", err),
log.Any("money", money),
log.Any("uid", uid),
)
return err
}
if res.UpsertedCount != 1 && res.ModifiedCount != 1 {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditMoney", table, "errors.New", "Invalid account"),
log.Any("money", money),
log.Any("uid", uid),
)
return errors.New("Invalid account")
}
return nil
}
// DebitMoney 货币扣除
func DebitMoney(t *db.MongoTool, money int64, uid uint64) (*Wallet, error) {
w := Wallet{}
if err := coll(t).FindOneAndUpdate(&w, bson.M{"uid": uid, "money": bson.M{"$gte": money}}, bson.M{
"$inc": bson.M{"money": -money},
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitMoney", table, "FindOneAndUpdate", err),
log.Any("money", money),
log.Any("uid", uid),
)
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("not enough balance")
}
return &w, nil
}
// CreditConsumption 总充值增加
func CreditConsumption(t *db.MongoTool, money int64, uid uint64) error {
res, err := coll(t).UpsertOne(bson.M{
"uid": uid,
}, bson.M{
"$inc": bson.M{
"consumption": money,
},
})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditConsumption", table, "UpsertOne", err),
log.Any("money", money),
log.Any("uid", uid),
)
return err
}
if res.UpsertedCount != 1 && res.ModifiedCount != 1 {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditConsumption", table, "errors.New", "Invalid account"),
log.Any("money", money),
log.Any("uid", uid),
)
return errors.New("Invalid account")
}
return nil
}
// CreditDownloadCount 总下载次数加
func CreditDownloadCount(t *db.MongoTool, downloadCount int64, uid uint64) error {
res, err := coll(t).UpsertOne(bson.M{"uid": uid}, bson.M{"$inc": bson.M{"downloadCount": -downloadCount}})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditDownloadCount", table, "UpsertOne", err),
log.Any("downloadCount", downloadCount),
log.Any("uid", uid),
)
return err
}
if res.UpsertedCount != 1 && res.ModifiedCount != 1 {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditDownloadCount", table, "errors.New", "Invalid account"),
log.Any("downloadCount", downloadCount),
log.Any("uid", uid),
)
return errors.New("update DownloadCount err")
}
return nil
}
func Find(filter bson.M) ([]*Wallet, error) {
ws := make([]*Wallet, 0)
if err := coll(nil).Find(&ws, filter); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "Find", table, "Find", err),
log.Any("filter", filter),
)
return nil, err
}
return ws, nil
}
// Credit 货币增加(虚拟货币)
func Credit(t *db.MongoTool, creditPlan CreditPlan, uid uint64) (*Wallet, error) {
w := Wallet{}
if err := coll(t).FindOneAndUpsert(&w, bson.M{"uid": uid}, bson.M{
"$inc": creditPlan,
}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CreditAmount", table, "FindOneAndUpsert", err),
log.Any("creditPlan", creditPlan),
log.Any("uid", uid),
)
return nil, err
}
return &w, nil
}
// DescCredit 货币扣除(虚拟货币)
func DescCredit(t *db.MongoTool, creditPlan CreditPlan, uid uint64) (wallet *Wallet, err error) {
filter := bson.M{"uid": uid}
if creditPlan.Income != nil {
filter["income"] = bson.M{"$gte": creditPlan.Income}
}
if creditPlan.Amount != nil {
filter["amount"] = bson.M{"$gte": creditPlan.Amount}
}
if creditPlan.LotteryTimes != nil {
filter["lotteryTimes"] = bson.M{"$gte": creditPlan.LotteryTimes}
}
err = coll(t).FindOneAndUpsert(&wallet, filter, bson.M{
"$inc": creditPlan,
})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DescCredit", table, "FindOneAndUpsert", err),
log.Any("creditPlan", creditPlan),
log.Any("uid", uid),
)
}
return
}
// 抽奖预扣
func AddFreeze(userId uint64, amt int64) (*Wallet, error) {
filter := bson.M{
"uid": userId,
"amount": bson.M{"$gte": amt},
}
inc := bson.M{
"amount": -amt,
"freezeAmount": amt,
}
w := Wallet{}
if err := coll(nil).FindOneAndUpdate(&w, filter, bson.M{"$inc": inc}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DrawFreeze", table, "FindOneAndUpdate", err),
log.Any("uid", userId),
log.Any("amt", amt),
)
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("not enough balance")
}
return &w, nil
}
// 扣除预扣
func CutFreeze(t *db.MongoTool, userId uint64, amt, amount int64) (*Wallet, error) {
filter := bson.M{
"uid": userId,
"freezeAmount": bson.M{"$gte": amt},
}
inc := bson.M{
"freezeAmount": -amt,
"amount": amount,
}
w := Wallet{}
if err := coll(nil).FindOneAndUpdate(&w, filter, bson.M{"$inc": inc}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CutFreeze", table, "FindOneAndUpdate", err),
log.Any("uid", userId),
log.Any("amt", amt),
)
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("not enough balance")
}
return &w, nil
}
func (w *Wallet) RealAmount() decimal.Decimal {
return decimal.NewFromInt(w.Amount).Add(decimal.NewFromInt(w.Income)).
Add(decimal.NewFromFloat(w.IncomePot)).Add(decimal.NewFromInt(w.Money))
}
func GetRealAmount(w *Wallet) decimal.Decimal {
if w == nil {
return decimal.Decimal{}
}
return decimal.NewFromInt(w.Amount).Add(decimal.NewFromInt(w.Income)).
Add(decimal.NewFromFloat(w.IncomePot)).Add(decimal.NewFromInt(w.Money))
}
func (w *Wallet) RealIntegral() decimal.Decimal {
if w != nil && w.Integral != 0 {
return decimal.NewFromInt(w.Integral)
} else {
return decimal.NewFromInt(0)
}
}
func UpsertOne(t *db.MongoTool, filter bson.M, update bson.M) error {
if _, err := coll(t).UpsertOne(filter, update); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "update", table, "updateOne", err))
return err
}
return nil
}
func BulkWrite(t *db.MongoTool, models []mongo.WriteModel, opts ...*options.BulkWriteOptions) error {
if _, err := coll(t).Bulk(models, opts...); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "update", table, "updateOne", err))
return err
}
return nil
}
// IncUsdtAmount usdt可提现额度加减
func IncUsdtAmount(userId uint64, usdtAmount int64) (*Wallet, error) {
filter := bson.M{"uid": userId}
if usdtAmount < 0 {
filter["usdtAmount"] = bson.M{"$gte": 0}
}
inc := bson.M{"usdtAmount": usdtAmount}
var w Wallet
if err := coll(nil).FindOneAndUpdate(&w, filter, bson.M{"$inc": inc}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "IncUsdtAmount", table, "FindOneAndUpdate", err),
log.Any("uid", userId),
log.Any("amt", usdtAmount),
)
return nil, err
}
if w.ID.IsZero() {
return nil, errors.New("wallet not found")
}
return &w, nil
}
// AddUsdtAmount 增加usdt可提现额度
func AddUsdtAmount(t *db.MongoTool, userId uint64, usdtAmount int64) error {
result, err := coll(t).UpdateOne(bson.M{"uid": userId}, bson.M{"$inc": bson.M{"usdtAmount": usdtAmount}})
if err != nil {
return err
}
if result.ModifiedCount == 0 {
return errors.New("result.ModifiedCount is 0")
}
return nil
}
// IsRechargeUser 是否充值用户
func IsRechargeUser(t *db.MongoTool, uid uint64) bool {
w := &Wallet{}
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "IsRechargeUser", table, "FindOne", err),
log.Any("uid", uid),
)
return false
}
if w.ID.IsZero() || w.Consumption <= 0 {
return false
}
return true
}
// DebitAmountAndIncome 货币扣除(虚拟货币)
func DebitAmountAndIncome(t *db.MongoTool, amt, income int64, uid uint64) (wallet *Wallet, err error) {
mutex.Lock()
defer mutex.Unlock()
filter := bson.M{"uid": uid}
update := bson.M{}
if amt > 0 {
filter["amount"] = bson.M{"$gte": amt}
update["amount"] = -amt
}
if income > 0 {
filter["income"] = bson.M{"$gte": income}
update["income"] = -income
}
err = coll(t).FindOneAndUpdate(&wallet, filter, bson.M{"$inc": update})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAmountAndIncome", table, "FindOneAndUpdate", err),
log.Any("filter", filter),
log.Any("update", update),
log.Any("uid", uid),
)
}
return
}
// ReturnAmountAndIncome 货币返回(虚拟货币)
func ReturnAmountAndIncome(t *db.MongoTool, amt, income int64, uid uint64) (wallet *Wallet, err error) {
mutex.Lock()
defer mutex.Unlock()
filter := bson.M{"uid": uid}
update := bson.M{}
if -amt > 0 {
update["amount"] = -amt
}
if -income > 0 {
update["income"] = -income
}
err = coll(t).FindOneAndUpdate(&wallet, filter, bson.M{"$inc": update})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "ReturnAmountAndIncome", table, "FindOneAndUpdate", err),
log.Any("filter", filter),
log.Any("update", update),
log.Any("uid", uid),
)
}
return
}
// DebitAiFreeTimes 扣出AI脱衣次数
func DebitAiFreeTimes(t *db.MongoTool, freeTimes int64, uid uint64) (wallet *Wallet, err error) {
filter := bson.M{"uid": uid}
if freeTimes > 0 {
filter["aiUndressFreeTimes"] = bson.M{"$gte": freeTimes}
}
err = coll(t).FindOneAndUpsert(&wallet, filter, bson.M{"$inc": bson.M{"aiUndressFreeTimes": -freeTimes}})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAiFreeTimes", table, "FindOneAndUpdate", err),
log.Any("freeTimes", freeTimes),
log.Any("uid", uid),
)
}
return
}
// DebitDownloadCounts 扣出下载次数
func DebitDownloadCounts(t *db.MongoTool, downloadCount int64, uid uint64) (wallet *Wallet, err error) {
filter := bson.M{"uid": uid}
if downloadCount > 0 {
filter["downloadCount"] = bson.M{"$gte": downloadCount}
}
err = coll(t).FindOneAndUpsert(&wallet, filter, bson.M{"$inc": bson.M{"downloadCount": -downloadCount}})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAiDownloadCount", table, "FindOneAndUpdate", err),
log.Any("downloadCount", downloadCount),
log.Any("uid", uid),
)
}
return
}
// AuthorizeDramaDownload atomically records one idempotency key and debits one
// shared download count. The bounded wallet history covers retries even if an
// App instance or Redis cache restarts.
func AuthorizeDramaDownload(t *db.MongoTool, uid uint64, requestKey, fingerprint string, now time.Time) (*Wallet, bool, error) {
wallet := &Wallet{}
if err := coll(t).FindOne(wallet, bson.M{"uid": uid}); err != nil {
return nil, false, err
}
for _, request := range wallet.DownloadRequests {
if request.RequestKey != requestKey {
continue
}
if request.Fingerprint != fingerprint {
return nil, false, ErrDownloadRequestConflict
}
return wallet, false, nil
}
if wallet.DownloadCount <= 0 {
return nil, false, ErrDownloadCountNotEnough
}
record := DownloadRequest{RequestKey: requestKey, Fingerprint: fingerprint, CreatedAt: now}
filter := bson.M{
"uid": uid, "downloadCount": bson.M{"$gte": 1},
"downloadRequests.requestKey": bson.M{"$ne": requestKey},
}
update := bson.M{
"$inc": bson.M{"downloadCount": -1},
"$push": bson.M{"downloadRequests": bson.M{
"$each": []DownloadRequest{record}, "$slice": -maxDownloadRequestHistory,
}},
}
updated := &Wallet{}
if err := coll(t).FindOneAndUpdate(updated, filter, update); err != nil {
return nil, false, err
}
if updated.UID == 0 {
return nil, false, ErrDownloadAuthorizationRace
}
return updated, true, nil
}
// DebitLotteryTimes 扣出抽奖次数
func DebitLotteryTimes(t *db.MongoTool, lotteryTimes int64, uid uint64) (wallet *Wallet, err error) {
filter := bson.M{"uid": uid}
if lotteryTimes > 0 {
filter["lotteryTimes"] = bson.M{"$gte": lotteryTimes}
}
err = coll(t).FindOneAndUpsert(&wallet, filter, bson.M{"$inc": bson.M{"lotteryTimes": -lotteryTimes}})
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DebitAiDownloadCount", table, "FindOneAndUpdate", err),
log.Any("downloadCount", lotteryTimes),
log.Any("uid", uid),
)
}
return
}
// Credit ai伴侣货币增加(虚拟货币)
func CreditAiMate(t *db.MongoTool, amt float64, uid uint64, aiMateOrderId string) (wallet *Wallet, err error) {
update := bson.M{"$inc": bson.M{"aiMateBalance": amt}}
if amt < 0 && aiMateOrderId != "" {
update["$set"] = bson.M{"lastAiMateRecordId": aiMateOrderId}
}
if err = coll(t).FindOneAndUpsert(&wallet, bson.M{"uid": uid}, update); err != nil {
log.Warn(fmt.Sprintf("[METHOD-CreditAmount]==> Model %s FindOneAndUpsert fail error:%+v:", table, err),
log.Any("aiMateBalance", amt),
log.Any("uid", uid),
)
}
return
}
// 重新设置用户ai积分
func SetAiMateBalance(t *db.MongoTool, uid uint64, aiMateBalance float64) error {
mutex.Lock()
defer mutex.Unlock()
_, err := coll(t).UpsertOne(bson.M{"uid": uid}, bson.M{"$set": bson.M{"aiMateBalance": aiMateBalance}})
return err
}
// GetIntegral 获取积分
func GetIntegral(t *db.MongoTool, uid uint64) (int64, error) {
w := &Wallet{}
if err := coll(t).FindOne(w, bson.M{"uid": uid}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetAmount", table, "FindOne", err),
log.Any("uid", uid),
)
return 0, err
}
return w.Integral, nil
}