|
|
@@ -844,18 +844,64 @@ type topUpRequest struct {
|
|
|
Key string `json:"key"`
|
|
|
}
|
|
|
|
|
|
-var topUpLock = sync.Mutex{}
|
|
|
+var topUpLocks sync.Map
|
|
|
+var topUpCreateLock sync.Mutex
|
|
|
+
|
|
|
+type topUpTryLock struct {
|
|
|
+ ch chan struct{}
|
|
|
+}
|
|
|
+
|
|
|
+func newTopUpTryLock() *topUpTryLock {
|
|
|
+ return &topUpTryLock{ch: make(chan struct{}, 1)}
|
|
|
+}
|
|
|
+
|
|
|
+func (l *topUpTryLock) TryLock() bool {
|
|
|
+ select {
|
|
|
+ case l.ch <- struct{}{}:
|
|
|
+ return true
|
|
|
+ default:
|
|
|
+ return false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (l *topUpTryLock) Unlock() {
|
|
|
+ select {
|
|
|
+ case <-l.ch:
|
|
|
+ default:
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func getTopUpLock(userID int) *topUpTryLock {
|
|
|
+ if v, ok := topUpLocks.Load(userID); ok {
|
|
|
+ return v.(*topUpTryLock)
|
|
|
+ }
|
|
|
+ topUpCreateLock.Lock()
|
|
|
+ defer topUpCreateLock.Unlock()
|
|
|
+ if v, ok := topUpLocks.Load(userID); ok {
|
|
|
+ return v.(*topUpTryLock)
|
|
|
+ }
|
|
|
+ l := newTopUpTryLock()
|
|
|
+ topUpLocks.Store(userID, l)
|
|
|
+ return l
|
|
|
+}
|
|
|
|
|
|
func TopUp(c *gin.Context) {
|
|
|
- topUpLock.Lock()
|
|
|
- defer topUpLock.Unlock()
|
|
|
+ id := c.GetInt("id")
|
|
|
+ lock := getTopUpLock(id)
|
|
|
+ if !lock.TryLock() {
|
|
|
+ c.JSON(http.StatusOK, gin.H{
|
|
|
+ "success": false,
|
|
|
+ "message": "充值处理中,请稍后重试",
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer lock.Unlock()
|
|
|
req := topUpRequest{}
|
|
|
err := c.ShouldBindJSON(&req)
|
|
|
if err != nil {
|
|
|
common.ApiError(c, err)
|
|
|
return
|
|
|
}
|
|
|
- id := c.GetInt("id")
|
|
|
quota, err := model.Redeem(req.Key, id)
|
|
|
if err != nil {
|
|
|
common.ApiError(c, err)
|
|
|
@@ -866,7 +912,6 @@ func TopUp(c *gin.Context) {
|
|
|
"message": "",
|
|
|
"data": quota,
|
|
|
})
|
|
|
- return
|
|
|
}
|
|
|
|
|
|
type UpdateUserSettingRequest struct {
|