<commit_before>package openshift

import (
	"context"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"

	"github.com/fabric8-services/fabric8-tenant/toggles"
	goajwt "github.com/goadesign/goa/middleware/security/jwt"
	jwt "github.com/dgrijalva/jwt-go"
    "github.com/fabric8-services/fabric8-wit/log"
)

type FilterFunc func(map[interface{}]interface{}) bool

func Filter(vs []map[interface{}]interface{}, f FilterFunc) []map[interface{}]interface{} {
	vsf := make([]map[interface{}]interface{}, 0)
	for _, v := range vs {
		if f(v) {
			vsf = append(vsf, v)
		}
	}
	return vsf
}

func IsOfKind(kinds ...string) FilterFunc {
	return func(vs map[interface{}]interface{}) bool {
		kind := GetKind(vs)
		for _, k := range kinds {
			if k == kind {
				return true
			}
		}
		return false
	}
}

func IsNotOfKind(kinds ...string) FilterFunc {
	f := IsOfKind(kinds...)
	return func(vs map[interface{}]interface{}) bool {
		return !f(vs)
	}
}

func RemoveReplicas(vs []map[interface{}]interface{}) []map[interface{}]interface{} {
	vsf := make([]map[interface{}]interface{}, 0)
	for _, v := range vs {
		if GetKind(v) == ValKindDeploymentConfig {
			if spec, specFound := v[FieldSpec].(map[interface{}]interface{}); specFound {
				delete(spec, FieldReplicas)
			}
		}
		vsf = append(vsf, v)
	}
	return vsf

}

func ProcessTemplate(template, namespace string, vars map[string]string) ([]map[interface{}]interface{}, error) {
	pt, err := Process(template, vars)
	if err != nil {
		return nil, err
	}
	return ParseObjects(pt, namespace)
}

func LoadProcessedTemplates(ctx context.Context, config Config, username string, templateVars map[string]string) ([]map[interface{}]interface{}, error) {
	var objs []map[interface{}]interface{}
	name := CreateName(username)

	vars := map[string]string{
		varProjectName:           name,
		varProjectTemplateName:   name,
		varProjectDisplayName:    name,
		varProjectDescription:    name,
		varProjectUser:           username,
		varProjectRequestingUser: username,
		varProjectAdminUser:      config.MasterUser,
	}

	for k, v := range templateVars {
		if _, exist := vars[k]; !exist {
			vars[k] = v
		}
	}

	extension := "openshift.yml"
	if KubernetesMode() {
		extension = "kubernetes.yml"

		keycloakUrl, err := FindKeyCloakURL(config)
		if err != nil {
			return nil, fmt.Errorf("Could not find the KeyCloak URL: %v", err)
		}
		vars[varKeycloakURL] = keycloakUrl

		projectVars, err := LoadKubernetesProjectVariables()
		if err != nil {
			return nil, err
		}
		for k, v := range projectVars {
			vars[k] = v
		}
	}

	userProjectT, err := loadTemplate(config, "fabric8-tenant-user-project-"+extension)
	if err != nil {
		return nil, err
	}

	userProjectRolesT, err := loadTemplate(config, "fabric8-tenant-user-rolebindings.yml")
	if err != nil {
		return nil, err
	}

	userProjectCollabT, err := loadTemplate(config, "fabric8-tenant-user-colaborators.yml")
	if err != nil {
		return nil, err
	}

	projectT, err := loadTemplate(config, "fabric8-tenant-team-"+extension)
	if err != nil {
		return nil, err
	}

	jenkinsT, err := loadTemplate(config, "fabric8-tenant-jenkins-"+extension)
	if err != nil {
		return nil, err
	}

	cheType := ""
	if toggles.IsEnabled(ctx, "deploy.che-multi-tenant", false) {
		token := goajwt.ContextJWT(ctx)
		if token != nil {
			vars["OSIO_TOKEN"] = token.Raw
			id := token.Claims.(jwt.MapClaims)["sub"]
			if id != nil {
				vars["IDENTITY_ID"] = id
			}
		}
		vars["REQUEST_ID"] = log.ExtractRequestID(ctx)
		cheType = "mt-"
	}

	cheT, err := loadTemplate(config, "fabric8-tenant-che-"+cheType+extension)
	if err != nil {
		return nil, err
	}

	processed, err := ProcessTemplate(string(userProjectT), name, vars)
	if err != nil {
		return nil, err
	}
	objs = append(objs, processed...)

	// TODO have kubernetes versions of these!
	if !KubernetesMode() {

		processed, err = ProcessTemplate(string(userProjectCollabT), name, vars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)

		processed, err = ProcessTemplate(string(userProjectRolesT), name, vars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)
	}

	{
		lvars := clone(vars)
		lvars[varProjectDisplayName] = lvars[varProjectName]

		processed, err = ProcessTemplate(string(projectT), name, lvars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)
	}

	// Quotas needs to be applied before we attempt to install the resources on OSO
	osoQuotas := true
	disableOsoQuotasFlag := os.Getenv("DISABLE_OSO_QUOTAS")
	if disableOsoQuotasFlag == "true" {
		osoQuotas = false
	}
	if osoQuotas && !KubernetesMode() {
		jenkinsQuotasT, err := loadTemplate(config, "fabric8-tenant-jenkins-quotas-oso-"+extension)
		if err != nil {
			return nil, err
		}
		cheQuotasT, err := loadTemplate(config, "fabric8-tenant-che-quotas-oso-"+extension)
		if err != nil {
			return nil, err
		}

		{
			lvars := clone(vars)
			nsname := fmt.Sprintf("%v-jenkins", name)
			lvars[varProjectNamespace] = vars[varProjectName]
			processed, err = ProcessTemplate(string(jenkinsQuotasT), nsname, lvars)
			if err != nil {
				return nil, err
			}
			objs = append(objs, processed...)
		}
		{
			lvars := clone(vars)
			nsname := fmt.Sprintf("%v-che", name)
			lvars[varProjectNamespace] = vars[varProjectName]
			processed, err = ProcessTemplate(string(cheQuotasT), nsname, lvars)
			if err != nil {
				return nil, err
			}
			objs = append(objs, processed...)
		}
	}

	{
		lvars := clone(vars)
		nsname := fmt.Sprintf("%v-jenkins", name)
		lvars[varProjectNamespace] = vars[varProjectName]
		processed, err = ProcessTemplate(string(jenkinsT), nsname, lvars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)
	}
	if KubernetesMode() {
		exposeT, err := loadTemplate(config, "fabric8-tenant-expose-kubernetes.yml")
		if err != nil {
			return nil, err
		}
		exposeVars, err := LoadExposeControllerVariables(config)
		if err != nil {
			return nil, err
		}

		{
			lvars := clone(vars)
			for k, v := range exposeVars {
				lvars[k] = v
			}
			nsname := fmt.Sprintf("%v-jenkins", name)
			lvars[varProjectNamespace] = vars[varProjectName]
			processed, err = ProcessTemplate(string(exposeT), nsname, lvars)
			if err != nil {
				return nil, err
			}
			objs = append(objs, processed...)
		}
		{
			lvars := clone(vars)
			for k, v := range exposeVars {
				lvars[k] = v
			}
			nsname := fmt.Sprintf("%v-che", name)
			lvars[varProjectNamespace] = vars[varProjectName]
			processed, err = ProcessTemplate(string(exposeT), nsname, lvars)
			if err != nil {
				return nil, err
			}
			objs = append(objs, processed...)
		}
	}
	{
		lvars := clone(vars)
		nsname := fmt.Sprintf("%v-che", name)
		lvars[varProjectNamespace] = vars[varProjectName]
		processed, err = ProcessTemplate(string(cheT), nsname, lvars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)
	}

	return objs, nil
}

func MapByNamespaceAndSort(objs []map[interface{}]interface{}) (map[string][]map[interface{}]interface{}, error) {
	ns := map[string][]map[interface{}]interface{}{}
	for _, obj := range objs {
		namespace := GetNamespace(obj)
		if namespace == "" {
			// ProjectRequests and Namespaces are not bound to a Namespace, as it's a Namespace request
			kind := GetKind(obj)
			if kind == ValKindProjectRequest || kind == ValKindNamespace {
				namespace = GetName(obj)
			} else {
				return nil, fmt.Errorf("Object is missing namespace %v", obj)
			}
		}

		if objects, found := ns[namespace]; found {
			objects = append(objects, obj)
			ns[namespace] = objects
		} else {
			objects = []map[interface{}]interface{}{obj}
			ns[namespace] = objects
		}
	}

	for key, val := range ns {
		sort.Sort(ByKind(val))
		ns[key] = val
	}
	return ns, nil
}

// CreateName returns a safe namespace basename based on a username
func CreateName(username string) string {
	return regexp.MustCompile("[^a-z0-9]").ReplaceAllString(strings.Split(username, "@")[0], "-")
}
<commit_msg>syntax error<commit_after>package openshift

import (
	"context"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"

	"github.com/fabric8-services/fabric8-tenant/toggles"
	goajwt "github.com/goadesign/goa/middleware/security/jwt"
	jwt "github.com/dgrijalva/jwt-go"
    "github.com/fabric8-services/fabric8-wit/log"
)

type FilterFunc func(map[interface{}]interface{}) bool

func Filter(vs []map[interface{}]interface{}, f FilterFunc) []map[interface{}]interface{} {
	vsf := make([]map[interface{}]interface{}, 0)
	for _, v := range vs {
		if f(v) {
			vsf = append(vsf, v)
		}
	}
	return vsf
}

func IsOfKind(kinds ...string) FilterFunc {
	return func(vs map[interface{}]interface{}) bool {
		kind := GetKind(vs)
		for _, k := range kinds {
			if k == kind {
				return true
			}
		}
		return false
	}
}

func IsNotOfKind(kinds ...string) FilterFunc {
	f := IsOfKind(kinds...)
	return func(vs map[interface{}]interface{}) bool {
		return !f(vs)
	}
}

func RemoveReplicas(vs []map[interface{}]interface{}) []map[interface{}]interface{} {
	vsf := make([]map[interface{}]interface{}, 0)
	for _, v := range vs {
		if GetKind(v) == ValKindDeploymentConfig {
			if spec, specFound := v[FieldSpec].(map[interface{}]interface{}); specFound {
				delete(spec, FieldReplicas)
			}
		}
		vsf = append(vsf, v)
	}
	return vsf

}

func ProcessTemplate(template, namespace string, vars map[string]string) ([]map[interface{}]interface{}, error) {
	pt, err := Process(template, vars)
	if err != nil {
		return nil, err
	}
	return ParseObjects(pt, namespace)
}

func LoadProcessedTemplates(ctx context.Context, config Config, username string, templateVars map[string]string) ([]map[interface{}]interface{}, error) {
	var objs []map[interface{}]interface{}
	name := CreateName(username)

	vars := map[string]string{
		varProjectName:           name,
		varProjectTemplateName:   name,
		varProjectDisplayName:    name,
		varProjectDescription:    name,
		varProjectUser:           username,
		varProjectRequestingUser: username,
		varProjectAdminUser:      config.MasterUser,
	}

	for k, v := range templateVars {
		if _, exist := vars[k]; !exist {
			vars[k] = v
		}
	}

	extension := "openshift.yml"
	if KubernetesMode() {
		extension = "kubernetes.yml"

		keycloakUrl, err := FindKeyCloakURL(config)
		if err != nil {
			return nil, fmt.Errorf("Could not find the KeyCloak URL: %v", err)
		}
		vars[varKeycloakURL] = keycloakUrl

		projectVars, err := LoadKubernetesProjectVariables()
		if err != nil {
			return nil, err
		}
		for k, v := range projectVars {
			vars[k] = v
		}
	}

	userProjectT, err := loadTemplate(config, "fabric8-tenant-user-project-"+extension)
	if err != nil {
		return nil, err
	}

	userProjectRolesT, err := loadTemplate(config, "fabric8-tenant-user-rolebindings.yml")
	if err != nil {
		return nil, err
	}

	userProjectCollabT, err := loadTemplate(config, "fabric8-tenant-user-colaborators.yml")
	if err != nil {
		return nil, err
	}

	projectT, err := loadTemplate(config, "fabric8-tenant-team-"+extension)
	if err != nil {
		return nil, err
	}

	jenkinsT, err := loadTemplate(config, "fabric8-tenant-jenkins-"+extension)
	if err != nil {
		return nil, err
	}

	cheType := ""
	if toggles.IsEnabled(ctx, "deploy.che-multi-tenant", false) {
		token := goajwt.ContextJWT(ctx)
		if token != nil {
			vars["OSIO_TOKEN"] = token.Raw
			id := token.Claims.(jwt.MapClaims)["sub"]
			if id != nil {
				vars["IDENTITY_ID"] = id.(string)
			}
		}
		vars["REQUEST_ID"] = log.ExtractRequestID(ctx)
		cheType = "mt-"
	}

	cheT, err := loadTemplate(config, "fabric8-tenant-che-"+cheType+extension)
	if err != nil {
		return nil, err
	}

	processed, err := ProcessTemplate(string(userProjectT), name, vars)
	if err != nil {
		return nil, err
	}
	objs = append(objs, processed...)

	// TODO have kubernetes versions of these!
	if !KubernetesMode() {

		processed, err = ProcessTemplate(string(userProjectCollabT), name, vars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)

		processed, err = ProcessTemplate(string(userProjectRolesT), name, vars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)
	}

	{
		lvars := clone(vars)
		lvars[varProjectDisplayName] = lvars[varProjectName]

		processed, err = ProcessTemplate(string(projectT), name, lvars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)
	}

	// Quotas needs to be applied before we attempt to install the resources on OSO
	osoQuotas := true
	disableOsoQuotasFlag := os.Getenv("DISABLE_OSO_QUOTAS")
	if disableOsoQuotasFlag == "true" {
		osoQuotas = false
	}
	if osoQuotas && !KubernetesMode() {
		jenkinsQuotasT, err := loadTemplate(config, "fabric8-tenant-jenkins-quotas-oso-"+extension)
		if err != nil {
			return nil, err
		}
		cheQuotasT, err := loadTemplate(config, "fabric8-tenant-che-quotas-oso-"+extension)
		if err != nil {
			return nil, err
		}

		{
			lvars := clone(vars)
			nsname := fmt.Sprintf("%v-jenkins", name)
			lvars[varProjectNamespace] = vars[varProjectName]
			processed, err = ProcessTemplate(string(jenkinsQuotasT), nsname, lvars)
			if err != nil {
				return nil, err
			}
			objs = append(objs, processed...)
		}
		{
			lvars := clone(vars)
			nsname := fmt.Sprintf("%v-che", name)
			lvars[varProjectNamespace] = vars[varProjectName]
			processed, err = ProcessTemplate(string(cheQuotasT), nsname, lvars)
			if err != nil {
				return nil, err
			}
			objs = append(objs, processed...)
		}
	}

	{
		lvars := clone(vars)
		nsname := fmt.Sprintf("%v-jenkins", name)
		lvars[varProjectNamespace] = vars[varProjectName]
		processed, err = ProcessTemplate(string(jenkinsT), nsname, lvars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)
	}
	if KubernetesMode() {
		exposeT, err := loadTemplate(config, "fabric8-tenant-expose-kubernetes.yml")
		if err != nil {
			return nil, err
		}
		exposeVars, err := LoadExposeControllerVariables(config)
		if err != nil {
			return nil, err
		}

		{
			lvars := clone(vars)
			for k, v := range exposeVars {
				lvars[k] = v
			}
			nsname := fmt.Sprintf("%v-jenkins", name)
			lvars[varProjectNamespace] = vars[varProjectName]
			processed, err = ProcessTemplate(string(exposeT), nsname, lvars)
			if err != nil {
				return nil, err
			}
			objs = append(objs, processed...)
		}
		{
			lvars := clone(vars)
			for k, v := range exposeVars {
				lvars[k] = v
			}
			nsname := fmt.Sprintf("%v-che", name)
			lvars[varProjectNamespace] = vars[varProjectName]
			processed, err = ProcessTemplate(string(exposeT), nsname, lvars)
			if err != nil {
				return nil, err
			}
			objs = append(objs, processed...)
		}
	}
	{
		lvars := clone(vars)
		nsname := fmt.Sprintf("%v-che", name)
		lvars[varProjectNamespace] = vars[varProjectName]
		processed, err = ProcessTemplate(string(cheT), nsname, lvars)
		if err != nil {
			return nil, err
		}
		objs = append(objs, processed...)
	}

	return objs, nil
}

func MapByNamespaceAndSort(objs []map[interface{}]interface{}) (map[string][]map[interface{}]interface{}, error) {
	ns := map[string][]map[interface{}]interface{}{}
	for _, obj := range objs {
		namespace := GetNamespace(obj)
		if namespace == "" {
			// ProjectRequests and Namespaces are not bound to a Namespace, as it's a Namespace request
			kind := GetKind(obj)
			if kind == ValKindProjectRequest || kind == ValKindNamespace {
				namespace = GetName(obj)
			} else {
				return nil, fmt.Errorf("Object is missing namespace %v", obj)
			}
		}

		if objects, found := ns[namespace]; found {
			objects = append(objects, obj)
			ns[namespace] = objects
		} else {
			objects = []map[interface{}]interface{}{obj}
			ns[namespace] = objects
		}
	}

	for key, val := range ns {
		sort.Sort(ByKind(val))
		ns[key] = val
	}
	return ns, nil
}

// CreateName returns a safe namespace basename based on a username
func CreateName(username string) string {
	return regexp.MustCompile("[^a-z0-9]").ReplaceAllString(strings.Split(username, "@")[0], "-")
}
<|endoftext|>


<commit_before>package gendb

import (
	"bytes"
	"encoding/json"
	"fmt"
	"path"
	"sort"
	"strings"
	"text/template"

	"github.com/Clever/wag/v8/swagger"
	"github.com/awslabs/goformation/v2/cloudformation/resources"
	"github.com/go-openapi/spec"
	"github.com/go-swagger/go-swagger/generator"
)

//go:generate go-bindata -nometadata -ignore .*\.go$ -pkg gendb -prefix $PWD/server/gendb/ $PWD/server/gendb/
//go:generate gofmt -w bindata.go

const xdbExtensionKey = "x-db"

// XDBConfig is the configuration that exists in swagger.yml for auto-generated database code.
type XDBConfig struct {
	// AllowOverwrites sets whether saving an object that already exists should fail.
	AllowOverwrites bool

	// CompositeAttributes encodes attributes that are composed of multiple properties in the schema.
	CompositeAttributes []CompositeAttribute

	// AllowBatchWrites determines whether a batch write method should be generated for the table.
	AllowBatchWrites bool

	// AllowPrimaryIndexScan determines whether methods should be generated that scan the primary index.
	AllowPrimaryIndexScan bool

	// AllowSecondaryIndexScan determines whether methods should be generated that scan each of the secondary indexes.
	AllowSecondaryIndexScan []string

	// DynamoDB configuration.
	DynamoDB AWSDynamoDBTable

	// EnableTransactions determines which schemas this schema will be able to perform transactions with. It only needs to be set for one per pair.
	EnableTransactions []string

	// SwaggerSpec, Schema and SchemaName that the config was contained within.
	SwaggerSpec spec.Swagger
	Schema      spec.Schema
	SchemaName  string
}

// CompositeAttribute is an attribute that is composed of multiple properties in the object's schema.
type CompositeAttribute struct {
	AttributeName string
	Properties    []string
	Separator     string
}

// Validate checks that the user enter a valid x-db config.
func (config XDBConfig) Validate(schemaNames []string) error {
	// check that all attribute names show up in the schema or in composite attribute defs.
	for _, ks := range config.DynamoDB.KeySchema {
		if err := config.attributeNameIsDefined(ks.AttributeName); err != nil {
			return err
		}
	}
	for _, gsi := range config.DynamoDB.GlobalSecondaryIndexes {
		for _, ks := range gsi.KeySchema {
			if err := config.attributeNameIsDefined(ks.AttributeName); err != nil {
				return err
			}
		}
	}
	// check that the transaction config is valid i.e. each schema name is valid
	for _, t := range config.EnableTransactions {
		if !contains(t, schemaNames) {
			return fmt.Errorf("invalid transaction config for %s: no matching schema %s", config.SchemaName, t)
		}
	}
	return nil
}

// attributeNameIsDefined checks whether a user has provided an AttributeName that
// is either contained as a property in the swagger schema or defined as a composite
// attribute.
func (config XDBConfig) attributeNameIsDefined(attributeName string) error {
	if _, ok := config.Schema.SchemaProps.Properties[attributeName]; ok {
		return nil
	} else if ca := findCompositeAttribute(config, attributeName); ca != nil {
		return nil
	}
	return fmt.Errorf("unrecognized attribute: '%s'. AttributeNames must match schema properties or be defined as composite attributes", attributeName)
}

// AWSDynamoDBTable is a subset of clouformation.AWSDynamoDBTable. Currently supported fields:
// -.DynamoDB.KeySchema: configures primary key
// future/todo:
// - GlobalSecondaryIndexes
// - TableName (if you want something other than pascalized model name)
type AWSDynamoDBTable struct {
	KeySchema              []resources.AWSDynamoDBTable_KeySchema            `json:"KeySchema,omitempty"`
	GlobalSecondaryIndexes []resources.AWSDynamoDBTable_GlobalSecondaryIndex `json:"GlobalSecondaryIndexes,omitempty"`
}

// DecodeConfig extracts a db configuration from the schema definition, if one exists.
func DecodeConfig(schemaName string, schema spec.Schema, swaggerSpec spec.Swagger) (*XDBConfig, error) {
	var config *XDBConfig
	for k, v := range schema.VendorExtensible.Extensions {
		switch k {
		case xdbExtensionKey:
			bs, _ := json.Marshal(v)
			if err := json.Unmarshal(bs, &config); err != nil {
				return nil, err
			}
			break
		}
	}
	if config != nil {
		config.SchemaName = schemaName
		config.Schema = schema
		config.SwaggerSpec = swaggerSpec
		if config.DynamoDB.KeySchema == nil || len(config.DynamoDB.KeySchema) == 0 {
			return nil, fmt.Errorf("x-db DynamoDB config must contain.DynamoDB.KeySchema: %s", schemaName)
		}
	}
	return config, nil
}

func findCompositeAttribute(config XDBConfig, attributeName string) *CompositeAttribute {
	for _, compositeAttr := range config.CompositeAttributes {
		if compositeAttr.AttributeName == attributeName {
			return &compositeAttr
		}
	}
	return nil

}

// GenerateDB generates DB code for schemas annotated with the x-db extension.
func GenerateDB(packageName, packagePath string, s *spec.Swagger, outputPath string) error {
	var schemaNames []string
	for schemaName := range s.Definitions {
		schemaNames = append(schemaNames, schemaName)
	}

	var xdbConfigs []XDBConfig
	for schemaName, schema := range s.Definitions {
		if config, err := DecodeConfig(schemaName, schema, *s); err != nil {
			return err
		} else if config != nil {
			if err := config.Validate(schemaNames); err != nil {
				return err
			}
			xdbConfigs = append(xdbConfigs, *config)
		}
	}
	if len(xdbConfigs) == 0 {
		return nil
	}
	sort.Slice(xdbConfigs, func(i, j int) bool { return xdbConfigs[i].SchemaName < xdbConfigs[j].SchemaName })

	writeTemplate := func(tmplFilename, outputFilename string, data interface{}) error {
		tmpl, err := template.New(tmplFilename).
			Funcs(generator.FuncMapFunc(generator.DefaultLanguageFunc())).
			Funcs(funcMap).
			Parse(string(MustAsset(tmplFilename)))
		if err != nil {
			return err
		}

		var tmpBuf bytes.Buffer
		err = tmpl.Execute(&tmpBuf, data)
		if err != nil {
			return err
		}

		g := swagger.Generator{PackagePath: packagePath}
		g.Printf(tmpBuf.String())
		return g.WriteFile(outputFilename)
	}

	type writeTemplateInput struct {
		tmplFilename   string
		outputFilename string
		data           interface{}
	}
	wtis := []writeTemplateInput{
		{
			tmplFilename:   "dynamodb-local.sh.tmpl",
			outputFilename: path.Join(outputPath, "dynamodb/dynamodb-local.sh"),
			data:           nil,
		},
		{
			tmplFilename:   "dynamodb.go.tmpl",
			outputFilename: path.Join(outputPath, "dynamodb/dynamodb.go"),
			data: map[string]interface{}{
				"PackageName": packageName,
				"XDBConfigs":  xdbConfigs,
				"OutputPath":  outputPath,
			},
		},
		{
			tmplFilename:   "dynamodb_test.go.tmpl",
			outputFilename: path.Join(outputPath, "dynamodb/dynamodb_test.go"),
			data: map[string]interface{}{
				"PackageName": packageName,
				"OutputPath":  outputPath,
			},
		},
		{
			tmplFilename:   "interface.go.tmpl",
			outputFilename: path.Join(outputPath, "interface.go"),
			data: map[string]interface{}{
				"PackageName": packageName,
				"ServiceName": s.Info.InfoProps.Title,
				"XDBConfigs":  xdbConfigs,
			},
		},
		{
			tmplFilename:   "tests.go.tmpl",
			outputFilename: path.Join(outputPath, "tests/tests.go"),
			data: map[string]interface{}{
				"PackageName": packageName,
				"XDBConfigs":  xdbConfigs,
				"OutputPath":  outputPath,
			},
		},
	}
	for _, xdbConfig := range xdbConfigs {
		wtis = append(wtis, writeTemplateInput{
			tmplFilename:   "table.go.tmpl",
			outputFilename: path.Join(outputPath, "dynamodb", fmt.Sprintf("%v.go", strings.ToLower(xdbConfig.SchemaName))),
			data: map[string]interface{}{
				"PackageName": packageName,
				"XDBConfig":   xdbConfig,
				"OutputPath":  outputPath,
			},
		})
	}

	for _, wti := range wtis {
		if err := writeTemplate(wti.tmplFilename, wti.outputFilename, wti.data); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>parse attirbute definitions from swagger file<commit_after>package gendb

import (
	"bytes"
	"encoding/json"
	"fmt"
	"path"
	"sort"
	"strings"
	"text/template"

	"github.com/Clever/wag/v8/swagger"
	"github.com/awslabs/goformation/v2/cloudformation/resources"
	"github.com/go-openapi/spec"
	"github.com/go-swagger/go-swagger/generator"
)

//go:generate go-bindata -nometadata -ignore .*\.go$ -pkg gendb -prefix $PWD/server/gendb/ $PWD/server/gendb/
//go:generate gofmt -w bindata.go

const xdbExtensionKey = "x-db"

// XDBConfig is the configuration that exists in swagger.yml for auto-generated database code.
type XDBConfig struct {
	// AllowOverwrites sets whether saving an object that already exists should fail.
	AllowOverwrites bool

	// CompositeAttributes encodes attributes that are composed of multiple properties in the schema.
	CompositeAttributes []CompositeAttribute

	// AllowBatchWrites determines whether a batch write method should be generated for the table.
	AllowBatchWrites bool

	// AllowPrimaryIndexScan determines whether methods should be generated that scan the primary index.
	AllowPrimaryIndexScan bool

	// AllowSecondaryIndexScan determines whether methods should be generated that scan each of the secondary indexes.
	AllowSecondaryIndexScan []string

	// DynamoDB configuration.
	DynamoDB AWSDynamoDBTable

	// EnableTransactions determines which schemas this schema will be able to perform transactions with. It only needs to be set for one per pair.
	EnableTransactions []string

	// SwaggerSpec, Schema and SchemaName that the config was contained within.
	SwaggerSpec spec.Swagger
	Schema      spec.Schema
	SchemaName  string
}

// CompositeAttribute is an attribute that is composed of multiple properties in the object's schema.
type CompositeAttribute struct {
	AttributeName string
	Properties    []string
	Separator     string
}

// Validate checks that the user enter a valid x-db config.
func (config XDBConfig) Validate(schemaNames []string) error {
	// check that all attribute names show up in the schema or in composite attribute defs.
	for _, ks := range config.DynamoDB.KeySchema {
		if err := config.attributeNameIsDefined(ks.AttributeName); err != nil {
			return err
		}
	}
	for _, gsi := range config.DynamoDB.GlobalSecondaryIndexes {
		for _, ks := range gsi.KeySchema {
			if err := config.attributeNameIsDefined(ks.AttributeName); err != nil {
				return err
			}
		}
	}
	// check that the transaction config is valid i.e. each schema name is valid
	for _, t := range config.EnableTransactions {
		if !contains(t, schemaNames) {
			return fmt.Errorf("invalid transaction config for %s: no matching schema %s", config.SchemaName, t)
		}
	}
	return nil
}

// attributeNameIsDefined checks whether a user has provided an AttributeName that
// is either contained as a property in the swagger schema or defined as a composite
// attribute.
func (config XDBConfig) attributeNameIsDefined(attributeName string) error {
	if _, ok := config.Schema.SchemaProps.Properties[attributeName]; ok {
		return nil
	} else if ca := findCompositeAttribute(config, attributeName); ca != nil {
		return nil
	}
	return fmt.Errorf("unrecognized attribute: '%s'. AttributeNames must match schema properties or be defined as composite attributes", attributeName)
}

// AWSDynamoDBTable is a subset of clouformation.AWSDynamoDBTable. Currently supported fields:
// -.DynamoDB.KeySchema: configures primary key
// future/todo:
// - GlobalSecondaryIndexes
// - TableName (if you want something other than pascalized model name)
type AWSDynamoDBTable struct {
	KeySchema              []resources.AWSDynamoDBTable_KeySchema            `json:"KeySchema,omitempty"`
	GlobalSecondaryIndexes []resources.AWSDynamoDBTable_GlobalSecondaryIndex `json:"GlobalSecondaryIndexes,omitempty"`
	AttributesDefinitions  []resources.AWSDynamoDBTable_AttributeDefinition  `json:"AttributeDefinitions,omitempty"`
}

// DecodeConfig extracts a db configuration from the schema definition, if one exists.
func DecodeConfig(schemaName string, schema spec.Schema, swaggerSpec spec.Swagger) (*XDBConfig, error) {
	var config *XDBConfig
	for k, v := range schema.VendorExtensible.Extensions {
		switch k {
		case xdbExtensionKey:
			bs, _ := json.Marshal(v)
			if err := json.Unmarshal(bs, &config); err != nil {
				return nil, err
			}
			break
		}
	}
	if config != nil {
		config.SchemaName = schemaName
		config.Schema = schema
		config.SwaggerSpec = swaggerSpec
		if config.DynamoDB.KeySchema == nil || len(config.DynamoDB.KeySchema) == 0 {
			return nil, fmt.Errorf("x-db DynamoDB config must contain.DynamoDB.KeySchema: %s", schemaName)
		}
	}
	return config, nil
}

func findCompositeAttribute(config XDBConfig, attributeName string) *CompositeAttribute {
	for _, compositeAttr := range config.CompositeAttributes {
		if compositeAttr.AttributeName == attributeName {
			return &compositeAttr
		}
	}
	return nil

}

// GenerateDB generates DB code for schemas annotated with the x-db extension.
func GenerateDB(packageName, packagePath string, s *spec.Swagger, outputPath string) error {
	var schemaNames []string
	for schemaName := range s.Definitions {
		schemaNames = append(schemaNames, schemaName)
	}

	var xdbConfigs []XDBConfig
	for schemaName, schema := range s.Definitions {
		if config, err := DecodeConfig(schemaName, schema, *s); err != nil {
			return err
		} else if config != nil {
			if err := config.Validate(schemaNames); err != nil {
				return err
			}
			xdbConfigs = append(xdbConfigs, *config)
		}
	}
	if len(xdbConfigs) == 0 {
		return nil
	}
	sort.Slice(xdbConfigs, func(i, j int) bool { return xdbConfigs[i].SchemaName < xdbConfigs[j].SchemaName })

	writeTemplate := func(tmplFilename, outputFilename string, data interface{}) error {
		tmpl, err := template.New(tmplFilename).
			Funcs(generator.FuncMapFunc(generator.DefaultLanguageFunc())).
			Funcs(funcMap).
			Parse(string(MustAsset(tmplFilename)))
		if err != nil {
			return err
		}

		var tmpBuf bytes.Buffer
		err = tmpl.Execute(&tmpBuf, data)
		if err != nil {
			return err
		}

		g := swagger.Generator{PackagePath: packagePath}
		g.Printf(tmpBuf.String())
		return g.WriteFile(outputFilename)
	}

	type writeTemplateInput struct {
		tmplFilename   string
		outputFilename string
		data           interface{}
	}
	wtis := []writeTemplateInput{
		{
			tmplFilename:   "dynamodb-local.sh.tmpl",
			outputFilename: path.Join(outputPath, "dynamodb/dynamodb-local.sh"),
			data:           nil,
		},
		{
			tmplFilename:   "dynamodb.go.tmpl",
			outputFilename: path.Join(outputPath, "dynamodb/dynamodb.go"),
			data: map[string]interface{}{
				"PackageName": packageName,
				"XDBConfigs":  xdbConfigs,
				"OutputPath":  outputPath,
			},
		},
		{
			tmplFilename:   "dynamodb_test.go.tmpl",
			outputFilename: path.Join(outputPath, "dynamodb/dynamodb_test.go"),
			data: map[string]interface{}{
				"PackageName": packageName,
				"OutputPath":  outputPath,
			},
		},
		{
			tmplFilename:   "interface.go.tmpl",
			outputFilename: path.Join(outputPath, "interface.go"),
			data: map[string]interface{}{
				"PackageName": packageName,
				"ServiceName": s.Info.InfoProps.Title,
				"XDBConfigs":  xdbConfigs,
			},
		},
		{
			tmplFilename:   "tests.go.tmpl",
			outputFilename: path.Join(outputPath, "tests/tests.go"),
			data: map[string]interface{}{
				"PackageName": packageName,
				"XDBConfigs":  xdbConfigs,
				"OutputPath":  outputPath,
			},
		},
	}
	for _, xdbConfig := range xdbConfigs {
		wtis = append(wtis, writeTemplateInput{
			tmplFilename:   "table.go.tmpl",
			outputFilename: path.Join(outputPath, "dynamodb", fmt.Sprintf("%v.go", strings.ToLower(xdbConfig.SchemaName))),
			data: map[string]interface{}{
				"PackageName": packageName,
				"XDBConfig":   xdbConfig,
				"OutputPath":  outputPath,
			},
		})
	}

	for _, wti := range wtis {
		if err := writeTemplate(wti.tmplFilename, wti.outputFilename, wti.data); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/timeredbull/gandalf/db"
	"github.com/timeredbull/gandalf/repository"
	"github.com/timeredbull/gandalf/user"
	"io"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"net/http"
	"reflect"
)

func GrantAccess(w http.ResponseWriter, r *http.Request) {
	repo := repository.Repository{Name: r.URL.Query().Get(":name")}
	c := db.Session.Repository()
	c.Find(bson.M{"_id": repo.Name}).One(&repo)
	req := map[string][]string{}
	err := parseBody(r.Body, &req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	for _, u := range req["users"] {
		_, err = getUserOr404(u)
		if err != nil {
			if len(req["users"]) == 1 {
				http.Error(w, err.Error(), http.StatusNotFound)
				return
			} else {
				// #TODO (flaviamissi): log a warning saying the user "u" was not found and skip it
				continue
			}
		}
		repo.Users = append(repo.Users, u)
	}
	err = c.Update(bson.M{"_id": repo.Name}, &repo)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func AddKey(w http.ResponseWriter, r *http.Request) {
	u := user.User{Name: r.URL.Query().Get(":name")}
	c := db.Session.User()
	err := c.Find(bson.M{"_id": u.Name}).One(&u)
	if err != nil {
		http.Error(w, "User not found", http.StatusNotFound)
		return
	}
	params := map[string]string{}
	err = parseBody(r.Body, &params)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if params["key"] == "" {
		http.Error(w, "A key is needed", http.StatusBadRequest)
		return
	}
	u.Keys = append(u.Keys, params["key"])
	err = c.Update(bson.M{"_id": u.Name}, u)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Key \"%s\" successfuly created", params["key"])
}

func NewUser(w http.ResponseWriter, r *http.Request) {
	var u user.User
	err := parseBody(r.Body, &u)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if u.Name == "" {
		http.Error(w, "User needs a name", http.StatusBadRequest)
		return
	}
	err = db.Session.User().Insert(&u)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "User %s successfuly created", u.Name)
}

func NewRepository(w http.ResponseWriter, r *http.Request) {
	var repo repository.Repository
	err := parseBody(r.Body, &repo)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
    rep, err := repository.New(repo.Name, repo.Users, repo.IsPublic)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "Repository %s successfuly created", rep.Name)
}

func parseBody(body io.ReadCloser, result interface{}) error {
	if reflect.ValueOf(result).Kind() == reflect.Struct {
		return errors.New("parseBody function cannot deal with struct. Use pointer")
	}
	b, err := ioutil.ReadAll(body)
	if err != nil {
		return err
	}
	err = json.Unmarshal(b, &result)
	if err != nil {
		e := fmt.Sprintf("Could not parse json: %s", err.Error())
		return errors.New(e)
	}
	return nil
}
<commit_msg>api: go fmt<commit_after>package api

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/timeredbull/gandalf/db"
	"github.com/timeredbull/gandalf/repository"
	"github.com/timeredbull/gandalf/user"
	"io"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"net/http"
	"reflect"
)

func GrantAccess(w http.ResponseWriter, r *http.Request) {
	repo := repository.Repository{Name: r.URL.Query().Get(":name")}
	c := db.Session.Repository()
	c.Find(bson.M{"_id": repo.Name}).One(&repo)
	req := map[string][]string{}
	err := parseBody(r.Body, &req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	for _, u := range req["users"] {
		_, err = getUserOr404(u)
		if err != nil {
			if len(req["users"]) == 1 {
				http.Error(w, err.Error(), http.StatusNotFound)
				return
			} else {
				// #TODO (flaviamissi): log a warning saying the user "u" was not found and skip it
				continue
			}
		}
		repo.Users = append(repo.Users, u)
	}
	err = c.Update(bson.M{"_id": repo.Name}, &repo)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func AddKey(w http.ResponseWriter, r *http.Request) {
	u := user.User{Name: r.URL.Query().Get(":name")}
	c := db.Session.User()
	err := c.Find(bson.M{"_id": u.Name}).One(&u)
	if err != nil {
		http.Error(w, "User not found", http.StatusNotFound)
		return
	}
	params := map[string]string{}
	err = parseBody(r.Body, &params)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if params["key"] == "" {
		http.Error(w, "A key is needed", http.StatusBadRequest)
		return
	}
	u.Keys = append(u.Keys, params["key"])
	err = c.Update(bson.M{"_id": u.Name}, u)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Key \"%s\" successfuly created", params["key"])
}

func NewUser(w http.ResponseWriter, r *http.Request) {
	var u user.User
	err := parseBody(r.Body, &u)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if u.Name == "" {
		http.Error(w, "User needs a name", http.StatusBadRequest)
		return
	}
	err = db.Session.User().Insert(&u)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "User %s successfuly created", u.Name)
}

func NewRepository(w http.ResponseWriter, r *http.Request) {
	var repo repository.Repository
	err := parseBody(r.Body, &repo)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	rep, err := repository.New(repo.Name, repo.Users, repo.IsPublic)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	fmt.Fprintf(w, "Repository %s successfuly created", rep.Name)
}

func parseBody(body io.ReadCloser, result interface{}) error {
	if reflect.ValueOf(result).Kind() == reflect.Struct {
		return errors.New("parseBody function cannot deal with struct. Use pointer")
	}
	b, err := ioutil.ReadAll(body)
	if err != nil {
		return err
	}
	err = json.Unmarshal(b, &result)
	if err != nil {
		e := fmt.Sprintf("Could not parse json: %s", err.Error())
		return errors.New(e)
	}
	return nil
}
<|endoftext|>


<commit_before>package api

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

var (
	ErrRenewerMissingInput  = errors.New("missing input to renewer")
	ErrRenewerMissingSecret = errors.New("missing secret to renew")
	ErrRenewerNotRenewable  = errors.New("secret is not renewable")
	ErrRenewerNoSecretData  = errors.New("returned empty secret data")

	// DefaultRenewerGrace is the default grace period
	DefaultRenewerGrace = 15 * time.Second

	// DefaultRenewerRenewBuffer is the default size of the buffer for renew
	// messages on the channel.
	DefaultRenewerRenewBuffer = 5
)

// Renewer is a process for renewing a secret.
//
// 	renewer, err := client.NewRenewer(&RenewerInput{
// 		Secret: mySecret,
// 	})
// 	go renewer.Renew()
// 	defer renewer.Stop()
//
// 	for {
// 		select {
// 		case err := <-renewer.DoneCh():
// 			if err != nil {
// 				log.Fatal(err)
// 			}
//
// 			// Renewal is now over
// 		case renewal := <-renewer.RenewCh():
// 			log.Printf("Successfully renewed: %#v", renewal)
// 		}
// 	}
//
//
// The `DoneCh` will return if renewal fails or if the remaining lease duration
// after a renewal is less than or equal to the grace (in number of seconds). In
// both cases, the caller should attempt a re-read of the secret. Clients should
// check the return value of the channel to see if renewal was successful.
type Renewer struct {
	l sync.Mutex

	client    *Client
	secret    *Secret
	grace     time.Duration
	random    *rand.Rand
	increment int
	doneCh    chan error
	renewCh   chan *RenewOutput

	stopped bool
	stopCh  chan struct{}
}

// RenewerInput is used as input to the renew function.
type RenewerInput struct {
	// Secret is the secret to renew
	Secret *Secret

	// Grace is a minimum renewal before returning so the upstream client
	// can do a re-read. This can be used to prevent clients from waiting
	// too long to read a new credential and incur downtime.
	Grace time.Duration

	// Rand is the randomizer to use for underlying randomization. If not
	// provided, one will be generated and seeded automatically. If provided, it
	// is assumed to have already been seeded.
	Rand *rand.Rand

	// RenewBuffer is the size of the buffered channel where renew messages are
	// dispatched.
	RenewBuffer int

	// The new TTL, in seconds, that should be set on the lease. The TTL set
	// here may or may not be honored by the vault server, based on Vault
	// configuration or any associated max TTL values.
	Increment int
}

// RenewOutput is the metadata returned to the client (if it's listening) to
// renew messages.
type RenewOutput struct {
	// RenewedAt is the timestamp when the renewal took place (UTC).
	RenewedAt time.Time

	// Secret is the underlying renewal data. It's the same struct as all data
	// that is returned from Vault, but since this is renewal data, it will not
	// usually include the secret itself.
	Secret *Secret
}

// NewRenewer creates a new renewer from the given input.
func (c *Client) NewRenewer(i *RenewerInput) (*Renewer, error) {
	if i == nil {
		return nil, ErrRenewerMissingInput
	}

	secret := i.Secret
	if secret == nil {
		return nil, ErrRenewerMissingSecret
	}

	grace := i.Grace
	if grace == 0 {
		grace = DefaultRenewerGrace
	}

	random := i.Rand
	if random == nil {
		random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
	}

	renewBuffer := i.RenewBuffer
	if renewBuffer == 0 {
		renewBuffer = DefaultRenewerRenewBuffer
	}

	return &Renewer{
		client:    c,
		secret:    secret,
		grace:     grace,
		increment: i.Increment,
		random:    random,
		doneCh:    make(chan error, 1),
		renewCh:   make(chan *RenewOutput, renewBuffer),

		stopped: false,
		stopCh:  make(chan struct{}),
	}, nil
}

// DoneCh returns the channel where the renewer will publish when renewal stops.
// If there is an error, this will be an error.
func (r *Renewer) DoneCh() <-chan error {
	return r.doneCh
}

// RenewCh is a channel that receives a message when a successful renewal takes
// place and includes metadata about the renewal.
func (r *Renewer) RenewCh() <-chan *RenewOutput {
	return r.renewCh
}

// Stop stops the renewer.
func (r *Renewer) Stop() {
	r.l.Lock()
	if !r.stopped {
		close(r.stopCh)
		r.stopped = true
	}
	r.l.Unlock()
}

// Renew starts a background process for renewing this secret. When the secret
// is has auth data, this attempts to renew the auth (token). When the secret
// has a lease, this attempts to renew the lease.
func (r *Renewer) Renew() {
	var result error
	if r.secret.Auth != nil {
		result = r.renewAuth()
	} else {
		result = r.renewLease()
	}

	select {
	case r.doneCh <- result:
	case <-r.stopCh:
	}
}

// renewAuth is a helper for renewing authentication.
func (r *Renewer) renewAuth() error {
	if !r.secret.Auth.Renewable || r.secret.Auth.ClientToken == "" {
		return ErrRenewerNotRenewable
	}

	client, token := r.client, r.secret.Auth.ClientToken

	for {
		// Check if we are stopped.
		select {
		case <-r.stopCh:
			return nil
		default:
		}

		// Renew the auth.
		renewal, err := client.Auth().Token().RenewTokenAsSelf(token, r.increment)
		if err != nil {
			return err
		}

		// Push a message that a renewal took place.
		select {
		case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
		default:
		}

		// Somehow, sometimes, this happens.
		if renewal == nil || renewal.Auth == nil {
			return ErrRenewerNoSecretData
		}

		// Do nothing if we are not renewable
		if !renewal.Auth.Renewable {
			return ErrRenewerNotRenewable
		}

		// Grab the lease duration and sleep duration - note that we grab the auth
		// lease duration, not the secret lease duration.
		leaseDuration := time.Duration(renewal.Auth.LeaseDuration) * time.Second
		sleepDuration := r.sleepDuration(leaseDuration)

		// If we are within grace, return now.
		if leaseDuration <= r.grace || sleepDuration <= r.grace {
			return nil
		}

		select {
		case <-r.stopCh:
			return nil
		case <-time.After(sleepDuration):
			continue
		}
	}
}

// renewLease is a helper for renewing a lease.
func (r *Renewer) renewLease() error {
	if !r.secret.Renewable || r.secret.LeaseID == "" {
		return ErrRenewerNotRenewable
	}

	client, leaseID := r.client, r.secret.LeaseID

	for {
		// Check if we are stopped.
		select {
		case <-r.stopCh:
			return nil
		default:
		}

		// Renew the lease.
		renewal, err := client.Sys().Renew(leaseID, r.increment)
		if err != nil {
			return err
		}

		// Push a message that a renewal took place.
		select {
		case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
		default:
		}

		// Somehow, sometimes, this happens.
		if renewal == nil {
			return ErrRenewerNoSecretData
		}

		// Do nothing if we are not renewable
		if !renewal.Renewable {
			return ErrRenewerNotRenewable
		}

		// Grab the lease duration and sleep duration
		leaseDuration := time.Duration(renewal.LeaseDuration) * time.Second
		sleepDuration := r.sleepDuration(leaseDuration)

		// If we are within grace, return now.
		if leaseDuration <= r.grace || sleepDuration <= r.grace {
			return nil
		}

		select {
		case <-r.stopCh:
			return nil
		case <-time.After(sleepDuration):
			continue
		}
	}
}

// sleepDuration calculates the time to sleep given the base lease duration. The
// base is the resulting lease duration. It will be reduced to 1/3 and
// multiplied by a random float between 0.0 and 1.0. This extra randomness
// prevents multiple clients from all trying to renew simultaneously.
func (r *Renewer) sleepDuration(base time.Duration) time.Duration {
	sleep := float64(base)

	// Renew at 1/3 the remaining lease. This will give us an opportunity to retry
	// at least one more time should the first renewal fail.
	sleep = sleep / 3.0

	// Use a randomness so many clients do not hit Vault simultaneously.
	sleep = sleep * (r.random.Float64() + 1) / 2.0

	return time.Duration(sleep)
}
<commit_msg>Fix typo (remove +is) (#4104)<commit_after>package api

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

var (
	ErrRenewerMissingInput  = errors.New("missing input to renewer")
	ErrRenewerMissingSecret = errors.New("missing secret to renew")
	ErrRenewerNotRenewable  = errors.New("secret is not renewable")
	ErrRenewerNoSecretData  = errors.New("returned empty secret data")

	// DefaultRenewerGrace is the default grace period
	DefaultRenewerGrace = 15 * time.Second

	// DefaultRenewerRenewBuffer is the default size of the buffer for renew
	// messages on the channel.
	DefaultRenewerRenewBuffer = 5
)

// Renewer is a process for renewing a secret.
//
// 	renewer, err := client.NewRenewer(&RenewerInput{
// 		Secret: mySecret,
// 	})
// 	go renewer.Renew()
// 	defer renewer.Stop()
//
// 	for {
// 		select {
// 		case err := <-renewer.DoneCh():
// 			if err != nil {
// 				log.Fatal(err)
// 			}
//
// 			// Renewal is now over
// 		case renewal := <-renewer.RenewCh():
// 			log.Printf("Successfully renewed: %#v", renewal)
// 		}
// 	}
//
//
// The `DoneCh` will return if renewal fails or if the remaining lease duration
// after a renewal is less than or equal to the grace (in number of seconds). In
// both cases, the caller should attempt a re-read of the secret. Clients should
// check the return value of the channel to see if renewal was successful.
type Renewer struct {
	l sync.Mutex

	client    *Client
	secret    *Secret
	grace     time.Duration
	random    *rand.Rand
	increment int
	doneCh    chan error
	renewCh   chan *RenewOutput

	stopped bool
	stopCh  chan struct{}
}

// RenewerInput is used as input to the renew function.
type RenewerInput struct {
	// Secret is the secret to renew
	Secret *Secret

	// Grace is a minimum renewal before returning so the upstream client
	// can do a re-read. This can be used to prevent clients from waiting
	// too long to read a new credential and incur downtime.
	Grace time.Duration

	// Rand is the randomizer to use for underlying randomization. If not
	// provided, one will be generated and seeded automatically. If provided, it
	// is assumed to have already been seeded.
	Rand *rand.Rand

	// RenewBuffer is the size of the buffered channel where renew messages are
	// dispatched.
	RenewBuffer int

	// The new TTL, in seconds, that should be set on the lease. The TTL set
	// here may or may not be honored by the vault server, based on Vault
	// configuration or any associated max TTL values.
	Increment int
}

// RenewOutput is the metadata returned to the client (if it's listening) to
// renew messages.
type RenewOutput struct {
	// RenewedAt is the timestamp when the renewal took place (UTC).
	RenewedAt time.Time

	// Secret is the underlying renewal data. It's the same struct as all data
	// that is returned from Vault, but since this is renewal data, it will not
	// usually include the secret itself.
	Secret *Secret
}

// NewRenewer creates a new renewer from the given input.
func (c *Client) NewRenewer(i *RenewerInput) (*Renewer, error) {
	if i == nil {
		return nil, ErrRenewerMissingInput
	}

	secret := i.Secret
	if secret == nil {
		return nil, ErrRenewerMissingSecret
	}

	grace := i.Grace
	if grace == 0 {
		grace = DefaultRenewerGrace
	}

	random := i.Rand
	if random == nil {
		random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
	}

	renewBuffer := i.RenewBuffer
	if renewBuffer == 0 {
		renewBuffer = DefaultRenewerRenewBuffer
	}

	return &Renewer{
		client:    c,
		secret:    secret,
		grace:     grace,
		increment: i.Increment,
		random:    random,
		doneCh:    make(chan error, 1),
		renewCh:   make(chan *RenewOutput, renewBuffer),

		stopped: false,
		stopCh:  make(chan struct{}),
	}, nil
}

// DoneCh returns the channel where the renewer will publish when renewal stops.
// If there is an error, this will be an error.
func (r *Renewer) DoneCh() <-chan error {
	return r.doneCh
}

// RenewCh is a channel that receives a message when a successful renewal takes
// place and includes metadata about the renewal.
func (r *Renewer) RenewCh() <-chan *RenewOutput {
	return r.renewCh
}

// Stop stops the renewer.
func (r *Renewer) Stop() {
	r.l.Lock()
	if !r.stopped {
		close(r.stopCh)
		r.stopped = true
	}
	r.l.Unlock()
}

// Renew starts a background process for renewing this secret. When the secret
// has auth data, this attempts to renew the auth (token). When the secret has
// a lease, this attempts to renew the lease.
func (r *Renewer) Renew() {
	var result error
	if r.secret.Auth != nil {
		result = r.renewAuth()
	} else {
		result = r.renewLease()
	}

	select {
	case r.doneCh <- result:
	case <-r.stopCh:
	}
}

// renewAuth is a helper for renewing authentication.
func (r *Renewer) renewAuth() error {
	if !r.secret.Auth.Renewable || r.secret.Auth.ClientToken == "" {
		return ErrRenewerNotRenewable
	}

	client, token := r.client, r.secret.Auth.ClientToken

	for {
		// Check if we are stopped.
		select {
		case <-r.stopCh:
			return nil
		default:
		}

		// Renew the auth.
		renewal, err := client.Auth().Token().RenewTokenAsSelf(token, r.increment)
		if err != nil {
			return err
		}

		// Push a message that a renewal took place.
		select {
		case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
		default:
		}

		// Somehow, sometimes, this happens.
		if renewal == nil || renewal.Auth == nil {
			return ErrRenewerNoSecretData
		}

		// Do nothing if we are not renewable
		if !renewal.Auth.Renewable {
			return ErrRenewerNotRenewable
		}

		// Grab the lease duration and sleep duration - note that we grab the auth
		// lease duration, not the secret lease duration.
		leaseDuration := time.Duration(renewal.Auth.LeaseDuration) * time.Second
		sleepDuration := r.sleepDuration(leaseDuration)

		// If we are within grace, return now.
		if leaseDuration <= r.grace || sleepDuration <= r.grace {
			return nil
		}

		select {
		case <-r.stopCh:
			return nil
		case <-time.After(sleepDuration):
			continue
		}
	}
}

// renewLease is a helper for renewing a lease.
func (r *Renewer) renewLease() error {
	if !r.secret.Renewable || r.secret.LeaseID == "" {
		return ErrRenewerNotRenewable
	}

	client, leaseID := r.client, r.secret.LeaseID

	for {
		// Check if we are stopped.
		select {
		case <-r.stopCh:
			return nil
		default:
		}

		// Renew the lease.
		renewal, err := client.Sys().Renew(leaseID, r.increment)
		if err != nil {
			return err
		}

		// Push a message that a renewal took place.
		select {
		case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
		default:
		}

		// Somehow, sometimes, this happens.
		if renewal == nil {
			return ErrRenewerNoSecretData
		}

		// Do nothing if we are not renewable
		if !renewal.Renewable {
			return ErrRenewerNotRenewable
		}

		// Grab the lease duration and sleep duration
		leaseDuration := time.Duration(renewal.LeaseDuration) * time.Second
		sleepDuration := r.sleepDuration(leaseDuration)

		// If we are within grace, return now.
		if leaseDuration <= r.grace || sleepDuration <= r.grace {
			return nil
		}

		select {
		case <-r.stopCh:
			return nil
		case <-time.After(sleepDuration):
			continue
		}
	}
}

// sleepDuration calculates the time to sleep given the base lease duration. The
// base is the resulting lease duration. It will be reduced to 1/3 and
// multiplied by a random float between 0.0 and 1.0. This extra randomness
// prevents multiple clients from all trying to renew simultaneously.
func (r *Renewer) sleepDuration(base time.Duration) time.Duration {
	sleep := float64(base)

	// Renew at 1/3 the remaining lease. This will give us an opportunity to retry
	// at least one more time should the first renewal fail.
	sleep = sleep / 3.0

	// Use a randomness so many clients do not hit Vault simultaneously.
	sleep = sleep * (r.random.Float64() + 1) / 2.0

	return time.Duration(sleep)
}
<|endoftext|>


<commit_before>package mvm

import (
	"time"

	"golang.org/x/text/language"

	"github.com/jinzhu/gorm"
)

// Show is a movie or an episode of a series
type Show struct {
	gorm.Model
	CommonData

	ReleaseDate time.Time `json:"release_date"`
	Tagline     string    `json:"tagline"`

	EpisodeData *EpisodeData `json:"episode_data"`

	Files []*VideoFile `json:"files",gorm:"ForeignKey:ShowID"`
}

// CommonData contains fields shared by movies, episodes and series
type CommonData struct {
	ImdbID      int               `json:"imdb_id",sql:"unique"`
	Title       string            `json:"title"`
	Year        uint              `json:"year"`
	OtherTitles map[string]string `json:"other_titles"`
	Duration    time.Duration     `json:"duration"`
	Plot        string            `json:"plot"`
	PlotMedium  string            `json:"plot_medium"`
	PlotLong    string            `json:"plot_long"`
	PosterURL   string            `json:"poster_url"`
	ImdbRating  float32           `json:"imdb_rating"`
	ImdbVotes   int               `json:"imdb_votes"`
	Languages   []language.Base   `json:"languages"`
}

// EpisodeData contains episode-specific keys
type EpisodeData struct {
	ID       uint `gorm:"primary_key"`
	Season   int  `json:"season"`
	Episode  int  `json:"episode"`
	SeriesID uint
}

// Series represents a series
type Series struct {
	gorm.Model
	CommonData

	Episodes []*Show `json:"episodes",gorm:"ForeignKey:SeriesID"`
}

// VideoFile reprsesents a file for an episode or movie
type VideoFile struct {
	gorm.Model

	Filename   string        `json:"filename"`
	FileSize   uint          `json:"filesize"`
	Resolution [2]uint       `json:"resolution"`
	Format     string        `json:"format"`
	Duration   time.Duration `json:"duration"`

	LastPlayed   time.Time     `json:"last_played"`
	LastPosition time.Duration `json:"last_position"`

	ShowID uint
}
<commit_msg>add osdb hash to video file<commit_after>package mvm

import (
	"time"

	"golang.org/x/text/language"

	"github.com/jinzhu/gorm"
)

// Show is a movie or an episode of a series
type Show struct {
	gorm.Model
	CommonData

	ReleaseDate time.Time `json:"release_date"`
	Tagline     string    `json:"tagline"`

	EpisodeData *EpisodeData `json:"episode_data"`

	Files []*VideoFile `json:"files",gorm:"ForeignKey:ShowID"`
}

// CommonData contains fields shared by movies, episodes and series
type CommonData struct {
	ImdbID      int               `json:"imdb_id",sql:"unique"`
	Title       string            `json:"title"`
	Year        uint              `json:"year"`
	OtherTitles map[string]string `json:"other_titles"`
	Duration    time.Duration     `json:"duration"`
	Plot        string            `json:"plot"`
	PlotMedium  string            `json:"plot_medium"`
	PlotLong    string            `json:"plot_long"`
	PosterURL   string            `json:"poster_url"`
	ImdbRating  float32           `json:"imdb_rating"`
	ImdbVotes   int               `json:"imdb_votes"`
	Languages   []language.Base   `json:"languages"`
}

// EpisodeData contains episode-specific keys
type EpisodeData struct {
	ID       uint `gorm:"primary_key"`
	Season   int  `json:"season"`
	Episode  int  `json:"episode"`
	SeriesID uint
}

// Series represents a series
type Series struct {
	gorm.Model
	CommonData

	Episodes []*Show `json:"episodes",gorm:"ForeignKey:SeriesID"`
}

// VideoFile reprsesents a file for an episode or movie
type VideoFile struct {
	gorm.Model

	Filename   string        `json:"filename"`
	FileSize   uint          `json:"filesize"`
	Resolution [2]uint       `json:"resolution"`
	OsdbHash   uint          `json:"osdb_hash"`
	Format     string        `json:"format"`
	Duration   time.Duration `json:"duration"`

	LastPlayed   time.Time     `json:"last_played"`
	LastPosition time.Duration `json:"last_position"`

	ShowID uint
}
<|endoftext|>


<commit_before>package libp2ptls

import (
	"context"
	"crypto/tls"
	"errors"
	"net"
	"os"

	ci "github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/sec"
)

// TLS 1.3 is opt-in in Go 1.12
// Activate it by setting the tls13 GODEBUG flag.
func init() {
	os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1")
}

// ID is the protocol ID (used when negotiating with multistream)
const ID = "/tls/1.0.0"

// Transport constructs secure communication sessions for a peer.
type Transport struct {
	identity *Identity

	localPeer peer.ID
	privKey   ci.PrivKey
}

// New creates a TLS encrypted transport
func New(key ci.PrivKey) (*Transport, error) {
	id, err := peer.IDFromPrivateKey(key)
	if err != nil {
		return nil, err
	}
	t := &Transport{
		localPeer: id,
		privKey:   key,
	}

	identity, err := NewIdentity(key)
	if err != nil {
		return nil, err
	}
	t.identity = identity
	return t, nil
}

var _ sec.SecureTransport = &Transport{}

// SecureInbound runs the TLS handshake as a server.
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (sec.SecureConn, error) {
	config, keyCh := t.identity.ConfigForAny()
	return t.handshake(ctx, tls.Server(insecure, config), keyCh)
}

// SecureOutbound runs the TLS handshake as a client.
// Note that SecureOutbound will not return an error if the server doesn't
// accept the certificate. This is due to the fact that in TLS 1.3, the client
// sends its certificate and the ClientFinished in the same flight, and can send
// application data immediately afterwards.
// If the handshake fails, the server will close the connection. The client will
// notice this after 1 RTT when calling Read.
func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
	config, keyCh := t.identity.ConfigForPeer(p)
	return t.handshake(ctx, tls.Client(insecure, config), keyCh)
}

func (t *Transport) handshake(
	ctx context.Context,
	tlsConn *tls.Conn,
	keyCh <-chan ci.PubKey,
) (sec.SecureConn, error) {
	// There's no way to pass a context to tls.Conn.Handshake().
	// See https://github.com/golang/go/issues/18482.
	// Close the connection instead.
	select {
	case <-ctx.Done():
		tlsConn.Close()
	default:
	}
	done := make(chan struct{})
	defer close(done)
	go func() {
		select {
		case <-done:
		case <-ctx.Done():
			tlsConn.Close()
		}
	}()

	if err := tlsConn.Handshake(); err != nil {
		// if the context was canceled, return the context error
		if ctxErr := ctx.Err(); ctxErr != nil {
			return nil, ctxErr
		}
		return nil, err
	}

	// Should be ready by this point, don't block.
	var remotePubKey ci.PubKey
	select {
	case remotePubKey = <-keyCh:
	default:
	}

	conn, err := t.setupConn(tlsConn, remotePubKey)
	if err != nil {
		// if the context was canceled, return the context error
		if ctxErr := ctx.Err(); ctxErr != nil {
			return nil, ctxErr
		}
		return nil, err
	}
	return conn, nil
}

func (t *Transport) setupConn(tlsConn *tls.Conn, remotePubKey ci.PubKey) (sec.SecureConn, error) {
	if remotePubKey == nil {
		return nil, errors.New("go-libp2p-tls BUG: expected remote pub key to be set")
	}

	remotePeerID, err := peer.IDFromPublicKey(remotePubKey)
	if err != nil {
		return nil, err
	}
	return &conn{
		Conn:         tlsConn,
		localPeer:    t.localPeer,
		privKey:      t.privKey,
		remotePeer:   remotePeerID,
		remotePubKey: remotePubKey,
	}, nil
}
<commit_msg>make the error check for not receiving a public key more explicit<commit_after>package libp2ptls

import (
	"context"
	"crypto/tls"
	"errors"
	"net"
	"os"

	ci "github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/sec"
)

// TLS 1.3 is opt-in in Go 1.12
// Activate it by setting the tls13 GODEBUG flag.
func init() {
	os.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tls13=1")
}

// ID is the protocol ID (used when negotiating with multistream)
const ID = "/tls/1.0.0"

// Transport constructs secure communication sessions for a peer.
type Transport struct {
	identity *Identity

	localPeer peer.ID
	privKey   ci.PrivKey
}

// New creates a TLS encrypted transport
func New(key ci.PrivKey) (*Transport, error) {
	id, err := peer.IDFromPrivateKey(key)
	if err != nil {
		return nil, err
	}
	t := &Transport{
		localPeer: id,
		privKey:   key,
	}

	identity, err := NewIdentity(key)
	if err != nil {
		return nil, err
	}
	t.identity = identity
	return t, nil
}

var _ sec.SecureTransport = &Transport{}

// SecureInbound runs the TLS handshake as a server.
func (t *Transport) SecureInbound(ctx context.Context, insecure net.Conn) (sec.SecureConn, error) {
	config, keyCh := t.identity.ConfigForAny()
	return t.handshake(ctx, tls.Server(insecure, config), keyCh)
}

// SecureOutbound runs the TLS handshake as a client.
// Note that SecureOutbound will not return an error if the server doesn't
// accept the certificate. This is due to the fact that in TLS 1.3, the client
// sends its certificate and the ClientFinished in the same flight, and can send
// application data immediately afterwards.
// If the handshake fails, the server will close the connection. The client will
// notice this after 1 RTT when calling Read.
func (t *Transport) SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
	config, keyCh := t.identity.ConfigForPeer(p)
	return t.handshake(ctx, tls.Client(insecure, config), keyCh)
}

func (t *Transport) handshake(
	ctx context.Context,
	tlsConn *tls.Conn,
	keyCh <-chan ci.PubKey,
) (sec.SecureConn, error) {
	// There's no way to pass a context to tls.Conn.Handshake().
	// See https://github.com/golang/go/issues/18482.
	// Close the connection instead.
	select {
	case <-ctx.Done():
		tlsConn.Close()
	default:
	}
	done := make(chan struct{})
	defer close(done)
	go func() {
		select {
		case <-done:
		case <-ctx.Done():
			tlsConn.Close()
		}
	}()

	if err := tlsConn.Handshake(); err != nil {
		// if the context was canceled, return the context error
		if ctxErr := ctx.Err(); ctxErr != nil {
			return nil, ctxErr
		}
		return nil, err
	}

	// Should be ready by this point, don't block.
	var remotePubKey ci.PubKey
	select {
	case remotePubKey = <-keyCh:
	default:
	}
	if remotePubKey == nil {
		return nil, errors.New("go-libp2p-tls BUG: expected remote pub key to be set")
	}

	conn, err := t.setupConn(tlsConn, remotePubKey)
	if err != nil {
		// if the context was canceled, return the context error
		if ctxErr := ctx.Err(); ctxErr != nil {
			return nil, ctxErr
		}
		return nil, err
	}
	return conn, nil
}

func (t *Transport) setupConn(tlsConn *tls.Conn, remotePubKey ci.PubKey) (sec.SecureConn, error) {
	remotePeerID, err := peer.IDFromPublicKey(remotePubKey)
	if err != nil {
		return nil, err
	}
	return &conn{
		Conn:         tlsConn,
		localPeer:    t.localPeer,
		privKey:      t.privKey,
		remotePeer:   remotePeerID,
		remotePubKey: remotePubKey,
	}, nil
}
<|endoftext|>


<commit_before>package app

import (
	"math/rand"
	"os"
	"strconv"

	"github.com/asaintgenis/catapi/data/cat"
)

func searchImage() cat.Cat {
	randomInt := rand.Intn(2) + 1
	fileName := "./ressources/" + strconv.Itoa(randomInt) + ".jpg"
	catFile, err := os.Open(fileName)
	if err != nil {
		panic("open fail")
	}
	content := make([]byte, 1024)
	catFile.Read(content)
	cat := cat.Cat{ID: "1", Pic: content}
	return cat
}
<commit_msg>panic in catretriever now take err as param<commit_after>package app

import (
	"math/rand"
	"os"
	"strconv"

	"github.com/asaintgenis/catapi/data/cat"
)

func searchImage() cat.Cat {
	randomInt := rand.Intn(2) + 1
	fileName := "./ressources/" + strconv.Itoa(randomInt) + ".jpg"
	catFile, err := os.Open(fileName)
	if err != nil {
		panic(err)
	}
	content := make([]byte, 1024)
	catFile.Read(content)
	cat := cat.Cat{ID: "1", Pic: content}
	return cat
}
<|endoftext|>


<commit_before>package memcached

import (
	"bufio"
	"bytes"
	"io/ioutil"
	"reflect"
	"testing"

	"github.com/dustin/gomemcached"
)

func TestTransmitRes(t *testing.T) {
	b := &bytes.Buffer{}
	buf := bufio.NewWriter(b)

	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 0x338,
		Key:    []byte("somekey"),
		Body:   []byte("somevalue"),
	}

	err := transmitResponse(buf, &res)
	if err != nil {
		t.Fatalf("Error transmitting request: %v", err)
	}

	buf.Flush()

	expected := []byte{
		gomemcached.RES_MAGIC, byte(gomemcached.SET),
		0x0, 0x7, // length of key
		0x0,       // extra length
		0x0,       // reserved
		0x3, 0x38, // Status
		0x0, 0x0, 0x0, 0x10, // Length of value
		0x0, 0x0, 0x1c, 0x4a, // opaque
		0x0, 0x0, 0x0, 0x0, 0x37, 0xef, 0x3a, 0x35, // CAS
		's', 'o', 'm', 'e', 'k', 'e', 'y',
		's', 'o', 'm', 'e', 'v', 'a', 'l', 'u', 'e'}

	if len(b.Bytes()) != res.Size() {
		t.Fatalf("Expected %v bytes, got %v", res.Size(),
			len(b.Bytes()))
	}

	if !reflect.DeepEqual(b.Bytes(), expected) {
		t.Fatalf("Expected:\n%#v\n  -- got -- \n%#v",
			expected, b.Bytes())
	}
}

func BenchmarkTransmitRes(b *testing.B) {
	bout := &bytes.Buffer{}

	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 824,
		Key:    []byte("somekey"),
		Body:   []byte("somevalue"),
	}

	b.SetBytes(int64(res.Size()))

	for i := 0; i < b.N; i++ {
		bout.Reset()
		buf := bufio.NewWriterSize(bout, res.Size()*2)
		err := transmitResponse(buf, &res)
		if err != nil {
			b.Fatalf("Error transmitting request: %v", err)
		}
	}
}

func BenchmarkTransmitResLarge(b *testing.B) {
	bout := &bytes.Buffer{}

	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 824,
		Key:    []byte("somekey"),
		Body:   make([]byte, 24*1024),
	}

	b.SetBytes(int64(res.Size()))

	for i := 0; i < b.N; i++ {
		bout.Reset()
		buf := bufio.NewWriterSize(bout, res.Size()*2)
		err := transmitResponse(buf, &res)
		if err != nil {
			b.Fatalf("Error transmitting request: %v", err)
		}
	}
}

func BenchmarkTransmitResNull(b *testing.B) {
	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 824,
		Key:    []byte("somekey"),
		Body:   []byte("somevalue"),
	}

	b.SetBytes(int64(res.Size()))

	for i := 0; i < b.N; i++ {
		err := transmitResponse(ioutil.Discard, &res)
		if err != nil {
			b.Fatalf("Error transmitting request: %v", err)
		}
	}
}

func TestMust(t *testing.T) {
	must(nil)
	errored := false
	func() {
		defer func() { _, errored = recover().(error) }()
		must(&gomemcached.MCResponse{})
	}()
}

func BenchmarkReceive(b *testing.B) {
	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 824,
		Key:    []byte("somekey"),
		Body:   []byte("somevalue"),
	}

	datum := res.Bytes()
	datum[0] = gomemcached.REQ_MAGIC
	b.SetBytes(int64(len(datum)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := ReadPacket(bytes.NewReader(datum))
		if err != nil {
			b.Fatalf("Failed to read: %v", err)
		}
	}
}
<commit_msg>test func handler<commit_after>package memcached

import (
	"bufio"
	"bytes"
	"io"
	"io/ioutil"
	"reflect"
	"testing"

	"github.com/dustin/gomemcached"
)

func TestTransmitRes(t *testing.T) {
	b := &bytes.Buffer{}
	buf := bufio.NewWriter(b)

	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 0x338,
		Key:    []byte("somekey"),
		Body:   []byte("somevalue"),
	}

	err := transmitResponse(buf, &res)
	if err != nil {
		t.Fatalf("Error transmitting request: %v", err)
	}

	buf.Flush()

	expected := []byte{
		gomemcached.RES_MAGIC, byte(gomemcached.SET),
		0x0, 0x7, // length of key
		0x0,       // extra length
		0x0,       // reserved
		0x3, 0x38, // Status
		0x0, 0x0, 0x0, 0x10, // Length of value
		0x0, 0x0, 0x1c, 0x4a, // opaque
		0x0, 0x0, 0x0, 0x0, 0x37, 0xef, 0x3a, 0x35, // CAS
		's', 'o', 'm', 'e', 'k', 'e', 'y',
		's', 'o', 'm', 'e', 'v', 'a', 'l', 'u', 'e'}

	if len(b.Bytes()) != res.Size() {
		t.Fatalf("Expected %v bytes, got %v", res.Size(),
			len(b.Bytes()))
	}

	if !reflect.DeepEqual(b.Bytes(), expected) {
		t.Fatalf("Expected:\n%#v\n  -- got -- \n%#v",
			expected, b.Bytes())
	}
}

func BenchmarkTransmitRes(b *testing.B) {
	bout := &bytes.Buffer{}

	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 824,
		Key:    []byte("somekey"),
		Body:   []byte("somevalue"),
	}

	b.SetBytes(int64(res.Size()))

	for i := 0; i < b.N; i++ {
		bout.Reset()
		buf := bufio.NewWriterSize(bout, res.Size()*2)
		err := transmitResponse(buf, &res)
		if err != nil {
			b.Fatalf("Error transmitting request: %v", err)
		}
	}
}

func BenchmarkTransmitResLarge(b *testing.B) {
	bout := &bytes.Buffer{}

	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 824,
		Key:    []byte("somekey"),
		Body:   make([]byte, 24*1024),
	}

	b.SetBytes(int64(res.Size()))

	for i := 0; i < b.N; i++ {
		bout.Reset()
		buf := bufio.NewWriterSize(bout, res.Size()*2)
		err := transmitResponse(buf, &res)
		if err != nil {
			b.Fatalf("Error transmitting request: %v", err)
		}
	}
}

func BenchmarkTransmitResNull(b *testing.B) {
	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 824,
		Key:    []byte("somekey"),
		Body:   []byte("somevalue"),
	}

	b.SetBytes(int64(res.Size()))

	for i := 0; i < b.N; i++ {
		err := transmitResponse(ioutil.Discard, &res)
		if err != nil {
			b.Fatalf("Error transmitting request: %v", err)
		}
	}
}

func TestMust(t *testing.T) {
	must(nil)
	errored := false
	func() {
		defer func() { _, errored = recover().(error) }()
		must(&gomemcached.MCResponse{})
	}()
}

func TestFuncHandler(t *testing.T) {
	ran := false
	h := FuncHandler(func(io.Writer, *gomemcached.MCRequest) *gomemcached.MCResponse {
		ran = true
		return nil
	})
	h.HandleMessage(nil, nil)
	if !ran {
		t.Fatalf("Didn't run our custom function")
	}
}

func BenchmarkReceive(b *testing.B) {
	res := gomemcached.MCResponse{
		Opcode: gomemcached.SET,
		Cas:    938424885,
		Opaque: 7242,
		Status: 824,
		Key:    []byte("somekey"),
		Body:   []byte("somevalue"),
	}

	datum := res.Bytes()
	datum[0] = gomemcached.REQ_MAGIC
	b.SetBytes(int64(len(datum)))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := ReadPacket(bytes.NewReader(datum))
		if err != nil {
			b.Fatalf("Failed to read: %v", err)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package shrug

import (
	"fmt"
	"regexp"

	"github.com/sirupsen/logrus"

	"k8s.io/test-infra/prow/github"
	"k8s.io/test-infra/prow/plugins"
)

const pluginName = "shrug"

var (
	shrugLabel = "¯\\_(ツ)_/¯"
	shrugRe    = regexp.MustCompile(`(?mi)^/shrug\s*$`)
	unshrugRe  = regexp.MustCompile(`(?mi)^/unshrug\s*$`)
)

type event struct {
	org           string
	repo          string
	number        int
	prAuthor      string
	commentAuthor string
	body          string
	assignees     []github.User
	hasLabel      func(label string) (bool, error)
	htmlurl       string
}

func init() {
	plugins.RegisterGenericCommentHandler(pluginName, handleGenericComment, nil)
}

type githubClient interface {
	AddLabel(owner, repo string, number int, label string) error
	CreateComment(owner, repo string, number int, comment string) error
	RemoveLabel(owner, repo string, number int, label string) error
	GetIssueLabels(org, repo string, number int) ([]github.Label, error)
}

func handleGenericComment(pc plugins.PluginClient, e github.GenericCommentEvent) error {
	return handle(pc.GitHubClient, pc.Logger, &e)
}

func handle(gc githubClient, log *logrus.Entry, e *github.GenericCommentEvent) error {
	if e.Action != github.GenericCommentActionCreated {
		return nil
	}

	wantShrug := false
	if shrugRe.MatchString(e.Body) {
		wantShrug = true
	} else if unshrugRe.MatchString(e.Body) {
		wantShrug = false
	} else {
		return nil
	}

	org := e.Repo.Owner.Login
	repo := e.Repo.Name

	// Only add the label if it doesn't have it yet.
	hasShrug := false
	labels, err := gc.GetIssueLabels(org, repo, e.Number)
	if err != nil {
		log.WithError(err).Errorf("Failed to get the labels on %s/%s#%d.", org, repo, e.Number)
	}
	for _, candidate := range labels {
		if candidate.Name == shrugLabel {
			hasShrug = true
			break
		}
	}
	if hasShrug && !wantShrug {
		log.Info("Removing Shrug label.")
		resp := "¯\\\\\\_(ツ)\\_/¯"
		log.Infof("Commenting with \"%s\".", resp)
		if err := gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, resp)); err != nil {
			return fmt.Errorf("failed to comment on %s/%s#%d: %v", org, repo, e.Number, err)
		}
		return gc.RemoveLabel(org, repo, e.Number, shrugLabel)
	} else if !hasShrug && wantShrug {
		log.Info("Adding Shrug label.")
		return gc.AddLabel(org, repo, e.Number, shrugLabel)
	}
	return nil
}
<commit_msg>add shrug help<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package shrug

import (
	"fmt"
	"regexp"

	"github.com/sirupsen/logrus"

	"k8s.io/test-infra/prow/github"
	"k8s.io/test-infra/prow/pluginhelp"
	"k8s.io/test-infra/prow/plugins"
)

const pluginName = "shrug"

var (
	shrugLabel = "¯\\_(ツ)_/¯"
	shrugRe    = regexp.MustCompile(`(?mi)^/shrug\s*$`)
	unshrugRe  = regexp.MustCompile(`(?mi)^/unshrug\s*$`)
)

type event struct {
	org           string
	repo          string
	number        int
	prAuthor      string
	commentAuthor string
	body          string
	assignees     []github.User
	hasLabel      func(label string) (bool, error)
	htmlurl       string
}

func init() {
	plugins.RegisterGenericCommentHandler(pluginName, handleGenericComment, helpProvider)
}

func helpProvider(config *plugins.Configuration, enabledRepos []string) (*pluginhelp.PluginHelp, error) {
	// The Config field is omitted because this plugin is not configurable.
	pluginHelp := &pluginhelp.PluginHelp{
		Description: shrugLabel,
	}
	pluginHelp.AddCommand(pluginhelp.Command{
		Usage:       "/[un]shrug",
		Description: shrugLabel,
		Featured:    false,
		WhoCanUse:   "Anyone, " + shrugLabel,
		Examples:    []string{"/shrug", "/unshrug"},
	})
	return pluginHelp, nil
}

type githubClient interface {
	AddLabel(owner, repo string, number int, label string) error
	CreateComment(owner, repo string, number int, comment string) error
	RemoveLabel(owner, repo string, number int, label string) error
	GetIssueLabels(org, repo string, number int) ([]github.Label, error)
}

func handleGenericComment(pc plugins.PluginClient, e github.GenericCommentEvent) error {
	return handle(pc.GitHubClient, pc.Logger, &e)
}

func handle(gc githubClient, log *logrus.Entry, e *github.GenericCommentEvent) error {
	if e.Action != github.GenericCommentActionCreated {
		return nil
	}

	wantShrug := false
	if shrugRe.MatchString(e.Body) {
		wantShrug = true
	} else if unshrugRe.MatchString(e.Body) {
		wantShrug = false
	} else {
		return nil
	}

	org := e.Repo.Owner.Login
	repo := e.Repo.Name

	// Only add the label if it doesn't have it yet.
	hasShrug := false
	labels, err := gc.GetIssueLabels(org, repo, e.Number)
	if err != nil {
		log.WithError(err).Errorf("Failed to get the labels on %s/%s#%d.", org, repo, e.Number)
	}
	for _, candidate := range labels {
		if candidate.Name == shrugLabel {
			hasShrug = true
			break
		}
	}
	if hasShrug && !wantShrug {
		log.Info("Removing Shrug label.")
		resp := "¯\\\\\\_(ツ)\\_/¯"
		log.Infof("Commenting with \"%s\".", resp)
		if err := gc.CreateComment(org, repo, e.Number, plugins.FormatResponseRaw(e.Body, e.HTMLURL, e.User.Login, resp)); err != nil {
			return fmt.Errorf("failed to comment on %s/%s#%d: %v", org, repo, e.Number, err)
		}
		return gc.RemoveLabel(org, repo, e.Number, shrugLabel)
	} else if !hasShrug && wantShrug {
		log.Info("Adding Shrug label.")
		return gc.AddLabel(org, repo, e.Number, shrugLabel)
	}
	return nil
}
<|endoftext|>


<commit_before>package basicauth

import (
	"fmt"
	"net/http"
)

var (
	// DEBUG is debug mode.
	// Set to true to enable debug messages.
	DEBUG bool = false
)

const (
	DefBasicRealmStr = "Please input username and password" // Default "Basic realm"
)

// Arguments is used to customize Basic Auth UI(Ex: "Basic realm" string
type Arguments struct {
	BasicRealmStr string // "Basic realm" string
}

// BasicAuth provides function to process HTTP Basic Auth
type BasicAuth struct {
	UserName string    // User Name
	Password string    // Password
	Args     Arguments // Arguments to customize Basic Auth UI(Ex: "Basic realm" string).
}

// New() creates a new BasicAuth with default arguments.
func New(username, password string) (ba *BasicAuth) {
	return &BasicAuth{username, password, Arguments{DefBasicRealmStr}}
}

// NewWithArgs() creates a new BasicAuth with user's arguments(Ex: "Basic realm" string).
//
// See Arguments for more.
func NewWithArgs(username, password string, args Arguments) (ba *BasicAuth) {
	return &BasicAuth{username, password, args}
}

// IsOK() checks HTTP Basic Auth.
func (ba *BasicAuth) IsOK(w http.ResponseWriter, r *http.Request) bool {
	username, password, ok := r.BasicAuth()
	if !ok {
		if DEBUG {
			fmt.Printf("r.BasicAuth() failed.\n")
		}
		goto end
	}

	if username != ba.UserName || password != ba.Password {
		ok = false
		goto end
	}

end:
	if !ok {
		w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%v"`, ba.Args.BasicRealmStr))
		w.WriteHeader(401)
	}
	return ok
}
<commit_msg>Remove () after func names in comments to remove golint warnings.<commit_after>package basicauth

import (
	"fmt"
	"net/http"
)

var (
	// DEBUG is debug mode.
	// Set to true to enable debug messages.
	DEBUG bool = false
)

const (
	DefBasicRealmStr = "Please input username and password" // Default "Basic realm"
)

// Arguments is used to customize Basic Auth UI(Ex: "Basic realm" string
type Arguments struct {
	BasicRealmStr string // "Basic realm" string
}

// BasicAuth provides function to process HTTP Basic Auth
type BasicAuth struct {
	UserName string    // User Name
	Password string    // Password
	Args     Arguments // Arguments to customize Basic Auth UI(Ex: "Basic realm" string).
}

// New creates a new BasicAuth with default arguments.
func New(username, password string) (ba *BasicAuth) {
	return &BasicAuth{username, password, Arguments{DefBasicRealmStr}}
}

// NewWithArgs creates a new BasicAuth with user's arguments(Ex: "Basic realm" string).
//
// See Arguments for more.
func NewWithArgs(username, password string, args Arguments) (ba *BasicAuth) {
	return &BasicAuth{username, password, args}
}

// IsOK checks HTTP Basic Auth.
func (ba *BasicAuth) IsOK(w http.ResponseWriter, r *http.Request) bool {
	username, password, ok := r.BasicAuth()
	if !ok {
		if DEBUG {
			fmt.Printf("r.BasicAuth() failed.\n")
		}
		goto end
	}

	if username != ba.UserName || password != ba.Password {
		ok = false
		goto end
	}

end:
	if !ok {
		w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%v"`, ba.Args.BasicRealmStr))
		w.WriteHeader(401)
	}
	return ok
}
<|endoftext|>


<commit_before>package units

import (
	"fmt"
	"strconv"
)

// ParseByteSizeString parses a human representation of an amount of
// data into a number of bytes
func ParseByteSizeString(input string) (int64, error) {
	// Empty input
	if input == "" {
		return 0, nil
	}

	// Find where the suffix begins
	suffixLen := 0
	for i, chr := range []byte(input) {
		_, err := strconv.Atoi(string([]byte{chr}))
		if err != nil {
			suffixLen = len(input) - i
			break
		}
	}

	if suffixLen == len(input) {
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	// Extract the suffix
	suffix := input[len(input)-suffixLen:]

	// Extract the value
	value := input[0 : len(input)-suffixLen]
	valueInt, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return -1, fmt.Errorf("Invalid integer: %s", input)
	}

	// Figure out the multiplicator
	multiplicator := int64(0)
	switch suffix {
	case "", "B", " bytes":
		multiplicator = 1
	case "kB":
		multiplicator = 1000
	case "MB":
		multiplicator = 1000 * 1000
	case "GB":
		multiplicator = 1000 * 1000 * 1000
	case "TB":
		multiplicator = 1000 * 1000 * 1000 * 1000
	case "PB":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000
	case "EB":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000 * 1000
	case "KiB":
		multiplicator = 1024
	case "MiB":
		multiplicator = 1024 * 1024
	case "GiB":
		multiplicator = 1024 * 1024 * 1024
	case "TiB":
		multiplicator = 1024 * 1024 * 1024 * 1024
	case "PiB":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024
	case "EiB":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024 * 1024
	default:
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	return valueInt * multiplicator, nil
}

// ParseBitSizeString parses a human representation of an amount of
// data into a number of bits
func ParseBitSizeString(input string) (int64, error) {
	// Empty input
	if input == "" {
		return 0, nil
	}

	// Find where the suffix begins
	suffixLen := 0
	for i, chr := range []byte(input) {
		_, err := strconv.Atoi(string([]byte{chr}))
		if err != nil {
			suffixLen = len(input) - i
			break
		}
	}

	if suffixLen == len(input) {
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	// Extract the suffix
	suffix := input[len(input)-suffixLen:]

	// Extract the value
	value := input[0 : len(input)-suffixLen]
	valueInt, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return -1, fmt.Errorf("Invalid integer: %s", input)
	}

	// Figure out the multiplicator
	multiplicator := int64(0)
	switch suffix {
	case "", "bit":
		multiplicator = 1
	case "kbit":
		multiplicator = 1000
	case "Mbit":
		multiplicator = 1000 * 1000
	case "Gbit":
		multiplicator = 1000 * 1000 * 1000
	case "Tbit":
		multiplicator = 1000 * 1000 * 1000 * 1000
	case "Pbit":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000
	case "Ebit":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000 * 1000
	case "Kibit":
		multiplicator = 1024
	case "Mibit":
		multiplicator = 1024 * 1024
	case "Gibit":
		multiplicator = 1024 * 1024 * 1024
	case "Tibit":
		multiplicator = 1024 * 1024 * 1024 * 1024
	case "Pibit":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024
	case "Eibit":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024 * 1024

	default:
		return -1, fmt.Errorf("Unsupported suffix: %s", suffix)
	}

	return valueInt * multiplicator, nil
}

// GetByteSizeString takes a number of bytes and precision and returns a
// human representation of the amount of data
func GetByteSizeString(input int64, precision uint) string {
	if input < 1000 {
		return fmt.Sprintf("%dB", input)
	}

	value := float64(input)

	for _, unit := range []string{"kB", "MB", "GB", "TB", "PB", "EB"} {
		value = value / 1000
		if value < 1000 {
			return fmt.Sprintf("%.*f%s", precision, value, unit)
		}
	}

	return fmt.Sprintf("%.*fEB", precision, value)
}
<commit_msg>units: handle multiplication integer overflow<commit_after>package units

import (
	"fmt"
	"strconv"
)

func handleOverflow(val int64, mult int64) (int64, error) {
	result := val * mult
	if val == 0 || mult == 0 || val == 1 || mult == 1 {
		return result, nil
	}

	if val != 0 && (result/val) != mult {
		return -1, fmt.Errorf("Overflow multiplying %d with %d", val, mult)
	}

	return result, nil
}

// ParseByteSizeString parses a human representation of an amount of
// data into a number of bytes
func ParseByteSizeString(input string) (int64, error) {
	// Empty input
	if input == "" {
		return 0, nil
	}

	// Find where the suffix begins
	suffixLen := 0
	for i, chr := range []byte(input) {
		_, err := strconv.Atoi(string([]byte{chr}))
		if err != nil {
			suffixLen = len(input) - i
			break
		}
	}

	if suffixLen == len(input) {
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	// Extract the suffix
	suffix := input[len(input)-suffixLen:]

	// Extract the value
	value := input[0 : len(input)-suffixLen]
	valueInt, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return -1, fmt.Errorf("Invalid integer: %s", input)
	}

	// Figure out the multiplicator
	multiplicator := int64(0)
	switch suffix {
	case "", "B", " bytes":
		multiplicator = 1
	case "kB":
		multiplicator = 1000
	case "MB":
		multiplicator = 1000 * 1000
	case "GB":
		multiplicator = 1000 * 1000 * 1000
	case "TB":
		multiplicator = 1000 * 1000 * 1000 * 1000
	case "PB":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000
	case "EB":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000 * 1000
	case "KiB":
		multiplicator = 1024
	case "MiB":
		multiplicator = 1024 * 1024
	case "GiB":
		multiplicator = 1024 * 1024 * 1024
	case "TiB":
		multiplicator = 1024 * 1024 * 1024 * 1024
	case "PiB":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024
	case "EiB":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024 * 1024
	default:
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	return handleOverflow(valueInt, multiplicator)
}

// ParseBitSizeString parses a human representation of an amount of
// data into a number of bits
func ParseBitSizeString(input string) (int64, error) {
	// Empty input
	if input == "" {
		return 0, nil
	}

	// Find where the suffix begins
	suffixLen := 0
	for i, chr := range []byte(input) {
		_, err := strconv.Atoi(string([]byte{chr}))
		if err != nil {
			suffixLen = len(input) - i
			break
		}
	}

	if suffixLen == len(input) {
		return -1, fmt.Errorf("Invalid value: %s", input)
	}

	// Extract the suffix
	suffix := input[len(input)-suffixLen:]

	// Extract the value
	value := input[0 : len(input)-suffixLen]
	valueInt, err := strconv.ParseInt(value, 10, 64)
	if err != nil {
		return -1, fmt.Errorf("Invalid integer: %s", input)
	}

	// Figure out the multiplicator
	multiplicator := int64(0)
	switch suffix {
	case "", "bit":
		multiplicator = 1
	case "kbit":
		multiplicator = 1000
	case "Mbit":
		multiplicator = 1000 * 1000
	case "Gbit":
		multiplicator = 1000 * 1000 * 1000
	case "Tbit":
		multiplicator = 1000 * 1000 * 1000 * 1000
	case "Pbit":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000
	case "Ebit":
		multiplicator = 1000 * 1000 * 1000 * 1000 * 1000 * 1000
	case "Kibit":
		multiplicator = 1024
	case "Mibit":
		multiplicator = 1024 * 1024
	case "Gibit":
		multiplicator = 1024 * 1024 * 1024
	case "Tibit":
		multiplicator = 1024 * 1024 * 1024 * 1024
	case "Pibit":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024
	case "Eibit":
		multiplicator = 1024 * 1024 * 1024 * 1024 * 1024 * 1024

	default:
		return -1, fmt.Errorf("Unsupported suffix: %s", suffix)
	}

	return handleOverflow(valueInt, multiplicator)
}

// GetByteSizeString takes a number of bytes and precision and returns a
// human representation of the amount of data
func GetByteSizeString(input int64, precision uint) string {
	if input < 1000 {
		return fmt.Sprintf("%dB", input)
	}

	value := float64(input)

	for _, unit := range []string{"kB", "MB", "GB", "TB", "PB", "EB"} {
		value = value / 1000
		if value < 1000 {
			return fmt.Sprintf("%.*f%s", precision, value, unit)
		}
	}

	return fmt.Sprintf("%.*fEB", precision, value)
}
<|endoftext|>


<commit_before>package quic

import (
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"time"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	quic "v2ray.com/core/external/github.com/lucas-clemente/quic-go"
	"v2ray.com/core/transport/internet"
)

type sysConn struct {
	conn   net.PacketConn
	header internet.PacketHeader
	auth   cipher.AEAD
}

func wrapSysConn(rawConn net.PacketConn, config *Config) (*sysConn, error) {
	header, err := getHeader(config)
	if err != nil {
		return nil, err
	}
	auth, err := getAuth(config)
	if err != nil {
		return nil, err
	}
	return &sysConn{
		conn:   rawConn,
		header: header,
		auth:   auth,
	}, nil
}

var errInvalidPacket = errors.New("invalid packet")

func (c *sysConn) readFromInternal(p []byte) (int, net.Addr, error) {
	buffer := getBuffer()
	defer putBuffer(buffer)

	nBytes, addr, err := c.conn.ReadFrom(buffer)
	if err != nil {
		return 0, nil, err
	}

	payload := buffer[:nBytes]
	if c.header != nil {
		if len(payload) <= int(c.header.Size()) {
			return 0, nil, errInvalidPacket
		}
		payload = payload[c.header.Size():]
	}

	if c.auth == nil {
		n := copy(p, payload)
		return n, addr, nil
	}

	if len(payload) <= c.auth.NonceSize() {
		return 0, nil, errInvalidPacket
	}

	nonce := payload[:c.auth.NonceSize()]
	payload = payload[c.auth.NonceSize():]

	p, err = c.auth.Open(p[:0], nonce, payload, nil)
	if err != nil {
		return 0, nil, errInvalidPacket
	}

	return len(p), addr, nil
}

func (c *sysConn) ReadFrom(p []byte) (int, net.Addr, error) {
	if c.header == nil && c.auth == nil {
		return c.conn.ReadFrom(p)
	}

	for {
		n, addr, err := c.readFromInternal(p)
		if err != nil && err != errInvalidPacket {
			return 0, nil, err
		}
		if err == nil {
			return n, addr, nil
		}
	}
}

func (c *sysConn) WriteTo(p []byte, addr net.Addr) (int, error) {
	if c.header == nil && c.auth == nil {
		return c.conn.WriteTo(p, addr)
	}

	buffer := getBuffer()
	defer putBuffer(buffer)

	payload := buffer
	n := 0
	if c.header != nil {
		c.header.Serialize(payload)
		n = int(c.header.Size())
	}

	if c.auth == nil {
		nBytes := copy(payload[n:], p)
		n += nBytes
	} else {
		nounce := payload[n : n+c.auth.NonceSize()]
		common.Must2(rand.Read(nounce))
		n += c.auth.NonceSize()
		pp := c.auth.Seal(payload[:n], nounce, p, nil)
		n = len(pp)
	}

	return c.conn.WriteTo(payload[:n], addr)
}

func (c *sysConn) Close() error {
	return c.conn.Close()
}

func (c *sysConn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

func (c *sysConn) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}

func (c *sysConn) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}

func (c *sysConn) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}

type interConn struct {
	stream quic.Stream
	local  net.Addr
	remote net.Addr
}

func (c *interConn) Read(b []byte) (int, error) {
	return c.stream.Read(b)
}

func (c *interConn) ReadMultiBuffer() (buf.MultiBuffer, error) {
	firstBuffer, err := buf.ReadBuffer(c)
	if err != nil {
		return nil, err
	}

	const BufferCount = 16
	mb := make(buf.MultiBuffer, 0, BufferCount)
	mb = append(mb, firstBuffer)
	for len(mb) < BufferCount && c.stream.HasMoreData() {
		b := buf.New()
		if _, err := b.ReadFrom(c.stream); err != nil {
			b.Release()
			break
		}
		mb = append(mb, b)
	}

	return mb, nil
}

func (c *interConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
	mb = buf.Compact(mb)
	mb, err := buf.WriteMultiBuffer(c, mb)
	buf.ReleaseMulti(mb)
	return err
}

func (c *interConn) Write(b []byte) (int, error) {
	return c.stream.Write(b)
}

func (c *interConn) Close() error {
	return c.stream.Close()
}

func (c *interConn) LocalAddr() net.Addr {
	return c.local
}

func (c *interConn) RemoteAddr() net.Addr {
	return c.remote
}

func (c *interConn) SetDeadline(t time.Time) error {
	return c.stream.SetDeadline(t)
}

func (c *interConn) SetReadDeadline(t time.Time) error {
	return c.stream.SetReadDeadline(t)
}

func (c *interConn) SetWriteDeadline(t time.Time) error {
	return c.stream.SetWriteDeadline(t)
}
<commit_msg>remove multi buffer reading in quic<commit_after>package quic

import (
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"time"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	quic "v2ray.com/core/external/github.com/lucas-clemente/quic-go"
	"v2ray.com/core/transport/internet"
)

type sysConn struct {
	conn   net.PacketConn
	header internet.PacketHeader
	auth   cipher.AEAD
}

func wrapSysConn(rawConn net.PacketConn, config *Config) (*sysConn, error) {
	header, err := getHeader(config)
	if err != nil {
		return nil, err
	}
	auth, err := getAuth(config)
	if err != nil {
		return nil, err
	}
	return &sysConn{
		conn:   rawConn,
		header: header,
		auth:   auth,
	}, nil
}

var errInvalidPacket = errors.New("invalid packet")

func (c *sysConn) readFromInternal(p []byte) (int, net.Addr, error) {
	buffer := getBuffer()
	defer putBuffer(buffer)

	nBytes, addr, err := c.conn.ReadFrom(buffer)
	if err != nil {
		return 0, nil, err
	}

	payload := buffer[:nBytes]
	if c.header != nil {
		if len(payload) <= int(c.header.Size()) {
			return 0, nil, errInvalidPacket
		}
		payload = payload[c.header.Size():]
	}

	if c.auth == nil {
		n := copy(p, payload)
		return n, addr, nil
	}

	if len(payload) <= c.auth.NonceSize() {
		return 0, nil, errInvalidPacket
	}

	nonce := payload[:c.auth.NonceSize()]
	payload = payload[c.auth.NonceSize():]

	p, err = c.auth.Open(p[:0], nonce, payload, nil)
	if err != nil {
		return 0, nil, errInvalidPacket
	}

	return len(p), addr, nil
}

func (c *sysConn) ReadFrom(p []byte) (int, net.Addr, error) {
	if c.header == nil && c.auth == nil {
		return c.conn.ReadFrom(p)
	}

	for {
		n, addr, err := c.readFromInternal(p)
		if err != nil && err != errInvalidPacket {
			return 0, nil, err
		}
		if err == nil {
			return n, addr, nil
		}
	}
}

func (c *sysConn) WriteTo(p []byte, addr net.Addr) (int, error) {
	if c.header == nil && c.auth == nil {
		return c.conn.WriteTo(p, addr)
	}

	buffer := getBuffer()
	defer putBuffer(buffer)

	payload := buffer
	n := 0
	if c.header != nil {
		c.header.Serialize(payload)
		n = int(c.header.Size())
	}

	if c.auth == nil {
		nBytes := copy(payload[n:], p)
		n += nBytes
	} else {
		nounce := payload[n : n+c.auth.NonceSize()]
		common.Must2(rand.Read(nounce))
		n += c.auth.NonceSize()
		pp := c.auth.Seal(payload[:n], nounce, p, nil)
		n = len(pp)
	}

	return c.conn.WriteTo(payload[:n], addr)
}

func (c *sysConn) Close() error {
	return c.conn.Close()
}

func (c *sysConn) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

func (c *sysConn) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}

func (c *sysConn) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}

func (c *sysConn) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}

type interConn struct {
	stream quic.Stream
	local  net.Addr
	remote net.Addr
}

func (c *interConn) Read(b []byte) (int, error) {
	return c.stream.Read(b)
}

func (c *interConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
	mb = buf.Compact(mb)
	mb, err := buf.WriteMultiBuffer(c, mb)
	buf.ReleaseMulti(mb)
	return err
}

func (c *interConn) Write(b []byte) (int, error) {
	return c.stream.Write(b)
}

func (c *interConn) Close() error {
	return c.stream.Close()
}

func (c *interConn) LocalAddr() net.Addr {
	return c.local
}

func (c *interConn) RemoteAddr() net.Addr {
	return c.remote
}

func (c *interConn) SetDeadline(t time.Time) error {
	return c.stream.SetDeadline(t)
}

func (c *interConn) SetReadDeadline(t time.Time) error {
	return c.stream.SetReadDeadline(t)
}

func (c *interConn) SetWriteDeadline(t time.Time) error {
	return c.stream.SetWriteDeadline(t)
}
<|endoftext|>