fix: устранены блокеры линтера в obf/multi

errcheck nolint на bufPool.Get в rtpopus3/listen.go; multi.MultiProvider
переименован в multi.Provider (revive stutter), дедуп vk.New в buildProvider.
This commit is contained in:
samosvalishe
2026-06-19 15:09:32 +03:00
parent 9564f3475f
commit bafdcdd027
3 changed files with 38 additions and 96 deletions
+14 -28
View File
@@ -130,14 +130,9 @@ func main() {
return c.User, c.Pass, c.ServerAddrs, nil
}
// При нескольких звонках (links) расширяем пул: каждый звонок даёт
// cfg.TURN.N стримов, все объединяются в общий SessionPool.
// Это даёт больше TURN-соединений → выше aggregate пропускная способность.
numLinks := len(cfg.VK.Links)
if numLinks < 1 {
numLinks = 1
}
totalStreams := cfg.TURN.N * numLinks
// Несколько -links расширяют пул: каждый звонок даёт cfg.TURN.N стримов,
// все объединяются в общий пул (больше параллельных TURN-аллокаций).
totalStreams := cfg.TURN.N * max(len(cfg.VK.Links), 1)
if cfg.Proxy.Mode != config.ProxyModeUDP {
tcpDtlsDialer := &dtlsdial.Dialer{
@@ -192,32 +187,16 @@ func main() {
}
}
// buildProvider выбирает реализацию provider.Provider по cfg.Provider.Name.
// При нескольких -links создаёт MultiProvider с одним vk.Provider на каждый link.
// buildProvider строит provider.Provider по cfg.Provider.Name. Одна -links даёт
// обычный vk.Provider; несколько - multi.Provider (один vk.Provider на ссылку).
func buildProvider(cfg *config.Client, dialer net.Dialer, connected *atomic.Int32, logger logx.Logger) (provider.Provider, error) {
switch cfg.Provider.Name {
case config.ProviderVK:
if len(cfg.VK.Links) == 0 {
return nil, fmt.Errorf("vk: no links configured")
}
// Одна ссылка — обычный vk.Provider (backward compat).
if len(cfg.VK.Links) == 1 {
newVK := func(link string) (provider.Provider, error) {
return vk.New(vk.Config{
Link: cfg.VK.Links[0],
Dialer: dialer,
ManualOnly: cfg.VK.ManualCaptcha,
Browser: string(cfg.VK.Browser),
StreamsPerCache: cfg.VK.StreamsPerCred,
StreamsAlive: connected.Load,
Log: logger,
Debug: cfg.Log.Debug,
}, vk.DefaultManualSolver)
}
// Несколько ссылок — MultiProvider. Каждый звонок даёт свой пул
// TURN-реквизитов → больше параллельных стримов.
providers := make([]provider.Provider, 0, len(cfg.VK.Links))
for i, link := range cfg.VK.Links {
p, err := vk.New(vk.Config{
Link: link,
Dialer: dialer,
ManualOnly: cfg.VK.ManualCaptcha,
@@ -227,12 +206,19 @@ func buildProvider(cfg *config.Client, dialer net.Dialer, connected *atomic.Int3
Log: logger,
Debug: cfg.Log.Debug,
}, vk.DefaultManualSolver)
}
if len(cfg.VK.Links) == 1 {
return newVK(cfg.VK.Links[0])
}
providers := make([]provider.Provider, 0, len(cfg.VK.Links))
for i, link := range cfg.VK.Links {
p, err := newVK(link)
if err != nil {
return nil, fmt.Errorf("vk provider [%d]: %w", i, err)
}
providers = append(providers, p)
}
logger.Infof("created MultiProvider with %d VK links (%d total streams)", len(providers), cfg.TURN.N*len(providers))
logger.Infof("multi-provider: %d VK links, %d total streams", len(providers), cfg.TURN.N*len(providers))
return multi.New(providers), nil
default:
return nil, fmt.Errorf("unknown provider %q", cfg.Provider.Name)
+22 -66
View File
@@ -1,6 +1,6 @@
// Package multi - MultiProvider: объединяет несколько provider.Provider
// в один, распределяя streamID по всем провайдерам round-robin.
// Позволяет использовать несколько VK-звонков одновременно для пула TURN-стримов.
// Package multi объединяет несколько provider.Provider в один, распределяя
// streamID по вложенным провайдерам round-robin. Применение: несколько
// VK-звонков как единый пул TURN-стримов (больше параллельных аллокаций).
package multi
import (
@@ -10,102 +10,58 @@ import (
"github.com/samosvalishe/free-turn-proxy/internal/provider"
)
// TCP mode (-mode tcp):
// Локальный TCP-поток (Xray)
//
// │
// ├─ без bond: pool.Pick() → round-robin по всем 30 smux-сессиям
// └─ с bond: bondclient.Handle → страйпинг по всем 30 сессиям
// │
// │ Каждая smux-сессия:
// │ DTLS → KCP → TURN allocate → Server DTLS
// │
// ▼
// Backend (Xray TCP)
//
// UDP mode (-mode udp):
// Локальный UDP (WireGuard)
//
// │
// ▼
// inboundChan → broadcast во все 30 DTLS-стримов
// │
// │ Каждый DTLS-стрим:
// │ (DTLS) → OBF → TURN allocate → Server DTLS
// │
// ▼
// Backend (WireGuard UDP)
//
// MultiProvider распределяет streamID по вложенным провайдерам.
// StreamID 1-based: (streamID-1) % n → выбор провайдера.
// Внутренний streamID: ((streamID-1) / n) + 1 → передаётся выбранному провайдеру.
//
// Например, 3 провайдера × 10 стримов = 30 стримов:
//
// streamID 1,4,7,10,13,16,19,22,25,28 → provider[0] (internal 1..10)
// streamID 2,5,8,11,14,17,20,23,26,29 → provider[1] (internal 1..10)
// streamID 3,6,9,12,15,18,21,24,27,30 → provider[2] (internal 1..10)
type MultiProvider struct {
// Provider распределяет 1-based streamID round-robin: провайдер = (streamID-1) % n,
// внутренний streamID = ((streamID-1) / n) + 1 (биекция, без коллизий).
// Без изменяемого состояния - thread-safe.
type Provider struct {
providers []provider.Provider
n int
}
// New создаёт MultiProvider. Паникует если providers пуст.
func New(providers []provider.Provider) *MultiProvider {
func New(providers []provider.Provider) *Provider {
if len(providers) == 0 {
panic("multi: empty providers")
}
return &MultiProvider{
providers: providers,
n: len(providers),
}
return &Provider{providers: providers, n: len(providers)}
}
// providerFor возвращает провайдера и внутренний streamID для глобального streamID.
func (m *MultiProvider) providerFor(streamID int) (provider.Provider, int) {
func (m *Provider) providerFor(streamID int) (provider.Provider, int) {
idx := (streamID - 1) % m.n
innerID := ((streamID - 1) / m.n) + 1
return m.providers[idx], innerID
}
// GetCredentials делегирует выбранному провайдеру.
func (m *MultiProvider) GetCredentials(ctx context.Context, streamID int) (provider.Credentials, error) {
func (m *Provider) GetCredentials(ctx context.Context, streamID int) (provider.Credentials, error) {
p, innerID := m.providerFor(streamID)
return p.GetCredentials(ctx, innerID)
}
// IsAuthError делегирует первому провайдеру (все VK провайдеры используют
// одинаковую эвристику auth-ошибки — проверку строки ошибки).
func (m *MultiProvider) IsAuthError(err error) bool {
// IsAuthError делегирует первому провайдеру: все вложенные однотипны (VK).
func (m *Provider) IsAuthError(err error) bool {
return m.providers[0].IsAuthError(err)
}
// HandleAuthError делегирует провайдеру, соответствующему streamID.
func (m *MultiProvider) HandleAuthError(streamID int) bool {
func (m *Provider) HandleAuthError(streamID int) bool {
p, innerID := m.providerFor(streamID)
return p.HandleAuthError(innerID)
}
// ResetErrors делегирует провайдеру, соответствующему streamID.
func (m *MultiProvider) ResetErrors(streamID int) {
func (m *Provider) ResetErrors(streamID int) {
p, innerID := m.providerFor(streamID)
p.ResetErrors(innerID)
}
// BackoffUntilUnix возвращает максимальный backoff среди всех провайдеров.
// Консервативно: если хотя бы один провайдер в блокировке, все стримы
// делают короткую паузу вместо tight-spin.
func (m *MultiProvider) BackoffUntilUnix() int64 {
var max int64
// BackoffUntilUnix - максимум среди провайдеров (один в блокировке -> пауза для всех).
func (m *Provider) BackoffUntilUnix() int64 {
var until int64
for _, p := range m.providers {
if v := p.BackoffUntilUnix(); v > max {
max = v
if v := p.BackoffUntilUnix(); v > until {
until = v
}
}
return max
return until
}
// Name возвращает "multi(N)".
func (m *MultiProvider) Name() string {
func (m *Provider) Name() string {
return fmt.Sprintf("multi(%d)", m.n)
}
+2 -2
View File
@@ -59,7 +59,7 @@ type packetConn struct {
}
func (c *packetConn) ReadFrom(p []byte) (int, net.Addr, error) {
bp := bufPool.Get().(*[]byte)
bp := bufPool.Get().(*[]byte) //nolint:errcheck // pool New always returns *[]byte
buf := *bp
need := len(p) + overhead
if cap(buf) < need {
@@ -86,7 +86,7 @@ func (c *packetConn) ReadFrom(p []byte) (int, net.Addr, error) {
func (c *packetConn) WriteTo(p []byte, addr net.Addr) (int, error) {
wireLen := overhead + len(p)
bp := bufPool.Get().(*[]byte)
bp := bufPool.Get().(*[]byte) //nolint:errcheck // pool New always returns *[]byte
out := *bp
if cap(out) < wireLen {
out = make([]byte, wireLen)