1package diodes
2
3import (
4	"context"
5	"time"
6)
7
8// Diode is any implementation of a diode.
9type Diode interface {
10	Set(GenericDataType)
11	TryNext() (GenericDataType, bool)
12}
13
14// Poller will poll a diode until a value is available.
15type Poller struct {
16	Diode
17	interval time.Duration
18	ctx      context.Context
19}
20
21// PollerConfigOption can be used to setup the poller.
22type PollerConfigOption func(*Poller)
23
24// WithPollingInterval sets the interval at which the diode is queried
25// for new data. The default is 10ms.
26func WithPollingInterval(interval time.Duration) PollerConfigOption {
27	return PollerConfigOption(func(c *Poller) {
28		c.interval = interval
29	})
30}
31
32// WithPollingContext sets the context to cancel any retrieval (Next()). It
33// will not change any results for adding data (Set()). Default is
34// context.Background().
35func WithPollingContext(ctx context.Context) PollerConfigOption {
36	return PollerConfigOption(func(c *Poller) {
37		c.ctx = ctx
38	})
39}
40
41// NewPoller returns a new Poller that wraps the given diode.
42func NewPoller(d Diode, opts ...PollerConfigOption) *Poller {
43	p := &Poller{
44		Diode:    d,
45		interval: 10 * time.Millisecond,
46		ctx:      context.Background(),
47	}
48
49	for _, o := range opts {
50		o(p)
51	}
52
53	return p
54}
55
56// Next polls the diode until data is available or until the context is done.
57// If the context is done, then nil will be returned.
58func (p *Poller) Next() GenericDataType {
59	for {
60		data, ok := p.Diode.TryNext()
61		if !ok {
62			if p.isDone() {
63				return nil
64			}
65
66			time.Sleep(p.interval)
67			continue
68		}
69		return data
70	}
71}
72
73func (p *Poller) isDone() bool {
74	select {
75	case <-p.ctx.Done():
76		return true
77	default:
78		return false
79	}
80}
81