<commit_before>package tracing

import (
	"context"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
	"go.opentelemetry.io/otel/trace"
)

// Configured indicates whether tracing has been configured or not.
//
// This variable is needed in order to shortcircuit span generation when
// tracing hasn't been configured.
//
//
var Configured bool

type Config struct {
	//TODO: set default value in resective cmd package (web, worker)
	ServiceName string            `long:"service-name"  description:"service name to attach to traces as metadata" default:"concourse-web"`
	Attributes  map[string]string `long:"attribute"  description:"attributes to attach to traces as metadata"`
	Honeycomb   Honeycomb
	Jaeger      Jaeger
	Stackdriver Stackdriver
	OTLP        OTLP
}

func (c Config) Prepare() error {
	var provider trace.TracerProvider
	var err error

	switch {
	case c.Honeycomb.IsConfigured():
		provider, err = c.traceProvider(c.Honeycomb.Exporter)
	case c.Jaeger.IsConfigured():
		provider, err = c.traceProvider(c.Jaeger.Exporter)
	case c.OTLP.IsConfigured():
		provider, err = c.traceProvider(c.OTLP.Exporter)
	case c.Stackdriver.IsConfigured():
		provider, err = c.traceProvider(c.Stackdriver.Exporter)
	}
	if err != nil {
		return err
	}

	if provider != nil {
		ConfigureTraceProvider(provider)
	}

	return nil
}

func (c Config) traceProvider(exporter func() (sdktrace.SpanExporter, []sdktrace.TracerProviderOption, error)) (trace.TracerProvider, error) {
	exp, exporterOptions, err := exporter()
	if err != nil {
		return nil, err
	}

	options := append([]sdktrace.TracerProviderOption{
		sdktrace.WithSampler(sdktrace.AlwaysSample()),
		sdktrace.WithBatcher(exp,
			sdktrace.WithMaxQueueSize(1000),
			sdktrace.WithMaxExportBatchSize(1000),
		),
		sdktrace.WithResource(c.resource()),
	}, exporterOptions...)

	provider := sdktrace.NewTracerProvider(options...)
	if err != nil {
		return nil, err
	}

	return provider, nil
}

func (c Config) resource() *resource.Resource {
	attributes := []attribute.KeyValue{
		semconv.TelemetrySDKNameKey.String("opentelemetry"),
		semconv.TelemetrySDKLanguageKey.String("go"),
		semconv.ServiceNameKey.String(c.ServiceName),
	}

	for key, value := range c.Attributes {
		attributes = append(attributes, attribute.String(key, value))
	}

	return resource.NewSchemaless(attributes...)
}

// StartSpan creates a span, giving back a context that has itself added as the
// parent span.
//
// Calls to this function with a context that has been generated from a previous
// call to this method will make the resulting span a child of the span that
// preceded it.
//
// For instance:
//
// ```
// func fn () {
//
//     rootCtx, rootSpan := StartSpan(context.Background(), "foo", nil)
//     defer rootSpan.End()
//
//     _, childSpan := StartSpan(rootCtx, "bar", nil)
//     defer childSpan.End()
//
// }
// ```
//
// calling `fn()` will lead to the following trace:
//
// ```
// foo   0--------3
//   bar    1----2
// ```
//
// where (0) is the start of the root span, which then gets a child `bar`
// initializing at (1), having its end called (2), and then the last span
// finalization happening for the root span (3) given how `defer` statements
// stack.
//
func StartSpan(
	ctx context.Context,
	component string,
	attrs Attrs,
) (context.Context, trace.Span) {
	return startSpan(ctx, component, attrs)
}

func FromContext(ctx context.Context) trace.Span {
	return trace.SpanFromContext(ctx)
}

func Inject(ctx context.Context, carrier propagation.TextMapCarrier) {
	propagation.TraceContext{}.Inject(ctx, carrier)
}

func Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context {
	return propagation.TraceContext{}.Extract(ctx, carrier)
}

type WithSpanContext interface {
	SpanContext() propagation.TextMapCarrier
}

func StartSpanFollowing(
	ctx context.Context,
	following WithSpanContext,
	component string,
	attrs Attrs,
) (context.Context, trace.Span) {
	if supplier := following.SpanContext(); supplier != nil {
		ctx = propagation.TraceContext{}.Extract(ctx, supplier)
	}

	return startSpan(ctx, component, attrs)
}

func StartSpanLinkedToFollowing(
	linked context.Context,
	following WithSpanContext,
	component string,
	attrs Attrs,
) (context.Context, trace.Span) {
	ctx := context.Background()
	if supplier := following.SpanContext(); supplier != nil {
		ctx = propagation.TraceContext{}.Extract(ctx, supplier)
	}
	linkedSpanContext := trace.SpanFromContext(linked).SpanContext()

	return startSpan(
		ctx,
		component,
		attrs,
		trace.WithLinks(trace.Link{SpanContext: linkedSpanContext}),
	)
}

func startSpan(
	ctx context.Context,
	component string,
	attrs Attrs,
	opts ...trace.SpanStartOption,
) (context.Context, trace.Span) {
	if !Configured {
		return ctx, NoopSpan
	}

	ctx, span := otel.GetTracerProvider().Tracer("concourse").Start(
		ctx,
		component,
		opts...,
	)

	if len(attrs) != 0 {
		span.SetAttributes(keyValueSlice(attrs)...)
	}

	return ctx, span
}

func End(span trace.Span, err error) {
	if !Configured {
		return
	}

	if err != nil {
		span.SetStatus(codes.Error, "")
		span.SetAttributes(
			attribute.String("error-message", err.Error()),
		)
	}

	span.End()
}

// ConfigureTraceProvider configures the sdk to use a given trace provider.
//
// By default, a noop tracer is registered, thus, it's safe to call StartSpan
// and other related methods even before `ConfigureTracer` it called.
//
func ConfigureTraceProvider(tp trace.TracerProvider) {
	otel.SetTracerProvider(tp)
	Configured = true
}
<commit_msg>batch opentelemetry requests<commit_after>package tracing

import (
	"context"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
	"go.opentelemetry.io/otel/trace"
)

// Configured indicates whether tracing has been configured or not.
//
// This variable is needed in order to shortcircuit span generation when
// tracing hasn't been configured.
//
//
var Configured bool

type Config struct {
	//TODO: set default value in resective cmd package (web, worker)
	ServiceName string            `long:"service-name"  description:"service name to attach to traces as metadata" default:"concourse-web"`
	Attributes  map[string]string `long:"attribute"  description:"attributes to attach to traces as metadata"`
	Honeycomb   Honeycomb
	Jaeger      Jaeger
	Stackdriver Stackdriver
	OTLP        OTLP
}

func (c Config) Prepare() error {
	var provider trace.TracerProvider
	var err error

	switch {
	case c.Honeycomb.IsConfigured():
		provider, err = c.traceProvider(c.Honeycomb.Exporter)
	case c.Jaeger.IsConfigured():
		provider, err = c.traceProvider(c.Jaeger.Exporter)
	case c.OTLP.IsConfigured():
		provider, err = c.traceProvider(c.OTLP.Exporter)
	case c.Stackdriver.IsConfigured():
		provider, err = c.traceProvider(c.Stackdriver.Exporter)
	}
	if err != nil {
		return err
	}

	if provider != nil {
		ConfigureTraceProvider(provider)
	}

	return nil
}

func (c Config) traceProvider(exporter func() (sdktrace.SpanExporter, []sdktrace.TracerProviderOption, error)) (trace.TracerProvider, error) {
	exp, exporterOptions, err := exporter()
	if err != nil {
		return nil, err
	}

	options := append([]sdktrace.TracerProviderOption{
		sdktrace.WithSampler(sdktrace.AlwaysSample()),
		sdktrace.WithBatcher(exp),
		sdktrace.WithResource(c.resource()),
	}, exporterOptions...)

	provider := sdktrace.NewTracerProvider(options...)
	if err != nil {
		return nil, err
	}

	return provider, nil
}

func (c Config) resource() *resource.Resource {
	attributes := []attribute.KeyValue{
		semconv.TelemetrySDKNameKey.String("opentelemetry"),
		semconv.TelemetrySDKLanguageKey.String("go"),
		semconv.ServiceNameKey.String(c.ServiceName),
	}

	for key, value := range c.Attributes {
		attributes = append(attributes, attribute.String(key, value))
	}

	return resource.NewSchemaless(attributes...)
}

// StartSpan creates a span, giving back a context that has itself added as the
// parent span.
//
// Calls to this function with a context that has been generated from a previous
// call to this method will make the resulting span a child of the span that
// preceded it.
//
// For instance:
//
// ```
// func fn () {
//
//     rootCtx, rootSpan := StartSpan(context.Background(), "foo", nil)
//     defer rootSpan.End()
//
//     _, childSpan := StartSpan(rootCtx, "bar", nil)
//     defer childSpan.End()
//
// }
// ```
//
// calling `fn()` will lead to the following trace:
//
// ```
// foo   0--------3
//   bar    1----2
// ```
//
// where (0) is the start of the root span, which then gets a child `bar`
// initializing at (1), having its end called (2), and then the last span
// finalization happening for the root span (3) given how `defer` statements
// stack.
//
func StartSpan(
	ctx context.Context,
	component string,
	attrs Attrs,
) (context.Context, trace.Span) {
	return startSpan(ctx, component, attrs)
}

func FromContext(ctx context.Context) trace.Span {
	return trace.SpanFromContext(ctx)
}

func Inject(ctx context.Context, carrier propagation.TextMapCarrier) {
	propagation.TraceContext{}.Inject(ctx, carrier)
}

func Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context {
	return propagation.TraceContext{}.Extract(ctx, carrier)
}

type WithSpanContext interface {
	SpanContext() propagation.TextMapCarrier
}

func StartSpanFollowing(
	ctx context.Context,
	following WithSpanContext,
	component string,
	attrs Attrs,
) (context.Context, trace.Span) {
	if supplier := following.SpanContext(); supplier != nil {
		ctx = propagation.TraceContext{}.Extract(ctx, supplier)
	}

	return startSpan(ctx, component, attrs)
}

func StartSpanLinkedToFollowing(
	linked context.Context,
	following WithSpanContext,
	component string,
	attrs Attrs,
) (context.Context, trace.Span) {
	ctx := context.Background()
	if supplier := following.SpanContext(); supplier != nil {
		ctx = propagation.TraceContext{}.Extract(ctx, supplier)
	}
	linkedSpanContext := trace.SpanFromContext(linked).SpanContext()

	return startSpan(
		ctx,
		component,
		attrs,
		trace.WithLinks(trace.Link{SpanContext: linkedSpanContext}),
	)
}

func startSpan(
	ctx context.Context,
	component string,
	attrs Attrs,
	opts ...trace.SpanStartOption,
) (context.Context, trace.Span) {
	if !Configured {
		return ctx, NoopSpan
	}

	ctx, span := otel.GetTracerProvider().Tracer("concourse").Start(
		ctx,
		component,
		opts...,
	)

	if len(attrs) != 0 {
		span.SetAttributes(keyValueSlice(attrs)...)
	}

	return ctx, span
}

func End(span trace.Span, err error) {
	if !Configured {
		return
	}

	if err != nil {
		span.SetStatus(codes.Error, "")
		span.SetAttributes(
			attribute.String("error-message", err.Error()),
		)
	}

	span.End()
}

// ConfigureTraceProvider configures the sdk to use a given trace provider.
//
// By default, a noop tracer is registered, thus, it's safe to call StartSpan
// and other related methods even before `ConfigureTracer` it called.
//
func ConfigureTraceProvider(tp trace.TracerProvider) {
	otel.SetTracerProvider(tp)
	Configured = true
}
<|endoftext|>


<commit_before>package gopcap

import (
	"bytes"
	"testing"
)

func TestTCPGood(t *testing.T) {
	// Define some data.
	data := []byte{
		0x0B, 0x20, 0x1A, 0x0B, 0x4D, 0xC8, 0x4E, 0xED, 0x54, 0xF1, 0x10, 0x72, 0x80, 0x18, 0x1F, 0x4B, 0x6D, 0x2E, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0A, 0x00, 0xD8,
		0xEA, 0x48, 0x82, 0xE4, 0xDA, 0xB0, 0x49, 0x53, 0x4F, 0x4E, 0x20, 0x54, 0x68, 0x75, 0x6E, 0x66, 0x69, 0x73, 0x63, 0x68, 0x20, 0x53, 0x6D, 0x69, 0x6C, 0x65,
		0x79, 0x20, 0x53, 0x6D, 0x69, 0x6C, 0x65, 0x79, 0x47, 0x0A,
	}
	optBytes := []byte{0x01, 0x01, 0x08, 0x0a, 0x00, 0xd8, 0xea, 0x48, 0x82, 0xe4, 0xda, 0xb0}
	pkt := new(TCPSegment)
	err := pkt.FromBytes(data)

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if pkt.SourcePort != uint16(2848) {
		t.Errorf("Unexpected source port: expected %v, got %v", 2848, pkt.SourcePort)
	}
	if pkt.DestinationPort != uint16(6667) {
		t.Errorf("Unexpected destination port: expected %v, got %v", 6667, pkt.DestinationPort)
	}
	if pkt.SequenceNumber != uint32(1304973037) {
		t.Errorf("Unexpected sequence number: expected %v, got %v", 1304973037, pkt.SequenceNumber)
	}
	if pkt.AckNumber != uint32(1425084530) {
		t.Errorf("Unexpected ack number: expected %v, got %v", 1425084530, pkt.AckNumber)
	}
	if pkt.HeaderSize != uint8(8) {
		t.Errorf("Unexpected header size: expected %v, got %v", 8, pkt.HeaderSize)
	}
	if pkt.NS {
		t.Errorf("Expected NS flag not to be set and it was.")
	}
	if pkt.CWR {
		t.Errorf("Expected CWR flag not to be set and it was.")
	}
	if pkt.ECE {
		t.Errorf("Expected ECE flag not to be set and it was.")
	}
	if pkt.URG {
		t.Errorf("Expected URG flag not to be set and it was.")
	}
	if !pkt.ACK {
		t.Errorf("Expected ACK flag to be set and it wasn't.")
	}
	if !pkt.PSH {
		t.Errorf("Expected PSH flag to be set and it wasn't.")
	}
	if pkt.RST {
		t.Errorf("Expected RST flag not to be set and it was.")
	}
	if pkt.SYN {
		t.Errorf("Expected SYN flag not to be set and it was.")
	}
	if pkt.FIN {
		t.Errorf("Expected FIN flag not to be set and it was.")
	}
	if pkt.WindowSize != uint16(8011) {
		t.Errorf("Unexpected window size: expected %v, got %v", 8011, pkt.WindowSize)
	}
	if pkt.Checksum != 0x6d2e {
		t.Errorf("Unexpected checksum: expected %v, got %v", 0x6d2e, pkt.Checksum)
	}
	if pkt.UrgentOffset != uint16(0) {
		t.Errorf("Unexpected urgent offset: expected %v, got %v", 0, pkt.UrgentOffset)
	}
	if bytes.Compare(pkt.OptionData, optBytes) != 0 {
		t.Errorf("Unexpected option data: expected %v, got %v", optBytes, pkt.OptionData)
	}
	if len(pkt.TransportData()) != 30 {
		t.Errorf("Unexpected length of transport data: expected %v, got %v", 30, len(pkt.TransportData()))
	}
}
<commit_msg>Test the new UDP datagram.<commit_after>package gopcap

import (
	"bytes"
	"testing"
)

func TestTCPGood(t *testing.T) {
	// Define some data.
	data := []byte{
		0x0B, 0x20, 0x1A, 0x0B, 0x4D, 0xC8, 0x4E, 0xED, 0x54, 0xF1, 0x10, 0x72, 0x80, 0x18, 0x1F, 0x4B, 0x6D, 0x2E, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0A, 0x00, 0xD8,
		0xEA, 0x48, 0x82, 0xE4, 0xDA, 0xB0, 0x49, 0x53, 0x4F, 0x4E, 0x20, 0x54, 0x68, 0x75, 0x6E, 0x66, 0x69, 0x73, 0x63, 0x68, 0x20, 0x53, 0x6D, 0x69, 0x6C, 0x65,
		0x79, 0x20, 0x53, 0x6D, 0x69, 0x6C, 0x65, 0x79, 0x47, 0x0A,
	}
	optBytes := []byte{0x01, 0x01, 0x08, 0x0a, 0x00, 0xd8, 0xea, 0x48, 0x82, 0xe4, 0xda, 0xb0}
	pkt := new(TCPSegment)
	err := pkt.FromBytes(data)

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if pkt.SourcePort != uint16(2848) {
		t.Errorf("Unexpected source port: expected %v, got %v", 2848, pkt.SourcePort)
	}
	if pkt.DestinationPort != uint16(6667) {
		t.Errorf("Unexpected destination port: expected %v, got %v", 6667, pkt.DestinationPort)
	}
	if pkt.SequenceNumber != uint32(1304973037) {
		t.Errorf("Unexpected sequence number: expected %v, got %v", 1304973037, pkt.SequenceNumber)
	}
	if pkt.AckNumber != uint32(1425084530) {
		t.Errorf("Unexpected ack number: expected %v, got %v", 1425084530, pkt.AckNumber)
	}
	if pkt.HeaderSize != uint8(8) {
		t.Errorf("Unexpected header size: expected %v, got %v", 8, pkt.HeaderSize)
	}
	if pkt.NS {
		t.Errorf("Expected NS flag not to be set and it was.")
	}
	if pkt.CWR {
		t.Errorf("Expected CWR flag not to be set and it was.")
	}
	if pkt.ECE {
		t.Errorf("Expected ECE flag not to be set and it was.")
	}
	if pkt.URG {
		t.Errorf("Expected URG flag not to be set and it was.")
	}
	if !pkt.ACK {
		t.Errorf("Expected ACK flag to be set and it wasn't.")
	}
	if !pkt.PSH {
		t.Errorf("Expected PSH flag to be set and it wasn't.")
	}
	if pkt.RST {
		t.Errorf("Expected RST flag not to be set and it was.")
	}
	if pkt.SYN {
		t.Errorf("Expected SYN flag not to be set and it was.")
	}
	if pkt.FIN {
		t.Errorf("Expected FIN flag not to be set and it was.")
	}
	if pkt.WindowSize != uint16(8011) {
		t.Errorf("Unexpected window size: expected %v, got %v", 8011, pkt.WindowSize)
	}
	if pkt.Checksum != 0x6d2e {
		t.Errorf("Unexpected checksum: expected %v, got %v", 0x6d2e, pkt.Checksum)
	}
	if pkt.UrgentOffset != uint16(0) {
		t.Errorf("Unexpected urgent offset: expected %v, got %v", 0, pkt.UrgentOffset)
	}
	if bytes.Compare(pkt.OptionData, optBytes) != 0 {
		t.Errorf("Unexpected option data: expected %v, got %v", optBytes, pkt.OptionData)
	}
	if len(pkt.TransportData()) != 30 {
		t.Errorf("Unexpected length of transport data: expected %v, got %v", 30, len(pkt.TransportData()))
	}
}

func TestUDPGood(t *testing.T) {
	// Define the data for a UDP datagram.
	data := []byte{
		0x08, 0x50, 0x00, 0x35, 0x00, 0x32, 0x83, 0x97, 0x31, 0x1f, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x01, 0x31,
		0x03, 0x31, 0x36, 0x38, 0x03, 0x31, 0x39, 0x32, 0x07, 0x69, 0x6e, 0x2d, 0x61, 0x64, 0x64, 0x72, 0x04, 0x61, 0x72, 0x70, 0x61, 0x00, 0x00, 0x0c,
		0x00, 0x01,
	}

	dgram := new(UDPDatagram)
	err := dgram.FromBytes(data)

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	if dgram.SourcePort != uint16(2128) {
		t.Errorf("Unexpected source port: expected %v, got %v.", 2128, dgram.SourcePort)
	}
	if dgram.DestinationPort != uint16(53) {
		t.Errorf("Unexpected destination port: expected %v, got %v.", 53, dgram.DestinationPort)
	}
	if dgram.Length != uint16(50) {
		t.Errorf("Unexpected length: expected %v, got %v.", 50, dgram.Length)
	}
	if dgram.Checksum != uint16(33687) {
		t.Errorf("Unexpected checksum: expected %v, got %v.", 33687, dgram.Checksum)
	}
	if len(dgram.TransportData()) != 42 {
		t.Errorf("Unexpected length of contained data: expected %v, got %v", 42, len(dgram.TransportData()))
	}
}
<|endoftext|>


<commit_before>package persist

import (
    "log"
    "os"
    "path"
    "io/ioutil"
    "regexp"
    "strings"

    "github.com/jmartin82/mmock/definition"
)

//FileBodyPersister persists body in file
type FileBodyPersister struct {
    PersistPath string
}

//Persist the body of the response to fiel if needed
func (fbp FileBodyPersister) Persist(per *definition.Persist, req *definition.Request, res *definition.Response) {
	if per.Name == ""{
        return
    }

    per.Name = fbp.replaceVars(req, per.Name)

    fileContent := []byte(res.Body)

    filePath := path.Join(fbp.PersistPath, per.Name);
    fileDir := path.Dir(filePath)

    err := os.MkdirAll(fileDir, 0644)
    if err != nil {
		panic(err)
	}

    err = ioutil.WriteFile(filePath, fileContent, 0644)

    if err != nil {
		panic(err)
	}
}

//NewFileBodyPersister creates a new FileBodyPersister
func NewFileBodyPersister(persistPath string) *FileBodyPersister {
	result := FileBodyPersister{PersistPath: persistPath}

    err := os.MkdirAll(result.PersistPath, 0644)
    if err != nil {
		panic(err)
	}

	return &result
}

func (fbp FileBodyPersister) replaceVars(req *definition.Request, input string) string {
	r := regexp.MustCompile(`\{\{\s*([^\}]+)\s*\}\}`)

	return r.ReplaceAllStringFunc(input, func(raw string) string {
		found := false
		s := ""
		tag := strings.Trim(raw[2:len(raw)-2], " ")
		if tag == "request.body" {
			s = req.Body
			found = true
		} else if i := strings.Index(tag, "request.url."); i == 0 {
			s, found = req.GetURLPart(tag[12:], "Value")
		} else if i := strings.Index(tag, "request.query."); i == 0 {
			s, found = req.GetQueryStringParam(tag[14:])
		} else if i := strings.Index(tag, "request.cookie."); i == 0 {
			s, found = req.GetCookieParam(tag[15:])
        }

		if !found {
			log.Printf("Defined tag {{%s}} not found\n", tag)
			return raw
		}
		return s
	})
}<commit_msg>added error handing when saving file<commit_after>package persist

import (
    "log"
    "os"
    "path"
    "io/ioutil"
    "regexp"
    "strings"

    "github.com/jmartin82/mmock/definition"
)

//FileBodyPersister persists body in file
type FileBodyPersister struct {
    PersistPath string
}

//Persist the body of the response to fiel if needed
func (fbp FileBodyPersister) Persist(per *definition.Persist, req *definition.Request, res *definition.Response) {
	if per.Name == ""{
        return
    }

    per.Name = fbp.replaceVars(req, per.Name)

    fileContent := []byte(res.Body)

    filePath := path.Join(fbp.PersistPath, per.Name);
    fileDir := path.Dir(filePath)

    err := os.MkdirAll(fileDir, 0644)
    if fbp.checkForFileWriteError(err, res) == nil{
        err = ioutil.WriteFile(filePath, fileContent, 0644)
        fbp.checkForFileWriteError(err, res)
    }
}

func (fbp FileBodyPersister) checkForFileWriteError(err error, res *definition.Response) error {
    if err != nil {
		log.Print(err)
        res.Body = err.Error()
        res.StatusCode = 500
	}
    return err
}

//NewFileBodyPersister creates a new FileBodyPersister
func NewFileBodyPersister(persistPath string) *FileBodyPersister {
	result := FileBodyPersister{PersistPath: persistPath}

    err := os.MkdirAll(result.PersistPath, 0644)
    if err != nil {
		panic(err)
	}

	return &result
}

func (fbp FileBodyPersister) replaceVars(req *definition.Request, input string) string {
	r := regexp.MustCompile(`\{\{\s*([^\}]+)\s*\}\}`)

	return r.ReplaceAllStringFunc(input, func(raw string) string {
		found := false
		s := ""
		tag := strings.Trim(raw[2:len(raw)-2], " ")
		if tag == "request.body" {
			s = req.Body
			found = true
		} else if i := strings.Index(tag, "request.url."); i == 0 {
			s, found = req.GetURLPart(tag[12:], "Value")
		} else if i := strings.Index(tag, "request.query."); i == 0 {
			s, found = req.GetQueryStringParam(tag[14:])
		} else if i := strings.Index(tag, "request.cookie."); i == 0 {
			s, found = req.GetCookieParam(tag[15:])
        }

		if !found {
			log.Printf("Defined tag {{%s}} not found\n", tag)
			return raw
		}
		return s
	})
}<|endoftext|>


<commit_before>package set1

import (
	"encoding/base64"
	"fmt"
)

// decToHex is used to lookup a single hex value in decimal.
var decToHex = map[byte]byte{
	0:  '0',
	1:  '1',
	2:  '2',
	3:  '3',
	4:  '4',
	5:  '5',
	6:  '6',
	7:  '7',
	8:  '8',
	9:  '9',
	10: 'a',
	11: 'b',
	12: 'c',
	13: 'd',
	14: 'e',
	15: 'f',
}

// Encodes a decimal byte slice to a hexidecimal byte slice
func HexEncode(text []byte) []byte {
	// output is always twice the size of input
	out := make([]byte, len(text)*2)

	// based on this article:
	// https://learn.sparkfun.com/tutorials/hexadecimal#converting-tofrom-decimal
	for i, char := range text {
		secondDigit := decToHex[char%16]
		firstDigit := decToHex[char/16]
		out[i*2] = firstDigit
		out[i*2+1] = secondDigit
	}

	return out
}

// hexToDec is used to lookup a single decimal value in hex.
func hexToDec(char byte) (byte, error) {
	var val byte
	// subtract ASCII decimal codes so that:
	//   "0" becomes 0
	//   "a" and "A" become 10
	switch {
	case char >= '0' && char <= '9':
		val = char - '0'
	case char >= 'A' && char <= 'F':
		val = char - 'A' + 10
	case char >= 'a' && char <= 'f':
		val = char - 'a' + 10
	default:
		return 0, fmt.Errorf("invalid hex character: %s", []byte{char})
	}

	return val, nil
}

// HexDecode decodes a hexidecimal byte slice to a decimal byte slice
func HexDecode(text []byte) ([]byte, error) {
	if len(text)%2 != 0 {
		return []byte{}, fmt.Errorf("input must be an even size")
	}

	// output is always half the size of input
	out := make([]byte, len(text)/2)

	// based on this article:
	// https://learn.sparkfun.com/tutorials/hexadecimal#converting-tofrom-decimal
	for i := 0; i < len(out); i++ {
		firstDigit, err := hexToDec(text[i*2])
		if err != nil {
			return []byte{}, err
		}

		secondDigit, err := hexToDec(text[i*2+1])
		if err != nil {
			return []byte{}, err
		}

		out[i] = firstDigit*16 + secondDigit
	}

	return out, nil
}

// HexToBase64 converts hexidecimal encoded text to base64.
func HexToBase64(text []byte) ([]byte, error) {
	raw, err := HexDecode(text)
	if err != nil {
		return []byte{}, err
	}

	b64 := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
	base64.StdEncoding.Encode(b64, raw)

	return b64, nil
}
<commit_msg>s1c1: Simpler lookup for HexEncode<commit_after>package set1

import (
	"encoding/base64"
	"fmt"
)

// decToHex is used to lookup a single hex value in decimal.
var decToHex = [16]byte{
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
	'a', 'b', 'c', 'd', 'e', 'f',
}

// Encodes a decimal byte slice to a hexidecimal byte slice
func HexEncode(text []byte) []byte {
	// output is always twice the size of input
	out := make([]byte, len(text)*2)

	// based on this article:
	// https://learn.sparkfun.com/tutorials/hexadecimal#converting-tofrom-decimal
	for i, char := range text {
		secondDigit := decToHex[char%16]
		firstDigit := decToHex[char/16]
		out[i*2] = firstDigit
		out[i*2+1] = secondDigit
	}

	return out
}

// hexToDec is used to lookup a single decimal value in hex.
func hexToDec(char byte) (byte, error) {
	var val byte
	// subtract ASCII decimal codes so that:
	//   "0" becomes 0
	//   "a" and "A" become 10
	switch {
	case char >= '0' && char <= '9':
		val = char - '0'
	case char >= 'A' && char <= 'F':
		val = char - 'A' + 10
	case char >= 'a' && char <= 'f':
		val = char - 'a' + 10
	default:
		return 0, fmt.Errorf("invalid hex character: %s", []byte{char})
	}

	return val, nil
}

// HexDecode decodes a hexidecimal byte slice to a decimal byte slice
func HexDecode(text []byte) ([]byte, error) {
	if len(text)%2 != 0 {
		return []byte{}, fmt.Errorf("input must be an even size")
	}

	// output is always half the size of input
	out := make([]byte, len(text)/2)

	// based on this article:
	// https://learn.sparkfun.com/tutorials/hexadecimal#converting-tofrom-decimal
	for i := 0; i < len(out); i++ {
		firstDigit, err := hexToDec(text[i*2])
		if err != nil {
			return []byte{}, err
		}

		secondDigit, err := hexToDec(text[i*2+1])
		if err != nil {
			return []byte{}, err
		}

		out[i] = firstDigit*16 + secondDigit
	}

	return out, nil
}

// HexToBase64 converts hexidecimal encoded text to base64.
func HexToBase64(text []byte) ([]byte, error) {
	raw, err := HexDecode(text)
	if err != nil {
		return []byte{}, err
	}

	b64 := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
	base64.StdEncoding.Encode(b64, raw)

	return b64, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"launchpad.net/mgo"
	"log"
	"os"
	"runtime/pprof"
	. "github.com/timeredbull/tsuru/api/service"
	. "github.com/timeredbull/tsuru/database"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write memory profile to file")

func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	session, err := mgo.Dial("localhost:27017")
	if err != nil {
		panic(err)
	}
	Db = session.DB("tsuru")
	defer session.Close()

	sType := &ServiceType{Name: "Mysql", Charm: "mysql"}
	sType.Create()
	var s Service
	var name string
	for i := 0; i < 1000; i++ {
		name = fmt.Sprintf("myService%d", i)
		s = Service{ServiceTypeId: sType.Id, Name: name}
		s.Create()
	}
	s = Service{}
	s.All()

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
	}

	// c := Db.C("services")
	// defer c.DropCollection()
}
<commit_msg>api/service/profile: update code to new db package<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime/pprof"
	. "github.com/timeredbull/tsuru/api/service"
	"github.com/timeredbull/tsuru/db"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var memprofile = flag.String("memprofile", "", "write memory profile to file")

func main() {
	flag.Parse()
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	var err error
	db.Session, err = db.Open("127.0.0.1:27017", "tsuru")
	if err != nil {
		panic(err)
	}
	defer db.Session.Close()

	sType := &ServiceType{Name: "Mysql", Charm: "mysql"}
	sType.Create()
	var s Service
	var name string
	for i := 0; i < 1000; i++ {
		name = fmt.Sprintf("myService%d", i)
		s = Service{ServiceTypeId: sType.Id, Name: name}
		s.Create()
	}
	s = Service{}
	s.All()

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
	}
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/af83/edwig/model"
)

func timeCheckResponseStatus(responseRecorder *httptest.ResponseRecorder, t *testing.T) {
	if status := responseRecorder.Code; status != http.StatusOK {
		t.Errorf("Handler returned wrong status code:\n got %v\n want %v",
			status, http.StatusOK)
	}

	if contentType := responseRecorder.Header().Get("Content-Type"); contentType != "application/json" {
		t.Errorf("Handler returned wrong Content-Type:\n got: %v\n want: %v",
			contentType, "application/json")
	}
}

func timePrepareRequest(method string, advance bool, body []byte, t *testing.T) (responseRecorder *httptest.ResponseRecorder, server *Server) {
	server = &Server{}
	server.SetClock(model.NewFakeClock())

	// Create a request
	var address string
	if advance {
		address = "/_time/advance"
	} else {
		address = "/_time"
	}

	request, err := http.NewRequest(method, address, bytes.NewReader(body))
	if err != nil {
		t.Fatal(err)
	}

	// Create a ResponseRecorder
	responseRecorder = httptest.NewRecorder()

	// Call APIHandler method and pass in our Request and ResponseRecorder.
	server.APIHandler(responseRecorder, request)

	return
}

func Test_TimeController_Get(t *testing.T) {
	// Send request
	responseRecorder, _ := timePrepareRequest("GET", false, nil, t)

	// Test response
	timeCheckResponseStatus(responseRecorder, t)

	//Test Results
	if expected := `{ "time": 1984-04-04T00:00:00.000Z }`; responseRecorder.Body.String() != expected {
		t.Errorf("Wrong body for GET response request:\n got: %v\n want: %v", responseRecorder.Body.String(), expected)
	}
}

func Test_TimeController_Advance(t *testing.T) {
	// Send request
	body := []byte(`{ "duration": "1s" }`)
	responseRecorder, server := timePrepareRequest("POST", true, body, t)

	// Test response
	timeCheckResponseStatus(responseRecorder, t)

	//Test Results
	if expected := `{ "time": 1984-04-04T00:00:01.000Z }`; responseRecorder.Body.String() != expected {
		t.Errorf("Wrong body for GET response request:\n got: %v\n want: %v", responseRecorder.Body.String(), expected)
	}
	if expected := time.Date(1984, time.April, 4, 0, 0, 1, 0, time.UTC); !server.Clock().Now().Equal(expected) {
		t.Errorf("Server Clock should have advanced:\n got: %v\n want: %v", server.Clock().Now(), expected)
	}
}
<commit_msg>Fixes TimeController tests<commit_after>package api

import (
	"bytes"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/af83/edwig/model"
)

func timeCheckResponseStatus(responseRecorder *httptest.ResponseRecorder, t *testing.T) {
	if status := responseRecorder.Code; status != http.StatusOK {
		t.Errorf("Handler returned wrong status code:\n got %v\n want %v",
			status, http.StatusOK)
	}

	if contentType := responseRecorder.Header().Get("Content-Type"); contentType != "application/json" {
		t.Errorf("Handler returned wrong Content-Type:\n got: %v\n want: %v",
			contentType, "application/json")
	}
}

func timePrepareRequest(method string, advance bool, body []byte, t *testing.T) (responseRecorder *httptest.ResponseRecorder, server *Server) {
	server = &Server{}
	server.SetClock(model.NewFakeClock())

	// Create a request
	var address string
	if advance {
		address = "/_time/advance"
	} else {
		address = "/_time"
	}

	request, err := http.NewRequest(method, address, bytes.NewReader(body))
	if err != nil {
		t.Fatal(err)
	}

	// Create a ResponseRecorder
	responseRecorder = httptest.NewRecorder()

	// Call APIHandler method and pass in our Request and ResponseRecorder.
	server.APIHandler(responseRecorder, request)

	return
}

func Test_TimeController_Get(t *testing.T) {
	// Send request
	responseRecorder, _ := timePrepareRequest("GET", false, nil, t)

	// Test response
	timeCheckResponseStatus(responseRecorder, t)

	//Test Results
	if expected := `{ "time": "1984-04-04T00:00:00.000Z" }`; responseRecorder.Body.String() != expected {
		t.Errorf("Wrong body for GET response request:\n got: %v\n want: %v", responseRecorder.Body.String(), expected)
	}
}

func Test_TimeController_Advance(t *testing.T) {
	// Send request
	body := []byte(`{ "duration": "1s" }`)
	responseRecorder, server := timePrepareRequest("POST", true, body, t)

	// Test response
	timeCheckResponseStatus(responseRecorder, t)

	//Test Results
	if expected := `{ "time": "1984-04-04T00:00:01.000Z" }`; responseRecorder.Body.String() != expected {
		t.Errorf("Wrong body for GET response request:\n got: %v\n want: %v", responseRecorder.Body.String(), expected)
	}
	if expected := time.Date(1984, time.April, 4, 0, 0, 1, 0, time.UTC); !server.Clock().Now().Equal(expected) {
		t.Errorf("Server Clock should have advanced:\n got: %v\n want: %v", server.Clock().Now(), expected)
	}
}
<|endoftext|>


<commit_before>package irelate

import (
	"log"

	"github.com/brentp/vcfgo"
	"github.com/brentp/xopen"
)

type Variant struct {
	vcfgo.Variant
	source  uint32
	related []Relatable
}

func NewVariant(v vcfgo.Variant, source uint32, related []Relatable) *Variant {
	return &Variant{v, source, related}
}

func (v *Variant) AddRelated(r Relatable) {
	if len(v.related) == 0 {
		v.related = make([]Relatable, 0, 12)
	}
	v.related = append(v.related, r)
}

func (v *Variant) Related() []Relatable {
	return v.related
}

func (v *Variant) SetSource(src uint32) { v.source = src }
func (v *Variant) Source() uint32       { return v.source }

func Vopen(f string) *vcfgo.Reader {
	rdr, err := xopen.Ropen(f)
	check(err)
	vcf, err := vcfgo.NewReader(rdr, true)
	if err != nil {
		log.Fatal(err)
	}
	return vcf
}

func StreamVCF(vcf *vcfgo.Reader) RelatableChannel {
	ch := make(RelatableChannel, 128)
	go func() {
		for {
			v := vcf.Read()
			if v == nil {
				break
			}
			ch <- &Variant{*v, 0, nil}
			vcf.Clear()
		}
		close(ch)
	}()
	return ch
}
<commit_msg>increase channel buffer<commit_after>package irelate

import (
	"log"

	"github.com/brentp/vcfgo"
	"github.com/brentp/xopen"
)

type Variant struct {
	vcfgo.Variant
	source  uint32
	related []Relatable
}

func NewVariant(v vcfgo.Variant, source uint32, related []Relatable) *Variant {
	return &Variant{v, source, related}
}

func (v *Variant) AddRelated(r Relatable) {
	if len(v.related) == 0 {
		v.related = make([]Relatable, 0, 12)
	}
	v.related = append(v.related, r)
}

func (v *Variant) Related() []Relatable {
	return v.related
}

func (v *Variant) SetSource(src uint32) { v.source = src }
func (v *Variant) Source() uint32       { return v.source }

func Vopen(f string) *vcfgo.Reader {
	rdr, err := xopen.Ropen(f)
	check(err)
	vcf, err := vcfgo.NewReader(rdr, true)
	if err != nil {
		log.Fatal(err)
	}
	return vcf
}

func StreamVCF(vcf *vcfgo.Reader) RelatableChannel {
	ch := make(RelatableChannel, 256)
	go func() {
		for {
			v := vcf.Read()
			if v == nil {
				break
			}
			ch <- &Variant{*v, 0, nil}
			vcf.Clear()
		}
		close(ch)
	}()
	return ch
}
<|endoftext|>


<commit_before>package encoding

import (
	"github.com/getlantern/bytemap"
	. "github.com/getlantern/zenodb/expr"
	"github.com/stretchr/testify/assert"
	"math/rand"
	"testing"
	"time"
)

var (
	res            = time.Minute
	epoch          = time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)
	truncateBefore = epoch.Add(-1000 * res)
)

func TestSequenceUpdate(t *testing.T) {
	e := SUM(MULT(FIELD("a"), FIELD("b")))

	checkWithTruncation := func(retainPeriods int) {
		t.Logf("Retention periods: %d", retainPeriods)
		retentionPeriod := res * time.Duration(retainPeriods)
		trunc := func(vals []float64, ignoreTrailingIndex int) []float64 {
			if len(vals) > retainPeriods {
				vals = vals[:retainPeriods]
				if len(vals)-1 == ignoreTrailingIndex {
					// Remove trailing zero to deal with append deep
					vals = vals[:retainPeriods-1]
				}
			}
			return vals
		}

		start := epoch
		var seq Sequence

		doIt := func(ts time.Time, params map[string]float64, expected []float64) {
			if ts.After(start) {
				start = ts
			}
			tb := start.Add(-1 * retentionPeriod)
			seq = seq.Update(NewTSParams(ts, bytemap.NewFloat(params)), nil, e, res, tb)
			checkUpdatedValues(t, e, seq, trunc(expected, 4))
		}

		// Set something on an empty Sequence
		doIt(epoch, map[string]float64{"a": 1, "b": 2}, []float64{2})

		// Prepend
		doIt(epoch.Add(2*res).Add(randBelow(res)), map[string]float64{"a": 1, "b": 1}, []float64{1, 0, 2})

		// Append
		doIt(epoch.Add(-1*res).Add(randBelow(res)), map[string]float64{"a": 1, "b": 3}, []float64{1, 0, 2, 3})

		// Append deep
		doIt(epoch.Add(-3*res).Add(randBelow(res)), map[string]float64{"a": 1, "b": 4}, []float64{1, 0, 2, 3, 0, 4})

		// Update value
		doIt(epoch.Add(randBelow(res)), map[string]float64{"a": 1, "b": 5}, []float64{1, 0, 7, 3, 0, 4})
	}

	for i := 6; i >= 0; i-- {
		checkWithTruncation(i)
	}
}

func checkUpdatedValues(t *testing.T, e Expr, seq Sequence, expected []float64) {
	if assert.Equal(t, len(expected), seq.NumPeriods(e.EncodedWidth())) {
		for i, v := range expected {
			actual, wasSet := seq.ValueAt(i, e)
			assert.EqualValues(t, v, actual)
			if v == 0 {
				assert.False(t, wasSet)
			}
		}
	}
}

func TestSequenceFull(t *testing.T) {
	resolutionOut := 10 * time.Second
	resolutionIn := 1 * time.Second

	eOut := ADD(SUM(FIELD("a")), SUM(FIELD("b")))
	eIn := SUM(FIELD("a"))
	eB := SUM(FIELD("b"))
	submergers := eOut.SubMergers([]Expr{eIn, eB})

	widthOut := eOut.EncodedWidth()
	widthIn := eIn.EncodedWidth()
	seqIn := NewSequence(widthIn, 100)

	params := FloatParams(1)
	for i := 0; i < 100; i++ {
		seqIn.UpdateValueAt(i, eIn, params, nil)
	}

	asOf := epoch.Add(-100 * resolutionIn)
	until := epoch

	for _, seqOut := range []Sequence{NewSequence(widthOut, 5), nil} {
		if seqOut != nil {
			seqOut.SetUntil(epoch.Add(-2 * resolutionOut))
			assert.Equal(t, epoch.Add(-2*resolutionOut).In(time.UTC), seqOut.Until().In(time.UTC))
			assert.Equal(t, epoch.Add(-7*resolutionOut).In(time.UTC), seqOut.AsOf(widthOut, resolutionOut).In(time.UTC))
		}

		seqIn.SetUntil(epoch)
		assert.Equal(t, epoch, seqIn.Until().In(time.UTC))
		assert.Equal(t, epoch.Add(-100*resolutionIn).In(time.UTC), seqIn.AsOf(widthIn, resolutionIn).In(time.UTC))

		merged := seqOut.SubMerge(seqIn, nil, resolutionOut, resolutionIn, eOut, eIn, submergers[0], asOf, until)
		assert.Equal(t, RoundTime(seqIn.Until().In(time.UTC), resolutionOut), merged.Until().In(time.UTC))
		assert.Equal(t, RoundTime(seqIn.AsOf(widthIn, resolutionIn).In(time.UTC), resolutionOut), merged.AsOf(widthOut, resolutionOut).In(time.UTC))

		assert.Equal(t, 10, merged.NumPeriods(widthOut))
		for i := 0; i < 10; i++ {
			val, found := merged.ValueAt(i, eOut)
			assert.True(t, found)
			assert.EqualValues(t, 10, val)
		}

		truncated := merged.Truncate(widthOut, resolutionOut, merged.AsOf(widthOut, resolutionOut).Add(resolutionOut), merged.Until().Add(-1*resolutionOut))
		assert.Equal(t, 8, truncated.NumPeriods(widthOut))
		for i := 0; i < 8; i++ {
			val, found := truncated.ValueAt(i, eOut)
			assert.True(t, found)
			assert.EqualValues(t, 10, val)
		}

		start := merged.Until()
		end := merged.AsOf(widthOut, resolutionOut)
		assert.Nil(t, merged.Truncate(widthOut, resolutionOut, start.Add(resolutionOut), start.Add(resolutionOut*2)))
		assert.Nil(t, merged.Truncate(widthOut, resolutionOut, time.Time{}, end.Add(-1*resolutionOut)))
	}
}

func TestSequenceValue(t *testing.T) {
	e := SUM(FIELD("a"))
	v := NewFloatValue(e, epoch, 56.78)
	assert.Equal(t, epoch, v.Until().In(time.UTC))
	assert.Equal(t, 1, v.NumPeriods(e.EncodedWidth()))
	val, found := v.ValueAt(0, e)
	assert.True(t, found)
	assert.Equal(t, 56.78, val)
}

func TestSequenceConstant(t *testing.T) {
	e := CONST(5.1)
	s := Sequence(nil)
	v, _ := s.ValueAt(0, e)
	assert.EqualValues(t, 5.1, v)
	v, _ = s.ValueAtOffset(0, e)
	assert.EqualValues(t, 5.1, v)
	v, _ = s.ValueAtTime(time.Time{}, e, 0)
	assert.EqualValues(t, 5.1, v)
}

func randBelow(res time.Duration) time.Duration {
	return time.Duration(-1 * rand.Intn(int(res)))
}
<commit_msg>Updated seq_test to use odd scaling factor<commit_after>package encoding

import (
	"github.com/getlantern/bytemap"
	. "github.com/getlantern/zenodb/expr"
	"github.com/stretchr/testify/assert"
	"math/rand"
	"testing"
	"time"
)

var (
	res            = time.Minute
	epoch          = time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)
	truncateBefore = epoch.Add(-1000 * res)
)

func TestSequenceUpdate(t *testing.T) {
	e := SUM(MULT(FIELD("a"), FIELD("b")))

	checkWithTruncation := func(retainPeriods int) {
		t.Logf("Retention periods: %d", retainPeriods)
		retentionPeriod := res * time.Duration(retainPeriods)
		trunc := func(vals []float64, ignoreTrailingIndex int) []float64 {
			if len(vals) > retainPeriods {
				vals = vals[:retainPeriods]
				if len(vals)-1 == ignoreTrailingIndex {
					// Remove trailing zero to deal with append deep
					vals = vals[:retainPeriods-1]
				}
			}
			return vals
		}

		start := epoch
		var seq Sequence

		doIt := func(ts time.Time, params map[string]float64, expected []float64) {
			if ts.After(start) {
				start = ts
			}
			tb := start.Add(-1 * retentionPeriod)
			seq = seq.Update(NewTSParams(ts, bytemap.NewFloat(params)), nil, e, res, tb)
			checkUpdatedValues(t, e, seq, trunc(expected, 4))
		}

		// Set something on an empty Sequence
		doIt(epoch, map[string]float64{"a": 1, "b": 2}, []float64{2})

		// Prepend
		doIt(epoch.Add(2*res).Add(randBelow(res)), map[string]float64{"a": 1, "b": 1}, []float64{1, 0, 2})

		// Append
		doIt(epoch.Add(-1*res).Add(randBelow(res)), map[string]float64{"a": 1, "b": 3}, []float64{1, 0, 2, 3})

		// Append deep
		doIt(epoch.Add(-3*res).Add(randBelow(res)), map[string]float64{"a": 1, "b": 4}, []float64{1, 0, 2, 3, 0, 4})

		// Update value
		doIt(epoch.Add(randBelow(res)), map[string]float64{"a": 1, "b": 5}, []float64{1, 0, 7, 3, 0, 4})
	}

	for i := 6; i >= 0; i-- {
		checkWithTruncation(i)
	}
}

func checkUpdatedValues(t *testing.T, e Expr, seq Sequence, expected []float64) {
	if assert.Equal(t, len(expected), seq.NumPeriods(e.EncodedWidth())) {
		for i, v := range expected {
			actual, wasSet := seq.ValueAt(i, e)
			assert.EqualValues(t, v, actual)
			if v == 0 {
				assert.False(t, wasSet)
			}
		}
	}
}

func TestSequenceFull(t *testing.T) {
	resolutionOut := 3 * time.Second
	resolutionIn := 1 * time.Second

	eOut := ADD(SUM(FIELD("a")), SUM(FIELD("b")))
	eIn := SUM(FIELD("a"))
	eB := SUM(FIELD("b"))
	submergers := eOut.SubMergers([]Expr{eIn, eB})

	inPeriods := int(10 * resolutionOut / time.Second)
	widthOut := eOut.EncodedWidth()
	widthIn := eIn.EncodedWidth()
	seqIn := NewSequence(widthIn, inPeriods)

	params := FloatParams(1)
	for i := 0; i < inPeriods; i++ {
		seqIn.UpdateValueAt(i, eIn, params, nil)
	}

	asOf := epoch.Add(-1 * time.Duration(inPeriods) * resolutionIn)
	until := epoch

	for _, seqOut := range []Sequence{NewSequence(widthOut, 5), nil} {
		if seqOut != nil {
			seqOut.SetUntil(epoch.Add(-2 * resolutionOut))
			assert.Equal(t, epoch.Add(-2*resolutionOut).In(time.UTC), seqOut.Until().In(time.UTC))
			assert.Equal(t, epoch.Add(-7*resolutionOut).In(time.UTC), seqOut.AsOf(widthOut, resolutionOut).In(time.UTC))
		}

		seqIn.SetUntil(epoch)
		assert.Equal(t, epoch, seqIn.Until().In(time.UTC))
		assert.Equal(t, epoch.Add(-1*time.Duration(inPeriods)*resolutionIn).In(time.UTC), seqIn.AsOf(widthIn, resolutionIn).In(time.UTC))

		merged := seqOut.SubMerge(seqIn, nil, resolutionOut, resolutionIn, eOut, eIn, submergers[0], asOf, until)
		assert.Equal(t, RoundTime(seqIn.Until().In(time.UTC), resolutionOut), merged.Until().In(time.UTC))
		assert.Equal(t, RoundTime(seqIn.AsOf(widthIn, resolutionIn).In(time.UTC), resolutionOut), merged.AsOf(widthOut, resolutionOut).In(time.UTC))

		assert.Equal(t, 10, merged.NumPeriods(widthOut))
		for i := 0; i < 10; i++ {
			val, found := merged.ValueAt(i, eOut)
			assert.True(t, found)
			assert.EqualValues(t, 3, val)
		}

		truncated := merged.Truncate(widthOut, resolutionOut, merged.AsOf(widthOut, resolutionOut).Add(resolutionOut), merged.Until().Add(-1*resolutionOut))
		assert.Equal(t, 8, truncated.NumPeriods(widthOut))
		for i := 0; i < 8; i++ {
			val, found := truncated.ValueAt(i, eOut)
			assert.True(t, found)
			assert.EqualValues(t, 3, val)
		}

		start := merged.Until()
		end := merged.AsOf(widthOut, resolutionOut)
		assert.Nil(t, merged.Truncate(widthOut, resolutionOut, start.Add(resolutionOut), start.Add(resolutionOut*2)))
		assert.Nil(t, merged.Truncate(widthOut, resolutionOut, time.Time{}, end.Add(-1*resolutionOut)))
	}
}

func TestSequenceValue(t *testing.T) {
	e := SUM(FIELD("a"))
	v := NewFloatValue(e, epoch, 56.78)
	assert.Equal(t, epoch, v.Until().In(time.UTC))
	assert.Equal(t, 1, v.NumPeriods(e.EncodedWidth()))
	val, found := v.ValueAt(0, e)
	assert.True(t, found)
	assert.Equal(t, 56.78, val)
}

func TestSequenceConstant(t *testing.T) {
	e := CONST(5.1)
	s := Sequence(nil)
	v, _ := s.ValueAt(0, e)
	assert.EqualValues(t, 5.1, v)
	v, _ = s.ValueAtOffset(0, e)
	assert.EqualValues(t, 5.1, v)
	v, _ = s.ValueAtTime(time.Time{}, e, 0)
	assert.EqualValues(t, 5.1, v)
}

func randBelow(res time.Duration) time.Duration {
	return time.Duration(-1 * rand.Intn(int(res)))
}
<|endoftext|>


<commit_before>package tensor3

type Vector struct {
	x, y, z BaseType
}

func (v Vector) Components() (BaseType, BaseType, BaseType) {
	return v.x, v.y, v.z
}

var xAxis, yAxis, zAxis = Vector{scale, 0, 0}, Vector{0, scale, 0}, Vector{0, 0, scale}
var yzPlane, xzPlane, zxPlane = Vector{0, scale, scale}, Vector{scale, 0, scale}, Vector{scale, scale, 0}

type Axis uint

const (
	XAxisIndex Axis = iota
	YAxisIndex
	ZAxisIndex
)

var Axes = [3]Vector{xAxis, yAxis, zAxis}
var AxisPlanes = [3]Vector{yzPlane, xzPlane, zxPlane}

// missing components default to zero, more than 3 are ignored
func NewVector(cs ...BaseType) (v Vector) {
	switch len(cs) {
	default:
		v.z = baseScale(cs[2])
		fallthrough
	case 2:
		v.y = baseScale(cs[1])
		fallthrough
	case 1:
		v.x = baseScale(cs[0])
	case 0:
		return
	}
	return
}

func (v *Vector) Add(v2 Vector) {
	v.x += v2.x
	v.y += v2.y
	v.z += v2.z
}

func (v *Vector) Subtract(v2 Vector) {
	v.x -= v2.x
	v.y -= v2.y
	v.z -= v2.z
}

// components independently multiplied, see Product for matrix multiplication
func (v *Vector) Multiply(s BaseType) {
	v.x *= s
	v.y *= s
	v.z *= s
}

// components independently divided
func (v *Vector) Divide(s BaseType) {
	v.x /= s
	v.y /= s
	v.z /= s
}

func (v Vector) Dot(v2 Vector) BaseType {
	return baseUnscale(v.x*v2.x + v.y*v2.y + v.z*v2.z)
}

func (v *Vector) Cross(v2 Vector) {
	v.x, v.y, v.z = v.y*v2.z-v.z*v2.y, v.z*v2.x-v.x*v2.z, v.x*v2.y-v.y*v2.x
	vectorUnscale(v)
}

// length squared. (returning squared means this package is not dependent on math package.)
func (v Vector) LengthLength() BaseType {
	return v.Dot(v)
}

func (v *Vector) Set(v2 Vector) {
	v.x = v2.x
	v.y = v2.y
	v.z = v2.z
}

func (v *Vector) Max(v2 Vector) {
	if v2.x > v.x {
		v.x = v2.x
	}
	if v2.y > v.y {
		v.y = v2.y
	}
	if v2.z > v.z {
		v.z = v2.z
	}
}

func (v *Vector) Min(v2 Vector) {
	if v2.x < v.x {
		v.x = v2.x
	}
	if v2.y < v.y {
		v.y = v2.y
	}
	if v2.z < v.z {
		v.z = v2.z
	}
}

func (v *Vector) Mid(v2 Vector) {
	v.x = (v2.x + v.x) / 2
	v.y = (v2.y + v.y) / 2
	v.z = (v2.z + v.z) / 2
}

func (v *Vector) Interpolate(v2 Vector, f BaseType) {
	v2.Multiply(1 - f)
	v.Multiply(f)
	v.Add(v2)
}

// apply a function repeatedly to the vector, parameterised by its current value and each vector in the supplied vectors in order.
func (v *Vector) Aggregate(vs Vectors, fn func(*Vector, Vector)) {
	for _, v2 := range vs {
		fn(v, v2)
	}
}

// apply a function repeatedly to the vector, parameterised by the current value of the vector and each vector in the supplied vectors.
func (v *Vector) ForAll(vs Vectors, fn func(*Vector, Vector)) {
	if !Parallel {
		vectorApplyAll(v, fn, vs)
	} else {
		if Hints.ChunkSizeFixed {
			vectorApplyAllChunked(v, fn, vs, Hints.DefaultChunkSize)
		} else {
			cs := uint(len(vs)) / (Hints.Threads + 1)
			if cs < Hints.DefaultChunkSize {
				cs = Hints.DefaultChunkSize
			}
			vectorApplyAllChunked(v, fn, vs, cs)
		}
	}
}

func vectorApplyAll(v *Vector, fn func(*Vector, Vector), vs Vectors) {
	for i := range vs {
		fn(v, vs[i])
	}
}

func vectorApplyAllChunked(v *Vector, fn func(*Vector, Vector), vs Vectors, chunkSize uint) {
	done := make(chan Vector, 1)
	var running uint
	for chunk := range vectorsInChunks(vs) {
		running++
		go func(cvs Vectors) {
			var nv Vector
			vectorApplyAll(&nv, fn, cvs)
			done <- nv
		}(chunk)
	}
	for ; running > 0; running-- {
		fn(v, <-done)
	}
}

// component wise multiplication. Use an axis-plane and this will project the vector to that axis.
func (v *Vector) Project(axis Vector) {
	v.x *= axis.x
	v.y *= axis.y
	v.z *= axis.z
	vectorUnscale(v)
}

// axis which vector is most aligned with.
func (v Vector) LongestAxis() Axis {
	v.Project(v)
	if v.z > v.y {
		if v.z > v.x {
			return ZAxisIndex
		}
		return XAxisIndex
	}
	if v.x > v.y {
		return XAxisIndex
	}
	return YAxisIndex
}

// axis which vector is least aligned with.
func (v Vector) ShortestAxis() Axis {
	v.Project(v)
	if v.z < v.y {
		if v.x < v.z {
			return XAxisIndex
		}
		return ZAxisIndex
	}
	if v.x > v.y {
		return YAxisIndex
	}
	return XAxisIndex
}

// vector - matrix multiplication
func (v *Vector) Product(m Matrix) {
	v.x, v.y, v.z = v.x*m.x.x+v.y*m.y.x+v.z*m.z.x, v.x*m.x.y+v.y*m.y.y+v.z*m.z.y, v.x*m.x.z+v.y*m.y.z+v.z*m.z.z
	vectorUnscale(v)
}

// vector - transposed matrix multiplication
func (v *Vector) ProductT(m Matrix) {
	v.x, v.y, v.z = v.x*m.x.x+v.y*m.x.y+v.z*m.x.z, v.x*m.y.x+v.y*m.y.y+v.z*m.y.z, v.x*m.z.x+v.y*m.z.y+v.z*m.z.z
	vectorUnscale(v)
}
<commit_msg>correct var names<commit_after>package tensor3

type Vector struct {
	x, y, z BaseType
}

func (v Vector) Components() (BaseType, BaseType, BaseType) {
	return v.x, v.y, v.z
}

var xAxis, yAxis, zAxis = Vector{scale, 0, 0}, Vector{0, scale, 0}, Vector{0, 0, scale}
var yzPlane, zxPlane, xyPlane = Vector{0, scale, scale}, Vector{scale, 0, scale}, Vector{scale, scale, 0}

type Axis uint

const (
	XAxisIndex Axis = iota
	YAxisIndex
	ZAxisIndex
)

var Axes = [3]Vector{xAxis, yAxis, zAxis}
var AxisPlanes = [3]Vector{yzPlane, zxPlane, xyPlane}

// missing components default to zero, more than 3 are ignored
func NewVector(cs ...BaseType) (v Vector) {
	switch len(cs) {
	default:
		v.z = baseScale(cs[2])
		fallthrough
	case 2:
		v.y = baseScale(cs[1])
		fallthrough
	case 1:
		v.x = baseScale(cs[0])
	case 0:
		return
	}
	return
}

func (v *Vector) Add(v2 Vector) {
	v.x += v2.x
	v.y += v2.y
	v.z += v2.z
}

func (v *Vector) Subtract(v2 Vector) {
	v.x -= v2.x
	v.y -= v2.y
	v.z -= v2.z
}

// components independently multiplied, see Product for matrix multiplication
func (v *Vector) Multiply(s BaseType) {
	v.x *= s
	v.y *= s
	v.z *= s
}

// components independently divided
func (v *Vector) Divide(s BaseType) {
	v.x /= s
	v.y /= s
	v.z /= s
}

func (v Vector) Dot(v2 Vector) BaseType {
	return baseUnscale(v.x*v2.x + v.y*v2.y + v.z*v2.z)
}

func (v *Vector) Cross(v2 Vector) {
	v.x, v.y, v.z = v.y*v2.z-v.z*v2.y, v.z*v2.x-v.x*v2.z, v.x*v2.y-v.y*v2.x
	vectorUnscale(v)
}

// length squared. (returning squared means this package is not dependent on math package.)
func (v Vector) LengthLength() BaseType {
	return v.Dot(v)
}

func (v *Vector) Set(v2 Vector) {
	v.x = v2.x
	v.y = v2.y
	v.z = v2.z
}

func (v *Vector) Max(v2 Vector) {
	if v2.x > v.x {
		v.x = v2.x
	}
	if v2.y > v.y {
		v.y = v2.y
	}
	if v2.z > v.z {
		v.z = v2.z
	}
}

func (v *Vector) Min(v2 Vector) {
	if v2.x < v.x {
		v.x = v2.x
	}
	if v2.y < v.y {
		v.y = v2.y
	}
	if v2.z < v.z {
		v.z = v2.z
	}
}

func (v *Vector) Mid(v2 Vector) {
	v.x = (v2.x + v.x) / 2
	v.y = (v2.y + v.y) / 2
	v.z = (v2.z + v.z) / 2
}

func (v *Vector) Interpolate(v2 Vector, f BaseType) {
	v2.Multiply(1 - f)
	v.Multiply(f)
	v.Add(v2)
}

// apply a function repeatedly to the vector, parameterised by its current value and each vector in the supplied vectors in order.
func (v *Vector) Aggregate(vs Vectors, fn func(*Vector, Vector)) {
	for _, v2 := range vs {
		fn(v, v2)
	}
}

// apply a function repeatedly to the vector, parameterised by the current value of the vector and each vector in the supplied vectors.
func (v *Vector) ForAll(vs Vectors, fn func(*Vector, Vector)) {
	if !Parallel {
		vectorApplyAll(v, fn, vs)
	} else {
		if Hints.ChunkSizeFixed {
			vectorApplyAllChunked(v, fn, vs, Hints.DefaultChunkSize)
		} else {
			cs := uint(len(vs)) / (Hints.Threads + 1)
			if cs < Hints.DefaultChunkSize {
				cs = Hints.DefaultChunkSize
			}
			vectorApplyAllChunked(v, fn, vs, cs)
		}
	}
}

func vectorApplyAll(v *Vector, fn func(*Vector, Vector), vs Vectors) {
	for i := range vs {
		fn(v, vs[i])
	}
}

func vectorApplyAllChunked(v *Vector, fn func(*Vector, Vector), vs Vectors, chunkSize uint) {
	done := make(chan Vector, 1)
	var running uint
	for chunk := range vectorsInChunks(vs) {
		running++
		go func(cvs Vectors) {
			var nv Vector
			vectorApplyAll(&nv, fn, cvs)
			done <- nv
		}(chunk)
	}
	for ; running > 0; running-- {
		fn(v, <-done)
	}
}

// component wise multiplication. Use an axis-plane and this will project the vector to that axis.
func (v *Vector) Project(axis Vector) {
	v.x *= axis.x
	v.y *= axis.y
	v.z *= axis.z
	vectorUnscale(v)
}

// axis which vector is most aligned with.
func (v Vector) LongestAxis() Axis {
	v.Project(v)
	if v.z > v.y {
		if v.z > v.x {
			return ZAxisIndex
		}
		return XAxisIndex
	}
	if v.x > v.y {
		return XAxisIndex
	}
	return YAxisIndex
}

// axis which vector is least aligned with.
func (v Vector) ShortestAxis() Axis {
	v.Project(v)
	if v.z < v.y {
		if v.x < v.z {
			return XAxisIndex
		}
		return ZAxisIndex
	}
	if v.x > v.y {
		return YAxisIndex
	}
	return XAxisIndex
}

// vector - matrix multiplication
func (v *Vector) Product(m Matrix) {
	v.x, v.y, v.z = v.x*m.x.x+v.y*m.y.x+v.z*m.z.x, v.x*m.x.y+v.y*m.y.y+v.z*m.z.y, v.x*m.x.z+v.y*m.y.z+v.z*m.z.z
	vectorUnscale(v)
}

// vector - transposed matrix multiplication
func (v *Vector) ProductT(m Matrix) {
	v.x, v.y, v.z = v.x*m.x.x+v.y*m.x.y+v.z*m.x.z, v.x*m.y.x+v.y*m.y.y+v.z*m.y.z, v.x*m.z.x+v.y*m.z.y+v.z*m.z.z
	vectorUnscale(v)
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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 codegen

import (
	"llvm/bindings/go/llvm"
)

// Cast casts the value v to the type ty.
func (v *Value) Cast(ty Type) *Value {
	srcTy, dstTy := v.Type(), ty
	if srcTy == dstTy {
		return v // No-op
	}
	if IsVector(srcTy) != IsVector(dstTy) {
		fail("Cannot cast between vector and non-vector types. (%v -> %v)", srcTy, dstTy)
	}
	if IsPointer(srcTy) && IsPointer(dstTy) {
		name := srcTy.TypeName() + "->" + dstTy.TypeName()
		return v.b.val(ty, v.b.llvm.CreatePointerCast(v.llvm, ty.llvmTy(), name))
	}
	assertVectorsSameLength(srcTy, dstTy)
	srcElTy, dstElTy := Scalar(srcTy), Scalar(dstTy)
	grow := srcElTy.SizeInBits() < dstElTy.SizeInBits()
	shink := srcElTy.SizeInBits() > dstElTy.SizeInBits()
	switch {
	case IsInteger(srcElTy) && IsPointer(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateIntToPtr(v.llvm, ty.llvmTy(), ""))
	case IsPointer(srcElTy) && IsInteger(dstElTy):
		return v.b.val(ty, v.b.llvm.CreatePtrToInt(v.llvm, ty.llvmTy(), ""))
	case IsSignedInteger(srcElTy) && IsFloat(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateSIToFP(v.llvm, ty.llvmTy(), ""))
	case IsUnsignedInteger(srcElTy) && IsFloat(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateUIToFP(v.llvm, ty.llvmTy(), ""))
	case IsFloat(srcElTy) && IsSignedInteger(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateFPToSI(v.llvm, ty.llvmTy(), ""))
	case IsFloat(srcElTy) && IsUnsignedInteger(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateFPToUI(v.llvm, ty.llvmTy(), ""))
	case IsBool(srcElTy) && IsInteger(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateZExt(v.llvm, ty.llvmTy(), ""))
	case IsInteger(srcElTy) && IsBool(dstElTy):
		return v.b.NotEqual(v, v.b.Zero(srcElTy))
	case IsIntegerOrEnum(srcElTy) && IsUnsignedInteger(srcElTy) && grow:
		return v.b.val(ty, v.b.llvm.CreateZExt(v.llvm, ty.llvmTy(), ""))
	case IsIntegerOrEnum(srcElTy) && IsSignedIntegerOrEnum(srcElTy) && grow:
		return v.b.val(ty, v.b.llvm.CreateSExt(v.llvm, ty.llvmTy(), ""))
	case IsIntegerOrEnum(srcElTy) && IsIntegerOrEnum(dstElTy) && shink:
		return v.b.val(ty, v.b.llvm.CreateTrunc(v.llvm, ty.llvmTy(), ""))
	case IsIntegerOrEnum(srcElTy) && IsIntegerOrEnum(dstElTy):
		return v.b.val(ty, v.llvm) // signed conversion
	case IsFloat(srcElTy) && IsFloat(dstElTy) && shink:
		return v.b.val(ty, v.b.llvm.CreateFPTrunc(v.llvm, ty.llvmTy(), ""))
	case IsFloat(srcElTy) && IsFloat(dstElTy) && grow:
		return v.b.val(ty, v.b.llvm.CreateFPExt(v.llvm, ty.llvmTy(), ""))
	default:
		fail("Cannot cast from %v -> %v", srcTy.TypeName(), dstTy.TypeName())
		return nil
	}
}

// Bitcast performs a bitwise cast of the value v to the type ty.
func (v *Value) Bitcast(ty Type) *Value {
	srcTy, dstTy := v.Type(), ty
	if srcTy == dstTy {
		return v // No-op
	}
	if srcSize, dstSize := srcTy.SizeInBits(), dstTy.SizeInBits(); srcSize != dstSize {
		fail("Bitcast cannot change sizes. (%v -> %v)", srcTy, dstTy)
	}
	return v.b.val(ty, v.b.llvm.CreateBitCast(v.llvm, ty.llvmTy(), "bitcast"))
}

// Cast casts the constant v to the type ty.
func (v Const) Cast(ty Type) Const {
	srcTy, dstTy := v.Type, ty
	if srcTy == dstTy {
		return v // No-op
	}
	if IsVector(srcTy) != IsVector(dstTy) {
		fail("Cannot cast between vector and non-vector types. (%v -> %v)", srcTy, dstTy)
	}
	if IsPointer(srcTy) && IsPointer(dstTy) {
		return Const{ty, llvm.ConstPointerCast(v.llvm, ty.llvmTy())}
	}
	assertVectorsSameLength(srcTy, dstTy)
	srcElTy, dstElTy := Scalar(srcTy), Scalar(dstTy)
	grow := srcElTy.SizeInBits() < dstElTy.SizeInBits()
	shink := srcElTy.SizeInBits() > dstElTy.SizeInBits()
	switch {
	case IsInteger(srcElTy) && IsPointer(dstElTy):
		return Const{ty, llvm.ConstIntToPtr(v.llvm, ty.llvmTy())}
	case IsSignedInteger(srcElTy) && IsFloat(dstElTy):
		return Const{ty, llvm.ConstSIToFP(v.llvm, ty.llvmTy())}
	case IsUnsignedInteger(srcElTy) && IsFloat(dstElTy):
		return Const{ty, llvm.ConstUIToFP(v.llvm, ty.llvmTy())}
	case IsFloat(srcElTy) && IsSignedInteger(dstElTy):
		return Const{ty, llvm.ConstFPToSI(v.llvm, ty.llvmTy())}
	case IsFloat(srcElTy) && IsUnsignedInteger(dstElTy):
		return Const{ty, llvm.ConstFPToUI(v.llvm, ty.llvmTy())}
	case IsBool(srcElTy) && IsInteger(dstElTy):
		return Const{ty, llvm.ConstZExt(v.llvm, ty.llvmTy())}
	case IsInteger(srcElTy) && IsUnsignedInteger(dstElTy) && grow:
		return Const{ty, llvm.ConstZExt(v.llvm, ty.llvmTy())}
	case IsInteger(srcElTy) && IsSignedInteger(dstElTy) && grow:
		return Const{ty, llvm.ConstSExt(v.llvm, ty.llvmTy())}
	case IsInteger(srcElTy) && IsInteger(dstElTy) && shink:
		return Const{ty, llvm.ConstTrunc(v.llvm, ty.llvmTy())}
	case IsInteger(srcElTy) && IsInteger(dstElTy):
		return Const{ty, v.llvm} // signed conversion
	default:
		fail("Cannot cast from %v -> %v", srcTy.TypeName(), dstTy.TypeName())
		return Const{}
	}
}

// Cast casts the global value to the given type.
func (v Global) Cast(ty Type) Global {
	return Global(Const(v).Cast(ty))
}
<commit_msg>core/codegen: Fix bad cast logic introduced by bf6864f9b<commit_after>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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 codegen

import (
	"llvm/bindings/go/llvm"
)

// Cast casts the value v to the type ty.
func (v *Value) Cast(ty Type) *Value {
	srcTy, dstTy := v.Type(), ty
	if srcTy == dstTy {
		return v // No-op
	}
	if IsVector(srcTy) != IsVector(dstTy) {
		fail("Cannot cast between vector and non-vector types. (%v -> %v)", srcTy, dstTy)
	}
	if IsPointer(srcTy) && IsPointer(dstTy) {
		name := srcTy.TypeName() + "->" + dstTy.TypeName()
		return v.b.val(ty, v.b.llvm.CreatePointerCast(v.llvm, ty.llvmTy(), name))
	}
	assertVectorsSameLength(srcTy, dstTy)
	srcElTy, dstElTy := Scalar(srcTy), Scalar(dstTy)
	grow := srcElTy.SizeInBits() < dstElTy.SizeInBits()
	shink := srcElTy.SizeInBits() > dstElTy.SizeInBits()
	switch {
	case IsInteger(srcElTy) && IsPointer(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateIntToPtr(v.llvm, ty.llvmTy(), ""))
	case IsPointer(srcElTy) && IsInteger(dstElTy):
		return v.b.val(ty, v.b.llvm.CreatePtrToInt(v.llvm, ty.llvmTy(), ""))
	case IsSignedInteger(srcElTy) && IsFloat(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateSIToFP(v.llvm, ty.llvmTy(), ""))
	case IsUnsignedInteger(srcElTy) && IsFloat(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateUIToFP(v.llvm, ty.llvmTy(), ""))
	case IsFloat(srcElTy) && IsSignedInteger(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateFPToSI(v.llvm, ty.llvmTy(), ""))
	case IsFloat(srcElTy) && IsUnsignedInteger(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateFPToUI(v.llvm, ty.llvmTy(), ""))
	case IsBool(srcElTy) && IsInteger(dstElTy):
		return v.b.val(ty, v.b.llvm.CreateZExt(v.llvm, ty.llvmTy(), ""))
	case IsInteger(srcElTy) && IsBool(dstElTy):
		return v.b.NotEqual(v, v.b.Zero(srcElTy))
	case IsUnsignedInteger(srcElTy) && IsIntegerOrEnum(dstElTy) && grow:
		return v.b.val(ty, v.b.llvm.CreateZExt(v.llvm, ty.llvmTy(), ""))
	case IsSignedIntegerOrEnum(srcElTy) && IsIntegerOrEnum(dstElTy) && grow:
		return v.b.val(ty, v.b.llvm.CreateSExt(v.llvm, ty.llvmTy(), ""))
	case IsIntegerOrEnum(srcElTy) && IsIntegerOrEnum(dstElTy) && shink:
		return v.b.val(ty, v.b.llvm.CreateTrunc(v.llvm, ty.llvmTy(), ""))
	case IsIntegerOrEnum(srcElTy) && IsIntegerOrEnum(dstElTy):
		return v.b.val(ty, v.llvm) // signed conversion
	case IsFloat(srcElTy) && IsFloat(dstElTy) && shink:
		return v.b.val(ty, v.b.llvm.CreateFPTrunc(v.llvm, ty.llvmTy(), ""))
	case IsFloat(srcElTy) && IsFloat(dstElTy) && grow:
		return v.b.val(ty, v.b.llvm.CreateFPExt(v.llvm, ty.llvmTy(), ""))
	default:
		fail("Cannot cast from %v -> %v", srcTy.TypeName(), dstTy.TypeName())
		return nil
	}
}

// Bitcast performs a bitwise cast of the value v to the type ty.
func (v *Value) Bitcast(ty Type) *Value {
	srcTy, dstTy := v.Type(), ty
	if srcTy == dstTy {
		return v // No-op
	}
	if srcSize, dstSize := srcTy.SizeInBits(), dstTy.SizeInBits(); srcSize != dstSize {
		fail("Bitcast cannot change sizes. (%v -> %v)", srcTy, dstTy)
	}
	return v.b.val(ty, v.b.llvm.CreateBitCast(v.llvm, ty.llvmTy(), "bitcast"))
}

// Cast casts the constant v to the type ty.
func (v Const) Cast(ty Type) Const {
	srcTy, dstTy := v.Type, ty
	if srcTy == dstTy {
		return v // No-op
	}
	if IsVector(srcTy) != IsVector(dstTy) {
		fail("Cannot cast between vector and non-vector types. (%v -> %v)", srcTy, dstTy)
	}
	if IsPointer(srcTy) && IsPointer(dstTy) {
		return Const{ty, llvm.ConstPointerCast(v.llvm, ty.llvmTy())}
	}
	assertVectorsSameLength(srcTy, dstTy)
	srcElTy, dstElTy := Scalar(srcTy), Scalar(dstTy)
	grow := srcElTy.SizeInBits() < dstElTy.SizeInBits()
	shink := srcElTy.SizeInBits() > dstElTy.SizeInBits()
	switch {
	case IsInteger(srcElTy) && IsPointer(dstElTy):
		return Const{ty, llvm.ConstIntToPtr(v.llvm, ty.llvmTy())}
	case IsSignedInteger(srcElTy) && IsFloat(dstElTy):
		return Const{ty, llvm.ConstSIToFP(v.llvm, ty.llvmTy())}
	case IsUnsignedInteger(srcElTy) && IsFloat(dstElTy):
		return Const{ty, llvm.ConstUIToFP(v.llvm, ty.llvmTy())}
	case IsFloat(srcElTy) && IsSignedInteger(dstElTy):
		return Const{ty, llvm.ConstFPToSI(v.llvm, ty.llvmTy())}
	case IsFloat(srcElTy) && IsUnsignedInteger(dstElTy):
		return Const{ty, llvm.ConstFPToUI(v.llvm, ty.llvmTy())}
	case IsBool(srcElTy) && IsInteger(dstElTy):
		return Const{ty, llvm.ConstZExt(v.llvm, ty.llvmTy())}
	case IsInteger(srcElTy) && IsUnsignedInteger(dstElTy) && grow:
		return Const{ty, llvm.ConstZExt(v.llvm, ty.llvmTy())}
	case IsInteger(srcElTy) && IsSignedInteger(dstElTy) && grow:
		return Const{ty, llvm.ConstSExt(v.llvm, ty.llvmTy())}
	case IsInteger(srcElTy) && IsInteger(dstElTy) && shink:
		return Const{ty, llvm.ConstTrunc(v.llvm, ty.llvmTy())}
	case IsInteger(srcElTy) && IsInteger(dstElTy):
		return Const{ty, v.llvm} // signed conversion
	default:
		fail("Cannot cast from %v -> %v", srcTy.TypeName(), dstTy.TypeName())
		return Const{}
	}
}

// Cast casts the global value to the given type.
func (v Global) Cast(ty Type) Global {
	return Global(Const(v).Cast(ty))
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"time"

	cmds "github.com/jbenet/go-ipfs/commands"
	notif "github.com/jbenet/go-ipfs/notifications"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	ipdht "github.com/jbenet/go-ipfs/routing/dht"
	u "github.com/jbenet/go-ipfs/util"
)

var DhtCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "Issue commands directly through the DHT",
		ShortDescription: ``,
	},

	Subcommands: map[string]*cmds.Command{
		"query":     queryDhtCmd,
		"findprovs": findProvidersDhtCmd,
	},
}

var queryDhtCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "Run a 'findClosestPeers' query through the DHT",
		ShortDescription: ``,
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("peerID", true, true, "The peerID to run the query against"),
	},
	Options: []cmds.Option{
		cmds.BoolOption("verbose", "v", "Write extra information"),
	},
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

		dht, ok := n.Routing.(*ipdht.IpfsDHT)
		if !ok {
			return nil, errors.New("Routing service was not a dht")
		}

		events := make(chan *notif.QueryEvent)
		ctx := notif.RegisterForQueryEvents(req.Context().Context, events)

		closestPeers, err := dht.GetClosestPeers(ctx, u.Key(req.Arguments()[0]))

		go func() {
			defer close(events)
			for p := range closestPeers {
				notif.PublishQueryEvent(ctx, &notif.QueryEvent{
					ID:   p,
					Type: notif.FinalPeer,
				})
			}
		}()

		outChan := make(chan interface{})
		go func() {
			defer close(outChan)
			for e := range events {
				outChan <- e
			}
		}()
		return outChan, nil
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			outChan, ok := res.Output().(<-chan interface{})
			if !ok {
				return nil, u.ErrCast()
			}

			marshal := func(v interface{}) (io.Reader, error) {
				obj, ok := v.(*notif.QueryEvent)
				if !ok {
					return nil, u.ErrCast()
				}

				buf := new(bytes.Buffer)
				fmt.Fprintf(buf, "%s: ", time.Now().Format("15:04:05.000"))
				switch obj.Type {
				case notif.FinalPeer:
					fmt.Fprintf(buf, "%s\n", obj.ID)
				case notif.PeerResponse:
					fmt.Fprintf(buf, "* %s says use ", obj.ID)
					for _, p := range obj.Responses {
						fmt.Fprintf(buf, "%s ", p.ID)
					}
					fmt.Fprintln(buf)
				case notif.SendingQuery:
					fmt.Fprintf(buf, "* querying %s\n", obj.ID)
				case notif.QueryError:
					fmt.Fprintf(buf, "error: %s\n", obj.Extra)
				default:
					fmt.Fprintf(buf, "unrecognized event type: %d\n", obj.Type)
				}
				return buf, nil
			}

			return &cmds.ChannelMarshaler{
				Channel:   outChan,
				Marshaler: marshal,
			}, nil
		},
	},
	Type: notif.QueryEvent{},
}

var findProvidersDhtCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Run a 'FindProviders' query through the DHT",
		ShortDescription: `
FindProviders will return a list of peers who are able to provide the value requested.
`,
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("key", true, true, "The key to find providers for"),
	},
	Options: []cmds.Option{
		cmds.BoolOption("verbose", "v", "Write extra information"),
	},
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

		dht, ok := n.Routing.(*ipdht.IpfsDHT)
		if !ok {
			return nil, errors.New("Routing service was not a dht")
		}

		numProviders := 20

		outChan := make(chan interface{})
		pchan := dht.FindProvidersAsync(req.Context().Context, u.B58KeyDecode(req.Arguments()[0]), numProviders)

		go func() {
			defer close(outChan)
			for p := range pchan {
				np := p
				outChan <- &np
			}
		}()
		return outChan, nil
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			outChan, ok := res.Output().(<-chan interface{})
			if !ok {
				return nil, u.ErrCast()
			}

			marshal := func(v interface{}) (io.Reader, error) {
				obj, ok := v.(*peer.PeerInfo)
				if !ok {
					return nil, u.ErrCast()
				}

				verbose, _, err := res.Request().Option("v").Bool()
				if err != nil {
					return nil, err
				}

				buf := new(bytes.Buffer)
				if verbose {
					fmt.Fprintf(buf, "%s\n", obj.ID.Pretty())
				} else {
					fmt.Fprintf(buf, "%s\n", obj.ID)
				}
				return buf, nil
			}

			return &cmds.ChannelMarshaler{
				Channel:   outChan,
				Marshaler: marshal,
			}, nil
		},
	},
	Type: peer.PeerInfo{},
}
<commit_msg>add findpeer command<commit_after>package commands

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"time"

	cmds "github.com/jbenet/go-ipfs/commands"
	notif "github.com/jbenet/go-ipfs/notifications"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	ipdht "github.com/jbenet/go-ipfs/routing/dht"
	u "github.com/jbenet/go-ipfs/util"
)

var DhtCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "Issue commands directly through the DHT",
		ShortDescription: ``,
	},

	Subcommands: map[string]*cmds.Command{
		"query":     queryDhtCmd,
		"findprovs": findProvidersDhtCmd,
		"findpeer":  findPeerDhtCmd,
	},
}

var queryDhtCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "Run a 'findClosestPeers' query through the DHT",
		ShortDescription: ``,
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("peerID", true, true, "The peerID to run the query against"),
	},
	Options: []cmds.Option{
		cmds.BoolOption("verbose", "v", "Write extra information"),
	},
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

		dht, ok := n.Routing.(*ipdht.IpfsDHT)
		if !ok {
			return nil, errors.New("Routing service was not a dht")
		}

		events := make(chan *notif.QueryEvent)
		ctx := notif.RegisterForQueryEvents(req.Context().Context, events)

		closestPeers, err := dht.GetClosestPeers(ctx, u.Key(req.Arguments()[0]))

		go func() {
			defer close(events)
			for p := range closestPeers {
				notif.PublishQueryEvent(ctx, &notif.QueryEvent{
					ID:   p,
					Type: notif.FinalPeer,
				})
			}
		}()

		outChan := make(chan interface{})
		go func() {
			defer close(outChan)
			for e := range events {
				outChan <- e
			}
		}()
		return outChan, nil
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			outChan, ok := res.Output().(<-chan interface{})
			if !ok {
				return nil, u.ErrCast()
			}

			marshal := func(v interface{}) (io.Reader, error) {
				obj, ok := v.(*notif.QueryEvent)
				if !ok {
					return nil, u.ErrCast()
				}

				buf := new(bytes.Buffer)
				fmt.Fprintf(buf, "%s: ", time.Now().Format("15:04:05.000"))
				switch obj.Type {
				case notif.FinalPeer:
					fmt.Fprintf(buf, "%s\n", obj.ID)
				case notif.PeerResponse:
					fmt.Fprintf(buf, "* %s says use ", obj.ID)
					for _, p := range obj.Responses {
						fmt.Fprintf(buf, "%s ", p.ID)
					}
					fmt.Fprintln(buf)
				case notif.SendingQuery:
					fmt.Fprintf(buf, "* querying %s\n", obj.ID)
				case notif.QueryError:
					fmt.Fprintf(buf, "error: %s\n", obj.Extra)
				default:
					fmt.Fprintf(buf, "unrecognized event type: %d\n", obj.Type)
				}
				return buf, nil
			}

			return &cmds.ChannelMarshaler{
				Channel:   outChan,
				Marshaler: marshal,
			}, nil
		},
	},
	Type: notif.QueryEvent{},
}

var findProvidersDhtCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Run a 'FindProviders' query through the DHT",
		ShortDescription: `
FindProviders will return a list of peers who are able to provide the value requested.
`,
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("key", true, true, "The key to find providers for"),
	},
	Options: []cmds.Option{
		cmds.BoolOption("verbose", "v", "Write extra information"),
	},
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

		dht, ok := n.Routing.(*ipdht.IpfsDHT)
		if !ok {
			return nil, errors.New("Routing service was not a dht")
		}

		numProviders := 20

		outChan := make(chan interface{})
		pchan := dht.FindProvidersAsync(req.Context().Context, u.B58KeyDecode(req.Arguments()[0]), numProviders)

		go func() {
			defer close(outChan)
			for p := range pchan {
				np := p
				outChan <- &np
			}
		}()
		return outChan, nil
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			outChan, ok := res.Output().(<-chan interface{})
			if !ok {
				return nil, u.ErrCast()
			}

			marshal := func(v interface{}) (io.Reader, error) {
				obj, ok := v.(*peer.PeerInfo)
				if !ok {
					return nil, u.ErrCast()
				}

				verbose, _, err := res.Request().Option("v").Bool()
				if err != nil {
					return nil, err
				}

				buf := new(bytes.Buffer)
				if verbose {
					fmt.Fprintf(buf, "%s\n", obj.ID.Pretty())
				} else {
					fmt.Fprintf(buf, "%s\n", obj.ID)
				}
				return buf, nil
			}

			return &cmds.ChannelMarshaler{
				Channel:   outChan,
				Marshaler: marshal,
			}, nil
		},
	},
	Type: peer.PeerInfo{},
}

var findPeerDhtCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline:          "Run a 'FindPeer' query through the DHT",
		ShortDescription: ``,
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("peerID", true, true, "The peer to search for"),
	},
	Run: func(req cmds.Request) (interface{}, error) {
		n, err := req.Context().GetNode()
		if err != nil {
			return nil, err
		}

		dht, ok := n.Routing.(*ipdht.IpfsDHT)
		if !ok {
			return nil, errors.New("Routing service was not a dht")
		}

		pid, err := peer.IDB58Decode(req.Arguments()[0])
		if err != nil {
			return nil, err
		}

		pi, err := dht.FindPeer(req.Context().Context, pid)
		if err != nil {
			return nil, err
		}

		return &pi, nil
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {
			pinfo, ok := res.Output().(*peer.PeerInfo)
			if !ok {
				return nil, u.ErrCast()
			}

			buf := new(bytes.Buffer)
			fmt.Fprintf(buf, "found peer: %s\n", pinfo.ID)
			fmt.Fprintf(buf, "reported addresses:\n")
			for _, addr := range pinfo.Addrs {
				fmt.Fprintf(buf, "\t%s\n", addr)
			}

			return buf, nil
		},
	},
	Type: peer.PeerInfo{},
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package apiserver

import (
	"context"
	"net/http"
	"net/url"
	"strings"
	"sync/atomic"
	"time"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/httpstream"
	"k8s.io/apimachinery/pkg/util/httpstream/spdy"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/proxy"
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
	endpointmetrics "k8s.io/apiserver/pkg/endpoints/metrics"
	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
	genericfeatures "k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/transport"
	"k8s.io/klog"
	apiregistrationv1api "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
	apiregistrationv1apihelper "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1/helper"
)

const (
	aggregatorComponent string = "aggregator"

	aggregatedDiscoveryTimeout = 5 * time.Second
)

// proxyHandler provides a http.Handler which will proxy traffic to locations
// specified by items implementing Redirector.
type proxyHandler struct {
	// localDelegate is used to satisfy local APIServices
	localDelegate http.Handler

	// proxyClientCert/Key are the client cert used to identify this proxy. Backing APIServices use
	// this to confirm the proxy's identity
	proxyClientCert []byte
	proxyClientKey  []byte
	proxyTransport  *http.Transport

	// Endpoints based routing to map from cluster IP to routable IP
	serviceResolver ServiceResolver

	handlingInfo atomic.Value

	enableAggregatedDiscoveryTimeout bool
}

type proxyHandlingInfo struct {
	// local indicates that this APIService is locally satisfied
	local bool

	// name is the name of the APIService
	name string
	// restConfig holds the information for building a roundtripper
	restConfig *restclient.Config
	// transportBuildingError is an error produced while building the transport.  If this
	// is non-nil, it will be reported to clients.
	transportBuildingError error
	// proxyRoundTripper is the re-useable portion of the transport.  It does not vary with any request.
	proxyRoundTripper http.RoundTripper
	// serviceName is the name of the service this handler proxies to
	serviceName string
	// namespace is the namespace the service lives in
	serviceNamespace string
	// serviceAvailable indicates this APIService is available or not
	serviceAvailable bool
	// servicePort is the port of the service this handler proxies to
	servicePort int32
}

func proxyError(w http.ResponseWriter, req *http.Request, error string, code int) {
	http.Error(w, error, code)

	ctx := req.Context()
	info, ok := genericapirequest.RequestInfoFrom(ctx)
	if !ok {
		klog.Warning("no RequestInfo found in the context")
		return
	}
	// TODO: record long-running request differently? The long-running check func does not necessarily match the one of the aggregated apiserver
	endpointmetrics.Record(req, info, aggregatorComponent, "", code, 0, 0)
}

func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	value := r.handlingInfo.Load()
	if value == nil {
		r.localDelegate.ServeHTTP(w, req)
		return
	}
	handlingInfo := value.(proxyHandlingInfo)
	if handlingInfo.local {
		if r.localDelegate == nil {
			http.Error(w, "", http.StatusNotFound)
			return
		}
		r.localDelegate.ServeHTTP(w, req)
		return
	}

	if !handlingInfo.serviceAvailable {
		proxyError(w, req, "service unavailable", http.StatusServiceUnavailable)
		return
	}

	if handlingInfo.transportBuildingError != nil {
		proxyError(w, req, handlingInfo.transportBuildingError.Error(), http.StatusInternalServerError)
		return
	}

	user, ok := genericapirequest.UserFrom(req.Context())
	if !ok {
		proxyError(w, req, "missing user", http.StatusInternalServerError)
		return
	}

	// write a new location based on the existing request pointed at the target service
	location := &url.URL{}
	location.Scheme = "https"
	rloc, err := r.serviceResolver.ResolveEndpoint(handlingInfo.serviceNamespace, handlingInfo.serviceName, handlingInfo.servicePort)
	if err != nil {
		klog.Errorf("error resolving %s/%s: %v", handlingInfo.serviceNamespace, handlingInfo.serviceName, err)
		proxyError(w, req, "service unavailable", http.StatusServiceUnavailable)
		return
	}
	location.Host = rloc.Host
	location.Path = req.URL.Path
	location.RawQuery = req.URL.Query().Encode()

	newReq, cancelFn := newRequestForProxy(location, req, r.enableAggregatedDiscoveryTimeout)
	defer cancelFn()

	if handlingInfo.proxyRoundTripper == nil {
		proxyError(w, req, "", http.StatusNotFound)
		return
	}

	// we need to wrap the roundtripper in another roundtripper which will apply the front proxy headers
	proxyRoundTripper, upgrade, err := maybeWrapForConnectionUpgrades(handlingInfo.restConfig, handlingInfo.proxyRoundTripper, req)
	if err != nil {
		proxyError(w, req, err.Error(), http.StatusInternalServerError)
		return
	}
	proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), user.GetGroups(), user.GetExtra(), proxyRoundTripper)

	// if we are upgrading, then the upgrade path tries to use this request with the TLS config we provide, but it does
	// NOT use the roundtripper.  Its a direct call that bypasses the round tripper.  This means that we have to
	// attach the "correct" user headers to the request ahead of time.  After the initial upgrade, we'll be back
	// at the roundtripper flow, so we only have to muck with this request, but we do have to do it.
	if upgrade {
		transport.SetAuthProxyHeaders(newReq, user.GetName(), user.GetGroups(), user.GetExtra())
	}

	handler := proxy.NewUpgradeAwareHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w})
	handler.ServeHTTP(w, newReq)
}

// newRequestForProxy returns a shallow copy of the original request with a context that may include a timeout for discovery requests
func newRequestForProxy(location *url.URL, req *http.Request, enableAggregatedDiscoveryTimeout bool) (*http.Request, context.CancelFunc) {
	newCtx := context.Background()
	cancelFn := func() {}

	// if the original request has a deadline, we should honor that deadline for our proxied request
	if deadline, ok := req.Context().Deadline(); ok {
		newCtx, cancelFn = context.WithDeadline(newCtx, deadline)

		// trim leading and trailing slashes. Then "/apis/group/version" requests are for discovery, so if we have exactly three
		// segments that we are going to proxy, we have a discovery request.
	} else if enableAggregatedDiscoveryTimeout && len(strings.Split(strings.Trim(req.URL.Path, "/"), "/")) == 3 {
		// discovery requests are used by kubectl and others to determine which resources a server has.  This is a cheap call that
		// should be fast for every aggregated apiserver.  Latency for aggregation is expected to be low (as for all extensions)
		// so forcing a short timeout here helps responsiveness of all clients.
		newCtx, cancelFn = context.WithTimeout(newCtx, aggregatedDiscoveryTimeout)
	}

	// WithContext creates a shallow clone of the request with the new context.
	newReq := req.WithContext(newCtx)
	newReq.Header = utilnet.CloneHeader(req.Header)
	newReq.URL = location
	newReq.Host = location.Host

	return newReq, cancelFn
}

// maybeWrapForConnectionUpgrades wraps the roundtripper for upgrades.  The bool indicates if it was wrapped
func maybeWrapForConnectionUpgrades(restConfig *restclient.Config, rt http.RoundTripper, req *http.Request) (http.RoundTripper, bool, error) {
	if !httpstream.IsUpgradeRequest(req) {
		return rt, false, nil
	}

	tlsConfig, err := restclient.TLSConfigFor(restConfig)
	if err != nil {
		return nil, true, err
	}
	followRedirects := utilfeature.DefaultFeatureGate.Enabled(genericfeatures.StreamingProxyRedirects)
	requireSameHostRedirects := utilfeature.DefaultFeatureGate.Enabled(genericfeatures.ValidateProxyRedirects)
	upgradeRoundTripper := spdy.NewRoundTripper(tlsConfig, followRedirects, requireSameHostRedirects)
	wrappedRT, err := restclient.HTTPWrappersForConfig(restConfig, upgradeRoundTripper)
	if err != nil {
		return nil, true, err
	}

	return wrappedRT, true, nil
}

// responder implements rest.Responder for assisting a connector in writing objects or errors.
type responder struct {
	w http.ResponseWriter
}

// TODO this should properly handle content type negotiation
// if the caller asked for protobuf and you write JSON bad things happen.
func (r *responder) Object(statusCode int, obj runtime.Object) {
	responsewriters.WriteRawJSON(statusCode, obj, r.w)
}

func (r *responder) Error(_ http.ResponseWriter, _ *http.Request, err error) {
	http.Error(r.w, err.Error(), http.StatusInternalServerError)
}

// these methods provide locked access to fields

func (r *proxyHandler) updateAPIService(apiService *apiregistrationv1api.APIService) {
	if apiService.Spec.Service == nil {
		r.handlingInfo.Store(proxyHandlingInfo{local: true})
		return
	}

	newInfo := proxyHandlingInfo{
		name: apiService.Name,
		restConfig: &restclient.Config{
			TLSClientConfig: restclient.TLSClientConfig{
				Insecure:   apiService.Spec.InsecureSkipTLSVerify,
				ServerName: apiService.Spec.Service.Name + "." + apiService.Spec.Service.Namespace + ".svc",
				CertData:   r.proxyClientCert,
				KeyData:    r.proxyClientKey,
				CAData:     apiService.Spec.CABundle,
			},
		},
		serviceName:      apiService.Spec.Service.Name,
		serviceNamespace: apiService.Spec.Service.Namespace,
		servicePort:      *apiService.Spec.Service.Port,
		serviceAvailable: apiregistrationv1apihelper.IsAPIServiceConditionTrue(apiService, apiregistrationv1api.Available),
	}
	if r.proxyTransport != nil && r.proxyTransport.DialContext != nil {
		newInfo.restConfig.Dial = r.proxyTransport.DialContext
	}
	newInfo.proxyRoundTripper, newInfo.transportBuildingError = restclient.TransportFor(newInfo.restConfig)
	if newInfo.transportBuildingError != nil {
		klog.Warning(newInfo.transportBuildingError.Error())
	}
	r.handlingInfo.Store(newInfo)
}
<commit_msg>use the same context for aggregated and proxy requests<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package apiserver

import (
	"context"
	"net/http"
	"net/url"
	"strings"
	"sync/atomic"
	"time"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/httpstream"
	"k8s.io/apimachinery/pkg/util/httpstream/spdy"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/proxy"
	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
	endpointmetrics "k8s.io/apiserver/pkg/endpoints/metrics"
	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
	genericfeatures "k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	restclient "k8s.io/client-go/rest"
	"k8s.io/client-go/transport"
	"k8s.io/klog"
	apiregistrationv1api "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
	apiregistrationv1apihelper "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1/helper"
)

const (
	aggregatorComponent string = "aggregator"

	aggregatedDiscoveryTimeout = 5 * time.Second
)

// proxyHandler provides a http.Handler which will proxy traffic to locations
// specified by items implementing Redirector.
type proxyHandler struct {
	// localDelegate is used to satisfy local APIServices
	localDelegate http.Handler

	// proxyClientCert/Key are the client cert used to identify this proxy. Backing APIServices use
	// this to confirm the proxy's identity
	proxyClientCert []byte
	proxyClientKey  []byte
	proxyTransport  *http.Transport

	// Endpoints based routing to map from cluster IP to routable IP
	serviceResolver ServiceResolver

	handlingInfo atomic.Value

	enableAggregatedDiscoveryTimeout bool
}

type proxyHandlingInfo struct {
	// local indicates that this APIService is locally satisfied
	local bool

	// name is the name of the APIService
	name string
	// restConfig holds the information for building a roundtripper
	restConfig *restclient.Config
	// transportBuildingError is an error produced while building the transport.  If this
	// is non-nil, it will be reported to clients.
	transportBuildingError error
	// proxyRoundTripper is the re-useable portion of the transport.  It does not vary with any request.
	proxyRoundTripper http.RoundTripper
	// serviceName is the name of the service this handler proxies to
	serviceName string
	// namespace is the namespace the service lives in
	serviceNamespace string
	// serviceAvailable indicates this APIService is available or not
	serviceAvailable bool
	// servicePort is the port of the service this handler proxies to
	servicePort int32
}

func proxyError(w http.ResponseWriter, req *http.Request, error string, code int) {
	http.Error(w, error, code)

	ctx := req.Context()
	info, ok := genericapirequest.RequestInfoFrom(ctx)
	if !ok {
		klog.Warning("no RequestInfo found in the context")
		return
	}
	// TODO: record long-running request differently? The long-running check func does not necessarily match the one of the aggregated apiserver
	endpointmetrics.Record(req, info, aggregatorComponent, "", code, 0, 0)
}

func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	value := r.handlingInfo.Load()
	if value == nil {
		r.localDelegate.ServeHTTP(w, req)
		return
	}
	handlingInfo := value.(proxyHandlingInfo)
	if handlingInfo.local {
		if r.localDelegate == nil {
			http.Error(w, "", http.StatusNotFound)
			return
		}
		r.localDelegate.ServeHTTP(w, req)
		return
	}

	if !handlingInfo.serviceAvailable {
		proxyError(w, req, "service unavailable", http.StatusServiceUnavailable)
		return
	}

	if handlingInfo.transportBuildingError != nil {
		proxyError(w, req, handlingInfo.transportBuildingError.Error(), http.StatusInternalServerError)
		return
	}

	user, ok := genericapirequest.UserFrom(req.Context())
	if !ok {
		proxyError(w, req, "missing user", http.StatusInternalServerError)
		return
	}

	// write a new location based on the existing request pointed at the target service
	location := &url.URL{}
	location.Scheme = "https"
	rloc, err := r.serviceResolver.ResolveEndpoint(handlingInfo.serviceNamespace, handlingInfo.serviceName, handlingInfo.servicePort)
	if err != nil {
		klog.Errorf("error resolving %s/%s: %v", handlingInfo.serviceNamespace, handlingInfo.serviceName, err)
		proxyError(w, req, "service unavailable", http.StatusServiceUnavailable)
		return
	}
	location.Host = rloc.Host
	location.Path = req.URL.Path
	location.RawQuery = req.URL.Query().Encode()

	newReq, cancelFn := newRequestForProxy(location, req, r.enableAggregatedDiscoveryTimeout)
	defer cancelFn()

	if handlingInfo.proxyRoundTripper == nil {
		proxyError(w, req, "", http.StatusNotFound)
		return
	}

	// we need to wrap the roundtripper in another roundtripper which will apply the front proxy headers
	proxyRoundTripper, upgrade, err := maybeWrapForConnectionUpgrades(handlingInfo.restConfig, handlingInfo.proxyRoundTripper, req)
	if err != nil {
		proxyError(w, req, err.Error(), http.StatusInternalServerError)
		return
	}
	proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), user.GetGroups(), user.GetExtra(), proxyRoundTripper)

	// if we are upgrading, then the upgrade path tries to use this request with the TLS config we provide, but it does
	// NOT use the roundtripper.  Its a direct call that bypasses the round tripper.  This means that we have to
	// attach the "correct" user headers to the request ahead of time.  After the initial upgrade, we'll be back
	// at the roundtripper flow, so we only have to muck with this request, but we do have to do it.
	if upgrade {
		transport.SetAuthProxyHeaders(newReq, user.GetName(), user.GetGroups(), user.GetExtra())
	}

	handler := proxy.NewUpgradeAwareHandler(location, proxyRoundTripper, true, upgrade, &responder{w: w})
	handler.ServeHTTP(w, newReq)
}

// newRequestForProxy returns a shallow copy of the original request with a context that may include a timeout for discovery requests
func newRequestForProxy(location *url.URL, req *http.Request, enableAggregatedDiscoveryTimeout bool) (*http.Request, context.CancelFunc) {
	newCtx := req.Context()
	cancelFn := func() {}

	// trim leading and trailing slashes. Then "/apis/group/version" requests are for discovery, so if we have exactly three
	// segments that we are going to proxy, we have a discovery request.
	if enableAggregatedDiscoveryTimeout && len(strings.Split(strings.Trim(req.URL.Path, "/"), "/")) == 3 {
		// discovery requests are used by kubectl and others to determine which resources a server has.  This is a cheap call that
		// should be fast for every aggregated apiserver.  Latency for aggregation is expected to be low (as for all extensions)
		// so forcing a short timeout here helps responsiveness of all clients.
		newCtx, cancelFn = context.WithTimeout(newCtx, aggregatedDiscoveryTimeout)
	}

	// WithContext creates a shallow clone of the request with the same context.
	newReq := req.WithContext(newCtx)
	newReq.Header = utilnet.CloneHeader(req.Header)
	newReq.URL = location
	newReq.Host = location.Host

	return newReq, cancelFn
}

// maybeWrapForConnectionUpgrades wraps the roundtripper for upgrades.  The bool indicates if it was wrapped
func maybeWrapForConnectionUpgrades(restConfig *restclient.Config, rt http.RoundTripper, req *http.Request) (http.RoundTripper, bool, error) {
	if !httpstream.IsUpgradeRequest(req) {
		return rt, false, nil
	}

	tlsConfig, err := restclient.TLSConfigFor(restConfig)
	if err != nil {
		return nil, true, err
	}
	followRedirects := utilfeature.DefaultFeatureGate.Enabled(genericfeatures.StreamingProxyRedirects)
	requireSameHostRedirects := utilfeature.DefaultFeatureGate.Enabled(genericfeatures.ValidateProxyRedirects)
	upgradeRoundTripper := spdy.NewRoundTripper(tlsConfig, followRedirects, requireSameHostRedirects)
	wrappedRT, err := restclient.HTTPWrappersForConfig(restConfig, upgradeRoundTripper)
	if err != nil {
		return nil, true, err
	}

	return wrappedRT, true, nil
}

// responder implements rest.Responder for assisting a connector in writing objects or errors.
type responder struct {
	w http.ResponseWriter
}

// TODO this should properly handle content type negotiation
// if the caller asked for protobuf and you write JSON bad things happen.
func (r *responder) Object(statusCode int, obj runtime.Object) {
	responsewriters.WriteRawJSON(statusCode, obj, r.w)
}

func (r *responder) Error(_ http.ResponseWriter, _ *http.Request, err error) {
	http.Error(r.w, err.Error(), http.StatusInternalServerError)
}

// these methods provide locked access to fields

func (r *proxyHandler) updateAPIService(apiService *apiregistrationv1api.APIService) {
	if apiService.Spec.Service == nil {
		r.handlingInfo.Store(proxyHandlingInfo{local: true})
		return
	}

	newInfo := proxyHandlingInfo{
		name: apiService.Name,
		restConfig: &restclient.Config{
			TLSClientConfig: restclient.TLSClientConfig{
				Insecure:   apiService.Spec.InsecureSkipTLSVerify,
				ServerName: apiService.Spec.Service.Name + "." + apiService.Spec.Service.Namespace + ".svc",
				CertData:   r.proxyClientCert,
				KeyData:    r.proxyClientKey,
				CAData:     apiService.Spec.CABundle,
			},
		},
		serviceName:      apiService.Spec.Service.Name,
		serviceNamespace: apiService.Spec.Service.Namespace,
		servicePort:      *apiService.Spec.Service.Port,
		serviceAvailable: apiregistrationv1apihelper.IsAPIServiceConditionTrue(apiService, apiregistrationv1api.Available),
	}
	if r.proxyTransport != nil && r.proxyTransport.DialContext != nil {
		newInfo.restConfig.Dial = r.proxyTransport.DialContext
	}
	newInfo.proxyRoundTripper, newInfo.transportBuildingError = restclient.TransportFor(newInfo.restConfig)
	if newInfo.transportBuildingError != nil {
		klog.Warning(newInfo.transportBuildingError.Error())
	}
	r.handlingInfo.Store(newInfo)
}
<|endoftext|>