about summary refs log tree commit diff
path: root/pkg/discord/gateway/heartbeat.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/discord/gateway/heartbeat.go')
-rw-r--r--pkg/discord/gateway/heartbeat.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/pkg/discord/gateway/heartbeat.go b/pkg/discord/gateway/heartbeat.go
new file mode 100644
index 0000000..6cefb21
--- /dev/null
+++ b/pkg/discord/gateway/heartbeat.go
@@ -0,0 +1,71 @@
+package gateway
+
+import (
+	"context"
+	"math/rand"
+	"time"
+
+	"github.com/rs/zerolog"
+)
+
+type Heartbeat interface {
+	Start(ctx context.Context, interval uint64)
+
+	ForceHeartbeat()
+	Ack()
+}
+
+var _ Heartbeat = &HeartbeatImpl{}
+
+type HeartbeatImpl struct {
+	ctx     context.Context
+	logger  *zerolog.Logger
+	gateway Gateway
+}
+
+func NewHeartbeat(logger *zerolog.Logger, gateway Gateway) *HeartbeatImpl {
+	return &HeartbeatImpl{
+		ctx:     nil,
+		logger:  logger,
+		gateway: gateway,
+	}
+}
+
+func (h *HeartbeatImpl) Start(ctx context.Context, interval uint64) {
+	h.ctx = ctx
+	go h.heartbeatRoutine(interval)
+}
+
+func (h *HeartbeatImpl) ForceHeartbeat() {
+	h.gateway.Heartbeat()
+}
+
+func (h *HeartbeatImpl) Ack() {
+	// What do we do here?
+	h.logger.Debug().Msg("received heartbeat ack")
+}
+
+func (h *HeartbeatImpl) heartbeatRoutine(interval uint64) {
+	h.logger.Debug().Msgf("beating heart every %dms", interval)
+
+	// REF: heartbeat_interval * jitter
+	jitter := rand.Intn(int(interval))
+	time.Sleep(time.Duration(jitter) * time.Millisecond)
+
+	ticker := time.NewTicker(time.Duration(interval) * time.Millisecond)
+	defer ticker.Stop()
+
+	for {
+		h.logger.Debug().Msg("sending heartbeat")
+		if err := h.gateway.Heartbeat(); err != nil {
+			h.logger.Error().Err(err).Msg("failed to send heartbeat")
+		}
+
+		select {
+		case <-h.ctx.Done():
+			return
+		case <-ticker.C:
+			continue
+		}
+	}
+}