<commit_before>// Copyright (c) 2018 Intel Corporation
//
// 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 logging

import (
	"fmt"
	"os"
	"strings"
	"time"
	"io"

	"github.com/pkg/errors"
	lumberjack "gopkg.in/natefinch/lumberjack.v2"
)

// Level type
type Level uint32

// PanicLevel...MaxLevel indicates the logging level
const (
	PanicLevel Level = iota
	ErrorLevel
	VerboseLevel
	DebugLevel
	MaxLevel
	UnknownLevel
)

var loggingStderr bool
var loggingW io.Writer
var loggingLevel Level

const defaultTimestampFormat = time.RFC3339

func (l Level) String() string {
	switch l {
	case PanicLevel:
		return "panic"
	case VerboseLevel:
		return "verbose"
	case ErrorLevel:
		return "error"
	case DebugLevel:
		return "debug"
	}
	return "unknown"
}

func printf(level Level, format string, a ...interface{}) {
	header := "%s [%s] "
	t := time.Now()
	if level > loggingLevel {
		return
	}

	if loggingStderr {
		fmt.Fprintf(os.Stderr, header, t.Format(defaultTimestampFormat), level)
		fmt.Fprintf(os.Stderr, format, a...)
		fmt.Fprintf(os.Stderr, "\n")
	}

	if loggingW != nil {
		fmt.Fprintf(loggingW, header, t.Format(defaultTimestampFormat), level)
		fmt.Fprintf(loggingW, format, a...)
		fmt.Fprintf(loggingW, "\n")
	}
}

// Debugf prints logging if logging level >= debug
func Debugf(format string, a ...interface{}) {
	printf(DebugLevel, format, a...)
}

// Verbosef prints logging if logging level >= verbose
func Verbosef(format string, a ...interface{}) {
	printf(VerboseLevel, format, a...)
}

// Errorf prints logging if logging level >= error
func Errorf(format string, a ...interface{}) error {
	printf(ErrorLevel, format, a...)
	return fmt.Errorf(format, a...)
}

// Panicf prints logging plus stack trace. This should be used only for unrecoverble error
func Panicf(format string, a ...interface{}) {
	printf(PanicLevel, format, a...)
	printf(PanicLevel, "========= Stack trace output ========")
	printf(PanicLevel, "%+v", errors.New("Multus Panic"))
	printf(PanicLevel, "========= Stack trace output end ========")
}

// GetLoggingLevel gets current logging level
func GetLoggingLevel() Level {
	return loggingLevel
}

func getLoggingLevel(levelStr string) Level {
	switch strings.ToLower(levelStr) {
	case "debug":
		return DebugLevel
	case "verbose":
		return VerboseLevel
	case "error":
		return ErrorLevel
	case "panic":
		return PanicLevel
	}
	fmt.Fprintf(os.Stderr, "multus logging: cannot set logging level to %s\n", levelStr)
	return UnknownLevel
}

// SetLogLevel sets logging level
func SetLogLevel(levelStr string) {
	level := getLoggingLevel(levelStr)
	if level < MaxLevel {
		loggingLevel = level
	}
}

// SetLogStderr sets flag for logging stderr output
func SetLogStderr(enable bool) {
	loggingStderr = enable
}

// SetLogFile sets logging file
func SetLogFile(filename string) {
	if filename == "" {
		return
	}

	loggingW = &lumberjack.Logger{
                        Filename:   filename,
                        MaxSize:    100, // megabytes
                        MaxBackups: 5,
                        MaxAge:     5, // days
                        Compress:   true,
                    }

}

func init() {
	loggingStderr = true
	loggingW = nil
	loggingLevel = PanicLevel
}
<commit_msg>Run 'go fmt' on code base.<commit_after>// Copyright (c) 2018 Intel Corporation
//
// 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 logging

import (
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"github.com/pkg/errors"
	lumberjack "gopkg.in/natefinch/lumberjack.v2"
)

// Level type
type Level uint32

// PanicLevel...MaxLevel indicates the logging level
const (
	PanicLevel Level = iota
	ErrorLevel
	VerboseLevel
	DebugLevel
	MaxLevel
	UnknownLevel
)

var loggingStderr bool
var loggingW io.Writer
var loggingLevel Level

const defaultTimestampFormat = time.RFC3339

func (l Level) String() string {
	switch l {
	case PanicLevel:
		return "panic"
	case VerboseLevel:
		return "verbose"
	case ErrorLevel:
		return "error"
	case DebugLevel:
		return "debug"
	}
	return "unknown"
}

func printf(level Level, format string, a ...interface{}) {
	header := "%s [%s] "
	t := time.Now()
	if level > loggingLevel {
		return
	}

	if loggingStderr {
		fmt.Fprintf(os.Stderr, header, t.Format(defaultTimestampFormat), level)
		fmt.Fprintf(os.Stderr, format, a...)
		fmt.Fprintf(os.Stderr, "\n")
	}

	if loggingW != nil {
		fmt.Fprintf(loggingW, header, t.Format(defaultTimestampFormat), level)
		fmt.Fprintf(loggingW, format, a...)
		fmt.Fprintf(loggingW, "\n")
	}
}

// Debugf prints logging if logging level >= debug
func Debugf(format string, a ...interface{}) {
	printf(DebugLevel, format, a...)
}

// Verbosef prints logging if logging level >= verbose
func Verbosef(format string, a ...interface{}) {
	printf(VerboseLevel, format, a...)
}

// Errorf prints logging if logging level >= error
func Errorf(format string, a ...interface{}) error {
	printf(ErrorLevel, format, a...)
	return fmt.Errorf(format, a...)
}

// Panicf prints logging plus stack trace. This should be used only for unrecoverble error
func Panicf(format string, a ...interface{}) {
	printf(PanicLevel, format, a...)
	printf(PanicLevel, "========= Stack trace output ========")
	printf(PanicLevel, "%+v", errors.New("Multus Panic"))
	printf(PanicLevel, "========= Stack trace output end ========")
}

// GetLoggingLevel gets current logging level
func GetLoggingLevel() Level {
	return loggingLevel
}

func getLoggingLevel(levelStr string) Level {
	switch strings.ToLower(levelStr) {
	case "debug":
		return DebugLevel
	case "verbose":
		return VerboseLevel
	case "error":
		return ErrorLevel
	case "panic":
		return PanicLevel
	}
	fmt.Fprintf(os.Stderr, "multus logging: cannot set logging level to %s\n", levelStr)
	return UnknownLevel
}

// SetLogLevel sets logging level
func SetLogLevel(levelStr string) {
	level := getLoggingLevel(levelStr)
	if level < MaxLevel {
		loggingLevel = level
	}
}

// SetLogStderr sets flag for logging stderr output
func SetLogStderr(enable bool) {
	loggingStderr = enable
}

// SetLogFile sets logging file
func SetLogFile(filename string) {
	if filename == "" {
		return
	}

	loggingW = &lumberjack.Logger{
		Filename:   filename,
		MaxSize:    100, // megabytes
		MaxBackups: 5,
		MaxAge:     5, // days
		Compress:   true,
	}

}

func init() {
	loggingStderr = true
	loggingW = nil
	loggingLevel = PanicLevel
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Datacratic. All rights reserved.

package nfork

import (
	"github.com/nativetouch/goklog/klog"

	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"syscall"
	"time"
)

// OutboundProperties contains information on the Outbound host
// as well as the outbound path to override the HTTP path.
type OutboundProperties struct {
	// Host is the address where HTTP requests
	// should be redirected to. Addresses should be of the for
	// <scheme>://<host>:<port>.
	Host string `json:"host"`
	// Path will be appended to the route of the host.
	// It will also override  the HTTP path.
	Path string `json:"path,omitempty"`
}

// DefaultInboundTimeout is used if no timeout is set for an inbound.
const DefaultInboundTimeout = 1 * time.Second

// Inbound duplicates HTTP requests to a set of outbounds and only forwards the
// HTTP response of an active outbound. All other responses are dropped.
//
// Stats are also gathered for each outbound and each outbounds can also be
// configured to timeout.
type Inbound struct {
	// Name is the name associated with this inbound.
	Name string

	// Listen defines which interface and port this inbound should listen on.
	Listen string

	// Outbound maps a set of outbound names to the address where HTTP requests
	// should be redirected to. Addresses should be of the for
	// <scheme>://<host>:<port>.
	// Optionally a path can be added which will be appended to the route of the
	// host.
	Outbound map[string]OutboundProperties

	// Active defines the name of the outbound whose response will be forwarded
	// back upstream. All other outbound responses are dropped.
	Active string

	// Timeout defines the timeout allowed for all outbounds. If the timeout
	// expires for the active outbound, TimeoutCode is sent back upstream.
	Timeout time.Duration

	// TimeoutCode is HTTP status code sent back upstream if a timeout occurs on
	// the active outbbound.
	TimeoutCode int

	// Client is the http.Client which will be used to forward HTTP requests to
	// all outbounds.
	Client *http.Client

	// IdleConnections defines the maximum size of the connection pool which
	// will be used by the http client for this inbound. Setting this will
	// overwrite the transport of the Client if it is set.
	IdleConnections int

	initialize sync.Once

	stats map[string]*StatsRecorder
}

// Copy returns a copy of the inbound object.
func (inbound *Inbound) Copy() *Inbound {
	newInbound := &Inbound{
		Name: inbound.Name,

		Listen:   inbound.Listen,
		Active:   inbound.Active,
		Outbound: make(map[string]OutboundProperties),

		Timeout:         inbound.Timeout,
		TimeoutCode:     inbound.TimeoutCode,
		IdleConnections: inbound.IdleConnections,

		Client: inbound.Client,
		stats:  make(map[string]*StatsRecorder),
	}

	for outbound, addr := range inbound.Outbound {
		newInbound.Outbound[outbound] = addr
	}

	for outbound, stats := range inbound.stats {
		newInbound.stats[outbound] = stats
	}

	return newInbound
}

// Validate returns an error if one of the Inbound invariants are not satisfied.
func (inbound *Inbound) Validate() error {
	if len(inbound.Name) == 0 {
		inbound.Name = inbound.Listen
	}

	if len(inbound.Listen) == 0 {
		return fmt.Errorf("missing listen host")
	}

	if len(inbound.Outbound) == 0 {
		return fmt.Errorf("no outbound in '%s'", inbound.Name)
	}

	if len(inbound.Active) == 0 {
		return fmt.Errorf("no active outbound in '%s'", inbound.Name)
	}

	if _, ok := inbound.Outbound[inbound.Active]; !ok {
		return fmt.Errorf("active outbound '%s' doesn't exist in '%s'", inbound.Active, inbound.Name)
	}

	return nil
}

// Init initializes the object. Inbounds are lazily initialized so calling this
// is optional.
func (inbound *Inbound) Init() {
	inbound.initialize.Do(inbound.init)
}

func (inbound *Inbound) init() {
	if inbound.Timeout == 0 {
		inbound.Timeout = DefaultInboundTimeout
	}

	if inbound.TimeoutCode == 0 {
		inbound.TimeoutCode = http.StatusServiceUnavailable
	}

	if inbound.Client == nil {
		inbound.Client = new(http.Client)
	}

	if inbound.IdleConnections > 0 {
		inbound.Client.Transport = httpTransport(inbound.IdleConnections)
	} else {
		inbound.IdleConnections = http.DefaultMaxIdleConnsPerHost
	}

	if inbound.Client.Timeout == 0 {
		inbound.Client.Timeout = inbound.Timeout
	}

	if inbound.stats == nil {
		inbound.stats = make(map[string]*StatsRecorder)
	}

	for outbound := range inbound.Outbound {
		inbound.stats[outbound] = new(StatsRecorder)
	}
}

// ReadStats returns the stats associated with each outbounds.
func (inbound *Inbound) ReadStats() map[string]*Stats {
	stats := make(map[string]*Stats)

	for outbound, recorder := range inbound.stats {
		stats[outbound] = recorder.Read()
	}

	return stats
}

// ReadOutboundStats returns the stats associated with a given outbound.
func (inbound *Inbound) ReadOutboundStats(outbound string) (*Stats, error) {
	if _, ok := inbound.Outbound[outbound]; !ok {
		return nil, fmt.Errorf("unknown outbound '%s' for inbound '%s'", outbound, inbound.Name)
	}

	return inbound.stats[outbound].Read(), nil
}

// AddOutbound adds a new outbound associated with the given address. If the
// outbound already exists, it is overridden.
func (inbound *Inbound) AddOutbound(outbound, addr, path string) error {
	inbound.Outbound[outbound] = OutboundProperties{Host: addr, Path: path}
	inbound.stats[outbound] = new(StatsRecorder)
	return nil
}

// RemoveOutbound removes the given outbound. An error is returned if the
// outbound doesn't exist.
func (inbound *Inbound) RemoveOutbound(outbound string) error {
	if _, ok := inbound.Outbound[outbound]; !ok {
		return fmt.Errorf("unknown outbound '%s' for inbound '%s'", outbound, inbound.Name)
	}

	if outbound == inbound.Active {
		return fmt.Errorf("can't remove active outbound '%s' for inbound '%s'", outbound, inbound.Name)
	}

	delete(inbound.Outbound, outbound)
	delete(inbound.stats, outbound)

	return nil
}

// ActivateOutbound activates the given outbound.
func (inbound *Inbound) ActivateOutbound(outbound string) error {
	if _, ok := inbound.Outbound[outbound]; !ok {
		return fmt.Errorf("unknown outbound '%s' for inbound '%s'", outbound, inbound.Name)
	}

	inbound.Active = outbound

	return nil
}

// ServeHTTP forwards the given HTTP request to all the outbounds and forwards
// the response of the active outbound back upstream. All other responses are
// dropped.
func (inbound *Inbound) ServeHTTP(writer http.ResponseWriter, httpReq *http.Request) {
	inbound.Init()

	body, err := ioutil.ReadAll(httpReq.Body)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusBadRequest)
		return
	}

	httpReq.Header.Set("X-Nfork", "true")

	var activeHost string
	var activePath string

	for outbound, host := range inbound.Outbound {
		if outbound != inbound.Active {
			go inbound.forward(outbound, httpReq, host.Host, host.Path, body)
		} else {
			activeHost = host.Host
			activePath = host.Path
		}
	}

	if len(activeHost) == 0 {
		log.Panicf("no active outbound '%s'", inbound.Active)
	}

	respHead, respBody, err := inbound.forward(inbound.Active, httpReq, activeHost, activePath, body)
	if err != nil {
		http.Error(writer, err.Error(), inbound.TimeoutCode)
		return
	}

	writerHeader := writer.Header()
	for key, val := range respHead.Header {
		writerHeader[key] = val
	}

	writer.WriteHeader(respHead.StatusCode)
	writer.Write(respBody)
}

func (inbound *Inbound) record(outbound string, event Event) {
	stats, ok := inbound.stats[outbound]
	if !ok {
		log.Panicf("no stats for outbound '%s'", outbound)
	}
	stats.Record(event)
}

func (inbound *Inbound) parseAddr(addr string) (host, scheme string) {
	if i := strings.Index(addr, "://"); i >= 0 {
		return addr[i+3:], addr[:i]
	}
	return addr, "http"
}

func addScheme(addr string) (schemedAddr string) {
	if i := strings.Index(addr, "://"); i >= 0 {
		return addr
	}
	return "http://" + addr
}

func addPath(addr, path string) (pathdAddr string) {
	if len(path) > 0 {
		return addr + "/" + path
	}
	return addr
}

func (inbound *Inbound) forward(
	outbound string, oldReq *http.Request, addr, path string, body []byte) (*http.Response, []byte, error) {

	t0 := time.Now()

	//host, scheme := inbound.parseAddr(addr)
	addr = addScheme(addr)
	addr = addPath(addr, path)
	parsedURL, err := url.ParseRequestURI(addr)
	if err != nil {
		return nil, nil, inbound.error("parse", addr, err, t0)
	}

	newReq := new(http.Request)
	*newReq = *oldReq

	newReq.URL = new(url.URL)
	newReq.Host = parsedURL.Host

	hasPath := len(path) > 0
	if hasPath {
		*newReq.URL = *parsedURL
	} else {
		*newReq.URL = *oldReq.URL
		newReq.URL.Host = parsedURL.Host
		newReq.URL.Scheme = parsedURL.Scheme
	}

	newReq.RequestURI = ""
	newReq.Body = ioutil.NopCloser(bytes.NewReader(body))

	resp, err := inbound.Client.Do(newReq)
	if err != nil {
		return nil, nil, inbound.error("send", outbound, err, t0)
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, nil, inbound.error("recv", outbound, err, t0)
	}

	inbound.record(outbound, Event{Response: resp.StatusCode, Latency: time.Since(t0)})
	return resp, respBody, nil
}

func (inbound *Inbound) error(title, outbound string, err error, t0 time.Time) error {

	if urlErr, ok := err.(*url.Error); ok {
		return inbound.error(title, outbound, urlErr.Err, t0)

	} else if netErr, ok := err.(*net.OpError); ok {
		if errno, ok := netErr.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED {
			klog.KPrintf(klog.Keyf("%s.%s.%s.timeout", inbound.Name, outbound, title), "%T -> %v", err, err)
			inbound.record(outbound, Event{Timeout: true, Latency: time.Since(t0)})
			return err
		}

		return inbound.error(title, outbound, netErr.Err, t0)
	}

	switch err.Error() {

	// Prevents spamming the logs with closed connections even though they were
	// not properly closed.
	case "EOF":
		inbound.record(outbound, Event{Error: true, Latency: time.Since(t0)})
		return err

	// I hate this but net and net/http provides no useful errors or indicators
	// that a request ended up in a timeout. Furthermore, most of the errors are
	// either not exported or are just randomly created as string. In other
	// words, this is a crappy interface that needs to be fixed bad.
	case "use of closed network connection": // net.errClosing
		fallthrough
	case "net/http: transport closed before response was received":
		fallthrough
	case "net/http: request canceled while waiting for connection":
		klog.KPrintf(klog.Keyf("%s.%s.%s.timeout", inbound.Name, outbound, title), "%T -> %v", err, err)
		inbound.record(outbound, Event{Timeout: true, Latency: time.Since(t0)})
		return err
	}

	klog.KPrintf(klog.Keyf("%s.%s.%s.error", inbound.Name, outbound, title), "%T -> %v", err, err)
	inbound.record(outbound, Event{Error: true, Latency: time.Since(t0)})
	return err
}

// UnmarshalJSON defines a custom JSON format for the encoding/json package.
func (inbound *Inbound) UnmarshalJSON(body []byte) (err error) {
	var inboundJSON struct {
		Name string `json:"name"`

		Listen   string                        `json:"listen"`
		Outbound map[string]OutboundProperties `json:"out"`
		Active   string                        `json:"active"`

		Timeout     string `json:"timeout,omitempty"`
		TimeoutCode int    `json:"timeoutCode,omitempty"`

		IdleConnections int `json:"idleConn"`
	}

	if err = json.Unmarshal(body, &inboundJSON); err != nil {
		return
	}

	inbound.Name = inboundJSON.Name

	inbound.Listen = inboundJSON.Listen
	inbound.Outbound = inboundJSON.Outbound
	inbound.Active = inboundJSON.Active

	if inbound.Timeout, err = time.ParseDuration(inboundJSON.Timeout); err != nil {
		return
	}
	inbound.TimeoutCode = inboundJSON.TimeoutCode

	inbound.IdleConnections = inboundJSON.IdleConnections

	return
}

// MarshalJSON defines a custom JSON format for the encoding/json package.
func (inbound *Inbound) MarshalJSON() ([]byte, error) {
	var inboundJSON struct {
		Name string `json:"name"`

		Listen   string                        `json:"listen"`
		Active   string                        `json:"active"`
		Outbound map[string]OutboundProperties `json:"out"`

		Timeout     string `json:"timeout,omitempty"`
		TimeoutCode int    `json:"timeoutCode,omitempty"`

		IdleConnections int `json:"idleConn"`
	}

	inboundJSON.Name = inbound.Name

	inboundJSON.Listen = inbound.Listen
	inboundJSON.Outbound = inbound.Outbound
	inboundJSON.Active = inbound.Active

	inboundJSON.Timeout = inbound.Timeout.String()
	inboundJSON.TimeoutCode = inbound.TimeoutCode

	inboundJSON.IdleConnections = inbound.IdleConnections

	return json.Marshal(&inboundJSON)
}
<commit_msg>update after code review<commit_after>// Copyright (c) 2014 Datacratic. All rights reserved.

package nfork

import (
	"github.com/nativetouch/goklog/klog"

	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"syscall"
	"time"
)

// OutboundProperties contains information on the Outbound host
// as well as the outbound path to override the HTTP path.
type OutboundProperties struct {
	// Host is the address where HTTP requests
	// should be redirected to. Addresses should be of the for
	// <scheme>://<host>:<port>.
	Host string `json:"host"`
	// Path will be appended to the route of the host.
	// It will also override  the HTTP path.
	Path string `json:"path,omitempty"`
}

// DefaultInboundTimeout is used if no timeout is set for an inbound.
const DefaultInboundTimeout = 1 * time.Second

// Inbound duplicates HTTP requests to a set of outbounds and only forwards the
// HTTP response of an active outbound. All other responses are dropped.
//
// Stats are also gathered for each outbound and each outbounds can also be
// configured to timeout.
type Inbound struct {
	// Name is the name associated with this inbound.
	Name string

	// Listen defines which interface and port this inbound should listen on.
	Listen string

	// Outbound maps a set of outbound names to the address where HTTP requests
	// should be redirected to. Addresses should be of the for
	// <scheme>://<host>:<port>.
	// Optionally a path can be added which will be appended to the route of the
	// host.
	Outbound map[string]OutboundProperties

	// Active defines the name of the outbound whose response will be forwarded
	// back upstream. All other outbound responses are dropped.
	Active string

	// Timeout defines the timeout allowed for all outbounds. If the timeout
	// expires for the active outbound, TimeoutCode is sent back upstream.
	Timeout time.Duration

	// TimeoutCode is HTTP status code sent back upstream if a timeout occurs on
	// the active outbbound.
	TimeoutCode int

	// Client is the http.Client which will be used to forward HTTP requests to
	// all outbounds.
	Client *http.Client

	// IdleConnections defines the maximum size of the connection pool which
	// will be used by the http client for this inbound. Setting this will
	// overwrite the transport of the Client if it is set.
	IdleConnections int

	initialize sync.Once

	stats map[string]*StatsRecorder
}

// Copy returns a copy of the inbound object.
func (inbound *Inbound) Copy() *Inbound {
	newInbound := &Inbound{
		Name: inbound.Name,

		Listen:   inbound.Listen,
		Active:   inbound.Active,
		Outbound: make(map[string]OutboundProperties),

		Timeout:         inbound.Timeout,
		TimeoutCode:     inbound.TimeoutCode,
		IdleConnections: inbound.IdleConnections,

		Client: inbound.Client,
		stats:  make(map[string]*StatsRecorder),
	}

	for outbound, addr := range inbound.Outbound {
		newInbound.Outbound[outbound] = addr
	}

	for outbound, stats := range inbound.stats {
		newInbound.stats[outbound] = stats
	}

	return newInbound
}

// Validate returns an error if one of the Inbound invariants are not satisfied.
func (inbound *Inbound) Validate() error {
	if len(inbound.Name) == 0 {
		inbound.Name = inbound.Listen
	}

	if len(inbound.Listen) == 0 {
		return fmt.Errorf("missing listen host")
	}

	if len(inbound.Outbound) == 0 {
		return fmt.Errorf("no outbound in '%s'", inbound.Name)
	}

	if len(inbound.Active) == 0 {
		return fmt.Errorf("no active outbound in '%s'", inbound.Name)
	}

	if _, ok := inbound.Outbound[inbound.Active]; !ok {
		return fmt.Errorf("active outbound '%s' doesn't exist in '%s'", inbound.Active, inbound.Name)
	}

	return nil
}

// Init initializes the object. Inbounds are lazily initialized so calling this
// is optional.
func (inbound *Inbound) Init() {
	inbound.initialize.Do(inbound.init)
}

func (inbound *Inbound) init() {
	if inbound.Timeout == 0 {
		inbound.Timeout = DefaultInboundTimeout
	}

	if inbound.TimeoutCode == 0 {
		inbound.TimeoutCode = http.StatusServiceUnavailable
	}

	if inbound.Client == nil {
		inbound.Client = new(http.Client)
	}

	if inbound.IdleConnections > 0 {
		inbound.Client.Transport = httpTransport(inbound.IdleConnections)
	} else {
		inbound.IdleConnections = http.DefaultMaxIdleConnsPerHost
	}

	if inbound.Client.Timeout == 0 {
		inbound.Client.Timeout = inbound.Timeout
	}

	if inbound.stats == nil {
		inbound.stats = make(map[string]*StatsRecorder)
	}

	for outbound := range inbound.Outbound {
		inbound.stats[outbound] = new(StatsRecorder)
	}
}

// ReadStats returns the stats associated with each outbounds.
func (inbound *Inbound) ReadStats() map[string]*Stats {
	stats := make(map[string]*Stats)

	for outbound, recorder := range inbound.stats {
		stats[outbound] = recorder.Read()
	}

	return stats
}

// ReadOutboundStats returns the stats associated with a given outbound.
func (inbound *Inbound) ReadOutboundStats(outbound string) (*Stats, error) {
	if _, ok := inbound.Outbound[outbound]; !ok {
		return nil, fmt.Errorf("unknown outbound '%s' for inbound '%s'", outbound, inbound.Name)
	}

	return inbound.stats[outbound].Read(), nil
}

// AddOutbound adds a new outbound associated with the given address. If the
// outbound already exists, it is overridden.
func (inbound *Inbound) AddOutbound(outbound, addr, path string) error {
	inbound.Outbound[outbound] = OutboundProperties{Host: addr, Path: path}
	inbound.stats[outbound] = new(StatsRecorder)
	return nil
}

// RemoveOutbound removes the given outbound. An error is returned if the
// outbound doesn't exist.
func (inbound *Inbound) RemoveOutbound(outbound string) error {
	if _, ok := inbound.Outbound[outbound]; !ok {
		return fmt.Errorf("unknown outbound '%s' for inbound '%s'", outbound, inbound.Name)
	}

	if outbound == inbound.Active {
		return fmt.Errorf("can't remove active outbound '%s' for inbound '%s'", outbound, inbound.Name)
	}

	delete(inbound.Outbound, outbound)
	delete(inbound.stats, outbound)

	return nil
}

// ActivateOutbound activates the given outbound.
func (inbound *Inbound) ActivateOutbound(outbound string) error {
	if _, ok := inbound.Outbound[outbound]; !ok {
		return fmt.Errorf("unknown outbound '%s' for inbound '%s'", outbound, inbound.Name)
	}

	inbound.Active = outbound

	return nil
}

// ServeHTTP forwards the given HTTP request to all the outbounds and forwards
// the response of the active outbound back upstream. All other responses are
// dropped.
func (inbound *Inbound) ServeHTTP(writer http.ResponseWriter, httpReq *http.Request) {
	inbound.Init()

	body, err := ioutil.ReadAll(httpReq.Body)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusBadRequest)
		return
	}

	httpReq.Header.Set("X-Nfork", "true")

	var activeHost string
	var activePath string

	for outbound, host := range inbound.Outbound {
		if outbound != inbound.Active {
			go inbound.forward(outbound, httpReq, host.Host, host.Path, body)
		} else {
			activeHost = host.Host
			activePath = host.Path
		}
	}

	if len(activeHost) == 0 {
		log.Panicf("no active outbound '%s'", inbound.Active)
	}

	respHead, respBody, err := inbound.forward(inbound.Active, httpReq, activeHost, activePath, body)
	if err != nil {
		http.Error(writer, err.Error(), inbound.TimeoutCode)
		return
	}

	writerHeader := writer.Header()
	for key, val := range respHead.Header {
		writerHeader[key] = val
	}

	writer.WriteHeader(respHead.StatusCode)
	writer.Write(respBody)
}

func (inbound *Inbound) record(outbound string, event Event) {
	stats, ok := inbound.stats[outbound]
	if !ok {
		log.Panicf("no stats for outbound '%s'", outbound)
	}
	stats.Record(event)
}

func addScheme(addr string) (schemedAddr string) {
	if i := strings.Index(addr, "://"); i >= 0 {
		return addr
	}
	return "http://" + addr
}

func addPath(addr, path string) (pathdAddr string) {
	if len(path) > 0 {
		return addr + "/" + path
	}
	return addr
}

func (inbound *Inbound) forward(
	outbound string, oldReq *http.Request, addr, path string, body []byte) (*http.Response, []byte, error) {

	t0 := time.Now()

	addr = addScheme(addr)
	addr = addPath(addr, path)
	parsedURL, err := url.ParseRequestURI(addr)
	if err != nil {
		return nil, nil, inbound.error("parse", addr, err, t0)
	}

	newReq := new(http.Request)
	*newReq = *oldReq

	newReq.URL = new(url.URL)
	newReq.Host = parsedURL.Host

	hasEnforcedPath := len(path) > 0
	if hasEnforcedPath {
		// Take the path added as a parameter as the new path where to forward
		// the messages
		*newReq.URL = *parsedURL
	} else {
		// Forward the messages to the same path as the incoming message but
		// make sure to send to the correct `Scheme` and `Host`.
		*newReq.URL = *oldReq.URL
		newReq.URL.Host = parsedURL.Host
		newReq.URL.Scheme = parsedURL.Scheme
	}

	newReq.RequestURI = ""
	newReq.Body = ioutil.NopCloser(bytes.NewReader(body))

	resp, err := inbound.Client.Do(newReq)
	if err != nil {
		return nil, nil, inbound.error("send", outbound, err, t0)
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, nil, inbound.error("recv", outbound, err, t0)
	}

	inbound.record(outbound, Event{Response: resp.StatusCode, Latency: time.Since(t0)})
	return resp, respBody, nil
}

func (inbound *Inbound) error(title, outbound string, err error, t0 time.Time) error {

	if urlErr, ok := err.(*url.Error); ok {
		return inbound.error(title, outbound, urlErr.Err, t0)

	} else if netErr, ok := err.(*net.OpError); ok {
		if errno, ok := netErr.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED {
			klog.KPrintf(klog.Keyf("%s.%s.%s.timeout", inbound.Name, outbound, title), "%T -> %v", err, err)
			inbound.record(outbound, Event{Timeout: true, Latency: time.Since(t0)})
			return err
		}

		return inbound.error(title, outbound, netErr.Err, t0)
	}

	switch err.Error() {

	// Prevents spamming the logs with closed connections even though they were
	// not properly closed.
	case "EOF":
		inbound.record(outbound, Event{Error: true, Latency: time.Since(t0)})
		return err

	// I hate this but net and net/http provides no useful errors or indicators
	// that a request ended up in a timeout. Furthermore, most of the errors are
	// either not exported or are just randomly created as string. In other
	// words, this is a crappy interface that needs to be fixed bad.
	case "use of closed network connection": // net.errClosing
		fallthrough
	case "net/http: transport closed before response was received":
		fallthrough
	case "net/http: request canceled while waiting for connection":
		klog.KPrintf(klog.Keyf("%s.%s.%s.timeout", inbound.Name, outbound, title), "%T -> %v", err, err)
		inbound.record(outbound, Event{Timeout: true, Latency: time.Since(t0)})
		return err
	}

	klog.KPrintf(klog.Keyf("%s.%s.%s.error", inbound.Name, outbound, title), "%T -> %v", err, err)
	inbound.record(outbound, Event{Error: true, Latency: time.Since(t0)})
	return err
}

// UnmarshalJSON defines a custom JSON format for the encoding/json package.
func (inbound *Inbound) UnmarshalJSON(body []byte) (err error) {
	var inboundJSON struct {
		Name string `json:"name"`

		Listen   string                        `json:"listen"`
		Outbound map[string]OutboundProperties `json:"out"`
		Active   string                        `json:"active"`

		Timeout     string `json:"timeout,omitempty"`
		TimeoutCode int    `json:"timeoutCode,omitempty"`

		IdleConnections int `json:"idleConn"`
	}

	if err = json.Unmarshal(body, &inboundJSON); err != nil {
		return
	}

	inbound.Name = inboundJSON.Name

	inbound.Listen = inboundJSON.Listen
	inbound.Outbound = inboundJSON.Outbound
	inbound.Active = inboundJSON.Active

	if inbound.Timeout, err = time.ParseDuration(inboundJSON.Timeout); err != nil {
		return
	}
	inbound.TimeoutCode = inboundJSON.TimeoutCode

	inbound.IdleConnections = inboundJSON.IdleConnections

	return
}

// MarshalJSON defines a custom JSON format for the encoding/json package.
func (inbound *Inbound) MarshalJSON() ([]byte, error) {
	var inboundJSON struct {
		Name string `json:"name"`

		Listen   string                        `json:"listen"`
		Active   string                        `json:"active"`
		Outbound map[string]OutboundProperties `json:"out"`

		Timeout     string `json:"timeout,omitempty"`
		TimeoutCode int    `json:"timeoutCode,omitempty"`

		IdleConnections int `json:"idleConn"`
	}

	inboundJSON.Name = inbound.Name

	inboundJSON.Listen = inbound.Listen
	inboundJSON.Outbound = inbound.Outbound
	inboundJSON.Active = inbound.Active

	inboundJSON.Timeout = inbound.Timeout.String()
	inboundJSON.TimeoutCode = inbound.TimeoutCode

	inboundJSON.IdleConnections = inbound.IdleConnections

	return json.Marshal(&inboundJSON)
}
<|endoftext|>


<commit_before>package libxml2

import (
	"bytes"
	"errors"
	"unsafe"
)

func CreateDocument() *Document {
	return NewDocument("1.0", "")
}

func NewDocument(version, encoding string) *Document {
	doc := xmlNewDoc(version)
	if encoding != "" {
		doc.encoding = xmlStrdup(encoding)
	}
	return wrapDocument(doc)
}

func (d *Document) Pointer() unsafe.Pointer {
	return unsafe.Pointer(d.ptr)
}

func (d *Document) NamespaceByHref(n Node, uri string) (*Namespace, error) {
	return xmlSearchNsByHref(d, n, uri), nil
}

func (d *Document) NamespaceByPrefix(n Node, prefix string) (*Namespace, error) {
	return xmlSearchNs(d, n, prefix), nil
}

func (d *Document) CreateAttribute(k, v string) (*Attribute, error) {
	attr, err := xmlNewDocProp(d, k, v)
	if err != nil {
		return nil, err
	}
	return wrapAttribute(attr), nil
}

func (d *Document) CreateAttributeNS(nsuri, k, v string) (*Attribute, error) {
	if nsuri == "" {
		return d.CreateAttribute(k, v)
	}

	if err := myTestNodeName(k); err != nil {
		return nil, err
	}

	root := d.DocumentElement()
	if root == nil {
		return nil, errors.New("attribute with namespaces require a root node")
	}

	prefix, local := splitPrefixLocal(k)

	ns := xmlSearchNsByHref(d, root, nsuri)
	if ns == nil {
		ns = xmlNewNs(root, nsuri, prefix)
		if ns == nil {
			return nil, errors.New("failed to create namespace")
		}
	}

	newAttr, err := xmlNewDocProp(d, local, v)
	if err != nil {
		return nil, err
	}
	attr := wrapAttribute(newAttr)
	xmlSetNs(attr, ns)

	return wrapAttribute(newAttr), nil
}

func (d *Document) CreateCDataSection(txt string) (*CDataSection, error) {
	cdata := xmlNewCDataBlock(d, txt)
	return wrapCDataSection(cdata), nil
}

func (d *Document) CreateCommentNode(txt string) (*Comment, error) {
	comment := xmlNewComment(txt)
	return wrapComment(comment), nil
}

func (d *Document) CreateElement(name string) (*Element, error) {
	if err := myTestNodeName(name); err != nil {
		return nil, err
	}

	newNode := xmlNewNode(nil, name)

	if newNode == nil {
		return nil, errors.New("element creation failed")
	}
	// XXX hmmm...
	newNode.doc = d.ptr
	return wrapElement(newNode), nil
}

func (d *Document) CreateElementNS(nsuri, name string) (*Element, error) {
	e, err := createElementNS(d, nsuri, name)
	if err != nil {
		return nil, err
	}
	return e, nil
}

func (d *Document) CreateTextNode(txt string) (*Text, error) {
	t := xmlNewText(txt)
	return wrapText(t), nil
}

func (d *Document) DocumentElement() Node {
	n := documentElement(d)
	if n == nil {
		return nil
	}
	return wrapToNode(n)
}

func (d *Document) FindNodes(xpath string) (NodeList, error) {
	root := d.DocumentElement()
	if root == nil {
		return nil, ErrNodeNotFound
	}
	return root.FindNodes(xpath)
}

func (d *Document) Encoding() string {
	return xmlCharToString(d.ptr.encoding)
}

func (d *Document) Free() {
	xmlFreeDoc(d)
}

func (d *Document) String() string {
	return documentString(d, d.Encoding(), false)
}

func (d *Document) Dump(format bool) string {
	return documentString(d, d.Encoding(), format)
}

func (d *Document) NodeType() XmlNodeType {
	return XmlNodeType(d.ptr._type)
}

func (d *Document) SetBaseURI(s string) {
	xmlNodeSetBase(d, s)
}

func (d *Document) SetDocumentElement(n Node) {
	setDocumentElement(d, n)
}

func (d *Document) SetEncoding(e string) {
	setDocumentEncoding(d, e)
}

func (d *Document) SetStandalone(v int) {
	setDocumentStandalone(d, v)
}

func (d *Document) SetVersion(v string) {
	setDocumentVersion(d, v)
}

func (d *Document) Standalone() int {
	return int(d.ptr.standalone)
}

func (d *Document) ToString(skipXmlDecl bool) string {
	buf := &bytes.Buffer{}
	for _, n := range childNodes(d) {
		if n.NodeType() == DTDNode {
			continue
		}
		buf.WriteString(n.String())
	}

	return buf.String()
}

func (d *Document) ToStringC14N(exclusive bool) (string, error) {
	return d.DocumentElement().ToStringC14N(exclusive)
}

func (d *Document) URI() string {
	return xmlCharToString(d.ptr.URL)
}

func (d *Document) Version() string {
	return xmlCharToString(d.ptr.version)
}

func (d *Document) Walk(fn func(Node) error) {
	walk(d.DocumentElement(), fn)

}
<commit_msg>Properly set the error value<commit_after>package libxml2

import (
	"bytes"
	"errors"
	"unsafe"
)

func CreateDocument() *Document {
	return NewDocument("1.0", "")
}

func NewDocument(version, encoding string) *Document {
	doc := xmlNewDoc(version)
	if encoding != "" {
		doc.encoding = xmlStrdup(encoding)
	}
	return wrapDocument(doc)
}

func (d *Document) Pointer() unsafe.Pointer {
	return unsafe.Pointer(d.ptr)
}

func (d *Document) NamespaceByHref(n Node, uri string) (*Namespace, error) {
	ns := xmlSearchNsByHref(d, n, uri)
	if ns == nil {
		return nil, errors.New("not found")
	}
	return ns, nil
}

func (d *Document) NamespaceByPrefix(n Node, prefix string) (*Namespace, error) {
	ns := xmlSearchNs(d, n, prefix)
	if ns == nil {
		return nil, errors.New("not found")
	}
	return ns, nil
}

func (d *Document) CreateAttribute(k, v string) (*Attribute, error) {
	attr, err := xmlNewDocProp(d, k, v)
	if err != nil {
		return nil, err
	}
	return wrapAttribute(attr), nil
}

func (d *Document) CreateAttributeNS(nsuri, k, v string) (*Attribute, error) {
	if nsuri == "" {
		return d.CreateAttribute(k, v)
	}

	if err := myTestNodeName(k); err != nil {
		return nil, err
	}

	root := d.DocumentElement()
	if root == nil {
		return nil, errors.New("attribute with namespaces require a root node")
	}

	prefix, local := splitPrefixLocal(k)

	ns := xmlSearchNsByHref(d, root, nsuri)
	if ns == nil {
		ns = xmlNewNs(root, nsuri, prefix)
		if ns == nil {
			return nil, errors.New("failed to create namespace")
		}
	}

	newAttr, err := xmlNewDocProp(d, local, v)
	if err != nil {
		return nil, err
	}
	attr := wrapAttribute(newAttr)
	xmlSetNs(attr, ns)

	return wrapAttribute(newAttr), nil
}

func (d *Document) CreateCDataSection(txt string) (*CDataSection, error) {
	cdata := xmlNewCDataBlock(d, txt)
	return wrapCDataSection(cdata), nil
}

func (d *Document) CreateCommentNode(txt string) (*Comment, error) {
	comment := xmlNewComment(txt)
	return wrapComment(comment), nil
}

func (d *Document) CreateElement(name string) (*Element, error) {
	if err := myTestNodeName(name); err != nil {
		return nil, err
	}

	newNode := xmlNewNode(nil, name)

	if newNode == nil {
		return nil, errors.New("element creation failed")
	}
	// XXX hmmm...
	newNode.doc = d.ptr
	return wrapElement(newNode), nil
}

func (d *Document) CreateElementNS(nsuri, name string) (*Element, error) {
	e, err := createElementNS(d, nsuri, name)
	if err != nil {
		return nil, err
	}
	return e, nil
}

func (d *Document) CreateTextNode(txt string) (*Text, error) {
	t := xmlNewText(txt)
	return wrapText(t), nil
}

func (d *Document) DocumentElement() Node {
	n := documentElement(d)
	if n == nil {
		return nil
	}
	return wrapToNode(n)
}

func (d *Document) FindNodes(xpath string) (NodeList, error) {
	root := d.DocumentElement()
	if root == nil {
		return nil, ErrNodeNotFound
	}
	return root.FindNodes(xpath)
}

func (d *Document) Encoding() string {
	return xmlCharToString(d.ptr.encoding)
}

func (d *Document) Free() {
	xmlFreeDoc(d)
}

func (d *Document) String() string {
	return documentString(d, d.Encoding(), false)
}

func (d *Document) Dump(format bool) string {
	return documentString(d, d.Encoding(), format)
}

func (d *Document) NodeType() XmlNodeType {
	return XmlNodeType(d.ptr._type)
}

func (d *Document) SetBaseURI(s string) {
	xmlNodeSetBase(d, s)
}

func (d *Document) SetDocumentElement(n Node) {
	setDocumentElement(d, n)
}

func (d *Document) SetEncoding(e string) {
	setDocumentEncoding(d, e)
}

func (d *Document) SetStandalone(v int) {
	setDocumentStandalone(d, v)
}

func (d *Document) SetVersion(v string) {
	setDocumentVersion(d, v)
}

func (d *Document) Standalone() int {
	return int(d.ptr.standalone)
}

func (d *Document) ToString(skipXmlDecl bool) string {
	buf := &bytes.Buffer{}
	for _, n := range childNodes(d) {
		if n.NodeType() == DTDNode {
			continue
		}
		buf.WriteString(n.String())
	}

	return buf.String()
}

func (d *Document) ToStringC14N(exclusive bool) (string, error) {
	return d.DocumentElement().ToStringC14N(exclusive)
}

func (d *Document) URI() string {
	return xmlCharToString(d.ptr.URL)
}

func (d *Document) Version() string {
	return xmlCharToString(d.ptr.version)
}

func (d *Document) Walk(fn func(Node) error) {
	walk(d.DocumentElement(), fn)

}
<|endoftext|>


<commit_before>package docker

import (
	b64 "encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/murat1985/hyperclair/config"
	"github.com/murat1985/hyperclair/docker/httpclient"
	"github.com/murat1985/hyperclair/xerrors"
)

type token struct {
	Value string `json:"token"`
}

func (tok token) String() string {
	return tok.Value
}

//BearerAuthParams parse Bearer Token on Www-Authenticate header
func BearerAuthParams(r *http.Response) map[string]string {
	s := strings.Fields(r.Header.Get("Www-Authenticate"))

	// Adding Basic authentication support
	bearer_or_basic, _ := regexp.MatchString("Bearer|Basic", s[0])
	if len(s) != 2 || !bearer_or_basic {
		logrus.Fatalf("Authentication Realm is not supported: ", s[0])
		return nil
	}

	result := map[string]string{}

	for _, kv := range strings.Split(s[1], ",") {
		parts := strings.Split(kv, "=")
		if len(parts) != 2 {
			continue
		}
		result[strings.Trim(parts[0], "\" ")] = strings.Trim(parts[1], "\" ")
	}
	return result
}

func AuthenticateResponse(dockerResponse *http.Response, request *http.Request) error {
	bearerToken := BearerAuthParams(dockerResponse)
	url := ""

	s := strings.Fields(dockerResponse.Header.Get("Www-Authenticate"))

	if s[0] == "Bearer" {
		url = bearerToken["realm"] + "?service=" + bearerToken["service"]
	} else {
		url = bearerToken["realm"] + "v2/"
	}

	if bearerToken["scope"] != "" {
		url += "&scope=" + bearerToken["scope"]
	}
	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return err
	}

	l, err := config.GetLogin(strings.Trim(bearerToken["realm"], "/"))
	if err != nil {
		return err
	}
	req.SetBasicAuth(l.Username, l.Password)

	response, err := httpclient.Get().Do(req)

	if err != nil {
		return err
	}

	if response.StatusCode == http.StatusUnauthorized {
		return xerrors.Unauthorized
	}

	if response.StatusCode != http.StatusOK {
		return fmt.Errorf("authentication server response: %v - %v", response.StatusCode, response.Status)
	}

	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)

	if err != nil {
		return err
	}

	if s[0] == "Bearer" {
		var tok token
		err = json.Unmarshal(body, &tok)

		if err != nil {
			return err
		}
		request.Header.Set("Authorization", "Bearer "+tok.String())
	} else {
		auth := fmt.Sprintf("%s:%s", l.Username, l.Password)
		request.Header.Set("Authorization", "Basic "+b64.StdEncoding.EncodeToString([]byte(auth)))
	}

	return nil
}
<commit_msg>fix docker registry auth<commit_after>package docker

import (
	b64 "encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/murat1985/hyperclair/config"
	"github.com/murat1985/hyperclair/docker/httpclient"
	"github.com/murat1985/hyperclair/xerrors"
)

type token struct {
	Value string `json:"token"`
}

func (tok token) String() string {
	return tok.Value
}

//BearerAuthParams parse Bearer Token on Www-Authenticate header
func BearerAuthParams(r *http.Response) map[string]string {
	s := strings.Fields(r.Header.Get("Www-Authenticate"))

	// Adding Basic authentication support
	bearer_or_basic, _ := regexp.MatchString("Bearer|Basic", s[0])
	if len(s) != 2 || !bearer_or_basic {
		logrus.Fatalf("Authentication Realm is not supported: ", s[0])
		return nil
	}

	result := map[string]string{}

	for _, kv := range strings.Split(s[1], ",") {
		parts := strings.Split(kv, "=")
		if len(parts) != 2 {
			continue
		}
		result[strings.Trim(parts[0], "\" ")] = strings.Trim(parts[1], "\" ")
	}
	return result
}

func AuthenticateResponse(dockerResponse *http.Response, request *http.Request) error {
	bearerToken := BearerAuthParams(dockerResponse)
	url := ""

	s := strings.Fields(dockerResponse.Header.Get("Www-Authenticate"))

	if s[0] == "Bearer" {
		url = bearerToken["realm"] + "?service=" + bearerToken["service"]
	} else {
		url = bearerToken["realm"] + "v2/"
	}

	if bearerToken["scope"] != "" {
		url += "&scope=" + bearerToken["scope"]
	}
	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return err
	}

	l, err := config.GetLogin(fmt.Sprintf("%s://%s", request.URL.Scheme, request.URL.Host))
	if err != nil {
		return err
	}
	req.SetBasicAuth(l.Username, l.Password)

	response, err := httpclient.Get().Do(req)

	if err != nil {
		return err
	}

	if response.StatusCode == http.StatusUnauthorized {
		return xerrors.Unauthorized
	}

	if response.StatusCode != http.StatusOK {
		return fmt.Errorf("authentication server response: %v - %v", response.StatusCode, response.Status)
	}

	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)

	if err != nil {
		return err
	}

	if s[0] == "Bearer" {
		var tok token
		err = json.Unmarshal(body, &tok)

		if err != nil {
			return err
		}
		request.Header.Set("Authorization", "Bearer "+tok.String())
	} else {
		auth := fmt.Sprintf("%s:%s", l.Username, l.Password)
		request.Header.Set("Authorization", "Basic "+b64.StdEncoding.EncodeToString([]byte(auth)))
	}

	return nil
}
<|endoftext|>


<commit_before>// https://code.google.com/codejam/contest/dashboard?c=6254486#s=p2

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	// ensure input filename entered on command line
	if len(os.Args) <= 1 {
		fmt.Println("Usage: > go run CoinJam.go <input.file>")
		return
	}

	// capture input file name
	file, err := os.Open(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error reading input file: %v\n", err)
		return
	}
	defer file.Close()

	// setup scanner to read input file
	scanner := bufio.NewScanner(file)

	k := 0 // line numbers
	testcasecount := 0	// only one testcase for both inputs for coinjam
	for scanner.Scan() {
		if k == 0 {
			// read test case number
			fmt.Printf("Case #: %s\n", strings.TrimSpace(scanner.Text()))
			k++
			continue
		}

		testcase_data := strings.split(strings.TrimSpace(scanner.Text()), " ")

		if len(testcase_data == 2) {
			cj_length := strconv.Atoi(strings.TrimSpace(testcase_data[0]))	// jamcoin length
			cj_num := strconv.Atoi(strings.TrimSpace(testcase_data[1]))		// number of coins to generate
		}
	}
}
<commit_msg>ValidateCoin()'s scaffold<commit_after>// https://code.google.com/codejam/contest/dashboard?c=6254486#s=p2

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	// ensure input filename entered on command line
	if len(os.Args) <= 1 {
		fmt.Println("Usage: > go run CoinJam.go <input.file>")
		return
	}

	// capture input file name
	file, err := os.Open(os.Args[1])
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error reading input file: %v\n", err)
		return
	}
	defer file.Close()

	// setup scanner to read input file
	scanner := bufio.NewScanner(file)

	k := 0             // line numbers
	// testcasecount := 0 // only one testcase for both inputs for coinjam
	for scanner.Scan() {
		if k == 0 {
			// read test case number
			fmt.Printf("Case #: %s\n", strings.TrimSpace(scanner.Text()))
			k++
			continue
		}

		testcase_data := strings.Split(strings.TrimSpace(scanner.Text()), " ")

		if len(testcase_data) == 2 {
			cj_length, _ := strconv.Atoi(strings.TrimSpace(testcase_data[0])) // jamcoin length
			cj_num, _ := strconv.Atoi(strings.TrimSpace(testcase_data[1]))    // number of coins to generate
			fmt.Printf("%d %d\n", cj_length, cj_num)
		}
	}
}

// validateCoin takes a coin and checks its validity - if valid returns null error and slice of proof
func validateCoin(coin String) (proof []int, error err) {

}
<|endoftext|>


<commit_before>/**
 * (c) 2014, Caoimhe Chaos <caoimhechaos@protonmail.com>,
 *	     Ancient Solutions. All rights reserved.
 *
 * Redistribution and use in source  and binary forms, with or without
 * modification, are permitted  provided that the following conditions
 * are met:
 *
 * * Redistributions of  source code  must retain the  above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this  list of conditions and the  following disclaimer in
 *   the  documentation  and/or  other  materials  provided  with  the
 *   distribution.
 * * Neither  the  name  of  Ancient Solutions  nor  the  name  of its
 *   contributors may  be used to endorse or  promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS"  AND ANY EXPRESS  OR IMPLIED WARRANTIES  OF MERCHANTABILITY
 * AND FITNESS  FOR A PARTICULAR  PURPOSE ARE DISCLAIMED. IN  NO EVENT
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT  LIABILITY,  OR  TORT  (INCLUDING NEGLIGENCE  OR  OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"crypto/tls"
	"crypto/x509"
	"flag"
	"io/ioutil"
	"log"
	"net"
	"net/rpc"

	"ancient-solutions.com/doozer/exportedservice"
	"ancient-solutions.com/mailpump"
	"code.google.com/p/goprotobuf/proto"
)

func main() {
	var service *MailSubmissionService
	var conf *mailpump.MailPumpConfiguration
	var l net.Listener
	var config_contents []byte
	var configpath string
	var err error

	flag.StringVar(&configpath, "config-path", "mailstream.cfg",
		"Path to the mailstream configuration file "+
			"(an ascii protocol buffer).")
	flag.Parse()

	config_contents, err = ioutil.ReadFile(configpath)
	if err != nil {
		log.Fatal("Unable to read ", configpath, ": ", err)
	}

	conf = new(mailpump.MailPumpConfiguration)
	err = proto.UnmarshalText(string(config_contents), conf)
	if err != nil {
		log.Fatal("Error parsing ", configpath, ": ", err)
	}

	if conf.GetInsecure() {
		l, err = net.Listen("tcp", conf.GetBindTo())
	} else {
		var tlscert tls.Certificate
		var config *tls.Config = new(tls.Config)
		var certdata []byte

		config.ClientAuth = tls.VerifyClientCertIfGiven
		config.MinVersion = tls.VersionTLS12

		tlscert, err = tls.LoadX509KeyPair(conf.GetX509Cert(),
			conf.GetX509Key())
		if err != nil {
			log.Fatal("Unable to load X.509 key pair: ", err)
		}
		config.Certificates = append(config.Certificates, tlscert)
		config.BuildNameToCertificate()

		config.ClientCAs = x509.NewCertPool()
		certdata, err = ioutil.ReadFile(conf.GetX509CaCert())
		if err != nil {
			log.Fatal("Error reading ", conf.GetX509CaCert(), ": ", err)
		}
		if !config.ClientCAs.AppendCertsFromPEM(certdata) {
			log.Fatal("Unable to load the X.509 certificates from ",
				conf.GetX509CaCert())
		}

		if conf.DoozerUri != nil && len(conf.GetDoozerUri()) > 0 {
			var exporter *exportedservice.ServiceExporter
			exporter, err = exportedservice.NewExporter(
				conf.GetDoozerUri(), conf.GetDoozerBootUri())
			if err != nil {
				log.Fatal("Error contacting lock service: ", err)
			}
			l, err = exporter.NewExportedTLSPort("tcp",
				conf.GetBindTo(), conf.GetServiceName(), config)
			if err != nil {
				log.Fatal("Error creating exported TLS port: ", err)
			}
			defer exporter.UnexportPort()
		} else {
			l, err = tls.Listen("tcp", conf.GetBindTo(), config)
			if err != nil {
				log.Fatal("Error creating TLS listener port: ", err)
			}
		}
	}

	// Create server-side service object and register with the HTTP server.
	service = &MailSubmissionService{
		config: conf,
	}

	if err = rpc.Register(service); err != nil {
		log.Fatal("Unable to register RPC handler: ", err)
	}

	log.Print("Listening on ", l.Addr())
	rpc.Accept(l)
}
<commit_msg>Try to fill Doozer settings from the environment.<commit_after>/**
 * (c) 2014, Caoimhe Chaos <caoimhechaos@protonmail.com>,
 *	     Ancient Solutions. All rights reserved.
 *
 * Redistribution and use in source  and binary forms, with or without
 * modification, are permitted  provided that the following conditions
 * are met:
 *
 * * Redistributions of  source code  must retain the  above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this  list of conditions and the  following disclaimer in
 *   the  documentation  and/or  other  materials  provided  with  the
 *   distribution.
 * * Neither  the  name  of  Ancient Solutions  nor  the  name  of its
 *   contributors may  be used to endorse or  promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS"  AND ANY EXPRESS  OR IMPLIED WARRANTIES  OF MERCHANTABILITY
 * AND FITNESS  FOR A PARTICULAR  PURPOSE ARE DISCLAIMED. IN  NO EVENT
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED  TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT  LIABILITY,  OR  TORT  (INCLUDING NEGLIGENCE  OR  OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"crypto/tls"
	"crypto/x509"
	"flag"
	"io/ioutil"
	"log"
	"net"
	"net/rpc"
	"os"

	"ancient-solutions.com/doozer/exportedservice"
	"ancient-solutions.com/mailpump"
	"code.google.com/p/goprotobuf/proto"
)

func main() {
	var service *MailSubmissionService
	var conf *mailpump.MailPumpConfiguration
	var l net.Listener
	var config_contents []byte
	var configpath string
	var err error

	flag.StringVar(&configpath, "config-path", "mailstream.cfg",
		"Path to the mailstream configuration file "+
			"(an ascii protocol buffer).")
	flag.Parse()

	config_contents, err = ioutil.ReadFile(configpath)
	if err != nil {
		log.Fatal("Unable to read ", configpath, ": ", err)
	}

	conf = new(mailpump.MailPumpConfiguration)
	err = proto.UnmarshalText(string(config_contents), conf)
	if err != nil {
		log.Fatal("Error parsing ", configpath, ": ", err)
	}

	if conf.DoozerUri == nil && len(os.Getenv("DOOZER_URI")) > 0 {
		conf.DoozerUri = new(string)
		*conf.DoozerUri = os.Getenv("DOOZER_URI")
	}

	if conf.DoozerBootUri == nil && len(os.Getenv("DOOZER_BOOT_URI")) > 0 {
		conf.DoozerBootUri = new(string)
		*conf.DoozerBootUri = os.Getenv("DOOZER_BOOT_URI")
	}

	if conf.GetInsecure() {
		l, err = net.Listen("tcp", conf.GetBindTo())
	} else {
		var tlscert tls.Certificate
		var config *tls.Config = new(tls.Config)
		var certdata []byte

		config.ClientAuth = tls.VerifyClientCertIfGiven
		config.MinVersion = tls.VersionTLS12

		tlscert, err = tls.LoadX509KeyPair(conf.GetX509Cert(),
			conf.GetX509Key())
		if err != nil {
			log.Fatal("Unable to load X.509 key pair: ", err)
		}
		config.Certificates = append(config.Certificates, tlscert)
		config.BuildNameToCertificate()

		config.ClientCAs = x509.NewCertPool()
		certdata, err = ioutil.ReadFile(conf.GetX509CaCert())
		if err != nil {
			log.Fatal("Error reading ", conf.GetX509CaCert(), ": ", err)
		}
		if !config.ClientCAs.AppendCertsFromPEM(certdata) {
			log.Fatal("Unable to load the X.509 certificates from ",
				conf.GetX509CaCert())
		}

		if conf.DoozerUri != nil && len(conf.GetDoozerUri()) > 0 {
			var exporter *exportedservice.ServiceExporter
			exporter, err = exportedservice.NewExporter(
				conf.GetDoozerUri(), conf.GetDoozerBootUri())
			if err != nil {
				log.Fatal("Error contacting lock service: ", err)
			}
			l, err = exporter.NewExportedTLSPort("tcp",
				conf.GetBindTo(), conf.GetServiceName(), config)
			if err != nil {
				log.Fatal("Error creating exported TLS port: ", err)
			}
			defer exporter.UnexportPort()
		} else {
			l, err = tls.Listen("tcp", conf.GetBindTo(), config)
			if err != nil {
				log.Fatal("Error creating TLS listener port: ", err)
			}
		}
	}

	// Create server-side service object and register with the HTTP server.
	service = &MailSubmissionService{
		config: conf,
	}

	if err = rpc.Register(service); err != nil {
		log.Fatal("Unable to register RPC handler: ", err)
	}

	log.Print("Listening on ", l.Addr())
	rpc.Accept(l)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
)

// HelpForDelete outputs usage information for the delete command
func (cmds *CommandSet) HelpForDelete() {
	fmt.Println("go-bigv delete")
	fmt.Println()
	fmt.Println("usage: bigv delete [-p | --purge] <name>")
	fmt.Println("       bigv delete vm [-p | ---purge] <virtual machine>")
	fmt.Println("       bigv delete group <group>")
	fmt.Println("       bigv delete account <account>")
	fmt.Println("       bigv delete user <auser>")
	fmt.Println("       bigv undelete vm <virtual machine>")
	fmt.Println()
	fmt.Println("Deletes the given virtual machine, group, account or user.")
	fmt.Println("If the --purge flag is given and the target is a virtual machine, will permanently delete the VM. Billing will cease and you will be unable to recover the VM.")
	fmt.Println()
	fmt.Println("The undelete vm command may be used to restore a deleted (but not purged) vm to its state prior to deletion.")
	fmt.Println()
}

// DeleteVM implements the delete-vm command, which is used to delete and purge BigV VMs. See HelpForDelete for usage information.
func (cmds *CommandSet) DeleteVM(args []string) ExitCode {

	// TODO(telyn): rewrite flag code here.
	flags := flag.NewFlagSet("DeleteVM", flag.ExitOnError)

	var purge = *flags.Bool("purge", false, "Whether or not to purge the VM. If yes, will delete all your data.")
	var force = *flags.Bool("force", false, "Don't confirm deletion. Be careful when using with --purge!")

	flags.Parse(args)

	name := cmds.bigv.ParseVirtualMachineName(flags.Args()[0])
	cmds.EnsureAuth()

	vm, err := cmds.bigv.GetVirtualMachine(name)
	if err != nil {
		return processError(err)
	}
	if vm.Deleted && !purge {
		fmt.Printf("Virtual machine %s has already been deleted.\r\nIf you wish to permanently delete it, add --purge", vm.Hostname)
		return E_SUCCESS
	}

	if !force {
		// TODO(telyn): use PromptYN
		buf := bufio.NewReader(os.Stdin)
		fstr := "Are you certain you wish to delete %s? (y/n) "
		if purge {
			fstr = "Are you certain you wish to PERMANENTLY delete %s? (y/n) "

		}
		fmt.Fprintf(os.Stderr, fstr, vm.Hostname)
		chr, err := buf.ReadByte()
		fmt.Println()
		if err != nil {
			return processError(err)
		} else if chr != 'y' {

			return processError(&UserRequestedExit{})

		}
	}

	err = cmds.bigv.DeleteVirtualMachine(name, purge)

	if err != nil {
		return processError(err)
	}

	if purge {
		fmt.Printf("Virtual machine %s purged successfully.\r\n", name)
	} else {
		fmt.Printf("Virtual machine %s deleted successfully.\r\n", name)
	}
	return E_SUCCESS
}

// UndeleteVM implements the undelete-vm command, which is used to remove the deleted flag from BigV VMs, allowing them to be reactivated.
func (cmds *CommandSet) UndeleteVM(args []string) ExitCode {

	name := cmds.bigv.ParseVirtualMachineName(args[0])
	cmds.EnsureAuth()

	vm, err := cmds.bigv.GetVirtualMachine(name)
	if err != nil {
		return processError(err)
	}

	if !vm.Deleted {
		fmt.Printf("Virtual machine %s was already undeleted", vm.Hostname)
		return E_SUCCESS
	}

	err = cmds.bigv.UndeleteVirtualMachine(name)

	if err != nil {
		return processError(err)
	}
	fmt.Printf("Successfully restored virtual machine %s\r\n", vm.Hostname)

	return E_SUCCESS
}
<commit_msg>Updated the usage info for delete- commands<commit_after>package main

import (
	"fmt"
)

// HelpForDelete outputs usage information for the delete command
func (cmds *CommandSet) HelpForDelete() {
	fmt.Println("go-bigv delete")
	fmt.Println()
	fmt.Println("usage: bigv delete [--force] [--purge] <name>")
	fmt.Println("       bigv delete vm [--force] [---purge] <virtual machine>")
	fmt.Println("       bigv delete group <group>")
	fmt.Println("       bigv delete account <account>")
	fmt.Println("       bigv delete user <auser>")
	fmt.Println("       bigv undelete vm <virtual machine>")
	fmt.Println()
	fmt.Println("Deletes the given virtual machine, group, account or user. Only empty groups and accounts can be deleted.")
	fmt.Println("If the --purge flag is given and the target is a virtual machine, will permanently delete the VM. Billing will cease and you will be unable to recover the VM.")
	fmt.Println("If the --force flag is given, you will not be prompted to confirm deletion.")
	fmt.Println()
	fmt.Println("The undelete vm command may be used to restore a deleted (but not purged) vm to its state prior to deletion.")
	fmt.Println()
}

// DeleteVM implements the delete-vm command, which is used to delete and purge BigV VMs. See HelpForDelete for usage information.
func (cmds *CommandSet) DeleteVM(args []string) ExitCode {

	// TODO(telyn): rewrite flag code here.
	flags := flag.NewFlagSet("DeleteVM", flag.ExitOnError)

	var purge = *flags.Bool("purge", false, "Whether or not to purge the VM. If yes, will delete all your data.")
	var force = *flags.Bool("force", false, "Don't confirm deletion. Be careful when using with --purge!")

	flags.Parse(args)

	name := cmds.bigv.ParseVirtualMachineName(flags.Args()[0])
	cmds.EnsureAuth()

	vm, err := cmds.bigv.GetVirtualMachine(name)
	if err != nil {
		return processError(err)
	}
	if vm.Deleted && !purge {
		fmt.Printf("Virtual machine %s has already been deleted.\r\nIf you wish to permanently delete it, add --purge", vm.Hostname)
		return E_SUCCESS
	}

	if !force {
		// TODO(telyn): use PromptYN
		buf := bufio.NewReader(os.Stdin)
		fstr := "Are you certain you wish to delete %s? (y/n) "
		if purge {
			fstr = "Are you certain you wish to PERMANENTLY delete %s? (y/n) "

		}
		fmt.Fprintf(os.Stderr, fstr, vm.Hostname)
		chr, err := buf.ReadByte()
		fmt.Println()
		if err != nil {
			return processError(err)
		} else if chr != 'y' {

			return processError(&UserRequestedExit{})

		}
	}

	err = cmds.bigv.DeleteVirtualMachine(name, purge)

	if err != nil {
		return processError(err)
	}

	if purge {
		fmt.Printf("Virtual machine %s purged successfully.\r\n", name)
	} else {
		fmt.Printf("Virtual machine %s deleted successfully.\r\n", name)
	}
	return E_SUCCESS
}

// UndeleteVM implements the undelete-vm command, which is used to remove the deleted flag from BigV VMs, allowing them to be reactivated.
func (cmds *CommandSet) UndeleteVM(args []string) ExitCode {

	name := cmds.bigv.ParseVirtualMachineName(args[0])
	cmds.EnsureAuth()

	vm, err := cmds.bigv.GetVirtualMachine(name)
	if err != nil {
		return processError(err)
	}

	if !vm.Deleted {
		fmt.Printf("Virtual machine %s was already undeleted", vm.Hostname)
		return E_SUCCESS
	}

	err = cmds.bigv.UndeleteVirtualMachine(name)

	if err != nil {
		return processError(err)
	}
	fmt.Printf("Successfully restored virtual machine %s\r\n", vm.Hostname)

	return E_SUCCESS
}
<|endoftext|>


<commit_before>package robustly
// Package robustly provides code to handle infrequent panics.

import (
	"bytes"
	"fmt"
	"runtime/debug"
	"time"
	"github.com/VividCortex/moving_average"
)

func Run(function func(), options map[string]int) int {
	// Set config options
	rateLimit := options["rateLimit"]
	timeout := options["timeout"]

	// We use a moving average to compute the rate of errors per second.
	avg := moving_average.NewMovingAverage(float64(timeout))
	before := time.Now()
	var startAboveLimit time.Time
	var belowLimit bool = true
	var beforeTimeout = true
	var totalPanics = 0
	var oktorun bool = true

	for oktorun {
		fmt.Println("running function resiliently, panic rate %f since %s",
								avg.Value(),
								startAboveLimit,
								)

		// Run the provided code and catch errors.
		func() {
			defer func() {
				localErr := recover()
				if localErr == nil {
					oktorun = false // The call to f() exited normally.
					return
				}

				totalPanics++
				after := time.Now()
				duration := after.Sub(before).Seconds()
				if duration > 0 {
					rate := 1.0 / duration
					avg.Add(rate)

					// Figure out whether we're above the rate limit and for how long
					if avg.Value() > float64(rateLimit) {
						if belowLimit {
							startAboveLimit = after
						}
						beforeTimeout =
							after.Before(startAboveLimit.Add(time.Second * time.Duration(timeout)))
						belowLimit = false
					} else {
						belowLimit = true
					}
				}
				before = after

				if !belowLimit && !beforeTimeout {
					panic(fmt.Sprintf("giving up after %d errors at %.2f/sec since %s",
						totalPanics, avg.Value(), startAboveLimit))
				}

				var buf bytes.Buffer
				fmt.Fprintf(&buf, "%v\n", localErr)
				buf.Write(debug.Stack())
				fmt.Println(buf.String())
			}()
			function()
			return
		}()

	}
	return totalPanics
}
<commit_msg>String interpolation in output messages<commit_after>package robustly
// Package robustly provides code to handle infrequent panics.

import (
	"bytes"
	"fmt"
	"runtime/debug"
	"time"
	"github.com/VividCortex/moving_average"
)

func Run(function func(), options map[string]int) int {
	// Set config options
	rateLimit := options["rateLimit"]
	timeout := options["timeout"]

	// We use a moving average to compute the rate of errors per second.
	avg := moving_average.NewMovingAverage(float64(timeout))
	before := time.Now()
	var startAboveLimit time.Time
	var belowLimit bool = true
	var beforeTimeout = true
	var totalPanics = 0
	var oktorun bool = true

	for oktorun {
		fmt.Printf("running function resiliently, panic rate %f since %s \n",
								avg.Value(),
								startAboveLimit,
								)

		// Run the provided code and catch errors.
		func() {
			defer func() {
				localErr := recover()
				if localErr == nil {
					oktorun = false // The call to f() exited normally.
					return
				}

				totalPanics++
				after := time.Now()
				duration := after.Sub(before).Seconds()
				if duration > 0 {
					rate := 1.0 / duration
					avg.Add(rate)

					// Figure out whether we're above the rate limit and for how long
					if avg.Value() > float64(rateLimit) {
						if belowLimit {
							startAboveLimit = after
						}
						beforeTimeout =
							after.Before(startAboveLimit.Add(time.Second * time.Duration(timeout)))
						belowLimit = false
					} else {
						belowLimit = true
					}
				}
				before = after

				if !belowLimit && !beforeTimeout {
					panic(fmt.Sprintf("giving up after %d errors at %.2f/sec since %s",
						totalPanics, avg.Value(), startAboveLimit))
				}

				var buf bytes.Buffer
				fmt.Fprintf(&buf, "%v\n", localErr)
				buf.Write(debug.Stack())
				//fmt.Printf(buf.String())
			}()
			function()
			return
		}()

	}
	return totalPanics
}
<|endoftext|>


<commit_before>// Copyright 2014 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Spencer Kimball (spencer.kimball@gmail.com)

package rpc

import (
	"fmt"
	"io"
	"math/rand"
	"net"
	"net/rpc"
	"time"

	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/log"
)

// OrderingPolicy is an enum for ordering strategies when there
// are multiple endpoints available.
type OrderingPolicy int

const (
	// OrderStable uses endpoints in the order provided.
	OrderStable = iota
	// OrderRandom randomly orders available endpoints.
	OrderRandom
)

// An Options structure describes the algorithm for sending RPCs to
// one or more replicas, depending on error conditions and how many
// successful responses are required.
type Options struct {
	// N is the number of successful responses required.
	N int
	// Ordering indicates how the available endpoints are ordered when
	// deciding which to send to (if there are more than one).
	Ordering OrderingPolicy
	// SendNextTimeout is the duration after which RPCs are sent to
	// other replicas in a set.
	SendNextTimeout time.Duration
	// Timeout is the maximum duration of an RPC before failure.
	// 0 for no timeout.
	Timeout time.Duration
}

// An rpcError indicates a failure to send the RPC. rpcErrors are
// retryable.
type rpcError struct {
	errMsg string
}

// Error implements the error interface.
func (r rpcError) Error() string { return r.errMsg }

// CanRetry implements the Retryable interface.
func (r rpcError) CanRetry() bool { return true }

// A SendError indicates that too many RPCs to the replica
// set failed to achieve requested number of successful responses.
// canRetry is set depending on the types of errors encountered.
type SendError struct {
	errMsg   string
	canRetry bool
}

// Error implements the error interface.
func (s SendError) Error() string {
	return "failed to send RPC: " + s.errMsg
}

// CanRetry implements the Retryable interface.
func (s SendError) CanRetry() bool { return s.canRetry }

// Send sends one or more method RPCs to clients specified by the
// slice of endpoint addrs. Arguments for methods are obtained using
// the supplied getArgs function. The number of required replies is
// given by opts.N. Reply structs are obtained through the getReply()
// function. On success, Send returns a slice of replies of length
// opts.N. Otherwise, Send returns an error if and as soon as the
// number of failed RPCs exceeds the available endpoints less the
// number of required replies.
func Send(opts Options, method string, addrs []net.Addr, getArgs func(addr net.Addr) interface{},
	getReply func() interface{}, context *Context) ([]interface{}, error) {
	if opts.N < len(addrs) {
		return nil, SendError{
			errMsg:   fmt.Sprintf("insufficient replicas (%d) to satisfy send request of %d", len(addrs), opts.N),
			canRetry: false,
		}
	}

	var clients []*Client
	switch opts.Ordering {
	case OrderStable:
		for _, addr := range addrs {
			clients = append(clients, NewClient(addr, nil, context))
		}
	case OrderRandom:
		// Randomly permute order, but keep known-unhealthy clients last.
		var healthy, unhealthy []*Client
		for _, addr := range addrs {
			client := NewClient(addr, nil, context)
			if client.IsHealthy() {
				healthy = append(healthy, client)
			} else {
				unhealthy = append(unhealthy, client)
			}
		}
		for _, idx := range rand.Perm(len(healthy)) {
			clients = append(clients, healthy[idx])
		}
		for _, idx := range rand.Perm(len(unhealthy)) {
			clients = append(clients, unhealthy[idx])
		}
	}
	// TODO(spencer): going to need to also sort by affinity; closest
	// ping time should win. Makes sense to have the rpc client/server
	// heartbeat measure ping times. With a bit of seasoning, each
	// node will be able to order the healthy replicas based on latency.

	replies := []interface{}(nil)
	helperChan := make(chan interface{}, len(clients))
	N := opts.N
	errors := 0
	retryableErrors := 0
	successes := 0
	index := 0

	// Send RPCs to replicas as necessary to achieve opts.N successes.
	for {
		// Start clients up to N.
		for ; index < N; index++ {
			args := getArgs(clients[index].Addr())
			if args == nil {
				helperChan <- util.Errorf("nil arguments returned for client %s", clients[index].Addr())
				continue
			}
			reply := getReply()
			if log.V(1) {
				log.Infof("%s: sending request to %s: %+v", method, clients[index].Addr(), args)
			}
			go sendOne(clients[index], opts.Timeout, method, args, reply, helperChan)
		}
		// Wait for completions.
		select {
		case r := <-helperChan:
			switch t := r.(type) {
			case error:
				errors++
				if retryErr, ok := t.(util.Retryable); ok && retryErr.CanRetry() {
					retryableErrors++
				}
				if log.V(1) {
					log.Warningf("%s: error reply: %+v", method, t)
				}
				remainingRPCs := len(clients) - errors
				if remainingRPCs < opts.N {
					return nil, SendError{
						errMsg:   fmt.Sprintf("too many errors encountered (%d of %d total): %v", errors, len(clients), t),
						canRetry: retryableErrors+remainingRPCs > len(clients),
					}
				}
				// Send to additional replicas if available.
				if N < len(clients) {
					N++
				}
			default:
				successes++
				if log.V(1) {
					log.Infof("%s: successful reply: %+v", method, t)
				}
				replies = append(replies, t)
				if successes == opts.N {
					return replies, nil
				}
			}
		case <-time.After(opts.SendNextTimeout):
			// On successive RPC timeouts, send to additional replicas if available.
			if N < len(clients) {
				N++
			}
		}
	}
}

// sendOne invokes the specified RPC on the supplied client when the
// client is ready. On success, the reply is sent on the channel;
// otherwise an error is sent.
func sendOne(client *Client, timeout time.Duration, method string, args, reply interface{}, c chan interface{}) {
	<-client.Ready
	call := client.Go(method, args, reply, nil)
	select {
	case <-call.Done:
		if call.Error != nil {
			// Handle cases which are retryable.
			switch call.Error {
			case rpc.ErrShutdown: // client connection fails: rpc/client.go
				fallthrough
			case io.ErrUnexpectedEOF: // server connection fails: rpc/client.go
				c <- rpcError{call.Error.Error()}
			default:
				// Otherwise, not retryable; just return error.
				c <- call.Error
			}
		} else {
			// Verify response data integrity if this is a proto response.
			if resp, ok := reply.(proto.Response); ok {
				if req, ok := args.(proto.Request); ok {
					if err := resp.Verify(req); err != nil {
						c <- err
						return
					}
				}
			}
			c <- reply
		}
	case <-client.Closed:
		c <- rpcError{fmt.Sprintf("rpc to %s failed as client connection was closed", method)}
	case <-time.After(timeout):
		c <- rpcError{fmt.Sprintf("rpc to %s timed out after %s", method, timeout)}
	}
}
<commit_msg>Fix the bug of address length comparision<commit_after>// Copyright 2014 The Cockroach 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. See the AUTHORS file
// for names of contributors.
//
// Author: Spencer Kimball (spencer.kimball@gmail.com)

package rpc

import (
	"fmt"
	"io"
	"math/rand"
	"net"
	"net/rpc"
	"time"

	"github.com/cockroachdb/cockroach/proto"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/log"
)

// OrderingPolicy is an enum for ordering strategies when there
// are multiple endpoints available.
type OrderingPolicy int

const (
	// OrderStable uses endpoints in the order provided.
	OrderStable = iota
	// OrderRandom randomly orders available endpoints.
	OrderRandom
)

// An Options structure describes the algorithm for sending RPCs to
// one or more replicas, depending on error conditions and how many
// successful responses are required.
type Options struct {
	// N is the number of successful responses required.
	N int
	// Ordering indicates how the available endpoints are ordered when
	// deciding which to send to (if there are more than one).
	Ordering OrderingPolicy
	// SendNextTimeout is the duration after which RPCs are sent to
	// other replicas in a set.
	SendNextTimeout time.Duration
	// Timeout is the maximum duration of an RPC before failure.
	// 0 for no timeout.
	Timeout time.Duration
}

// An rpcError indicates a failure to send the RPC. rpcErrors are
// retryable.
type rpcError struct {
	errMsg string
}

// Error implements the error interface.
func (r rpcError) Error() string { return r.errMsg }

// CanRetry implements the Retryable interface.
func (r rpcError) CanRetry() bool { return true }

// A SendError indicates that too many RPCs to the replica
// set failed to achieve requested number of successful responses.
// canRetry is set depending on the types of errors encountered.
type SendError struct {
	errMsg   string
	canRetry bool
}

// Error implements the error interface.
func (s SendError) Error() string {
	return "failed to send RPC: " + s.errMsg
}

// CanRetry implements the Retryable interface.
func (s SendError) CanRetry() bool { return s.canRetry }

// Send sends one or more method RPCs to clients specified by the
// slice of endpoint addrs. Arguments for methods are obtained using
// the supplied getArgs function. The number of required replies is
// given by opts.N. Reply structs are obtained through the getReply()
// function. On success, Send returns a slice of replies of length
// opts.N. Otherwise, Send returns an error if and as soon as the
// number of failed RPCs exceeds the available endpoints less the
// number of required replies.
func Send(opts Options, method string, addrs []net.Addr, getArgs func(addr net.Addr) interface{},
	getReply func() interface{}, context *Context) ([]interface{}, error) {

	// Return error if provided addrs is less. modified by joezxy 2015/03/07
	if len(addrs) < opts.N {
		return nil, SendError{
			errMsg:   fmt.Sprintf("insufficient replicas (%d) to satisfy send request of %d", len(addrs), opts.N),
			canRetry: false,
		}
	}

	var clients []*Client
	switch opts.Ordering {
	case OrderStable:
		for _, addr := range addrs {
			clients = append(clients, NewClient(addr, nil, context))
		}
	case OrderRandom:
		// Randomly permute order, but keep known-unhealthy clients last.
		var healthy, unhealthy []*Client
		for _, addr := range addrs {
			client := NewClient(addr, nil, context)
			if client.IsHealthy() {
				healthy = append(healthy, client)
			} else {
				unhealthy = append(unhealthy, client)
			}
		}
		for _, idx := range rand.Perm(len(healthy)) {
			clients = append(clients, healthy[idx])
		}
		for _, idx := range rand.Perm(len(unhealthy)) {
			clients = append(clients, unhealthy[idx])
		}
	}
	// TODO(spencer): going to need to also sort by affinity; closest
	// ping time should win. Makes sense to have the rpc client/server
	// heartbeat measure ping times. With a bit of seasoning, each
	// node will be able to order the healthy replicas based on latency.

	replies := []interface{}(nil)
	helperChan := make(chan interface{}, len(clients))
	N := opts.N
	errors := 0
	retryableErrors := 0
	successes := 0
	index := 0

	// Send RPCs to replicas as necessary to achieve opts.N successes.
	for {
		// Start clients up to N.
		for ; index < N; index++ {
			args := getArgs(clients[index].Addr())
			if args == nil {
				helperChan <- util.Errorf("nil arguments returned for client %s", clients[index].Addr())
				continue
			}
			reply := getReply()
			if log.V(1) {
				log.Infof("%s: sending request to %s: %+v", method, clients[index].Addr(), args)
			}
			go sendOne(clients[index], opts.Timeout, method, args, reply, helperChan)
		}
		// Wait for completions.
		select {
		case r := <-helperChan:
			switch t := r.(type) {
			case error:
				errors++
				if retryErr, ok := t.(util.Retryable); ok && retryErr.CanRetry() {
					retryableErrors++
				}
				if log.V(1) {
					log.Warningf("%s: error reply: %+v", method, t)
				}
				remainingRPCs := len(clients) - errors
				if remainingRPCs < opts.N {
					return nil, SendError{
						errMsg:   fmt.Sprintf("too many errors encountered (%d of %d total): %v", errors, len(clients), t),
						canRetry: retryableErrors+remainingRPCs > len(clients),
					}
				}
				// Send to additional replicas if available.
				if N < len(clients) {
					N++
				}
			default:
				successes++
				if log.V(1) {
					log.Infof("%s: successful reply: %+v", method, t)
				}
				replies = append(replies, t)
				if successes == opts.N {
					return replies, nil
				}
			}
		case <-time.After(opts.SendNextTimeout):
			// On successive RPC timeouts, send to additional replicas if available.
			if N < len(clients) {
				N++
			}
		}
	}
}

// sendOne invokes the specified RPC on the supplied client when the
// client is ready. On success, the reply is sent on the channel;
// otherwise an error is sent.
func sendOne(client *Client, timeout time.Duration, method string, args, reply interface{}, c chan interface{}) {
	<-client.Ready
	call := client.Go(method, args, reply, nil)
	select {
	case <-call.Done:
		if call.Error != nil {
			// Handle cases which are retryable.
			switch call.Error {
			case rpc.ErrShutdown: // client connection fails: rpc/client.go
				fallthrough
			case io.ErrUnexpectedEOF: // server connection fails: rpc/client.go
				c <- rpcError{call.Error.Error()}
			default:
				// Otherwise, not retryable; just return error.
				c <- call.Error
			}
		} else {
			// Verify response data integrity if this is a proto response.
			if resp, ok := reply.(proto.Response); ok {
				if req, ok := args.(proto.Request); ok {
					if err := resp.Verify(req); err != nil {
						c <- err
						return
					}
				}
			}
			c <- reply
		}
	case <-client.Closed:
		c <- rpcError{fmt.Sprintf("rpc to %s failed as client connection was closed", method)}
	case <-time.After(timeout):
		c <- rpcError{fmt.Sprintf("rpc to %s timed out after %s", method, timeout)}
	}
}
<|endoftext|>


<commit_before><commit_msg>防止传递空指针进入,引起程序崩溃<commit_after><|endoftext|>


<commit_before>package fosite

import "github.com/go-errors/errors"

var (
	ErrInvalidRequest          = errors.New("The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed")
	ErrUnauthorizedClient      = errors.New("The client is not authorized to request a token using this method")
	ErrAccessDenied            = errors.New("The resource owner or authorization server denied the request")
	ErrUnsupportedResponseType = errors.New("The authorization server does not support obtaining a token using this method")
	ErrInvalidScope            = errors.New("The requested scope is invalid, unknown, or malformed")
	ErrServerError             = errors.New("The authorization server encountered an unexpected condition that prevented it from fulfilling the request")
	ErrTemporarilyUnavailable  = errors.New("The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server")
	ErrUnsupportedGrantType    = errors.New("The authorization grant type is not supported by the authorization server")
	ErrInvalidGrant            = errors.New("The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client")
	ErrInvalidClient           = errors.New("Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)")
	ErrInvalidState            = errors.Errorf("The state is missing or has less than %d characters and is therefore considered too weak", minStateLength)
)

const (
	errInvalidRequestName          = "invalid_request"
	errUnauthorizedClientName      = "unauthorized_client"
	errAccessDeniedName            = "acccess_denied"
	errUnsupportedResponseTypeName = "unsupported_response_type"
	errInvalidScopeName            = "invalid_scope"
	errServerErrorName             = "server_error"
	errTemporarilyUnavailableName  = "errTemporarilyUnavailableName"
	errUnsupportedGrantTypeName    = "unsupported_grant_type"
	errInvalidGrantName            = "invalid_grant"
	errInvalidClientName           = "invalid_client"
	errInvalidError                = "invalid_error"
	errInvalidState                = "invalid_state"
)

type RFC6749Error struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Hint        string `json:"-"`
}

func ErrorToRFC6749Error(err error) *RFC6749Error {
	ge, ok := err.(*errors.Error)
	if !ok {
		return &RFC6749Error{
			Name:        errInvalidError,
			Description: "The error is unrecognizable.",
			Hint:        err.Error(),
		}
	}
	if errors.Is(ge, ErrInvalidRequest) {
		return &RFC6749Error{
			Name:        errInvalidRequestName,
			Description: ge.Error(),
			Hint:        "Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified.",
		}
	} else if errors.Is(ge, ErrUnauthorizedClient) {
		return &RFC6749Error{
			Name:        errUnauthorizedClientName,
			Description: ge.Error(),
			Hint:        "Make sure that client id and secret are correctly specified and that the client exists.",
		}
	} else if errors.Is(ge, ErrAccessDenied) {
		return &RFC6749Error{
			Name:        errAccessDeniedName,
			Description: ge.Error(),
			Hint:        "Make sure that the request you are making is valid. Maybe the credential or request parameters you are using are limited in scope or otherwise restricted.",
		}
	} else if errors.Is(ge, ErrUnsupportedResponseType) {
		return &RFC6749Error{
			Name:        errUnsupportedResponseTypeName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrInvalidScope) {
		return &RFC6749Error{
			Name:        errInvalidScopeName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrServerError) {
		return &RFC6749Error{
			Name:        errServerErrorName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrTemporarilyUnavailable) {
		return &RFC6749Error{
			Name:        errTemporarilyUnavailableName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrUnsupportedGrantType) {
		return &RFC6749Error{
			Name:        errUnsupportedGrantTypeName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrInvalidGrant) {
		return &RFC6749Error{
			Name:        errInvalidGrantName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrInvalidClient) {
		return &RFC6749Error{
			Name:        errInvalidClientName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrInvalidState) {
		return &RFC6749Error{
			Name:        errInvalidState,
			Description: ge.Error(),
		}
	}
	return &RFC6749Error{
		Name:        errInvalidError,
		Description: "The error is unrecognizable.",
		Hint:        ge.Error(),
	}
}
<commit_msg>errors: fixed wrongfully set constant ErrTemporaryUnvailableName<commit_after>package fosite

import "github.com/go-errors/errors"

var (
	ErrInvalidRequest          = errors.New("The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed")
	ErrUnauthorizedClient      = errors.New("The client is not authorized to request a token using this method")
	ErrAccessDenied            = errors.New("The resource owner or authorization server denied the request")
	ErrUnsupportedResponseType = errors.New("The authorization server does not support obtaining a token using this method")
	ErrInvalidScope            = errors.New("The requested scope is invalid, unknown, or malformed")
	ErrServerError             = errors.New("The authorization server encountered an unexpected condition that prevented it from fulfilling the request")
	ErrTemporarilyUnavailable  = errors.New("The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server")
	ErrUnsupportedGrantType    = errors.New("The authorization grant type is not supported by the authorization server")
	ErrInvalidGrant            = errors.New("The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client")
	ErrInvalidClient           = errors.New("Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)")
	ErrInvalidState            = errors.Errorf("The state is missing or has less than %d characters and is therefore considered too weak", minStateLength)
)

const (
	errInvalidRequestName          = "invalid_request"
	errUnauthorizedClientName      = "unauthorized_client"
	errAccessDeniedName            = "acccess_denied"
	errUnsupportedResponseTypeName = "unsupported_response_type"
	errInvalidScopeName            = "invalid_scope"
	errServerErrorName             = "server_error"
	errTemporarilyUnavailableName  = "temporarily_unavailable"
	errUnsupportedGrantTypeName    = "unsupported_grant_type"
	errInvalidGrantName            = "invalid_grant"
	errInvalidClientName           = "invalid_client"
	errInvalidError                = "invalid_error"
	errInvalidState                = "invalid_state"
)

type RFC6749Error struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Hint        string `json:"-"`
}

func ErrorToRFC6749Error(err error) *RFC6749Error {
	ge, ok := err.(*errors.Error)
	if !ok {
		return &RFC6749Error{
			Name:        errInvalidError,
			Description: "The error is unrecognizable.",
			Hint:        err.Error(),
		}
	}
	if errors.Is(ge, ErrInvalidRequest) {
		return &RFC6749Error{
			Name:        errInvalidRequestName,
			Description: ge.Error(),
			Hint:        "Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified.",
		}
	} else if errors.Is(ge, ErrUnauthorizedClient) {
		return &RFC6749Error{
			Name:        errUnauthorizedClientName,
			Description: ge.Error(),
			Hint:        "Make sure that client id and secret are correctly specified and that the client exists.",
		}
	} else if errors.Is(ge, ErrAccessDenied) {
		return &RFC6749Error{
			Name:        errAccessDeniedName,
			Description: ge.Error(),
			Hint:        "Make sure that the request you are making is valid. Maybe the credential or request parameters you are using are limited in scope or otherwise restricted.",
		}
	} else if errors.Is(ge, ErrUnsupportedResponseType) {
		return &RFC6749Error{
			Name:        errUnsupportedResponseTypeName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrInvalidScope) {
		return &RFC6749Error{
			Name:        errInvalidScopeName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrServerError) {
		return &RFC6749Error{
			Name:        errServerErrorName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrTemporarilyUnavailable) {
		return &RFC6749Error{
			Name:        errTemporarilyUnavailableName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrUnsupportedGrantType) {
		return &RFC6749Error{
			Name:        errUnsupportedGrantTypeName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrInvalidGrant) {
		return &RFC6749Error{
			Name:        errInvalidGrantName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrInvalidClient) {
		return &RFC6749Error{
			Name:        errInvalidClientName,
			Description: ge.Error(),
		}
	} else if errors.Is(ge, ErrInvalidState) {
		return &RFC6749Error{
			Name:        errInvalidState,
			Description: ge.Error(),
		}
	}
	return &RFC6749Error{
		Name:        errInvalidError,
		Description: "The error is unrecognizable.",
		Hint:        ge.Error(),
	}
}
<|endoftext|>


<commit_before>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package optimize

import (
	"errors"
	"fmt"
)

var (
	// ErrInf signifies the initial function value is Inf.
	ErrInf = errors.New("optimize: initial function value is Inf")

	// ErrGradInf signifies the initial function value is Inf.
	ErrGradInf = errors.New("optimize: initial gradient is Inf")

	// ErrLinesearchFailure signifies the linesearch has iterated too many
	// times. This may occur if the gradient tolerance is set too low.
	ErrLinesearchFailure = errors.New("linesearch: failed to converge")

	// ErrNaN signifies the initial function value is NaN.
	ErrNaN = errors.New("optimize: initial function value is NaN")

	// ErrGradNaN signifies the initial function value is NaN.
	ErrGradNaN = errors.New("optimize: initial gradient is NaN")

	// ErrNonNegativeStepDirection signifies that the linesearch has received a
	// step direction in which the gradient is not negative.
	ErrNonNegativeStepDirection = errors.New("linesearch: projected gradient not negative")

	// ErrZeroDimensional signifies an optimization was called with an input of length 0.
	ErrZeroDimensional = errors.New("optimize: zero dimensional input")

	// ErrNoProgress signifies that Linesearch cannot make further progress
	// because there is no change in location after LinesearchMethod step due
	// to floating-point arithmetic.
	ErrNoProgress = errors.New("linesearch: no change in location after linesearch step")
)

// ErrMismatch signifies that the optimization function did not implement the
// interfaces necessary for the supplied optimization method.
type ErrMismatch struct {
	Type EvaluationType
}

func (e ErrMismatch) Error() string {
	return fmt.Sprintf("optimizer wanted to use evaluation type %v, but the user supplied function does not implement it", e.Type)
}
<commit_msg>optimize: delete ErrMismatch<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package optimize

import "errors"

var (
	// ErrInf signifies the initial function value is Inf.
	ErrInf = errors.New("optimize: initial function value is Inf")

	// ErrGradInf signifies the initial function value is Inf.
	ErrGradInf = errors.New("optimize: initial gradient is Inf")

	// ErrLinesearchFailure signifies the linesearch has iterated too many
	// times. This may occur if the gradient tolerance is set too low.
	ErrLinesearchFailure = errors.New("linesearch: failed to converge")

	// ErrNaN signifies the initial function value is NaN.
	ErrNaN = errors.New("optimize: initial function value is NaN")

	// ErrGradNaN signifies the initial function value is NaN.
	ErrGradNaN = errors.New("optimize: initial gradient is NaN")

	// ErrNonNegativeStepDirection signifies that the linesearch has received a
	// step direction in which the gradient is not negative.
	ErrNonNegativeStepDirection = errors.New("linesearch: projected gradient not negative")

	// ErrZeroDimensional signifies an optimization was called with an input of length 0.
	ErrZeroDimensional = errors.New("optimize: zero dimensional input")

	// ErrNoProgress signifies that Linesearch cannot make further progress
	// because there is no change in location after LinesearchMethod step due
	// to floating-point arithmetic.
	ErrNoProgress = errors.New("linesearch: no change in location after linesearch step")
)
<|endoftext|>