github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/internal/net/net.go (about) 1 package net 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "os" 8 "strconv" 9 "strings" 10 ) 11 12 // HostPort format addr and port suitable for dial 13 func HostPort(addr string, port interface{}) string { 14 host := addr 15 if strings.Count(addr, ":") > 0 { 16 host = fmt.Sprintf("[%s]", addr) 17 } 18 // when port is blank or 0, host is a queue name 19 if v, ok := port.(string); ok && v == "" { 20 return host 21 } else if v, ok := port.(int); ok && v == 0 && net.ParseIP(host) == nil { 22 return host 23 } 24 25 return fmt.Sprintf("%s:%v", host, port) 26 } 27 28 // Listen takes addr:portmin-portmax and binds to the first available port 29 // Example: Listen("localhost:5000-6000", fn) 30 func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, error) { 31 32 if strings.Count(addr, ":") == 1 && strings.Count(addr, "-") == 0 { 33 return fn(addr) 34 } 35 36 // host:port || host:min-max 37 host, ports, err := net.SplitHostPort(addr) 38 if err != nil { 39 return nil, err 40 } 41 42 // try to extract port range 43 prange := strings.Split(ports, "-") 44 45 // single port 46 if len(prange) < 2 { 47 return fn(addr) 48 } 49 50 // we have a port range 51 52 // extract min port 53 min, err := strconv.Atoi(prange[0]) 54 if err != nil { 55 return nil, errors.New("unable to extract port range") 56 } 57 58 // extract max port 59 max, err := strconv.Atoi(prange[1]) 60 if err != nil { 61 return nil, errors.New("unable to extract port range") 62 } 63 64 // range the ports 65 for port := min; port <= max; port++ { 66 // try bind to host:port 67 ln, err := fn(HostPort(host, port)) 68 if err == nil { 69 return ln, nil 70 } 71 72 // hit max port 73 if port == max { 74 return nil, err 75 } 76 } 77 78 // why are we here? 79 return nil, fmt.Errorf("unable to bind to %s", addr) 80 } 81 82 // Proxy returns the proxy and the address if it exits 83 func Proxy(service string, address []string) (string, []string, bool) { 84 var hasProxy bool 85 86 // get proxy. we parse out address if present 87 if prx := os.Getenv("VOLTS_PROXY"); len(prx) > 0 { 88 // default name 89 if prx == "service" { 90 prx = "go.volts.proxy" 91 address = nil 92 } 93 94 // check if its an address 95 if v := strings.Split(prx, ":"); len(v) > 1 { 96 address = []string{prx} 97 } 98 99 service = prx 100 hasProxy = true 101 102 return service, address, hasProxy 103 } 104 105 if prx := os.Getenv("VOLTS_NETWORK"); len(prx) > 0 { 106 // default name 107 if prx == "service" { 108 prx = "go.volts.network" 109 } 110 service = prx 111 hasProxy = true 112 } 113 114 if prx := os.Getenv("VOLTS_NETWORK_ADDRESS"); len(prx) > 0 { 115 address = []string{prx} 116 hasProxy = true 117 } 118 119 return service, address, hasProxy 120 }