code.vegaprotocol.io/vega@v0.79.0/wallet/api/request_controller.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package api 17 18 import ( 19 "fmt" 20 "sync" 21 "time" 22 ) 23 24 type RequestController struct { 25 publicKeysInUse sync.Map 26 27 maximumAttempt uint 28 intervalDelayBetweenRetries time.Duration 29 } 30 31 func (c *RequestController) IsPublicKeyAlreadyInUse(publicKey string) (func(), error) { 32 doneCh, err := c.impatientWait(publicKey) 33 if err != nil { 34 return nil, err 35 } 36 37 go func() { 38 <-doneCh 39 c.publicKeysInUse.Delete(publicKey) 40 }() 41 42 return func() { 43 close(doneCh) 44 }, nil 45 } 46 47 func (c *RequestController) impatientWait(publicKey string) (chan interface{}, error) { 48 tick := time.NewTicker(c.intervalDelayBetweenRetries) 49 defer tick.Stop() 50 51 doneCh := make(chan interface{}) 52 53 attemptsLeft := c.maximumAttempt 54 for attemptsLeft > 0 { 55 if _, alreadyInUse := c.publicKeysInUse.LoadOrStore(publicKey, doneCh); !alreadyInUse { 56 return doneCh, nil 57 } 58 <-tick.C 59 attemptsLeft-- 60 } 61 62 close(doneCh) 63 return nil, fmt.Errorf("this public key %q is already in use, retry later", publicKey) 64 } 65 66 func DefaultRequestController() *RequestController { 67 return NewRequestController( 68 WithMaximumAttempt(10), 69 WithIntervalDelayBetweenRetries(2*time.Second), 70 ) 71 } 72 73 func NewRequestController(opts ...RequestControllerOptionFn) *RequestController { 74 rq := &RequestController{ 75 publicKeysInUse: sync.Map{}, 76 } 77 78 for _, opt := range opts { 79 opt(rq) 80 } 81 82 return rq 83 } 84 85 type RequestControllerOptionFn func(rq *RequestController) 86 87 func WithMaximumAttempt(max uint) RequestControllerOptionFn { 88 return func(rq *RequestController) { 89 rq.maximumAttempt = max 90 } 91 } 92 93 func WithIntervalDelayBetweenRetries(duration time.Duration) RequestControllerOptionFn { 94 return func(rq *RequestController) { 95 rq.intervalDelayBetweenRetries = duration 96 } 97 }