go-micro.dev/v5@v5.12.0/util/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  	if strings.Count(addr, ":") == 1 && strings.Count(addr, "-") == 0 {
    32  		return fn(addr)
    33  	}
    34  
    35  	// host:port || host:min-max
    36  	host, ports, err := net.SplitHostPort(addr)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	// try to extract port range
    42  	prange := strings.Split(ports, "-")
    43  
    44  	// single port
    45  	if len(prange) < 2 {
    46  		return fn(addr)
    47  	}
    48  
    49  	// we have a port range
    50  
    51  	// extract min port
    52  	min, err := strconv.Atoi(prange[0])
    53  	if err != nil {
    54  		return nil, errors.New("unable to extract port range")
    55  	}
    56  
    57  	// extract max port
    58  	max, err := strconv.Atoi(prange[1])
    59  	if err != nil {
    60  		return nil, errors.New("unable to extract port range")
    61  	}
    62  
    63  	// range the ports
    64  	for port := min; port <= max; port++ {
    65  		// try bind to host:port
    66  		ln, err := fn(HostPort(host, port))
    67  		if err == nil {
    68  			return ln, nil
    69  		}
    70  
    71  		// hit max port
    72  		if port == max {
    73  			return nil, err
    74  		}
    75  	}
    76  
    77  	// why are we here?
    78  	return nil, fmt.Errorf("unable to bind to %s", addr)
    79  }
    80  
    81  // Proxy returns the proxy and the address if it exits.
    82  func Proxy(service string, address []string) (string, []string, bool) {
    83  	var hasProxy bool
    84  
    85  	// get proxy. we parse out address if present
    86  	if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
    87  		// default name
    88  		if prx == "service" {
    89  			prx = "go.micro.proxy"
    90  			address = nil
    91  		}
    92  
    93  		// check if its an address
    94  		if v := strings.Split(prx, ":"); len(v) > 1 {
    95  			address = []string{prx}
    96  		}
    97  
    98  		service = prx
    99  		hasProxy = true
   100  
   101  		return service, address, hasProxy
   102  	}
   103  
   104  	if prx := os.Getenv("MICRO_NETWORK"); len(prx) > 0 {
   105  		// default name
   106  		if prx == "service" {
   107  			prx = "go.micro.network"
   108  		}
   109  		service = prx
   110  		hasProxy = true
   111  	}
   112  
   113  	if prx := os.Getenv("MICRO_NETWORK_ADDRESS"); len(prx) > 0 {
   114  		address = []string{prx}
   115  		hasProxy = true
   116  	}
   117  
   118  	return service, address, hasProxy
   119  }