<commit_before>package environment

import (
	"fmt"
	authclient "github.com/fabric8-services/fabric8-tenant/auth/client"
	"github.com/fabric8-services/fabric8-tenant/configuration"
	"github.com/fabric8-services/fabric8-tenant/keycloak"
	"gopkg.in/yaml.v2"
	"regexp"
	"strings"
)

const (
	FieldKind            = "kind"
	FieldAPIVersion      = "apiVersion"
	FieldObjects         = "objects"
	FieldSpec            = "spec"
	FieldTemplate        = "templateDef"
	FieldItems           = "items"
	FieldMetadata        = "metadata"
	FieldLabels          = "labels"
	FieldReplicas        = "replicas"
	FieldVersion         = "version"
	FieldNamespace       = "namespace"
	FieldName            = "name"
	FieldStatus          = "status"
	FieldResourceVersion = "resourceVersion"
	FieldParameters      = "parameters"

	ValKindTemplate               = "Template"
	ValKindNamespace              = "Namespace"
	ValKindConfigMap              = "ConfigMap"
	ValKindLimitRange             = "LimitRange"
	ValKindProject                = "Project"
	ValKindProjectRequest         = "ProjectRequest"
	ValKindPersistenceVolumeClaim = "PersistentVolumeClaim"
	ValKindService                = "Service"
	ValKindSecret                 = "Secret"
	ValKindServiceAccount         = "ServiceAccount"
	ValKindRoleBindingRestriction = "RoleBindingRestriction"
	ValKindRoleBinding            = "RoleBinding"
	ValKindRoute                  = "Route"
	ValKindJob                    = "Job"
	ValKindList                   = "List"
	ValKindDeployment             = "Deployment"
	ValKindDeploymentConfig       = "DeploymentConfig"
	ValKindResourceQuota          = "ResourceQuota"

	varUserName              = "USER_NAME"
	varProjectUser           = "PROJECT_USER"
	varProjectRequestingUser = "PROJECT_REQUESTING_USER"
	varProjectAdminUser      = "PROJECT_ADMIN_USER"
	varKeycloakURL           = "KEYCLOAK_URL"
	varCommit                = "COMMIT"
	varDeployType            = "DEPLOY_TYPE"
	varKeycloakOsoEndpoint   = "KEYCLOAK_OSO_ENDPOINT"
	varKeycloakGHEndpoint    = "KEYCLOAK_GITHUB_ENDPOINT"
)

var sortOrder = map[string]int{
	"Namespace":              1,
	"ProjectRequest":         1,
	"RoleBindingRestriction": 2,
	"LimitRange":             3,
	"ResourceQuota":          4,
	"Secret":                 5,
	"ServiceAccount":         6,
	"Service":                7,
	"RoleBinding":            8,
	"PersistentVolumeClaim":  9,
	"ConfigMap":              10,
	"DeploymentConfig":       11,
	"Route":                  12,
	"Job":                    13,
}

type Objects []map[interface{}]interface{}
type Object map[interface{}]interface{}

type Template struct {
	Filename      string
	DefaultParams map[string]string
	Content       string
	Version       string
}

var (
	specialCharRegexp = regexp.MustCompile("[^a-z0-9]")
	variableRegexp    = regexp.MustCompile(`\${([A-Z_0-9]+)}`)
)

func newTemplate(filename string, defaultParams map[string]string) *Template {
	return &Template{
		Filename:      filename,
		DefaultParams: defaultParams,
	}
}

func (t *Template) Process(vars map[string]string) (Objects, error) {
	var objects Objects
	templateVars := merge(vars, t.DefaultParams)
	paramsFromTemplate, err := t.getParamsFromTemplate()
	if err != nil {
		return objects, err
	}
	if paramsFromTemplate != nil {
		templateVars = merge(paramsFromTemplate, templateVars)
	}
	pt, err := t.ReplaceVars(templateVars)
	if err != nil {
		return objects, err
	}
	t.Version = vars[varCommit]
	return ParseObjects(pt)
}

func (t *Template) getParamsFromTemplate() (map[string]string, error) {
	var template Object

	err := yaml.Unmarshal([]byte(t.Content), &template)
	if err != nil {
		return nil, err
	}
	if paramsPart, exist := template[FieldParameters]; exist {
		templateParams := make(map[string]string)
		if params, ok := paramsPart.([]interface{}); ok {
			for _, paramObj := range params {
				if param, ok := paramObj.(Object); ok {
					if name, exist := param["name"]; exist {
						if value, exist := param["value"]; exist {
							templateParams[fmt.Sprint(name)] = fmt.Sprint(value)
						}
					}
				}
			}
			return templateParams, nil
		}
	}
	return nil, nil
}

// Process takes a K8/Openshift Template as input and resolves the variable expresions
func (t *Template) ReplaceVars(variables map[string]string) (string, error) {
	return string(variableRegexp.ReplaceAllFunc([]byte(t.Content), func(found []byte) []byte {
		variableName := toVariableName(string(found))
		if variable, ok := variables[variableName]; ok {
			return []byte(variable)
		}
		return found
	})), nil
}

func CollectVars(user, masterUser string, config *configuration.Data) map[string]string {
	userName := RetrieveUserName(user)

	vars := map[string]string{
		varUserName:              userName,
		varProjectUser:           user,
		varProjectRequestingUser: user,
		varProjectAdminUser:      masterUser,
	}

	return merge(vars, getVariables(config))
}

// RetrieveUserName returns a safe namespace basename based on a username
func RetrieveUserName(openshiftUsername string) string {
	return specialCharRegexp.ReplaceAllString(strings.Split(openshiftUsername, "@")[0], "-")
}

func getVariables(config *configuration.Data) map[string]string {
	keycloakConfig := keycloak.Config{
		BaseURL: config.GetKeycloakURL(),
		Realm:   config.GetKeycloakRealm(),
		Broker:  config.GetKeycloakOpenshiftBroker(),
	}

	templateVars, err := config.GetTemplateValues()
	if err != nil {
		panic(err)
	}
	templateVars[varKeycloakURL] = ""
	templateVars[varKeycloakOsoEndpoint] = keycloakConfig.CustomBrokerTokenURL("openshift-v3")
	templateVars[varKeycloakGHEndpoint] = fmt.Sprintf("%s%s?for=https://github.com", config.GetAuthURL(), authclient.RetrieveTokenPath())

	return templateVars
}

func merge(target, second map[string]string) map[string]string {
	if len(second) == 0 {
		return target
	}
	result := clone(second)
	for k, v := range target {
		if _, exist := result[k]; !exist {
			result[k] = v
		}
	}
	return result
}

func clone(maps map[string]string) map[string]string {
	maps2 := make(map[string]string)
	for k2, v2 := range maps {
		maps2[k2] = v2
	}
	return maps2
}

func toVariableName(exp string) string {
	return exp[:len(exp)-1][2:]
}

// ParseObjects return a string yaml and return a array of the objects/items from a Template/List kind
func ParseObjects(source string) (Objects, error) {
	var template Object

	err := yaml.Unmarshal([]byte(source), &template)
	if err != nil {
		return nil, err
	}

	if GetKind(template) == ValKindTemplate || GetKind(template) == ValKindList {
		var ts []interface{}
		if GetKind(template) == ValKindTemplate {
			ts = template[FieldObjects].([]interface{})
		} else if GetKind(template) == ValKindList {
			ts = template[FieldItems].([]interface{})
		}
		var objs Objects
		for _, obj := range ts {
			parsedObj := obj.(Object)
			stringKeys := make(Object, len(parsedObj))
			for key, value := range parsedObj {
				stringKeys[key.(string)] = value
			}
			objs = append(objs, stringKeys)
		}
		return objs, nil
	}

	return Objects{template}, nil
}

func GetName(obj Object) string {
	if meta, metaFound := obj[FieldMetadata].(Object); metaFound {
		if name, nameFound := meta[FieldName].(string); nameFound {
			return name
		}
	}
	return ""
}

func GetNamespace(obj Object) string {
	if meta, metaFound := obj[FieldMetadata].(Object); metaFound {
		if name, nameFound := meta[FieldNamespace].(string); nameFound {
			return name
		}
	}
	return ""
}

func GetKind(obj Object) string {
	if kind, kindFound := obj[FieldKind].(string); kindFound {
		return kind
	}
	return ""
}

func HasValidStatus(obj Object) bool {
	return len(GetStatus(obj)) > 0
}

func GetStatus(obj Object) Object {
	if status, statusFound := obj[FieldStatus].(Object); statusFound {
		return status
	}
	return nil
}

func GetLabelVersion(obj Object) string {
	return GetLabel(obj, FieldVersion)
}

func GetLabel(obj Object, name string) string {
	if meta, metaFound := obj[FieldMetadata].(Object); metaFound {
		if labels, labelsFound := meta[FieldLabels].(Object); labelsFound {
			if label, labelFound := labels[name]; labelFound {
				return fmt.Sprint(label)
			}
		}
	}
	return ""
}

// ByKind represents a list of Openshift objects sortable by Kind
type ByKind Objects

func (a ByKind) Len() int      { return len(a) }
func (a ByKind) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByKind) Less(i, j int) bool {
	iO := 30
	jO := 30

	if val, ok := sortOrder[GetKind(a[i])]; ok {
		iO = val
	}
	if val, ok := sortOrder[GetKind(a[j])]; ok {
		jO = val
	}
	return iO < jO
}
<commit_msg>Sort Role before RoleBindingX (#656)<commit_after>package environment

import (
	"fmt"
	"regexp"
	"strings"

	authclient "github.com/fabric8-services/fabric8-tenant/auth/client"
	"github.com/fabric8-services/fabric8-tenant/configuration"
	"github.com/fabric8-services/fabric8-tenant/keycloak"
	"gopkg.in/yaml.v2"
)

const (
	FieldKind            = "kind"
	FieldAPIVersion      = "apiVersion"
	FieldObjects         = "objects"
	FieldSpec            = "spec"
	FieldTemplate        = "templateDef"
	FieldItems           = "items"
	FieldMetadata        = "metadata"
	FieldLabels          = "labels"
	FieldReplicas        = "replicas"
	FieldVersion         = "version"
	FieldNamespace       = "namespace"
	FieldName            = "name"
	FieldStatus          = "status"
	FieldResourceVersion = "resourceVersion"
	FieldParameters      = "parameters"

	ValKindTemplate               = "Template"
	ValKindNamespace              = "Namespace"
	ValKindConfigMap              = "ConfigMap"
	ValKindLimitRange             = "LimitRange"
	ValKindProject                = "Project"
	ValKindProjectRequest         = "ProjectRequest"
	ValKindPersistenceVolumeClaim = "PersistentVolumeClaim"
	ValKindService                = "Service"
	ValKindSecret                 = "Secret"
	ValKindServiceAccount         = "ServiceAccount"
	ValKindRoleBindingRestriction = "RoleBindingRestriction"
	ValKindRoleBinding            = "RoleBinding"
	ValKindRoute                  = "Route"
	ValKindJob                    = "Job"
	ValKindList                   = "List"
	ValKindDeployment             = "Deployment"
	ValKindDeploymentConfig       = "DeploymentConfig"
	ValKindResourceQuota          = "ResourceQuota"

	varUserName              = "USER_NAME"
	varProjectUser           = "PROJECT_USER"
	varProjectRequestingUser = "PROJECT_REQUESTING_USER"
	varProjectAdminUser      = "PROJECT_ADMIN_USER"
	varKeycloakURL           = "KEYCLOAK_URL"
	varCommit                = "COMMIT"
	varDeployType            = "DEPLOY_TYPE"
	varKeycloakOsoEndpoint   = "KEYCLOAK_OSO_ENDPOINT"
	varKeycloakGHEndpoint    = "KEYCLOAK_GITHUB_ENDPOINT"
)

var sortOrder = map[string]int{
	"Namespace":      1,
	"ProjectRequest": 1,
	"Role":           2,
	"RoleBindingRestriction": 3,
	"LimitRange":             4,
	"ResourceQuota":          5,
	"Secret":                 6,
	"ServiceAccount":         7,
	"Service":                8,
	"RoleBinding":            9,
	"PersistentVolumeClaim":  10,
	"ConfigMap":              11,
	"DeploymentConfig":       12,
	"Route":                  13,
	"Job":                    14,
}

type Objects []map[interface{}]interface{}
type Object map[interface{}]interface{}

type Template struct {
	Filename      string
	DefaultParams map[string]string
	Content       string
	Version       string
}

var (
	specialCharRegexp = regexp.MustCompile("[^a-z0-9]")
	variableRegexp    = regexp.MustCompile(`\${([A-Z_0-9]+)}`)
)

func newTemplate(filename string, defaultParams map[string]string) *Template {
	return &Template{
		Filename:      filename,
		DefaultParams: defaultParams,
	}
}

func (t *Template) Process(vars map[string]string) (Objects, error) {
	var objects Objects
	templateVars := merge(vars, t.DefaultParams)
	paramsFromTemplate, err := t.getParamsFromTemplate()
	if err != nil {
		return objects, err
	}
	if paramsFromTemplate != nil {
		templateVars = merge(paramsFromTemplate, templateVars)
	}
	pt, err := t.ReplaceVars(templateVars)
	if err != nil {
		return objects, err
	}
	t.Version = vars[varCommit]
	return ParseObjects(pt)
}

func (t *Template) getParamsFromTemplate() (map[string]string, error) {
	var template Object

	err := yaml.Unmarshal([]byte(t.Content), &template)
	if err != nil {
		return nil, err
	}
	if paramsPart, exist := template[FieldParameters]; exist {
		templateParams := make(map[string]string)
		if params, ok := paramsPart.([]interface{}); ok {
			for _, paramObj := range params {
				if param, ok := paramObj.(Object); ok {
					if name, exist := param["name"]; exist {
						if value, exist := param["value"]; exist {
							templateParams[fmt.Sprint(name)] = fmt.Sprint(value)
						}
					}
				}
			}
			return templateParams, nil
		}
	}
	return nil, nil
}

// Process takes a K8/Openshift Template as input and resolves the variable expresions
func (t *Template) ReplaceVars(variables map[string]string) (string, error) {
	return string(variableRegexp.ReplaceAllFunc([]byte(t.Content), func(found []byte) []byte {
		variableName := toVariableName(string(found))
		if variable, ok := variables[variableName]; ok {
			return []byte(variable)
		}
		return found
	})), nil
}

func CollectVars(user, masterUser string, config *configuration.Data) map[string]string {
	userName := RetrieveUserName(user)

	vars := map[string]string{
		varUserName:              userName,
		varProjectUser:           user,
		varProjectRequestingUser: user,
		varProjectAdminUser:      masterUser,
	}

	return merge(vars, getVariables(config))
}

// RetrieveUserName returns a safe namespace basename based on a username
func RetrieveUserName(openshiftUsername string) string {
	return specialCharRegexp.ReplaceAllString(strings.Split(openshiftUsername, "@")[0], "-")
}

func getVariables(config *configuration.Data) map[string]string {
	keycloakConfig := keycloak.Config{
		BaseURL: config.GetKeycloakURL(),
		Realm:   config.GetKeycloakRealm(),
		Broker:  config.GetKeycloakOpenshiftBroker(),
	}

	templateVars, err := config.GetTemplateValues()
	if err != nil {
		panic(err)
	}
	templateVars[varKeycloakURL] = ""
	templateVars[varKeycloakOsoEndpoint] = keycloakConfig.CustomBrokerTokenURL("openshift-v3")
	templateVars[varKeycloakGHEndpoint] = fmt.Sprintf("%s%s?for=https://github.com", config.GetAuthURL(), authclient.RetrieveTokenPath())

	return templateVars
}

func merge(target, second map[string]string) map[string]string {
	if len(second) == 0 {
		return target
	}
	result := clone(second)
	for k, v := range target {
		if _, exist := result[k]; !exist {
			result[k] = v
		}
	}
	return result
}

func clone(maps map[string]string) map[string]string {
	maps2 := make(map[string]string)
	for k2, v2 := range maps {
		maps2[k2] = v2
	}
	return maps2
}

func toVariableName(exp string) string {
	return exp[:len(exp)-1][2:]
}

// ParseObjects return a string yaml and return a array of the objects/items from a Template/List kind
func ParseObjects(source string) (Objects, error) {
	var template Object

	err := yaml.Unmarshal([]byte(source), &template)
	if err != nil {
		return nil, err
	}

	if GetKind(template) == ValKindTemplate || GetKind(template) == ValKindList {
		var ts []interface{}
		if GetKind(template) == ValKindTemplate {
			ts = template[FieldObjects].([]interface{})
		} else if GetKind(template) == ValKindList {
			ts = template[FieldItems].([]interface{})
		}
		var objs Objects
		for _, obj := range ts {
			parsedObj := obj.(Object)
			stringKeys := make(Object, len(parsedObj))
			for key, value := range parsedObj {
				stringKeys[key.(string)] = value
			}
			objs = append(objs, stringKeys)
		}
		return objs, nil
	}

	return Objects{template}, nil
}

func GetName(obj Object) string {
	if meta, metaFound := obj[FieldMetadata].(Object); metaFound {
		if name, nameFound := meta[FieldName].(string); nameFound {
			return name
		}
	}
	return ""
}

func GetNamespace(obj Object) string {
	if meta, metaFound := obj[FieldMetadata].(Object); metaFound {
		if name, nameFound := meta[FieldNamespace].(string); nameFound {
			return name
		}
	}
	return ""
}

func GetKind(obj Object) string {
	if kind, kindFound := obj[FieldKind].(string); kindFound {
		return kind
	}
	return ""
}

func HasValidStatus(obj Object) bool {
	return len(GetStatus(obj)) > 0
}

func GetStatus(obj Object) Object {
	if status, statusFound := obj[FieldStatus].(Object); statusFound {
		return status
	}
	return nil
}

func GetLabelVersion(obj Object) string {
	return GetLabel(obj, FieldVersion)
}

func GetLabel(obj Object, name string) string {
	if meta, metaFound := obj[FieldMetadata].(Object); metaFound {
		if labels, labelsFound := meta[FieldLabels].(Object); labelsFound {
			if label, labelFound := labels[name]; labelFound {
				return fmt.Sprint(label)
			}
		}
	}
	return ""
}

// ByKind represents a list of Openshift objects sortable by Kind
type ByKind Objects

func (a ByKind) Len() int      { return len(a) }
func (a ByKind) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByKind) Less(i, j int) bool {
	iO := 30
	jO := 30

	if val, ok := sortOrder[GetKind(a[i])]; ok {
		iO = val
	}
	if val, ok := sortOrder[GetKind(a[j])]; ok {
		jO = val
	}
	return iO < jO
}
<|endoftext|>


<commit_before>package amqp

import (
	"fmt"
	"github.com/RichardKnop/machinery/v1/brokers/iface"
	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/tasks"
	"github.com/streadway/amqp"
	"testing"
)

type doNothingProcessor struct {}
func (_ doNothingProcessor) Process(signature *tasks.Signature) error {
	return fmt.Errorf("failed")
}

func (_ doNothingProcessor) CustomQueue() string {
	return "oops"
}

func TestConsume(t *testing.T) {
	var (
		iBroker iface.Broker
		deliveries = make(chan amqp.Delivery, 3)
		closeChan chan *amqp.Error
		processor doNothingProcessor
	)

	t.Run("with deliveries more than the number of concurrency", func(t *testing.T) {
		iBroker = New(&config.Config{})
		broker, _ := iBroker.(*Broker)

		// simulate that there are too much deliveries
		go func() {
			for i := 0; i < 3; i++  {
				deliveries <- amqp.Delivery{} // broker.consumeOne() will complain this error: Received an empty message
			}
		}()

		broker.consume(deliveries, 2, processor, closeChan)
	})
}<commit_msg>test: make sure the test case can be terminated<commit_after>package amqp

import (
	"fmt"
	"github.com/RichardKnop/machinery/v1/brokers/iface"
	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/tasks"
	"github.com/streadway/amqp"
	"testing"
	"time"
)

type doNothingProcessor struct {}
func (_ doNothingProcessor) Process(signature *tasks.Signature) error {
	return fmt.Errorf("failed")
}

func (_ doNothingProcessor) CustomQueue() string {
	return "oops"
}

func TestConsume(t *testing.T) {
	var (
		iBroker iface.Broker
		deliveries = make(chan amqp.Delivery, 3)
		closeChan chan *amqp.Error
		processor doNothingProcessor
	)

	t.Run("with deliveries more than the number of concurrency", func(t *testing.T) {
		iBroker = New(&config.Config{})
		broker, _ := iBroker.(*Broker)
		errChan := make(chan error)

		// simulate that there are too much deliveries
		go func() {
			for i := 0; i < 3; i++  {
				deliveries <- amqp.Delivery{} // broker.consumeOne() will complain this error: Received an empty message
			}
		}()

		go func() {
			err := broker.consume(deliveries, 2, processor, closeChan)
			if err != nil {
				errChan <- err
			}
		}()

		select{
		case <- errChan:
		case <- time.After(1 * time.Second):
			t.Error("Maybe deadlock")
		}
	})
}<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/field"
	"github.com/pingcap/tidb/kv"
	mysql "github.com/pingcap/tidb/mysqldef"
	"github.com/pingcap/tidb/rset"
	tidberrors "github.com/pingcap/tidb/util/errors"
	"github.com/pingcap/tidb/util/errors2"
)

// TiDBDriver implements IDriver.
type TiDBDriver struct {
	store kv.Storage
}

// NewTiDBDriver creates a new TiDBDriver.
func NewTiDBDriver(store kv.Storage) *TiDBDriver {
	driver := &TiDBDriver{
		store: store,
	}
	return driver
}

// TiDBContext implements IContext.
type TiDBContext struct {
	session      tidb.Session
	currentDB    string
	warningCount uint16
	stmts        map[int]*TiDBStatement
}

// TiDBStatement implements IStatement.
type TiDBStatement struct {
	id          uint32
	numParams   int
	boundParams [][]byte
	ctx         *TiDBContext
}

// ID implements IStatement ID method.
func (ts *TiDBStatement) ID() int {
	return int(ts.id)
}

// Execute implements IStatement Execute method.
func (ts *TiDBStatement) Execute(args ...interface{}) (rs ResultSet, err error) {
	tidbRecordset, err := ts.ctx.session.ExecutePreparedStmt(ts.id, args...)
	if errors2.ErrorEqual(err, kv.ErrConditionNotMatch) {
		return nil, ts.ctx.session.Retry()
	}
	if err != nil {
		return nil, err
	}
	if tidbRecordset == nil {
		return
	}
	rs = &tidbResultSet{
		recordSet: tidbRecordset,
	}
	return
}

// AppendParam implements IStatement AppendParam method.
func (ts *TiDBStatement) AppendParam(paramID int, data []byte) error {
	if paramID >= len(ts.boundParams) {
		return mysql.NewDefaultError(mysql.ErWrongArguments, "stmt_send_longdata")
	}
	ts.boundParams[paramID] = append(ts.boundParams[paramID], data...)
	return nil
}

// NumParams implements IStatement NumParams method.
func (ts *TiDBStatement) NumParams() int {
	return ts.numParams
}

// BoundParams implements IStatement BoundParams method.
func (ts *TiDBStatement) BoundParams() [][]byte {
	return ts.boundParams
}

// Reset implements IStatement Reset method.
func (ts *TiDBStatement) Reset() {
	for i := range ts.boundParams {
		ts.boundParams[i] = nil
	}
}

// Close implements IStatement Close method.
func (ts *TiDBStatement) Close() error {
	//TODO close at tidb level
	err := ts.ctx.session.DropPreparedStmt(ts.id)
	if err != nil {
		return errors.Trace(err)
	}
	delete(ts.ctx.stmts, int(ts.id))
	return nil
}

// OpenCtx implements IDriver.
func (qd *TiDBDriver) OpenCtx(capability uint32, collation uint8, dbname string) (IContext, error) {
	session, _ := tidb.CreateSession(qd.store)
	session.SetClientCapability(capability)
	if dbname != "" {
		_, err := session.Execute("use " + dbname)
		if err != nil {
			return nil, err
		}
	}
	tc := &TiDBContext{
		session:   session,
		currentDB: dbname,
		stmts:     make(map[int]*TiDBStatement),
	}
	return tc, nil
}

// Status implements IContext Status method.
func (tc *TiDBContext) Status() uint16 {
	return tc.session.Status()
}

// LastInsertID implements IContext LastInsertID method.
func (tc *TiDBContext) LastInsertID() uint64 {
	return tc.session.LastInsertID()
}

// AffectedRows implements IContext AffectedRows method.
func (tc *TiDBContext) AffectedRows() uint64 {
	return tc.session.AffectedRows()
}

// CurrentDB implements IContext CurrentDB method.
func (tc *TiDBContext) CurrentDB() string {
	return tc.currentDB
}

// WarningCount implements IContext WarningCount method.
func (tc *TiDBContext) WarningCount() uint16 {
	return tc.warningCount
}

// Execute implements IContext Execute method.
func (tc *TiDBContext) Execute(sql string) (rs ResultSet, err error) {
	rsList, err := tc.session.Execute(sql)
	if errors2.ErrorEqual(err, kv.ErrConditionNotMatch) {
		return nil, tc.session.Retry()
	}
	if err != nil {
		return
	}
	if len(rsList) == 0 { // result ok
		return
	}
	rs = &tidbResultSet{
		recordSet: rsList[0],
	}
	return
}

// Close implements IContext Close method.
func (tc *TiDBContext) Close() (err error) {
	return tc.session.Close()
}

// FieldList implements IContext FieldList method.
func (tc *TiDBContext) FieldList(table string) (colums []*ColumnInfo, err error) {
	rs, err := tc.Execute("SELECT * FROM " + table + " LIMIT 0")
	if err != nil {
		return nil, errors.Trace(err)
	}
	colums, err = rs.Columns()
	if err != nil {
		return nil, errors.Trace(err)
	}
	return
}

// GetStatement implements IContext GetStatement method.
func (tc *TiDBContext) GetStatement(stmtID int) IStatement {
	tcStmt := tc.stmts[stmtID]
	if tcStmt != nil {
		return tcStmt
	}
	return nil
}

// Prepare implements IContext Prepare method.
func (tc *TiDBContext) Prepare(sql string) (statement IStatement, columns, params []*ColumnInfo, err error) {
	stmtID, paramCount, fields, err := tc.session.PrepareStmt(sql)
	if err != nil {
		return
	}
	stmt := &TiDBStatement{
		id:          stmtID,
		numParams:   paramCount,
		boundParams: make([][]byte, paramCount),
		ctx:         tc,
	}
	statement = stmt
	columns = make([]*ColumnInfo, len(fields))
	for i := range fields {
		columns[i] = convertColumnInfo(fields[i])
	}
	params = make([]*ColumnInfo, paramCount)
	for i := range params {
		params[i] = &ColumnInfo{
			Type: mysql.TypeBlob,
		}
	}
	tc.stmts[int(stmtID)] = stmt
	return
}

type tidbResultSet struct {
	recordSet rset.Recordset
}

func (trs *tidbResultSet) Next() ([]interface{}, error) {
	row, err := trs.recordSet.Next()
	if err != nil {
		return nil, errors.Trace(err)
	}
	if row != nil {
		return row.Data, nil
	}
	return nil, nil
}

func (trs *tidbResultSet) Close() error {
	return trs.recordSet.Close()
}

func (trs *tidbResultSet) Columns() ([]*ColumnInfo, error) {
	fields, err := trs.recordSet.Fields()
	if err != nil {
		return nil, errors.Trace(err)
	}
	var columns []*ColumnInfo
	for _, v := range fields {
		columns = append(columns, convertColumnInfo(v))
	}
	return columns, nil
}

func convertColumnInfo(fld *field.ResultField) (ci *ColumnInfo) {
	ci = new(ColumnInfo)
	ci.Name = fld.Name
	ci.OrgName = fld.ColumnInfo.Name.O
	ci.Table = fld.TableName
	ci.OrgTable = fld.OrgTableName
	ci.Schema = fld.DBName
	ci.Flag = uint16(fld.Flag)
	ci.Charset = uint16(mysql.CharsetIDs[fld.Charset])
	ci.ColumnLength = uint32(fld.Flen)
	ci.Decimal = uint8(fld.Decimal)
	ci.Type = uint8(fld.Tp)
	return
}

// Bootstrap initiates TiDB server.
func Bootstrap(store kv.Storage) {
	td := NewTiDBDriver(store)
	tc, err := td.OpenCtx(defaultCapability, mysql.DefaultCollationID, "")
	defer tc.Close()
	if err != nil {
		log.Fatal(err)
	}
	// Create a test database.
	_, err = tc.Execute("CREATE DATABASE IF NOT EXISTS test")
	if err != nil {
		log.Fatal(err)
	}

	//  Check if mysql db exists.
	_, err = tc.Execute("USE mysql;")
	if err == nil {
		// Already bootstrapeds
		return
	} else if !errors2.ErrorEqual(err, tidberrors.ErrDatabaseNotExist) {
		log.Fatal(err)
	}
	_, err = tc.Execute("CREATE DATABASE mysql;")
	if err != nil {
		log.Fatal(err)
	}
	_, err = tc.Execute("CREATE TABLE mysql.user (Host CHAR(64), User CHAR(16), Password CHAR(41), PRIMARY KEY (Host, User));")
	if err != nil {
		log.Fatal(err)
	}
	// Insert a default user with empty password.
	_, err = tc.Execute(`INSERT INTO mysql.user VALUES ("localhost", "root", ""), ("127.0.0.1", "root", "");`)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>tidb-server: Address comment<commit_after>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/field"
	"github.com/pingcap/tidb/kv"
	mysql "github.com/pingcap/tidb/mysqldef"
	"github.com/pingcap/tidb/rset"
	tidberrors "github.com/pingcap/tidb/util/errors"
	"github.com/pingcap/tidb/util/errors2"
)

// TiDBDriver implements IDriver.
type TiDBDriver struct {
	store kv.Storage
}

// NewTiDBDriver creates a new TiDBDriver.
func NewTiDBDriver(store kv.Storage) *TiDBDriver {
	driver := &TiDBDriver{
		store: store,
	}
	return driver
}

// TiDBContext implements IContext.
type TiDBContext struct {
	session      tidb.Session
	currentDB    string
	warningCount uint16
	stmts        map[int]*TiDBStatement
}

// TiDBStatement implements IStatement.
type TiDBStatement struct {
	id          uint32
	numParams   int
	boundParams [][]byte
	ctx         *TiDBContext
}

// ID implements IStatement ID method.
func (ts *TiDBStatement) ID() int {
	return int(ts.id)
}

// Execute implements IStatement Execute method.
func (ts *TiDBStatement) Execute(args ...interface{}) (rs ResultSet, err error) {
	tidbRecordset, err := ts.ctx.session.ExecutePreparedStmt(ts.id, args...)
	if errors2.ErrorEqual(err, kv.ErrConditionNotMatch) {
		return nil, ts.ctx.session.Retry()
	}
	if err != nil {
		return nil, err
	}
	if tidbRecordset == nil {
		return
	}
	rs = &tidbResultSet{
		recordSet: tidbRecordset,
	}
	return
}

// AppendParam implements IStatement AppendParam method.
func (ts *TiDBStatement) AppendParam(paramID int, data []byte) error {
	if paramID >= len(ts.boundParams) {
		return mysql.NewDefaultError(mysql.ErWrongArguments, "stmt_send_longdata")
	}
	ts.boundParams[paramID] = append(ts.boundParams[paramID], data...)
	return nil
}

// NumParams implements IStatement NumParams method.
func (ts *TiDBStatement) NumParams() int {
	return ts.numParams
}

// BoundParams implements IStatement BoundParams method.
func (ts *TiDBStatement) BoundParams() [][]byte {
	return ts.boundParams
}

// Reset implements IStatement Reset method.
func (ts *TiDBStatement) Reset() {
	for i := range ts.boundParams {
		ts.boundParams[i] = nil
	}
}

// Close implements IStatement Close method.
func (ts *TiDBStatement) Close() error {
	//TODO close at tidb level
	err := ts.ctx.session.DropPreparedStmt(ts.id)
	if err != nil {
		return errors.Trace(err)
	}
	delete(ts.ctx.stmts, int(ts.id))
	return nil
}

// OpenCtx implements IDriver.
func (qd *TiDBDriver) OpenCtx(capability uint32, collation uint8, dbname string) (IContext, error) {
	session, _ := tidb.CreateSession(qd.store)
	session.SetClientCapability(capability)
	if dbname != "" {
		_, err := session.Execute("use " + dbname)
		if err != nil {
			return nil, err
		}
	}
	tc := &TiDBContext{
		session:   session,
		currentDB: dbname,
		stmts:     make(map[int]*TiDBStatement),
	}
	return tc, nil
}

// Status implements IContext Status method.
func (tc *TiDBContext) Status() uint16 {
	return tc.session.Status()
}

// LastInsertID implements IContext LastInsertID method.
func (tc *TiDBContext) LastInsertID() uint64 {
	return tc.session.LastInsertID()
}

// AffectedRows implements IContext AffectedRows method.
func (tc *TiDBContext) AffectedRows() uint64 {
	return tc.session.AffectedRows()
}

// CurrentDB implements IContext CurrentDB method.
func (tc *TiDBContext) CurrentDB() string {
	return tc.currentDB
}

// WarningCount implements IContext WarningCount method.
func (tc *TiDBContext) WarningCount() uint16 {
	return tc.warningCount
}

// Execute implements IContext Execute method.
func (tc *TiDBContext) Execute(sql string) (rs ResultSet, err error) {
	rsList, err := tc.session.Execute(sql)
	if errors2.ErrorEqual(err, kv.ErrConditionNotMatch) {
		return nil, tc.session.Retry()
	}
	if err != nil {
		return
	}
	if len(rsList) == 0 { // result ok
		return
	}
	rs = &tidbResultSet{
		recordSet: rsList[0],
	}
	return
}

// Close implements IContext Close method.
func (tc *TiDBContext) Close() (err error) {
	return tc.session.Close()
}

// FieldList implements IContext FieldList method.
func (tc *TiDBContext) FieldList(table string) (colums []*ColumnInfo, err error) {
	rs, err := tc.Execute("SELECT * FROM " + table + " LIMIT 0")
	if err != nil {
		return nil, errors.Trace(err)
	}
	colums, err = rs.Columns()
	if err != nil {
		return nil, errors.Trace(err)
	}
	return
}

// GetStatement implements IContext GetStatement method.
func (tc *TiDBContext) GetStatement(stmtID int) IStatement {
	tcStmt := tc.stmts[stmtID]
	if tcStmt != nil {
		return tcStmt
	}
	return nil
}

// Prepare implements IContext Prepare method.
func (tc *TiDBContext) Prepare(sql string) (statement IStatement, columns, params []*ColumnInfo, err error) {
	stmtID, paramCount, fields, err := tc.session.PrepareStmt(sql)
	if err != nil {
		return
	}
	stmt := &TiDBStatement{
		id:          stmtID,
		numParams:   paramCount,
		boundParams: make([][]byte, paramCount),
		ctx:         tc,
	}
	statement = stmt
	columns = make([]*ColumnInfo, len(fields))
	for i := range fields {
		columns[i] = convertColumnInfo(fields[i])
	}
	params = make([]*ColumnInfo, paramCount)
	for i := range params {
		params[i] = &ColumnInfo{
			Type: mysql.TypeBlob,
		}
	}
	tc.stmts[int(stmtID)] = stmt
	return
}

type tidbResultSet struct {
	recordSet rset.Recordset
}

func (trs *tidbResultSet) Next() ([]interface{}, error) {
	row, err := trs.recordSet.Next()
	if err != nil {
		return nil, errors.Trace(err)
	}
	if row != nil {
		return row.Data, nil
	}
	return nil, nil
}

func (trs *tidbResultSet) Close() error {
	return trs.recordSet.Close()
}

func (trs *tidbResultSet) Columns() ([]*ColumnInfo, error) {
	fields, err := trs.recordSet.Fields()
	if err != nil {
		return nil, errors.Trace(err)
	}
	var columns []*ColumnInfo
	for _, v := range fields {
		columns = append(columns, convertColumnInfo(v))
	}
	return columns, nil
}

func convertColumnInfo(fld *field.ResultField) (ci *ColumnInfo) {
	ci = new(ColumnInfo)
	ci.Name = fld.Name
	ci.OrgName = fld.ColumnInfo.Name.O
	ci.Table = fld.TableName
	ci.OrgTable = fld.OrgTableName
	ci.Schema = fld.DBName
	ci.Flag = uint16(fld.Flag)
	ci.Charset = uint16(mysql.CharsetIDs[fld.Charset])
	ci.ColumnLength = uint32(fld.Flen)
	ci.Decimal = uint8(fld.Decimal)
	ci.Type = uint8(fld.Tp)
	return
}

// Bootstrap initiates TiDB server.
func Bootstrap(store kv.Storage) {
	td := NewTiDBDriver(store)
	tc, err := td.OpenCtx(defaultCapability, mysql.DefaultCollationID, "")
	defer tc.Close()
	if err != nil {
		log.Fatal(err)
	}
	// Create a test database.
	_, err = tc.Execute("CREATE DATABASE IF NOT EXISTS test")
	if err != nil {
		log.Fatal(err)
	}

	//  Check if mysql db exists.
	_, err = tc.Execute("USE mysql;")
	if err == nil {
		// We have already finished bootstrap.
		return
	} else if !errors2.ErrorEqual(err, tidberrors.ErrDatabaseNotExist) {
		log.Fatal(err)
	}
	_, err = tc.Execute("CREATE DATABASE mysql;")
	if err != nil {
		log.Fatal(err)
	}
	_, err = tc.Execute("CREATE TABLE mysql.user (Host CHAR(64), User CHAR(16), Password CHAR(41), PRIMARY KEY (Host, User));")
	if err != nil {
		log.Fatal(err)
	}
	// Insert a default user with empty password.
	_, err = tc.Execute(`INSERT INTO mysql.user VALUES ("localhost", "root", ""), ("127.0.0.1", "root", "");`)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package volume

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/camptocamp/conplicity/handler"
	"github.com/camptocamp/conplicity/util"
)

// Volume provides backup methods for a single Docker volume
type Volume struct {
	Name            string
	Target          string
	BackupDir       string
	Mount           string
	FullIfOlderThan string
	RemoveOlderThan string
	Client          *handler.Conplicity
}

// Constants
const cacheMount = "duplicity_cache:/root/.cache/duplicity"
const timeFormat = "Mon Jan 2 15:04:05 2006"

var fullBackupRx = regexp.MustCompile("Last full backup date: (.+)")
var chainEndTimeRx = regexp.MustCompile("Chain end time: (.+)")

// Backup performs the backup of a volume with duplicity
func (v *Volume) Backup() (metrics []string, err error) {
	_, _, err = v.Client.LaunchDuplicity(
		[]string{
			"--full-if-older-than", v.FullIfOlderThan,
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--allow-source-mismatch",
			"--name", v.Name,
			v.BackupDir,
			v.Target,
		},
		[]string{
			v.Mount,
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)
	return
}

// RemoveOld cleans up old backup data from duplicity
func (v *Volume) RemoveOld() (metrics []string, err error) {
	_, _, err = v.Client.LaunchDuplicity(
		[]string{
			"remove-older-than", v.RemoveOlderThan,
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--force",
			"--name", v.Name,
			v.Target,
		},
		[]string{
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)
	return
}

// Cleanup removes old index data from duplicity
func (v *Volume) Cleanup() (metrics []string, err error) {
	_, _, err = v.Client.LaunchDuplicity(
		[]string{
			"cleanup",
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--force",
			"--extra-clean",
			"--name", v.Name,
			v.Target,
		},
		[]string{
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)
	return
}

// Verify checks that the backup is usable
func (v *Volume) Verify() (metrics []string, err error) {
	state, _, err := v.Client.LaunchDuplicity(
		[]string{
			"verify",
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--allow-source-mismatch",
			"--name", v.Name,
			v.Target,
			v.BackupDir,
		},
		[]string{
			v.Mount,
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)

	metric := fmt.Sprintf("conplicity{volume=\"%v\",what=\"verifyExitCode\"} %v", v.Name, state.ExitCode)
	metrics = []string{
		metric,
	}
	return
}

// Status gets the latest backup date info from duplicity
func (v *Volume) Status() (metrics []string, err error) {
	_, stdout, err := v.Client.LaunchDuplicity(
		[]string{
			"collection-status",
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--name", v.Name,
			v.Target,
		},
		[]string{
			v.Mount,
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)

	fullBackup := fullBackupRx.FindStringSubmatch(stdout)
	fullBackupDate, err := time.Parse(timeFormat, strings.TrimSpace(fullBackup[1]))
	util.CheckErr(err, "Failed to parse full backup date: %v", -1)
	chainEndTime := chainEndTimeRx.FindStringSubmatch(stdout)
	chainEndTimeDate, err := time.Parse(timeFormat, strings.TrimSpace(chainEndTime[1]))
	util.CheckErr(err, "Failed to parse chain end time date: %v", -1)

	lastBackupMetric := fmt.Sprintf("conplicity{volume=\"%v\",what=\"lastBackup\"} %v", v.Name, chainEndTimeDate.Unix())

	lastFullBackupMetric := fmt.Sprintf("conplicity{volume=\"%v\",what=\"lastFullBackup\"} %v", v.Name, fullBackupDate.Unix())

	metrics = []string{
		lastBackupMetric,
		lastFullBackupMetric,
	}

	return
}
<commit_msg>Return error when stdout could not be processed<commit_after>package volume

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/camptocamp/conplicity/handler"
	"github.com/camptocamp/conplicity/util"
)

// Volume provides backup methods for a single Docker volume
type Volume struct {
	Name            string
	Target          string
	BackupDir       string
	Mount           string
	FullIfOlderThan string
	RemoveOlderThan string
	Client          *handler.Conplicity
}

// Constants
const cacheMount = "duplicity_cache:/root/.cache/duplicity"
const timeFormat = "Mon Jan 2 15:04:05 2006"

var fullBackupRx = regexp.MustCompile("Last full backup date: (.+)")
var chainEndTimeRx = regexp.MustCompile("Chain end time: (.+)")

// Backup performs the backup of a volume with duplicity
func (v *Volume) Backup() (metrics []string, err error) {
	_, _, err = v.Client.LaunchDuplicity(
		[]string{
			"--full-if-older-than", v.FullIfOlderThan,
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--allow-source-mismatch",
			"--name", v.Name,
			v.BackupDir,
			v.Target,
		},
		[]string{
			v.Mount,
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)
	return
}

// RemoveOld cleans up old backup data from duplicity
func (v *Volume) RemoveOld() (metrics []string, err error) {
	_, _, err = v.Client.LaunchDuplicity(
		[]string{
			"remove-older-than", v.RemoveOlderThan,
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--force",
			"--name", v.Name,
			v.Target,
		},
		[]string{
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)
	return
}

// Cleanup removes old index data from duplicity
func (v *Volume) Cleanup() (metrics []string, err error) {
	_, _, err = v.Client.LaunchDuplicity(
		[]string{
			"cleanup",
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--force",
			"--extra-clean",
			"--name", v.Name,
			v.Target,
		},
		[]string{
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)
	return
}

// Verify checks that the backup is usable
func (v *Volume) Verify() (metrics []string, err error) {
	state, _, err := v.Client.LaunchDuplicity(
		[]string{
			"verify",
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--allow-source-mismatch",
			"--name", v.Name,
			v.Target,
			v.BackupDir,
		},
		[]string{
			v.Mount,
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)

	metric := fmt.Sprintf("conplicity{volume=\"%v\",what=\"verifyExitCode\"} %v", v.Name, state.ExitCode)
	metrics = []string{
		metric,
	}
	return
}

// Status gets the latest backup date info from duplicity
func (v *Volume) Status() (metrics []string, err error) {
	_, stdout, err := v.Client.LaunchDuplicity(
		[]string{
			"collection-status",
			"--s3-use-new-style",
			"--ssh-options", "-oStrictHostKeyChecking=no",
			"--no-encryption",
			"--name", v.Name,
			v.Target,
		},
		[]string{
			v.Mount,
			cacheMount,
		},
	)
	util.CheckErr(err, "Failed to launch Duplicity: %v", 1)

	fullBackup := fullBackupRx.FindStringSubmatch(stdout)
	var fullBackupDate time.Time
	if len(fullBackup) > 0 {
		fullBackupDate, err = time.Parse(timeFormat, strings.TrimSpace(fullBackup[1]))
		util.CheckErr(err, "Failed to parse full backup date: %v", -1)
	} else {
		err_msg := fmt.Sprintf("Failed to parse Duplicity output for last full backup date of %v", v.Name)
		err = errors.New(err_msg)
		return
	}

	chainEndTime := chainEndTimeRx.FindStringSubmatch(stdout)
	var chainEndTimeDate time.Time
	if len(chainEndTime) > 0 {
		chainEndTimeDate, err = time.Parse(timeFormat, strings.TrimSpace(chainEndTime[1]))
		util.CheckErr(err, "Failed to parse chain end time date: %v", -1)
	} else {
		err_msg := fmt.Sprintf("Failed to parse Duplicity output for chain end time of %v", v.Name)
		err = errors.New(err_msg)
		return
	}

	lastBackupMetric := fmt.Sprintf("conplicity{volume=\"%v\",what=\"lastBackup\"} %v", v.Name, chainEndTimeDate.Unix())

	lastFullBackupMetric := fmt.Sprintf("conplicity{volume=\"%v\",what=\"lastFullBackup\"} %v", v.Name, fullBackupDate.Unix())

	metrics = []string{
		lastBackupMetric,
		lastFullBackupMetric,
	}

	return
}
<|endoftext|>


<commit_before>package peerwriter

import (
	"bytes"
	"container/list"
	"encoding/binary"
	"io"
	"net"
	"time"

	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/peerprotocol"
)

const keepAlivePeriod = 2 * time.Minute

type PeerWriter struct {
	conn       net.Conn
	queueC     chan peerprotocol.Message
	cancelC    chan peerprotocol.CancelMessage
	writeQueue *list.List
	writeC     chan peerprotocol.Message
	messages   chan interface{}
	log        logger.Logger
	stopC      chan struct{}
	doneC      chan struct{}
}

func New(conn net.Conn, l logger.Logger) *PeerWriter {
	return &PeerWriter{
		conn:       conn,
		queueC:     make(chan peerprotocol.Message),
		cancelC:    make(chan peerprotocol.CancelMessage),
		writeQueue: list.New(),
		writeC:     make(chan peerprotocol.Message),
		messages:   make(chan interface{}),
		log:        l,
		stopC:      make(chan struct{}),
		doneC:      make(chan struct{}),
	}
}

func (p *PeerWriter) Messages() <-chan interface{} {
	return p.messages
}

func (p *PeerWriter) SendMessage(msg peerprotocol.Message) {
	select {
	case p.queueC <- msg:
	case <-p.doneC:
	}
}

func (p *PeerWriter) SendPiece(msg peerprotocol.RequestMessage, pi io.ReaderAt) {
	m := Piece{Piece: pi, Index: msg.Index, Begin: msg.Begin, Length: msg.Length}
	select {
	case p.queueC <- m:
	case <-p.doneC:
	}
}

func (p *PeerWriter) CancelRequest(msg peerprotocol.CancelMessage) {
	select {
	case p.cancelC <- msg:
	case <-p.doneC:
	}
}

func (p *PeerWriter) Stop() {
	close(p.stopC)
}

func (p *PeerWriter) Done() chan struct{} {
	return p.doneC
}

func (p *PeerWriter) Run() {
	defer close(p.doneC)

	go p.messageWriter()

	for {
		var (
			e      *list.Element
			msg    peerprotocol.Message
			writeC chan peerprotocol.Message
		)
		if p.writeQueue.Len() > 0 {
			e = p.writeQueue.Front()
			msg = e.Value.(peerprotocol.Message)
			writeC = p.writeC
		}
		select {
		case msg = <-p.queueC:
			p.queueMessage(msg)
		case writeC <- msg:
			p.writeQueue.Remove(e)
		case cm := <-p.cancelC:
			p.cancelRequest(cm)
		case <-p.stopC:
			return
		}
	}
}

func (p *PeerWriter) queueMessage(msg peerprotocol.Message) {
	if _, ok := msg.(peerprotocol.ChokeMessage); ok {
		p.cancelQueuedPieceMessages()
	}
	p.writeQueue.PushBack(msg)
}

func (p *PeerWriter) cancelQueuedPieceMessages() {
	var next *list.Element
	for e := p.writeQueue.Front(); e != nil; e = next {
		next = e.Next()
		if _, ok := e.Value.(Piece); ok {
			p.writeQueue.Remove(e)
		}
	}
}

func (p *PeerWriter) cancelRequest(cm peerprotocol.CancelMessage) {
	for e := p.writeQueue.Front(); e != nil; e = e.Next() {
		if pi, ok := e.Value.(Piece); ok && pi.Index == cm.Index && pi.Begin == cm.Begin && pi.Length == cm.Length {
			p.writeQueue.Remove(e)
			break
		}
	}
}

func (p *PeerWriter) messageWriter() {
	defer p.conn.Close()

	// Disable write deadline that is previously set by handshaker.
	err := p.conn.SetWriteDeadline(time.Time{})
	if err != nil {
		p.log.Error(err)
		return
	}

	keepAliveTicker := time.NewTicker(keepAlivePeriod / 2)
	defer keepAliveTicker.Stop()

	for {
		select {
		case msg := <-p.writeC:
			// p.log.Debugf("writing message of type: %q", msg.ID())
			payload, err := msg.MarshalBinary()
			if err != nil {
				p.log.Errorf("cannot marshal message [%v]: %s", msg.ID(), err.Error())
				return
			}
			buf := bytes.NewBuffer(make([]byte, 0, 4+1+len(payload)))
			var header = struct {
				Length uint32
				ID     peerprotocol.MessageID
			}{
				Length: uint32(1 + len(payload)),
				ID:     msg.ID(),
			}
			_ = binary.Write(buf, binary.BigEndian, &header)
			buf.Write(payload)
			n, err := p.conn.Write(buf.Bytes())
			p.countUploadBytes(msg, n)
			if _, ok := err.(*net.OpError); ok {
				p.log.Debugf("cannot write message [%v]: %s", msg.ID(), err.Error())
				return
			}
			if err != nil {
				p.log.Errorf("cannot write message [%v]: %s", msg.ID(), err.Error())
				return
			}
		case <-keepAliveTicker.C:
			_, err := p.conn.Write([]byte{0, 0, 0, 0})
			if _, ok := err.(*net.OpError); ok {
				p.log.Debugf("cannot write keepalive message: %s", err.Error())
				return
			}
			if err != nil {
				p.log.Errorf("cannot write keepalive message: %s", err.Error())
				return
			}
		case <-p.stopC:
			return
		}
	}
}

func (p *PeerWriter) countUploadBytes(msg peerprotocol.Message, n int) {
	if _, ok := msg.(Piece); ok {
		uploaded := uint32(n) - 13
		if uploaded < 0 {
			uploaded = 0
		}
		if uploaded > 0 {
			select {
			case p.messages <- BlockUploaded{Length: uploaded}:
			case <-p.stopC:
			}
		}
	}
}
<commit_msg>do not log error for closed connections<commit_after>package peerwriter

import (
	"bytes"
	"container/list"
	"encoding/binary"
	"io"
	"net"
	"time"

	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/peerprotocol"
)

const keepAlivePeriod = 2 * time.Minute

type PeerWriter struct {
	conn       net.Conn
	queueC     chan peerprotocol.Message
	cancelC    chan peerprotocol.CancelMessage
	writeQueue *list.List
	writeC     chan peerprotocol.Message
	messages   chan interface{}
	log        logger.Logger
	stopC      chan struct{}
	doneC      chan struct{}
}

func New(conn net.Conn, l logger.Logger) *PeerWriter {
	return &PeerWriter{
		conn:       conn,
		queueC:     make(chan peerprotocol.Message),
		cancelC:    make(chan peerprotocol.CancelMessage),
		writeQueue: list.New(),
		writeC:     make(chan peerprotocol.Message),
		messages:   make(chan interface{}),
		log:        l,
		stopC:      make(chan struct{}),
		doneC:      make(chan struct{}),
	}
}

func (p *PeerWriter) Messages() <-chan interface{} {
	return p.messages
}

func (p *PeerWriter) SendMessage(msg peerprotocol.Message) {
	select {
	case p.queueC <- msg:
	case <-p.doneC:
	}
}

func (p *PeerWriter) SendPiece(msg peerprotocol.RequestMessage, pi io.ReaderAt) {
	m := Piece{Piece: pi, Index: msg.Index, Begin: msg.Begin, Length: msg.Length}
	select {
	case p.queueC <- m:
	case <-p.doneC:
	}
}

func (p *PeerWriter) CancelRequest(msg peerprotocol.CancelMessage) {
	select {
	case p.cancelC <- msg:
	case <-p.doneC:
	}
}

func (p *PeerWriter) Stop() {
	close(p.stopC)
}

func (p *PeerWriter) Done() chan struct{} {
	return p.doneC
}

func (p *PeerWriter) Run() {
	defer close(p.doneC)

	go p.messageWriter()

	for {
		var (
			e      *list.Element
			msg    peerprotocol.Message
			writeC chan peerprotocol.Message
		)
		if p.writeQueue.Len() > 0 {
			e = p.writeQueue.Front()
			msg = e.Value.(peerprotocol.Message)
			writeC = p.writeC
		}
		select {
		case msg = <-p.queueC:
			p.queueMessage(msg)
		case writeC <- msg:
			p.writeQueue.Remove(e)
		case cm := <-p.cancelC:
			p.cancelRequest(cm)
		case <-p.stopC:
			return
		}
	}
}

func (p *PeerWriter) queueMessage(msg peerprotocol.Message) {
	if _, ok := msg.(peerprotocol.ChokeMessage); ok {
		p.cancelQueuedPieceMessages()
	}
	p.writeQueue.PushBack(msg)
}

func (p *PeerWriter) cancelQueuedPieceMessages() {
	var next *list.Element
	for e := p.writeQueue.Front(); e != nil; e = next {
		next = e.Next()
		if _, ok := e.Value.(Piece); ok {
			p.writeQueue.Remove(e)
		}
	}
}

func (p *PeerWriter) cancelRequest(cm peerprotocol.CancelMessage) {
	for e := p.writeQueue.Front(); e != nil; e = e.Next() {
		if pi, ok := e.Value.(Piece); ok && pi.Index == cm.Index && pi.Begin == cm.Begin && pi.Length == cm.Length {
			p.writeQueue.Remove(e)
			break
		}
	}
}

func (p *PeerWriter) messageWriter() {
	defer p.conn.Close()

	// Disable write deadline that is previously set by handshaker.
	err := p.conn.SetWriteDeadline(time.Time{})
	if _, ok := err.(*net.OpError); ok {
		p.log.Debugln("cannot set deadline:", err)
		return
	}
	if err != nil {
		p.log.Error(err)
		return
	}

	keepAliveTicker := time.NewTicker(keepAlivePeriod / 2)
	defer keepAliveTicker.Stop()

	for {
		select {
		case msg := <-p.writeC:
			// p.log.Debugf("writing message of type: %q", msg.ID())
			payload, err := msg.MarshalBinary()
			if err != nil {
				p.log.Errorf("cannot marshal message [%v]: %s", msg.ID(), err.Error())
				return
			}
			buf := bytes.NewBuffer(make([]byte, 0, 4+1+len(payload)))
			var header = struct {
				Length uint32
				ID     peerprotocol.MessageID
			}{
				Length: uint32(1 + len(payload)),
				ID:     msg.ID(),
			}
			_ = binary.Write(buf, binary.BigEndian, &header)
			buf.Write(payload)
			n, err := p.conn.Write(buf.Bytes())
			p.countUploadBytes(msg, n)
			if _, ok := err.(*net.OpError); ok {
				p.log.Debugf("cannot write message [%v]: %s", msg.ID(), err.Error())
				return
			}
			if err != nil {
				p.log.Errorf("cannot write message [%v]: %s", msg.ID(), err.Error())
				return
			}
		case <-keepAliveTicker.C:
			_, err := p.conn.Write([]byte{0, 0, 0, 0})
			if _, ok := err.(*net.OpError); ok {
				p.log.Debugf("cannot write keepalive message: %s", err.Error())
				return
			}
			if err != nil {
				p.log.Errorf("cannot write keepalive message: %s", err.Error())
				return
			}
		case <-p.stopC:
			return
		}
	}
}

func (p *PeerWriter) countUploadBytes(msg peerprotocol.Message, n int) {
	if _, ok := msg.(Piece); ok {
		uploaded := uint32(n) - 13
		if uploaded < 0 {
			uploaded = 0
		}
		if uploaded > 0 {
			select {
			case p.messages <- BlockUploaded{Length: uploaded}:
			case <-p.stopC:
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"math"
	"net"
	"net/http"
	"sync/atomic"
	"time"

	"github.com/gorilla/context"

	"github.com/getlantern/measured"

	// "github.com/getlantern/http-proxy-extensions/devicefilter"
	"github.com/getlantern/http-proxy-extensions/mimic"
	// "github.com/getlantern/http-proxy-extensions/profilter"
	"github.com/getlantern/http-proxy-extensions/tokenfilter"
	"github.com/getlantern/http-proxy/commonfilter"
	"github.com/getlantern/http-proxy/forward"
	"github.com/getlantern/http-proxy/httpconnect"
)

var (
	testingLocal = false
)

type Server struct {
	firstHandler http.Handler
	httpServer   http.Server
	tls          bool

	listener net.Listener

	maxConns uint64
	numConns uint64

	idleTimeout time.Duration

	enableReports bool
}

func NewServer(token string, maxConns uint64, idleTimeout time.Duration, enableFilters, enableReports bool) *Server {
	if maxConns == 0 {
		maxConns = math.MaxInt64
	}

	// The following middleware architecture can be seen as a chain of
	// filters that is run from last to first.
	// Don't forget to check Oxy and Gorilla's handlers for middleware.

	// Handles Direct Proxying
	forwardHandler, _ := forward.New(
		nil,
		forward.IdleTimeoutSetter(idleTimeout),
	)

	// Handles HTTP CONNECT
	connectHandler, _ := httpconnect.New(
		forwardHandler,
		httpconnect.IdleTimeoutSetter(idleTimeout),
	)

	// Catches any request before reaching the CONNECT middleware or
	// the forwarder
	commonFilter, _ := commonfilter.New(
		connectHandler,
		testingLocal,
	)

	var firstHandler http.Handler
	if !enableFilters {
		firstHandler = commonFilter
	} else {
		// Temporarily remove deviceFilter and lanternPro.  These need changes in the client
		// that will come after the proxy is well tested.
		/*
			// Identifies Lantern Pro users (currently NOOP)
			lanternPro, _ := profilter.New(
				commonFilter,
				profilter.Logger(utils.NewTimeLogger(&stdWriter, logLevel)),
			)
			// Returns a 404 to requests without the proper token.  Removes the
			// header before continuing.
			tokenFilter, _ := tokenfilter.New(
				lanternPro,
				tokenfilter.TokenSetter(token),
				tokenfilter.Logger(utils.NewTimeLogger(&stdWriter, logLevel)),
			)
			// Extracts the user ID and attaches the matching client to the request
			// context.  Returns a 404 to requests without the UID.  Removes the
			// header before continuing.
			deviceFilter, _ := devicefilter.New(
				tokenFilter,
				devicefilter.Logger(utils.NewTimeLogger(&stdWriter, logLevel)),
			)
			firstHandler = deviceFilter
		*/
		tokenFilter, _ := tokenfilter.New(
			connectHandler,
			tokenfilter.TokenSetter(token),
		)
		firstHandler = tokenFilter
	}

	server := &Server{
		firstHandler:  firstHandler,
		maxConns:      maxConns,
		numConns:      0,
		idleTimeout:   idleTimeout,
		enableReports: enableReports,
	}
	return server
}

func (s *Server) ServeHTTP(addr string, chListenOn *chan string) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	s.tls = false
	log.Debugf("Listen http on %s", addr)
	return s.doServe(listener, chListenOn)
}

func (s *Server) ServeHTTPS(addr, keyfile, certfile string, chListenOn *chan string) error {
	listener, err := listenTLS(addr, keyfile, certfile)
	if err != nil {
		return err
	}
	s.tls = true
	log.Debugf("Listen https on %s", addr)
	return s.doServe(listener, chListenOn)
}

func (s *Server) doServe(listener net.Listener, chListenOn *chan string) error {
	// A dirty trick to associate a connection with the http.Request it
	// contains. In "net/http/server.go", handler will be called
	// immediately after ConnState changed to StateActive, so it's safe to
	// loop through all elements in a channel to find a match remote addr.
	q := make(chan net.Conn, 10)

	proxy := http.HandlerFunc(
		func(w http.ResponseWriter, req *http.Request) {
			for c := range q {
				if c.RemoteAddr().String() == req.RemoteAddr {
					context.Set(req, "conn", c)
					break
				} else {
					q <- c
				}
			}
			s.firstHandler.ServeHTTP(w, req)
		})

	limListener := newLimitedListener(listener, &s.numConns, s.idleTimeout)

	if s.enableReports {
		mListener := measured.Listener(limListener, 30*time.Second)
		s.listener = mListener
	} else {
		s.listener = limListener
	}

	s.httpServer = http.Server{Handler: proxy,
		ConnState: func(c net.Conn, state http.ConnState) {
			switch state {
			case http.StateNew:
				if atomic.LoadUint64(&s.numConns) >= s.maxConns {
					limListener.Stop()
				} else if limListener.IsStopped() {
					limListener.Restart()
				}
			case http.StateActive:
				select {
				case q <- c:
				default:
					log.Error("Oops! the connection queue is full!")
				}
			}
		},
	}

	addr := s.listener.Addr().String()
	host, port, err := net.SplitHostPort(addr)
	if err != nil {
		panic("should not happen")
	}
	mimic.Host = host
	mimic.Port = port
	if chListenOn != nil {
		*chListenOn <- addr
	}

	return s.httpServer.Serve(s.listener)
}
<commit_msg>Rollback Travis test<commit_after>package main

import (
	"math"
	"net"
	"net/http"
	"sync/atomic"
	"time"

	"github.com/gorilla/context"

	"github.com/getlantern/measured"

	// "github.com/getlantern/http-proxy-extensions/devicefilter"
	"github.com/getlantern/http-proxy-extensions/mimic"
	// "github.com/getlantern/http-proxy-extensions/profilter"
	"github.com/getlantern/http-proxy-extensions/tokenfilter"
	"github.com/getlantern/http-proxy/commonfilter"
	"github.com/getlantern/http-proxy/forward"
	"github.com/getlantern/http-proxy/httpconnect"
)

var (
	testingLocal = false
)

type Server struct {
	firstHandler http.Handler
	httpServer   http.Server
	tls          bool

	listener net.Listener

	maxConns uint64
	numConns uint64

	idleTimeout time.Duration

	enableReports bool
}

func NewServer(token string, maxConns uint64, idleTimeout time.Duration, enableFilters, enableReports bool) *Server {
	if maxConns == 0 {
		maxConns = math.MaxInt64
	}

	// The following middleware architecture can be seen as a chain of
	// filters that is run from last to first.
	// Don't forget to check Oxy and Gorilla's handlers for middleware.

	// Handles Direct Proxying
	forwardHandler, _ := forward.New(
		nil,
		forward.IdleTimeoutSetter(idleTimeout),
	)

	// Handles HTTP CONNECT
	connectHandler, _ := httpconnect.New(
		forwardHandler,
		httpconnect.IdleTimeoutSetter(idleTimeout),
	)

	// Catches any request before reaching the CONNECT middleware or
	// the forwarder
	commonFilter, _ := commonfilter.New(
		connectHandler,
		testingLocal,
	)

	var firstHandler http.Handler
	if !enableFilters {
		firstHandler = commonFilter
	} else {
		// Temporarily remove deviceFilter and lanternPro.  These need changes in the client
		// that will come after the proxy is well tested.
		/*
			// Identifies Lantern Pro users (currently NOOP)
			lanternPro, _ := profilter.New(
				commonFilter,
				profilter.Logger(utils.NewTimeLogger(&stdWriter, logLevel)),
			)
			// Returns a 404 to requests without the proper token.  Removes the
			// header before continuing.
			tokenFilter, _ := tokenfilter.New(
				lanternPro,
				tokenfilter.TokenSetter(token),
				tokenfilter.Logger(utils.NewTimeLogger(&stdWriter, logLevel)),
			)
			// Extracts the user ID and attaches the matching client to the request
			// context.  Returns a 404 to requests without the UID.  Removes the
			// header before continuing.
			deviceFilter, _ := devicefilter.New(
				tokenFilter,
				devicefilter.Logger(utils.NewTimeLogger(&stdWriter, logLevel)),
			)
			firstHandler = deviceFilter
		*/
		tokenFilter, _ := tokenfilter.New(
			commonFilter,
			tokenfilter.TokenSetter(token),
		)
		firstHandler = tokenFilter
	}

	server := &Server{
		firstHandler:  firstHandler,
		maxConns:      maxConns,
		numConns:      0,
		idleTimeout:   idleTimeout,
		enableReports: enableReports,
	}
	return server
}

func (s *Server) ServeHTTP(addr string, chListenOn *chan string) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	s.tls = false
	log.Debugf("Listen http on %s", addr)
	return s.doServe(listener, chListenOn)
}

func (s *Server) ServeHTTPS(addr, keyfile, certfile string, chListenOn *chan string) error {
	listener, err := listenTLS(addr, keyfile, certfile)
	if err != nil {
		return err
	}
	s.tls = true
	log.Debugf("Listen https on %s", addr)
	return s.doServe(listener, chListenOn)
}

func (s *Server) doServe(listener net.Listener, chListenOn *chan string) error {
	// A dirty trick to associate a connection with the http.Request it
	// contains. In "net/http/server.go", handler will be called
	// immediately after ConnState changed to StateActive, so it's safe to
	// loop through all elements in a channel to find a match remote addr.
	q := make(chan net.Conn, 10)

	proxy := http.HandlerFunc(
		func(w http.ResponseWriter, req *http.Request) {
			for c := range q {
				if c.RemoteAddr().String() == req.RemoteAddr {
					context.Set(req, "conn", c)
					break
				} else {
					q <- c
				}
			}
			s.firstHandler.ServeHTTP(w, req)
		})

	limListener := newLimitedListener(listener, &s.numConns, s.idleTimeout)

	if s.enableReports {
		mListener := measured.Listener(limListener, 30*time.Second)
		s.listener = mListener
	} else {
		s.listener = limListener
	}

	s.httpServer = http.Server{Handler: proxy,
		ConnState: func(c net.Conn, state http.ConnState) {
			switch state {
			case http.StateNew:
				if atomic.LoadUint64(&s.numConns) >= s.maxConns {
					limListener.Stop()
				} else if limListener.IsStopped() {
					limListener.Restart()
				}
			case http.StateActive:
				select {
				case q <- c:
				default:
					log.Error("Oops! the connection queue is full!")
				}
			}
		},
	}

	addr := s.listener.Addr().String()
	host, port, err := net.SplitHostPort(addr)
	if err != nil {
		panic("should not happen")
	}
	mimic.Host = host
	mimic.Port = port
	if chListenOn != nil {
		*chListenOn <- addr
	}

	return s.httpServer.Serve(s.listener)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"strconv"

	"github.com/hashicorp/terraform/helper/schema"
)

type domainRecordResource struct {
	Customer string
	Domain   string
	Records  []*DomainRecord
}

var defaultRecords = []*DomainRecord{
	// A Records
	&DomainRecord{Type: "A", Name: "@", Data: "50.63.202.43", TTL: 600},
	// CNAME Records
	&DomainRecord{Type: "CNAME", Name: "email", Data: "email.secureserver.net", TTL: 3600},
	&DomainRecord{Type: "CNAME", Name: "ftp", Data: "@", TTL: 3600},
	&DomainRecord{Type: "CNAME", Name: "www", Data: "@", TTL: 3600},
	&DomainRecord{Type: "CNAME", Name: "_domainconnect", Data: "_domainconnect.gd.domaincontrol.com", TTL: 3600},
	// MX Records
	&DomainRecord{Type: "MX", Name: "@", Data: "mailstore1.secureserver.net", TTL: 3600, Priority: 10},
	&DomainRecord{Type: "MX", Name: "@", Data: "smtp.secureserver.net", TTL: 3600, Priority: 0},
	// NS Records
	&DomainRecord{Type: "NS", Name: "@", Data: "ns45.domaincontrol.com", TTL: 3600},
	&DomainRecord{Type: "NS", Name: "@", Data: "ns46.domaincontrol.com", TTL: 3600},
}

func newDomainRecordResource(d *schema.ResourceData) (domainRecordResource, error) {
	var err error
	r := domainRecordResource{}

	if attr, ok := d.GetOk("customer"); ok {
		r.Customer = attr.(string)
	}

	if attr, ok := d.GetOk("domain"); ok {
		r.Domain = attr.(string)
	}

	if attr, ok := d.GetOk("record"); ok {
		records := attr.(*schema.Set).List()
		r.Records = make([]*DomainRecord, len(records))

		for i, rec := range records {
			data := rec.(map[string]interface{})
			r.Records[i], err = NewDomainRecord(
				data["name"].(string),
				data["type"].(string),
				data["data"].(string),
				data["ttl"].(int))

			if err != nil {
				return r, err
			}
		}
	}

	return r, err
}

func resourceDomainRecord() *schema.Resource {
	return &schema.Resource{
		Create: resourceDomainRecordUpdate,
		Read:   resourceDomainRecordRead,
		Update: resourceDomainRecordUpdate,
		Delete: resourceDomainRecordRestore,

		Schema: map[string]*schema.Schema{
			// Optional
			"customer": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			// Required
			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"record": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"type": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"data": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"ttl": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Default:  3600,
						},
					},
				},
			},
		},
	}
}

func resourceDomainRecordRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*GoDaddyClient)
	customer := d.Get("customer").(string)
	domain := d.Get("domain").(string)

	log.Println("Fetching", domain, "records...")
	records, err := client.GetDomainRecords(customer, domain)
	if err != nil {
		return fmt.Errorf("couldn't find domain record: ", err.Error())
	}

	return populateResourceDataFromResponse(records, d)
}

func resourceDomainRecordUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*GoDaddyClient)
	r, err := newDomainRecordResource(d)
	if err != nil {
		return err
	}

	if err = populateDomainInfo(client, &r, d); err != nil {
		return err
	}

	log.Println("Updating", r.Domain, "domain records...")
	return client.UpdateDomainRecords(r.Customer, r.Domain, r.Records)
}

func resourceDomainRecordRestore(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*GoDaddyClient)
	r, err := newDomainRecordResource(d)
	if err != nil {
		return err
	}

	if err = populateDomainInfo(client, &r, d); err != nil {
		return err
	}

	log.Println("Restoring", r.Domain, "domain records...")
	return client.UpdateDomainRecords(r.Customer, r.Domain, defaultRecords)
}

func populateDomainInfo(client *GoDaddyClient, r *domainRecordResource, d *schema.ResourceData) error {
	var err error
	var domain *Domain

	log.Println("Fetching", r.Domain, "info...")
	domain, err = client.GetDomain(r.Customer, r.Domain)
	if err != nil {
		return fmt.Errorf("couldn't find domain: ", err.Error())
	}

	d.SetId(strconv.FormatInt(domain.ID, 10))
	return nil
}

func populateResourceDataFromResponse(r []*DomainRecord, d *schema.ResourceData) error {
	d.Set("record", flattenRecords(r))
	return nil
}

func flattenRecords(list []*DomainRecord) []map[string]interface{} {
	result := make([]map[string]interface{}, 0, len(list))
	for _, r := range list {
		l := map[string]interface{}{
			"name": r.Name,
			"type": r.Type,
			"data": r.Data,
			"ttl":  r.TTL,
		}
		result = append(result, l)
	}
	return result
}
<commit_msg>Cleanup error messages<commit_after>package main

import (
	"fmt"
	"log"
	"strconv"

	"github.com/hashicorp/terraform/helper/schema"
)

type domainRecordResource struct {
	Customer string
	Domain   string
	Records  []*DomainRecord
}

var defaultRecords = []*DomainRecord{
	// A Records
	&DomainRecord{Type: "A", Name: "@", Data: "50.63.202.43", TTL: 600},
	// CNAME Records
	&DomainRecord{Type: "CNAME", Name: "email", Data: "email.secureserver.net", TTL: 3600},
	&DomainRecord{Type: "CNAME", Name: "ftp", Data: "@", TTL: 3600},
	&DomainRecord{Type: "CNAME", Name: "www", Data: "@", TTL: 3600},
	&DomainRecord{Type: "CNAME", Name: "_domainconnect", Data: "_domainconnect.gd.domaincontrol.com", TTL: 3600},
	// MX Records
	&DomainRecord{Type: "MX", Name: "@", Data: "mailstore1.secureserver.net", TTL: 3600, Priority: 10},
	&DomainRecord{Type: "MX", Name: "@", Data: "smtp.secureserver.net", TTL: 3600, Priority: 0},
	// NS Records
	&DomainRecord{Type: "NS", Name: "@", Data: "ns45.domaincontrol.com", TTL: 3600},
	&DomainRecord{Type: "NS", Name: "@", Data: "ns46.domaincontrol.com", TTL: 3600},
}

func newDomainRecordResource(d *schema.ResourceData) (domainRecordResource, error) {
	var err error
	r := domainRecordResource{}

	if attr, ok := d.GetOk("customer"); ok {
		r.Customer = attr.(string)
	}

	if attr, ok := d.GetOk("domain"); ok {
		r.Domain = attr.(string)
	}

	if attr, ok := d.GetOk("record"); ok {
		records := attr.(*schema.Set).List()
		r.Records = make([]*DomainRecord, len(records))

		for i, rec := range records {
			data := rec.(map[string]interface{})
			r.Records[i], err = NewDomainRecord(
				data["name"].(string),
				data["type"].(string),
				data["data"].(string),
				data["ttl"].(int))

			if err != nil {
				return r, err
			}
		}
	}

	return r, err
}

func resourceDomainRecord() *schema.Resource {
	return &schema.Resource{
		Create: resourceDomainRecordUpdate,
		Read:   resourceDomainRecordRead,
		Update: resourceDomainRecordUpdate,
		Delete: resourceDomainRecordRestore,

		Schema: map[string]*schema.Schema{
			// Optional
			"customer": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			// Required
			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"record": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"type": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"data": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"ttl": &schema.Schema{
							Type:     schema.TypeInt,
							Optional: true,
							Default:  3600,
						},
					},
				},
			},
		},
	}
}

func resourceDomainRecordRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*GoDaddyClient)
	customer := d.Get("customer").(string)
	domain := d.Get("domain").(string)

	log.Println("Fetching", domain, "records...")
	records, err := client.GetDomainRecords(customer, domain)
	if err != nil {
		return fmt.Errorf("couldn't find domain record (%s): %s", domain, err.Error())
	}

	return populateResourceDataFromResponse(records, d)
}

func resourceDomainRecordUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*GoDaddyClient)
	r, err := newDomainRecordResource(d)
	if err != nil {
		return err
	}

	if err = populateDomainInfo(client, &r, d); err != nil {
		return err
	}

	log.Println("Updating", r.Domain, "domain records...")
	return client.UpdateDomainRecords(r.Customer, r.Domain, r.Records)
}

func resourceDomainRecordRestore(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*GoDaddyClient)
	r, err := newDomainRecordResource(d)
	if err != nil {
		return err
	}

	if err = populateDomainInfo(client, &r, d); err != nil {
		return err
	}

	log.Println("Restoring", r.Domain, "domain records...")
	return client.UpdateDomainRecords(r.Customer, r.Domain, defaultRecords)
}

func populateDomainInfo(client *GoDaddyClient, r *domainRecordResource, d *schema.ResourceData) error {
	var err error
	var domain *Domain

	log.Println("Fetching", r.Domain, "info...")
	domain, err = client.GetDomain(r.Customer, r.Domain)
	if err != nil {
		return fmt.Errorf("couldn't find domain (%s): %s", r.Domain, err.Error())
	}

	d.SetId(strconv.FormatInt(domain.ID, 10))
	return nil
}

func populateResourceDataFromResponse(r []*DomainRecord, d *schema.ResourceData) error {
	d.Set("record", flattenRecords(r))
	return nil
}

func flattenRecords(list []*DomainRecord) []map[string]interface{} {
	result := make([]map[string]interface{}, 0, len(list))
	for _, r := range list {
		l := map[string]interface{}{
			"name": r.Name,
			"type": r.Type,
			"data": r.Data,
			"ttl":  r.TTL,
		}
		result = append(result, l)
	}
	return result
}
<|endoftext|>


<commit_before>package game_engine

import (
    "fmt"
    "encoding/json"
    "errors"
    "requests"
)

type Game struct {
    terrain [][]terrain
    unitMap map[location]*unit
    players []*player
    numPlayers int
    turnOwner int
}

func NewGame(playerIds []int, worldId int) (*Game, error) {
    numPlayers := len(playerIds)
    if numPlayers > 4 || numPlayers < 1 {
        return nil, errors.New("must have between 1 and 4 players")
    }
    players := make([]*player, numPlayers)
    for i, playerId := range(playerIds) {
        players[i] = newPlayer(playerId, nation(i), team(i))
    }
    ret_game := &Game{
        terrain: [][]terrain{
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains}},
        unitMap: make(map[location]*unit),
        players: players,
        numPlayers: numPlayers,
        turnOwner: 0}
    ret_game.AddUnit(newLocation(0, 0), tank(red))
    return ret_game, nil
}

func (game *Game) verifyTurnOwner(playerId int) error {
    fmt.Println(game.players[game.turnOwner].playerId)
    if playerId == game.players[game.turnOwner].playerId {
        return errors.New("Not the turn owner")
    }
    return nil
}

func (game *Game) AddUnit(location location, unit *unit) error {
    fmt.Println("adding unit")
    _, ok := game.unitMap[location]; if !ok {
        game.unitMap[location] = unit
        fmt.Println("added unit")
        return nil
    } else {
        fmt.Println("failed to add unit")
        return errors.New("location already occupied")
    }
}

func (game *Game) EndTurn(playerId int) error {
    ownerError := game.verifyTurnOwner(playerId)
    if ownerError != nil {
        return ownerError
    }
    nextOwner := game.turnOwner + 1
    if nextOwner >= game.numPlayers {
        game.turnOwner = 0
    } else {
        game.turnOwner = nextOwner
    }
    return nil
}

func (game *Game) MoveUnit(playerId int, rawLocations []requests.LocationStruct) error {
    ownerError := game.verifyTurnOwner(playerId)
    if ownerError != nil {
        return ownerError
    }
    locations := make([]location, len(rawLocations))
    for i, location := range(rawLocations) {
        locations[i] = newLocation(location.X, location.Y)
    }
    if len(locations) < 1 {
        message := "must supply more than zero  locations"
        fmt.Println(message)
        return errors.New(message)
    }

    tiles := make([]terrain, len(locations))
    for i, location := range(locations) {
        tiles[i] = game.terrain[location.x][location.y]
    }
    //fmt.Println(tiles)
    //fmt.Println(game.unitMap)
    //fmt.Println(locations)
    unit, ok := game.unitMap[locations[0]]; if ok {
        moveErr := validMove(
            unit.movement.distance,
            unit.movement,
            tiles,
            locations)
        if moveErr == nil {
            end := len(locations)
            unit = game.unitMap[newLocation(locations[0].x, locations[0].y)]
            game.unitMap[newLocation(locations[end-1].x, locations[end-1].y)] = unit
            delete(game.unitMap, newLocation(locations[0].x, locations[0].y))
            return nil
        } else {
            fmt.Println(moveErr)
            return moveErr
        }
    } else {
        message := "Invalid starting location"
        fmt.Println(message)
        return errors.New(message)
    }
}

func (game *Game) Serialize(playerId int) ([]byte, error) {
    players := make([]*requests.PlayerStruct, len(game.players))
    for i, player := range(game.players) {
        players[i] = player.serialize()
    }
    terrainInts := make([][]int, len(game.terrain))
    for i, t := range(game.terrain) {
        thoriz := make([]int, len(t))
        for j, t_ := range(t) {
            thoriz[j] = int(t_)
        }
        terrainInts[i] = thoriz
    }
    units := make([]*requests.UnitStruct, len(game.unitMap))
    i := 0
    for location, unit := range(game.unitMap) {
        units[i] = unit.serialize(location)
        i += 1
    }
    return json.Marshal(requests.WorldStruct{
        Terrain: terrainInts,
        Units: units,
        Players: players,
        TurnOwner: 0})
}
<commit_msg>Clean up turnOwner and turnOwner serialization<commit_after>package game_engine

import (
    "fmt"
    "encoding/json"
    "errors"
    "requests"
)

type Game struct {
    terrain [][]terrain
    unitMap map[location]*unit
    players []*player
    numPlayers int
    turnOwner int
}

func NewGame(playerIds []int, worldId int) (*Game, error) {
    numPlayers := len(playerIds)
    if numPlayers > 4 || numPlayers < 1 {
        return nil, errors.New("must have between 1 and 4 players")
    }
    players := make([]*player, numPlayers)
    for i, playerId := range(playerIds) {
        players[i] = newPlayer(playerId, nation(i), team(i))
    }
    ret_game := &Game{
        terrain: [][]terrain{
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains},
            []terrain{plains, plains, plains, plains, plains, plains, plains, plains}},
        unitMap: make(map[location]*unit),
        players: players,
        numPlayers: numPlayers,
        turnOwner: 0}
    ret_game.AddUnit(newLocation(0, 0), tank(red))
    return ret_game, nil
}

func (game *Game) verifyTurnOwner(playerId int) error {
    if playerId != game.players[game.turnOwner].playerId {
        return errors.New("Not the turn owner")
    }
    return nil
}

func (game *Game) AddUnit(location location, unit *unit) error {
    fmt.Println("adding unit")
    _, ok := game.unitMap[location]; if !ok {
        game.unitMap[location] = unit
        fmt.Println("added unit")
        return nil
    } else {
        fmt.Println("failed to add unit")
        return errors.New("location already occupied")
    }
}

func (game *Game) EndTurn(playerId int) error {
    ownerError := game.verifyTurnOwner(playerId)
    if ownerError != nil {
        return ownerError
    }
    nextOwner := game.turnOwner + 1
    if nextOwner >= game.numPlayers {
        game.turnOwner = 0
    } else {
        game.turnOwner = nextOwner
    }
    return nil
}

func (game *Game) MoveUnit(playerId int, rawLocations []requests.LocationStruct) error {
    ownerError := game.verifyTurnOwner(playerId)
    if ownerError != nil {
        return ownerError
    }
    locations := make([]location, len(rawLocations))
    for i, location := range(rawLocations) {
        locations[i] = newLocation(location.X, location.Y)
    }
    if len(locations) < 1 {
        message := "must supply more than zero  locations"
        fmt.Println(message)
        return errors.New(message)
    }

    tiles := make([]terrain, len(locations))
    for i, location := range(locations) {
        tiles[i] = game.terrain[location.x][location.y]
    }
    //fmt.Println(tiles)
    //fmt.Println(game.unitMap)
    //fmt.Println(locations)
    unit, ok := game.unitMap[locations[0]]; if ok {
        moveErr := validMove(
            unit.movement.distance,
            unit.movement,
            tiles,
            locations)
        if moveErr == nil {
            end := len(locations)
            unit = game.unitMap[newLocation(locations[0].x, locations[0].y)]
            game.unitMap[newLocation(locations[end-1].x, locations[end-1].y)] = unit
            delete(game.unitMap, newLocation(locations[0].x, locations[0].y))
            return nil
        } else {
            fmt.Println(moveErr)
            return moveErr
        }
    } else {
        message := "Invalid starting location"
        fmt.Println(message)
        return errors.New(message)
    }
}

func (game *Game) Serialize(playerId int) ([]byte, error) {
    players := make([]*requests.PlayerStruct, len(game.players))
    for i, player := range(game.players) {
        players[i] = player.serialize()
    }
    terrainInts := make([][]int, len(game.terrain))
    for i, t := range(game.terrain) {
        thoriz := make([]int, len(t))
        for j, t_ := range(t) {
            thoriz[j] = int(t_)
        }
        terrainInts[i] = thoriz
    }
    units := make([]*requests.UnitStruct, len(game.unitMap))
    i := 0
    for location, unit := range(game.unitMap) {
        units[i] = unit.serialize(location)
        i += 1
    }
    return json.Marshal(requests.WorldStruct{
        Terrain: terrainInts,
        Units: units,
        Players: players,
        TurnOwner: game.players[game.turnOwner].playerId})
}
<|endoftext|>


<commit_before>//
// Copyright 2021, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
	"net/http"
	"reflect"
	"testing"
)

func TestTagsService_ListTags(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/1/repository/tags", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, `[{"name": "1.0.0"},{"name": "1.0.1"}]`)
	})

	opt := &ListTagsOptions{ListOptions: ListOptions{Page: 2, PerPage: 3}}

	tags, _, err := client.Tags.ListTags(1, opt)
	if err != nil {
		t.Errorf("Tags.ListTags returned error: %v", err)
	}

	want := []*Tag{{Name: "1.0.0"}, {Name: "1.0.1"}}
	if !reflect.DeepEqual(want, tags) {
		t.Errorf("Tags.ListTags returned %+v, want %+v", tags, want)
	}
}

func TestTagsService_CreateReleaseNote(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/1/repository/tags/1.0.0/release",
		func(w http.ResponseWriter, r *http.Request) {
			testMethod(t, r, http.MethodPost)
			fmt.Fprint(w, `{"tag_name": "1.0.0", "description": "Amazing release. Wow"}`)
		})

	opt := &CreateReleaseNoteOptions{Description: String("Amazing release. Wow")}

	release, _, err := client.Tags.CreateReleaseNote(1, "1.0.0", opt)
	if err != nil {
		t.Errorf("Tags.CreateRelease returned error: %v", err)
	}

	want := &ReleaseNote{TagName: "1.0.0", Description: "Amazing release. Wow"}
	if !reflect.DeepEqual(want, release) {
		t.Errorf("Tags.CreateRelease returned %+v, want %+v", release, want)
	}
}

func TestTagsService_UpdateReleaseNote(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/1/repository/tags/1.0.0/release",
		func(w http.ResponseWriter, r *http.Request) {
			testMethod(t, r, http.MethodPut)
			fmt.Fprint(w, `{"tag_name": "1.0.0", "description": "Amazing release. Wow!"}`)
		})

	opt := &UpdateReleaseNoteOptions{Description: String("Amazing release. Wow!")}

	release, _, err := client.Tags.UpdateReleaseNote(1, "1.0.0", opt)
	if err != nil {
		t.Errorf("Tags.UpdateRelease returned error: %v", err)
	}

	want := &ReleaseNote{TagName: "1.0.0", Description: "Amazing release. Wow!"}
	if !reflect.DeepEqual(want, release) {
		t.Errorf("Tags.UpdateRelease returned %+v, want %+v", release, want)
	}
}
<commit_msg>Add fields to tests<commit_after>//
// Copyright 2021, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
	"encoding/json"
	"net/http"
	"reflect"
	"testing"
)

func TestTagsService_ListTags(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	tagsJson := `[{"name": "1.0.0", "message": "test", "target": "fffff", "protected": false},{"name": "1.0.1"}]`
	var want []*Tag
	err := json.Unmarshal([]byte(tagsJson), &want)
	if err != nil {
		t.Errorf("Error occured during unmarshaling: %v", err)
	}

	mux.HandleFunc("/api/v4/projects/1/repository/tags", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, http.MethodGet)
		fmt.Fprint(w, tagsJson)
	})

	opt := &ListTagsOptions{ListOptions: ListOptions{Page: 2, PerPage: 3}}

	tags, _, err := client.Tags.ListTags(1, opt)
	if err != nil {
		t.Errorf("Tags.ListTags returned error: %v", err)
	}

	if !reflect.DeepEqual(want, tags) {
		t.Errorf("Tags.ListTags returned %+v, want %+v", tags, want)
	}
}

func TestTagsService_CreateReleaseNote(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/1/repository/tags/1.0.0/release",
		func(w http.ResponseWriter, r *http.Request) {
			testMethod(t, r, http.MethodPost)
			fmt.Fprint(w, `{"tag_name": "1.0.0", "description": "Amazing release. Wow"}`)
		})

	opt := &CreateReleaseNoteOptions{Description: String("Amazing release. Wow")}

	release, _, err := client.Tags.CreateReleaseNote(1, "1.0.0", opt)
	if err != nil {
		t.Errorf("Tags.CreateRelease returned error: %v", err)
	}

	want := &ReleaseNote{TagName: "1.0.0", Description: "Amazing release. Wow"}
	if !reflect.DeepEqual(want, release) {
		t.Errorf("Tags.CreateRelease returned %+v, want %+v", release, want)
	}
}

func TestTagsService_UpdateReleaseNote(t *testing.T) {
	mux, server, client := setup(t)
	defer teardown(server)

	mux.HandleFunc("/api/v4/projects/1/repository/tags/1.0.0/release",
		func(w http.ResponseWriter, r *http.Request) {
			testMethod(t, r, http.MethodPut)
			fmt.Fprint(w, `{"tag_name": "1.0.0", "description": "Amazing release. Wow!"}`)
		})

	opt := &UpdateReleaseNoteOptions{Description: String("Amazing release. Wow!")}

	release, _, err := client.Tags.UpdateReleaseNote(1, "1.0.0", opt)
	if err != nil {
		t.Errorf("Tags.UpdateRelease returned error: %v", err)
	}

	want := &ReleaseNote{TagName: "1.0.0", Description: "Amazing release. Wow!"}
	if !reflect.DeepEqual(want, release) {
		t.Errorf("Tags.UpdateRelease returned %+v, want %+v", release, want)
	}
}
<|endoftext|>


<commit_before>package apiutils

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
)

func RequireParams(form url.Values, params []string) error {
	for _, param := range params {
		if len(form[param]) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

// ReadParams reads in parameters from the request, using the content type.
func ReadParams(r *http.Request) (map[string]interface{}, error) {
	params := make(map[string]interface{})

	if r.Header.Get("Content-Type") == "application/json" {
		decoder := json.NewDecoder(r.Body)
		return params, decoder.Decode(&params)
	} else {
		r.ParseForm()

		// Take first argument, equivalent to Get()
		for k, v := range r.Form {
			params[k] = v[0]
		}

		return params, nil
	}
}

func RequireFormParams(r *http.Request, params []string) error {
	for _, param := range params {
		if len(r.FormValue(param)) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

type ErrorResponse struct {
	Status  int    `json:"status"`
	Message string `json:"message"`
	Error   string `json:"error"`
}

func NewErrorResponse(status int, message string) ErrorResponse {
	return ErrorResponse{
		Status:  status,
		Message: message,
		Error:   http.StatusText(status),
	}
}

func ServeJSON(w http.ResponseWriter, v interface{}) {
	content, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Length", strconv.Itoa(len(content)))
	w.Header().Set("Content-Type", "application/json")
	w.Write(content)
}

func ServeError(w http.ResponseWriter, errRes ErrorResponse) {
	w.WriteHeader(errRes.Status)
	ServeJSON(w, errRes)
}
<commit_msg>ErrorResponse implements the error interface<commit_after>package apiutils

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
)

func RequireParams(form url.Values, params []string) error {
	for _, param := range params {
		if len(form[param]) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

// ReadParams reads in parameters from the request, using the content type.
func ReadParams(r *http.Request) (map[string]interface{}, error) {
	params := make(map[string]interface{})

	if r.Header.Get("Content-Type") == "application/json" {
		decoder := json.NewDecoder(r.Body)
		return params, decoder.Decode(&params)
	} else {
		r.ParseForm()

		// Take first argument, equivalent to Get()
		for k, v := range r.Form {
			params[k] = v[0]
		}

		return params, nil
	}
}

func RequireFormParams(r *http.Request, params []string) error {
	for _, param := range params {
		if len(r.FormValue(param)) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

type ErrorResponse struct {
	Status     int    `json:"status"`
	Message    string `json:"message"`
	StatusText string `json:"error"`
}

func (T ErrorResponse) Error() string {
	return fmt.Sprintf("Error (%d): %s", T.Status, T.Message)
}

func NewErrorResponse(status int, message string) ErrorResponse {
	return ErrorResponse{
		Status:     status,
		Message:    message,
		StatusText: http.StatusText(status),
	}
}

func ServeJSON(w http.ResponseWriter, v interface{}) {
	content, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Length", strconv.Itoa(len(content)))
	w.Header().Set("Content-Type", "application/json")
	w.Write(content)
}

func ServeError(w http.ResponseWriter, errRes ErrorResponse) {
	w.WriteHeader(errRes.Status)
	ServeJSON(w, errRes)
}
<|endoftext|>


<commit_before>// Copyright 2017 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package binding

import (
	"fmt"
	"reflect"
	"strings"
	"sync"

	"github.com/go-playground/validator/v10"
)

type defaultValidator struct {
	once     sync.Once
	validate *validator.Validate
}

type sliceValidateError []error

func (err sliceValidateError) Error() string {
	var errMsgs []string
	for i, e := range err {
		if e == nil {
			continue
		}
		errMsgs = append(errMsgs, fmt.Sprintf("[%d]: %s", i, e.Error()))
	}
	return strings.Join(errMsgs, "\n")
}

var _ StructValidator = &defaultValidator{}

// ValidateStruct receives any kind of type, but only performed struct or pointer to struct type.
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
	if obj == nil {
		return nil
	}

	value := reflect.ValueOf(obj)
	switch value.Kind() {
	case reflect.Ptr:
		return v.ValidateStruct(value.Elem().Interface())
	case reflect.Struct:
		return v.validateStruct(obj)
	case reflect.Slice, reflect.Array:
		count := value.Len()
		validateRet := make(sliceValidateError, 0)
		for i := 0; i < count; i++ {
			if err := v.ValidateStruct(value.Index(i).Interface()); err != nil {
				validateRet = append(validateRet, err)
			}
		}
		if len(validateRet) == 0 {
			return nil
		}
		return validateRet
	default:
		return nil
	}
}

// validateStruct receives struct type
func (v *defaultValidator) validateStruct(obj interface{}) error {
	v.lazyinit()
	return v.validate.Struct(obj)
}

// Engine returns the underlying validator engine which powers the default
// Validator instance. This is useful if you want to register custom validations
// or struct level validations. See validator GoDoc for more info -
// https://godoc.org/gopkg.in/go-playground/validator.v8
func (v *defaultValidator) Engine() interface{} {
	v.lazyinit()
	return v.validate
}

func (v *defaultValidator) lazyinit() {
	v.once.Do(func() {
		v.validate = validator.New()
		v.validate.SetTagName("binding")
	})
}
<commit_msg>Update default validator's docs link (#2738)<commit_after>// Copyright 2017 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package binding

import (
	"fmt"
	"reflect"
	"strings"
	"sync"

	"github.com/go-playground/validator/v10"
)

type defaultValidator struct {
	once     sync.Once
	validate *validator.Validate
}

type sliceValidateError []error

func (err sliceValidateError) Error() string {
	var errMsgs []string
	for i, e := range err {
		if e == nil {
			continue
		}
		errMsgs = append(errMsgs, fmt.Sprintf("[%d]: %s", i, e.Error()))
	}
	return strings.Join(errMsgs, "\n")
}

var _ StructValidator = &defaultValidator{}

// ValidateStruct receives any kind of type, but only performed struct or pointer to struct type.
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
	if obj == nil {
		return nil
	}

	value := reflect.ValueOf(obj)
	switch value.Kind() {
	case reflect.Ptr:
		return v.ValidateStruct(value.Elem().Interface())
	case reflect.Struct:
		return v.validateStruct(obj)
	case reflect.Slice, reflect.Array:
		count := value.Len()
		validateRet := make(sliceValidateError, 0)
		for i := 0; i < count; i++ {
			if err := v.ValidateStruct(value.Index(i).Interface()); err != nil {
				validateRet = append(validateRet, err)
			}
		}
		if len(validateRet) == 0 {
			return nil
		}
		return validateRet
	default:
		return nil
	}
}

// validateStruct receives struct type
func (v *defaultValidator) validateStruct(obj interface{}) error {
	v.lazyinit()
	return v.validate.Struct(obj)
}

// Engine returns the underlying validator engine which powers the default
// Validator instance. This is useful if you want to register custom validations
// or struct level validations. See validator GoDoc for more info -
// https://pkg.go.dev/github.com/go-playground/validator/v10
func (v *defaultValidator) Engine() interface{} {
	v.lazyinit()
	return v.validate
}

func (v *defaultValidator) lazyinit() {
	v.once.Do(func() {
		v.validate = validator.New()
		v.validate.SetTagName("binding")
	})
}
<|endoftext|>