Files
x/handler/tunnel/dialer.go
T
ginuerzh e791ba47e2 refactor(handler/tunnel): split 794-line entrypoint.go into 6 files, fix 3 bugs, add 48 tests
Breaking Change: moves Connector, ConnectorPool, parseTunnelID from
tunnel.go into dedicated connector.go and id.go.

Bug Fixes:
- dialer.go: clear stale retry err so SD fallback is not masked (nil err
  from pool.Get() left previous iteration's error live)
- connect.go: check WriteTo errors in both mux and non-mux paths
- eprelay.go: use fresh relay.Response for features sent over mux
  (previously reused same resp struct after resp.WriteTo(muxConn))

Refactor:
- entrypoint.go: split ~790 lines into 6 files (ephttp, eptls, eprelay,
  epwebsocket, eplistener, entrypointsvc), moved to dedicated package
- handler.go: moved initEntrypoints/createEntrypointService to
  entrypointsvc.go
- tunnel.go: moved Connector/ConnectorPool/parseTunnelID to
  connector.go and id.go
- connect.go: moved entrypoint-originated handleConnect to eprelay.go
  (handler-side handleConnect kept in connect.go)

Tests (48 new, 88 total):
- id_test.go: parseTunnelID variants (empty, UUID, private '$', invalid)
- tunnel_test.go: Tunnel lifecycle (AddConnector, GetConnector
  weighted/closed filtering, CloseOnIdle, clean),
  Connector (NewConnector nil-opts, GetConn nil/closed session, Close,
  IsClosed), ConnectorPool (Add/Get/Close, idle cleanup, concurrency)
- dialer_test.go: SD error paths (sd.Get error, empty address)
- handler_test.go: observeStats (nil observer, cancelled context loop),
  initEntrypoints (no entrypoints configured)
- helpers_test.go: testLogger, fakeConn for handler tests
- eprelay_test.go: handleConnect ingress/dial/SD round-trip
2026-06-01 22:20:43 +08:00

80 lines
1.3 KiB
Go

package tunnel
import (
"context"
"net"
"time"
"github.com/go-gost/core/logger"
"github.com/go-gost/core/sd"
)
type Dialer struct {
node string
pool *ConnectorPool
sd sd.SD
retry int
timeout time.Duration
log logger.Logger
}
func (d *Dialer) Dial(ctx context.Context, network string, tid string) (conn net.Conn, node string, cid string, err error) {
retry := d.retry
if retry <= 0 {
retry = 1
}
for i := 0; i < retry; i++ {
c := d.pool.Get(network, tid)
if c == nil {
err = nil // clear stale err so SD fallback is not masked
break
}
conn, err = c.GetConn()
if err != nil {
d.log.Error(err)
continue
}
node = d.node
cid = c.id.String()
break
}
if conn != nil || err != nil {
return
}
if d.sd == nil {
err = ErrTunnelNotAvailable
return
}
ss, err := d.sd.Get(ctx, tid)
if err != nil {
return
}
var service *sd.Service
for _, s := range ss {
d.log.Debugf("%+v", s)
if s.Node != d.node && s.Network == network {
service = s
break
}
}
if service == nil || service.Address == "" {
err = ErrTunnelNotAvailable
return
}
node = service.Node
cid = service.ID
dialer := net.Dialer{
Timeout: d.timeout,
}
conn, err = dialer.DialContext(ctx, "tcp", service.Address)
return
}