<commit_before>// Copyright 2016 The Serviced Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package web

import (
	"encoding/json"
	"fmt"
	"strings"
	"sync/atomic"
	"time"

	"github.com/control-center/serviced/dao"
	"github.com/control-center/serviced/domain"
	"github.com/control-center/serviced/health"
	"github.com/control-center/serviced/isvcs"
	"github.com/control-center/serviced/metrics"
	"github.com/control-center/serviced/node"
	"github.com/zenoss/glog"
	"github.com/zenoss/go-json-rest"
)

var (
	cachedvalue     atomic.Value
	cachetimeout    = time.Duration(5) * time.Second
	emptyvalue      = []byte{}
	isvcsRootHealth = map[string]health.HealthStatus{
		"alive": health.HealthStatus{
			Status:    health.OK,
			StartedAt: time.Now(),
		},
	}
)

// SetServiceStatsCacheTimeout sets the time in seconds for stats on
// running instances to be cached for the UI.
func SetServiceStatsCacheTimeout(seconds int) {
	cachetimeout = time.Duration(seconds) * time.Second
}

// ConciseServiceStatus contains the information necessary to display the
// status of a service in the UI. It joins running instances with health checks
// with memory stats. It does not include fields unnecessary for status
// display, such as config files or monitoring profiles.
type ConciseServiceStatus struct {
	DockerID        string
	HostID          string
	ID              string
	InSync          bool
	InstanceID      int
	Instances       int
	Name            string
	ParentServiceID string
	PoolID          string
	ServiceID       string
	StartedAt       time.Time
	RAMMax          int64
	RAMLast         int64
	RAMAverage      int64
	HealthChecks    map[string]health.HealthStatus
}

func memoryKey(serviceID, instanceID string) string {
	return fmt.Sprintf("%s-%s", serviceID, instanceID)
}

// convertInstancesToMetric converts dao.RunningServices into the structure the
// metrics API wants
func convertInstancesToMetric(instances []dao.RunningService) []metrics.ServiceInstance {
	svcInstances := make([]metrics.ServiceInstance, len(instances))
	for i, inst := range instances {
		svcInstances[i] = metrics.ServiceInstance{
			inst.ServiceID,
			inst.InstanceID,
		}
	}
	return svcInstances
}

func getAllServiceStatuses(client *node.ControlClient) (statuses []*ConciseServiceStatus, err error) {
	// Get all running service instances
	glog.V(2).Info("Retrieving statuses, memory and health checks for running services")
	var instances []dao.RunningService
	if err := client.GetRunningServices(&empty, &instances); err != nil {
		return nil, err
	}
	if instances == nil {
		glog.V(3).Info("Nil service list returned")
		instances = []dao.RunningService{}
	}

	// Look up memory stats for the last hour
	// Memory stats for isvcs don't work the same way, so we don't append
	// those services to this list yet
	memoryStats := make(map[string]metrics.MemoryUsageStats)
	if len(instances) > 0 {
		response := []metrics.MemoryUsageStats{}
		query := dao.MetricRequest{
			StartTime: time.Now().Add(-time.Hour * 24),
			Instances: convertInstancesToMetric(instances),
		}
		if err := client.GetInstanceMemoryStats(query, &response); err != nil {
			glog.Errorf("Unable to look up instance memory stats (%s)", err)
		}
		for _, mus := range response {
			memoryStats[memoryKey(mus.ServiceID, mus.InstanceID)] = mus
		}
	}

	// Look up health check statuses
	healthChecks := make(map[string]map[string]health.HealthStatus)
	if len(instances) > 0 {
		results := make(map[string]map[int]map[string]health.HealthStatus)
		if err := client.GetServicesHealth(0, &results); err != nil {
			glog.Errorf("Unable to look up health check results (%s)", err)
		}
		for svcid, insts := range results {
			for instid, checks := range insts {
				healthChecks[memoryKey(svcid, string(instid))] = checks
			}
		}
	}

	// Add isvcs to the mix
	isvcInstances := getIRS()
	for _, isvc := range isvcInstances {
		var checks map[string]health.HealthStatus
		instances = append(instances, isvc)
		if isvc.ServiceID == "isvc-internalservices" {
			checks = isvcsRootHealth
		} else {
			results, err := isvcs.Mgr.GetHealthStatus(strings.TrimPrefix(isvc.ServiceID, "isvc-"))
			if err != nil {
				glog.Warningf("Error acquiring health status for %s (%s)", isvc.ServiceID, err)
				continue
			}
			checks = convertDomainHealthToNewHealth(results.HealthStatuses)
		}
		healthChecks[memoryKey(isvc.ServiceID, string(isvc.InstanceID))] = checks
	}
	// Create the concise service statuses
	for _, instance := range instances {
		stat := &ConciseServiceStatus{
			DockerID:        instance.DockerID,
			HostID:          instance.HostID,
			ID:              instance.ID,
			InSync:          instance.InSync,
			InstanceID:      instance.InstanceID,
			Instances:       instance.Instances,
			Name:            instance.Name,
			ParentServiceID: instance.ParentServiceID,
			PoolID:          instance.PoolID,
			ServiceID:       instance.ServiceID,
			StartedAt:       instance.StartedAt,
		}
		key := memoryKey(instance.ServiceID, string(instance.InstanceID))
		if mem, ok := memoryStats[key]; ok {
			stat.RAMMax = mem.Max
			stat.RAMLast = mem.Last
			stat.RAMAverage = mem.Average
		}
		if hc, ok := healthChecks[key]; ok {
			stat.HealthChecks = hc
		}
		statuses = append(statuses, stat)
	}
	return
}

func restGetConciseServiceStatus(w *rest.ResponseWriter, r *rest.Request, client *node.ControlClient) {
	f := func() []byte {
		statuses, err := getAllServiceStatuses(client)
		if err != nil {
			glog.Errorf("Error retrieving service statuses: (%s)", err)
			restServerError(w, err)
		}
		bytes, err := json.Marshal(statuses)
		if err != nil {
			glog.Errorf("Error serializing service statuses: (%s)", err)
			restServerError(w, err)
		}
		return bytes
	}
	w.Header().Set("content-type", "application/json")
	w.Write(getCached(f))
}

func getCached(f func() []byte) []byte {
	val := cachedvalue.Load()
	if val == nil || len(val.([]byte)) == 0 {
		val = f()
		cachedvalue.Store(val)
		go func() {
			time.Sleep(cachetimeout)
			cachedvalue.Store(emptyvalue)
		}()
	}
	return val.([]byte)
}

// ConvertDomainHealthToNewHealth changes the domain health check status into
// a new-style health status for consumption by the UI or other interface.
// Sort of deprecated, in that it will be rendered useless once
// domain.HealthCheckStatus is no longer returned by isvcs.Mgr.
func convertDomainHealthToNewHealth(sources []domain.HealthCheckStatus) map[string]health.HealthStatus {
	var status string
	result := make(map[string]health.HealthStatus)
	for _, hcs := range sources {
		switch hcs.Status {
		case "passed":
			status = health.OK
		case "failed":
			status = health.Failed
		default:
			status = health.Unknown
		}
		// Not going to bother populating Duration, since it doesn't have an
		// analogue in domain.HealthCheckStatus.
		result[hcs.Name] = health.HealthStatus{
			Status:    status,
			StartedAt: time.Unix(hcs.Timestamp, 0),
		}
	}
	return result
}
<commit_msg>Add RAMCommitment to status<commit_after>// Copyright 2016 The Serviced Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package web

import (
	"encoding/json"
	"fmt"
	"strings"
	"sync/atomic"
	"time"

	"github.com/control-center/serviced/dao"
	"github.com/control-center/serviced/domain"
	"github.com/control-center/serviced/health"
	"github.com/control-center/serviced/isvcs"
	"github.com/control-center/serviced/metrics"
	"github.com/control-center/serviced/node"
	"github.com/control-center/serviced/utils"
	"github.com/zenoss/glog"
	"github.com/zenoss/go-json-rest"
)

var (
	cachedvalue     atomic.Value
	cachetimeout    = time.Duration(5) * time.Second
	emptyvalue      = []byte{}
	isvcsRootHealth = map[string]health.HealthStatus{
		"alive": health.HealthStatus{
			Status:    health.OK,
			StartedAt: time.Now(),
		},
	}
)

// SetServiceStatsCacheTimeout sets the time in seconds for stats on
// running instances to be cached for the UI.
func SetServiceStatsCacheTimeout(seconds int) {
	cachetimeout = time.Duration(seconds) * time.Second
}

// ConciseServiceStatus contains the information necessary to display the
// status of a service in the UI. It joins running instances with health checks
// with memory stats. It does not include fields unnecessary for status
// display, such as config files or monitoring profiles.
type ConciseServiceStatus struct {
	DockerID        string
	HostID          string
	ID              string
	InSync          bool
	InstanceID      int
	Instances       int
	Name            string
	ParentServiceID string
	PoolID          string
	ServiceID       string
	StartedAt       time.Time
	RAMMax          int64
	RAMLast         int64
	RAMAverage      int64
	RAMCommitment   utils.EngNotation
	HealthChecks    map[string]health.HealthStatus
}

func memoryKey(serviceID, instanceID string) string {
	return fmt.Sprintf("%s-%s", serviceID, instanceID)
}

// convertInstancesToMetric converts dao.RunningServices into the structure the
// metrics API wants
func convertInstancesToMetric(instances []dao.RunningService) []metrics.ServiceInstance {
	svcInstances := make([]metrics.ServiceInstance, len(instances))
	for i, inst := range instances {
		svcInstances[i] = metrics.ServiceInstance{
			inst.ServiceID,
			inst.InstanceID,
		}
	}
	return svcInstances
}

func getAllServiceStatuses(client *node.ControlClient) (statuses []*ConciseServiceStatus, err error) {
	// Get all running service instances
	glog.V(2).Info("Retrieving statuses, memory and health checks for running services")
	var instances []dao.RunningService
	if err := client.GetRunningServices(&empty, &instances); err != nil {
		return nil, err
	}
	if instances == nil {
		glog.V(3).Info("Nil service list returned")
		instances = []dao.RunningService{}
	}

	// Look up memory stats for the last hour
	// Memory stats for isvcs don't work the same way, so we don't append
	// those services to this list yet
	memoryStats := make(map[string]metrics.MemoryUsageStats)
	if len(instances) > 0 {
		response := []metrics.MemoryUsageStats{}
		query := dao.MetricRequest{
			StartTime: time.Now().Add(-time.Hour * 24),
			Instances: convertInstancesToMetric(instances),
		}
		if err := client.GetInstanceMemoryStats(query, &response); err != nil {
			glog.Errorf("Unable to look up instance memory stats (%s)", err)
		}
		for _, mus := range response {
			memoryStats[memoryKey(mus.ServiceID, mus.InstanceID)] = mus
		}
	}

	// Look up health check statuses
	healthChecks := make(map[string]map[string]health.HealthStatus)
	if len(instances) > 0 {
		results := make(map[string]map[int]map[string]health.HealthStatus)
		if err := client.GetServicesHealth(0, &results); err != nil {
			glog.Errorf("Unable to look up health check results (%s)", err)
		}
		for svcid, insts := range results {
			for instid, checks := range insts {
				healthChecks[memoryKey(svcid, string(instid))] = checks
			}
		}
	}

	// Add isvcs to the mix
	isvcInstances := getIRS()
	for _, isvc := range isvcInstances {
		var checks map[string]health.HealthStatus
		instances = append(instances, isvc)
		if isvc.ServiceID == "isvc-internalservices" {
			checks = isvcsRootHealth
		} else {
			results, err := isvcs.Mgr.GetHealthStatus(strings.TrimPrefix(isvc.ServiceID, "isvc-"))
			if err != nil {
				glog.Warningf("Error acquiring health status for %s (%s)", isvc.ServiceID, err)
				continue
			}
			checks = convertDomainHealthToNewHealth(results.HealthStatuses)
		}
		healthChecks[memoryKey(isvc.ServiceID, string(isvc.InstanceID))] = checks
	}
	// Create the concise service statuses
	for _, instance := range instances {
		stat := &ConciseServiceStatus{
			DockerID:        instance.DockerID,
			HostID:          instance.HostID,
			ID:              instance.ID,
			InSync:          instance.InSync,
			InstanceID:      instance.InstanceID,
			Instances:       instance.Instances,
			Name:            instance.Name,
			ParentServiceID: instance.ParentServiceID,
			PoolID:          instance.PoolID,
			ServiceID:       instance.ServiceID,
			StartedAt:       instance.StartedAt,
			RAMCommitment:   instance.RAMCommitment,
		}
		key := memoryKey(instance.ServiceID, string(instance.InstanceID))
		if mem, ok := memoryStats[key]; ok {
			stat.RAMMax = mem.Max
			stat.RAMLast = mem.Last
			stat.RAMAverage = mem.Average
		}
		if hc, ok := healthChecks[key]; ok {
			stat.HealthChecks = hc
		}
		statuses = append(statuses, stat)
	}
	return
}

func restGetConciseServiceStatus(w *rest.ResponseWriter, r *rest.Request, client *node.ControlClient) {
	f := func() []byte {
		statuses, err := getAllServiceStatuses(client)
		if err != nil {
			glog.Errorf("Error retrieving service statuses: (%s)", err)
			restServerError(w, err)
		}
		bytes, err := json.Marshal(statuses)
		if err != nil {
			glog.Errorf("Error serializing service statuses: (%s)", err)
			restServerError(w, err)
		}
		return bytes
	}
	w.Header().Set("content-type", "application/json")
	w.Write(getCached(f))
}

func getCached(f func() []byte) []byte {
	val := cachedvalue.Load()
	if val == nil || len(val.([]byte)) == 0 {
		val = f()
		cachedvalue.Store(val)
		go func() {
			time.Sleep(cachetimeout)
			cachedvalue.Store(emptyvalue)
		}()
	}
	return val.([]byte)
}

// ConvertDomainHealthToNewHealth changes the domain health check status into
// a new-style health status for consumption by the UI or other interface.
// Sort of deprecated, in that it will be rendered useless once
// domain.HealthCheckStatus is no longer returned by isvcs.Mgr.
func convertDomainHealthToNewHealth(sources []domain.HealthCheckStatus) map[string]health.HealthStatus {
	var status string
	result := make(map[string]health.HealthStatus)
	for _, hcs := range sources {
		switch hcs.Status {
		case "passed":
			status = health.OK
		case "failed":
			status = health.Failed
		default:
			status = health.Unknown
		}
		// Not going to bother populating Duration, since it doesn't have an
		// analogue in domain.HealthCheckStatus.
		result[hcs.Name] = health.HealthStatus{
			Status:    status,
			StartedAt: time.Unix(hcs.Timestamp, 0),
		}
	}
	return result
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Northwestern Mutual.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package handlers

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/Sirupsen/logrus"
	"github.com/northwesternmutual/kanali/config"
	"github.com/northwesternmutual/kanali/controller"
	"github.com/northwesternmutual/kanali/monitor"
	"github.com/northwesternmutual/kanali/utils"
	"github.com/opentracing/opentracing-go"
	"github.com/spf13/viper"
)

// Handler is used to provide additional parameters to an HTTP handler
type Handler struct {
	*controller.Controller
	context.Context
	H func(ctx context.Context, c *controller.Controller, w http.ResponseWriter, r *http.Request, trace opentracing.Span) error
}

func (h Handler) serveHTTP(w http.ResponseWriter, r *http.Request) {

	// start a global trace
	sp := opentracing.StartSpan(fmt.Sprintf("%s %s",
		r.Method,
		r.URL.Path,
	))

	closer, str, err := utils.DupReaderAndString(r.Body)
	if err != nil {
		logrus.Errorf("error copying request body, data may not be as expected: %s", err.Error())
	}

	// copy new reader into freshly drained reader
	r.Body = closer

	sp.SetTag("http.request_body", str)
	sp.SetTag("http.url", r.RequestURI)
	sp.SetTag("http.method", r.Method)

	jsonHeaders, err := json.Marshal(utils.OmitHeaderValues(r.Header, viper.GetString(config.FlagHeaderMaskValue.GetLong()), config.FlagApikeyHeaderKey.GetLong()))
	if err != nil {
		logrus.Warnf("could not marsah request headers into JSON - tracing data maybe not be as expected")
	} else {
		sp.SetTag("http.headers", string(jsonHeaders))
	}

	defer sp.Finish()

	err = h.H(h.Context, h.Controller, w, r, sp)

	// handle request errors
	if err != nil {

		// all errors will need the application/json Content-Type header
		w.Header().Set("Content-Type", "application/json")

		// we'll have multiple types off errors
		switch e := err.(type) {
		case utils.Error:

			sp.SetTag("http.status_code", e.Status())

			// log error
			logrus.WithFields(logrus.Fields{
				"method": r.Method,
				"uri":    r.RequestURI,
			}).Error(e.Error())

			h.Context = monitor.AddCtxMetric(h.Context, "http_response_code", strconv.Itoa(e.Status()))

			errStatus, err := json.Marshal(utils.JSONErr{Code: e.Status(), Msg: e.Error()})
			if err != nil {
				logrus.Warnf("could not marsah request headers into JSON - tracing data maybe not be as expected")
			} else {
				sp.SetTag("http.response_body", string(errStatus))
			}

			// write error code to response
			w.WriteHeader(e.Status())

			// write error message to response
			if err := json.NewEncoder(w).Encode(utils.JSONErr{Code: e.Status(), Msg: e.Error()}); err != nil {
				logrus.Fatal(err.Error())
			}

		default:

			sp.SetTag("http.status_code", http.StatusInternalServerError)

			// log error
			logrus.WithFields(logrus.Fields{
				"method": r.Method,
				"uri":    r.RequestURI,
			}).Error("unknown error")

			h.Context = monitor.AddCtxMetric(h.Context, "http_response_code", strconv.Itoa(http.StatusInternalServerError))

			errStatus, err := json.Marshal(utils.JSONErr{Code: http.StatusInternalServerError, Msg: "unknown error"})
			if err != nil {
				logrus.Warnf("could not marsah request headers into JSON - tracing data maybe not be as expected")
			} else {
				sp.SetTag("http.response_body", string(errStatus))
			}

			// write error code to response
			w.WriteHeader(http.StatusInternalServerError)

			// write error message to response
			if err := json.NewEncoder(w).Encode(utils.JSONErr{Code: http.StatusInternalServerError, Msg: "unknown error"}); err != nil {
				logrus.Fatal(err.Error())
			}

		}
	}
}
<commit_msg>updating ci<commit_after>// Copyright (c) 2017 Northwestern Mutual.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package handlers

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/Sirupsen/logrus"
	"github.com/northwesternmutual/kanali/config"
	"github.com/northwesternmutual/kanali/controller"
	"github.com/northwesternmutual/kanali/monitor"
	"github.com/northwesternmutual/kanali/utils"
	"github.com/opentracing/opentracing-go"
	"github.com/spf13/viper"
)

// Handler is used to provide additional parameters to an HTTP handler
type Handler struct {
	*controller.Controller
	context.Context
	H func(ctx context.Context, c *controller.Controller, w http.ResponseWriter, r *http.Request, trace opentracing.Span) error
}

func (h Handler) serveHTTP(w http.ResponseWriter, r *http.Request) {

	// start a global trace
	sp := opentracing.StartSpan(fmt.Sprintf("%s %s",
		r.Method,
		r.URL.Path,
	))

	closer, str, err := utils.DupReaderAndString(r.Body)
	if err != nil {
		logrus.Errorf("error copying request body, data may not be as expected: %s", err.Error())
	}

	// copy new reader into freshly drained reader
	r.Body = closer

	sp.SetTag("http.request_body", str)
	sp.SetTag("http.url", r.RequestURI)
	sp.SetTag("http.method", r.Method)

	jsonHeaders, err := json.Marshal(utils.OmitHeaderValues(r.Header, viper.GetString(config.FlagHeaderMaskValue.GetLong()), config.FlagApikeyHeaderKey.GetLong()))
	if err != nil {
		logrus.Warnf("could not marsah request headers into JSON - tracing data maybe not be as expected")
	} else {
		sp.SetTag("http.headers", jsonHeaders)
	}

	defer sp.Finish()

	err = h.H(h.Context, h.Controller, w, r, sp)

	// handle request errors
	if err != nil {

		// all errors will need the application/json Content-Type header
		w.Header().Set("Content-Type", "application/json")

		// we'll have multiple types off errors
		switch e := err.(type) {
		case utils.Error:

			sp.SetTag("http.status_code", e.Status())

			// log error
			logrus.WithFields(logrus.Fields{
				"method": r.Method,
				"uri":    r.RequestURI,
			}).Error(e.Error())

			h.Context = monitor.AddCtxMetric(h.Context, "http_response_code", strconv.Itoa(e.Status()))

			errStatus, err := json.Marshal(utils.JSONErr{Code: e.Status(), Msg: e.Error()})
			if err != nil {
				logrus.Warnf("could not marsah request headers into JSON - tracing data maybe not be as expected")
			} else {
				sp.SetTag("http.response_body", string(errStatus))
			}

			// write error code to response
			w.WriteHeader(e.Status())

			// write error message to response
			if err := json.NewEncoder(w).Encode(utils.JSONErr{Code: e.Status(), Msg: e.Error()}); err != nil {
				logrus.Fatal(err.Error())
			}

		default:

			sp.SetTag("http.status_code", http.StatusInternalServerError)

			// log error
			logrus.WithFields(logrus.Fields{
				"method": r.Method,
				"uri":    r.RequestURI,
			}).Error("unknown error")

			h.Context = monitor.AddCtxMetric(h.Context, "http_response_code", strconv.Itoa(http.StatusInternalServerError))

			errStatus, err := json.Marshal(utils.JSONErr{Code: http.StatusInternalServerError, Msg: "unknown error"})
			if err != nil {
				logrus.Warnf("could not marsah request headers into JSON - tracing data maybe not be as expected")
			} else {
				sp.SetTag("http.response_body", string(errStatus))
			}

			// write error code to response
			w.WriteHeader(http.StatusInternalServerError)

			// write error message to response
			if err := json.NewEncoder(w).Encode(utils.JSONErr{Code: http.StatusInternalServerError, Msg: "unknown error"}); err != nil {
				logrus.Fatal(err.Error())
			}

		}
	}
}
<|endoftext|>


<commit_before>package handlers

import (
	"errors"
	"github.com/hacksoc-manchester/www/helpers/crypto"
	"github.com/hacksoc-manchester/www/services/databaseService"
	"github.com/hacksoc-manchester/www/services/emailService"
	"net/http"
	"os"
)

func signUp(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		templates["sign-up"].ExecuteTemplate(w, "layout", reCaptchaSiteKey)

	case "POST":
		firstName := r.PostFormValue("first-name")
		lastName := r.PostFormValue("last-name")
		email := r.PostFormValue("email")
		subscribedToArticles := r.PostFormValue("subscribe-to-articles") == "on"
		subscribedToEvents := r.PostFormValue("subscribe-to-events") == "on"

		var response string

		if reCaptcha.Verify(*r) {
			err := registerUser(firstName, lastName, email, subscribedToArticles, subscribedToEvents)

			if err == nil {
				response = "Welcome! You are now part of our mailing list."
			} else {
				response = err.Error()
			}
		} else {
			response = "Turing test failed. Please try again."
		}

		templates["message"].ExecuteTemplate(w, "layout", messageModel{"Sign Up", response})

	default:
		errorHandler(w, r, http.StatusBadRequest)
	}
}

func registerUser(firstName, lastName, email string, subscribedToArticles, subscribedToEvents bool) error {
	if !subscribedToArticles && !subscribedToEvents {
		return errors.New("Please select at least one subscription.")
	}

	err := databaseService.CreateUser(firstName, lastName, email, subscribedToArticles, subscribedToEvents)

	if err != nil {
		return err
	}

	senderName := "HackSoc"
	senderEmail := os.Getenv("NOREPLY_EMAIL")
	receiverName := firstName + " " + lastName
	subject := "Welcome to HackSoc!"
	message := `You are now part of our mailing list.

                    To unsubscribe, <a href=\"` + getUnsubscribeLink(email) + `">click here.`

	return emailService.Send(senderName, senderEmail, receiverName, email, subject, message)
}

func getUnsubscribeLink(email string) string {
	token, _ := crypto.Encrypt(email)

	return "http://hacksoc.com/unsubscribe?token=" + token
}
<commit_msg>Changed indentation<commit_after>package handlers

import (
	"errors"
	"github.com/hacksoc-manchester/www/helpers/crypto"
	"github.com/hacksoc-manchester/www/services/databaseService"
	"github.com/hacksoc-manchester/www/services/emailService"
	"net/http"
	"os"
)

func signUp(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		templates["sign-up"].ExecuteTemplate(w, "layout", reCaptchaSiteKey)

	case "POST":
		firstName := r.PostFormValue("first-name")
		lastName := r.PostFormValue("last-name")
		email := r.PostFormValue("email")
		subscribedToArticles := r.PostFormValue("subscribe-to-articles") == "on"
		subscribedToEvents := r.PostFormValue("subscribe-to-events") == "on"

		var response string

		if reCaptcha.Verify(*r) {
			err := registerUser(firstName, lastName, email, subscribedToArticles, subscribedToEvents)

			if err == nil {
				response = "Welcome! You are now part of our mailing list."
			} else {
				response = err.Error()
			}
		} else {
			response = "Turing test failed. Please try again."
		}

		templates["message"].ExecuteTemplate(w, "layout", messageModel{"Sign Up", response})

	default:
		errorHandler(w, r, http.StatusBadRequest)
	}
}

func registerUser(firstName, lastName, email string, subscribedToArticles, subscribedToEvents bool) error {
	if !subscribedToArticles && !subscribedToEvents {
		return errors.New("Please select at least one subscription.")
	}

	err := databaseService.CreateUser(firstName, lastName, email, subscribedToArticles, subscribedToEvents)

	if err != nil {
		return err
	}

	senderName := "HackSoc"
	senderEmail := os.Getenv("NOREPLY_EMAIL")
	receiverName := firstName + " " + lastName
	subject := "Welcome to HackSoc!"
	message := `You are now part of our mailing list.

		To unsubscribe, <a href=\"` + getUnsubscribeLink(email) + `">click here.`

	return emailService.Send(senderName, senderEmail, receiverName, email, subject, message)
}

func getUnsubscribeLink(email string) string {
	token, _ := crypto.Encrypt(email)

	return "http://hacksoc.com/unsubscribe?token=" + token
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"							//used for unifrom database access
	"fmt"									//print statements
	"github.com/go-martini/martini"			//extra frame work build on net/http
	_ "github.com/lib/pq"					//go sql driver
	"net/http"								//framework
)

func SetupDB() *sql.DB {
	db, err := sql.Open("postgres", "host=192.168.50.131 user=postgres password=1 dbname=postgres sslmode=disable") 		//my only lib/pq usage? login into postgres database
	PanicIf(err)

	return db
}

func PanicIf(err error) {
	if err != nil {
		panic(err)
	}
}

func ShowDB(db *sql.DB, r *http.Request, rw http.ResponseWriter) { //localhost:3000/?search=name
		search := "%" + r.URL.Query().Get("search") + "%"
		rows, err := db.Query(`SELECT fname, LName, cost, city
                           FROM custauth
                           WHERE FName ILIKE $1
                           OR LName ILIKE $1
                           OR city ILIKE $1`, search)
		PanicIf(err)
		defer rows.Close()

		var FirstName, LastName, cost, city string
		for rows.Next() {
			err := rows.Scan(&FirstName, &LastName, &cost, &city)
			PanicIf(err)
			fmt.Fprintf(rw, "First Name: %s\nLast Name: %s\nCost: %s\nCity: %s\n\n", FirstName, LastName, cost, city)
		}
	}

func InsertPur(r *http.Request, db *sql.DB){
//	_, err := db.Query("INSERT INTO custauth (custid, fname, lname, city,state, country,email,cost,errorflag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,$9)",
	_, err := db.Exec("INSERT INTO custauth (custid, fname, lname, city,state, country,email,cost,errorflag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,$9)",
	r.FormValue("custid"),
		r.FormValue("fname"),
		r.FormValue("lname"),
		r.FormValue("city"),
		r.FormValue("state"),
		r.FormValue("country"),
		r.FormValue("email"),
		r.FormValue("cost"),
		r.FormValue("errorflag"))

	PanicIf(err)
}

func main() {
	m := martini.Classic()
	m.Map(SetupDB())
	m.Get("/", func() string {
    return "192.168.50.131 !"
  })
	m.Get("/show", ShowDB)
	m.Post("/add", InsertPur)
	m.Run()
}
<commit_msg>Update webservice.go<commit_after>package main

import (
	"database/sql"							//used for unifrom database access
	"fmt"									//print statements
	"github.com/go-martini/martini"			//extra frame work build on net/http
	_ "github.com/lib/pq"					//go sql driver
	"net/http"								//framework
)

func SetupDB() *sql.DB {
	db, err := sql.Open("postgres", "host=127.0.0.1 user=postgres password=1 dbname=postgres sslmode=disable") 		//my only lib/pq usage? login into postgres database
	PanicIf(err)

	return db
}

func PanicIf(err error) {
	if err != nil {
		panic(err)
	}
}

func ShowDB(db *sql.DB, r *http.Request, rw http.ResponseWriter) { //localhost:3000/?search=name
		search := "%" + r.URL.Query().Get("search") + "%"
		rows, err := db.Query(`SELECT fname, LName, cost, city
                           FROM custauth
                           WHERE FName ILIKE $1
                           OR LName ILIKE $1
                           OR city ILIKE $1`, search)
		PanicIf(err)
		defer rows.Close()

		var FirstName, LastName, cost, city string
		for rows.Next() {
			err := rows.Scan(&FirstName, &LastName, &cost, &city)
			PanicIf(err)
			fmt.Fprintf(rw, "First Name: %s\nLast Name: %s\nCost: %s\nCity: %s\n\n", FirstName, LastName, cost, city)
		}
	}

func InsertPur(r *http.Request, db *sql.DB){
//	_, err := db.Query("INSERT INTO custauth (custid, fname, lname, city,state, country,email,cost,errorflag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,$9)",
	_, err := db.Exec("INSERT INTO custauth (custid, fname, lname, city,state, country,email,cost,errorflag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,$9)",
	r.FormValue("custid"),
		r.FormValue("fname"),
		r.FormValue("lname"),
		r.FormValue("city"),
		r.FormValue("state"),
		r.FormValue("country"),
		r.FormValue("email"),
		r.FormValue("cost"),
		r.FormValue("errorflag"))

	PanicIf(err)
}

func main() {
	m := martini.Classic()
	m.Map(SetupDB())
	m.Get("/", func() string {
    return "192.168.50.131 !"
  })
	m.Get("/show", ShowDB)
	m.Post("/add", InsertPur)
	m.Run()
}
<|endoftext|>


<commit_before>package gomatrixserverlib

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

var (
	errNoWellKnown = errors.New("No .well-known found")
)

// WellKnownResult is the result of looking up a matrix server's well-known file.
// Located at https://<server_name>/.well-known/matrix/server
type WellKnownResult struct {
	NewAddress     ServerName `json:"m.server"`
	CacheExpiresAt int64
}

// LookupWellKnown looks up a well-known record for a matrix server. If one if
// found, it returns the server to redirect to.
func LookupWellKnown(serverNameType ServerName) (*WellKnownResult, error) {
	serverName := string(serverNameType)

	// Handle ending "/"
	serverName = strings.TrimRight(serverName, "/")

	wellKnownPath := "/.well-known/matrix/server"

	// Request server's well-known record
	resp, err := http.Get("https://" + serverName + wellKnownPath)
	if err != nil {
		return nil, err
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	if resp.StatusCode != 200 {
		return nil, errNoWellKnown
	}

	// Figure out when the cache expiry time of this well-known record is
	cacheControlHeader := resp.Header.Get("Cache-Control")
	expiresHeader := resp.Header.Get("Expires")

	expiryTimestamp := int64(0)

	if expiresHeader != "" {
		// parse the HTTP-date (RFC7231 section 7.1.1.1)
		// Mon Jan 2 15:04:05 -0700 MST 2006
		referenceTimeFormat := "Mon, 02 Jan 2006 15:04:05 MST"
		expiresTime, err := time.Parse(referenceTimeFormat, expiresHeader)
		if err == nil {
			expiryTimestamp = expiresTime.Unix()
		}
	}

	// According to RFC7234 section 5.3, Cache-Control with max-age directive
	// MUST be preferred to Expires header.
	if cacheControlHeader != "" {
		kvPairs := strings.Split(cacheControlHeader, ",")
		for _, keyValuePair := range kvPairs {
			keyValuePair = strings.Trim(keyValuePair, " ")
			pieces := strings.SplitN(keyValuePair, "=", 2)
			if len(pieces) == 2 && strings.EqualFold(pieces[0], "max-age") {
				// max-age is the (maximum) number of seconds this record can
				// be assumed to live
				stringValue := pieces[1]
				age, err := strconv.ParseInt(stringValue, 10, 64)

				if err == nil {
					expiryTimestamp = age + time.Now().Unix()
				}
			}
		}
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// Convert result to JSON
	wellKnownResponse := &WellKnownResult{
		CacheExpiresAt: expiryTimestamp,
	}
	err = json.Unmarshal(body, wellKnownResponse)
	if err != nil {
		return nil, err
	}

	if wellKnownResponse.NewAddress == "" {
		return nil, errors.New("No m.server key found in well-known response")
	}

	// Return result
	return wellKnownResponse, nil
}
<commit_msg>Limit well-known response sizes (#250)<commit_after>package gomatrixserverlib

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"
)

var (
	errNoWellKnown = errors.New("No .well-known found")
)

const WellKnownMaxSize = 50 * 1024 // 50KB

// WellKnownResult is the result of looking up a matrix server's well-known file.
// Located at https://<server_name>/.well-known/matrix/server
type WellKnownResult struct {
	NewAddress     ServerName `json:"m.server"`
	CacheExpiresAt int64
}

// LookupWellKnown looks up a well-known record for a matrix server. If one if
// found, it returns the server to redirect to.
func LookupWellKnown(serverNameType ServerName) (*WellKnownResult, error) {
	serverName := string(serverNameType)

	// Handle ending "/"
	serverName = strings.TrimRight(serverName, "/")

	wellKnownPath := "/.well-known/matrix/server"

	// Request server's well-known record
	resp, err := http.Get("https://" + serverName + wellKnownPath)
	if err != nil {
		return nil, err
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	if resp.StatusCode != 200 {
		return nil, errNoWellKnown
	}

	// If the remote server reports a Content-Length to us then make sure
	// that the well-known response size doesn't exceed WellKnownMaxSize.
	contentLengthHeader := resp.Header.Get("Content-Length")
	if l, err := strconv.Atoi(contentLengthHeader); err == nil && l > WellKnownMaxSize {
		return nil, fmt.Errorf("well-known content length %d exceeds %d bytes", l, WellKnownMaxSize)
	}

	// Figure out when the cache expiry time of this well-known record is
	cacheControlHeader := resp.Header.Get("Cache-Control")
	expiresHeader := resp.Header.Get("Expires")

	expiryTimestamp := int64(0)

	if expiresHeader != "" {
		// parse the HTTP-date (RFC7231 section 7.1.1.1)
		// Mon Jan 2 15:04:05 -0700 MST 2006
		referenceTimeFormat := "Mon, 02 Jan 2006 15:04:05 MST"
		expiresTime, err := time.Parse(referenceTimeFormat, expiresHeader)
		if err == nil {
			expiryTimestamp = expiresTime.Unix()
		}
	}

	// According to RFC7234 section 5.3, Cache-Control with max-age directive
	// MUST be preferred to Expires header.
	if cacheControlHeader != "" {
		kvPairs := strings.Split(cacheControlHeader, ",")
		for _, keyValuePair := range kvPairs {
			keyValuePair = strings.Trim(keyValuePair, " ")
			pieces := strings.SplitN(keyValuePair, "=", 2)
			if len(pieces) == 2 && strings.EqualFold(pieces[0], "max-age") {
				// max-age is the (maximum) number of seconds this record can
				// be assumed to live
				stringValue := pieces[1]
				age, err := strconv.ParseInt(stringValue, 10, 64)

				if err == nil {
					expiryTimestamp = age + time.Now().Unix()
				}
			}
		}
	}

	// By this point we hope that we've caught any huge well-known records
	// by checking Content-Length, but it's possible that header will be
	// missing. Better to be safe than sorry by reading no more than the
	// WellKnownMaxSize in any case.
	bodyBuffer := make([]byte, WellKnownMaxSize)
	limitedReader := &io.LimitedReader{
		R: resp.Body,
		N: WellKnownMaxSize,
	}
	n, err := limitedReader.Read(bodyBuffer)
	if err != nil {
		return nil, err
	}
	body := bodyBuffer[:n]

	// Convert result to JSON
	wellKnownResponse := &WellKnownResult{
		CacheExpiresAt: expiryTimestamp,
	}
	err = json.Unmarshal(body, wellKnownResponse)
	if err != nil {
		return nil, err
	}

	if wellKnownResponse.NewAddress == "" {
		return nil, errors.New("No m.server key found in well-known response")
	}

	// Return result
	return wellKnownResponse, nil
}
<|endoftext|>


<commit_before>package servicehttp

import (
	"net/http"
	"strings"

	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/service"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
)

// KeyFunc examines an HTTP request and produces the service key to use when finding
// an instance to use.
//
// The device.IDHashParser function is a valid KeyFunc, and is the typical one used by WebPA.
type KeyFunc func(*http.Request) ([]byte, error)

// RedirectHandler is an http.Handler that redirects all incoming requests using a key obtained
// from a request.  The Accessor is passed the key to return the appropriate instance to redirect to.
type RedirectHandler struct {
	// Logger is the logger to which all output from ServeHTTP is sent
	Logger log.Logger

	// KeyFunc is the function used to extract a hash key from a request
	KeyFunc KeyFunc

	// Accessor produces instances given hash keys.  Note that a Subscription implements the Accessor interface.
	Accessor service.Accessor

	// RedirectCode is the HTTP status code sent as part of the redirect.  If not set, http.StatusTemporaryRedirect is used.
	RedirectCode int
}

func (rh *RedirectHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	key, err := rh.KeyFunc(request)
	if err != nil {
		rh.Logger.Log(level.Key(), level.ErrorValue(), logging.MessageKey(), "unable to obtain service key from request", logging.ErrorKey(), err)
		http.Error(response, err.Error(), http.StatusBadRequest)
		return
	}

	instance, err := rh.Accessor.Get(key)
	if err != nil {
		rh.Logger.Log(level.Key(), level.ErrorValue(), logging.MessageKey(), "accessor failed to return an instance", logging.ErrorKey(), err)
		http.Error(response, err.Error(), http.StatusInternalServerError)
		return
	}

	instance += strings.TrimRight(request.RequestURI, "/")
	rh.Logger.Log(level.Key(), level.DebugValue(), logging.MessageKey(), "redirecting", "instance", instance)

	code := rh.RedirectCode
	if code < 300 {
		code = http.StatusTemporaryRedirect
	}

	http.Redirect(response, request, instance, code)
}
<commit_msg>redirectHandler: get logger from context when error<commit_after>package servicehttp

import (
	"net/http"
	"strings"

	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/service"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
)

// KeyFunc examines an HTTP request and produces the service key to use when finding
// an instance to use.
//
// The device.IDHashParser function is a valid KeyFunc, and is the typical one used by WebPA.
type KeyFunc func(*http.Request) ([]byte, error)

// RedirectHandler is an http.Handler that redirects all incoming requests using a key obtained
// from a request.  The Accessor is passed the key to return the appropriate instance to redirect to.
type RedirectHandler struct {
	// Logger is the logger to which all output from ServeHTTP is sent
	Logger log.Logger

	// KeyFunc is the function used to extract a hash key from a request
	KeyFunc KeyFunc

	// Accessor produces instances given hash keys.  Note that a Subscription implements the Accessor interface.
	Accessor service.Accessor

	// RedirectCode is the HTTP status code sent as part of the redirect.  If not set, http.StatusTemporaryRedirect is used.
	RedirectCode int
}

func (rh *RedirectHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	key, err := rh.KeyFunc(request)
	if err != nil {
		ctxLogger := logging.GetLogger(request.Context())
		rh.Logger = ctxLogger
		rh.Logger.Log(level.Key(), level.ErrorValue(), logging.MessageKey(), "unable to obtain service key from request", logging.ErrorKey(), err)
		http.Error(response, err.Error(), http.StatusBadRequest)
		return
	}

	instance, err := rh.Accessor.Get(key)
	if err != nil {
		rh.Logger.Log(level.Key(), level.ErrorValue(), logging.MessageKey(), "accessor failed to return an instance", logging.ErrorKey(), err)
		http.Error(response, err.Error(), http.StatusInternalServerError)
		return
	}

	instance += strings.TrimRight(request.RequestURI, "/")
	rh.Logger.Log(level.Key(), level.DebugValue(), logging.MessageKey(), "redirecting", "instance", instance)

	code := rh.RedirectCode
	if code < 300 {
		code = http.StatusTemporaryRedirect
	}

	http.Redirect(response, request, instance, code)
}
<|endoftext|>


<commit_before>// Find local, non-loopback IP address
//
// Skips docker bridge address and IPv6 addresses, unless it can't find another
package main

import (
  "flag"
  "fmt"
  "io/ioutil"
  "log"
  "net"
  "net/http"
  "os"
  "sort"
  "strings"
)

const (
  fallbackService = "http://benizi.com/ip?raw=1"
)

func getAddresses(external bool) (addrs []net.Addr) {
  if external {
    addrs = getExternal()
  } else {
    got, err := net.InterfaceAddrs()
    if err != nil {
      os.Exit(1)
    }
    addrs = got
  }
  return
}

func getExternal() []net.Addr {
  res, err := http.Get(fallbackService)
  if err != nil {
    os.Exit(1)
  }
  defer res.Body.Close()

  ip, err := ioutil.ReadAll(res.Body)
  if err != nil {
    os.Exit(1)
  }

  _, network, err := net.ParseCIDR(fmt.Sprintf("%s/32", ip[0:len(ip)-1]))
  if err != nil {
    os.Exit(1)
  }

  return []net.Addr{network}
}

type foundAddr struct {
  ip net.IP
  preferred bool
  rejected bool
  loopback bool
  isRfc1918 bool
  v6 bool
  original int
}

func xor(a, b bool) bool {
  return (a && !b) || (!a && b)
}

type ByAttributes struct {
  addrs []foundAddr
}

func (v ByAttributes) Len() int { return len(v.addrs) }
func (v ByAttributes) Swap(i, j int) { v.addrs[i], v.addrs[j] = v.addrs[j], v.addrs[i] }
func (v ByAttributes) Less(i, j int) bool {
  a := v.addrs[i]
  b := v.addrs[j]
  if xor(a.v6, b.v6) {
    return !a.v6
  }
  if xor(a.preferred, b.preferred) {
    return a.preferred
  }
  if xor(a.rejected, b.rejected) {
    return !a.rejected
  }
  if xor(a.loopback, b.loopback) {
    return !a.loopback
  }
  if xor(a.isRfc1918, b.isRfc1918) {
    return !a.isRfc1918
  }
  if a.original != b.original {
    return a.original < b.original
  }
  return a.ip.String() < b.ip.String()
}

func anyContains(networks []net.IPNet, ip net.IP) bool {
  for _, network := range networks {
    if network.Contains(ip) {
      return true
    }
  }
  return false
}

func parseNetwork(cidr string) (*net.IPNet, error) {
  _, network, err := net.ParseCIDR(cidr)
  if err == nil {
    return network, nil
  }

  // Try parsing it as an octet or octets
  // e.g. "10" => "10.0.0.0/8", "192.168" => "192.168.0.0/16"
  dots := strings.Count(cidr, ".")
  needed := 3 - dots
  if needed < 0 {
    return nil, err
  }
  cidr = fmt.Sprintf("%s%s/%d", cidr, strings.Repeat(".0", needed), 32 - 8 * needed)
  _, network, e := net.ParseCIDR(cidr)
  if e == nil {
    return network, nil
  }

  // return the original error
  return nil, err
}

func main() {
  print4 := false
  print6 := false
  external := false
  excludeDocker := true
  docker := "172.17.0.0/16"
  printAll := false

  flag.BoolVar(&print4, "4", print4, "Print IPv4")
  flag.BoolVar(&print6, "6", print6, "Print IPv6")
  flag.BoolVar(&external, "x", external, "Fetch external address")
  flag.BoolVar(&excludeDocker, "nodocker", excludeDocker, "Exclude Docker interface")
  flag.StringVar(&docker, "dockernet", docker, "Docker network to exclude")
  flag.BoolVar(&printAll, "all", printAll, "Print all addresses")
  flag.BoolVar(&printAll, "a", printAll, "Print all addresses (alias)")
  flag.Parse()

  var acceptable []net.IPNet
  var rejectable []net.IPNet
  rfc1918 := []net.IPNet{}

  for _, cidr := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} {
    _, parsed, err := net.ParseCIDR(cidr)
    if err != nil {
      log.Fatalln("Failed to parse RFC 1918 network", cidr)
    }
    rfc1918 = append(rfc1918, *parsed)
  }

  if excludeDocker {
    _, dockerNet, err := net.ParseCIDR(docker)
    if err != nil {
      log.Fatalln("Failed to parse Docker network", docker)
    }

    rejectable = append(rejectable, *dockerNet)
  }

  for _, arg := range flag.Args() {
    if len(arg) == 0 {
      continue
    }

    addTo := &acceptable
    if arg[0] == '!' || arg[0] == 'x' {
      addTo = &rejectable
      arg = arg[1:len(arg)]
    }

    network, err := parseNetwork(arg)
    if err != nil {
      log.Fatal(err)
    }

    *addTo = append(*addTo, *network)
  }

  found := make([]foundAddr, 0)

  addrs := getAddresses(external)
  for _, addr := range addrs {
    network, ok := addr.(*net.IPNet)
    if !ok {
      continue
    }

    v6 := network.IP.To4() == nil
    if xor(print4, print6) && xor(print6, v6) {
      continue
    }
    found = append(found, foundAddr{
      ip: network.IP,
      preferred: anyContains(acceptable, network.IP),
      rejected: anyContains(rejectable, network.IP),
      isRfc1918: anyContains(rfc1918, network.IP),
      loopback: network.IP.IsLoopback(),
      v6: v6,
      original: len(found),
    })
  }

  if len(found) == 0 {
    os.Exit(1)
  }

  sort.Sort(ByAttributes{found})

  for _, addr := range found {
    fmt.Println(addr.ip.String())
    if !printAll {
      break
    }
  }
}
<commit_msg>Correct a pet-peeve code style<commit_after>// Find local, non-loopback IP address
//
// Skips docker bridge address and IPv6 addresses, unless it can't find another
package main

import (
  "flag"
  "fmt"
  "io/ioutil"
  "log"
  "net"
  "net/http"
  "os"
  "sort"
  "strings"
)

const (
  fallbackService = "http://benizi.com/ip?raw=1"
)

func getAddresses() []net.Addr {
  addrs, err := net.InterfaceAddrs()
  if err != nil {
    os.Exit(1)
  }
  return addrs
}

func getExternal() []net.Addr {
  res, err := http.Get(fallbackService)
  if err != nil {
    os.Exit(1)
  }
  defer res.Body.Close()

  ip, err := ioutil.ReadAll(res.Body)
  if err != nil {
    os.Exit(1)
  }

  _, network, err := net.ParseCIDR(fmt.Sprintf("%s/32", ip[0:len(ip)-1]))
  if err != nil {
    os.Exit(1)
  }

  return []net.Addr{network}
}

type foundAddr struct {
  ip net.IP
  preferred bool
  rejected bool
  loopback bool
  isRfc1918 bool
  v6 bool
  original int
}

func xor(a, b bool) bool {
  return (a && !b) || (!a && b)
}

type ByAttributes struct {
  addrs []foundAddr
}

func (v ByAttributes) Len() int { return len(v.addrs) }
func (v ByAttributes) Swap(i, j int) { v.addrs[i], v.addrs[j] = v.addrs[j], v.addrs[i] }
func (v ByAttributes) Less(i, j int) bool {
  a := v.addrs[i]
  b := v.addrs[j]
  if xor(a.v6, b.v6) {
    return !a.v6
  }
  if xor(a.preferred, b.preferred) {
    return a.preferred
  }
  if xor(a.rejected, b.rejected) {
    return !a.rejected
  }
  if xor(a.loopback, b.loopback) {
    return !a.loopback
  }
  if xor(a.isRfc1918, b.isRfc1918) {
    return !a.isRfc1918
  }
  if a.original != b.original {
    return a.original < b.original
  }
  return a.ip.String() < b.ip.String()
}

func anyContains(networks []net.IPNet, ip net.IP) bool {
  for _, network := range networks {
    if network.Contains(ip) {
      return true
    }
  }
  return false
}

func parseNetwork(cidr string) (*net.IPNet, error) {
  _, network, err := net.ParseCIDR(cidr)
  if err == nil {
    return network, nil
  }

  // Try parsing it as an octet or octets
  // e.g. "10" => "10.0.0.0/8", "192.168" => "192.168.0.0/16"
  dots := strings.Count(cidr, ".")
  needed := 3 - dots
  if needed < 0 {
    return nil, err
  }
  cidr = fmt.Sprintf("%s%s/%d", cidr, strings.Repeat(".0", needed), 32 - 8 * needed)
  _, network, e := net.ParseCIDR(cidr)
  if e == nil {
    return network, nil
  }

  // return the original error
  return nil, err
}

func main() {
  print4 := false
  print6 := false
  external := false
  excludeDocker := true
  docker := "172.17.0.0/16"
  printAll := false

  flag.BoolVar(&print4, "4", print4, "Print IPv4")
  flag.BoolVar(&print6, "6", print6, "Print IPv6")
  flag.BoolVar(&external, "x", external, "Fetch external address")
  flag.BoolVar(&excludeDocker, "nodocker", excludeDocker, "Exclude Docker interface")
  flag.StringVar(&docker, "dockernet", docker, "Docker network to exclude")
  flag.BoolVar(&printAll, "all", printAll, "Print all addresses")
  flag.BoolVar(&printAll, "a", printAll, "Print all addresses (alias)")
  flag.Parse()

  var acceptable []net.IPNet
  var rejectable []net.IPNet
  rfc1918 := []net.IPNet{}

  for _, cidr := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} {
    _, parsed, err := net.ParseCIDR(cidr)
    if err != nil {
      log.Fatalln("Failed to parse RFC 1918 network", cidr)
    }
    rfc1918 = append(rfc1918, *parsed)
  }

  if excludeDocker {
    _, dockerNet, err := net.ParseCIDR(docker)
    if err != nil {
      log.Fatalln("Failed to parse Docker network", docker)
    }

    rejectable = append(rejectable, *dockerNet)
  }

  for _, arg := range flag.Args() {
    if len(arg) == 0 {
      continue
    }

    addTo := &acceptable
    if arg[0] == '!' || arg[0] == 'x' {
      addTo = &rejectable
      arg = arg[1:len(arg)]
    }

    network, err := parseNetwork(arg)
    if err != nil {
      log.Fatal(err)
    }

    *addTo = append(*addTo, *network)
  }

  found := make([]foundAddr, 0)

  var addrs []net.Addr
  if external {
    addrs = getExternal()
  } else {
    addrs = getAddresses()
  }

  for _, addr := range addrs {
    network, ok := addr.(*net.IPNet)
    if !ok {
      continue
    }

    v6 := network.IP.To4() == nil
    if xor(print4, print6) && xor(print6, v6) {
      continue
    }
    found = append(found, foundAddr{
      ip: network.IP,
      preferred: anyContains(acceptable, network.IP),
      rejected: anyContains(rejectable, network.IP),
      isRfc1918: anyContains(rfc1918, network.IP),
      loopback: network.IP.IsLoopback(),
      v6: v6,
      original: len(found),
    })
  }

  if len(found) == 0 {
    os.Exit(1)
  }

  sort.Sort(ByAttributes{found})

  for _, addr := range found {
    fmt.Println(addr.ip.String())
    if !printAll {
      break
    }
  }
}
<|endoftext|>


<commit_before>//go:build !bindata
// +build !bindata

/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package main

import (
	"github.com/admpub/nging/v4/application/library/bindata"
)

func init() {
	bindata.PathAliases.Add(`caddy`, `../../nging-plugins/caddymanager/template`)
	bindata.PathAliases.Add(`collector`, `../../nging-plugins/collector/template`)
	bindata.PathAliases.Add(`db`, `../../nging-plugins/dbmanager/template`)
	bindata.PathAliases.Add(`ddns`, `../../nging-plugins/ddnsmanager/template`)
	bindata.PathAliases.Add(`download`, `../../nging-plugins/dlmanager/template`)
	bindata.PathAliases.Add(`frp`, `../../nging-plugins/frpmanager/template`)
	bindata.PathAliases.Add(`ftp`, `../../nging-plugins/ftpmanager/template`)
	bindata.PathAliases.Add(`server`, `../../nging-plugins/servermanager/template`)
	bindata.PathAliases.Add(`term`, `../../nging-plugins/sshmanager/template`)

	bindata.Initialize()
}
<commit_msg>update<commit_after>//go:build !bindata
// +build !bindata

/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package main

import (
	"github.com/admpub/nging/v4/application/library/bindata"
)

func init() {
	bindata.PathAliases.Add(`caddy`, `../../nging-plugins/caddymanager/template/backend`)
	bindata.PathAliases.Add(`collector`, `../../nging-plugins/collector/template/backend`)
	bindata.PathAliases.Add(`db`, `../../nging-plugins/dbmanager/template/backend`)
	bindata.PathAliases.Add(`ddns`, `../../nging-plugins/ddnsmanager/template/backend`)
	bindata.PathAliases.Add(`download`, `../../nging-plugins/dlmanager/template/backend`)
	bindata.PathAliases.Add(`frp`, `../../nging-plugins/frpmanager/template/backend`)
	bindata.PathAliases.Add(`ftp`, `../../nging-plugins/ftpmanager/template/backend`)
	bindata.PathAliases.Add(`server`, `../../nging-plugins/servermanager/template/backend`)
	bindata.PathAliases.Add(`term`, `../../nging-plugins/sshmanager/template/backend`)

	bindata.Initialize()
}
<|endoftext|>


<commit_before>package otp

import (
	"bufio"
	"fmt"
	"net"
	"strconv"
	"strings"
	"sync"
)

type RedisStore struct {
	sync.Mutex
	conn    net.Conn
	scanner *bufio.Scanner
}

func NewRedisStore(host string) *RedisStore {
	conn, err := net.Dial("tcp", host)
	if err != nil {
		panic(err)
	}

	return &RedisStore{
		conn:    conn,
		scanner: bufio.NewScanner(conn),
	}
}

func (rs *RedisStore) runCmd(args ...string) string {
	chunks := []string{
		fmt.Sprintf("*%d", len(args)),
	}

	for _, arg := range args {
		chunks = append(chunks,
			fmt.Sprintf("$%d", len(arg)), arg)
	}

	chunks = append(chunks, "")

	result := strings.Join(chunks, "\r\n")

	rs.conn.Write([]byte(result))

	rs.scanner.Scan()
	return rs.scanner.Text()
}

func (rs *RedisStore) Get(key string) *string {
	rs.Lock()
	defer rs.Unlock()

	rs.runCmd("HGET", key, "content")

	rs.scanner.Scan()
	value := rs.scanner.Text()

	rs.runCmd("HINCRBY", key, "views", "-1")
	rs.runCmd("HGET", key, "views")

	rs.scanner.Scan()
	raw_views := rs.scanner.Text()

	if views, _ := strconv.Atoi(strings.TrimSpace(string(raw_views))); views <= 0 {
		rs.runCmd("DEL", key)
	}

	return &value

}

func (rs *RedisStore) Exists(key string) bool {
	rs.Lock()
	defer rs.Unlock()

	response := rs.runCmd("EXISTS", key)
	return response[1] == '1'
}

func (rs *RedisStore) Set(content string, views int, expire int) string {
	rs.Lock()
	defer rs.Unlock()

	key := generateUUID()
	rs.runCmd("HMSET", key, "content", content, "views", strconv.Itoa(views))
	rs.runCmd("EXPIRE", key, strconv.Itoa(expire))

	return key
}
<commit_msg>Switch to bufio.Reader to handle multi-line pastes<commit_after>package otp

import (
	"bufio"
	"fmt"
	"net"
	"strconv"
	"strings"
	"sync"
)

type RedisStore struct {
	sync.Mutex
	conn   net.Conn
	reader *bufio.Reader
}

func NewRedisStore(host string) *RedisStore {
	conn, err := net.Dial("tcp", host)
	if err != nil {
		panic(err)
	}

	return &RedisStore{
		conn:   conn,
		reader: bufio.NewReader(conn),
	}
}

func (rs *RedisStore) runCmd(args ...string) string {
	chunks := []string{
		fmt.Sprintf("*%d", len(args)),
	}

	for _, arg := range args {
		chunks = append(chunks,
			fmt.Sprintf("$%d", len(arg)), arg)
	}

	chunks = append(chunks, "")

	result := strings.Join(chunks, "\r\n")

	rs.conn.Write([]byte(result))

	raw, _ := rs.reader.ReadBytes('\n')
	return string(raw[:len(raw)-2])
}

func (rs *RedisStore) Get(key string) *string {
	rs.Lock()
	defer rs.Unlock()

	resp := rs.runCmd("HGET", key, "content")

	n, err := strconv.Atoi(resp[1:])
	if err != nil {
		panic(err)
	}

	bytes := make([]byte, n)
	rs.reader.Read(bytes)
	rs.reader.Discard(2) // throw away next \r\n
	value := string(bytes)

	rs.runCmd("HINCRBY", key, "views", "-1")
	rs.runCmd("HGET", key, "views")

	raw_views, _ := rs.reader.ReadBytes('\n')
	if views, _ := strconv.Atoi(string(raw_views[:len(raw_views)-2])); views <= 0 {
		rs.runCmd("DEL", key)
	}

	return &value

}

func (rs *RedisStore) Exists(key string) bool {
	rs.Lock()
	defer rs.Unlock()

	response := rs.runCmd("EXISTS", key)
	return response[1] == '1'
}

func (rs *RedisStore) Set(content string, views int, expire int) string {
	rs.Lock()
	defer rs.Unlock()

	key := generateUUID()
	rs.runCmd("HMSET", key, "content", content, "views", strconv.Itoa(views))
	rs.runCmd("EXPIRE", key, strconv.Itoa(expire))

	return key
}
<|endoftext|>


<commit_before>package dynamixel

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"strings"
)

const (

	// Instruction Types
	Ping      byte = 0x01
	ReadData  byte = 0x02
	WriteData byte = 0x03
	RegWrite  byte = 0x04
	Action    byte = 0x05
	Reset     byte = 0x06
	SyncWrite byte = 0x83

	// Send an instruction to all servos
	BroadcastIdent byte = 0xFE // 254
)

type DynamixelNetwork struct {
	Serial   io.ReadWriteCloser
	Buffered bool
	Debug    bool
}

func NewNetwork(serial io.ReadWriteCloser) *DynamixelNetwork {
	return &DynamixelNetwork{
		Serial:   serial,
		Buffered: false,
		Debug:    false,
	}
}

//
// Puts the network in bufferred write mode, which means that the REG_WRITE
// instruction will be used, rather than WRITE_DATA. This causes calls to
// WriteData to be bufferred until the Action method is called, at which time
// they'll all be executed at once.
//
// This is very useful for synchronizing the movements of multiple servos.
//
func (n *DynamixelNetwork) SetBuffered(buffered bool) {
	n.Buffered = buffered
}

//
// Converts an error byte (as included in a status packet) into an error object
// with a friendly error message. We can't be too specific about it, because any
// combination of errors might occur at the same time.
//
// See: http://support.robotis.com/en/product/dynamixel/communication/dxl_packet.htm#Status_Packet
//
func DecodeStatusError(errBits byte) error {
	str := []string{}

	if errBits&1 == 1 {
		str = append(str, "input voltage")
	}

	if errBits&2 == 2 {
		str = append(str, "angle limit")
	}

	if errBits&4 == 4 {
		str = append(str, "overheating")
	}

	if errBits&8 == 8 {
		str = append(str, "range")
	}

	if errBits&16 == 16 {
		str = append(str, "checksum")
	}

	if errBits&32 == 32 {
		str = append(str, "overload")
	}

	if errBits&64 == 64 {
		str = append(str, "instruction")
	}

	if errBits&128 == 128 {
		str = append(str, "unknown")
	}

	return fmt.Errorf("status error(s): %s", strings.Join(str, ", "))
}

//
// This stuff is generic to all Dynamixels. See:
//
// * http://support.robotis.com/en/product/dynamixel/communication/dxl_packet.htm
// * http://support.robotis.com/en/product/dynamixel/communication/dxl_instruction.htm
//
func (network *DynamixelNetwork) WriteInstruction(ident uint8, instruction byte, params ...byte) error {
	buf := new(bytes.Buffer)
	paramsLength := byte(len(params) + 2)

	// build instruction packet

	buf.Write([]byte{
		0xFF,               // header
		0xFF,               // header
		byte(ident),        // target Dynamixel ID
		byte(paramsLength), // len(params) + 2
		instruction,        // instruction type (read/write/etc)
	})

	buf.Write(params)

	// calculate checksum

	sum := ident + paramsLength + instruction

	for _, value := range params {
		sum += value
	}

	buf.WriteByte(byte((^sum) & 0xFF))

	// write to port

	network.Log(">> %#v\n", buf.Bytes())
	_, err := buf.WriteTo(network.Serial)

	if err != nil {
		return err
	}

	return nil
}

//
// Reads `b` bytes, blocking if they're not immediately available.
//
func (network *DynamixelNetwork) read(b int) ([]byte, error) {
	buf := make([]byte, b)
	n := 0

	for n < b {
		nn, err := network.Serial.Read(buf[n:])
		n += nn

		// It's okay if we reached the end of the available bytes. They're probably
		// just not available yet. Other errors are fatal.
		if err != nil && err != io.EOF {
			return buf, err
		}
	}

	return buf, nil
}

func (network *DynamixelNetwork) ReadStatusPacket(expectIdent uint8) ([]byte, error) {

	//
	// Status packets are similar to instruction packet:
	//
	// +------+------+ ------ +-------+----------+---------+--------+--------+----------+
	// | 0xFF | 0xFF |  0xFF  | ident | params+2 | errBits | param1 | param2 | checksum |
	// +------+------+ ------ +-------+----------+---------+--------+--------+----------+
	//
	//                  ^-- sometimes, but it shouldn't be there?!
	//
	// We don't know the length, because responses can have variable numbers of
	// parameters.
	//

	// Read the first three bytes, which are always present. Hopefully, the first
	// two are the header, and the third is the ID of the servo which this packet
	// refers to. But sometimes, the third byte is another 0xFF. I don't know why,
	// and I can't seem to find any useful information on the matter.

	headerBuf, headerErr := network.read(3)
	network.Log("<< %#v (header, ident)\n", headerBuf)
	if headerErr != nil {
		return []byte{}, headerErr
	}

	if headerBuf[0] != 0xFF || headerBuf[1] != 0xFF {
		return []byte{}, fmt.Errorf("bad status packet header: %x %x", headerBuf[0], headerBuf[1])
	}

	// The third byte should be the ident. But if an extra header byte has shown
	// up, ignore it and read another byte to replace it.

	resIdent := uint8(headerBuf[2])
	if resIdent == 255 {

		identBuf, identErr := network.read(1)
		network.Log("<< %#v (ident retry)\n", identBuf)
		if identErr != nil {
			return []byte{}, identErr
		}

		resIdent = uint8(identBuf[0])
	}

	// The next two bytes are always present, so just read them.

	paramCountAndErrBitsBuf, pcebErr := network.read(2)
	network.Log("<< %#v (p+2, errbits)\n", paramCountAndErrBitsBuf)
	if pcebErr != nil {
		return []byte{}, pcebErr
	}

	numParams := uint8(paramCountAndErrBitsBuf[0]) - 2
	errBits := paramCountAndErrBitsBuf[1]

	// now read the params, if there are any. we must do this before checking for
	// errors, to avoid leaving junk in the buffer.

	paramsBuf, paramsErr := network.read(int(numParams))
	network.Log("<< %#v (params)\n", paramsBuf)
	if paramsErr != nil {
		return []byte{}, paramsErr
	}

	// read the checksum, which is always one byte
	// TODO: check the checksum

	checksumBuf, checksumErr := network.read(1)
	network.Log("<< %#v (checksum)\n", checksumBuf)
	if checksumErr != nil {
		return []byte{}, checksumErr
	}

	// return an error if the packet contained one.
	// TODO: decode the error bit(s) and return a proper message!

	if errBits != 0x0 {
		return []byte{}, DecodeStatusError(errBits)
	}

	// return an error if we received a packet with the wrong ID. this indicates
	// a concurrency issue (maybe clashing IDs on a single bus).

	if resIdent != expectIdent {
		return []byte{}, fmt.Errorf("expected status packet for %v, but got %v", expectIdent, resIdent)
	}

	// omg, nothing went wrong

	return paramsBuf, nil
}

func (n *DynamixelNetwork) ReadData(ident uint8, startAddress byte, length int) (uint16, error) {
	params := []byte{startAddress, byte(length)}
	err1 := n.WriteInstruction(ident, ReadData, params...)
	if err1 != nil {
		return 0, err1
	}

	buf, err2 := n.ReadStatusPacket(ident)
	if err2 != nil {
		return 0, err2
	}

	var val uint16
	err3 := binary.Read(bytes.NewReader(buf), binary.LittleEndian, &val)
	if err3 != nil {
		return 0, err3
	}

	return val, nil
}

func (n *DynamixelNetwork) WriteData(ident uint8, params ...byte) error {
	var instruction byte

	if n.Buffered {
		instruction = RegWrite
	} else {
		instruction = WriteData
	}

	writeErr := n.WriteInstruction(ident, instruction, params...)
	if writeErr != nil {
		return writeErr
	}

	_, readErr := n.ReadStatusPacket(ident)
	if readErr != nil {
		return readErr
	}

	return nil
}

//
// Broadcasts the ACTION instruction, which initiates any previously bufferred
// instructions.
//
// Doesn't wait for a status packet in response, because they are not sent in
// response to broadcast instructions.
//
func (n *DynamixelNetwork) Action() error {
	return n.WriteInstruction(BroadcastIdent, Action)
}

func (n *DynamixelNetwork) Log(format string, v ...interface{}) {
	if n.Debug {
		log.Printf(format, v...)
	}
}
<commit_msg>Don't bother reading zero params<commit_after>package dynamixel

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"strings"
)

const (

	// Instruction Types
	Ping      byte = 0x01
	ReadData  byte = 0x02
	WriteData byte = 0x03
	RegWrite  byte = 0x04
	Action    byte = 0x05
	Reset     byte = 0x06
	SyncWrite byte = 0x83

	// Send an instruction to all servos
	BroadcastIdent byte = 0xFE // 254
)

type DynamixelNetwork struct {
	Serial   io.ReadWriteCloser
	Buffered bool
	Debug    bool
}

func NewNetwork(serial io.ReadWriteCloser) *DynamixelNetwork {
	return &DynamixelNetwork{
		Serial:   serial,
		Buffered: false,
		Debug:    false,
	}
}

//
// Puts the network in bufferred write mode, which means that the REG_WRITE
// instruction will be used, rather than WRITE_DATA. This causes calls to
// WriteData to be bufferred until the Action method is called, at which time
// they'll all be executed at once.
//
// This is very useful for synchronizing the movements of multiple servos.
//
func (n *DynamixelNetwork) SetBuffered(buffered bool) {
	n.Buffered = buffered
}

//
// Converts an error byte (as included in a status packet) into an error object
// with a friendly error message. We can't be too specific about it, because any
// combination of errors might occur at the same time.
//
// See: http://support.robotis.com/en/product/dynamixel/communication/dxl_packet.htm#Status_Packet
//
func DecodeStatusError(errBits byte) error {
	str := []string{}

	if errBits&1 == 1 {
		str = append(str, "input voltage")
	}

	if errBits&2 == 2 {
		str = append(str, "angle limit")
	}

	if errBits&4 == 4 {
		str = append(str, "overheating")
	}

	if errBits&8 == 8 {
		str = append(str, "range")
	}

	if errBits&16 == 16 {
		str = append(str, "checksum")
	}

	if errBits&32 == 32 {
		str = append(str, "overload")
	}

	if errBits&64 == 64 {
		str = append(str, "instruction")
	}

	if errBits&128 == 128 {
		str = append(str, "unknown")
	}

	return fmt.Errorf("status error(s): %s", strings.Join(str, ", "))
}

//
// This stuff is generic to all Dynamixels. See:
//
// * http://support.robotis.com/en/product/dynamixel/communication/dxl_packet.htm
// * http://support.robotis.com/en/product/dynamixel/communication/dxl_instruction.htm
//
func (network *DynamixelNetwork) WriteInstruction(ident uint8, instruction byte, params ...byte) error {
	buf := new(bytes.Buffer)
	paramsLength := byte(len(params) + 2)

	// build instruction packet

	buf.Write([]byte{
		0xFF,               // header
		0xFF,               // header
		byte(ident),        // target Dynamixel ID
		byte(paramsLength), // len(params) + 2
		instruction,        // instruction type (read/write/etc)
	})

	buf.Write(params)

	// calculate checksum

	sum := ident + paramsLength + instruction

	for _, value := range params {
		sum += value
	}

	buf.WriteByte(byte((^sum) & 0xFF))

	// write to port

	network.Log(">> %#v\n", buf.Bytes())
	_, err := buf.WriteTo(network.Serial)

	if err != nil {
		return err
	}

	return nil
}

//
// Reads `b` bytes, blocking if they're not immediately available.
//
func (network *DynamixelNetwork) read(b int) ([]byte, error) {
	buf := make([]byte, b)
	n := 0

	for n < b {
		nn, err := network.Serial.Read(buf[n:])
		n += nn

		// It's okay if we reached the end of the available bytes. They're probably
		// just not available yet. Other errors are fatal.
		if err != nil && err != io.EOF {
			return buf, err
		}
	}

	return buf, nil
}

func (network *DynamixelNetwork) ReadStatusPacket(expectIdent uint8) ([]byte, error) {

	//
	// Status packets are similar to instruction packet:
	//
	// +------+------+ ------ +-------+----------+---------+--------+--------+----------+
	// | 0xFF | 0xFF |  0xFF  | ident | params+2 | errBits | param1 | param2 | checksum |
	// +------+------+ ------ +-------+----------+---------+--------+--------+----------+
	//
	//                  ^-- sometimes, but it shouldn't be there?!
	//
	// We don't know the length, because responses can have variable numbers of
	// parameters.
	//

	// Read the first three bytes, which are always present. Hopefully, the first
	// two are the header, and the third is the ID of the servo which this packet
	// refers to. But sometimes, the third byte is another 0xFF. I don't know why,
	// and I can't seem to find any useful information on the matter.

	headerBuf, headerErr := network.read(3)
	network.Log("<< %#v (header, ident)\n", headerBuf)
	if headerErr != nil {
		return []byte{}, headerErr
	}

	if headerBuf[0] != 0xFF || headerBuf[1] != 0xFF {
		return []byte{}, fmt.Errorf("bad status packet header: %x %x", headerBuf[0], headerBuf[1])
	}

	// The third byte should be the ident. But if an extra header byte has shown
	// up, ignore it and read another byte to replace it.

	resIdent := uint8(headerBuf[2])
	if resIdent == 255 {

		identBuf, identErr := network.read(1)
		network.Log("<< %#v (ident retry)\n", identBuf)
		if identErr != nil {
			return []byte{}, identErr
		}

		resIdent = uint8(identBuf[0])
	}

	// The next two bytes are always present, so just read them.

	paramCountAndErrBitsBuf, pcebErr := network.read(2)
	network.Log("<< %#v (p+2, errbits)\n", paramCountAndErrBitsBuf)
	if pcebErr != nil {
		return []byte{}, pcebErr
	}

	numParams := uint8(paramCountAndErrBitsBuf[0]) - 2
	errBits := paramCountAndErrBitsBuf[1]
	paramsBuf := make([]byte, numParams)

	// now read the params, if there are any. we must do this before checking for
	// errors, to avoid leaving junk in the buffer.

	if numParams > 0 {
		paramsBuf, paramsErr := network.read(int(numParams))
		network.Log("<< %#v (params)\n", paramsBuf)
		if paramsErr != nil {
			return []byte{}, paramsErr
		}
	}

	// read the checksum, which is always one byte
	// TODO: check the checksum

	checksumBuf, checksumErr := network.read(1)
	network.Log("<< %#v (checksum)\n", checksumBuf)
	if checksumErr != nil {
		return []byte{}, checksumErr
	}

	// return an error if the packet contained one.
	// TODO: decode the error bit(s) and return a proper message!

	if errBits != 0x0 {
		return []byte{}, DecodeStatusError(errBits)
	}

	// return an error if we received a packet with the wrong ID. this indicates
	// a concurrency issue (maybe clashing IDs on a single bus).

	if resIdent != expectIdent {
		return []byte{}, fmt.Errorf("expected status packet for %v, but got %v", expectIdent, resIdent)
	}

	// omg, nothing went wrong

	return paramsBuf, nil
}

func (n *DynamixelNetwork) ReadData(ident uint8, startAddress byte, length int) (uint16, error) {
	params := []byte{startAddress, byte(length)}
	err1 := n.WriteInstruction(ident, ReadData, params...)
	if err1 != nil {
		return 0, err1
	}

	buf, err2 := n.ReadStatusPacket(ident)
	if err2 != nil {
		return 0, err2
	}

	var val uint16
	err3 := binary.Read(bytes.NewReader(buf), binary.LittleEndian, &val)
	if err3 != nil {
		return 0, err3
	}

	return val, nil
}

func (n *DynamixelNetwork) WriteData(ident uint8, params ...byte) error {
	var instruction byte

	if n.Buffered {
		instruction = RegWrite
	} else {
		instruction = WriteData
	}

	writeErr := n.WriteInstruction(ident, instruction, params...)
	if writeErr != nil {
		return writeErr
	}

	_, readErr := n.ReadStatusPacket(ident)
	if readErr != nil {
		return readErr
	}

	return nil
}

//
// Broadcasts the ACTION instruction, which initiates any previously bufferred
// instructions.
//
// Doesn't wait for a status packet in response, because they are not sent in
// response to broadcast instructions.
//
func (n *DynamixelNetwork) Action() error {
	return n.WriteInstruction(BroadcastIdent, Action)
}

func (n *DynamixelNetwork) Log(format string, v ...interface{}) {
	if n.Debug {
		log.Printf(format, v...)
	}
}
<|endoftext|>


<commit_before>package repository_fetcher

import (
	"crypto/md5"
	"errors"
	"fmt"
	"net/url"
	"sync"

	"github.com/cloudfoundry-incubator/garden-linux/process"
	"github.com/docker/docker/image"
	"github.com/docker/docker/pkg/archive"
	"github.com/pivotal-golang/lager"
)

type IDer interface {
	ID(path string) string
}

type Local struct {
	Graph             Graph
	DefaultRootFSPath string
	IDer              IDer

	mu sync.RWMutex
}

func (l *Local) Fetch(
	logger lager.Logger,
	repoURL *url.URL,
	tag string,
) (string, process.Env, []string, error) {

	path := repoURL.Path
	if len(path) == 0 {
		path = l.DefaultRootFSPath
	}

	if len(path) == 0 {
		return "", nil, nil, errors.New("RootFSPath: is a required parameter, since no default rootfs was provided to the server. To provide a default rootfs, use the --rootfs flag on startup.")
	}

	id, err := l.fetch(path)
	return id, nil, nil, err
}

func (l *Local) fetch(path string) (string, error) {
	id := l.IDer.ID(path)

	l.mu.RLock()
	if l.Graph.Exists(id) {
		return id, nil // use cache
	}
	l.mu.RUnlock()

	// synchronize all downloads, we could optimize by only mutexing around each
	// particular rootfs path, but in practice importing local rootfses is decently fast,
	// and concurrently importing local rootfses is rare.
	l.mu.Lock()
	defer l.mu.Unlock()

	tar, err := archive.Tar(path, archive.Uncompressed)
	if err != nil {
		return "", fmt.Errorf("fetch local rootfs: %s", err)
	}

	if err := l.Graph.Register(&image.Image{ID: id}, tar); err != nil {
		return "", fmt.Errorf("fetch local rootfs: %v", err)
	}

	return id, nil
}

type MD5ID struct{}

func (MD5ID) ID(path string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(path)))
}
<commit_msg>Ensure readlock is always released<commit_after>package repository_fetcher

import (
	"crypto/md5"
	"errors"
	"fmt"
	"net/url"
	"sync"

	"github.com/cloudfoundry-incubator/garden-linux/process"
	"github.com/docker/docker/image"
	"github.com/docker/docker/pkg/archive"
	"github.com/pivotal-golang/lager"
)

type IDer interface {
	ID(path string) string
}

type Local struct {
	Graph             Graph
	DefaultRootFSPath string
	IDer              IDer

	mu sync.RWMutex
}

func (l *Local) Fetch(
	logger lager.Logger,
	repoURL *url.URL,
	tag string,
) (string, process.Env, []string, error) {

	path := repoURL.Path
	if len(path) == 0 {
		path = l.DefaultRootFSPath
	}

	if len(path) == 0 {
		return "", nil, nil, errors.New("RootFSPath: is a required parameter, since no default rootfs was provided to the server. To provide a default rootfs, use the --rootfs flag on startup.")
	}

	id, err := l.fetch(path)
	return id, nil, nil, err
}

func (l *Local) fetch(path string) (string, error) {
	id := l.IDer.ID(path)

	if l.isCached(id) {
		return id, nil // use cache
	}

	// synchronize all downloads, we could optimize by only mutexing around each
	// particular rootfs path, but in practice importing local rootfses is decently fast,
	// and concurrently importing local rootfses is rare.
	l.mu.Lock()
	defer l.mu.Unlock()

	tar, err := archive.Tar(path, archive.Uncompressed)
	if err != nil {
		return "", fmt.Errorf("fetch local rootfs: %s", err)
	}

	if err := l.Graph.Register(&image.Image{ID: id}, tar); err != nil {
		return "", fmt.Errorf("fetch local rootfs: %v", err)
	}

	return id, nil
}

func (l *Local) isCached(id string) bool {
	l.mu.RLock()
	defer l.mu.RUnlock()

	return l.Graph.Exists(id)
}

type MD5ID struct{}

func (MD5ID) ID(path string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(path)))
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
	"github.com/prometheus/client_golang/prometheus"
	"k8s.io/ingress/core/pkg/ingress"
)

const (
	ns             = "ingress_controller"
	operation      = "count"
	reloadLabel    = "reloads"
	sslLabelExpire = "ssl_expire_time_seconds"
	sslLabelHost   = "host"
)

func init() {
	prometheus.MustRegister(reloadOperation)
	prometheus.MustRegister(reloadOperationErrors)
	prometheus.MustRegister(sslExpireTime)

}

var (
	reloadOperation = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: ns,
			Name:      "success",
			Help:      "Cumulative number of Ingress controller reload operations",
		},
		[]string{operation},
	)
	reloadOperationErrors = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: ns,
			Name:      "errors",
			Help:      "Cumulative number of Ingress controller errors during reload operations",
		},
		[]string{operation},
	)
	sslExpireTime = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Namespace: ns,
			Name:      sslLabelExpire,
			Help:      "Number of seconds since 1970 to the SSL Certificate expire. An example to check if this " +
				"certificate will expire in 10 days is: \"ingress_controller_ssl_expire_time_seconds < (time() + (10 * 24 * 3600))\"",
		},
		[]string{sslLabelHost},
	)
)

func incReloadCount() {
	reloadOperation.WithLabelValues(reloadLabel).Inc()
}

func incReloadErrorCount() {
	reloadOperationErrors.WithLabelValues(reloadLabel).Inc()
}

func setSSLExpireTime(servers []*ingress.Server) {

	for _, s := range servers {
		sslExpireTime.WithLabelValues(s.Hostname).Set(float64(s.SSLExpireTime.Unix()))
	}

}
<commit_msg>Don't expose certificate metrics for default server<commit_after>/*
Copyright 2015 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
	"github.com/prometheus/client_golang/prometheus"
	"k8s.io/ingress/core/pkg/ingress"
)

const (
	ns             = "ingress_controller"
	operation      = "count"
	reloadLabel    = "reloads"
	sslLabelExpire = "ssl_expire_time_seconds"
	sslLabelHost   = "host"
)

func init() {
	prometheus.MustRegister(reloadOperation)
	prometheus.MustRegister(reloadOperationErrors)
	prometheus.MustRegister(sslExpireTime)

}

var (
	reloadOperation = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: ns,
			Name:      "success",
			Help:      "Cumulative number of Ingress controller reload operations",
		},
		[]string{operation},
	)
	reloadOperationErrors = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: ns,
			Name:      "errors",
			Help:      "Cumulative number of Ingress controller errors during reload operations",
		},
		[]string{operation},
	)
	sslExpireTime = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Namespace: ns,
			Name:      sslLabelExpire,
			Help:      "Number of seconds since 1970 to the SSL Certificate expire. An example to check if this " +
				"certificate will expire in 10 days is: \"ingress_controller_ssl_expire_time_seconds < (time() + (10 * 24 * 3600))\"",
		},
		[]string{sslLabelHost},
	)
)

func incReloadCount() {
	reloadOperation.WithLabelValues(reloadLabel).Inc()
}

func incReloadErrorCount() {
	reloadOperationErrors.WithLabelValues(reloadLabel).Inc()
}

func setSSLExpireTime(servers []*ingress.Server) {

	for _, s := range servers {
		if s.Hostname != defServerName {
			sslExpireTime.WithLabelValues(s.Hostname).Set(float64(s.SSLExpireTime.Unix()))
		}
	}

}
<|endoftext|>


<commit_before>package mpb

import (
	"sync"
	"testing"
)

const total = 1000

func BenchmarkIncrementOneBar(b *testing.B) {
	benchBody(1, b)
}

func BenchmarkIncrementTwoBars(b *testing.B) {
	benchBody(2, b)
}

func BenchmarkIncrementThreeBars(b *testing.B) {
	benchBody(3, b)
}

func BenchmarkIncrementFourBars(b *testing.B) {
	benchBody(4, b)
}

func benchBody(n int, b *testing.B) {
	p := New(WithOutput(nil), WithWidth(80))
	wg := new(sync.WaitGroup)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		for j := 0; j < n; j++ {
			bar := p.AddBar(total)
			switch j {
			case n - 1:
				complete(b, bar)
			default:
				wg.Add(1)
				go func() {
					complete(b, bar)
					wg.Done()
				}()
			}
		}
		wg.Wait()
	}
	p.Wait()
}

func complete(b *testing.B, bar *Bar) {
	for i := 0; i < total; i++ {
		bar.Increment()
	}
	if !bar.Completed() {
		b.Fail()
	}
}
<commit_msg>minor: barbench refactoring<commit_after>package mpb

import (
	"sync"
	"testing"
)

const total = 1000

func BenchmarkNopStyleOneBar(b *testing.B) {
	bench(b, NopStyle(), 1)
}

func BenchmarkNopStyleTwoBars(b *testing.B) {
	bench(b, NopStyle(), 2)
}

func BenchmarkNopStyleThreeBars(b *testing.B) {
	bench(b, NopStyle(), 3)
}

func BenchmarkBarStyleOneBar(b *testing.B) {
	bench(b, BarStyle(), 1)
}

func BenchmarkBarStyleTwoBars(b *testing.B) {
	bench(b, BarStyle(), 2)
}

func BenchmarkBarStyleThreeBars(b *testing.B) {
	bench(b, BarStyle(), 3)
}

func bench(b *testing.B, builder BarFillerBuilder, n int) {
	var wg sync.WaitGroup
	p := New(WithOutput(nil), WithWidth(80))
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		for j := 0; j < n; j++ {
			bar := p.New(total, builder)
			switch j {
			case n - 1:
				complete(b, bar)
			default:
				wg.Add(1)
				go func() {
					complete(b, bar)
					wg.Done()
				}()
			}
		}
		wg.Wait()
	}
	p.Wait()
}

func complete(b *testing.B, bar *Bar) {
	for i := 0; i < total; i++ {
		bar.Increment()
	}
	if !bar.Completed() {
		b.Fail()
	}
	bar.Wait()
}
<|endoftext|>


<commit_before>package curator

import (
	"math"
	"math/rand"
	"time"
)

// Abstraction for retry policies to sleep
type RetrySleeper interface {
	// Sleep for the given time
	SleepFor(time time.Duration) error
}

// Abstracts the policy to use when retrying connections
type RetryPolicy interface {
	// Called when an operation has failed for some reason.
	// This method should return true to make another attempt.
	AllowRetry(retryCount int, elapsedTime time.Duration, sleeper RetrySleeper) bool
}

type SleepingRetry struct {
	RetryPolicy

	N            int
	getSleepTime func(retryCount int, elapsedTime time.Duration) time.Duration
}

func (r *SleepingRetry) AllowRetry(retryCount int, elapsedTime time.Duration, sleeper RetrySleeper) bool {
	if retryCount < r.N {
		if err := sleeper.SleepFor(r.getSleepTime(retryCount, elapsedTime)); err != nil {
			return false
		}

		return true
	}

	return false
}

// Retry policy that retries a max number of times
type RetryNTimes struct {
	SleepingRetry
}

func NewRetryNTimes(n int, sleepBetweenRetries time.Duration) *RetryNTimes {
	return &RetryNTimes{
		SleepingRetry: SleepingRetry{
			N:            n,
			getSleepTime: func(retryCount int, elapsedTime time.Duration) time.Duration { return sleepBetweenRetries },
		},
	}
}

// A retry policy that retries only once
type RetryOneTime struct {
	RetryNTimes
}

func NewRetryOneTime(sleepBetweenRetry time.Duration) *RetryOneTime {
	return &RetryOneTime{
		*NewRetryNTimes(1, sleepBetweenRetry),
	}
}

const (
	MAX_RETRIES_LIMIT               = 29
	DEFAULT_MAX_SLEEP time.Duration = time.Duration(math.MaxInt32 * int64(time.Second))
)

// Retry policy that retries a set number of times with increasing sleep time between retries
type ExponentialBackoffRetry struct {
	SleepingRetry
}

func NewExponentialBackoffRetry(baseSleepTime time.Duration, maxRetries int, maxSleep time.Duration) *ExponentialBackoffRetry {
	if maxRetries > MAX_RETRIES_LIMIT {
		maxRetries = MAX_RETRIES_LIMIT
	}

	return &ExponentialBackoffRetry{
		SleepingRetry: SleepingRetry{
			N: maxRetries,
			getSleepTime: func(retryCount int, elapsedTime time.Duration) time.Duration {
				sleepTime := time.Duration(int64(baseSleepTime) * rand.Int63n(1<<uint(retryCount)))

				if sleepTime > maxSleep {
					sleepTime = maxSleep
				}

				return sleepTime
			},
		}}
}

// A retry policy that retries until a given amount of time elapses
type RetryUntilElapsed struct {
	SleepingRetry

	maxElapsedTime time.Duration
}

func NewRetryUntilElapsed(maxElapsedTime, sleepBetweenRetries time.Duration) *RetryUntilElapsed {
	return &RetryUntilElapsed{
		SleepingRetry: SleepingRetry{
			N:            math.MaxInt64,
			getSleepTime: func(retryCount int, elapsedTime time.Duration) time.Duration { return sleepBetweenRetries },
		},
		maxElapsedTime: maxElapsedTime,
	}
}

func (r *RetryUntilElapsed) AllowRetry(retryCount int, elapsedTime time.Duration, sleeper RetrySleeper) bool {
	return elapsedTime < r.maxElapsedTime && r.SleepingRetry.AllowRetry(retryCount, elapsedTime, sleeper)
}
<commit_msg>add RetryLoop<commit_after>package curator

import (
	"math"
	"math/rand"
	"net"
	"time"

	"github.com/samuel/go-zookeeper/zk"
)

// Abstraction for retry policies to sleep
type RetrySleeper interface {
	// Sleep for the given time
	SleepFor(time time.Duration) error
}

// Abstracts the policy to use when retrying connections
type RetryPolicy interface {
	// Called when an operation has failed for some reason.
	// This method should return true to make another attempt.
	AllowRetry(retryCount int, elapsedTime time.Duration, sleeper RetrySleeper) bool
}

type retryLoop struct {
	done         bool
	retryCount   int
	startTime    time.Time
	retryPolicy  RetryPolicy
	retrySleeper RetrySleeper
}

func newRetryLoop(retryPolicy RetryPolicy, retrySleeper RetrySleeper) *retryLoop {
	return &retryLoop{
		startTime:    time.Now(),
		retryPolicy:  retryPolicy,
		retrySleeper: retrySleeper,
	}
}

func (l *retryLoop) SleepFor(d time.Duration) error {
	time.Sleep(d)

	return nil
}

// If true is returned, make an attempt at the operation
func (l *retryLoop) shouldContinue() bool { return !l.done }

// Call this when your operation has successfully completed
func (l *retryLoop) markComplete() { l.done = true }

// return true if the given Zookeeper result code is retry-able
func (l *retryLoop) shouldRetry(err error) bool {
	if err == zk.ErrSessionExpired || err == zk.ErrSessionMoved {
		return true
	}

	if netErr, ok := err.(net.Error); ok {
		return netErr.Timeout() || netErr.Temporary()
	}

	return false
}

// creates a retry loop calling the given proc and retrying if needed
func (l *retryLoop) callWithRetry(client CuratorZookeeperClient, proc func() (interface{}, error)) (interface{}, error) {
	for l.shouldContinue() {
		if ret, err := proc(); err != nil {
			if l.shouldRetry(err) {
				l.retryCount++

				if !l.retryPolicy.AllowRetry(l.retryCount, time.Now()-l.startTime, l) {
					return ret, err
				}
			}
		} else {
			l.markComplete()

			return ret, err
		}
	}
}

type SleepingRetry struct {
	RetryPolicy

	N            int
	getSleepTime func(retryCount int, elapsedTime time.Duration) time.Duration
}

func (r *SleepingRetry) AllowRetry(retryCount int, elapsedTime time.Duration, sleeper RetrySleeper) bool {
	if retryCount < r.N {
		if err := sleeper.SleepFor(r.getSleepTime(retryCount, elapsedTime)); err != nil {
			return false
		}

		return true
	}

	return false
}

// Retry policy that retries a max number of times
type RetryNTimes struct {
	SleepingRetry
}

func NewRetryNTimes(n int, sleepBetweenRetries time.Duration) *RetryNTimes {
	return &RetryNTimes{
		SleepingRetry: SleepingRetry{
			N:            n,
			getSleepTime: func(retryCount int, elapsedTime time.Duration) time.Duration { return sleepBetweenRetries },
		},
	}
}

// A retry policy that retries only once
type RetryOneTime struct {
	RetryNTimes
}

func NewRetryOneTime(sleepBetweenRetry time.Duration) *RetryOneTime {
	return &RetryOneTime{
		*NewRetryNTimes(1, sleepBetweenRetry),
	}
}

const (
	MAX_RETRIES_LIMIT               = 29
	DEFAULT_MAX_SLEEP time.Duration = time.Duration(math.MaxInt32 * int64(time.Second))
)

// Retry policy that retries a set number of times with increasing sleep time between retries
type ExponentialBackoffRetry struct {
	SleepingRetry
}

func NewExponentialBackoffRetry(baseSleepTime time.Duration, maxRetries int, maxSleep time.Duration) *ExponentialBackoffRetry {
	if maxRetries > MAX_RETRIES_LIMIT {
		maxRetries = MAX_RETRIES_LIMIT
	}

	return &ExponentialBackoffRetry{
		SleepingRetry: SleepingRetry{
			N: maxRetries,
			getSleepTime: func(retryCount int, elapsedTime time.Duration) time.Duration {
				sleepTime := time.Duration(int64(baseSleepTime) * rand.Int63n(1<<uint(retryCount)))

				if sleepTime > maxSleep {
					sleepTime = maxSleep
				}

				return sleepTime
			},
		}}
}

// A retry policy that retries until a given amount of time elapses
type RetryUntilElapsed struct {
	SleepingRetry

	maxElapsedTime time.Duration
}

func NewRetryUntilElapsed(maxElapsedTime, sleepBetweenRetries time.Duration) *RetryUntilElapsed {
	return &RetryUntilElapsed{
		SleepingRetry: SleepingRetry{
			N:            math.MaxInt64,
			getSleepTime: func(retryCount int, elapsedTime time.Duration) time.Duration { return sleepBetweenRetries },
		},
		maxElapsedTime: maxElapsedTime,
	}
}

func (r *RetryUntilElapsed) AllowRetry(retryCount int, elapsedTime time.Duration, sleeper RetrySleeper) bool {
	return elapsedTime < r.maxElapsedTime && r.SleepingRetry.AllowRetry(retryCount, elapsedTime, sleeper)
}
<|endoftext|>


<commit_before>package tagger

import (
	"bytes"
	"encoding/json"
)

type Metric struct {
	Path        []byte
	Level       int
	ParentIndex int
	Tags        *Set
}

type ByPath []Metric

func (p ByPath) Len() int           { return len(p) }
func (p ByPath) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p ByPath) Less(i, j int) bool { return bytes.Compare(p[i].Path, p[j].Path) < 0 }

func (m *Metric) ParentPath() []byte {
	if len(m.Path) == 0 {
		return nil
	}

	index := bytes.LastIndexByte(m.Path[:len(m.Path)-1], '.')
	if index < 0 {
		return nil
	}

	return m.Path[:index+1]
}

func (m *Metric) IsLeaf() uint8 {
	if len(m.Path) > 0 && m.Path[len(m.Path)-1] == '.' {
		return 1
	}
	return 0
}

func (m *Metric) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]interface{}{
		"Path":   unsafeString(m.Path),
		"Level":  m.Level,
		"Tags":   m.Tags,
		"IsLeaf": m.IsLeaf(),
	})
}
<commit_msg>fix isleaf<commit_after>package tagger

import (
	"bytes"
	"encoding/json"
)

type Metric struct {
	Path        []byte
	Level       int
	ParentIndex int
	Tags        *Set
}

type ByPath []Metric

func (p ByPath) Len() int           { return len(p) }
func (p ByPath) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p ByPath) Less(i, j int) bool { return bytes.Compare(p[i].Path, p[j].Path) < 0 }

func (m *Metric) ParentPath() []byte {
	if len(m.Path) == 0 {
		return nil
	}

	index := bytes.LastIndexByte(m.Path[:len(m.Path)-1], '.')
	if index < 0 {
		return nil
	}

	return m.Path[:index+1]
}

func (m *Metric) IsLeaf() uint8 {
	if len(m.Path) > 0 && m.Path[len(m.Path)-1] == '.' {
		return 0
	}
	return 1
}

func (m *Metric) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]interface{}{
		"Path":   unsafeString(m.Path),
		"Level":  m.Level,
		"Tags":   m.Tags,
		"IsLeaf": m.IsLeaf(),
	})
}
<|endoftext|>