SPB Git forge
15commits 1branches 0releases
29.7 MBsize
maindefault branch
10 days agolast push
TypeScript 36.3% Python 31.8% Go 18% JavaScript 9.8% Shell 1.9% SQL 1.4% CSS 0.5%
1.6 KB · 61 lines go
Raw Blame History
1package client23import (4	"sync"5	"time"6)78// Clock estimates clock_offset_ms = local − server from server_time in responses, with half-RTT correction9// (the server stamped the response roughly in the middle of the request round-trip) and an EWMA.10type Clock struct {11	mu      sync.Mutex12	offset  time.Duration13	samples int14	alpha   float6415}1617// NewClock returns an EWMA clock with α = 0.3.18func NewClock() *Clock { return &Clock{alpha: 0.3} }1920// Observe records one sample: request sent at t0 (local), took rtt, server said serverTime.21func (c *Clock) Observe(t0 time.Time, rtt time.Duration, serverTime time.Time) {22	localMid := t0.Add(rtt / 2)23	sample := localMid.Sub(serverTime)24	c.mu.Lock()25	defer c.mu.Unlock()26	if c.samples == 0 {27		c.offset = sample28	} else {29		c.offset = time.Duration(float64(c.offset)*(1-c.alpha) + float64(sample)*c.alpha)30	}31	c.samples++32}3334// Set forces the offset from a single authoritative observation (401 skew resync).35func (c *Clock) Set(localMid, serverTime time.Time) {36	c.mu.Lock()37	defer c.mu.Unlock()38	c.offset = localMid.Sub(serverTime)39	c.samples++40}4142// Offset returns the current estimate (local − server).43func (c *Clock) Offset() time.Duration {44	c.mu.Lock()45	defer c.mu.Unlock()46	return c.offset47}4849// OffsetMs returns the estimate in whole milliseconds.50func (c *Clock) OffsetMs() int64 { return c.Offset().Milliseconds() }5152// Samples returns how many observations were folded in.53func (c *Clock) Samples() int {54	c.mu.Lock()55	defer c.mu.Unlock()56	return c.samples57}5859// ServerNow returns the local time corrected to the server's clock.60func (c *Clock) ServerNow() time.Time { return time.Now().Add(-c.Offset()) }61