forked from Silverfish/proton-bridge
feat: implement confirmer
This commit is contained in:
44
pkg/confirmer/confirmer.go
Normal file
44
pkg/confirmer/confirmer.go
Normal file
@ -0,0 +1,44 @@
|
||||
package confirmer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Confirmer struct {
|
||||
requests map[string]*Request
|
||||
locker sync.Locker
|
||||
}
|
||||
|
||||
func New() *Confirmer {
|
||||
return &Confirmer{
|
||||
requests: make(map[string]*Request),
|
||||
locker: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Confirmer) NewRequest(timeout time.Duration) *Request {
|
||||
c.locker.Lock()
|
||||
defer c.locker.Unlock()
|
||||
|
||||
req := newRequest(timeout)
|
||||
|
||||
c.requests[req.ID()] = req
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *Confirmer) SetResponse(uuid string, value bool) error {
|
||||
c.locker.Lock()
|
||||
defer c.locker.Unlock()
|
||||
|
||||
req, ok := c.requests[uuid]
|
||||
if !ok {
|
||||
return errors.New("no such request")
|
||||
}
|
||||
|
||||
req.value <- value
|
||||
|
||||
return nil
|
||||
}
|
||||
50
pkg/confirmer/confirmer_test.go
Normal file
50
pkg/confirmer/confirmer_test.go
Normal file
@ -0,0 +1,50 @@
|
||||
package confirmer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfirmerYes(t *testing.T) {
|
||||
c := New()
|
||||
|
||||
req := c.NewRequest(1 * time.Second)
|
||||
|
||||
go func() {
|
||||
assert.NoError(t, c.SetResponse(req.ID(), true))
|
||||
}()
|
||||
|
||||
res, err := req.Result()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, res)
|
||||
}
|
||||
|
||||
func TestConfirmerNo(t *testing.T) {
|
||||
c := New()
|
||||
|
||||
req := c.NewRequest(1 * time.Second)
|
||||
|
||||
go func() {
|
||||
assert.NoError(t, c.SetResponse(req.ID(), false))
|
||||
}()
|
||||
|
||||
res, err := req.Result()
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, res)
|
||||
}
|
||||
|
||||
func TestConfirmerTimeout(t *testing.T) {
|
||||
c := New()
|
||||
|
||||
req := c.NewRequest(1 * time.Second)
|
||||
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
assert.NoError(t, c.SetResponse(req.ID(), true))
|
||||
}()
|
||||
|
||||
_, err := req.Result()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
36
pkg/confirmer/request.go
Normal file
36
pkg/confirmer/request.go
Normal file
@ -0,0 +1,36 @@
|
||||
package confirmer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
uuid string
|
||||
value chan bool
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func newRequest(timeout time.Duration) *Request {
|
||||
return &Request{
|
||||
uuid: uuid.New().String(),
|
||||
value: make(chan bool),
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) ID() string {
|
||||
return r.uuid
|
||||
}
|
||||
|
||||
func (r *Request) Result() (bool, error) {
|
||||
select {
|
||||
case res := <-r.value:
|
||||
return res, nil
|
||||
|
||||
case <-time.After(r.timeout):
|
||||
return false, errors.New("timed out waiting for result")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user