151 lines
4.2 KiB
Go
151 lines
4.2 KiB
Go
package mysql
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"time"
|
|
|
|
"hyapp/pkg/appcode"
|
|
"hyapp/pkg/xerr"
|
|
)
|
|
|
|
func (r *Repository) creditHostPeriodDiamonds(ctx context.Context, tx *sql.Tx, transactionID string, commandID string, metadata giftMetadata, nowMs int64) (int64, int64, error) {
|
|
|
|
if metadata.HostPeriodDiamondAdded <= 0 {
|
|
return 0, 0, nil
|
|
}
|
|
after, version, exists, err := r.lockHostPeriodDiamondAccount(ctx, tx, metadata.TargetUserID, metadata.HostPeriodCycleKey)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
if !exists {
|
|
|
|
after = metadata.HostPeriodDiamondAdded
|
|
version = 1
|
|
_, err = tx.ExecContext(ctx,
|
|
`INSERT INTO host_period_diamond_accounts (
|
|
app_code, user_id, cycle_key, region_id, agency_owner_user_id, total_diamonds, gift_diamond_total,
|
|
version, first_gift_at_ms, last_gift_at_ms, created_at_ms, updated_at_ms
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
appcode.FromContext(ctx),
|
|
metadata.TargetUserID,
|
|
metadata.HostPeriodCycleKey,
|
|
metadata.TargetHostRegionID,
|
|
metadata.TargetAgencyOwnerUserID,
|
|
after,
|
|
metadata.HostPeriodDiamondAdded,
|
|
version,
|
|
nowMs,
|
|
nowMs,
|
|
nowMs,
|
|
nowMs,
|
|
)
|
|
if err != nil && isMySQLDuplicateError(err) {
|
|
|
|
after, version, exists, err = r.lockHostPeriodDiamondAccount(ctx, tx, metadata.TargetUserID, metadata.HostPeriodCycleKey)
|
|
}
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
if !exists {
|
|
if err := r.insertHostPeriodDiamondEntry(ctx, tx, transactionID, commandID, metadata, after, nowMs); err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return after, version, nil
|
|
}
|
|
}
|
|
|
|
after, err = checkedAdd(after, metadata.HostPeriodDiamondAdded)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
version++
|
|
|
|
result, err := tx.ExecContext(ctx,
|
|
`UPDATE host_period_diamond_accounts
|
|
SET region_id = ?, agency_owner_user_id = ?, total_diamonds = ?, gift_diamond_total = gift_diamond_total + ?,
|
|
version = ?, last_gift_at_ms = ?, updated_at_ms = ?
|
|
WHERE app_code = ? AND user_id = ? AND cycle_key = ?`,
|
|
metadata.TargetHostRegionID,
|
|
metadata.TargetAgencyOwnerUserID,
|
|
after,
|
|
metadata.HostPeriodDiamondAdded,
|
|
version,
|
|
nowMs,
|
|
nowMs,
|
|
appcode.FromContext(ctx),
|
|
metadata.TargetUserID,
|
|
metadata.HostPeriodCycleKey,
|
|
)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
rows, err := result.RowsAffected()
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
if rows != 1 {
|
|
return 0, 0, xerr.New(xerr.LedgerConflict, "host period diamond account version conflict")
|
|
}
|
|
if err := r.insertHostPeriodDiamondEntry(ctx, tx, transactionID, commandID, metadata, after, nowMs); err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return after, version, nil
|
|
}
|
|
|
|
func (r *Repository) lockHostPeriodDiamondAccount(ctx context.Context, tx *sql.Tx, userID int64, cycleKey string) (int64, int64, bool, error) {
|
|
|
|
row := tx.QueryRowContext(ctx,
|
|
`SELECT total_diamonds, version
|
|
FROM host_period_diamond_accounts
|
|
WHERE app_code = ? AND user_id = ? AND cycle_key = ?
|
|
FOR UPDATE`,
|
|
appcode.FromContext(ctx),
|
|
userID,
|
|
cycleKey,
|
|
)
|
|
var totalDiamonds int64
|
|
var version int64
|
|
if err := row.Scan(&totalDiamonds, &version); err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return 0, 0, false, nil
|
|
}
|
|
return 0, 0, false, err
|
|
}
|
|
return totalDiamonds, version, true, nil
|
|
}
|
|
|
|
func (r *Repository) insertHostPeriodDiamondEntry(ctx context.Context, tx *sql.Tx, transactionID string, commandID string, metadata giftMetadata, diamondAfter int64, nowMs int64) error {
|
|
|
|
_, err := tx.ExecContext(ctx,
|
|
`INSERT INTO host_period_diamond_entries (
|
|
app_code, transaction_id, command_id, user_id, cycle_key, region_id, agency_owner_user_id,
|
|
diamond_delta, diamond_after, gift_charge_asset_type, gift_charge_amount,
|
|
gift_id, gift_count, sender_user_id, room_id, created_at_ms
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
appcode.FromContext(ctx),
|
|
transactionID,
|
|
commandID,
|
|
metadata.TargetUserID,
|
|
metadata.HostPeriodCycleKey,
|
|
metadata.TargetHostRegionID,
|
|
metadata.TargetAgencyOwnerUserID,
|
|
metadata.HostPeriodDiamondAdded,
|
|
diamondAfter,
|
|
metadata.ChargeAssetType,
|
|
metadata.ChargeAmount,
|
|
metadata.GiftID,
|
|
metadata.GiftCount,
|
|
metadata.SenderUserID,
|
|
metadata.RoomID,
|
|
nowMs,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func hostPeriodCycleKeyFromMS(ms int64) string {
|
|
|
|
return time.UnixMilli(ms).UTC().Format("2006-01")
|
|
}
|