<commit_before>package openapi3edit

import (
	"fmt"
	"net/http"
	"strings"

	oas3 "github.com/getkin/kin-openapi/openapi3"
	"github.com/grokify/swaggman/openapi3"
)

type OperationEditor struct {
	Operation *oas3.Operation
}

func (oedit *OperationEditor) AddExternalDocs(docURL, docDescription string, preserveIfReqEmpty bool) {
	operationAddExternalDocs(oedit.Operation, docURL, docDescription, preserveIfReqEmpty)
}

func (oedit *OperationEditor) AddRequestBodySchemaRef(description string, required bool, contentType string, schemaRef *oas3.SchemaRef) error {
	return operationAddRequestBodySchemaRef(oedit.Operation, description, required, contentType, schemaRef)
}

func (oedit *OperationEditor) AddResponseBodySchemaRef(statusCode, description, contentType string, schemaRef *oas3.SchemaRef) error {
	return operationAddResponseBodySchemaRef(oedit.Operation, statusCode, description, contentType, schemaRef)
}

func operationAddRequestBodySchemaRef(op *oas3.Operation, description string, required bool, contentType string, schemaRef *oas3.SchemaRef) error {
	if op == nil {
		return fmt.Errorf("operation to edit is nil")
	}
	if op.RequestBody == nil {
		op.RequestBody = &oas3.RequestBodyRef{}
	}
	description = strings.TrimSpace(description)
	contentType = strings.ToLower(strings.TrimSpace(contentType))
	if len(contentType) == 0 {
		return fmt.Errorf("content type [%s] is empty", contentType)
	}
	if len(op.RequestBody.Ref) > 0 {
		return fmt.Errorf("request body is reference for operationId [%s]", op.OperationID)
	}
	op.RequestBody.Value.Description = description
	op.RequestBody.Value.Required = required
	if op.RequestBody.Value.Content == nil {
		op.RequestBody.Value.Content = oas3.NewContent()
	}
	op.RequestBody.Value.Content[contentType] = oas3.NewMediaType().WithSchemaRef(schemaRef)
	return nil
}

func operationAddResponseBodySchemaRef(op *oas3.Operation, statusCode, description, contentType string, schemaRef *oas3.SchemaRef) error {
	if op == nil {
		return fmt.Errorf("operation to edit is nil")
	}
	if schemaRef == nil {
		return fmt.Errorf("operation response to body to add is nil")
	}
	statusCode = strings.TrimSpace(statusCode)
	description = strings.TrimSpace(description)
	contentType = strings.ToLower(strings.TrimSpace(contentType))
	if statusCode == "" || contentType == "" {
		return fmt.Errorf("status code [%s] or content type [%s] is empty", statusCode, contentType)
	}
	if op.Responses[statusCode] == nil {
		op.Responses[statusCode] = &oas3.ResponseRef{}
	}
	if len(op.Responses[statusCode].Ref) > 0 {
		return fmt.Errorf("response is a reference and not actual")
	}
	if op.Responses[statusCode].Value == nil {
		op.Responses[statusCode].Value = &oas3.Response{
			Description: &description,
		}
	}
	if op.Responses[statusCode].Value.Content == nil {
		op.Responses[statusCode].Value.Content = oas3.NewContent()
	}
	op.Responses[statusCode].Value.Content[contentType] = oas3.NewMediaType().WithSchemaRef(schemaRef)
	return nil
}

func operationAddExternalDocs(op *oas3.Operation, docURL, docDescription string, preserveIfReqEmpty bool) error {
	if op == nil {
		return fmt.Errorf("operation to edit is nil")
	}
	docURL = strings.TrimSpace(docURL)
	docDescription = strings.TrimSpace(docDescription)
	if len(docURL) > 0 || len(docDescription) > 0 {
		if preserveIfReqEmpty {
			if op.ExternalDocs == nil {
				op.ExternalDocs = &oas3.ExternalDocs{}
			}
			if len(docURL) > 0 {
				op.ExternalDocs.URL = docURL
			}
			if len(docDescription) > 0 {
				op.ExternalDocs.Description = docDescription
			}
		} else {
			op.ExternalDocs = &oas3.ExternalDocs{
				Description: docDescription,
				URL:         docURL}
		}
	}
	return nil
}

func SpecOperationsCount(spec *oas3.Swagger) uint {
	count := uint(0)
	openapi3.VisitOperations(spec, func(skipPath, skipMethod string, op *oas3.Operation) {
		count++
	})
	return count
}

func SpecSetOperation(spec *oas3.Swagger, path, method string, op oas3.Operation) {
	pathItem, ok := spec.Paths[path]
	if !ok {
		pathItem = &oas3.PathItem{}
	}
	method = strings.ToUpper(strings.TrimSpace(method))
	switch method {
	case http.MethodGet:
		pathItem.Get = &op
	case http.MethodPost:
		pathItem.Post = &op
	case http.MethodPut:
		pathItem.Put = &op
	case http.MethodPatch:
		pathItem.Patch = &op
	}

}

func SpecOperationIds(spec *oas3.Swagger) map[string]int {
	msi := map[string]int{}
	openapi3.VisitOperations(spec, func(skipPath, skipMethod string, op *oas3.Operation) {
		op.OperationID = strings.TrimSpace(op.OperationID)
		if _, ok := msi[op.OperationID]; !ok {
			msi[op.OperationID] = 0
		}
		msi[op.OperationID]++
	})
	return msi
}

func SpecOperationIdsFromSummaries(spec *oas3.Swagger, errorOnEmpty bool) error {
	empty := []string{}
	openapi3.VisitOperations(spec, func(path, method string, op *oas3.Operation) {
		op.Summary = strings.Join(strings.Split(op.Summary, " "), " ")
		op.OperationID = op.Summary
		if len(op.OperationID) == 0 {
			empty = append(empty, path+" "+method)
		}
	})
	if errorOnEmpty && len(empty) > 0 {
		return fmt.Errorf("no_opid: [%s]", strings.Join(empty, ", "))
	}
	return nil
}

func SpecAddCustomProperties(spec *oas3.Swagger, custom map[string]interface{}, addToOperations, addToSchemas bool) {
	if spec == nil || len(custom) == 0 {
		return
	}
	if addToOperations {
		openapi3.VisitOperations(spec, func(skipPath, skipMethod string, op *oas3.Operation) {
			for key, val := range custom {
				op.Extensions[key] = val
			}
		})
	}
	if addToSchemas {
		for _, schema := range spec.Components.Schemas {
			if schema.Value != nil {
				for key, val := range custom {
					schema.Value.Extensions[key] = val
				}
			}
		}
	}
}

func SpecAddOperationMetas(spec *oas3.Swagger, metas map[string]openapi3.OperationMeta, overwrite bool) {
	if spec == nil || len(metas) == 0 {
		return
	}
	openapi3.VisitOperations(spec, func(skipPath, skipMethod string, op *oas3.Operation) {
		if op == nil {
			return
		}
		opMeta, ok := metas[op.OperationID]
		if !ok {
			return
		}
		opMeta.TrimSpace()
		writeDocs := false
		writeScopes := false
		writeThrottling := false
		if overwrite {
			writeDocs = true
			writeScopes = true
			writeThrottling = true
		}
		if writeDocs {
			operationAddExternalDocs(op, opMeta.DocsURL, opMeta.DocsDescription, true)
		}
		if writeScopes {
			if len(opMeta.SecurityScopes) > 0 {
				op.Security = &oas3.SecurityRequirements{
					map[string][]string{"oauth": opMeta.SecurityScopes},
				}
			} else {
				op.Security = nil
			}
		}
		if writeThrottling {
			if op.ExtensionProps.Extensions == nil {
				op.ExtensionProps.Extensions = map[string]interface{}{}
			}
			op.ExtensionProps.Extensions[openapi3.XThrottlingGroup] = opMeta.XThrottlingGroup
		}
	})
}

type OperationMoreSet struct {
	OperationMores []OperationMore
}

type OperationMore struct {
	UrlPath   string
	Method    string
	Operation *oas3.Operation
}

func QueryOperationsByTags(spec *oas3.Swagger, tags []string) *OperationMoreSet {
	tagsWantMatch := map[string]int{}
	for _, tag := range tags {
		tagsWantMatch[tag] = 1
	}
	opmSet := &OperationMoreSet{OperationMores: []OperationMore{}}
	// for path, pathInfo := range spec.Paths {
	openapi3.VisitOperations(spec, func(url, method string, op *oas3.Operation) {
		if op == nil {
			return
		}
		for _, tagTry := range op.Tags {
			if _, ok := tagsWantMatch[tagTry]; ok {
				opmSet.OperationMores = append(opmSet.OperationMores,
					OperationMore{
						UrlPath:   url,
						Method:    method,
						Operation: op})
				return
			}
		}
	})
	// }
	return opmSet
}
<commit_msg>enhance: openapi3edit: `operationAddRequestBodySchemaRef` add default `RequestBody{}`<commit_after>package openapi3edit

import (
	"fmt"
	"net/http"
	"strings"

	oas3 "github.com/getkin/kin-openapi/openapi3"
	"github.com/grokify/swaggman/openapi3"
)

type OperationEditor struct {
	Operation *oas3.Operation
}

func (oedit *OperationEditor) AddExternalDocs(docURL, docDescription string, preserveIfReqEmpty bool) {
	operationAddExternalDocs(oedit.Operation, docURL, docDescription, preserveIfReqEmpty)
}

func (oedit *OperationEditor) AddRequestBodySchemaRef(description string, required bool, contentType string, schemaRef *oas3.SchemaRef) error {
	return operationAddRequestBodySchemaRef(oedit.Operation, description, required, contentType, schemaRef)
}

func (oedit *OperationEditor) AddResponseBodySchemaRef(statusCode, description, contentType string, schemaRef *oas3.SchemaRef) error {
	return operationAddResponseBodySchemaRef(oedit.Operation, statusCode, description, contentType, schemaRef)
}

func operationAddRequestBodySchemaRef(op *oas3.Operation, description string, required bool, contentType string, schemaRef *oas3.SchemaRef) error {
	if op == nil {
		return fmt.Errorf("operation to edit is nil")
	}
	if op.RequestBody == nil {
		op.RequestBody = &oas3.RequestBodyRef{}
	}
	description = strings.TrimSpace(description)
	contentType = strings.ToLower(strings.TrimSpace(contentType))
	if len(contentType) == 0 {
		return fmt.Errorf("content type [%s] is empty", contentType)
	}
	if len(op.RequestBody.Ref) > 0 {
		return fmt.Errorf("request body is reference for operationId [%s]", op.OperationID)
	}
	if op.RequestBody.Value == nil {
		op.RequestBody.Value = &oas3.RequestBody{}
	}
	op.RequestBody.Value.Description = description
	op.RequestBody.Value.Required = required
	if op.RequestBody.Value.Content == nil {
		op.RequestBody.Value.Content = oas3.NewContent()
	}
	op.RequestBody.Value.Content[contentType] = oas3.NewMediaType().WithSchemaRef(schemaRef)
	return nil
}

func operationAddResponseBodySchemaRef(op *oas3.Operation, statusCode, description, contentType string, schemaRef *oas3.SchemaRef) error {
	if op == nil {
		return fmt.Errorf("operation to edit is nil")
	}
	if schemaRef == nil {
		return fmt.Errorf("operation response to body to add is nil")
	}
	statusCode = strings.TrimSpace(statusCode)
	description = strings.TrimSpace(description)
	contentType = strings.ToLower(strings.TrimSpace(contentType))
	if statusCode == "" || contentType == "" {
		return fmt.Errorf("status code [%s] or content type [%s] is empty", statusCode, contentType)
	}
	if op.Responses[statusCode] == nil {
		op.Responses[statusCode] = &oas3.ResponseRef{}
	}
	if len(op.Responses[statusCode].Ref) > 0 {
		return fmt.Errorf("response is a reference and not actual")
	}
	if op.Responses[statusCode].Value == nil {
		op.Responses[statusCode].Value = &oas3.Response{
			Description: &description,
		}
	}
	if op.Responses[statusCode].Value.Content == nil {
		op.Responses[statusCode].Value.Content = oas3.NewContent()
	}
	op.Responses[statusCode].Value.Content[contentType] = oas3.NewMediaType().WithSchemaRef(schemaRef)
	return nil
}

func operationAddExternalDocs(op *oas3.Operation, docURL, docDescription string, preserveIfReqEmpty bool) error {
	if op == nil {
		return fmt.Errorf("operation to edit is nil")
	}
	docURL = strings.TrimSpace(docURL)
	docDescription = strings.TrimSpace(docDescription)
	if len(docURL) > 0 || len(docDescription) > 0 {
		if preserveIfReqEmpty {
			if op.ExternalDocs == nil {
				op.ExternalDocs = &oas3.ExternalDocs{}
			}
			if len(docURL) > 0 {
				op.ExternalDocs.URL = docURL
			}
			if len(docDescription) > 0 {
				op.ExternalDocs.Description = docDescription
			}
		} else {
			op.ExternalDocs = &oas3.ExternalDocs{
				Description: docDescription,
				URL:         docURL}
		}
	}
	return nil
}

func SpecOperationsCount(spec *oas3.Swagger) uint {
	count := uint(0)
	openapi3.VisitOperations(spec, func(skipPath, skipMethod string, op *oas3.Operation) {
		count++
	})
	return count
}

func SpecSetOperation(spec *oas3.Swagger, path, method string, op oas3.Operation) {
	pathItem, ok := spec.Paths[path]
	if !ok {
		pathItem = &oas3.PathItem{}
	}
	method = strings.ToUpper(strings.TrimSpace(method))
	switch method {
	case http.MethodGet:
		pathItem.Get = &op
	case http.MethodPost:
		pathItem.Post = &op
	case http.MethodPut:
		pathItem.Put = &op
	case http.MethodPatch:
		pathItem.Patch = &op
	}

}

func SpecOperationIds(spec *oas3.Swagger) map[string]int {
	msi := map[string]int{}
	openapi3.VisitOperations(spec, func(skipPath, skipMethod string, op *oas3.Operation) {
		op.OperationID = strings.TrimSpace(op.OperationID)
		if _, ok := msi[op.OperationID]; !ok {
			msi[op.OperationID] = 0
		}
		msi[op.OperationID]++
	})
	return msi
}

func SpecOperationIdsFromSummaries(spec *oas3.Swagger, errorOnEmpty bool) error {
	empty := []string{}
	openapi3.VisitOperations(spec, func(path, method string, op *oas3.Operation) {
		op.Summary = strings.Join(strings.Split(op.Summary, " "), " ")
		op.OperationID = op.Summary
		if len(op.OperationID) == 0 {
			empty = append(empty, path+" "+method)
		}
	})
	if errorOnEmpty && len(empty) > 0 {
		return fmt.Errorf("no_opid: [%s]", strings.Join(empty, ", "))
	}
	return nil
}

func SpecAddCustomProperties(spec *oas3.Swagger, custom map[string]interface{}, addToOperations, addToSchemas bool) {
	if spec == nil || len(custom) == 0 {
		return
	}
	if addToOperations {
		openapi3.VisitOperations(spec, func(skipPath, skipMethod string, op *oas3.Operation) {
			for key, val := range custom {
				op.Extensions[key] = val
			}
		})
	}
	if addToSchemas {
		for _, schema := range spec.Components.Schemas {
			if schema.Value != nil {
				for key, val := range custom {
					schema.Value.Extensions[key] = val
				}
			}
		}
	}
}

func SpecAddOperationMetas(spec *oas3.Swagger, metas map[string]openapi3.OperationMeta, overwrite bool) {
	if spec == nil || len(metas) == 0 {
		return
	}
	openapi3.VisitOperations(spec, func(skipPath, skipMethod string, op *oas3.Operation) {
		if op == nil {
			return
		}
		opMeta, ok := metas[op.OperationID]
		if !ok {
			return
		}
		opMeta.TrimSpace()
		writeDocs := false
		writeScopes := false
		writeThrottling := false
		if overwrite {
			writeDocs = true
			writeScopes = true
			writeThrottling = true
		}
		if writeDocs {
			operationAddExternalDocs(op, opMeta.DocsURL, opMeta.DocsDescription, true)
		}
		if writeScopes {
			if len(opMeta.SecurityScopes) > 0 {
				op.Security = &oas3.SecurityRequirements{
					map[string][]string{"oauth": opMeta.SecurityScopes},
				}
			} else {
				op.Security = nil
			}
		}
		if writeThrottling {
			if op.ExtensionProps.Extensions == nil {
				op.ExtensionProps.Extensions = map[string]interface{}{}
			}
			op.ExtensionProps.Extensions[openapi3.XThrottlingGroup] = opMeta.XThrottlingGroup
		}
	})
}

type OperationMoreSet struct {
	OperationMores []OperationMore
}

type OperationMore struct {
	UrlPath   string
	Method    string
	Operation *oas3.Operation
}

func QueryOperationsByTags(spec *oas3.Swagger, tags []string) *OperationMoreSet {
	tagsWantMatch := map[string]int{}
	for _, tag := range tags {
		tagsWantMatch[tag] = 1
	}
	opmSet := &OperationMoreSet{OperationMores: []OperationMore{}}
	// for path, pathInfo := range spec.Paths {
	openapi3.VisitOperations(spec, func(url, method string, op *oas3.Operation) {
		if op == nil {
			return
		}
		for _, tagTry := range op.Tags {
			if _, ok := tagsWantMatch[tagTry]; ok {
				opmSet.OperationMores = append(opmSet.OperationMores,
					OperationMore{
						UrlPath:   url,
						Method:    method,
						Operation: op})
				return
			}
		}
	})
	// }
	return opmSet
}
<|endoftext|>


<commit_before>package executors

import (
	"os/exec"
	"strings"
)

type commandLineExecutor struct {
	runCommand runCommand
}

func NewCommandLineExecutor() commandLineExecutor {
	runOnCommandLine := func (command string, args []string) ([]byte, error) {
			return exec.Command(command, args...).CombinedOutput()
		}

	return NewCustomCommandLineExecutor(runOnCommandLine)
}

func NewCustomCommandLineExecutor(runCommand runCommand) commandLineExecutor {
	return commandLineExecutor{runCommand}
}

func (c commandLineExecutor) Execute(command string, args []string) (string, error) {
	out, err := c.runCommand(command, args)
	message := strings.Trim(string(out), "\n")
	return message, err
}<commit_msg>Removing unused constructor from command line executor<commit_after>package executors

import (
	"os/exec"
	"strings"
)

type commandLineExecutor struct {
	runCommand runCommand
}

func NewCommandLineExecutor() commandLineExecutor {
	runOnCommandLine := func (command string, args []string) ([]byte, error) {
			return exec.Command(command, args...).CombinedOutput()
		}

	return commandLineExecutor{runOnCommandLine}
}

func (c commandLineExecutor) Execute(command string, args []string) (string, error) {
	out, err := c.runCommand(command, args)
	message := strings.Trim(string(out), "\n")
	return message, err
}<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 prometheus

import (
	"errors"
	"github.com/ligato/cn-infra/flavors/local"
	"github.com/ligato/cn-infra/rpc/rest"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/unrolled/render"
	"net/http"
	"strings"
	"sync"
)

// DefaultMetricsPath default Prometheus metrics URL
const DefaultRegistry = "/metrics"

var (
	// PathInvalidFormatError is returned if the path doesn't start with slash
	PathInvalidFormatError = errors.New("path is invalid, it must start with '/' character")
	// PathAlreadyRegistryError is returned on attempt to register a path used by a registry
	PathAlreadyRegistryError = errors.New("registry with the path is already registered")
	// RegistryNotFoundError is returned on attempt to use register that has not been created
	RegistryNotFoundError = errors.New("registry was not found")
)

// Plugin struct holds all plugin-related data.
type Plugin struct {
	Deps
	sync.Mutex
	// regs is a map of URL path(symbolic names) to registries. Registries group metrics and can be exposed at different urls.
	regs map[string]*registry
}

// Deps lists dependencies of the plugin.
type Deps struct {
	local.PluginInfraDeps // inject
	// HTTP server used to expose metrics
	HTTP rest.HTTPHandlers // inject
}

type registry struct {
	prometheus.Gatherer
	prometheus.Registerer
	// httpOpts applied when exposing registry using http
	httpOpts promhttp.HandlerOpts
}

// Init initializes the internal structures
func (p *Plugin) Init() (err error) {

	p.regs = map[string]*registry{}

	// add default registry
	p.regs[DefaultRegistry] = &registry{
		Gatherer:   prometheus.DefaultGatherer,
		Registerer: prometheus.DefaultRegisterer,
	}

	return nil
}

// AfterInit registers HTTP handlers.
func (p *Plugin) AfterInit() error {
	if p.HTTP != nil {
		for path, reg := range p.regs {
			p.HTTP.RegisterHTTPHandler(path, p.createHandlerHandler(reg.Gatherer), "GET")
			p.Log.Infof("Serving %s on port %d", path, p.HTTP.GetPort())

		}
	} else {
		p.Log.Info("Unable to register Prometheus metrics handlers, HTTP is nil")
	}

	return nil
}

// Close cleans up the allocated resources.
func (p *Plugin) Close() error {
	return nil
}

// NewRegistry creates new registry exposed at defined URL path (must begin with '/' character), path is used to reference
// registry while adding new metrics into registry, opts adjust the behavior of exposed registry. Must be called before
// AfterInit phase of the Prometheus plugin. An attempt to create  a registry with path that is already used
// by different registry returns an error.
func (p *Plugin) NewRegistry(path string, opts promhttp.HandlerOpts) error {
	p.Lock()
	defer p.Unlock()

	if !strings.HasPrefix(path, "/") {
		return PathInvalidFormatError
	}
	if _, found := p.regs[path]; found {
		return PathAlreadyRegistryError
	}
	newReg := prometheus.NewRegistry()
	p.regs[path] = &registry{
		Registerer: newReg,
		Gatherer:   newReg,
		httpOpts:   opts,
	}
	return nil
}

// Register registers prometheus metric to a specified registry. In order to add metrics
// to default registry use prometheus.DefaultRegistry const.
func (p *Plugin) Register(registryPath string, collector prometheus.Collector) error {
	p.Lock()
	defer p.Unlock()

	reg, found := p.regs[registryPath]
	if !found {
		return RegistryNotFoundError
	}
	return reg.Register(collector)
}

// RegisterGauge registers custom gauge with specific valueFunc to report status when invoked. RegistryPath identifies
// the registry where gauge is added.
func (p *Plugin) RegisterGaugeFunc(registryPath string, namespace string, subsystem string, name string, help string,
	labels prometheus.Labels, valueFunc func() float64) error {

	p.Lock()
	defer p.Unlock()

	reg, found := p.regs[registryPath]
	if !found {
		return RegistryNotFoundError
	}

	gaugeName := name
	if subsystem != "" {
		gaugeName = subsystem + "_" + gaugeName
	}
	if namespace != "" {
		gaugeName = namespace + "_" + gaugeName
	}

	err := reg.Register(prometheus.NewGaugeFunc(
		prometheus.GaugeOpts{
			Namespace:   namespace,
			Subsystem:   subsystem,
			Name:        name,
			Help:        help,
			ConstLabels: labels,
		},
		valueFunc,
	))
	if err != nil {
		p.Log.Errorf("GaugeFunc('%s') registration failed: %s", gaugeName, err)
		return err
	}
	p.Log.Infof("GaugeFunc('%s') registered.", gaugeName)
	return nil
}

func (p *Plugin) createHandlerHandler(gatherer prometheus.Gatherer) func(formatter *render.Render) http.HandlerFunc {
	return func(formatter *render.Render) http.HandlerFunc {
		return promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{}).ServeHTTP
	}
}
<commit_msg>Add missing lock in prometheus plugin<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 prometheus

import (
	"errors"
	"github.com/ligato/cn-infra/flavors/local"
	"github.com/ligato/cn-infra/rpc/rest"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/unrolled/render"
	"net/http"
	"strings"
	"sync"
)

// DefaultMetricsPath default Prometheus metrics URL
const DefaultRegistry = "/metrics"

var (
	// PathInvalidFormatError is returned if the path doesn't start with slash
	PathInvalidFormatError = errors.New("path is invalid, it must start with '/' character")
	// PathAlreadyRegistryError is returned on attempt to register a path used by a registry
	PathAlreadyRegistryError = errors.New("registry with the path is already registered")
	// RegistryNotFoundError is returned on attempt to use register that has not been created
	RegistryNotFoundError = errors.New("registry was not found")
)

// Plugin struct holds all plugin-related data.
type Plugin struct {
	Deps
	sync.Mutex
	// regs is a map of URL path(symbolic names) to registries. Registries group metrics and can be exposed at different urls.
	regs map[string]*registry
}

// Deps lists dependencies of the plugin.
type Deps struct {
	local.PluginInfraDeps // inject
	// HTTP server used to expose metrics
	HTTP rest.HTTPHandlers // inject
}

type registry struct {
	prometheus.Gatherer
	prometheus.Registerer
	// httpOpts applied when exposing registry using http
	httpOpts promhttp.HandlerOpts
}

// Init initializes the internal structures
func (p *Plugin) Init() (err error) {

	p.regs = map[string]*registry{}

	// add default registry
	p.regs[DefaultRegistry] = &registry{
		Gatherer:   prometheus.DefaultGatherer,
		Registerer: prometheus.DefaultRegisterer,
	}

	return nil
}

// AfterInit registers HTTP handlers.
func (p *Plugin) AfterInit() error {
	if p.HTTP != nil {
		p.Lock()
		defer p.Unlock()
		for path, reg := range p.regs {
			p.HTTP.RegisterHTTPHandler(path, p.createHandlerHandler(reg.Gatherer), "GET")
			p.Log.Infof("Serving %s on port %d", path, p.HTTP.GetPort())

		}
	} else {
		p.Log.Info("Unable to register Prometheus metrics handlers, HTTP is nil")
	}

	return nil
}

// Close cleans up the allocated resources.
func (p *Plugin) Close() error {
	return nil
}

// NewRegistry creates new registry exposed at defined URL path (must begin with '/' character), path is used to reference
// registry while adding new metrics into registry, opts adjust the behavior of exposed registry. Must be called before
// AfterInit phase of the Prometheus plugin. An attempt to create  a registry with path that is already used
// by different registry returns an error.
func (p *Plugin) NewRegistry(path string, opts promhttp.HandlerOpts) error {
	p.Lock()
	defer p.Unlock()

	if !strings.HasPrefix(path, "/") {
		return PathInvalidFormatError
	}
	if _, found := p.regs[path]; found {
		return PathAlreadyRegistryError
	}
	newReg := prometheus.NewRegistry()
	p.regs[path] = &registry{
		Registerer: newReg,
		Gatherer:   newReg,
		httpOpts:   opts,
	}
	return nil
}

// Register registers prometheus metric to a specified registry. In order to add metrics
// to default registry use prometheus.DefaultRegistry const.
func (p *Plugin) Register(registryPath string, collector prometheus.Collector) error {
	p.Lock()
	defer p.Unlock()

	reg, found := p.regs[registryPath]
	if !found {
		return RegistryNotFoundError
	}
	return reg.Register(collector)
}

// RegisterGauge registers custom gauge with specific valueFunc to report status when invoked. RegistryPath identifies
// the registry where gauge is added.
func (p *Plugin) RegisterGaugeFunc(registryPath string, namespace string, subsystem string, name string, help string,
	labels prometheus.Labels, valueFunc func() float64) error {

	p.Lock()
	defer p.Unlock()

	reg, found := p.regs[registryPath]
	if !found {
		return RegistryNotFoundError
	}

	gaugeName := name
	if subsystem != "" {
		gaugeName = subsystem + "_" + gaugeName
	}
	if namespace != "" {
		gaugeName = namespace + "_" + gaugeName
	}

	err := reg.Register(prometheus.NewGaugeFunc(
		prometheus.GaugeOpts{
			Namespace:   namespace,
			Subsystem:   subsystem,
			Name:        name,
			Help:        help,
			ConstLabels: labels,
		},
		valueFunc,
	))
	if err != nil {
		p.Log.Errorf("GaugeFunc('%s') registration failed: %s", gaugeName, err)
		return err
	}
	p.Log.Infof("GaugeFunc('%s') registered.", gaugeName)
	return nil
}

func (p *Plugin) createHandlerHandler(gatherer prometheus.Gatherer) func(formatter *render.Render) http.HandlerFunc {
	return func(formatter *render.Render) http.HandlerFunc {
		return promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{}).ServeHTTP
	}
}
<|endoftext|>


<commit_before>package effio

import (
	"flag"
	"fmt"
	"os"
	"strings"
)

type Cmd struct {
	Process string
	Command string
	Args    []string
	FlagSet *flag.FlagSet
}

// NewCmd returns a new command struct with arguments broken out.
// The first argument is always considered a subcommand but is not
// parsed by this package. It is meant to be used with the flag package.
// Usage: cmd := effio.NewCmd(os.Args)
func NewCmd(args []string) (cmd Cmd) {
	if len(args) < 2 {
		cmd.Usage("subcommand required: make|run|inventory|mountall|graph\n")
	}

	cmd.Process = args[0]
	cmd.Command = args[1]

	if len(args) > 2 {
		cmd.Args = args[2:]
	} else {
		cmd.Args = []string{}
	}

	cmd.FlagSet = flag.NewFlagSet(cmd.Process, flag.ExitOnError)
	cmd.FlagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		cmd.FlagSet.PrintDefaults()
		os.Exit(2)
	}

	return cmd
}

func (cmd *Cmd) Run() {
	switch cmd.Command {
	case "make":
		cmd.MakeSuite()
	case "run":
		cmd.RunSuite()
	case "inventory":
		cmd.Inventory()
	case "mountall":
		cmd.Mountall()
	case "graph":
		cmd.GraphSuite()
	case "summarize":
		cmd.SummarizeCSV()
	case "help", "-h", "-help", "--help":
		cmd.Usage()
	default:
		cmd.Usage(fmt.Sprintf("Invalid subcommand '%s'.\n", cmd.Command))
	}
}

// TODO: fill in usage when things settle down
func (cmd *Cmd) Usage(more ...string) {
	fmt.Fprintf(os.Stderr, strings.Join(more, ""))
	fmt.Fprintf(os.Stderr, "Usage: %s <command> <args>\n", os.Args[0])
	os.Exit(2)
}
<commit_msg>remove removed commands<commit_after>package effio

import (
	"flag"
	"fmt"
	"os"
	"strings"
)

type Cmd struct {
	Process string
	Command string
	Args    []string
	FlagSet *flag.FlagSet
}

// NewCmd returns a new command struct with arguments broken out.
// The first argument is always considered a subcommand but is not
// parsed by this package. It is meant to be used with the flag package.
// Usage: cmd := effio.NewCmd(os.Args)
func NewCmd(args []string) (cmd Cmd) {
	if len(args) < 2 {
		cmd.Usage("subcommand required: run|inventory\n")
	}

	cmd.Process = args[0]
	cmd.Command = args[1]

	if len(args) > 2 {
		cmd.Args = args[2:]
	} else {
		cmd.Args = []string{}
	}

	cmd.FlagSet = flag.NewFlagSet(cmd.Process, flag.ExitOnError)
	cmd.FlagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		cmd.FlagSet.PrintDefaults()
		os.Exit(2)
	}

	return cmd
}

func (cmd *Cmd) Run() {
	switch cmd.Command {
	case "run":
		cmd.RunSuite()
	case "inventory":
		cmd.Inventory()
	case "summarize":
		cmd.SummarizeCSV()
	case "help", "-h", "-help", "--help":
		cmd.Usage()
	default:
		cmd.Usage(fmt.Sprintf("Invalid subcommand '%s'.\n", cmd.Command))
	}
}

// TODO: fill in usage when things settle down
func (cmd *Cmd) Usage(more ...string) {
	fmt.Fprintf(os.Stderr, strings.Join(more, ""))
	fmt.Fprintf(os.Stderr, "Usage: %s <command> <args>\n", os.Args[0])
	os.Exit(2)
}
<|endoftext|>


<commit_before>// Generic Security Services Application Program Interface implementation required for SPNEGO kerberos authentication
package GSSAPI

import (
	"errors"
	"fmt"
	"github.com/jcmturner/asn1"
	"github.com/jcmturner/gokrb5/asn1tools"
)

var SPNEGO_OID = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 2}

type SPNEGO struct {
	Init         bool
	Resp         bool
	NegTokenInit NegTokenInit
	NegTokenResp NegTokenResp
}

// Unmarshal SPNEGO negotiation token
func (s *SPNEGO) Unmarshal(b []byte) error {
	var r []byte
	var err error
	if b[0] != byte(161) {
		// Not a NegTokenResp/Targ could be a NegTokenInit
		var oid asn1.ObjectIdentifier
		r, err = asn1.UnmarshalWithParams(b, &oid, fmt.Sprintf("application,explicit,tag:%v", 0))
		if err != nil {
			return fmt.Errorf("Not a valid SPNEGO token: %v", err)
		}
		// Check the OID is the SPNEGO OID value
		if !oid.Equal(asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 2}) {
			return errors.New("OID does not match SPNEGO OID 1.3.6.1.5.5.2")
		}
	} else {
		// Could be a NegTokenResp/Targ
		r = b
	}

	var a asn1.RawValue
	_, err = asn1.Unmarshal(r, &a)
	if err != nil {
		return fmt.Errorf("Error unmarshalling SPNEGO: %v", err)
	}
	switch a.Tag {
	case 0:
		_, err = asn1.Unmarshal(a.Bytes, &s.NegTokenInit)
		if err != nil {
			return fmt.Errorf("Error unmarshalling NegotiationToken type %d (Init): %v", a.Tag, err)
		}
		s.Init = true
	case 1:
		_, err = asn1.Unmarshal(a.Bytes, &s.NegTokenResp)
		if err != nil {
			return fmt.Errorf("Error unmarshalling NegotiationToken type %d (Resp/Targ): %v", a.Tag, err)
		}
		s.Resp = true
	default:
		return errors.New("Unknown choice type for NegotiationToken")
	}
	return nil
}

// Marshal SPNEGO negotiation token
func (s *SPNEGO) Marshal() ([]byte, error) {
	var b []byte
	if !s.Init && !s.Resp {
		return b, errors.New("SPNEGO cannot be marshalled. It contains neither a NegTokenInit or NegTokenResp")
	}
	hb, _ := asn1.Marshal(SPNEGO_OID)
	if s.Init {
		tb, err := s.NegTokenInit.Marshal()
		if err != nil {
			return b, fmt.Errorf("Could not marshal NegTokenInit: %v", err)
		}
		b = append(hb, tb...)
	}
	if s.Resp {
		tb, err := s.NegTokenResp.Marshal()
		if err != nil {
			return b, fmt.Errorf("Could not marshal NegTokenResp: %v", err)
		}
		b = append(hb, tb...)
	}
	return asn1tools.AddASNAppTag(b, 0), nil
}
<commit_msg>comment<commit_after>// Generic Security Services Application Program Interface implementation required for SPNEGO kerberos authentication.
package GSSAPI

import (
	"errors"
	"fmt"
	"github.com/jcmturner/asn1"
	"github.com/jcmturner/gokrb5/asn1tools"
)

var SPNEGO_OID = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 2}

type SPNEGO struct {
	Init         bool
	Resp         bool
	NegTokenInit NegTokenInit
	NegTokenResp NegTokenResp
}

// Unmarshal SPNEGO negotiation token
func (s *SPNEGO) Unmarshal(b []byte) error {
	var r []byte
	var err error
	if b[0] != byte(161) {
		// Not a NegTokenResp/Targ could be a NegTokenInit
		var oid asn1.ObjectIdentifier
		r, err = asn1.UnmarshalWithParams(b, &oid, fmt.Sprintf("application,explicit,tag:%v", 0))
		if err != nil {
			return fmt.Errorf("Not a valid SPNEGO token: %v", err)
		}
		// Check the OID is the SPNEGO OID value
		if !oid.Equal(asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 2}) {
			return errors.New("OID does not match SPNEGO OID 1.3.6.1.5.5.2")
		}
	} else {
		// Could be a NegTokenResp/Targ
		r = b
	}

	var a asn1.RawValue
	_, err = asn1.Unmarshal(r, &a)
	if err != nil {
		return fmt.Errorf("Error unmarshalling SPNEGO: %v", err)
	}
	switch a.Tag {
	case 0:
		_, err = asn1.Unmarshal(a.Bytes, &s.NegTokenInit)
		if err != nil {
			return fmt.Errorf("Error unmarshalling NegotiationToken type %d (Init): %v", a.Tag, err)
		}
		s.Init = true
	case 1:
		_, err = asn1.Unmarshal(a.Bytes, &s.NegTokenResp)
		if err != nil {
			return fmt.Errorf("Error unmarshalling NegotiationToken type %d (Resp/Targ): %v", a.Tag, err)
		}
		s.Resp = true
	default:
		return errors.New("Unknown choice type for NegotiationToken")
	}
	return nil
}

// Marshal SPNEGO negotiation token
func (s *SPNEGO) Marshal() ([]byte, error) {
	var b []byte
	if !s.Init && !s.Resp {
		return b, errors.New("SPNEGO cannot be marshalled. It contains neither a NegTokenInit or NegTokenResp")
	}
	hb, _ := asn1.Marshal(SPNEGO_OID)
	if s.Init {
		tb, err := s.NegTokenInit.Marshal()
		if err != nil {
			return b, fmt.Errorf("Could not marshal NegTokenInit: %v", err)
		}
		b = append(hb, tb...)
	}
	if s.Resp {
		tb, err := s.NegTokenResp.Marshal()
		if err != nil {
			return b, fmt.Errorf("Could not marshal NegTokenResp: %v", err)
		}
		b = append(hb, tb...)
	}
	return asn1tools.AddASNAppTag(b, 0), nil
}
<|endoftext|>


<commit_before>package mailserver

// This file describes two routes that are used throughout the Melange System.

import (
	"airdispat.ch/identity"
	"airdispat.ch/routing"
	"airdispat.ch/tracker"
	"errors"
	"strings"
)

var ServerKey *identity.Identity

func InitRouter() {
	if ServerKey == nil {
		ServerKey, _ = identity.CreateIdentity()
	}
	if RegistrationRouter == nil {
		RegistrationRouter = &tracker.TrackerRouter{
			tracker.GetTrackingServerLocationFromURL("airdispat.ch"),
			ServerKey,
		}
	}
	if LookupRouter == nil {
		LookupRouter = &Router{ServerKey}
	}
}

var RegistrationRouter routing.Router
var LookupRouter routing.Router

type Router struct {
	Origin *identity.Identity
}

func (a *Router) LookupAlias(from string) (*identity.Address, error) {
	comp := strings.Split("@", from)
	if len(comp) != 2 {
		return nil, errors.New("Can't use lookup router without tracker address.")
	}

	url := tracker.GetTrackingServerLocationFromURL(comp[1])
	t := tracker.CreateTrackerListRouterWithStrings(a.Origin, url)

	return t.LookupAlias(from)
}

func (a *Router) Lookup(from string) (*identity.Address, error) {
	return nil, errors.New("Can't use lookup router for non-aliased names.")
}

func (a *Router) Register(key *identity.Identity, alias string) error {
	return errors.New("Can't use LookupRouter for registration.")
}
<commit_msg>Fixed String Splitting Error<commit_after>package mailserver

// This file describes two routes that are used throughout the Melange System.

import (
	"airdispat.ch/identity"
	"airdispat.ch/routing"
	"airdispat.ch/tracker"
	"errors"
	"strings"
)

var ServerKey *identity.Identity

func InitRouter() {
	if ServerKey == nil {
		ServerKey, _ = identity.CreateIdentity()
	}
	if RegistrationRouter == nil {
		RegistrationRouter = &tracker.TrackerRouter{
			tracker.GetTrackingServerLocationFromURL("airdispat.ch"),
			ServerKey,
		}
	}
	if LookupRouter == nil {
		LookupRouter = &Router{ServerKey}
	}
}

var RegistrationRouter routing.Router
var LookupRouter routing.Router

type Router struct {
	Origin *identity.Identity
}

func (a *Router) LookupAlias(from string) (*identity.Address, error) {
	comp := strings.Split(from, "@")
	if len(comp) != 2 {
		return nil, errors.New("Can't use lookup router without tracker address.")
	}

	url := tracker.GetTrackingServerLocationFromURL(comp[1])
	t := tracker.CreateTrackerListRouterWithStrings(a.Origin, url)

	return t.LookupAlias(from)
}

func (a *Router) Lookup(from string) (*identity.Address, error) {
	return nil, errors.New("Can't use lookup router for non-aliased names.")
}

func (a *Router) Register(key *identity.Identity, alias string) error {
	return errors.New("Can't use LookupRouter for registration.")
}
<|endoftext|>


<commit_before>/*

*/
package mandrake

import (
	"log"
	"net/rpc/jsonrpc"
	"github.com/natefinch/pie"
)

type Mandrake struct {
	consumers		chan string
}

func NewMandrake() (*Mandrake, error) {
	return &Mandrake{make(chan string)}, nil
}

func (m *Mandrake) ListenAndServe() {
	p := pie.NewProvider()
	if err := p.RegisterName("mandrake", m); err != nil {
		log.Fatalf("Failed to register plugin: %s", err)
	}

	go p.ServeCodec(jsonrpc.NewServerCodec)
}

func (m *Mandrake) Analyze(fname string, response *string) error {
	log.Printf("Beginning analysis: %s", fname)

	m.consumers <- fname

	return nil
}<commit_msg>update all<commit_after>/*

*/
package mandrake

import (
	"log"

	"github.com/hosom/gomandrake/config"
	"github.com/hosom/gomandrake/plugin"
)

type Mandrake struct {
	AnalysisPipeline	chan string
	Input				string
}

func NewMandrake(c config.Config) (*Mandrake, error) {
	return &Mandrake{make(chan string), c.Input}, nil
}

func (m *Mandrake) ListenAndServe() {
	go plugin.CreateListenerAndServe(m.AnalysisPipelinem, m.Input)
}<|endoftext|>


<commit_before>package dragon

import (
	"bufio"
	"go/build"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/sync/errgroup"
)

var (
	apiFiles = [...]string{
		"go1.txt",
		"go1.1.txt",
		"go1.2.txt",
		"go1.3.txt",
		"go1.4.txt",
		"go1.5.txt",
		"go1.6.txt",
		"go1.7.txt",
		"go1.8.txt",
		"go1.9.txt",
		"go1.10.txt",
	}
	sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`)
)

func stdLibs(libChan chan lib) error {
	apiDir := filepath.Join(build.Default.GOROOT, "api")
	eg := &errgroup.Group{}
	for _, f := range apiFiles {
		r, err := os.Open(filepath.Join(apiDir, f))
		if err != nil {
			return err
		}
		eg.Go(func() error {
			sc := bufio.NewScanner(r)
			for sc.Scan() {
				l := sc.Text()
				has := func(v string) bool { return strings.Contains(l, v) }
				if has("struct, ") || has("interface, ") || has(", method (") {
					continue
				}

				if m := sym.FindStringSubmatch(l); m != nil {
					libChan <- lib{
						pkg:    path.Base(m[1]),
						object: m[2],
						path:   m[1],
					}
				}
			}
			return sc.Err()
		})
	}
	return eg.Wait()
}
<commit_msg>retrieve apiFiles by using glob<commit_after>package dragon

import (
	"bufio"
	"go/build"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/sync/errgroup"
)

var sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`)

func stdLibs(libChan chan lib) error {
	apiFiles, err := filepath.Glob(filepath.Join(build.Default.GOROOT, "api", "go1.*txt"))
	if err != nil {
		return err
	}
	eg := &errgroup.Group{}
	for _, f := range apiFiles {
		r, err := os.Open(f)
		if err != nil {
			return err
		}
		eg.Go(func() error {
			sc := bufio.NewScanner(r)
			for sc.Scan() {
				l := sc.Text()
				has := func(v string) bool { return strings.Contains(l, v) }
				if has("struct, ") || has("interface, ") || has(", method (") {
					continue
				}

				if m := sym.FindStringSubmatch(l); m != nil {
					libChan <- lib{
						pkg:    path.Base(m[1]),
						object: m[2],
						path:   m[1],
					}
				}
			}
			return sc.Err()
		})
	}
	return eg.Wait()
}
<|endoftext|>


<commit_before>package luddite

import (
	"fmt"
	"net/http"
	"os"
	"runtime"
	"strings"
	"time"

	log "github.com/SpirentOrion/logrus"
	"github.com/SpirentOrion/luddite/datastore"
	"github.com/SpirentOrion/luddite/stats"
	"github.com/SpirentOrion/trace"
	"github.com/SpirentOrion/trace/dynamorec"
	"github.com/SpirentOrion/trace/yamlrec"
	"github.com/rs/cors"
	"golang.org/x/net/context"
)

const MAX_STACK_SIZE = 8 * 1024

// Bottom is the bottom-most middleware layer that combines CORS,
// tracing, logging, metrics and recovery actions. Tracing generates a
// unique request id and optionally records traces to a persistent
// backend.  Logging logs requests/responses in a structured JSON
// format.  Metrics increments basic request/response stats. Recovery
// handles panics that occur in HTTP method handlers and optionally
// includes stack traces in 500 responses.
type Bottom struct {
	defaultLogger *log.Logger
	accessLogger  *log.Logger
	stats         stats.Stats
	respStacks    bool
	respStackSize int
	cors          *cors.Cors
}

// NewBottom returns a new Bottom instance.
func NewBottom(config *ServiceConfig, defaultLogger, accessLogger *log.Logger, stats stats.Stats) *Bottom {
	b := &Bottom{
		defaultLogger: defaultLogger,
		accessLogger:  accessLogger,
		stats:         stats,
		respStacks:    config.Debug.Stacks,
		respStackSize: config.Debug.StackSize,
	}

	if b.respStacks && b.respStackSize < 1 {
		b.respStackSize = MAX_STACK_SIZE
	}

	if config.Cors.Enabled {
		// Enable CORS
		corsOptions := cors.Options{
			AllowedOrigins:   config.Cors.AllowedOrigins,
			AllowedMethods:   config.Cors.AllowedMethods,
			AllowCredentials: config.Cors.AllowCredentials,
		}
		if len(corsOptions.AllowedMethods) == 0 {
			corsOptions.AllowedMethods = []string{"GET", "POST", "PUT", "DELETE"}
		}
		b.cors = cors.New(corsOptions)
	}

	if config.Trace.Enabled {
		// Enable trace recording
		var (
			rec trace.Recorder
			err error
		)
		switch config.Trace.Recorder {
		case datastore.YAML_PROVIDER:
			var p *datastore.YAMLParams
			p, err = datastore.NewYAMLParams(config.Trace.Params)
			if err != nil {
				break
			}
			var f *os.File
			f, err = os.OpenFile(p.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
			if err != nil {
				break
			}
			rec, err = yamlrec.New(f)
			if err != nil {
				f.Close()
			}
		case datastore.DYNAMODB_PROVIDER:
			var p *datastore.DynamoParams
			p, err = datastore.NewDynamoParams(config.Trace.Params)
			if err != nil {
				break
			}
			rec, err = dynamorec.New(p.Region, p.TableName, p.AccessKey, p.SecretKey)
		default:
			err = fmt.Errorf("unknown trace recorder: %s", config.Trace.Recorder)
		}

		if rec != nil {
			err = trace.Record(rec, config.Trace.Buffer, defaultLogger)
		}

		if err != nil {
			defaultLogger.Warn("trace recording is not active: ", err)
		} else {
			defaultLogger.Debug("recording traces to ", rec)
		}
	}

	return b
}

func (b *Bottom) HandleHTTP(ctx context.Context, rw http.ResponseWriter, req *http.Request, next ContextHandlerFunc) {
	// Start duration measurement ASAP
	start := time.Now()
	var latency time.Duration

	// Don't allow panics to escape the bottom handler under any circumstances!
	defer func() {
		if rcv := recover(); rcv != nil {
			stack := make([]byte, MAX_STACK_SIZE)
			stack = stack[:runtime.Stack(stack, false)]
			b.defaultLogger.WithFields(log.Fields{
				"error": rcv,
				"stack": string(stack),
			}).Error("PANIC")
		}
	}()

	// Handle CORS preflight requests prior to tracing
	if b.cors != nil && req.Method == "OPTIONS" {
		b.cors.HandlerFunc(rw, req)
		return
	}

	// For now, always honor incoming id headers. If present, header must be in the form "traceId:parentId"
	traceId, parentId := b.getRequestTraceIds(req)

	// Start a new trace, either using an existing id (from the request header) or a new one
	if traceId == 0 {
		traceId, _ = trace.GenerateId()
	}
	s, _ := trace.New(traceId, TraceKindRequest, req.URL.Path)
	if s != nil {
		s.ParentId = parentId
	}
	b.addRequestResponseTraceIds(rw, req, traceId)

	res := rw.(ResponseWriter)
	trace.Run(s, func() {
		// If a panic occurs in a downstream handler, log it, generate a 500 error
		// response, and annotate the trace with additional panic-related info
		defer func() {
			if rcv := recover(); rcv != nil {
				stack := make([]byte, MAX_STACK_SIZE)
				stack = stack[:runtime.Stack(stack, false)]
				b.defaultLogger.WithFields(log.Fields{
					"error": rcv,
					"stack": string(stack),
				}).Error("PANIC")

				resp := NewError(nil, EcodeInternal, rcv)
				if b.respStacks {
					if len(stack) > b.respStackSize {
						resp.Stack = string(stack[:b.respStackSize])
					} else {
						resp.Stack = string(stack)
					}
				}
				WriteResponse(rw, http.StatusInternalServerError, resp)
				latency = time.Now().Sub(start)

				b.accessLogger.WithFields(log.Fields{
					"client_addr":   req.RemoteAddr,
					"forwarded_for": req.Header.Get(HeaderForwardedFor),
					"proto":         req.Proto,
					"method":        req.Method,
					"uri":           req.RequestURI,
					"status_code":   res.Status(),
					"size":          res.Size(),
					"user_agent":    req.UserAgent(),
					"req_id":        traceId,
					"api_version":   rw.Header().Get(HeaderSpirentApiVersion),
					"time_duration": fmt.Sprintf("%.3f", latency.Seconds()*1000),
				}).Error()

				if s != nil {
					data := s.Data()
					data["panic"] = rcv
					data["stack"] = string(stack)
					data["req_method"] = req.Method
					data["resp_status"] = res.Status()
					data["resp_size"] = res.Size()
				}
			}
		}()

		// Invoke the next handler
		next(ctx, rw, req)

		// Log the request
		status := res.Status()
		latency = time.Now().Sub(start)
		entry := b.accessLogger.WithFields(log.Fields{
			"client_addr":   req.RemoteAddr,
			"forwarded_for": req.Header.Get(HeaderForwardedFor),
			"proto":         req.Proto,
			"method":        req.Method,
			"uri":           req.RequestURI,
			"status_code":   status,
			"size":          res.Size(),
			"user_agent":    req.UserAgent(),
			"req_id":        traceId,
			"api_version":   rw.Header().Get(HeaderSpirentApiVersion),
			"time_duration": fmt.Sprintf("%.3f", latency.Seconds()*1000),
		})
		if status/100 != 5 {
			entry.Info()
		} else {
			entry.Error()
		}

		// Annotate the trace
		if s != nil {
			data := s.Data()
			data["req_method"] = req.Method
			data["resp_status"] = res.Status()
			data["resp_size"] = res.Size()
		}
	})

	// Update request/response metrics
	stat := fmt.Sprintf("request.http.%s", strings.ToLower(req.Method))
	b.stats.Incr(stat, 1)
	stat = fmt.Sprintf("response.http.%s.%d", strings.ToLower(req.Method), res.Status())
	b.stats.Incr(stat, 1)
}

func (b *Bottom) getRequestTraceIds(req *http.Request) (traceId, parentId int64) {
	if hdr := req.Header.Get(HeaderRequestId); hdr != "" {
		n, _ := fmt.Sscanf(hdr, "%d:%d", &traceId, &parentId)
		if n < 2 || traceId < 1 || parentId < 1 {
			traceId = 0
			parentId = 0
		}
	}
	return
}

func (b *Bottom) addRequestResponseTraceIds(rw http.ResponseWriter, req *http.Request, traceId int64) {
	traceIdStr := fmt.Sprint(traceId)
	req.Header.Set(HeaderRequestId, traceIdStr)
	rw.Header().Set(HeaderRequestId, traceIdStr)
}
<commit_msg>Modify error logging.<commit_after>package luddite

import (
	"fmt"
	"net/http"
	"os"
	"runtime"
	"strings"
	"time"

	log "github.com/SpirentOrion/logrus"
	"github.com/SpirentOrion/luddite/datastore"
	"github.com/SpirentOrion/luddite/stats"
	"github.com/SpirentOrion/trace"
	"github.com/SpirentOrion/trace/dynamorec"
	"github.com/SpirentOrion/trace/yamlrec"
	"github.com/rs/cors"
	"golang.org/x/net/context"
)

const MAX_STACK_SIZE = 8 * 1024

// Bottom is the bottom-most middleware layer that combines CORS,
// tracing, logging, metrics and recovery actions. Tracing generates a
// unique request id and optionally records traces to a persistent
// backend.  Logging logs requests/responses in a structured JSON
// format.  Metrics increments basic request/response stats. Recovery
// handles panics that occur in HTTP method handlers and optionally
// includes stack traces in 500 responses.
type Bottom struct {
	defaultLogger *log.Logger
	accessLogger  *log.Logger
	stats         stats.Stats
	respStacks    bool
	respStackSize int
	cors          *cors.Cors
}

// NewBottom returns a new Bottom instance.
func NewBottom(config *ServiceConfig, defaultLogger, accessLogger *log.Logger, stats stats.Stats) *Bottom {
	b := &Bottom{
		defaultLogger: defaultLogger,
		accessLogger:  accessLogger,
		stats:         stats,
		respStacks:    config.Debug.Stacks,
		respStackSize: config.Debug.StackSize,
	}

	if b.respStacks && b.respStackSize < 1 {
		b.respStackSize = MAX_STACK_SIZE
	}

	if config.Cors.Enabled {
		// Enable CORS
		corsOptions := cors.Options{
			AllowedOrigins:   config.Cors.AllowedOrigins,
			AllowedMethods:   config.Cors.AllowedMethods,
			AllowCredentials: config.Cors.AllowCredentials,
		}
		if len(corsOptions.AllowedMethods) == 0 {
			corsOptions.AllowedMethods = []string{"GET", "POST", "PUT", "DELETE"}
		}
		b.cors = cors.New(corsOptions)
	}

	if config.Trace.Enabled {
		// Enable trace recording
		var (
			rec trace.Recorder
			err error
		)
		switch config.Trace.Recorder {
		case datastore.YAML_PROVIDER:
			var p *datastore.YAMLParams
			p, err = datastore.NewYAMLParams(config.Trace.Params)
			if err != nil {
				break
			}
			var f *os.File
			f, err = os.OpenFile(p.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
			if err != nil {
				break
			}
			rec, err = yamlrec.New(f)
			if err != nil {
				f.Close()
			}
		case datastore.DYNAMODB_PROVIDER:
			var p *datastore.DynamoParams
			p, err = datastore.NewDynamoParams(config.Trace.Params)
			if err != nil {
				break
			}
			rec, err = dynamorec.New(p.Region, p.TableName, p.AccessKey, p.SecretKey)
		default:
			err = fmt.Errorf("unknown trace recorder: %s", config.Trace.Recorder)
		}

		if rec != nil {
			err = trace.Record(rec, config.Trace.Buffer, defaultLogger)
		}

		if err != nil {
			defaultLogger.Warn("trace recording is not active: ", err)
		} else {
			defaultLogger.Debug("recording traces to ", rec)
		}
	}

	return b
}

func (b *Bottom) HandleHTTP(ctx context.Context, rw http.ResponseWriter, req *http.Request, next ContextHandlerFunc) {
	// Start duration measurement ASAP
	start := time.Now()
	var latency time.Duration

	// Don't allow panics to escape the bottom handler under any circumstances!
	defer func() {
		if rcv := recover(); rcv != nil {
			stack := make([]byte, MAX_STACK_SIZE)
			stack = stack[:runtime.Stack(stack, false)]
			b.defaultLogger.WithFields(log.Fields{
				"stack": string(stack),
			}).Error(rcv)
		}
	}()

	// Handle CORS preflight requests prior to tracing
	if b.cors != nil && req.Method == "OPTIONS" {
		b.cors.HandlerFunc(rw, req)
		return
	}

	// For now, always honor incoming id headers. If present, header must be in the form "traceId:parentId"
	traceId, parentId := b.getRequestTraceIds(req)

	// Start a new trace, either using an existing id (from the request header) or a new one
	if traceId == 0 {
		traceId, _ = trace.GenerateId()
	}
	s, _ := trace.New(traceId, TraceKindRequest, req.URL.Path)
	if s != nil {
		s.ParentId = parentId
	}
	b.addRequestResponseTraceIds(rw, req, traceId)

	res := rw.(ResponseWriter)
	trace.Run(s, func() {
		// If a panic occurs in a downstream handler, log it, generate a 500 error
		// response, and annotate the trace with additional panic-related info
		defer func() {
			if rcv := recover(); rcv != nil {
				stack := make([]byte, MAX_STACK_SIZE)
				stack = stack[:runtime.Stack(stack, false)]
				b.defaultLogger.WithFields(log.Fields{
					"stack": string(stack),
				}).Error(rcv)

				resp := NewError(nil, EcodeInternal, rcv)
				if b.respStacks {
					if len(stack) > b.respStackSize {
						resp.Stack = string(stack[:b.respStackSize])
					} else {
						resp.Stack = string(stack)
					}
				}
				WriteResponse(rw, http.StatusInternalServerError, resp)
				latency = time.Now().Sub(start)

				b.accessLogger.WithFields(log.Fields{
					"client_addr":   req.RemoteAddr,
					"forwarded_for": req.Header.Get(HeaderForwardedFor),
					"proto":         req.Proto,
					"method":        req.Method,
					"uri":           req.RequestURI,
					"status_code":   res.Status(),
					"size":          res.Size(),
					"user_agent":    req.UserAgent(),
					"req_id":        traceId,
					"api_version":   rw.Header().Get(HeaderSpirentApiVersion),
					"time_duration": fmt.Sprintf("%.3f", latency.Seconds()*1000),
				}).Error()

				if s != nil {
					data := s.Data()
					data["panic"] = rcv
					data["stack"] = string(stack)
					data["req_method"] = req.Method
					data["resp_status"] = res.Status()
					data["resp_size"] = res.Size()
				}
			}
		}()

		// Invoke the next handler
		next(ctx, rw, req)

		// Log the request
		status := res.Status()
		latency = time.Now().Sub(start)
		entry := b.accessLogger.WithFields(log.Fields{
			"client_addr":   req.RemoteAddr,
			"forwarded_for": req.Header.Get(HeaderForwardedFor),
			"proto":         req.Proto,
			"method":        req.Method,
			"uri":           req.RequestURI,
			"status_code":   status,
			"size":          res.Size(),
			"user_agent":    req.UserAgent(),
			"req_id":        traceId,
			"api_version":   rw.Header().Get(HeaderSpirentApiVersion),
			"time_duration": fmt.Sprintf("%.3f", latency.Seconds()*1000),
		})
		if status/100 != 5 {
			entry.Info()
		} else {
			entry.Error()
		}

		// Annotate the trace
		if s != nil {
			data := s.Data()
			data["req_method"] = req.Method
			data["resp_status"] = res.Status()
			data["resp_size"] = res.Size()
		}
	})

	// Update request/response metrics
	stat := fmt.Sprintf("request.http.%s", strings.ToLower(req.Method))
	b.stats.Incr(stat, 1)
	stat = fmt.Sprintf("response.http.%s.%d", strings.ToLower(req.Method), res.Status())
	b.stats.Incr(stat, 1)
}

func (b *Bottom) getRequestTraceIds(req *http.Request) (traceId, parentId int64) {
	if hdr := req.Header.Get(HeaderRequestId); hdr != "" {
		n, _ := fmt.Sscanf(hdr, "%d:%d", &traceId, &parentId)
		if n < 2 || traceId < 1 || parentId < 1 {
			traceId = 0
			parentId = 0
		}
	}
	return
}

func (b *Bottom) addRequestResponseTraceIds(rw http.ResponseWriter, req *http.Request, traceId int64) {
	traceIdStr := fmt.Sprint(traceId)
	req.Header.Set(HeaderRequestId, traceIdStr)
	rw.Header().Set(HeaderRequestId, traceIdStr)
}
<|endoftext|>


<commit_before>package osm

import (
	"errors"

	"github.com/paulmach/orb/tile"
)

// Bounds are the bounds of osm data as defined in the xml file.
type Bounds struct {
	MinLat float64 `xml:"minlat,attr"`
	MaxLat float64 `xml:"maxlat,attr"`
	MinLon float64 `xml:"minlon,attr"`
	MaxLon float64 `xml:"maxlon,attr"`
}

// NewBoundsFromTile creates a bound given an online map tile index.
func NewBoundsFromTile(x, y, z uint32) (*Bounds, error) {
	maxIndex := uint32(1) << z
	if x >= maxIndex {
		return nil, errors.New("osm: x index out of range for this zoom")
	}
	if y >= maxIndex {
		return nil, errors.New("osm: y index out of range for this zoom")
	}

	b := tile.Tile{X: x, Y: y, Z: z}.GeoBound()

	return &Bounds{
		MinLat: b[0].Lat(),
		MaxLat: b[1].Lat(),
		MinLon: b[0].Lon(),
		MaxLon: b[1].Lon(),
	}, nil
}

// ContainsNode returns true if the node is within the bound.
// Uses inclusive intervals, ie. returns true if on the boundary.
func (b *Bounds) ContainsNode(n *Node) bool {
	if n.Lat < b.MinLat || n.Lat > b.MaxLat {
		return false
	}

	if n.Lon < b.MinLon || n.Lon > b.MaxLon {
		return false
	}

	return true
}
<commit_msg>fix for updates in orb/tile<commit_after>package osm

import (
	"errors"

	"github.com/paulmach/orb/tile"
)

// Bounds are the bounds of osm data as defined in the xml file.
type Bounds struct {
	MinLat float64 `xml:"minlat,attr"`
	MaxLat float64 `xml:"maxlat,attr"`
	MinLon float64 `xml:"minlon,attr"`
	MaxLon float64 `xml:"maxlon,attr"`
}

// NewBoundsFromTile creates a bound given an online map tile index.
func NewBoundsFromTile(x, y, z uint32) (*Bounds, error) {
	maxIndex := uint32(1) << z
	if x >= maxIndex {
		return nil, errors.New("osm: x index out of range for this zoom")
	}
	if y >= maxIndex {
		return nil, errors.New("osm: y index out of range for this zoom")
	}

	b := tile.Tile{X: x, Y: y, Z: z}.Bound()

	return &Bounds{
		MinLat: b[0].Lat(),
		MaxLat: b[1].Lat(),
		MinLon: b[0].Lon(),
		MaxLon: b[1].Lon(),
	}, nil
}

// ContainsNode returns true if the node is within the bound.
// Uses inclusive intervals, ie. returns true if on the boundary.
func (b *Bounds) ContainsNode(n *Node) bool {
	if n.Lat < b.MinLat || n.Lat > b.MaxLat {
		return false
	}

	if n.Lon < b.MinLon || n.Lon > b.MaxLon {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>package gotomic

import (
	"fmt"
	"runtime"
	"testing"
)

type testNode struct {
	value string
	left  *testNode
	right *testNode
}

func (self *testNode) Clone() Clonable {
	rval := *self
	return &rval
}

func tWrite(t *testing.T, tr *Transaction, h *Handle) Thing {
	x, err := tr.Write(h)
	if err != nil {
		t.Errorf("%v should be able to write %v, but got %v", tr, h, err)
	}
	return x
}

func tRead(t *testing.T, tr *Transaction, h *Handle) Thing {
	x, err := tr.Read(h)
	if err != nil {
		t.Errorf("%v should be able to read %v, but got %v", tr, h, err)
	}
	return x
}

func TestIsolation(t *testing.T) {
	h := NewHandle(&testNode{"a", nil, nil})
	tr := NewTransaction()
	n := tWrite(t, tr, h).(*testNode)
	if n.value != "a" {
		t.Errorf("%v should be 'a'", n.value)
	}
	n.value = "b"
	if n.value != "b" {
		t.Errorf("%v should be 'b'", n.value)
	}
	tr2 := NewTransaction()
	n2 := tWrite(t, tr2, h).(*testNode)
	if n2.value != "a" {
		t.Errorf("%v should be 'a'", n2.value)
	}
	n2.value = "c"
	if n2.value != "c" {
		t.Errorf("%v should be 'c'", n2.value)
	}
}

func TestReadBreakage(t *testing.T) {
	h := NewHandle(&testNode{"a", nil, nil})
	tr := NewTransaction()
	tr2 := NewTransaction()
	n2 := tWrite(t, tr2, h).(*testNode)
	if n2.value != "a" {
		t.Errorf("%v should be 'a'", n2.value)
	}
	if !tr2.Commit() {
		t.Errorf("%v should commit!")
	}
	n, err := tr.Write(h)
	if err == nil {
		t.Errorf("%v should not allow reading of %v, but got %v", tr, h, n)
	}
}

func TestDiffTrans1(t *testing.T) {
	tr1 := NewTransaction()
	tr2 := NewTransaction()
	h1 := NewHandle(&testNode{"a", nil, nil})
	h2 := NewHandle(&testNode{"b", nil, nil})
	h3 := NewHandle(&testNode{"c", nil, nil})
	n11 := tRead(t, tr1, h1).(*testNode)
	n12 := tRead(t, tr1, h2).(*testNode)
	n22 := tRead(t, tr2, h2).(*testNode)
	n23 := tRead(t, tr2, h3).(*testNode)
	if n11.value != "a" {
		t.Error("bad value")
	}
	if n12.value != "b" {
		t.Error("bad value")
	}
	if n22.value != "b" {
		t.Error("bad value")
	}
	if n23.value != "c" {
		t.Error("bad value")
	}
	if !tr1.Commit() {
		t.Error("should commit")
	}
	if !tr2.Commit() {
		t.Error("should commit")
	}
}

func TestDiffTrans2(t *testing.T) {
	tr1 := NewTransaction()
	tr2 := NewTransaction()
	h1 := NewHandle(&testNode{"a", nil, nil})
	h2 := NewHandle(&testNode{"b", nil, nil})
	h3 := NewHandle(&testNode{"c", nil, nil})
	n11 := tWrite(t, tr1, h1).(*testNode)
	n12 := tRead(t, tr1, h2).(*testNode)
	n22 := tRead(t, tr2, h2).(*testNode)
	n23 := tWrite(t, tr2, h3).(*testNode)
	if n11.value != "a" {
		t.Error("bad value")
	}
	if n12.value != "b" {
		t.Error("bad value")
	}
	if n22.value != "b" {
		t.Error("bad value")
	}
	if n23.value != "c" {
		t.Error("bad value")
	}
	n11.value = "a2"
	n23.value = "c2"
	if !tr1.Commit() {
		t.Error("should commit")
	}
	if !tr2.Commit() {
		t.Error("should commit")
	}
	tr3 := NewTransaction()
	if tRead(t, tr3, h1).(*testNode).value != "a2" {
		t.Error("bad value")
	}
	if tRead(t, tr3, h3).(*testNode).value != "c2" {
		t.Error("bad value")
	}
}

func TestDiffTrans3(t *testing.T) {
	tr1 := NewTransaction()
	tr2 := NewTransaction()
	h1 := NewHandle(&testNode{"a", nil, nil})
	h2 := NewHandle(&testNode{"b", nil, nil})
	h3 := NewHandle(&testNode{"c", nil, nil})
	n11 := tWrite(t, tr1, h1).(*testNode)
	n12 := tWrite(t, tr1, h2).(*testNode)
	n22 := tWrite(t, tr2, h2).(*testNode)
	n23 := tWrite(t, tr2, h3).(*testNode)
	if n11.value != "a" {
		t.Error("bad value")
	}
	if n12.value != "b" {
		t.Error("bad value")
	}
	if n22.value != "b" {
		t.Error("bad value")
	}
	if n23.value != "c" {
		t.Error("bad value")
	}
	n12.value = "b2"
	n22.value = "b3"
	if !tr1.Commit() {
		t.Error("should commit")
	}
	if tr2.Commit() {
		t.Error("should not commit")
	}
	tr3 := NewTransaction()
	if tRead(t, tr3, h2).(*testNode).value != "b2" {
		t.Error("bad value")
	}
}

func fiddleTrans(t *testing.T, x string, h1, h2 *Handle, do, done chan bool) {
	<-do
	for i := 0; i < 10000; i++ {
		tr := NewTransaction()
		n1, err1 := tr.Write(h1)
		n2, err2 := tr.Write(h2)
		if err1 == nil && err2 == nil {
			if n1.(*testNode).value != n2.(*testNode).value {
				t.Errorf("%v, %v: %v should == %v", x, i, n1, n2)
			}
			n1.(*testNode).value = x
			n2.(*testNode).value = x
			tr = NewTransaction()
			n1, err1 = tr.Read(h1)
			n2, err2 = tr.Read(h2)
			if err1 == nil && err2 == nil && n1.(*testNode).value != n2.(*testNode).value {
				t.Errorf("%v, %v: %v should == %v", x, i, n1, n2)
			}
		}
	}
	done <- true
}

func TestTransConcurrency(t *testing.T) {
	runtime.GOMAXPROCS(runtime.NumCPU())
	do := make(chan bool)
	done := make(chan bool)
	h1 := NewHandle(&testNode{"a", nil, nil})
	h2 := NewHandle(&testNode{"a", nil, nil})
	for i := 0; i < runtime.NumCPU(); i++ {
		go fiddleTrans(t, fmt.Sprint(i), h1, h2, do, done)
	}
	close(do)
	for i := 0; i < runtime.NumCPU(); i++ {
		<-done
	}
}

func TestCommit(t *testing.T) {
	h := NewHandle(&testNode{"a", nil, nil})
	tr := NewTransaction()
	n := tWrite(t, tr, h).(*testNode)
	if n.value != "a" {
		t.Errorf("%v should be 'a'", n.value)
	}
	n.value = "b"
	if n.value != "b" {
		t.Errorf("%v should be 'b'", n.value)
	}
	tr2 := NewTransaction()
	n2 := tWrite(t, tr2, h).(*testNode)
	if n2.value != "a" {
		t.Errorf("%v should be 'a'", n2.value)
	}
	n2.value = "c"
	if n2.value != "c" {
		t.Errorf("%v should be 'c'", n2.value)
	}
	if !tr.Commit() {
		t.Errorf("%v should commit", tr)
	}
	tr3 := NewTransaction()
	n3 := tWrite(t, tr3, h).(*testNode)
	if n3.value != "b" {
		t.Errorf("%v should be 'b'", n3.value)
	}
	if n2.value != "c" {
		t.Errorf("%v should be 'c'", n2.value)
	}
	if tr2.Commit() {
		t.Errorf("%v should not commit", tr2)
	}
	tr4 := NewTransaction()
	n4 := tWrite(t, tr4, h).(*testNode)
	if n4.value != "b" {
		t.Errorf("%v should be 'b'", n4.value)
	}
}
<commit_msg>added non concurrent tests on a trivial binary tree<commit_after>package gotomic

import (
	"bytes"
	"fmt"
	"runtime"
	"testing"
)

func compStrings(i, j string) int {
	l := len(i)
	if len(j) < l {
		l = len(j)
	}
	for ind := 0; ind < l; ind++ {
		if i[ind] < j[ind] {
			return -1
		} else if i[ind] > j[ind] {
			return 1
		}
	}
	if len(i) < len(j) {
		return -1
	} else if len(i) > len(j) {
		return 1
	}
	return 0
}

type testNode struct {
	value string
	left  *Handle
	right *Handle
}

func (self *testNode) insert(t *Transaction, v string) error {
	cmp := compStrings(self.value, v)
	if cmp > 0 {
		if self.left == nil {
			self.left = NewHandle(&testNode{v, nil, nil})
		} else {
			ln, err := t.Write(self.left)
			if err != nil {
				return err
			}
			if err = ln.(*testNode).insert(t, v); err != nil {
				return err
			}
		}
	} else if cmp < 0 {
		if self.right == nil {
			self.right = NewHandle(&testNode{v, nil, nil})
		} else {
			rn, err := t.Write(self.right)
			if err != nil {
				return err
			}
			if err = rn.(*testNode).insert(t, v); err != nil {
				return err
			}
		}
	}
	return nil
}
func (self *testNode) Clone() Clonable {
	rval := *self
	return &rval
}
func (self *testNode) indentString(t *Transaction, i int) string {
	buf := new(bytes.Buffer)
	for j := 0; j < i; j++ {
		fmt.Fprint(buf, " ")
	}
	fmt.Fprintf(buf, "%#v", self)
	if self.left != nil {
		if ln, _ := t.Read(self.left); ln != nil {
			fmt.Fprintf(buf, "\nl:%v", ln.(*testNode).indentString(t, i+1))
		}
	}
	if self.right != nil {
		if rn, _ := t.Read(self.right); rn != nil {
			fmt.Fprintf(buf, "\nr:%v", rn.(*testNode).indentString(t, i+1))
		}
	}
	return string(buf.Bytes())
}
func (self *testNode) String() string {
	return self.indentString(NewTransaction(), 0)
}

func TestSTMBasicTestTree(t *testing.T) {
	hc := NewHandle(&testNode{"c", nil, nil})
	tr := NewTransaction()
	nc := tWrite(t, tr, hc).(*testNode)
	if err := nc.insert(tr, "a"); err != nil {
		t.Errorf("%v should insert 'a' but got %v", nc, err)
	}
	if err := nc.insert(tr, "d"); err != nil {
		t.Errorf("%v should insert 'd' but got %v", nc, err)
	}
	if err := nc.insert(tr, "b"); err != nil {
		t.Errorf("%v should insert 'b' but got %v", nc, err)
	}
	tr.Commit()
	tr = NewTransaction()
	nc = tRead(t, tr, hc).(*testNode)
	if nc.value != "c" {
		t.Error("bad value")
	}
	nd := tRead(t, tr, nc.right).(*testNode)
	if nd.value != "d" {
		t.Error("bad value")
	}
	na := tRead(t, tr, nc.left).(*testNode)
	if na.value != "a" {
		t.Error("bad value")
	}
	nb := tRead(t, tr, na.right).(*testNode)
	if nb.value != "b" {
		t.Error("bad value")
	}
}

func tWrite(t *testing.T, tr *Transaction, h *Handle) Thing {
	x, err := tr.Write(h)
	if err != nil {
		t.Errorf("%v should be able to write %v, but got %v", tr, h, err)
	}
	return x
}

func tRead(t *testing.T, tr *Transaction, h *Handle) Thing {
	x, err := tr.Read(h)
	if err != nil {
		t.Errorf("%v should be able to read %v, but got %v", tr, h, err)
	}
	return x
}

func TestSTMIsolation(t *testing.T) {
	h := NewHandle(&testNode{"a", nil, nil})
	tr := NewTransaction()
	n := tWrite(t, tr, h).(*testNode)
	if n.value != "a" {
		t.Errorf("%v should be 'a'", n.value)
	}
	n.value = "b"
	if n.value != "b" {
		t.Errorf("%v should be 'b'", n.value)
	}
	tr2 := NewTransaction()
	n2 := tWrite(t, tr2, h).(*testNode)
	if n2.value != "a" {
		t.Errorf("%v should be 'a'", n2.value)
	}
	n2.value = "c"
	if n2.value != "c" {
		t.Errorf("%v should be 'c'", n2.value)
	}
}

func TestSTMReadBreakage(t *testing.T) {
	h := NewHandle(&testNode{"a", nil, nil})
	tr := NewTransaction()
	tr2 := NewTransaction()
	n2 := tWrite(t, tr2, h).(*testNode)
	if n2.value != "a" {
		t.Errorf("%v should be 'a'", n2.value)
	}
	if !tr2.Commit() {
		t.Errorf("%v should commit!")
	}
	n, err := tr.Write(h)
	if err == nil {
		t.Errorf("%v should not allow reading of %v, but got %v", tr, h, n)
	}
}

func TestSTMDiffTrans1(t *testing.T) {
	tr1 := NewTransaction()
	tr2 := NewTransaction()
	h1 := NewHandle(&testNode{"a", nil, nil})
	h2 := NewHandle(&testNode{"b", nil, nil})
	h3 := NewHandle(&testNode{"c", nil, nil})
	n11 := tRead(t, tr1, h1).(*testNode)
	n12 := tRead(t, tr1, h2).(*testNode)
	n22 := tRead(t, tr2, h2).(*testNode)
	n23 := tRead(t, tr2, h3).(*testNode)
	if n11.value != "a" {
		t.Error("bad value")
	}
	if n12.value != "b" {
		t.Error("bad value")
	}
	if n22.value != "b" {
		t.Error("bad value")
	}
	if n23.value != "c" {
		t.Error("bad value")
	}
	if !tr1.Commit() {
		t.Error("should commit")
	}
	if !tr2.Commit() {
		t.Error("should commit")
	}
}

func TestSTMDiffTrans2(t *testing.T) {
	tr1 := NewTransaction()
	tr2 := NewTransaction()
	h1 := NewHandle(&testNode{"a", nil, nil})
	h2 := NewHandle(&testNode{"b", nil, nil})
	h3 := NewHandle(&testNode{"c", nil, nil})
	n11 := tWrite(t, tr1, h1).(*testNode)
	n12 := tRead(t, tr1, h2).(*testNode)
	n22 := tRead(t, tr2, h2).(*testNode)
	n23 := tWrite(t, tr2, h3).(*testNode)
	if n11.value != "a" {
		t.Error("bad value")
	}
	if n12.value != "b" {
		t.Error("bad value")
	}
	if n22.value != "b" {
		t.Error("bad value")
	}
	if n23.value != "c" {
		t.Error("bad value")
	}
	n11.value = "a2"
	n23.value = "c2"
	if !tr1.Commit() {
		t.Error("should commit")
	}
	if !tr2.Commit() {
		t.Error("should commit")
	}
	tr3 := NewTransaction()
	if tRead(t, tr3, h1).(*testNode).value != "a2" {
		t.Error("bad value")
	}
	if tRead(t, tr3, h3).(*testNode).value != "c2" {
		t.Error("bad value")
	}
}

func TestSTMDiffTrans3(t *testing.T) {
	tr1 := NewTransaction()
	tr2 := NewTransaction()
	h1 := NewHandle(&testNode{"a", nil, nil})
	h2 := NewHandle(&testNode{"b", nil, nil})
	h3 := NewHandle(&testNode{"c", nil, nil})
	n11 := tWrite(t, tr1, h1).(*testNode)
	n12 := tWrite(t, tr1, h2).(*testNode)
	n22 := tWrite(t, tr2, h2).(*testNode)
	n23 := tWrite(t, tr2, h3).(*testNode)
	if n11.value != "a" {
		t.Error("bad value")
	}
	if n12.value != "b" {
		t.Error("bad value")
	}
	if n22.value != "b" {
		t.Error("bad value")
	}
	if n23.value != "c" {
		t.Error("bad value")
	}
	n12.value = "b2"
	n22.value = "b3"
	if !tr1.Commit() {
		t.Error("should commit")
	}
	if tr2.Commit() {
		t.Error("should not commit")
	}
	tr3 := NewTransaction()
	if tRead(t, tr3, h2).(*testNode).value != "b2" {
		t.Error("bad value")
	}
}

func fiddleTrans(t *testing.T, x string, h1, h2 *Handle, do, done chan bool) {
	<-do
	for i := 0; i < 10000; i++ {
		tr := NewTransaction()
		n1, err1 := tr.Write(h1)
		n2, err2 := tr.Write(h2)
		if err1 == nil && err2 == nil {
			if n1.(*testNode).value != n2.(*testNode).value {
				t.Errorf("%v, %v: %v should == %v", x, i, n1, n2)
			}
			n1.(*testNode).value = x
			n2.(*testNode).value = x
			tr = NewTransaction()
			n1, err1 = tr.Read(h1)
			n2, err2 = tr.Read(h2)
			if err1 == nil && err2 == nil && n1.(*testNode).value != n2.(*testNode).value {
				t.Errorf("%v, %v: %v should == %v", x, i, n1, n2)
			}
		}
	}
	done <- true
}

func TestSTMTransConcurrency(t *testing.T) {
	runtime.GOMAXPROCS(runtime.NumCPU())
	do := make(chan bool)
	done := make(chan bool)
	h1 := NewHandle(&testNode{"a", nil, nil})
	h2 := NewHandle(&testNode{"a", nil, nil})
	for i := 0; i < runtime.NumCPU(); i++ {
		go fiddleTrans(t, fmt.Sprint(i), h1, h2, do, done)
	}
	close(do)
	for i := 0; i < runtime.NumCPU(); i++ {
		<-done
	}
}

func TestSTMCommit(t *testing.T) {
	h := NewHandle(&testNode{"a", nil, nil})
	tr := NewTransaction()
	n := tWrite(t, tr, h).(*testNode)
	if n.value != "a" {
		t.Errorf("%v should be 'a'", n.value)
	}
	n.value = "b"
	if n.value != "b" {
		t.Errorf("%v should be 'b'", n.value)
	}
	tr2 := NewTransaction()
	n2 := tWrite(t, tr2, h).(*testNode)
	if n2.value != "a" {
		t.Errorf("%v should be 'a'", n2.value)
	}
	n2.value = "c"
	if n2.value != "c" {
		t.Errorf("%v should be 'c'", n2.value)
	}
	if !tr.Commit() {
		t.Errorf("%v should commit", tr)
	}
	tr3 := NewTransaction()
	n3 := tWrite(t, tr3, h).(*testNode)
	if n3.value != "b" {
		t.Errorf("%v should be 'b'", n3.value)
	}
	if n2.value != "c" {
		t.Errorf("%v should be 'c'", n2.value)
	}
	if tr2.Commit() {
		t.Errorf("%v should not commit", tr2)
	}
	tr4 := NewTransaction()
	n4 := tWrite(t, tr4, h).(*testNode)
	if n4.value != "b" {
		t.Errorf("%v should be 'b'", n4.value)
	}
}
<|endoftext|>


<commit_before>package balancer

import (
	"log"
	"net"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

func HandleBalancerPackets(packetsIn chan gopacket.Packet, backendPackets chan *TCPPacket, stateTable *PacketBridgeStateTable) {
	for p := range packetsIn {
		// get layers
		layer := p.Layer(layers.LayerTypeEthernet)
		if layer == nil {
			log.Println("Could not get Ethernet layer")
			continue
		}
		ethLayer, ok := layer.(*layers.Ethernet)
		if !ok {
			log.Println("Could not cast layer to Ethernet")
			continue
		}

		layer = p.Layer(layers.LayerTypeIPv4)
		if layer == nil {
			log.Println("Could not get IPv4 layer")
			continue
		}
		ipLayer, ok := layer.(*layers.IPv4)
		if !ok {
			log.Println("Could not cast layer to IPv4")
			continue
		}

		layer = p.Layer(layers.LayerTypeTCP)
		if layer == nil {
			log.Println("Could not get TCP layer")
			continue
		}
		tcpLayer, ok := layer.(*layers.TCP)
		if !ok {
			log.Println("Could not cast layer to TCP")
			continue
		}

		if connState, ok := stateTable.GetByIP(ipLayer.SrcIP, tcpLayer.SrcPort); ok {
			// this is a known connection
			if connState.State == TCP_STATE_ESTABLISHED {
				// migrate the TCP state to packetbridge <> backend handshake
				tcpLayer.Ack = tcpLayer.Ack + connState.SeqOffset
				tcpLayer.SrcPort = connState.RandPort

				// the function responsible for sending the TCP packets will
				// set the correct source and destination IPs
				backendPackets <- NewTCPPacket(ipLayer, tcpLayer)
			} else {
				// TODO handle this case properly
				log.Println("Received packet, but connection is not established...")
			}
		} else {
			// we don't know about this connection yet, add it to the state
			// table and get the random port number for this connection
			// (so we can look it up later)
			connState := stateTable.NewState(ipLayer.SrcIP, ethLayer.SrcMAC, tcpLayer.SrcPort, ipLayer.TOS, tcpLayer.Ack, tcpLayer.Payload)

			// start the TCP handshake with the backend
			tcpSYN := &layers.TCP{
				SrcPort: connState.RandPort,
				DstPort: tcpLayer.DstPort,
				Seq:     tcpLayer.Seq - 1, // the handshake will increase it with +1
				Ack:     0,
				SYN:     true,
				Window:  64240,
			}

			log.Printf("New TCP connection: %s:%d, sending SYN to backend", ipLayer.SrcIP, tcpLayer.SrcPort)

			connState.State = TCP_STATE_SYN_SENT
			backendPackets <- NewTCPPacket(ipLayer, tcpSYN)
		}
	}
}

func SendToBackend(conn net.PacketConn, backendPackets chan *TCPPacket, srcIP, dstIP net.IP) {
	for p := range backendPackets {
		p.SetDstIP(dstIP)
		p.SetSrcIP(srcIP)

		bytes, err := p.MarshalBinary()
		if err != nil {
			log.Fatalf("Could not serialize packet: %s", err)
		}

		log.Printf("Sending packet to backend: %s", p)

		if _, err = conn.WriteTo(bytes, &net.IPAddr{IP: dstIP.To4()}); err != nil {
			log.Printf("Could not write TCP packet: %s", err)
		}
	}
}

func SendToClient(handle *pcap.Handle, ethPackets chan *EthPacket) {
	for p := range ethPackets {
		p.SetTOS(1)
		log.Printf("Sending eth packet: %s", p)
		bytes, err := p.MarshalBinary()
		if err != nil {
			log.Fatalf("Could not serialize packet: %s", err)
		}
		handle.WritePacketData(bytes)
	}
}

func HandleBackendPackets(conn net.PacketConn, dstIP, srcIP net.IP, srcPort layers.TCPPort, pbIface *net.Interface, backendTCPPackets chan *TCPPacket, ethPackets chan *EthPacket, stateTable *PacketBridgeStateTable, balancers map[uint8]net.IP) {
	b := make([]byte, 1500)
	for {
		n, srcAddr, err := conn.ReadFrom(b)
		if err != nil {
			log.Printf("Could not read from TCP connection: %s", err)
			continue
		}

		packet := gopacket.NewPacket(b[:n], layers.LayerTypeTCP, gopacket.Default)
		layer := packet.Layer(layers.LayerTypeTCP)
		if layer == nil {
			log.Println("Could not get TCP layer")
			continue
		}
		tcpLayer, ok := layer.(*layers.TCP)
		if !ok {
			log.Println("Could not cast to TCP layer")
			continue
		}

		if !(srcAddr.String() == srcIP.String() && tcpLayer.SrcPort == srcPort) {
			// this was not the packet that we were waiting for, ignore
			continue
		}

		connState, ok := stateTable.GetByPort(tcpLayer.DstPort)
		if !ok {
			// set RST
			// (we received a packet for a connection that is not known)
			tcpRST := &layers.TCP{
				SrcPort: tcpLayer.DstPort,
				DstPort: tcpLayer.SrcPort,
				Seq:     tcpLayer.Ack,
				Ack:     tcpLayer.Seq + 1,
				ACK:     true,
				RST:     true,
				Window:  64240,
			}
			ipLayer := &layers.IPv4{
				Protocol: layers.IPProtocolTCP,
			}
			log.Printf("Packet received for unknown connection from backend (port: %d). Sending RST to backend.", tcpLayer.DstPort)
			backendTCPPackets <- NewTCPPacket(ipLayer, tcpRST)
		} else if connState.State == TCP_STATE_SYN_SENT && tcpLayer.SYN && tcpLayer.ACK {
			// send ACK
			// (we sent the SYN and are now receiving the SYN ACK from the backend)
			connState.State = TCP_STATE_ESTABLISHED
			connState.SeqOffset = tcpLayer.Seq - connState.SeqOffset + 1

			tcpACK := &layers.TCP{
				SrcPort: tcpLayer.DstPort,
				DstPort: tcpLayer.SrcPort,
				Seq:     tcpLayer.Ack,
				Ack:     tcpLayer.Seq + 1,
				ACK:     true,
				Window:  64240,
			}
			ipLayer := &layers.IPv4{
				Protocol: layers.IPProtocolTCP,
			}

			log.Println("Received SYN ACK from backend, sending ACK.")
			backendTCPPackets <- NewTCPPacket(ipLayer, tcpACK)
		} else {
			// correct sequence number and set the RstPort to the original
			// client port. we're now sending the packet back to the user
			tcpLayer.Seq = tcpLayer.Seq - connState.SeqOffset
			tcpLayer.DstPort = connState.Port

			ethLayer := &layers.Ethernet{
				SrcMAC:       pbIface.HardwareAddr,
				DstMAC:       connState.HardwareAddr,
				EthernetType: layers.EthernetTypeIPv4,
			}

			ipLayer := &layers.IPv4{
				SrcIP:    balancers[connState.LBIndex].To4(),
				DstIP:    connState.IP.To4(),
				Protocol: layers.IPProtocolTCP,
				Version:  4,
				Id:       23423, // todo make this random?
				Flags:    layers.IPv4DontFragment,
				TTL:      64,
			}

			log.Println("Sending packet from the backend to the user")
			ethPackets <- NewEthPacket(ethLayer, ipLayer, tcpLayer)
		}
	}
}
<commit_msg>More comments.<commit_after>package balancer

import (
	"log"
	"net"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

// HandleBalancerPackets handles the incoming packets from the balancer
// app. When the connection is known, it will forward it to the backend.
// If not, it will first start a TCP handshake with the backend.
func HandleBalancerPackets(packetsIn chan gopacket.Packet, backendPackets chan *TCPPacket, stateTable *PacketBridgeStateTable) {
	for p := range packetsIn {
		// get layers
		layer := p.Layer(layers.LayerTypeEthernet)
		if layer == nil {
			log.Println("Could not get Ethernet layer")
			continue
		}
		ethLayer, ok := layer.(*layers.Ethernet)
		if !ok {
			log.Println("Could not cast layer to Ethernet")
			continue
		}

		layer = p.Layer(layers.LayerTypeIPv4)
		if layer == nil {
			log.Println("Could not get IPv4 layer")
			continue
		}
		ipLayer, ok := layer.(*layers.IPv4)
		if !ok {
			log.Println("Could not cast layer to IPv4")
			continue
		}

		layer = p.Layer(layers.LayerTypeTCP)
		if layer == nil {
			log.Println("Could not get TCP layer")
			continue
		}
		tcpLayer, ok := layer.(*layers.TCP)
		if !ok {
			log.Println("Could not cast layer to TCP")
			continue
		}

		if connState, ok := stateTable.GetByIP(ipLayer.SrcIP, tcpLayer.SrcPort); ok {
			// this is a known connection
			if connState.State == TCP_STATE_ESTABLISHED {
				// migrate the TCP state to packetbridge <> backend handshake
				tcpLayer.Ack = tcpLayer.Ack + connState.SeqOffset
				tcpLayer.SrcPort = connState.RandPort

				// the function responsible for sending the TCP packets will
				// set the correct source and destination IPs
				backendPackets <- NewTCPPacket(ipLayer, tcpLayer)
			} else {
				// TODO handle this case properly
				log.Println("Received packet, but connection is not established...")
			}
		} else {
			// we don't know about this connection yet, add it to the state
			// table and get the random port number for this connection
			// (so we can look it up later)
			connState := stateTable.NewState(ipLayer.SrcIP, ethLayer.SrcMAC, tcpLayer.SrcPort, ipLayer.TOS, tcpLayer.Ack, tcpLayer.Payload)

			// start the TCP handshake with the backend
			tcpSYN := &layers.TCP{
				SrcPort: connState.RandPort,
				DstPort: tcpLayer.DstPort,
				Seq:     tcpLayer.Seq - 1, // the handshake will increase it with +1
				Ack:     0,
				SYN:     true,
				Window:  64240,
			}

			log.Printf("New TCP connection: %s:%d, sending SYN to backend", ipLayer.SrcIP, tcpLayer.SrcPort)

			connState.State = TCP_STATE_SYN_SENT
			backendPackets <- NewTCPPacket(ipLayer, tcpSYN)
		}
	}
}

// SendToBackend sends packets from the packetbridge to the backend.
func SendToBackend(conn net.PacketConn, backendPackets chan *TCPPacket, srcIP, dstIP net.IP) {
	for p := range backendPackets {
		p.SetDstIP(dstIP)
		p.SetSrcIP(srcIP)

		bytes, err := p.MarshalBinary()
		if err != nil {
			log.Fatalf("Could not serialize packet: %s", err)
		}

		log.Printf("Sending packet to backend: %s", p)

		if _, err = conn.WriteTo(bytes, &net.IPAddr{IP: dstIP.To4()}); err != nil {
			log.Printf("Could not write TCP packet: %s", err)
		}
	}
}

// SendToClient sends packets to the client who started the request at
// the balancer.
func SendToClient(handle *pcap.Handle, ethPackets chan *EthPacket) {
	for p := range ethPackets {
		p.SetTOS(1)
		log.Printf("Sending eth packet: %s", p)
		bytes, err := p.MarshalBinary()
		if err != nil {
			log.Fatalf("Could not serialize packet: %s", err)
		}
		handle.WritePacketData(bytes)
	}
}

// HandleBackendPackets handles incoming packets from the backend. If the
// connection is known, it will forward these packets to the client.
func HandleBackendPackets(conn net.PacketConn, dstIP, srcIP net.IP, srcPort layers.TCPPort, pbIface *net.Interface, backendTCPPackets chan *TCPPacket, ethPackets chan *EthPacket, stateTable *PacketBridgeStateTable, balancers map[uint8]net.IP) {
	b := make([]byte, 1500)
	for {
		n, srcAddr, err := conn.ReadFrom(b)
		if err != nil {
			log.Printf("Could not read from TCP connection: %s", err)
			continue
		}

		packet := gopacket.NewPacket(b[:n], layers.LayerTypeTCP, gopacket.Default)
		layer := packet.Layer(layers.LayerTypeTCP)
		if layer == nil {
			log.Println("Could not get TCP layer")
			continue
		}
		tcpLayer, ok := layer.(*layers.TCP)
		if !ok {
			log.Println("Could not cast to TCP layer")
			continue
		}

		if !(srcAddr.String() == srcIP.String() && tcpLayer.SrcPort == srcPort) {
			// this was not the packet that we were waiting for, ignore
			continue
		}

		connState, ok := stateTable.GetByPort(tcpLayer.DstPort)
		if !ok {
			// set RST
			// (we received a packet for a connection that is not known)
			tcpRST := &layers.TCP{
				SrcPort: tcpLayer.DstPort,
				DstPort: tcpLayer.SrcPort,
				Seq:     tcpLayer.Ack,
				Ack:     tcpLayer.Seq + 1,
				ACK:     true,
				RST:     true,
				Window:  64240,
			}
			ipLayer := &layers.IPv4{
				Protocol: layers.IPProtocolTCP,
			}
			log.Printf("Packet received for unknown connection from backend (port: %d). Sending RST to backend.", tcpLayer.DstPort)
			backendTCPPackets <- NewTCPPacket(ipLayer, tcpRST)
		} else if connState.State == TCP_STATE_SYN_SENT && tcpLayer.SYN && tcpLayer.ACK {
			// send ACK
			// (we sent the SYN and are now receiving the SYN ACK from the backend)
			connState.State = TCP_STATE_ESTABLISHED
			connState.SeqOffset = tcpLayer.Seq - connState.SeqOffset + 1

			tcpACK := &layers.TCP{
				SrcPort: tcpLayer.DstPort,
				DstPort: tcpLayer.SrcPort,
				Seq:     tcpLayer.Ack,
				Ack:     tcpLayer.Seq + 1,
				ACK:     true,
				Window:  64240,
			}
			ipLayer := &layers.IPv4{
				Protocol: layers.IPProtocolTCP,
			}

			log.Println("Received SYN ACK from backend, sending ACK.")
			backendTCPPackets <- NewTCPPacket(ipLayer, tcpACK)
		} else {
			// correct sequence number and set the RstPort to the original
			// client port. we're now sending the packet back to the user
			tcpLayer.Seq = tcpLayer.Seq - connState.SeqOffset
			tcpLayer.DstPort = connState.Port

			ethLayer := &layers.Ethernet{
				SrcMAC:       pbIface.HardwareAddr,
				DstMAC:       connState.HardwareAddr,
				EthernetType: layers.EthernetTypeIPv4,
			}

			ipLayer := &layers.IPv4{
				SrcIP:    balancers[connState.LBIndex].To4(),
				DstIP:    connState.IP.To4(),
				Protocol: layers.IPProtocolTCP,
				Version:  4,
				Id:       23423, // todo make this random?
				Flags:    layers.IPv4DontFragment,
				TTL:      64,
			}

			log.Println("Sending packet from the backend to the user")
			ethPackets <- NewEthPacket(ethLayer, ipLayer, tcpLayer)
		}
	}
}
<|endoftext|>


<commit_before>package sphere

import (
	"errors"

	"github.com/streamrail/concurrent-map"
)

const (
	// BrokerErrorOverrideOnSubscribe to warn use to override OnSubsribe function
	BrokerErrorOverrideOnSubscribe = "please override OnSubscribe"
	// BrokerErrorOverrideOnUnsubscribe to warn use to override OnUnsubscribe function
	BrokerErrorOverrideOnUnsubscribe = "please override OnUnsubscribe"
	// BrokerErrorOverrideOnPublish to warn use to override OnPublish function
	BrokerErrorOverrideOnPublish = "please override OnPublish"
	// BrokerErrorOverrideOnMessage to warn use to override OnMessage function
	BrokerErrorOverrideOnMessage = "please override OnMessage"
)

// Agent represents Broker instance
type Agent interface {
	ID() string                            // => Broker ID
	ChannelName(string, string) string     // => Broker generate channel name with namespace and channel
	IsSubscribed(string) bool              // => Broker channel subscribe state
	OnSubscribe(*Channel) error            // => Broker OnSubscribe
	OnUnsubscribe(*Channel) error          // => Broker OnUnsubscribe
	OnPublish(*Channel, interface{}) error // => Broker OnPublish
	OnMessage(*Channel, interface{}) error // => Broker OnMessage
}

// ExtendBroker creates a broker instance
func ExtendBroker() *Broker {
	return &Broker{
		id:    guid.String(),
		store: cmap.New(),
	}
}

// Broker allows you to interact directly with Websocket internal data and pub/sub channels
type Broker struct {
	// Broker ID
	id string
	// Channel store
	store cmap.ConcurrentMap
}

// ID returns the unique id for the broker
func (broker *Broker) ID() string {
	return broker.id
}

// ChannelName returns channel name with provided namespace and room name
func (broker *Broker) ChannelName(namespace string, room string) string {
	return namespace + ":" + room
}

// IsSubscribed return the broker state of the channel
func (broker *Broker) IsSubscribed(name string) bool {
	return broker.store.Has(name)
}

// OnSubscribe when websocket subscribes to a channel
func (broker *Broker) OnSubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnSubscribe)
}

// OnUnsubscribe when websocket unsubscribes from a channel
func (broker *Broker) OnUnsubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnUnsubscribe)
}

// OnPublish when websocket publishes data to a particular channel from the current broker
func (broker *Broker) OnPublish(channel *Channel, data interface{}) error {
	return errors.New(BrokerErrorOverrideOnPublish)
}

// OnMessage when websocket receive data from the broker subscriber
func (broker *Broker) OnMessage(channel *Channel, data interface{}) error {
	return errors.New(BrokerErrorOverrideOnMessage)
}
<commit_msg>change data type from interface to Packet<commit_after>package sphere

import (
	"errors"

	"github.com/streamrail/concurrent-map"
)

const (
	// BrokerErrorOverrideOnSubscribe to warn use to override OnSubsribe function
	BrokerErrorOverrideOnSubscribe = "please override OnSubscribe"
	// BrokerErrorOverrideOnUnsubscribe to warn use to override OnUnsubscribe function
	BrokerErrorOverrideOnUnsubscribe = "please override OnUnsubscribe"
	// BrokerErrorOverrideOnPublish to warn use to override OnPublish function
	BrokerErrorOverrideOnPublish = "please override OnPublish"
	// BrokerErrorOverrideOnMessage to warn use to override OnMessage function
	BrokerErrorOverrideOnMessage = "please override OnMessage"
)

// Agent represents Broker instance
type Agent interface {
	ID() string                        // => Broker ID
	ChannelName(string, string) string // => Broker generate channel name with namespace and channel
	IsSubscribed(string) bool          // => Broker channel subscribe state
	OnSubscribe(*Channel) error        // => Broker OnSubscribe
	OnUnsubscribe(*Channel) error      // => Broker OnUnsubscribe
	OnPublish(*Channel, *Packet) error // => Broker OnPublish
	OnMessage(*Channel, *Packet) error // => Broker OnMessage
}

// ExtendBroker creates a broker instance
func ExtendBroker() *Broker {
	return &Broker{
		id:    guid.String(),
		store: cmap.New(),
	}
}

// Broker allows you to interact directly with Websocket internal data and pub/sub channels
type Broker struct {
	// Broker ID
	id string
	// Channel store
	store cmap.ConcurrentMap
}

// ID returns the unique id for the broker
func (broker *Broker) ID() string {
	return broker.id
}

// ChannelName returns channel name with provided namespace and room name
func (broker *Broker) ChannelName(namespace string, room string) string {
	return namespace + ":" + room
}

// IsSubscribed return the broker state of the channel
func (broker *Broker) IsSubscribed(name string) bool {
	return broker.store.Has(name)
}

// OnSubscribe when websocket subscribes to a channel
func (broker *Broker) OnSubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnSubscribe)
}

// OnUnsubscribe when websocket unsubscribes from a channel
func (broker *Broker) OnUnsubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnUnsubscribe)
}

// OnPublish when websocket publishes data to a particular channel from the current broker
func (broker *Broker) OnPublish(channel *Channel, data *Packet) error {
	return errors.New(BrokerErrorOverrideOnPublish)
}

// OnMessage when websocket receive data from the broker subscriber
func (broker *Broker) OnMessage(channel *Channel, data *Packet) error {
	return errors.New(BrokerErrorOverrideOnMessage)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
)

type State int8

const (
	STATE_DISABLED State  = iota - 1
	STATE_OFF
	STATE_PUMP
	STATE_SWEEP
	STATE_SOLAR
	STATE_SOLAR_MIXING
)

const SolarLED uint8 = 6

func (s State) String() string {
	switch s {
	case STATE_DISABLED:
		return "STATE_DISABLED"
	case STATE_OFF:
		return "STATE_OFF"
	case STATE_PUMP:
		return "STATE_PUMP"
	case STATE_SWEEP:
		return "STATE_SWEEP"
	case STATE_SOLAR:
		return "STATE_SOLAR"
	case STATE_SOLAR_MIXING:
		return "STATE_SOLAR_MIXING"
	default:
		return "STATE_UNKNOWN"
	}
}

type Switches struct {
	state       State
	pump        *Relay
	sweep       *Relay
	solar       *Relay
	solarLed    PiPin
	manualOp    time.Time
}

func (p *Switches) String() string {
	return fmt.Sprintf(
		"Pump: {State: %s,\nPump: {%s},\nSweep: {%s},\nSolar: {%s},\nManualOp: %s}",
		p.state.String(), p.pump.String(), p.sweep.String(), p.solar.String(),
		timeStr(p.manualOp))
}

func NewSwitches(manufacturer string) (*Switches) {
	return newSwitches(
		NewRelay(Relay1, "Pool Pump", manufacturer),
		NewRelay(Relay2, "Pool Sweep", manufacturer),
		NewRelay(Relay3, "Solar", manufacturer),
		NewGpio(SolarLED))
}

func newSwitches(pump *Relay, sweep *Relay, solar *Relay, solarLed PiPin) (*Switches) {
	p := Switches{
		state: STATE_OFF,
		pump:  pump,
		sweep: sweep,
		solar: solar,
		solarLed: solarLed,
		manualOp: time.Now().Add(time.Hour * -24),
	}
	solarLed.Output()
	p.bindHK()
	return &p
}

func (p *Switches) bindHK() {
	p.pump.accessory.Switch.On.OnValueRemoteUpdate(func(on bool) {
                if on == true {
			p.SetState(STATE_PUMP, true)
                } else {
                        p.StopAll(true)
                }
        })

	p.sweep.accessory.Switch.On.OnValueRemoteUpdate(func(on bool) {
		state := p.state
		switch p.state {
		case STATE_SOLAR:
			if on {
				state = STATE_SOLAR_MIXING
			}
			break
		case STATE_SOLAR_MIXING:
			if !on {
				state = STATE_SOLAR
			}
			break
		default:
			if on {
				state = STATE_SWEEP
			} else {
				state = STATE_PUMP
			}
		}
		p.SetState(state, true)
        })

	p.solar.accessory.Switch.On.OnValueRemoteUpdate(func(on bool) {
		state := p.state
		switch p.state {
		case STATE_SWEEP:
		case STATE_SOLAR_MIXING:
			if on {
				state = STATE_SOLAR_MIXING
			} else {
				state = STATE_SWEEP
			}
			break
		case STATE_SOLAR:
			if !on {
				state = STATE_PUMP
			}
			break
		default:
			if on {
				state = STATE_SOLAR
			} else {
				state = STATE_OFF
			}
		}
		p.SetState(state, true)
        })

}

func (p *Switches) GetStartTime() time.Time {
	return p.pump.GetStartTime()
}

func (p *Switches) GetStopTime() time.Time {
	return p.pump.GetStopTime()
}

func (p *Switches) Enable() {
	if p.state == STATE_DISABLED {
		p.state = STATE_OFF
		p.StopAll(true)
	}
}

func (p *Switches) Disable() {
	p.StopAll(true)
	p.state = STATE_DISABLED
}

func turnOn(relay *Relay, on bool) {
	if on {
		relay.TurnOn()
	} else {
		relay.TurnOff()
	}
}

func (p *Switches) setSwitches(pumpOn, sweepOn, solarOn, isManual bool, state State) {
	if solarOn { p.solarLed.High() } else { p.solarLed.Low() }
	turnOn(p.solar, solarOn)
	turnOn(p.pump, pumpOn)
	turnOn(p.sweep, sweepOn)
	if isManual {
		if p.GetStartTime().After(p.GetStopTime()) {
			p.manualOp = p.GetStartTime()
		} else {
			p.manualOp = p.GetStopTime()
		}
	}
	p.state = state
}

func (p *Switches) StopAll(manual bool) {
	state := STATE_OFF
	if p.state == STATE_DISABLED { state = STATE_DISABLED }
	p.setSwitches(false, false, false, manual, state)
}

func (p *Switches) SetState(s State, manual bool) {
	if p.state == s { return // Nothing to do here }
	if p.state == STATE_DISABLED {
		Info("Disabled, can't change state from %s to %s",
			p.state, s);
		return
	}
	if p.ManualState() && !manual {
		Debug("Manual override, can't change state from %s to %s",
			p.state, s);
		return // Don't override a manual operation
	}
	Info("State change from %s to %s", p.state, s)
	switch s {
	case STATE_DISABLED:
		p.Disable(); return
	case STATE_OFF:
		p.StopAll(manual); return
	case STATE_PUMP:
		p.setSwitches(true, false, false, manual, s); return
	case STATE_SWEEP:
		p.setSwitches(true, true, false, manual, s); return
	case STATE_SOLAR:
		p.setSwitches(true, false, true, manual, s); return
	case STATE_SOLAR_MIXING:
		p.setSwitches(true, true, true, manual, s); return
	}
}

func (p *Switches) State() State {
	return p.state
}

func (p *Switches) ManualState() bool {
	if time.Now().Sub(p.manualOp) > 2 * time.Hour {
		return false
	}
	if p.manualOp.Equal(p.GetStartTime()) && p.GetStartTime().After(p.GetStopTime()) {
		return true
	}
	if p.manualOp.Equal(p.GetStopTime()) && p.GetStopTime().After(p.GetStartTime()) {
		return true
	}
	return false
}
<commit_msg>cleanup<commit_after>package main

import (
	"fmt"
	"time"
)

type State int8

const (
	STATE_DISABLED State  = iota - 1
	STATE_OFF
	STATE_PUMP
	STATE_SWEEP
	STATE_SOLAR
	STATE_SOLAR_MIXING
)

const SolarLED uint8 = 6

func (s State) String() string {
	switch s {
	case STATE_DISABLED:
		return "STATE_DISABLED"
	case STATE_OFF:
		return "STATE_OFF"
	case STATE_PUMP:
		return "STATE_PUMP"
	case STATE_SWEEP:
		return "STATE_SWEEP"
	case STATE_SOLAR:
		return "STATE_SOLAR"
	case STATE_SOLAR_MIXING:
		return "STATE_SOLAR_MIXING"
	default:
		return "STATE_UNKNOWN"
	}
}

type Switches struct {
	state       State
	pump        *Relay
	sweep       *Relay
	solar       *Relay
	solarLed    PiPin
	manualOp    time.Time
}

func (p *Switches) String() string {
	return fmt.Sprintf(
		"Pump: {State: %s,\nPump: {%s},\nSweep: {%s},\nSolar: {%s},\nManualOp: %s}",
		p.state.String(), p.pump.String(), p.sweep.String(), p.solar.String(),
		timeStr(p.manualOp))
}

func NewSwitches(manufacturer string) (*Switches) {
	return newSwitches(
		NewRelay(Relay1, "Pool Pump", manufacturer),
		NewRelay(Relay2, "Pool Sweep", manufacturer),
		NewRelay(Relay3, "Solar", manufacturer),
		NewGpio(SolarLED))
}

func newSwitches(pump *Relay, sweep *Relay, solar *Relay, solarLed PiPin) (*Switches) {
	p := Switches{
		state: STATE_OFF,
		pump:  pump,
		sweep: sweep,
		solar: solar,
		solarLed: solarLed,
		manualOp: time.Now().Add(time.Hour * -24),
	}
	solarLed.Output()
	p.bindHK()
	return &p
}

func (p *Switches) bindHK() {
	p.pump.accessory.Switch.On.OnValueRemoteUpdate(func(on bool) {
                if on == true {
			p.SetState(STATE_PUMP, true)
                } else {
                        p.StopAll(true)
                }
        })

	p.sweep.accessory.Switch.On.OnValueRemoteUpdate(func(on bool) {
		state := p.state
		switch p.state {
		case STATE_SOLAR:
			if on {
				state = STATE_SOLAR_MIXING
			}
			break
		case STATE_SOLAR_MIXING:
			if !on {
				state = STATE_SOLAR
			}
			break
		default:
			if on {
				state = STATE_SWEEP
			} else {
				state = STATE_PUMP
			}
		}
		p.SetState(state, true)
        })

	p.solar.accessory.Switch.On.OnValueRemoteUpdate(func(on bool) {
		state := p.state
		switch p.state {
		case STATE_SWEEP:
		case STATE_SOLAR_MIXING:
			if on {
				state = STATE_SOLAR_MIXING
			} else {
				state = STATE_SWEEP
			}
			break
		case STATE_SOLAR:
			if !on {
				state = STATE_PUMP
			}
			break
		default:
			if on {
				state = STATE_SOLAR
			} else {
				state = STATE_OFF
			}
		}
		p.SetState(state, true)
        })

}

func (p *Switches) GetStartTime() time.Time {
	return p.pump.GetStartTime()
}

func (p *Switches) GetStopTime() time.Time {
	return p.pump.GetStopTime()
}

func (p *Switches) Enable() {
	if p.state == STATE_DISABLED {
		p.state = STATE_OFF
		p.StopAll(true)
	}
}

func (p *Switches) Disable() {
	p.StopAll(true)
	p.state = STATE_DISABLED
}

func turnOn(relay *Relay, on bool) {
	if on {
		relay.TurnOn()
	} else {
		relay.TurnOff()
	}
}

func (p *Switches) setSwitches(pumpOn, sweepOn, solarOn, isManual bool, state State) {
	if solarOn { p.solarLed.High() } else { p.solarLed.Low() }
	turnOn(p.solar, solarOn)
	turnOn(p.pump, pumpOn)
	turnOn(p.sweep, sweepOn)
	if isManual {
		if p.GetStartTime().After(p.GetStopTime()) {
			p.manualOp = p.GetStartTime()
		} else {
			p.manualOp = p.GetStopTime()
		}
	}
	p.state = state
}

func (p *Switches) StopAll(manual bool) {
	state := STATE_OFF
	if p.state == STATE_DISABLED { state = STATE_DISABLED }
	p.setSwitches(false, false, false, manual, state)
}

func (p *Switches) SetState(s State, manual bool) {
	if p.state == s {
		return // Nothing to do here
	}
	if p.state == STATE_DISABLED {
		Info("Disabled, can't change state from %s to %s",
			p.state, s);
		return
	}
	if p.ManualState() && !manual {
		Debug("Manual override, can't change state from %s to %s",
			p.state, s);
		return // Don't override a manual operation
	}
	Info("State change from %s to %s", p.state, s)
	switch s {
	case STATE_DISABLED:
		p.Disable(); return
	case STATE_OFF:
		p.StopAll(manual); return
	case STATE_PUMP:
		p.setSwitches(true, false, false, manual, s); return
	case STATE_SWEEP:
		p.setSwitches(true, true, false, manual, s); return
	case STATE_SOLAR:
		p.setSwitches(true, false, true, manual, s); return
	case STATE_SOLAR_MIXING:
		p.setSwitches(true, true, true, manual, s); return
	}
}

func (p *Switches) State() State {
	return p.state
}

func (p *Switches) ManualState() bool {
	if time.Now().Sub(p.manualOp) > 2 * time.Hour {
		return false
	}
	if p.manualOp.Equal(p.GetStartTime()) && p.GetStartTime().After(p.GetStopTime()) {
		return true
	}
	if p.manualOp.Equal(p.GetStopTime()) && p.GetStopTime().After(p.GetStartTime()) {
		return true
	}
	return false
}
<|endoftext|>