feat: 实现 Go 与 JS/TS SDK 连接收发与其余接口
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
package nixmsg
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// reconnectBackoff 按 DEVELOPMENT 第 9 节:1s 起、加倍、上限 30s、±30% 抖动;
|
||||
// 稳定在线 60s 后恢复到 1s。
|
||||
type reconnectBackoff struct {
|
||||
mu sync.Mutex
|
||||
base time.Duration
|
||||
onlineAt time.Time
|
||||
online bool
|
||||
stable bool
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
func newReconnectBackoff() *reconnectBackoff {
|
||||
return &reconnectBackoff{base: time.Second}
|
||||
}
|
||||
|
||||
func (b *reconnectBackoff) Func(attempt int) time.Duration {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if attempt <= 0 {
|
||||
return 0
|
||||
}
|
||||
d := b.base
|
||||
for i := 1; i < attempt; i++ {
|
||||
d *= 2
|
||||
if d > 30*time.Second {
|
||||
d = 30 * time.Second
|
||||
break
|
||||
}
|
||||
}
|
||||
return withJitter(d)
|
||||
}
|
||||
|
||||
func (b *reconnectBackoff) MarkOnline() {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
b.online = true
|
||||
b.onlineAt = time.Now()
|
||||
b.stable = false
|
||||
if b.timer != nil {
|
||||
b.timer.Stop()
|
||||
}
|
||||
b.timer = time.AfterFunc(60*time.Second, func() {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if b.online {
|
||||
b.stable = true
|
||||
b.base = time.Second
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *reconnectBackoff) MarkOffline() {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if b.timer != nil {
|
||||
b.timer.Stop()
|
||||
b.timer = nil
|
||||
}
|
||||
wasOnline := b.online
|
||||
b.online = false
|
||||
if !wasOnline {
|
||||
// 连接尚未成功就失败:在 Func 内已按 attempt 加倍,这里把 base 提到下次周期的起点。
|
||||
next := b.base * 2
|
||||
if next > 30*time.Second {
|
||||
next = 30 * time.Second
|
||||
}
|
||||
if next < time.Second {
|
||||
next = time.Second
|
||||
}
|
||||
b.base = next
|
||||
return
|
||||
}
|
||||
if b.stable || time.Since(b.onlineAt) >= 60*time.Second {
|
||||
b.base = time.Second
|
||||
b.stable = false
|
||||
return
|
||||
}
|
||||
next := b.base * 2
|
||||
if next > 30*time.Second {
|
||||
next = 30 * time.Second
|
||||
}
|
||||
b.base = next
|
||||
b.stable = false
|
||||
}
|
||||
|
||||
func (b *reconnectBackoff) Base() time.Duration {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.base
|
||||
}
|
||||
|
||||
func withJitter(d time.Duration) time.Duration {
|
||||
// ±30%
|
||||
f := 0.7 + rand.Float64()*0.6
|
||||
return time.Duration(float64(d) * f)
|
||||
}
|
||||
|
||||
// computeBackoffDelay 供单测:无 attempt 与 base 计算无抖动前的标称延迟。
|
||||
func computeBackoffDelay(base time.Duration, attempt int) time.Duration {
|
||||
if attempt <= 0 {
|
||||
return 0
|
||||
}
|
||||
d := base
|
||||
for i := 1; i < attempt; i++ {
|
||||
d *= 2
|
||||
if d > 30*time.Second {
|
||||
return 30 * time.Second
|
||||
}
|
||||
}
|
||||
if d > 30*time.Second {
|
||||
return 30 * time.Second
|
||||
}
|
||||
return d
|
||||
}
|
||||
Reference in New Issue
Block a user