Files
samosvalishe ee30afc922 feat(client): провайдер direct - прямо на сервер без TURN-реле
Тот же DTLS с обфускацией, сервер не меняется. По умолчанию один поток.
2026-09-22 00:07:28 +03:00

95 lines
3.0 KiB
Go

package session
import (
"context"
"fmt"
"net"
"sync/atomic"
"github.com/samosvalishe/free-turn-proxy/internal/config"
"github.com/samosvalishe/free-turn-proxy/internal/logx"
"github.com/samosvalishe/free-turn-proxy/internal/provider"
"github.com/samosvalishe/free-turn-proxy/internal/provider/multi"
"github.com/samosvalishe/free-turn-proxy/internal/provider/vk"
"github.com/samosvalishe/free-turn-proxy/internal/proxy/allocpace"
"github.com/samosvalishe/free-turn-proxy/internal/proxy/udprelay"
"github.com/samosvalishe/free-turn-proxy/internal/transport/turndial"
)
func (s *Session) link(dialer net.Dialer, peer *net.UDPAddr) (udprelay.AuthHandler, udprelay.DialFunc, error) {
log := s.deps.Logger
if s.cfg.Provider.Name == config.ProviderDirect {
log.Infof("provider=%s", config.ProviderDirect)
return udprelay.NopAuth{}, func(ctx context.Context, _ int) (*turndial.Stream, error) {
return turndial.Direct(ctx, peer)
}, nil
}
prov, err := buildProvider(s.cfg, dialer, &s.connected, s.deps.Solver, log, s.total)
if err != nil {
return nil, nil, err
}
log.Infof("provider=%s", prov.Name())
getCreds := func(ctx context.Context, streamID int) (string, string, []string, error) {
c, err := prov.GetCredentials(ctx, streamID)
if err != nil {
return "", "", nil, err
}
return c.User, c.Pass, c.ServerAddrs, nil
}
pacer := allocpace.New(allocpace.DefaultInterval)
turn := s.cfg.TURN
return prov, func(ctx context.Context, streamID int) (*turndial.Stream, error) {
if !pacer.Wait(ctx) {
return nil, ctx.Err()
}
return udprelay.DialTURN(ctx, turn.Host, turn.Port, turn.TransportUDP, peer, streamID, getCreds, log)
}, nil
}
// buildProvider создаёт экземпляр provider.Provider в зависимости от конфигурации.
func buildProvider(
cfg *config.Client,
dialer net.Dialer,
connected *atomic.Int32,
solver vk.ManualSolverFunc,
logger logx.Logger,
total int,
) (provider.Provider, error) {
switch cfg.Provider.Name {
case config.ProviderVK:
if len(cfg.VK.Links) == 0 {
return nil, fmt.Errorf("vk: no links configured")
}
newVK := func(link string) (provider.Provider, error) {
return vk.New(vk.Config{
Link: link,
Dialer: dialer,
ManualOnly: cfg.VK.ManualCaptcha,
Platform: string(cfg.VK.Platform),
StreamsPerCache: cfg.VK.StreamsPerCred,
StreamsAlive: connected.Load,
FingerprintSeed: cfg.ClientID,
StatePaths: vk.DefaultStatePaths(),
Log: logger,
Debug: cfg.Log.Debug,
}, solver)
}
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("multi-provider: %d VK links, %d total streams", len(providers), total)
return multi.New(providers), nil
default:
return nil, fmt.Errorf("unknown provider %q", cfg.Provider.Name)
}
}