github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/client/web/resolver.go (about)

     1  package web
     2  
     3  import (
     4  	"errors"
     5  	"math/rand"
     6  	"net/http"
     7  	"regexp"
     8  	"strings"
     9  
    10  	"github.com/tickoalcantara12/micro/v3/service/api/resolver"
    11  	res "github.com/tickoalcantara12/micro/v3/service/api/resolver"
    12  	"github.com/tickoalcantara12/micro/v3/service/router"
    13  )
    14  
    15  var re = regexp.MustCompile("^[a-zA-Z0-9]+([a-zA-Z0-9-]*[a-zA-Z0-9]*)?$")
    16  
    17  type WebResolver struct {
    18  	// Options
    19  	Options resolver.Options
    20  	// selector to choose from a pool of nodes
    21  	// Selector selector.Selector
    22  	// router to lookup routes
    23  	Router router.Router
    24  }
    25  
    26  func (r *WebResolver) String() string {
    27  	return "web/resolver"
    28  }
    29  
    30  // Resolve replaces the values of Host, Path, Scheme to calla backend service
    31  // It accounts for subdomains for service names based on namespace
    32  func (r *WebResolver) Resolve(req *http.Request, opts ...res.ResolveOption) (*res.Endpoint, error) {
    33  	// parse the options
    34  	options := resolver.NewResolveOptions(opts...)
    35  
    36  	parts := strings.Split(req.URL.Path, "/")
    37  	if len(parts) < 2 {
    38  		return nil, errors.New("unknown service")
    39  	}
    40  
    41  	if !re.MatchString(parts[1]) {
    42  		return nil, res.ErrInvalidPath
    43  	}
    44  
    45  	// lookup the routes for the service
    46  	query := []router.LookupOption{
    47  		router.LookupNetwork(options.Domain),
    48  	}
    49  
    50  	routes, err := r.Router.Lookup(parts[1], query...)
    51  	if err == router.ErrRouteNotFound {
    52  		return nil, res.ErrNotFound
    53  	} else if err != nil {
    54  		return nil, err
    55  	} else if len(routes) == 0 {
    56  		return nil, res.ErrNotFound
    57  	}
    58  
    59  	// select a random route to use
    60  	// todo: update to use selector once go-micro has updated the interface
    61  	// route, err := r.Selector.Select(routes...)
    62  	// if err != nil {
    63  	// 	return nil, err
    64  	// }
    65  	route := routes[rand.Intn(len(routes))]
    66  
    67  	// we're done
    68  	return &res.Endpoint{
    69  		Name:   parts[1],
    70  		Method: req.Method,
    71  		Host:   route.Address,
    72  		Path:   "/" + strings.Join(parts[2:], "/"),
    73  		Domain: options.Domain,
    74  	}, nil
    75  }