From 5ad307868ebdadd0c5b8de25b1dafec5e88395bf Mon Sep 17 00:00:00 2001 From: James Houlahan Date: Thu, 23 Jul 2020 14:55:55 +0200 Subject: [PATCH] feat: add expiry --- internal/smtp/backend.go | 2 +- pkg/confirmer/confirmer.go | 4 ++-- pkg/confirmer/confirmer_test.go | 17 +++++++++++++++++ pkg/confirmer/request.go | 31 ++++++++++++++++++++++++++++--- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/internal/smtp/backend.go b/internal/smtp/backend.go index fee55818..eae408ee 100644 --- a/internal/smtp/backend.go +++ b/internal/smtp/backend.go @@ -105,7 +105,7 @@ func (sb *smtpBackend) shouldReportOutgoingNoEnc() bool { } func (sb *smtpBackend) ConfirmNoEncryption(messageID string, shouldSend bool) { - if err := sb.confirmer.SetResponse(messageID, shouldSend); err != nil { + if err := sb.confirmer.SetResult(messageID, shouldSend); err != nil { logrus.WithError(err).Error("Failed to set confirmation value") } } diff --git a/pkg/confirmer/confirmer.go b/pkg/confirmer/confirmer.go index 5273ad82..eabb59c7 100644 --- a/pkg/confirmer/confirmer.go +++ b/pkg/confirmer/confirmer.go @@ -61,9 +61,9 @@ func (c *Confirmer) SetResult(id string, value bool) error { return errors.New("no such request") } - req.value <- value + req.ch <- value - close(req.value) + close(req.ch) delete(c.requests, id) return nil diff --git a/pkg/confirmer/confirmer_test.go b/pkg/confirmer/confirmer_test.go index ab5de060..58caafe3 100644 --- a/pkg/confirmer/confirmer_test.go +++ b/pkg/confirmer/confirmer_test.go @@ -65,3 +65,20 @@ func TestConfirmerTimeout(t *testing.T) { _, err := req.Result() assert.Error(t, err) } + +func TestConfirmerMultipleRequestCalls(t *testing.T) { + c := New() + + req := c.NewRequest(1 * time.Second) + + go func() { + assert.NoError(t, c.SetResult(req.ID(), true)) + }() + + res, err := req.Result() + assert.NoError(t, err) + assert.True(t, res) + + _, errAgain := req.Result() + assert.Error(t, errAgain) +} diff --git a/pkg/confirmer/request.go b/pkg/confirmer/request.go index 6aa15ace..26217842 100644 --- a/pkg/confirmer/request.go +++ b/pkg/confirmer/request.go @@ -19,6 +19,7 @@ package confirmer import ( "errors" + "sync" "time" "github.com/google/uuid" @@ -27,15 +28,19 @@ import ( // Request provides a result when it becomes available. type Request struct { uuid string - value chan bool + ch chan bool timeout time.Duration + + expired bool + locker sync.Locker } func newRequest(timeout time.Duration) *Request { return &Request{ uuid: uuid.New().String(), - value: make(chan bool), + ch: make(chan bool), timeout: timeout, + locker: &sync.Mutex{}, } } @@ -46,11 +51,31 @@ func (r *Request) ID() string { // Result returns the result or an error if it is not available within the request timeout. func (r *Request) Result() (bool, error) { + if r.hasExpired() { + return false, errors.New("this result has expired") + } + + defer r.done() + select { - case res := <-r.value: + case res := <-r.ch: return res, nil case <-time.After(r.timeout): return false, errors.New("timed out waiting for result") } } + +func (r *Request) hasExpired() bool { + r.locker.Lock() + defer r.locker.Unlock() + + return r.expired +} + +func (r *Request) done() { + r.locker.Lock() + defer r.locker.Unlock() + + r.expired = true +}