Exemplo n.º 1
0
func Route(cache etcache.Cache, r *http.Request, etcdKey string, modulos uint64) (io.ReadCloser, error) {
	bucket := HashResource(r.URL.Path) % modulos
	shard := fmt.Sprint(bucket, "-", fmt.Sprint(modulos))

	_master, err := cache.Get(path.Join(etcdKey, shard), false, false)
	if err != nil {
		return nil, err
	}
	master := _master.Node.Value

	httpClient := &http.Client{}
	// `Do` will complain if r.RequestURI is set so we unset it
	r.RequestURI = ""
	r.URL.Scheme = "http"
	r.URL.Host = strings.TrimPrefix(master, "http://")
	resp, err := httpClient.Do(r)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Failed request (%s) to %s.", resp.Status, r.URL.String())
	}
	return resp.Body, nil
}
Exemplo n.º 2
0
// Multicast enables the Ogre Magi to rapidly cast his spells, giving them
// greater potency.
// Multicast sends a request to every host it finds under a key and returns a
// ReadCloser for each one.
func Multicast(cache etcache.Cache, r *http.Request, etcdKey string) ([]*http.Response, error) {
	_endpoints, err := cache.Get(etcdKey, false, true)
	if err != nil {
		return nil, err
	}
	endpoints := _endpoints.Node.Nodes
	if len(endpoints) == 0 {
		return nil, ErrNoHosts
	}

	// If the request has a body we need to store it in memory because it needs
	// to be sent to multiple endpoints and Reader (the type of r.Body) is
	// single use.
	var body []byte
	if r.ContentLength != 0 {
		body, err = ioutil.ReadAll(r.Body)
		if err != nil {
			return nil, err
		}
	}

	var resps []*http.Response
	errors := make(chan error, len(endpoints))
	var lock sync.Mutex
	var wg sync.WaitGroup
	wg.Add(len(endpoints))
	for _, node := range endpoints {
		go func(node *etcd.Node) {
			defer wg.Done()
			httpClient := &http.Client{}
			// First make a request, taking some values from the previous request.
			url := node.Value + r.URL.Path + "?" + r.URL.RawQuery
			req, err := http.NewRequest(r.Method, url,
				ioutil.NopCloser(bytes.NewReader(body)))
			if err != nil {
				errors <- err
				return
			}
			// Send the request
			resp, err := httpClient.Do(req)
			if err != nil {
				errors <- err
				return
			}
			if resp.StatusCode != http.StatusOK {
				errors <- fmt.Errorf("Failed request (%s) to %s.", resp.Status, r.URL.String())
				return
			}
			// Append the request to the response slice.
			lock.Lock()
			resps = append(resps, resp)
			lock.Unlock()
		}(node)
	}
	wg.Wait()
	close(errors)

	for err := range errors {
		if err != nil {
			return nil, err
		}
	}

	return resps, nil
}