github.com/TBD54566975/ftl@v0.219.0/internal/bind/bind_allocator.go (about) 1 package bind 2 3 import ( 4 "net" 5 "net/url" 6 "strconv" 7 8 "github.com/alecthomas/atomic" 9 ) 10 11 type BindAllocator struct { 12 baseURL *url.URL 13 port atomic.Int32 14 } 15 16 func NewBindAllocator(url *url.URL) (*BindAllocator, error) { 17 _, portStr, err := net.SplitHostPort(url.Host) 18 if err != nil { 19 return nil, err 20 } 21 22 port, err := strconv.Atoi(portStr) 23 if err != nil { 24 return nil, err 25 } 26 27 return &BindAllocator{ 28 baseURL: url, 29 port: atomic.NewInt32(int32(port) - 1), //nolint:gosec 30 }, nil 31 } 32 33 func (b *BindAllocator) Next() *url.URL { 34 var l *net.TCPListener 35 var err error 36 for { 37 b.port.Add(1) 38 l, err = net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP(b.baseURL.Hostname()), Port: int(b.port.Load())}) 39 40 if err != nil { 41 continue 42 } 43 _ = l.Close() 44 45 newURL := *b.baseURL 46 newURL.Host = net.JoinHostPort(b.baseURL.Hostname(), strconv.Itoa(int(b.port.Load()))) 47 return &newURL 48 } 49 }