<commit_before>// Copyright (c) 2018 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package native

import (
	"net/http"

	"github.com/m3db/m3/src/query/api/v1/handler"
	"github.com/m3db/m3/src/query/api/v1/handler/prometheus/handleroptions"
	"github.com/m3db/m3/src/query/api/v1/options"
	"github.com/m3db/m3/src/query/util/json"
	"github.com/m3db/m3/src/query/util/logging"
	xhttp "github.com/m3db/m3/src/x/net/http"
	xopentracing "github.com/m3db/m3/src/x/opentracing"

	opentracingext "github.com/opentracing/opentracing-go/ext"
	opentracinglog "github.com/opentracing/opentracing-go/log"
	"go.uber.org/zap"
)

const (
	// PromReadURL is the URL for native prom read handler, this matches the
	// default URL for the query range endpoint found on a Prometheus server.
	PromReadURL = handler.RoutePrefixV1 + "/query_range"

	// PromReadInstantURL is the URL for native instantaneous prom read
	// handler, this matches the  default URL for the query endpoint
	// found on a Prometheus server.
	PromReadInstantURL = handler.RoutePrefixV1 + "/query"

	// PrometheusReadURL is the URL for native prom read handler.
	PrometheusReadURL = "/prometheus" + PromReadURL

	// PrometheusReadInstantURL is the URL for native instantaneous prom read handler.
	PrometheusReadInstantURL = "/prometheus" + PromReadInstantURL

	// M3QueryReadURL is the URL for native m3 query read handler.
	M3QueryReadURL = "/m3query" + PromReadURL

	// M3QueryReadInstantURL is the URL for native instantaneous m3 query read handler.
	M3QueryReadInstantURL = "/m3query" + PromReadInstantURL
)

var (
	// PromReadHTTPMethods are the HTTP methods for the read handler.
	PromReadHTTPMethods = []string{
		http.MethodGet,
		http.MethodPost,
	}

	// PromReadInstantHTTPMethods are the HTTP methods for the instant handler.
	PromReadInstantHTTPMethods = []string{
		http.MethodGet,
		http.MethodPost,
	}
)

// promReadHandler represents a handler for prometheus read endpoint.
type promReadHandler struct {
	instant         bool
	promReadMetrics promReadMetrics
	opts            options.HandlerOptions
}

// NewPromReadHandler returns a new prometheus-compatible read handler.
func NewPromReadHandler(opts options.HandlerOptions) http.Handler {
	return newHandler(opts, false)
}

// NewPromReadInstantHandler returns a new pro instance of handler.
func NewPromReadInstantHandler(opts options.HandlerOptions) http.Handler {
	return newHandler(opts, true)
}

// newHandler returns a new pro instance of handler.
func newHandler(opts options.HandlerOptions, instant bool) http.Handler {
	name := "native-read"
	if instant {
		name = "native-instant-read"
	}

	taggedScope := opts.InstrumentOpts().MetricsScope().
		Tagged(map[string]string{"handler": name})
	h := &promReadHandler{
		promReadMetrics: newPromReadMetrics(taggedScope),
		opts:            opts,
		instant:         instant,
	}
	return h
}

func (h *promReadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	timer := h.promReadMetrics.fetchTimerSuccess.Start()
	defer timer.Stop()

	iOpts := h.opts.InstrumentOpts()
	logger := logging.WithContext(r.Context(), iOpts)

	ctx, parsedOptions, rErr := ParseRequest(r.Context(), r, h.instant, h.opts)
	if rErr != nil {
		h.promReadMetrics.incError(rErr)
		logger.Error("could not parse request", zap.Error(rErr))
		xhttp.WriteError(w, rErr)
		return
	}
	ctx = logging.NewContext(ctx,
		iOpts,
		zap.String("query", parsedOptions.Params.Query),
		zap.Time("start", parsedOptions.Params.Start),
		zap.Time("end", parsedOptions.Params.End),
		zap.Duration("step", parsedOptions.Params.Step),
		zap.Duration("timeout", parsedOptions.Params.Timeout),
		zap.Duration("fetchTimeout", parsedOptions.FetchOpts.Timeout),
	)

	result, err := read(ctx, parsedOptions, h.opts)
	if err != nil {
		sp := xopentracing.SpanFromContextOrNoop(ctx)
		sp.LogFields(opentracinglog.Error(err))
		opentracingext.Error.Set(sp, true)
		logger.Error("range query error",
			zap.Error(err),
			zap.Any("parsedOptions", parsedOptions))
		h.promReadMetrics.incError(err)

		xhttp.WriteError(w, err)
		return
	}

	w.Header().Set(xhttp.HeaderContentType, xhttp.ContentTypeJSON)

	h.promReadMetrics.fetchSuccess.Inc(1)

	keepNaNs := h.opts.Config().ResultOptions.KeepNaNs
	if !keepNaNs {
		keepNaNs = result.Meta.KeepNaNs
	}

	renderOpts := RenderResultsOptions{
		Start:                   parsedOptions.Params.Start,
		End:                     parsedOptions.Params.End,
		KeepNaNs:                keepNaNs,
		ReturnedSeriesLimit:     parsedOptions.FetchOpts.ReturnedSeriesLimit,
		ReturnedDatapointsLimit: parsedOptions.FetchOpts.ReturnedDatapointsLimit,
	}

	// First invoke the results rendering with a noop writer in order to
	// check the returned-data limits. This must be done before the actual rendering
	// so that we can add the returned-data-limited header which must precede body writing.
	var (
		renderResult RenderResultsResult
		noopWriter   = json.NewNoopWriter()
	)
	if h.instant {
		renderResult = renderResultsInstantaneousJSON(noopWriter, result, renderOpts)
	} else {
		renderResult = RenderResultsJSON(noopWriter, result, renderOpts)
	}

	h.promReadMetrics.returnedDataMetrics.FetchDatapoints.RecordValue(float64(renderResult.Datapoints))
	h.promReadMetrics.returnedDataMetrics.FetchSeries.RecordValue(float64(renderResult.Series))

	meta := result.Meta
	limited := &handleroptions.ReturnedDataLimited{
		Limited:     renderResult.LimitedMaxReturnedData,
		Series:      renderResult.Series,
		TotalSeries: renderResult.TotalSeries,
		Datapoints:  renderResult.Datapoints,
	}
	err = handleroptions.AddResponseHeaders(w, meta, parsedOptions.FetchOpts, limited, nil)
	if err != nil {
		logger.Error("error writing returned data limited header", zap.Error(err))
		xhttp.WriteError(w, err)
		return
	}

	// Write the actual results after having checked for limits and wrote headers if needed.
	responseWriter := json.NewWriter(w)
	if h.instant {
		_ = renderResultsInstantaneousJSON(responseWriter, result, renderOpts)
	} else {
		_ = RenderResultsJSON(responseWriter, result, renderOpts)
	}

	if responseWriter.Close() != nil {
		w.WriteHeader(http.StatusInternalServerError)
		logger.Error("failed to render results", zap.Error(err))
	} else {
		w.WriteHeader(http.StatusOK)
	}
}
<commit_msg>Log Close err in prom read handler (#3436)<commit_after>// Copyright (c) 2018 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package native

import (
	"net/http"

	"github.com/m3db/m3/src/query/api/v1/handler"
	"github.com/m3db/m3/src/query/api/v1/handler/prometheus/handleroptions"
	"github.com/m3db/m3/src/query/api/v1/options"
	"github.com/m3db/m3/src/query/util/json"
	"github.com/m3db/m3/src/query/util/logging"
	xhttp "github.com/m3db/m3/src/x/net/http"
	xopentracing "github.com/m3db/m3/src/x/opentracing"

	opentracingext "github.com/opentracing/opentracing-go/ext"
	opentracinglog "github.com/opentracing/opentracing-go/log"
	"go.uber.org/zap"
)

const (
	// PromReadURL is the URL for native prom read handler, this matches the
	// default URL for the query range endpoint found on a Prometheus server.
	PromReadURL = handler.RoutePrefixV1 + "/query_range"

	// PromReadInstantURL is the URL for native instantaneous prom read
	// handler, this matches the  default URL for the query endpoint
	// found on a Prometheus server.
	PromReadInstantURL = handler.RoutePrefixV1 + "/query"

	// PrometheusReadURL is the URL for native prom read handler.
	PrometheusReadURL = "/prometheus" + PromReadURL

	// PrometheusReadInstantURL is the URL for native instantaneous prom read handler.
	PrometheusReadInstantURL = "/prometheus" + PromReadInstantURL

	// M3QueryReadURL is the URL for native m3 query read handler.
	M3QueryReadURL = "/m3query" + PromReadURL

	// M3QueryReadInstantURL is the URL for native instantaneous m3 query read handler.
	M3QueryReadInstantURL = "/m3query" + PromReadInstantURL
)

var (
	// PromReadHTTPMethods are the HTTP methods for the read handler.
	PromReadHTTPMethods = []string{
		http.MethodGet,
		http.MethodPost,
	}

	// PromReadInstantHTTPMethods are the HTTP methods for the instant handler.
	PromReadInstantHTTPMethods = []string{
		http.MethodGet,
		http.MethodPost,
	}
)

// promReadHandler represents a handler for prometheus read endpoint.
type promReadHandler struct {
	instant         bool
	promReadMetrics promReadMetrics
	opts            options.HandlerOptions
}

// NewPromReadHandler returns a new prometheus-compatible read handler.
func NewPromReadHandler(opts options.HandlerOptions) http.Handler {
	return newHandler(opts, false)
}

// NewPromReadInstantHandler returns a new pro instance of handler.
func NewPromReadInstantHandler(opts options.HandlerOptions) http.Handler {
	return newHandler(opts, true)
}

// newHandler returns a new pro instance of handler.
func newHandler(opts options.HandlerOptions, instant bool) http.Handler {
	name := "native-read"
	if instant {
		name = "native-instant-read"
	}

	taggedScope := opts.InstrumentOpts().MetricsScope().
		Tagged(map[string]string{"handler": name})
	h := &promReadHandler{
		promReadMetrics: newPromReadMetrics(taggedScope),
		opts:            opts,
		instant:         instant,
	}
	return h
}

func (h *promReadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	timer := h.promReadMetrics.fetchTimerSuccess.Start()
	defer timer.Stop()

	iOpts := h.opts.InstrumentOpts()
	logger := logging.WithContext(r.Context(), iOpts)

	ctx, parsedOptions, rErr := ParseRequest(r.Context(), r, h.instant, h.opts)
	if rErr != nil {
		h.promReadMetrics.incError(rErr)
		logger.Error("could not parse request", zap.Error(rErr))
		xhttp.WriteError(w, rErr)
		return
	}
	ctx = logging.NewContext(ctx,
		iOpts,
		zap.String("query", parsedOptions.Params.Query),
		zap.Time("start", parsedOptions.Params.Start),
		zap.Time("end", parsedOptions.Params.End),
		zap.Duration("step", parsedOptions.Params.Step),
		zap.Duration("timeout", parsedOptions.Params.Timeout),
		zap.Duration("fetchTimeout", parsedOptions.FetchOpts.Timeout),
	)

	result, err := read(ctx, parsedOptions, h.opts)
	if err != nil {
		sp := xopentracing.SpanFromContextOrNoop(ctx)
		sp.LogFields(opentracinglog.Error(err))
		opentracingext.Error.Set(sp, true)
		logger.Error("range query error",
			zap.Error(err),
			zap.Any("parsedOptions", parsedOptions))
		h.promReadMetrics.incError(err)

		xhttp.WriteError(w, err)
		return
	}

	w.Header().Set(xhttp.HeaderContentType, xhttp.ContentTypeJSON)

	h.promReadMetrics.fetchSuccess.Inc(1)

	keepNaNs := h.opts.Config().ResultOptions.KeepNaNs
	if !keepNaNs {
		keepNaNs = result.Meta.KeepNaNs
	}

	renderOpts := RenderResultsOptions{
		Start:                   parsedOptions.Params.Start,
		End:                     parsedOptions.Params.End,
		KeepNaNs:                keepNaNs,
		ReturnedSeriesLimit:     parsedOptions.FetchOpts.ReturnedSeriesLimit,
		ReturnedDatapointsLimit: parsedOptions.FetchOpts.ReturnedDatapointsLimit,
	}

	// First invoke the results rendering with a noop writer in order to
	// check the returned-data limits. This must be done before the actual rendering
	// so that we can add the returned-data-limited header which must precede body writing.
	var (
		renderResult RenderResultsResult
		noopWriter   = json.NewNoopWriter()
	)
	if h.instant {
		renderResult = renderResultsInstantaneousJSON(noopWriter, result, renderOpts)
	} else {
		renderResult = RenderResultsJSON(noopWriter, result, renderOpts)
	}

	h.promReadMetrics.returnedDataMetrics.FetchDatapoints.RecordValue(float64(renderResult.Datapoints))
	h.promReadMetrics.returnedDataMetrics.FetchSeries.RecordValue(float64(renderResult.Series))

	meta := result.Meta
	limited := &handleroptions.ReturnedDataLimited{
		Limited:     renderResult.LimitedMaxReturnedData,
		Series:      renderResult.Series,
		TotalSeries: renderResult.TotalSeries,
		Datapoints:  renderResult.Datapoints,
	}
	err = handleroptions.AddResponseHeaders(w, meta, parsedOptions.FetchOpts, limited, nil)
	if err != nil {
		logger.Error("error writing returned data limited header", zap.Error(err))
		xhttp.WriteError(w, err)
		return
	}

	// Write the actual results after having checked for limits and wrote headers if needed.
	responseWriter := json.NewWriter(w)
	if h.instant {
		_ = renderResultsInstantaneousJSON(responseWriter, result, renderOpts)
	} else {
		_ = RenderResultsJSON(responseWriter, result, renderOpts)
	}

	if err := responseWriter.Close(); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		logger.Error("failed to render results", zap.Error(err))
	} else {
		w.WriteHeader(http.StatusOK)
	}
}
<|endoftext|>


<commit_before>// +build !js

package webrtc

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pion/rtp"
	"github.com/pion/rtp/codecs"
	"github.com/pion/sdp/v2"
)

// PayloadTypes for the default codecs
const (
	DefaultPayloadTypePCMU = 0
	DefaultPayloadTypePCMA = 8
	DefaultPayloadTypeG722 = 9
	DefaultPayloadTypeOpus = 111
	DefaultPayloadTypeVP8  = 96
	DefaultPayloadTypeVP9  = 98
	DefaultPayloadTypeH264 = 102

	mediaNameAudio = "audio"
	mediaNameVideo = "video"
)

// MediaEngine defines the codecs supported by a PeerConnection
type MediaEngine struct {
	codecs []*RTPCodec
}

// RegisterCodec registers a codec to a media engine
func (m *MediaEngine) RegisterCodec(codec *RTPCodec) uint8 {
	// pion/webrtc#43
	m.codecs = append(m.codecs, codec)
	return codec.PayloadType
}

// RegisterDefaultCodecs is a helper that registers the default codecs supported by Pion WebRTC
func (m *MediaEngine) RegisterDefaultCodecs() {
	// Audio Codecs in order of preference
	m.RegisterCodec(NewRTPOpusCodec(DefaultPayloadTypeOpus, 48000))
	m.RegisterCodec(NewRTPPCMUCodec(DefaultPayloadTypePCMU, 8000))
	m.RegisterCodec(NewRTPPCMACodec(DefaultPayloadTypePCMA, 8000))
	m.RegisterCodec(NewRTPG722Codec(DefaultPayloadTypeG722, 8000))

	// Video Codecs in order of preference
	m.RegisterCodec(NewRTPVP8Codec(DefaultPayloadTypeVP8, 90000))
	m.RegisterCodec(NewRTPVP9Codec(DefaultPayloadTypeVP9, 90000))
	m.RegisterCodec(NewRTPH264Codec(DefaultPayloadTypeH264, 90000))
}

// PopulateFromSDP finds all codecs in a session description and adds them to a MediaEngine, using dynamic
// payload types and parameters from the sdp.
func (m *MediaEngine) PopulateFromSDP(sd SessionDescription) error {
	sdp := sdp.SessionDescription{}
	if err := sdp.Unmarshal([]byte(sd.SDP)); err != nil {
		return err
	}

	for _, md := range sdp.MediaDescriptions {
		if md.MediaName.Media != mediaNameAudio && md.MediaName.Media != mediaNameVideo {
			continue
		}

		for _, format := range md.MediaName.Formats {
			pt, err := strconv.Atoi(format)
			if err != nil {
				return fmt.Errorf("format parse error")
			}

			payloadType := uint8(pt)
			payloadCodec, err := sdp.GetCodecForPayloadType(payloadType)
			if err != nil {
				return fmt.Errorf("could not find codec for payload type %d", payloadType)
			}

			var codec *RTPCodec
			switch {
			case strings.EqualFold(payloadCodec.Name, PCMA):
				codec = NewRTPPCMACodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, PCMU):
				codec = NewRTPPCMUCodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, G722):
				codec = NewRTPG722Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, Opus):
				codec = NewRTPOpusCodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, VP8):
				codec = NewRTPVP8Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, VP9):
				codec = NewRTPVP9Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, H264):
				codec = NewRTPH264Codec(payloadType, payloadCodec.ClockRate)
			default:
				// ignoring other codecs
				continue
			}

			codec.SDPFmtpLine = payloadCodec.Fmtp
			m.RegisterCodec(codec)
		}
	}
	return nil
}

func (m *MediaEngine) getCodec(payloadType uint8) (*RTPCodec, error) {
	for _, codec := range m.codecs {
		if codec.PayloadType == payloadType {
			return codec, nil
		}
	}
	return nil, ErrCodecNotFound
}

func (m *MediaEngine) getCodecSDP(sdpCodec sdp.Codec) (*RTPCodec, error) {
	for _, codec := range m.codecs {
		if codec.Name == sdpCodec.Name &&
			codec.ClockRate == sdpCodec.ClockRate &&
			(sdpCodec.EncodingParameters == "" ||
				strconv.Itoa(int(codec.Channels)) == sdpCodec.EncodingParameters) &&
			codec.SDPFmtpLine == sdpCodec.Fmtp { // pion/webrtc#43
			return codec, nil
		}
	}
	return nil, ErrCodecNotFound
}

// GetCodecsByKind returns all codecs of a chosen kind in the codecs list
func (m *MediaEngine) GetCodecsByKind(kind RTPCodecType) []*RTPCodec {
	var codecs []*RTPCodec
	for _, codec := range m.codecs {
		if codec.Type == kind {
			codecs = append(codecs, codec)
		}
	}
	return codecs
}

// Names for the default codecs supported by Pion WebRTC
const (
	PCMU = "PCMU"
	PCMA = "PCMA"
	G722 = "G722"
	Opus = "opus"
	VP8  = "VP8"
	VP9  = "VP9"
	H264 = "H264"
)

// NewRTPPCMUCodec is a helper to create a PCMU codec
func NewRTPPCMUCodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		PCMU,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G711Payloader{})
	return c
}

// NewRTPPCMACodec is a helper to create a PCMA codec
func NewRTPPCMACodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		PCMA,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G711Payloader{})
	return c
}

// NewRTPG722Codec is a helper to create a G722 codec
func NewRTPG722Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		G722,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G722Payloader{})
	return c
}

// NewRTPOpusCodec is a helper to create an Opus codec
func NewRTPOpusCodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		Opus,
		clockrate,
		2, //According to RFC7587, Opus RTP streams must have exactly 2 channels.
		"minptime=10;useinbandfec=1",
		payloadType,
		&codecs.OpusPayloader{})
	return c
}

// NewRTPVP8Codec is a helper to create an VP8 codec
func NewRTPVP8Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		VP8,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.VP8Payloader{})
	return c
}

// NewRTPVP8CodecExt is a helper to create an VP8 codec
func NewRTPVP8CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		VP8,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.VP8Payloader{})
	return c
}

// NewRTPVP9Codec is a helper to create an VP9 codec
func NewRTPVP9Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		VP9,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.VP9Payloader{})
	return c
}

// NewRTPH264Codec is a helper to create an H264 codec
func NewRTPH264Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		H264,
		clockrate,
		0,
		"level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
		payloadType,
		&codecs.H264Payloader{})
	return c
}

// NewRTPH264CodecExt is a helper to create an H264 codec
func NewRTPH264CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		H264,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.H264Payloader{})
	return c
}

// RTPCodecType determines the type of a codec
type RTPCodecType int

const (

	// RTPCodecTypeAudio indicates this is an audio codec
	RTPCodecTypeAudio RTPCodecType = iota + 1

	// RTPCodecTypeVideo indicates this is a video codec
	RTPCodecTypeVideo
)

func (t RTPCodecType) String() string {
	switch t {
	case RTPCodecTypeAudio:
		return "audio"
	case RTPCodecTypeVideo:
		return "video"
	default:
		return ErrUnknownType.Error()
	}
}

// NewRTPCodecType creates a RTPCodecType from a string
func NewRTPCodecType(r string) RTPCodecType {
	switch {
	case strings.EqualFold(r, "audio"):
		return RTPCodecTypeAudio
	case strings.EqualFold(r, "video"):
		return RTPCodecTypeVideo
	default:
		return RTPCodecType(0)
	}
}

// RTPCodec represents a codec supported by the PeerConnection
type RTPCodec struct {
	RTPCodecCapability
	Type        RTPCodecType
	Name        string
	PayloadType uint8
	Payloader   rtp.Payloader
}

// NewRTPCodec is used to define a new codec
func NewRTPCodec(
	codecType RTPCodecType,
	name string,
	clockrate uint32,
	channels uint16,
	fmtp string,
	payloadType uint8,
	payloader rtp.Payloader,
) *RTPCodec {
	return &RTPCodec{
		RTPCodecCapability: RTPCodecCapability{
			MimeType:    codecType.String() + "/" + name,
			ClockRate:   clockrate,
			Channels:    channels,
			SDPFmtpLine: fmtp,
		},
		PayloadType: payloadType,
		Payloader:   payloader,
		Type:        codecType,
		Name:        name,
	}
}

// NewRTPCodecExt is used to define a new codec
func NewRTPCodecExt(
	codecType RTPCodecType,
	name string,
	clockrate uint32,
	channels uint16,
	fmtp string,
	payloadType uint8,
	rtcpfb []RTCPFeedback,
	payloader rtp.Payloader,
) *RTPCodec {
	return &RTPCodec{
		RTPCodecCapability: RTPCodecCapability{
			MimeType:     codecType.String() + "/" + name,
			ClockRate:    clockrate,
			Channels:     channels,
			SDPFmtpLine:  fmtp,
			RTCPFeedback: rtcpfb,
		},
		PayloadType: payloadType,
		Payloader:   payloader,
		Type:        codecType,
		Name:        name,
	}
}

// RTPCodecCapability provides information about codec capabilities.
type RTPCodecCapability struct {
	MimeType     string
	ClockRate    uint32
	Channels     uint16
	SDPFmtpLine  string
	RTCPFeedback []RTCPFeedback
}

// RTPHeaderExtensionCapability is used to define a RFC5285 RTP header extension supported by the codec.
type RTPHeaderExtensionCapability struct {
	URI string
}

// RTPCapabilities represents the capabilities of a transceiver
type RTPCapabilities struct {
	Codecs           []RTPCodecCapability
	HeaderExtensions []RTPHeaderExtensionCapability
}
<commit_msg>Document that some MediaEngines may be re-used<commit_after>// +build !js

package webrtc

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pion/rtp"
	"github.com/pion/rtp/codecs"
	"github.com/pion/sdp/v2"
)

// PayloadTypes for the default codecs
const (
	DefaultPayloadTypePCMU = 0
	DefaultPayloadTypePCMA = 8
	DefaultPayloadTypeG722 = 9
	DefaultPayloadTypeOpus = 111
	DefaultPayloadTypeVP8  = 96
	DefaultPayloadTypeVP9  = 98
	DefaultPayloadTypeH264 = 102

	mediaNameAudio = "audio"
	mediaNameVideo = "video"
)

// A MediaEngine defines the codecs supported by a PeerConnection.
// MediaEngines populated using RegisterCodec (and RegisterDefaultCodecs)
// may be set up once and reused, including concurrently,
// as long as no other codecs are added subsequently.
// MediaEngines populated using PopulateFromSDP should be used
// only for that session.
type MediaEngine struct {
	codecs []*RTPCodec
}

// RegisterCodec adds codec to m.
// RegisterCodec is not safe for concurrent use.
func (m *MediaEngine) RegisterCodec(codec *RTPCodec) uint8 {
	// TODO: dynamically generate a payload type in the range 96-127 if one wasn't provided.
	// See https://github.com/pion/webrtc/issues/43
	m.codecs = append(m.codecs, codec)
	return codec.PayloadType
}

// RegisterDefaultCodecs registers the default codecs supported by Pion WebRTC.
// RegisterDefaultCodecs is not safe for concurrent use.
func (m *MediaEngine) RegisterDefaultCodecs() {
	// Audio Codecs in descending order of preference
	m.RegisterCodec(NewRTPOpusCodec(DefaultPayloadTypeOpus, 48000))
	m.RegisterCodec(NewRTPPCMUCodec(DefaultPayloadTypePCMU, 8000))
	m.RegisterCodec(NewRTPPCMACodec(DefaultPayloadTypePCMA, 8000))
	m.RegisterCodec(NewRTPG722Codec(DefaultPayloadTypeG722, 8000))

	// Video Codecs in descending order of preference
	m.RegisterCodec(NewRTPVP8Codec(DefaultPayloadTypeVP8, 90000))
	m.RegisterCodec(NewRTPVP9Codec(DefaultPayloadTypeVP9, 90000))
	m.RegisterCodec(NewRTPH264Codec(DefaultPayloadTypeH264, 90000))
}

// PopulateFromSDP finds all codecs in sd and adds them to m, using the dynamic
// payload types and parameters from sd.
// PopulateFromSDP is intended for use when answering a request.
// The offerer sets the PayloadTypes for the connection.
// PopulateFromSDP allows an answerer to properly match the PayloadTypes from the offerer.
// A MediaEngine populated by PopulateFromSDP should be used only for a single session.
func (m *MediaEngine) PopulateFromSDP(sd SessionDescription) error {
	sdp := sdp.SessionDescription{}
	if err := sdp.Unmarshal([]byte(sd.SDP)); err != nil {
		return err
	}

	for _, md := range sdp.MediaDescriptions {
		if md.MediaName.Media != mediaNameAudio && md.MediaName.Media != mediaNameVideo {
			continue
		}

		for _, format := range md.MediaName.Formats {
			pt, err := strconv.Atoi(format)
			if err != nil {
				return fmt.Errorf("format parse error")
			}

			payloadType := uint8(pt)
			payloadCodec, err := sdp.GetCodecForPayloadType(payloadType)
			if err != nil {
				return fmt.Errorf("could not find codec for payload type %d", payloadType)
			}

			var codec *RTPCodec
			switch {
			case strings.EqualFold(payloadCodec.Name, PCMA):
				codec = NewRTPPCMACodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, PCMU):
				codec = NewRTPPCMUCodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, G722):
				codec = NewRTPG722Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, Opus):
				codec = NewRTPOpusCodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, VP8):
				codec = NewRTPVP8Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, VP9):
				codec = NewRTPVP9Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, H264):
				codec = NewRTPH264Codec(payloadType, payloadCodec.ClockRate)
			default:
				// ignoring other codecs
				continue
			}

			codec.SDPFmtpLine = payloadCodec.Fmtp
			m.RegisterCodec(codec)
		}
	}
	return nil
}

func (m *MediaEngine) getCodec(payloadType uint8) (*RTPCodec, error) {
	for _, codec := range m.codecs {
		if codec.PayloadType == payloadType {
			return codec, nil
		}
	}
	return nil, ErrCodecNotFound
}

func (m *MediaEngine) getCodecSDP(sdpCodec sdp.Codec) (*RTPCodec, error) {
	for _, codec := range m.codecs {
		if codec.Name == sdpCodec.Name &&
			codec.ClockRate == sdpCodec.ClockRate &&
			(sdpCodec.EncodingParameters == "" ||
				strconv.Itoa(int(codec.Channels)) == sdpCodec.EncodingParameters) &&
			codec.SDPFmtpLine == sdpCodec.Fmtp { // pion/webrtc#43
			return codec, nil
		}
	}
	return nil, ErrCodecNotFound
}

// GetCodecsByKind returns all codecs of kind kind that are supported by m.
// The returned codecs should not be modified.
func (m *MediaEngine) GetCodecsByKind(kind RTPCodecType) []*RTPCodec {
	var codecs []*RTPCodec
	for _, codec := range m.codecs {
		if codec.Type == kind {
			// TODO: clone the codec for safety?
			codecs = append(codecs, codec)
		}
	}
	return codecs
}

// Names for the default codecs supported by Pion WebRTC
const (
	PCMU = "PCMU"
	PCMA = "PCMA"
	G722 = "G722"
	Opus = "opus"
	VP8  = "VP8"
	VP9  = "VP9"
	H264 = "H264"
)

// NewRTPPCMUCodec is a helper to create a PCMU codec
func NewRTPPCMUCodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		PCMU,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G711Payloader{})
	return c
}

// NewRTPPCMACodec is a helper to create a PCMA codec
func NewRTPPCMACodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		PCMA,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G711Payloader{})
	return c
}

// NewRTPG722Codec is a helper to create a G722 codec
func NewRTPG722Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		G722,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G722Payloader{})
	return c
}

// NewRTPOpusCodec is a helper to create an Opus codec
func NewRTPOpusCodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		Opus,
		clockrate,
		2, //According to RFC7587, Opus RTP streams must have exactly 2 channels.
		"minptime=10;useinbandfec=1",
		payloadType,
		&codecs.OpusPayloader{})
	return c
}

// NewRTPVP8Codec is a helper to create an VP8 codec
func NewRTPVP8Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		VP8,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.VP8Payloader{})
	return c
}

// NewRTPVP8CodecExt is a helper to create an VP8 codec
func NewRTPVP8CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		VP8,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.VP8Payloader{})
	return c
}

// NewRTPVP9Codec is a helper to create an VP9 codec
func NewRTPVP9Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		VP9,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.VP9Payloader{})
	return c
}

// NewRTPH264Codec is a helper to create an H264 codec
func NewRTPH264Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		H264,
		clockrate,
		0,
		"level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
		payloadType,
		&codecs.H264Payloader{})
	return c
}

// NewRTPH264CodecExt is a helper to create an H264 codec
func NewRTPH264CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		H264,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.H264Payloader{})
	return c
}

// RTPCodecType determines the type of a codec
type RTPCodecType int

const (

	// RTPCodecTypeAudio indicates this is an audio codec
	RTPCodecTypeAudio RTPCodecType = iota + 1

	// RTPCodecTypeVideo indicates this is a video codec
	RTPCodecTypeVideo
)

func (t RTPCodecType) String() string {
	switch t {
	case RTPCodecTypeAudio:
		return "audio"
	case RTPCodecTypeVideo:
		return "video"
	default:
		return ErrUnknownType.Error()
	}
}

// NewRTPCodecType creates a RTPCodecType from a string
func NewRTPCodecType(r string) RTPCodecType {
	switch {
	case strings.EqualFold(r, "audio"):
		return RTPCodecTypeAudio
	case strings.EqualFold(r, "video"):
		return RTPCodecTypeVideo
	default:
		return RTPCodecType(0)
	}
}

// RTPCodec represents a codec supported by the PeerConnection
type RTPCodec struct {
	RTPCodecCapability
	Type        RTPCodecType
	Name        string
	PayloadType uint8
	Payloader   rtp.Payloader
}

// NewRTPCodec is used to define a new codec
func NewRTPCodec(
	codecType RTPCodecType,
	name string,
	clockrate uint32,
	channels uint16,
	fmtp string,
	payloadType uint8,
	payloader rtp.Payloader,
) *RTPCodec {
	return &RTPCodec{
		RTPCodecCapability: RTPCodecCapability{
			MimeType:    codecType.String() + "/" + name,
			ClockRate:   clockrate,
			Channels:    channels,
			SDPFmtpLine: fmtp,
		},
		PayloadType: payloadType,
		Payloader:   payloader,
		Type:        codecType,
		Name:        name,
	}
}

// NewRTPCodecExt is used to define a new codec
func NewRTPCodecExt(
	codecType RTPCodecType,
	name string,
	clockrate uint32,
	channels uint16,
	fmtp string,
	payloadType uint8,
	rtcpfb []RTCPFeedback,
	payloader rtp.Payloader,
) *RTPCodec {
	return &RTPCodec{
		RTPCodecCapability: RTPCodecCapability{
			MimeType:     codecType.String() + "/" + name,
			ClockRate:    clockrate,
			Channels:     channels,
			SDPFmtpLine:  fmtp,
			RTCPFeedback: rtcpfb,
		},
		PayloadType: payloadType,
		Payloader:   payloader,
		Type:        codecType,
		Name:        name,
	}
}

// RTPCodecCapability provides information about codec capabilities.
type RTPCodecCapability struct {
	MimeType     string
	ClockRate    uint32
	Channels     uint16
	SDPFmtpLine  string
	RTCPFeedback []RTCPFeedback
}

// RTPHeaderExtensionCapability is used to define a RFC5285 RTP header extension supported by the codec.
type RTPHeaderExtensionCapability struct {
	URI string
}

// RTPCapabilities represents the capabilities of a transceiver
type RTPCapabilities struct {
	Codecs           []RTPCodecCapability
	HeaderExtensions []RTPHeaderExtensionCapability
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/bgentry/heroku-go"
)

var cmdScale = &Command{
	Run:      runScale,
	Usage:    "scale <type>=[<qty>]:[<size>]...",
	NeedsApp: true,
	Category: "dyno",
	Short:    "change dyno quantities and sizes",
	Long: `
Scale changes the quantity of dynos (horizontal scale) and/or the
dyno size (vertical scale) for each process type. Note that
changing dyno size will restart all dynos of that type.

Example:

    $ hk scale web=2
    Scaled myapp to web=2:1X.

    $ hk scale web=2:1X worker=5:2X
    Scaled myapp to web=2:1X, worker=5:2X.

    $ hk scale web=PX worker=1X
    Scaled myapp to web=2:PX, worker=5:1X.
`,
}

// takes args of the form "web=1", "worker=3X", web=4:2X etc
func runScale(cmd *Command, args []string) {
	appname := mustApp()
	if len(args) == 0 {
		cmd.printUsage()
		os.Exit(2)
	}
	todo := make([]heroku.FormationBatchUpdateOpts, len(args))
	types := make(map[string]bool)
	for i, arg := range args {
		pstype, qty, size, err := parseScaleArg(arg)
		if err != nil {
			cmd.printUsage()
			os.Exit(2)
		}
		if _, exists := types[pstype]; exists {
			// can only specify each process type once
			cmd.printUsage()
			os.Exit(2)
		}
		types[pstype] = true

		opt := heroku.FormationBatchUpdateOpts{Process: pstype}
		if qty != -1 {
			opt.Quantity = &qty
		}
		if size != "" {
			opt.Size = &size
		}
		todo[i] = opt
	}

	formations, err := client.FormationBatchUpdate(appname, todo)
	must(err)

	sortedFormations := formationsByType(formations)
	sort.Sort(sortedFormations)
	results := make([]string, len(types))
	rindex := 0
	for _, f := range sortedFormations {
		if _, exists := types[f.Type]; exists {
			results[rindex] = f.Type + "=" + strconv.Itoa(f.Quantity) + ":" + f.Size + "X"
			rindex += 1
		}
	}
	log.Printf("Scaled %s to %s.", appname, strings.Join(results, ", "))
}

var errInvalidScaleArg = errors.New("invalid argument")

func parseScaleArg(arg string) (pstype string, qty int, size string, err error) {
	qty = -1
	iEquals := strings.IndexRune(arg, '=')
	if fields := strings.Fields(arg); len(fields) > 1 || iEquals == -1 {
		err = errInvalidScaleArg
		return
	}
	pstype = arg[:iEquals]

	rem := strings.ToUpper(arg[iEquals+1:])
	if len(rem) == 0 {
		err = errInvalidScaleArg
		return
	}

	if iColon := strings.IndexRune(rem, ':'); iColon == -1 {
		if iX := strings.IndexRune(rem, 'X'); iX == -1 {
			qty, err = strconv.Atoi(rem)
			if err != nil {
				return pstype, -1, "", errInvalidScaleArg
			}
		} else {
			size = rem
		}
	} else {
		if iColon > 0 {
			qty, err = strconv.Atoi(rem[:iColon])
			if err != nil {
				return pstype, -1, "", errInvalidScaleArg
			}
		}
		if len(rem) > iColon+1 {
			size = rem[iColon+1:]
		}
	}
	if err != nil || qty == -1 && size == "" {
		err = errInvalidScaleArg
	}
	return
}

type formationsByType []heroku.Formation

func (f formationsByType) Len() int           { return len(f) }
func (f formationsByType) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
func (f formationsByType) Less(i, j int) bool { return f[i].Type < f[j].Type }
<commit_msg>remove superfluous X from scale output<commit_after>package main

import (
	"errors"
	"log"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/bgentry/heroku-go"
)

var cmdScale = &Command{
	Run:      runScale,
	Usage:    "scale <type>=[<qty>]:[<size>]...",
	NeedsApp: true,
	Category: "dyno",
	Short:    "change dyno quantities and sizes",
	Long: `
Scale changes the quantity of dynos (horizontal scale) and/or the
dyno size (vertical scale) for each process type. Note that
changing dyno size will restart all dynos of that type.

Example:

    $ hk scale web=2
    Scaled myapp to web=2:1X.

    $ hk scale web=2:1X worker=5:2X
    Scaled myapp to web=2:1X, worker=5:2X.

    $ hk scale web=PX worker=1X
    Scaled myapp to web=2:PX, worker=5:1X.
`,
}

// takes args of the form "web=1", "worker=3X", web=4:2X etc
func runScale(cmd *Command, args []string) {
	appname := mustApp()
	if len(args) == 0 {
		cmd.printUsage()
		os.Exit(2)
	}
	todo := make([]heroku.FormationBatchUpdateOpts, len(args))
	types := make(map[string]bool)
	for i, arg := range args {
		pstype, qty, size, err := parseScaleArg(arg)
		if err != nil {
			cmd.printUsage()
			os.Exit(2)
		}
		if _, exists := types[pstype]; exists {
			// can only specify each process type once
			cmd.printUsage()
			os.Exit(2)
		}
		types[pstype] = true

		opt := heroku.FormationBatchUpdateOpts{Process: pstype}
		if qty != -1 {
			opt.Quantity = &qty
		}
		if size != "" {
			opt.Size = &size
		}
		todo[i] = opt
	}

	formations, err := client.FormationBatchUpdate(appname, todo)
	must(err)

	sortedFormations := formationsByType(formations)
	sort.Sort(sortedFormations)
	results := make([]string, len(types))
	rindex := 0
	for _, f := range sortedFormations {
		if _, exists := types[f.Type]; exists {
			results[rindex] = f.Type + "=" + strconv.Itoa(f.Quantity) + ":" + f.Size
			rindex += 1
		}
	}
	log.Printf("Scaled %s to %s.", appname, strings.Join(results, ", "))
}

var errInvalidScaleArg = errors.New("invalid argument")

func parseScaleArg(arg string) (pstype string, qty int, size string, err error) {
	qty = -1
	iEquals := strings.IndexRune(arg, '=')
	if fields := strings.Fields(arg); len(fields) > 1 || iEquals == -1 {
		err = errInvalidScaleArg
		return
	}
	pstype = arg[:iEquals]

	rem := strings.ToUpper(arg[iEquals+1:])
	if len(rem) == 0 {
		err = errInvalidScaleArg
		return
	}

	if iColon := strings.IndexRune(rem, ':'); iColon == -1 {
		if iX := strings.IndexRune(rem, 'X'); iX == -1 {
			qty, err = strconv.Atoi(rem)
			if err != nil {
				return pstype, -1, "", errInvalidScaleArg
			}
		} else {
			size = rem
		}
	} else {
		if iColon > 0 {
			qty, err = strconv.Atoi(rem[:iColon])
			if err != nil {
				return pstype, -1, "", errInvalidScaleArg
			}
		}
		if len(rem) > iColon+1 {
			size = rem[iColon+1:]
		}
	}
	if err != nil || qty == -1 && size == "" {
		err = errInvalidScaleArg
	}
	return
}

type formationsByType []heroku.Formation

func (f formationsByType) Len() int           { return len(f) }
func (f formationsByType) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
func (f formationsByType) Less(i, j int) bool { return f[i].Type < f[j].Type }
<|endoftext|>


<commit_before>package kite

import (
	"errors"
	"testing"
	"time"
)

func TestMethod_Latest(t *testing.T) {
	k := New("testkite", "0.0.1")
	k.Config.DisableAuthentication = true
	k.Config.Port = 9999

	k.MethodHandling = ReturnLatest

	k.PreHandleFunc(func(r *Request) (interface{}, error) { return nil, nil })
	k.PreHandleFunc(func(r *Request) (interface{}, error) { return "hello", nil })

	// the following shouldn't do anything because the previous error breaks the chain
	k.HandleFunc("foo", func(r *Request) (interface{}, error) {
		return "handle", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post1", nil })
	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post2", nil })

	go k.Run()
	defer k.Close()
	<-k.ServerReadyNotify()

	c := New("exp", "0.0.1").NewClient("http://127.0.0.1:9999/kite")
	if err := c.Dial(); err != nil {
		t.Fatal(err)
	}

	result, err := c.TellWithTimeout("foo", 4*time.Second)
	if err != nil {
		t.Fatal(err)
	}

	if result.MustString() != "post2" {
		t.Errorf("Latest repsonse should be post2, got %s", result.MustString())
	}

}

func TestMethod_First(t *testing.T) {
	k := New("testkite", "0.0.1")
	k.Config.DisableAuthentication = true
	k.Config.Port = 9999

	k.MethodHandling = ReturnFirst

	k.PreHandleFunc(func(r *Request) (interface{}, error) { return nil, nil })
	k.PreHandleFunc(func(r *Request) (interface{}, error) { return "hello", nil })

	// the following shouldn't do anything because the previous error breaks the chain
	k.HandleFunc("foo", func(r *Request) (interface{}, error) {
		return "handle", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post1", nil })
	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post2", nil })

	go k.Run()
	defer k.Close()
	<-k.ServerReadyNotify()

	c := New("exp", "0.0.1").NewClient("http://127.0.0.1:9999/kite")
	if err := c.Dial(); err != nil {
		t.Fatal(err)
	}

	result, err := c.TellWithTimeout("foo", 4*time.Second)
	if err != nil {
		t.Fatal(err)
	}

	if result.MustString() != "hello" {
		t.Errorf("Latest repsonse should be hello, got %s", result.MustString())
	}

}

func TestMethod_Error(t *testing.T) {
	k := New("testkite", "0.0.1")
	k.Config.DisableAuthentication = true
	k.Config.Port = 9999

	var testError = errors.New("an error")

	k.PreHandleFunc(func(r *Request) (interface{}, error) { return nil, testError })

	// the following shouldn't do anything because the previous error breaks the chain
	k.HandleFunc("foo", func(r *Request) (interface{}, error) {
		return "handle", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post1", nil })
	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post2", nil })

	go k.Run()
	defer k.Close()
	<-k.ServerReadyNotify()

	c := New("exp", "0.0.1").NewClient("http://127.0.0.1:9999/kite")
	if err := c.Dial(); err != nil {
		t.Fatal(err)
	}

	_, err := c.TellWithTimeout("foo", 4*time.Second)
	if err == nil {
		t.Fatal("PreHandle returns an error, however error is non-nil.")
	}

	if err.Error() != testError.Error() {
		t.Errorf("Error should be '%v', got '%v'", testError, err)
	}
}

func TestMethod_Base(t *testing.T) {
	k := New("testkite", "0.0.1")
	k.Config.DisableAuthentication = true
	k.Config.Port = 9999

	k.PreHandleFunc(func(r *Request) (interface{}, error) {
		r.Context.Set("pre1", "pre1")
		return nil, nil
	})

	k.PreHandleFunc(func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("pre1")
		if res != "pre1" {
			t.Errorf("Context response from previous pre handler should be pre1, got: %v", res)
		}

		r.Context.Set("pre2", "pre2")
		return nil, nil
	})

	k.HandleFunc("foo", func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("funcPre1")
		if res != "funcPre1" {
			t.Errorf("Context response from previous pre handler should be funcPre1, got: %v", res)
		}

		r.Context.Set("handle", "handle")
		return "main-response", nil
	}).PreHandleFunc(func(r *Request) (interface{}, error) {
		r.Context.Set("funcPre1", "funcPre1")
		return "funcPre1", nil
	}).PostHandleFunc(func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("handle")
		if res != "handle" {
			t.Errorf("Context response from previous pre handler should be handle, got: %v", res)
		}

		r.Context.Set("funcPost1", "funcPost1")
		return "funcPost1", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("funcPost1")
		if res != "funcPost1" {
			t.Errorf("Context response from previous pre handler should be funcPost1, got: %v", res)
		}

		r.Context.Set("post1", "post1")
		return "post1", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("post1")
		if res != "post1" {
			t.Errorf("Context response from previous pre handler should be post1, got: %v", res)
		}

		return "post2", nil
	})

	go k.Run()
	defer k.Close()
	<-k.ServerReadyNotify()

	c := New("exp", "0.0.1").NewClient("http://127.0.0.1:9999/kite")
	if err := c.Dial(); err != nil {
		t.Fatal(err)
	}

	result, err := c.TellWithTimeout("foo", 4*time.Second)
	if err != nil {
		t.Fatal(err)
	}

	if result.MustString() != "main-response" {
		t.Errorf("Latest repsonse should be main-response, got %s", result.MustString())
	}

}
<commit_msg>kite: ports should be different to avoid collision<commit_after>package kite

import (
	"errors"
	"testing"
	"time"
)

func TestMethod_Latest(t *testing.T) {
	k := New("testkite", "0.0.1")
	k.Config.DisableAuthentication = true
	k.Config.Port = 9997

	k.MethodHandling = ReturnLatest

	k.PreHandleFunc(func(r *Request) (interface{}, error) { return nil, nil })
	k.PreHandleFunc(func(r *Request) (interface{}, error) { return "hello", nil })

	// the following shouldn't do anything because the previous error breaks the chain
	k.HandleFunc("foo", func(r *Request) (interface{}, error) {
		return "handle", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post1", nil })
	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post2", nil })

	go k.Run()
	defer k.Close()
	<-k.ServerReadyNotify()

	c := New("exp", "0.0.1").NewClient("http://127.0.0.1:9997/kite")
	if err := c.Dial(); err != nil {
		t.Fatal(err)
	}

	result, err := c.TellWithTimeout("foo", 4*time.Second)
	if err != nil {
		t.Fatal(err)
	}

	if result.MustString() != "post2" {
		t.Errorf("Latest repsonse should be post2, got %s", result.MustString())
	}

}

func TestMethod_First(t *testing.T) {
	k := New("testkite", "0.0.1")
	k.SetLogLevel(DEBUG)
	k.Config.DisableAuthentication = true
	k.Config.Port = 9998

	k.MethodHandling = ReturnFirst

	k.PreHandleFunc(func(r *Request) (interface{}, error) { return nil, nil })
	k.PreHandleFunc(func(r *Request) (interface{}, error) { return "hello", nil })

	// the following shouldn't do anything because the previous error breaks the chain
	k.HandleFunc("foo", func(r *Request) (interface{}, error) {
		return "handle", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post1", nil })
	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post2", nil })

	go k.Run()
	defer k.Close()
	<-k.ServerReadyNotify()

	c := New("exp", "0.0.1").NewClient("http://127.0.0.1:9998/kite")
	if err := c.Dial(); err != nil {
		t.Fatal(err)
	}

	result, err := c.TellWithTimeout("foo", 4*time.Second)
	if err != nil {
		t.Fatal(err)
	}

	if result.MustString() != "hello" {
		t.Errorf("Latest repsonse should be hello, got %s", result.MustString())
	}

}

func TestMethod_Error(t *testing.T) {
	k := New("testkite", "0.0.1")
	k.Config.DisableAuthentication = true
	k.Config.Port = 9999

	var testError = errors.New("an error")

	k.PreHandleFunc(func(r *Request) (interface{}, error) { return nil, testError })

	// the following shouldn't do anything because the previous error breaks the chain
	k.HandleFunc("foo", func(r *Request) (interface{}, error) {
		return "handle", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post1", nil })
	k.PostHandleFunc(func(r *Request) (interface{}, error) { return "post2", nil })

	go k.Run()
	defer k.Close()
	<-k.ServerReadyNotify()

	c := New("exp", "0.0.1").NewClient("http://127.0.0.1:9999/kite")
	if err := c.Dial(); err != nil {
		t.Fatal(err)
	}

	_, err := c.TellWithTimeout("foo", 4*time.Second)
	if err == nil {
		t.Fatal("PreHandle returns an error, however error is non-nil.")
	}

	if err.Error() != testError.Error() {
		t.Errorf("Error should be '%v', got '%v'", testError, err)
	}
}

func TestMethod_Base(t *testing.T) {
	k := New("testkite", "0.0.1")
	k.Config.DisableAuthentication = true
	k.Config.Port = 10000

	k.PreHandleFunc(func(r *Request) (interface{}, error) {
		r.Context.Set("pre1", "pre1")
		return nil, nil
	})

	k.PreHandleFunc(func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("pre1")
		if res != "pre1" {
			t.Errorf("Context response from previous pre handler should be pre1, got: %v", res)
		}

		r.Context.Set("pre2", "pre2")
		return nil, nil
	})

	k.HandleFunc("foo", func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("funcPre1")
		if res != "funcPre1" {
			t.Errorf("Context response from previous pre handler should be funcPre1, got: %v", res)
		}

		r.Context.Set("handle", "handle")
		return "main-response", nil
	}).PreHandleFunc(func(r *Request) (interface{}, error) {
		r.Context.Set("funcPre1", "funcPre1")
		return "funcPre1", nil
	}).PostHandleFunc(func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("handle")
		if res != "handle" {
			t.Errorf("Context response from previous pre handler should be handle, got: %v", res)
		}

		r.Context.Set("funcPost1", "funcPost1")
		return "funcPost1", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("funcPost1")
		if res != "funcPost1" {
			t.Errorf("Context response from previous pre handler should be funcPost1, got: %v", res)
		}

		r.Context.Set("post1", "post1")
		return "post1", nil
	})

	k.PostHandleFunc(func(r *Request) (interface{}, error) {
		res, _ := r.Context.Get("post1")
		if res != "post1" {
			t.Errorf("Context response from previous pre handler should be post1, got: %v", res)
		}

		return "post2", nil
	})

	go k.Run()
	defer k.Close()
	<-k.ServerReadyNotify()

	c := New("exp", "0.0.1").NewClient("http://127.0.0.1:10000/kite")
	if err := c.Dial(); err != nil {
		t.Fatal(err)
	}

	result, err := c.TellWithTimeout("foo", 4*time.Second)
	if err != nil {
		t.Fatal(err)
	}

	if result.MustString() != "main-response" {
		t.Errorf("Latest repsonse should be main-response, got %s", result.MustString())
	}

}
<|endoftext|>


<commit_before>package main

import ()

// サポートするスコープと紐付くクレーム。
var knownScops = map[string]map[string]bool{
	// ID トークンの被発行権。
	"openid": {},
	// リフレッシュトークンの被発行権。
	//"offline_access": {},
	// 以下、クレーム集合の取得権。
	"profile": {
		"name":               true,
		"family_name":        true,
		"given_name":         true,
		"middle_name":        true,
		"nickname":           true,
		"preferred_username": true,
		"profile":            true,
		"picture":            true,
		"website":            true,
		"gender":             true,
		"birthdate":          true,
		"zoneinfo":           true,
		"locale":             true,
		"updated_at":         true,
	},
	"email": {
		"email":          true,
		"email_verified": true,
	},
	"address": {
		"address": true,
	},
	"phone": {
		"phone_number":          true,
		"phone_number_verified": true,
	},
}

// scope に対応するクレームを返す。
// 返り値は自由に書き換えて良い。
func scopesToClaims(scops map[string]bool) map[string]bool {
	clms := map[string]bool{}
	for scop, ok := range scops {
		if !ok {
			continue
		}
		for clm, ok := range knownScops[scop] {
			if !ok {
				continue
			}
			clms[clm] = true
		}
	}
	return clms
}
<commit_msg>知らないスコープを取り除く関数を追加<commit_after>package main

import ()

// サポートするスコープと紐付くクレーム。
var knownScops = map[string]map[string]bool{
	// ID トークンの被発行権。
	"openid": {},
	// リフレッシュトークンの被発行権。
	//"offline_access": {},
	// 以下、クレーム集合の取得権。
	"profile": {
		"name":               true,
		"family_name":        true,
		"given_name":         true,
		"middle_name":        true,
		"nickname":           true,
		"preferred_username": true,
		"profile":            true,
		"picture":            true,
		"website":            true,
		"gender":             true,
		"birthdate":          true,
		"zoneinfo":           true,
		"locale":             true,
		"updated_at":         true,
	},
	"email": {
		"email":          true,
		"email_verified": true,
	},
	"address": {
		"address": true,
	},
	"phone": {
		"phone_number":          true,
		"phone_number_verified": true,
	},
}

// 知らないスコープを除く。
// 返り値は scops。
func stripUnknownScopes(scops map[string]bool) map[string]bool {
	for scop := range scops {
		if knownScops[scop] == nil {
			log.Debug("Remove " + scop)
			delete(scops, scop)
		}
	}
	return scops
}

// スコープに対応するクレームを返す。
// 返り値は自由に書き換えて良い。
func scopesToClaims(scops map[string]bool) map[string]bool {
	clms := map[string]bool{}
	for scop, ok := range scops {
		if !ok {
			continue
		}
		for clm, ok := range knownScops[scop] {
			if !ok {
				continue
			}
			clms[clm] = true
		}
	}
	return clms
}
<|endoftext|>


<commit_before>package infrastructure

import (
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/lambda"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/goadapp/goad/version"
	"github.com/satori/go.uuid"
)

// Infrastructure manages the resource creation and updates necessary to use
// Goad.
type Infrastructure struct {
	config   *aws.Config
	queueURL string
	regions  []string
}

// New creates the required infrastructure to run the load tests in Lambda
// functions.
func New(regions []string, config *aws.Config) (*Infrastructure, error) {
	infra := &Infrastructure{config: config, regions: regions}
	if err := infra.setup(); err != nil {
		return nil, err
	}
	return infra, nil
}

// QueueURL returns the URL of the SQS queue to use for the load test session.
func (infra *Infrastructure) QueueURL() string {
	return infra.queueURL
}

// Clean removes any AWS resources that cannot be reused for a subsequent test.
func (infra *Infrastructure) Clean() {
	infra.removeSQSQueue()
}

func (infra *Infrastructure) setup() error {
	roleArn, err := infra.createIAMLambdaRole("goad-lambda-role")
	if err != nil {
		return err
	}
	zip, err := Asset("data/lambda.zip")
	if err != nil {
		return err
	}
	for _, region := range infra.regions {
		err = infra.createOrUpdateLambdaFunction(region, roleArn, zip)
		if err != nil {
			return err
		}
	}
	queueURL, err := infra.createSQSQueue()
	if err != nil {
		return err
	}
	infra.queueURL = queueURL
	return nil
}

func (infra *Infrastructure) createOrUpdateLambdaFunction(region, roleArn string, payload []byte) error {
	config := infra.config.WithRegion(region)
	svc := lambda.New(session.New(), config)

	exists, err := lambdaExists(svc)

	if err != nil {
		return err
	}

	if exists {
		aliasExists, err := lambdaAliasExists(svc)
		if err != nil || aliasExists {
			return err
		}
		return infra.updateLambdaFunction(svc, roleArn, payload)
	}

	return infra.createLambdaFunction(svc, roleArn, payload)
}

func (infra *Infrastructure) createLambdaFunction(svc *lambda.Lambda, roleArn string, payload []byte) error {
	function, err := svc.CreateFunction(&lambda.CreateFunctionInput{
		Code: &lambda.FunctionCode{
			ZipFile: payload,
		},
		FunctionName: aws.String("goad"),
		Handler:      aws.String("index.handler"),
		Role:         aws.String(roleArn),
		Runtime:      aws.String("nodejs"),
		MemorySize:   aws.Int64(1536),
		Publish:      aws.Bool(true),
		Timeout:      aws.Int64(300),
	})
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			// Calling this function too soon after creating the role might
			// fail, so we should retry after a little while.
			// TODO: limit the number of retries.
			if awsErr.Code() == "InvalidParameterValueException" {
				time.Sleep(time.Second)
				return infra.createLambdaFunction(svc, roleArn, payload)
			}
		}
		return err
	}
	return createLambdaAlias(svc, function.Version)
}

func (infra *Infrastructure) updateLambdaFunction(svc *lambda.Lambda, roleArn string, payload []byte) error {
	function, err := svc.UpdateFunctionCode(&lambda.UpdateFunctionCodeInput{
		ZipFile:      payload,
		FunctionName: aws.String("goad"),
		Publish:      aws.Bool(true),
	})
	if err != nil {
		return err
	}
	return createLambdaAlias(svc, function.Version)
}

func lambdaExists(svc *lambda.Lambda) (bool, error) {
	_, err := svc.GetFunction(&lambda.GetFunctionInput{
		FunctionName: aws.String("goad"),
	})

	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "ResourceNotFoundException" {
				return false, nil
			}
		}
		return false, err
	}

	return true, nil
}

func createLambdaAlias(svc *lambda.Lambda, functionVersion *string) error {
	_, err := svc.CreateAlias(&lambda.CreateAliasInput{
		FunctionName:    aws.String("goad"),
		FunctionVersion: functionVersion,
		Name:            aws.String(version.LambdaVersion()),
	})
	return err
}

func lambdaAliasExists(svc *lambda.Lambda) (bool, error) {
	_, err := svc.GetAlias(&lambda.GetAliasInput{
		FunctionName: aws.String("goad"),
		Name:         aws.String(version.LambdaVersion()),
	})

	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "ResourceNotFoundException" {
				return false, nil
			}
		}
		return false, err
	}

	return true, nil
}

func (infra *Infrastructure) createIAMLambdaRole(roleName string) (arn string, err error) {
	svc := iam.New(session.New(), infra.config)

	resp, err := svc.GetRole(&iam.GetRoleInput{
		RoleName: aws.String(roleName),
	})
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "NoSuchEntity" {
				res, err := svc.CreateRole(&iam.CreateRoleInput{
					AssumeRolePolicyDocument: aws.String(`{
        	          "Version": "2012-10-17",
        	          "Statement": {
        	            "Effect": "Allow",
        	            "Principal": {"Service": "lambda.amazonaws.com"},
        	            "Action": "sts:AssumeRole"
        	          }
            	    }`),
					RoleName: aws.String(roleName),
					Path:     aws.String("/"),
				})
				if err != nil {
					return "", err
				}
				if err := infra.createIAMLambdaRolePolicy(*res.Role.RoleName); err != nil {
					return "", err
				}
				return *res.Role.Arn, nil
			}
		}
		return "", err
	}

	return *resp.Role.Arn, nil
}

func (infra *Infrastructure) createIAMLambdaRolePolicy(roleName string) error {
	svc := iam.New(session.New(), infra.config)

	_, err := svc.PutRolePolicy(&iam.PutRolePolicyInput{
		PolicyDocument: aws.String(`{
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "sqs:SendMessage"
              ],
              "Effect": "Allow",
              "Resource": "arn:aws:sqs:*:*:goad-*"
		  	},
			{
              "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
              ],
              "Effect": "Allow",
              "Resource": "arn:aws:logs:*:*:*"
	        }
          ]
        }`),
		PolicyName: aws.String("goad-lambda-role-policy"),
		RoleName:   aws.String(roleName),
	})
	return err
}

func (infra *Infrastructure) createSQSQueue() (url string, err error) {
	svc := sqs.New(session.New(), infra.config)

	resp, err := svc.CreateQueue(&sqs.CreateQueueInput{
		QueueName: aws.String("goad-" + uuid.NewV4().String()),
	})

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

	return *resp.QueueUrl, nil
}

func (infra *Infrastructure) removeSQSQueue() {
	svc := sqs.New(session.New(), infra.config)

	svc.DeleteQueue(&sqs.DeleteQueueInput{
		QueueUrl: aws.String(infra.queueURL),
	})
}
<commit_msg>fixing Lambda to be updated on AWS<commit_after>package infrastructure

import (
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/lambda"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/goadapp/goad/version"
	"github.com/satori/go.uuid"
)

// Infrastructure manages the resource creation and updates necessary to use
// Goad.
type Infrastructure struct {
	config   *aws.Config
	queueURL string
	regions  []string
}

// New creates the required infrastructure to run the load tests in Lambda
// functions.
func New(regions []string, config *aws.Config) (*Infrastructure, error) {
	infra := &Infrastructure{config: config, regions: regions}
	if err := infra.setup(); err != nil {
		return nil, err
	}
	return infra, nil
}

// QueueURL returns the URL of the SQS queue to use for the load test session.
func (infra *Infrastructure) QueueURL() string {
	return infra.queueURL
}

// Clean removes any AWS resources that cannot be reused for a subsequent test.
func (infra *Infrastructure) Clean() {
	infra.removeSQSQueue()
}

func (infra *Infrastructure) setup() error {
	roleArn, err := infra.createIAMLambdaRole("goad-lambda-role")
	if err != nil {
		return err
	}
	zip, err := Asset("data/lambda.zip")
	if err != nil {
		return err
	}
	for _, region := range infra.regions {
		err = infra.createOrUpdateLambdaFunction(region, roleArn, zip)
		if err != nil {
			return err
		}
	}
	queueURL, err := infra.createSQSQueue()
	if err != nil {
		return err
	}
	infra.queueURL = queueURL
	return nil
}

func (infra *Infrastructure) createOrUpdateLambdaFunction(region, roleArn string, payload []byte) error {
	config := infra.config.WithRegion(region)
	svc := lambda.New(session.New(), config)

	exists, err := lambdaExists(svc)

	if err != nil {
		log.Fatal(err)
	}

	if exists {
		aliasExists, err := lambdaAliasExists(svc)
		if err != nil || aliasExists {
			return infra.updateLambdaFunction(svc, roleArn, payload)
		}
	}

	return infra.createLambdaFunction(svc, roleArn, payload)
}

func (infra *Infrastructure) createLambdaFunction(svc *lambda.Lambda, roleArn string, payload []byte) error {
	function, err := svc.CreateFunction(&lambda.CreateFunctionInput{
		Code: &lambda.FunctionCode{
			ZipFile: payload,
		},
		FunctionName: aws.String("goad"),
		Handler:      aws.String("index.handler"),
		Role:         aws.String(roleArn),
		Runtime:      aws.String("nodejs"),
		MemorySize:   aws.Int64(1536),
		Publish:      aws.Bool(true),
		Timeout:      aws.Int64(300),
	})
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			// Calling this function too soon after creating the role might
			// fail, so we should retry after a little while.
			// TODO: limit the number of retries.
			if awsErr.Code() == "InvalidParameterValueException" {
				time.Sleep(time.Second)
				return infra.createLambdaFunction(svc, roleArn, payload)
			}
		}
		return err
	}
	return createLambdaAlias(svc, function.Version)
}

func (infra *Infrastructure) updateLambdaFunction(svc *lambda.Lambda, roleArn string, payload []byte) error {
	function, err := svc.UpdateFunctionCode(&lambda.UpdateFunctionCodeInput{
		ZipFile:      payload,
		FunctionName: aws.String("goad"),
		Publish:      aws.Bool(true),
	})
	if err != nil {
		return err
	}
	return updateLambdaAlias(svc, function.Version)
}

func lambdaExists(svc *lambda.Lambda) (bool, error) {
	_, err := svc.GetFunction(&lambda.GetFunctionInput{
		FunctionName: aws.String("goad"),
	})

	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "ResourceNotFoundException" {
				return false, nil
			}
		}
		return false, err
	}

	return true, nil
}

func createLambdaAlias(svc *lambda.Lambda, functionVersion *string) error {
	_, err := svc.CreateAlias(&lambda.CreateAliasInput{
		FunctionName:    aws.String("goad"),
		FunctionVersion: functionVersion,
		Name:            aws.String(version.LambdaVersion()),
	})
	return err
}

func updateLambdaAlias(svc *lambda.Lambda, functionVersion *string) error {
	_, err := svc.UpdateAlias(&lambda.UpdateAliasInput{
		FunctionName:    aws.String("goad"),
		FunctionVersion: functionVersion,
		Name:            aws.String(version.LambdaVersion()),
	})
	return err
}

func lambdaAliasExists(svc *lambda.Lambda) (bool, error) {
	_, err := svc.GetAlias(&lambda.GetAliasInput{
		FunctionName: aws.String("goad"),
		Name:         aws.String(version.LambdaVersion()),
	})

	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "ResourceNotFoundException" {
				return false, nil
			}
		}
		return false, err
	}

	return true, nil
}

func (infra *Infrastructure) createIAMLambdaRole(roleName string) (arn string, err error) {
	svc := iam.New(session.New(), infra.config)

	resp, err := svc.GetRole(&iam.GetRoleInput{
		RoleName: aws.String(roleName),
	})
	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			if awsErr.Code() == "NoSuchEntity" {
				res, err := svc.CreateRole(&iam.CreateRoleInput{
					AssumeRolePolicyDocument: aws.String(`{
        	          "Version": "2012-10-17",
        	          "Statement": {
        	            "Effect": "Allow",
        	            "Principal": {"Service": "lambda.amazonaws.com"},
        	            "Action": "sts:AssumeRole"
        	          }
            	    }`),
					RoleName: aws.String(roleName),
					Path:     aws.String("/"),
				})
				if err != nil {
					return "", err
				}
				if err := infra.createIAMLambdaRolePolicy(*res.Role.RoleName); err != nil {
					return "", err
				}
				return *res.Role.Arn, nil
			}
		}
		return "", err
	}

	return *resp.Role.Arn, nil
}

func (infra *Infrastructure) createIAMLambdaRolePolicy(roleName string) error {
	svc := iam.New(session.New(), infra.config)

	_, err := svc.PutRolePolicy(&iam.PutRolePolicyInput{
		PolicyDocument: aws.String(`{
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "sqs:SendMessage"
              ],
              "Effect": "Allow",
              "Resource": "arn:aws:sqs:*:*:goad-*"
		  	},
			{
              "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
              ],
              "Effect": "Allow",
              "Resource": "arn:aws:logs:*:*:*"
	        }
          ]
        }`),
		PolicyName: aws.String("goad-lambda-role-policy"),
		RoleName:   aws.String(roleName),
	})
	return err
}

func (infra *Infrastructure) createSQSQueue() (url string, err error) {
	svc := sqs.New(session.New(), infra.config)

	resp, err := svc.CreateQueue(&sqs.CreateQueueInput{
		QueueName: aws.String("goad-" + uuid.NewV4().String()),
	})

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

	return *resp.QueueUrl, nil
}

func (infra *Infrastructure) removeSQSQueue() {
	svc := sqs.New(session.New(), infra.config)

	svc.DeleteQueue(&sqs.DeleteQueueInput{
		QueueUrl: aws.String(infra.queueURL),
	})
}
<|endoftext|>


<commit_before>package ploop

import "os/exec"
import "sync"

// #cgo CFLAGS: -D_GNU_SOURCE
// #cgo LDFLAGS: -lploop -lxml2 -lrt
// #include <ploop/libploop.h>
import "C"

// Possible SetVerboseLevel arguments
const (
	NoConsole  = C.PLOOP_LOG_NOCONSOLE
	NoStdout   = C.PLOOP_LOG_NOSTDOUT
	Timestamps = C.PLOOP_LOG_TIMESTAMPS
)

// SetVerboseLevel sets a level of verbosity when logging to stdout/stderr
func SetVerboseLevel(v int) {
	C.ploop_set_verbose_level(C.int(v))
}

// SetLogFile enables logging to a file and sets log file name
func SetLogFile(file string) error {
	cfile := C.CString(file)
	defer cfree(cfile)

	ret := C.ploop_set_log_file(cfile)

	return mkerr(ret)
}

// SetLogLevel sets a level of verbosity when logging to a file
func SetLogLevel(v int) {
	C.ploop_set_log_level(C.int(v))
}

// Ploop is a type containing DiskDescriptor.xml opened by the library
type Ploop struct {
	d *C.struct_ploop_disk_images_data
}

var once sync.Once

// load ploop modules
func load_kmod() {
	// try to load ploop modules
	modules := []string{"ploop", "pfmt_ploop1", "pfmt_raw", "pio_direct", "pio_nfs", "pio_kaio"}
	for _, m := range modules {
		exec.Command("modprobe", m).Run()
	}
}

// Open opens a ploop DiskDescriptor.xml, most ploop operations require it
func Open(file string) (Ploop, error) {
	var d Ploop

	once.Do(load_kmod)

	cfile := C.CString(file)
	defer cfree(cfile)

	ret := C.ploop_open_dd(&d.d, cfile)

	return d, mkerr(ret)
}

// Close closes a ploop disk descriptor when it is no longer needed
func (d Ploop) Close() {
	C.ploop_close_dd(d.d)
}

type ImageMode int

// Possible values for ImageMode
const (
	Expanded     ImageMode = C.PLOOP_EXPANDED_MODE
	Preallocated ImageMode = C.PLOOP_EXPANDED_PREALLOCATED_MODE
	Raw          ImageMode = C.PLOOP_RAW_MODE
)

// CreateParam is a set of parameters for a newly created ploop
type CreateParam struct {
	Size uint64 // image size, in kilobytes (FS size is about 10% smaller)
	Mode ImageMode
	File string // path to and a file name for base delta image
}

// Create creates a ploop image and its DiskDescriptor.xml
func Create(p *CreateParam) error {
	var a C.struct_ploop_create_param

	once.Do(load_kmod)

	// default image file name
	if p.File == "" {
		p.File = "root.hdd"
	}

	a.size = convertSize(p.Size)
	a.mode = C.int(p.Mode)
	a.image = C.CString(p.File)
	defer cfree(a.image)
	a.fstype = C.CString("ext4")
	defer cfree(a.fstype)

	ret := C.ploop_create_image(&a)
	return mkerr(ret)
}

// MountParam is a set of parameters to pass to Mount()
type MountParam struct {
	UUID     string // snapshot uuid (empty for top delta)
	Target   string // mount point (empty if no mount is needed)
	Flags    int    // bit mount flags such as MS_NOATIME
	Data     string // auxiliary mount options
	Readonly bool   // mount read-only
	Fsck     bool   // do fsck before mounting inner FS
	Quota    bool   // enable quota for inner FS
}

// Mount creates a ploop device and (optionally) mounts it
func (d Ploop) Mount(p *MountParam) (string, error) {
	var a C.struct_ploop_mount_param
	var device string

	if p.UUID != "" {
		a.guid = C.CString(p.UUID)
		defer cfree(a.guid)
	}
	if p.Target != "" {
		a.target = C.CString(p.Target)
		defer cfree(a.target)
	}

	// mount_data should not be NULL
	a.mount_data = C.CString(p.Data)
	defer cfree(a.mount_data)

	a.flags = C.int(p.Flags)
	a.ro = bool2cint(p.Readonly)
	a.fsck = bool2cint(p.Fsck)
	a.quota = bool2cint(p.Quota)

	ret := C.ploop_mount_image(d.d, &a)
	if ret == 0 {
		device = C.GoString(&a.device[0])
		// TODO? fsck_code = C.GoString(a.fsck_rc)
	}
	return device, mkerr(ret)
}

// Umount unmounts the ploop filesystem and dismantles the device
func (d Ploop) Umount() error {
	ret := C.ploop_umount_image(d.d)

	return mkerr(ret)
}

// Resize changes the ploop size. Online resize is recommended.
func (d Ploop) Resize(size uint64, offline bool) error {
	var p C.struct_ploop_resize_param

	p.size = convertSize(size)
	p.offline_resize = bool2cint(offline)

	ret := C.ploop_resize_image(d.d, &p)
	return mkerr(ret)
}

// Snapshot creates a ploop snapshot, returning its uuid
func (d Ploop) Snapshot() (string, error) {
	var p C.struct_ploop_snapshot_param
	var uuid, err = UUID()
	if err != nil {
		return "", err
	}
	p.guid = C.CString(uuid)
	defer cfree(p.guid)

	ret := C.ploop_create_snapshot(d.d, &p)
	if ret == 0 {
		uuid = C.GoString(p.guid)
	}

	return uuid, mkerr(ret)
}

// SwitchSnapshot switches to a specified snapshot,
// creates a new empty one on top of it, and makes it a top one
// (i.e. the one new data will be written to).
// Old top delta (i.e. data modified since the last snapshot) is lost.
func (d Ploop) SwitchSnapshot(uuid string) error {
	var p C.struct_ploop_snapshot_switch_param

	p.guid = C.CString(uuid)
	defer cfree(p.guid)

	ret := C.ploop_switch_snapshot_ex(d.d, &p)

	return mkerr(ret)
}

type SwitchFlag uint

// Possible values for SwitchSnapshotExtended flags argument
const (
	SkipDestroy SwitchFlag = C.PLOOP_SNAP_SKIP_TOPDELTA_DESTROY
	SkipCreate  SwitchFlag = C.PLOOP_SNAP_SKIP_TOPDELTA_CREATE
)

// SwitchSnapshot switches to a specified snapshot, creates a new
// empty one on top of it (unless SkipCreate flag is set), and
// makes it a top one (i.e. the one new data will be written to).
// Old top delta (i.e. data modified since the last snapshot) is lost,
// unless the SkipDestroy flag is set -- in this case the changes
// are saved into a new snapshot, and its uuid is returned.
func (d Ploop) SwitchSnapshotExtended(uuid string, flags SwitchFlag) (string, error) {
	var p C.struct_ploop_snapshot_switch_param
	old_uuid := ""

	p.guid = C.CString(uuid)
	defer cfree(p.guid)

	p.flags = C.int(flags)

	if flags&SkipDestroy != 0 {
		old_uuid, err := UUID()
		if err != nil {
			return "", err
		}
		p.guid_old = C.CString(old_uuid)
		defer cfree(p.guid_old)
	}

	ret := C.ploop_switch_snapshot_ex(d.d, &p)

	return old_uuid, mkerr(ret)
}

// DeleteSnapshot deletes a snapshot (merging it down if necessary)
func (d Ploop) DeleteSnapshot(uuid string) error {
	cuuid := C.CString(uuid)
	defer cfree(cuuid)

	ret := C.ploop_delete_snapshot(d.d, cuuid)

	return mkerr(ret)
}

type ReplaceFlag int

// Possible values for ReplaceParam.flags
const (
	// KeepName renames the new file to old file name after replace;
	// note that if this option is used the old file is removed.
	KeepName ReplaceFlag = C.PLOOP_REPLACE_KEEP_NAME
)

// ReplaceParam is a set of parameters to Replace()
type ReplaceParam struct {
	File string // new image file name
	// Image to be replaced is specified by either
	// uuid, current file name, or level,
	// in the above order of preference.
	UUID    string
	CurFile string
	Level   int
	Flags   ReplaceFlag
}

// Replace replaces a ploop image to a different (but identical) one
func (d Ploop) Replace(p *ReplaceParam) error {
	var a C.struct_ploop_replace_param

	a.file = C.CString(p.File)
	defer cfree(a.file)

	if p.UUID != "" {
		a.guid = C.CString(p.UUID)
		defer cfree(a.guid)
	} else if p.CurFile != "" {
		a.cur_file = C.CString(p.CurFile)
		defer cfree(a.cur_file)
	} else {
		a.level = C.int(p.Level)
	}

	a.flags = C.int(p.Flags)

	ret := C.ploop_replace_image(d.d, &a)

	return mkerr(ret)
}

// FSInfoData holds information about ploop inner file system
type FSInfoData struct {
	Blocksize   uint64
	Blocks      uint64
	Blocks_free uint64
	Inodes      uint64
	Inodes_free uint64
}

// FSInfo gets info of ploop's inner file system
func FSInfo(file string) (FSInfoData, error) {
	var cinfo C.struct_ploop_info
	var info FSInfoData
	cfile := C.CString(file)
	defer cfree(cfile)

	once.Do(load_kmod)

	ret := C.ploop_get_info_by_descr(cfile, &cinfo)
	if ret == 0 {
		info.Blocksize = uint64(cinfo.fs_bsize)
		info.Blocks = uint64(cinfo.fs_blocks)
		info.Blocks_free = uint64(cinfo.fs_bfree)
		info.Inodes = uint64(cinfo.fs_inodes)
		info.Inodes_free = uint64(cinfo.fs_ifree)
	}

	return info, mkerr(ret)
}

// ImageInfoData holds information about ploop image
type ImageInfoData struct {
	Blocks    uint64
	Blocksize uint32
	Version   int
}

// ImageInfo gets information about a ploop image
func (d Ploop) ImageInfo() (ImageInfoData, error) {
	var cinfo C.struct_ploop_spec
	var info ImageInfoData

	ret := C.ploop_get_spec(d.d, &cinfo)
	if ret == 0 {
		info.Blocks = uint64(cinfo.size)
		info.Blocksize = uint32(cinfo.blocksize)
		info.Version = int(cinfo.fmt_version)
	}

	return info, mkerr(ret)
}

// UUID generates a ploop UUID
func UUID() (string, error) {
	var cuuid [39]C.char

	ret := C.ploop_uuid_generate(&cuuid[0], 39)
	if ret != 0 {
		return "", mkerr(ret)
	}

	uuid := C.GoString(&cuuid[0])
	return uuid, nil
}
<commit_msg>SwitchSnapshot, SwitchSnapshotExtended: fix doc<commit_after>package ploop

import "os/exec"
import "sync"

// #cgo CFLAGS: -D_GNU_SOURCE
// #cgo LDFLAGS: -lploop -lxml2 -lrt
// #include <ploop/libploop.h>
import "C"

// Possible SetVerboseLevel arguments
const (
	NoConsole  = C.PLOOP_LOG_NOCONSOLE
	NoStdout   = C.PLOOP_LOG_NOSTDOUT
	Timestamps = C.PLOOP_LOG_TIMESTAMPS
)

// SetVerboseLevel sets a level of verbosity when logging to stdout/stderr
func SetVerboseLevel(v int) {
	C.ploop_set_verbose_level(C.int(v))
}

// SetLogFile enables logging to a file and sets log file name
func SetLogFile(file string) error {
	cfile := C.CString(file)
	defer cfree(cfile)

	ret := C.ploop_set_log_file(cfile)

	return mkerr(ret)
}

// SetLogLevel sets a level of verbosity when logging to a file
func SetLogLevel(v int) {
	C.ploop_set_log_level(C.int(v))
}

// Ploop is a type containing DiskDescriptor.xml opened by the library
type Ploop struct {
	d *C.struct_ploop_disk_images_data
}

var once sync.Once

// load ploop modules
func load_kmod() {
	// try to load ploop modules
	modules := []string{"ploop", "pfmt_ploop1", "pfmt_raw", "pio_direct", "pio_nfs", "pio_kaio"}
	for _, m := range modules {
		exec.Command("modprobe", m).Run()
	}
}

// Open opens a ploop DiskDescriptor.xml, most ploop operations require it
func Open(file string) (Ploop, error) {
	var d Ploop

	once.Do(load_kmod)

	cfile := C.CString(file)
	defer cfree(cfile)

	ret := C.ploop_open_dd(&d.d, cfile)

	return d, mkerr(ret)
}

// Close closes a ploop disk descriptor when it is no longer needed
func (d Ploop) Close() {
	C.ploop_close_dd(d.d)
}

type ImageMode int

// Possible values for ImageMode
const (
	Expanded     ImageMode = C.PLOOP_EXPANDED_MODE
	Preallocated ImageMode = C.PLOOP_EXPANDED_PREALLOCATED_MODE
	Raw          ImageMode = C.PLOOP_RAW_MODE
)

// CreateParam is a set of parameters for a newly created ploop
type CreateParam struct {
	Size uint64 // image size, in kilobytes (FS size is about 10% smaller)
	Mode ImageMode
	File string // path to and a file name for base delta image
}

// Create creates a ploop image and its DiskDescriptor.xml
func Create(p *CreateParam) error {
	var a C.struct_ploop_create_param

	once.Do(load_kmod)

	// default image file name
	if p.File == "" {
		p.File = "root.hdd"
	}

	a.size = convertSize(p.Size)
	a.mode = C.int(p.Mode)
	a.image = C.CString(p.File)
	defer cfree(a.image)
	a.fstype = C.CString("ext4")
	defer cfree(a.fstype)

	ret := C.ploop_create_image(&a)
	return mkerr(ret)
}

// MountParam is a set of parameters to pass to Mount()
type MountParam struct {
	UUID     string // snapshot uuid (empty for top delta)
	Target   string // mount point (empty if no mount is needed)
	Flags    int    // bit mount flags such as MS_NOATIME
	Data     string // auxiliary mount options
	Readonly bool   // mount read-only
	Fsck     bool   // do fsck before mounting inner FS
	Quota    bool   // enable quota for inner FS
}

// Mount creates a ploop device and (optionally) mounts it
func (d Ploop) Mount(p *MountParam) (string, error) {
	var a C.struct_ploop_mount_param
	var device string

	if p.UUID != "" {
		a.guid = C.CString(p.UUID)
		defer cfree(a.guid)
	}
	if p.Target != "" {
		a.target = C.CString(p.Target)
		defer cfree(a.target)
	}

	// mount_data should not be NULL
	a.mount_data = C.CString(p.Data)
	defer cfree(a.mount_data)

	a.flags = C.int(p.Flags)
	a.ro = bool2cint(p.Readonly)
	a.fsck = bool2cint(p.Fsck)
	a.quota = bool2cint(p.Quota)

	ret := C.ploop_mount_image(d.d, &a)
	if ret == 0 {
		device = C.GoString(&a.device[0])
		// TODO? fsck_code = C.GoString(a.fsck_rc)
	}
	return device, mkerr(ret)
}

// Umount unmounts the ploop filesystem and dismantles the device
func (d Ploop) Umount() error {
	ret := C.ploop_umount_image(d.d)

	return mkerr(ret)
}

// Resize changes the ploop size. Online resize is recommended.
func (d Ploop) Resize(size uint64, offline bool) error {
	var p C.struct_ploop_resize_param

	p.size = convertSize(size)
	p.offline_resize = bool2cint(offline)

	ret := C.ploop_resize_image(d.d, &p)
	return mkerr(ret)
}

// Snapshot creates a ploop snapshot, returning its uuid
func (d Ploop) Snapshot() (string, error) {
	var p C.struct_ploop_snapshot_param
	var uuid, err = UUID()
	if err != nil {
		return "", err
	}
	p.guid = C.CString(uuid)
	defer cfree(p.guid)

	ret := C.ploop_create_snapshot(d.d, &p)
	if ret == 0 {
		uuid = C.GoString(p.guid)
	}

	return uuid, mkerr(ret)
}

// SwitchSnapshot switches to a specified snapshot,
// creates a new empty delta on top of it, and makes it a top one
// (i.e. the one new data will be written to).
// Old top delta (i.e. data modified since the last snapshot) is lost.
func (d Ploop) SwitchSnapshot(uuid string) error {
	var p C.struct_ploop_snapshot_switch_param

	p.guid = C.CString(uuid)
	defer cfree(p.guid)

	ret := C.ploop_switch_snapshot_ex(d.d, &p)

	return mkerr(ret)
}

// Possible values for SwitchSnapshotExtended flags argument
type SwitchFlag uint

const (
	// SkipDestroy, if set, modifies the behavior of
	// SwitchSnapshotExtended to not delete the old top delta, but
	// make it a snapshot and return its uuid. Without this flag,
	// old top delta (i.e. data modified since the last snapshot)
	// is lost.
	SkipDestroy SwitchFlag = C.PLOOP_SNAP_SKIP_TOPDELTA_DESTROY
	// SkipCreate flag, if set, modifies the behavior of
	// SwitchSnapshotExtended to not create a new top delta,
	// but rather transform the specified snapshot itself to be
	// the new top delta), so all new changes will be written
	// right to it. Snapshot UUID is lost in this case.
	SkipCreate SwitchFlag = C.PLOOP_SNAP_SKIP_TOPDELTA_CREATE
)

// SwitchSnapshotExtended is same as SwitchSnapshot but with additional
// flags modifying its behavior. Please see individual flags description.
// Returns uuid of what was the old top delta if SkipDestroy flag is set.
func (d Ploop) SwitchSnapshotExtended(uuid string, flags SwitchFlag) (string, error) {
	var p C.struct_ploop_snapshot_switch_param
	old_uuid := ""

	p.guid = C.CString(uuid)
	defer cfree(p.guid)

	p.flags = C.int(flags)

	if flags&SkipDestroy != 0 {
		old_uuid, err := UUID()
		if err != nil {
			return "", err
		}
		p.guid_old = C.CString(old_uuid)
		defer cfree(p.guid_old)
	}

	ret := C.ploop_switch_snapshot_ex(d.d, &p)

	return old_uuid, mkerr(ret)
}

// DeleteSnapshot deletes a snapshot (merging it down if necessary)
func (d Ploop) DeleteSnapshot(uuid string) error {
	cuuid := C.CString(uuid)
	defer cfree(cuuid)

	ret := C.ploop_delete_snapshot(d.d, cuuid)

	return mkerr(ret)
}

type ReplaceFlag int

// Possible values for ReplaceParam.flags
const (
	// KeepName renames the new file to old file name after replace;
	// note that if this option is used the old file is removed.
	KeepName ReplaceFlag = C.PLOOP_REPLACE_KEEP_NAME
)

// ReplaceParam is a set of parameters to Replace()
type ReplaceParam struct {
	File string // new image file name
	// Image to be replaced is specified by either
	// uuid, current file name, or level,
	// in the above order of preference.
	UUID    string
	CurFile string
	Level   int
	Flags   ReplaceFlag
}

// Replace replaces a ploop image to a different (but identical) one
func (d Ploop) Replace(p *ReplaceParam) error {
	var a C.struct_ploop_replace_param

	a.file = C.CString(p.File)
	defer cfree(a.file)

	if p.UUID != "" {
		a.guid = C.CString(p.UUID)
		defer cfree(a.guid)
	} else if p.CurFile != "" {
		a.cur_file = C.CString(p.CurFile)
		defer cfree(a.cur_file)
	} else {
		a.level = C.int(p.Level)
	}

	a.flags = C.int(p.Flags)

	ret := C.ploop_replace_image(d.d, &a)

	return mkerr(ret)
}

// FSInfoData holds information about ploop inner file system
type FSInfoData struct {
	Blocksize   uint64
	Blocks      uint64
	Blocks_free uint64
	Inodes      uint64
	Inodes_free uint64
}

// FSInfo gets info of ploop's inner file system
func FSInfo(file string) (FSInfoData, error) {
	var cinfo C.struct_ploop_info
	var info FSInfoData
	cfile := C.CString(file)
	defer cfree(cfile)

	once.Do(load_kmod)

	ret := C.ploop_get_info_by_descr(cfile, &cinfo)
	if ret == 0 {
		info.Blocksize = uint64(cinfo.fs_bsize)
		info.Blocks = uint64(cinfo.fs_blocks)
		info.Blocks_free = uint64(cinfo.fs_bfree)
		info.Inodes = uint64(cinfo.fs_inodes)
		info.Inodes_free = uint64(cinfo.fs_ifree)
	}

	return info, mkerr(ret)
}

// ImageInfoData holds information about ploop image
type ImageInfoData struct {
	Blocks    uint64
	Blocksize uint32
	Version   int
}

// ImageInfo gets information about a ploop image
func (d Ploop) ImageInfo() (ImageInfoData, error) {
	var cinfo C.struct_ploop_spec
	var info ImageInfoData

	ret := C.ploop_get_spec(d.d, &cinfo)
	if ret == 0 {
		info.Blocks = uint64(cinfo.size)
		info.Blocksize = uint32(cinfo.blocksize)
		info.Version = int(cinfo.fmt_version)
	}

	return info, mkerr(ret)
}

// UUID generates a ploop UUID
func UUID() (string, error) {
	var cuuid [39]C.char

	ret := C.ploop_uuid_generate(&cuuid[0], 39)
	if ret != 0 {
		return "", mkerr(ret)
	}

	uuid := C.GoString(&cuuid[0])
	return uuid, nil
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "net/http"
  "os"
  "io/ioutil"
)

func main(){
  var url string
  fmt.Println(">> url: (Make sure to use http://)")
  fmt.Scanf("%s", &url)
  if url == "" {
    fmt.Println("Please type in an url")
    os.Exit(1)
  }
  fmt.Println("Fetching url...")
  if err = !nil {
    fmt.Println("Something went wrong...")
    os.Exit(1)
  }
  data, err := http.Get(url)
  if err != nil{
    os.Exit(1)
  }else{
    defer data.Body.Close()
    contents, err := ioutil.ReadAll(data.Body)
    if err != nil{
      fmt.Println("%s\n", err)
    }
    fmt.Println("%s\n", string(contents))
  }
}
<commit_msg>Remove error action<commit_after>package main

import (
  "fmt"
  "net/http"
  "os"
  "io/ioutil"
)

func main(){
  var url string
  fmt.Println(">> url: (Make sure to use http://)")
  fmt.Scanf("%s", &url)
  if url == "" {
    fmt.Println("Please type in an url")
    os.Exit(1)
  }
  /* fmt.Println("Fetching url...")
  if err = !nil {
    fmt.Println("Something went wrong...")
    os.Exit(1)
  } */
  data, err := http.Get(url)
  if err != nil{
    os.Exit(1)
  }else{
    defer data.Body.Close()
    contents, err := ioutil.ReadAll(data.Body)
    if err != nil{
      fmt.Println("%s\n", err)
    }
    fmt.Println("%s\n", string(contents))
  }
}
<|endoftext|>


<commit_before>// (c) Copyright IBM Corp. 2022

//go:build go1.13
// +build go1.13

package instapgx

import (
	"context"
	"fmt"
	"sync"

	instana "github.com/instana/go-sensor"
	"github.com/jackc/pgconn"
	"github.com/jackc/pgx/v4"
)

var detailedBatchMode = false
var detailedBatchModeMaxEntries = 10

// EnableDetailedBatchMode allows reporting up to detailedBatchModeMaxEntries sql when executing sql in batches.
func EnableDetailedBatchMode() {
	detailedBatchMode = true
}

// Conn wraps *pgx.Conn and adds tracing to it.
type Conn struct {
	*pgx.Conn
	sensor *instana.Sensor
	config *pgx.ConnConfig
}

// Prepare wraps (*pgx.Conn).Prepare method and adds tracing to it.
func (c *Conn) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error) {
	childCtx, span := contextWithChildSpan(ctx, fmt.Sprintf("PREPARE %s AS %s", name, sql), c.config, c.sensor)
	defer span.Finish()

	sd, err := c.Conn.Prepare(childCtx, name, sql)
	if err != nil {
		recordAnError(span, err)
	}

	return sd, err
}

// Begin wraps (*pgx.Conn).Begin method and adds tracing to it.
func (c *Conn) Begin(ctx context.Context) (pgx.Tx, error) {
	childCtx, span := contextWithChildSpan(ctx, "BEGIN", c.config, c.sensor)
	defer span.Finish()

	t, err := c.Conn.Begin(childCtx)
	if err != nil {
		recordAnError(span, err)
	}

	return &instaTx{
		Tx:     t,
		sensor: c.sensor,
		config: c.config,
	}, err
}

// BeginTx wraps (*pgx.Conn).BeginTx method and adds tracing to it.
func (c *Conn) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error) {
	childCtx, span := contextWithChildSpan(ctx, fmt.Sprintf("BEGIN %s %s %s", txOptions.IsoLevel, txOptions.AccessMode, txOptions.DeferrableMode), c.config, c.sensor)
	defer span.Finish()

	t, err := c.Conn.BeginTx(childCtx, txOptions)
	if err != nil {
		recordAnError(span, err)
	}

	return &instaTx{
		Tx:     t,
		sensor: c.sensor,
		config: c.config,
	}, err
}

// BeginFunc wraps (*pgx.Conn).BeginFunc method and adds tracing to it.
func (c *Conn) BeginFunc(ctx context.Context, f func(pgx.Tx) error) error {
	return c.BeginTxFunc(ctx, pgx.TxOptions{}, f)
}

// BeginTxFunc wraps (*pgx.Conn).BeginTxFunc method and adds tracing to it.
func (c *Conn) BeginTxFunc(ctx context.Context, txOptions pgx.TxOptions, f func(pgx.Tx) error) error {
	childCtx, span := contextWithChildSpan(ctx, fmt.Sprintf("BEGIN %s %s %s", txOptions.IsoLevel, txOptions.DeferrableMode, txOptions.AccessMode), c.config, c.sensor)

	wf := func(t pgx.Tx) error {
		fErr := f(&instaTx{
			Tx:          t,
			sensor:      c.sensor,
			config:      c.config,
			ctxWithSpan: childCtx,
		})

		if fErr != nil {
			_, span := contextWithChildSpan(childCtx, "ROLLBACK", c.config, c.sensor)
			span.Finish()
		} else {
			_, span := contextWithChildSpan(childCtx, "COMMIT", c.config, c.sensor)
			span.Finish()
		}

		return fErr
	}

	span.Finish()
	err := c.Conn.BeginTxFunc(childCtx, txOptions, wf)
	if err != nil {
		recordAnError(span, err)
	}

	return err
}

// CopyFrom wraps (*pgx.Conn).CopyFrom method and adds tracing to it. It doesn't provide details of the call.
func (c *Conn) CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) {
	childCtx, span := contextWithChildSpan(ctx, "PGCOPY", c.config, c.sensor)
	defer span.Finish()

	n, err := c.Conn.CopyFrom(childCtx, tableName, columnNames, rowSrc)
	if err != nil {
		recordAnError(span, err)
	}

	return n, err
}

// Ping wraps (*pgx.Conn).Ping method and adds tracing to it.
func (c *Conn) Ping(ctx context.Context) error {
	childCtx, span := contextWithChildSpan(ctx, ";", c.config, c.sensor)
	defer span.Finish()

	err := c.Conn.Ping(childCtx)
	if err != nil {
		recordAnError(span, err)
	}

	return err
}

// Exec wraps (*pgx.Conn).Exec method and adds tracing to it.
func (c *Conn) Exec(ctx context.Context, sql string, arguments ...interface{}) (pgconn.CommandTag, error) {
	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)
	defer span.Finish()

	tags, err := c.Conn.Exec(childCtx, sql, arguments...)
	if err != nil {
		recordAnError(span, err)
	}

	return tags, err
}

// Query wraps (*pgx.Conn).Query method and adds tracing to it.
func (c *Conn) Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error) {
	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)

	defer span.Finish()

	rows, err := c.Conn.Query(childCtx, sql, args...)
	if err != nil {
		recordAnError(span, err)
	}

	return rows, err
}

// QueryRow wraps (*pgx.Conn).QueryRow method and adds tracing to it.
// It requires to calling Scan method on the returned row to finish a span.
func (c *Conn) QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row {
	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)

	r := c.Conn.QueryRow(childCtx, sql, args...)
	return &row{
		Row:  r,
		span: span,
		m:    &sync.Mutex{},
	}
}

// QueryFunc wraps (*pgx.Conn).QueryFunc method and adds tracing to it.
func (c *Conn) QueryFunc(ctx context.Context, sql string, args []interface{}, scans []interface{}, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) {
	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)
	defer span.Finish()

	tags, err := c.Conn.QueryFunc(childCtx, sql, args, scans, f)
	if err != nil {
		recordAnError(span, err)
	}

	return tags, err
}

// SendBatch wraps (*pgx.Conn).SendBatch method and adds tracing to it. Call the EnableDetailedBatchMode(), to have
// sql statements in the span. Amount of the sql that might be reported are limited by detailedBatchModeMaxEntries var.
func (c *Conn) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults {
	sql := "-- SEND BATCH"
	if detailedBatchMode {
		sql = appendBatchDetails(b, sql)
	}

	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)
	defer span.Finish()

	br := c.Conn.SendBatch(childCtx, b)

	return &batchResults{
		br,
		childCtx,
		c.sensor,
		c.config,
	}
}
<commit_msg>update godoc<commit_after>// (c) Copyright IBM Corp. 2022

//go:build go1.13
// +build go1.13

package instapgx

import (
	"context"
	"fmt"
	"sync"

	instana "github.com/instana/go-sensor"
	"github.com/jackc/pgconn"
	"github.com/jackc/pgx/v4"
)

var detailedBatchMode = false
var detailedBatchModeMaxEntries = 10

// EnableDetailedBatchMode allows reporting detailed information about sql statements when executing sql in batches.
func EnableDetailedBatchMode() {
	detailedBatchMode = true
}

// Conn wraps *pgx.Conn and adds tracing to it.
type Conn struct {
	*pgx.Conn
	sensor *instana.Sensor
	config *pgx.ConnConfig
}

// Prepare wraps (*pgx.Conn).Prepare method and adds tracing to it.
func (c *Conn) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error) {
	childCtx, span := contextWithChildSpan(ctx, fmt.Sprintf("PREPARE %s AS %s", name, sql), c.config, c.sensor)
	defer span.Finish()

	sd, err := c.Conn.Prepare(childCtx, name, sql)
	if err != nil {
		recordAnError(span, err)
	}

	return sd, err
}

// Begin wraps (*pgx.Conn).Begin method and adds tracing to it.
func (c *Conn) Begin(ctx context.Context) (pgx.Tx, error) {
	childCtx, span := contextWithChildSpan(ctx, "BEGIN", c.config, c.sensor)
	defer span.Finish()

	t, err := c.Conn.Begin(childCtx)
	if err != nil {
		recordAnError(span, err)
	}

	return &instaTx{
		Tx:     t,
		sensor: c.sensor,
		config: c.config,
	}, err
}

// BeginTx wraps (*pgx.Conn).BeginTx method and adds tracing to it.
func (c *Conn) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error) {
	childCtx, span := contextWithChildSpan(ctx, fmt.Sprintf("BEGIN %s %s %s", txOptions.IsoLevel, txOptions.AccessMode, txOptions.DeferrableMode), c.config, c.sensor)
	defer span.Finish()

	t, err := c.Conn.BeginTx(childCtx, txOptions)
	if err != nil {
		recordAnError(span, err)
	}

	return &instaTx{
		Tx:     t,
		sensor: c.sensor,
		config: c.config,
	}, err
}

// BeginFunc wraps (*pgx.Conn).BeginFunc method and adds tracing to it.
func (c *Conn) BeginFunc(ctx context.Context, f func(pgx.Tx) error) error {
	return c.BeginTxFunc(ctx, pgx.TxOptions{}, f)
}

// BeginTxFunc wraps (*pgx.Conn).BeginTxFunc method and adds tracing to it.
func (c *Conn) BeginTxFunc(ctx context.Context, txOptions pgx.TxOptions, f func(pgx.Tx) error) error {
	childCtx, span := contextWithChildSpan(ctx, fmt.Sprintf("BEGIN %s %s %s", txOptions.IsoLevel, txOptions.DeferrableMode, txOptions.AccessMode), c.config, c.sensor)

	wf := func(t pgx.Tx) error {
		fErr := f(&instaTx{
			Tx:          t,
			sensor:      c.sensor,
			config:      c.config,
			ctxWithSpan: childCtx,
		})

		if fErr != nil {
			_, span := contextWithChildSpan(childCtx, "ROLLBACK", c.config, c.sensor)
			span.Finish()
		} else {
			_, span := contextWithChildSpan(childCtx, "COMMIT", c.config, c.sensor)
			span.Finish()
		}

		return fErr
	}

	span.Finish()
	err := c.Conn.BeginTxFunc(childCtx, txOptions, wf)
	if err != nil {
		recordAnError(span, err)
	}

	return err
}

// CopyFrom wraps (*pgx.Conn).CopyFrom method and adds tracing to it. It doesn't provide details of the call.
func (c *Conn) CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) {
	childCtx, span := contextWithChildSpan(ctx, "PGCOPY", c.config, c.sensor)
	defer span.Finish()

	n, err := c.Conn.CopyFrom(childCtx, tableName, columnNames, rowSrc)
	if err != nil {
		recordAnError(span, err)
	}

	return n, err
}

// Ping wraps (*pgx.Conn).Ping method and adds tracing to it.
func (c *Conn) Ping(ctx context.Context) error {
	childCtx, span := contextWithChildSpan(ctx, ";", c.config, c.sensor)
	defer span.Finish()

	err := c.Conn.Ping(childCtx)
	if err != nil {
		recordAnError(span, err)
	}

	return err
}

// Exec wraps (*pgx.Conn).Exec method and adds tracing to it.
func (c *Conn) Exec(ctx context.Context, sql string, arguments ...interface{}) (pgconn.CommandTag, error) {
	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)
	defer span.Finish()

	tags, err := c.Conn.Exec(childCtx, sql, arguments...)
	if err != nil {
		recordAnError(span, err)
	}

	return tags, err
}

// Query wraps (*pgx.Conn).Query method and adds tracing to it.
func (c *Conn) Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error) {
	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)

	defer span.Finish()

	rows, err := c.Conn.Query(childCtx, sql, args...)
	if err != nil {
		recordAnError(span, err)
	}

	return rows, err
}

// QueryRow wraps (*pgx.Conn).QueryRow method and adds tracing to it.
// It requires to calling Scan method on the returned row to finish a span.
func (c *Conn) QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row {
	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)

	r := c.Conn.QueryRow(childCtx, sql, args...)
	return &row{
		Row:  r,
		span: span,
		m:    &sync.Mutex{},
	}
}

// QueryFunc wraps (*pgx.Conn).QueryFunc method and adds tracing to it.
func (c *Conn) QueryFunc(ctx context.Context, sql string, args []interface{}, scans []interface{}, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) {
	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)
	defer span.Finish()

	tags, err := c.Conn.QueryFunc(childCtx, sql, args, scans, f)
	if err != nil {
		recordAnError(span, err)
	}

	return tags, err
}

// SendBatch wraps (*pgx.Conn).SendBatch method and adds tracing to it. Call the EnableDetailedBatchMode(), to have
// sql statements in the span. Amount of the sql statements that might be reported are limited.
func (c *Conn) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults {
	sql := "-- SEND BATCH"
	if detailedBatchMode {
		sql = appendBatchDetails(b, sql)
	}

	childCtx, span := contextWithChildSpan(ctx, sql, c.config, c.sensor)
	defer span.Finish()

	br := c.Conn.SendBatch(childCtx, b)

	return &batchResults{
		br,
		childCtx,
		c.sensor,
		c.config,
	}
}
<|endoftext|>