This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"iter"
|
||||
"time"
|
||||
|
||||
"gitea.libretechconsulting.com/rmcguire/wingbits/pkg/types/readsb"
|
||||
"gitea.libretechconsulting.com/rmcguire/wingbits/pkg/types/wingbits"
|
||||
)
|
||||
|
||||
// Poll turns any fetch into a pull-based stream: an iter.Seq2[R, error] that
|
||||
// yields a fresh result immediately, then once per interval, until ctx is
|
||||
// cancelled or the consumer breaks out of the range. Each step yields exactly
|
||||
// one of a value or the error from that poll.
|
||||
//
|
||||
// It is the engine behind every Poll* method, exported so the same cadence can
|
||||
// be applied to a custom or composed fetch without re-implementing the loop.
|
||||
// Because the iterator runs in the consumer's goroutine, breaking the range
|
||||
// stops polling immediately — there is no background goroutine to leak.
|
||||
func Poll[R any](ctx context.Context, interval time.Duration, fetch func(context.Context) (R, error)) iter.Seq2[R, error] {
|
||||
return func(yield func(R, error) bool) {
|
||||
tick := time.NewTicker(interval)
|
||||
defer tick.Stop()
|
||||
for {
|
||||
if !yield(fetch(ctx)) {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-tick.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PollAircraft polls aircraft.json every interval, applying the given filters.
|
||||
func (c *Client) PollAircraft(ctx context.Context, interval time.Duration, filters ...readsb.AircraftFilter) iter.Seq2[*readsb.AircraftReport, error] {
|
||||
return Poll(ctx, interval, func(ctx context.Context) (*readsb.AircraftReport, error) {
|
||||
return c.Aircraft(ctx, filters...)
|
||||
})
|
||||
}
|
||||
|
||||
// PollStats polls stats.json every interval.
|
||||
func (c *Client) PollStats(ctx context.Context, interval time.Duration) iter.Seq2[*readsb.Stats, error] {
|
||||
return Poll(ctx, interval, c.Stats)
|
||||
}
|
||||
|
||||
// PollReceiver polls receiver.json every interval.
|
||||
func (c *Client) PollReceiver(ctx context.Context, interval time.Duration) iter.Seq2[*readsb.Receiver, error] {
|
||||
return Poll(ctx, interval, c.Receiver)
|
||||
}
|
||||
|
||||
// PollOutline polls outline.json every interval.
|
||||
func (c *Client) PollOutline(ctx context.Context, interval time.Duration) iter.Seq2[*readsb.Outline, error] {
|
||||
return Poll(ctx, interval, c.Outline)
|
||||
}
|
||||
|
||||
// PollDiagnostics polls /network/diagnostics every interval.
|
||||
func (c *Client) PollDiagnostics(ctx context.Context, interval time.Duration) iter.Seq2[*wingbits.Diagnostics, error] {
|
||||
return Poll(ctx, interval, c.Diagnostics)
|
||||
}
|
||||
|
||||
// PollMetrics polls /metrics every interval.
|
||||
func (c *Client) PollMetrics(ctx context.Context, interval time.Duration) iter.Seq2[*wingbits.Metrics, error] {
|
||||
return Poll(ctx, interval, c.Metrics)
|
||||
}
|
||||
|
||||
// PollStatus polls the Tailscale status every interval.
|
||||
func (c *Client) PollStatus(ctx context.Context, interval time.Duration) iter.Seq2[*wingbits.TailscaleStatus, error] {
|
||||
return Poll(ctx, interval, c.Status)
|
||||
}
|
||||
Reference in New Issue
Block a user