github.com/m-lab/locate@v0.17.6/clientgeo/locator.go (about)

     1  // Package clientgeo supports interfaces to different data sources to help
     2  // identify client geo location for server selection.
     3  package clientgeo
     4  
     5  import (
     6  	"context"
     7  	"net/http"
     8  
     9  	"github.com/hashicorp/go-multierror"
    10  )
    11  
    12  // Constants defining the X-Locate-* header names produced by Locators.
    13  const (
    14  	hLocateClientlatlon       = "X-Locate-Clientlatlon"
    15  	hLocateClientlatlonMethod = "X-Locate-Clientlatlon-Method"
    16  )
    17  
    18  // Locator supports locating a client request and Reloading the underlying database.
    19  type Locator interface {
    20  	Locate(req *http.Request) (*Location, error)
    21  	Reload(context.Context)
    22  }
    23  
    24  // Location contains an estimated the latitude and longitude of a client IP.
    25  type Location struct {
    26  	Latitude  string
    27  	Longitude string
    28  	Headers   http.Header
    29  }
    30  
    31  // NullLocator always returns a client location of 0,0.
    32  type NullLocator struct{}
    33  
    34  // Locate returns the static 0,0 lat/lon location.
    35  func (f *NullLocator) Locate(req *http.Request) (*Location, error) {
    36  	return &Location{
    37  		Latitude:  "0.000000",
    38  		Longitude: "0.000000",
    39  	}, nil
    40  }
    41  
    42  // Reload does nothing.
    43  func (f *NullLocator) Reload(ctx context.Context) {}
    44  
    45  // MultiLocator wraps several Locator types into the Locate interface.
    46  type MultiLocator []Locator
    47  
    48  // Locate calls Locate on all client Locators. The first successfully identifiec
    49  // location is returned. If all Locators returns an error, a multierror.Error is
    50  // returned as an error with all Locator error messages.
    51  func (g MultiLocator) Locate(req *http.Request) (*Location, error) {
    52  	var merr *multierror.Error
    53  	for _, locator := range g {
    54  		l, err := locator.Locate(req)
    55  		if err != nil {
    56  			merr = multierror.Append(merr, err)
    57  			continue
    58  		}
    59  		return l, nil
    60  	}
    61  	return nil, merr
    62  }
    63  
    64  // Reload calls Reload on all Client Locators.
    65  func (g MultiLocator) Reload(ctx context.Context) {
    66  	for _, locator := range g {
    67  		locator.Reload(ctx)
    68  	}
    69  }