<commit_before>package tls

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/x509"
	"math/big"
	"strings"

	. "gopkg.in/check.v1"
)

type FVTests struct{}

var _ = Suite(&FVTests{})

func (t *FVTests) TestAcceptPeerCertNoFpNoFunc(c *C) {
	crt := t.makeTestCert(c)
	fpv := FingerprintVerifier{}
	c.Assert(fpv.acceptPeerCert(crt), Equals, false)
}

func (t *FVTests) TestAcceptPeerCertAcceptFuncFail(c *C) {
	crt := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		VerificationFunc: func(fp string) bool {
			return false
		},
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, false)
	c.Assert(fpv.AcceptFingerprint, Equals, "")
}

func (t *FVTests) TestAcceptPeerCertAcceptFuncAccept(c *C) {
	crt := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		VerificationFunc: func(fp string) bool {
			return true
		},
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, true)
	c.Assert(fpv.AcceptFingerprint, Equals, testCertFp)
	fpv.VerificationFunc = func(fp string) bool {
		c.Fatal("unexpected call to verification func")
		return false
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, true)
}

func (t *FVTests) TestAcceptPeerCertPreset(c *C) {
	crt := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		AcceptFingerprint: testCertFp,
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, true)
}

func (t *FVTests) TestAcceptPeerCertPresetFail(c *C) {
	crt := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		AcceptFingerprint: strings.Replace(testCertFp, "c", "d", 1),
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, false)
}

const testCertFp = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"

func (t *FVTests) makeTestCert(c *C) *x509.Certificate {
	entropy := bytes.NewBufferString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
	priv, err := ecdsa.GenerateKey(elliptic.P521(), entropy)
	c.Assert(err, IsNil)

	template := x509.Certificate{
		SerialNumber: big.NewInt(1),
	}

	_, err = x509.CreateCertificate(entropy, &template, &template,
		&priv.PublicKey, priv)
	c.Assert(err, IsNil)
	return &template
}
<commit_msg>api/tls: test DialTLS<commit_after>package tls

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"math/big"
	"net"
	"strings"

	. "gopkg.in/check.v1"
)

type FVTests struct{}

var _ = Suite(&FVTests{})

func (t *FVTests) TestAcceptPeerCertNoFpNoFunc(c *C) {
	crt, _, _ := t.makeTestCert(c)
	fpv := FingerprintVerifier{}
	c.Assert(fpv.acceptPeerCert(crt), Equals, false)
}

func (t *FVTests) TestAcceptPeerCertAcceptFuncFail(c *C) {
	crt, _, _ := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		VerificationFunc: func(fp string) bool {
			return false
		},
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, false)
	c.Assert(fpv.AcceptFingerprint, Equals, "")
}

func (t *FVTests) TestAcceptPeerCertAcceptFuncAccept(c *C) {
	crt, _, _ := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		VerificationFunc: func(fp string) bool {
			return true
		},
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, true)
	c.Assert(fpv.AcceptFingerprint, Equals, testCertFp)
	fpv.VerificationFunc = func(fp string) bool {
		c.Fatal("unexpected call to verification func")
		return false
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, true)
}

func (t *FVTests) TestAcceptPeerCertPreset(c *C) {
	crt, _, _ := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		AcceptFingerprint: testCertFp,
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, true)
}

func (t *FVTests) TestAcceptPeerCertPresetFail(c *C) {
	crt, _, _ := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		AcceptFingerprint: strings.Replace(testCertFp, "c", "d", 1),
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, false)
}

func (t *FVTests) TestAcceptPeerCertPresetFailNoCall(c *C) {
	crt, _, _ := t.makeTestCert(c)
	fpv := FingerprintVerifier{
		AcceptFingerprint: strings.Replace(testCertFp, "c", "d", 1),
		VerificationFunc: func(fp string) bool {
			c.Fatal("verification called although unexpected")
			return false
		},
	}
	c.Assert(fpv.acceptPeerCert(crt), Equals, false)
}

func (t *FVTests) setupTLSServer(c *C) (string, net.Listener) {
	l, err := net.Listen("tcp", "127.0.0.1:0")
	c.Assert(err, IsNil)
	_, derBytes, priv := t.makeTestCert(c)
	myCert := tls.Certificate{
		Certificate: [][]byte{derBytes},
		PrivateKey:  priv,
	}
	tlsL := tls.NewListener(l, &tls.Config{
		NextProtos:   []string{"http/1.1"},
		Certificates: []tls.Certificate{myCert},
	})
	go func() {
		conn, err := tlsL.Accept()
		c.Assert(err, IsNil)
		defer conn.Close()
		_, err = conn.Write([]byte("test"))
		c.Assert(err, IsNil)
	}()
	addr := tlsL.Addr().String()
	return addr, l
}

func (t *FVTests) TestDialTLSReject(c *C) {
	addr, l := t.setupTLSServer(c)
	defer l.Close()
	fpv := &FingerprintVerifier{}
	_, err := fpv.DialTLS("tcp", addr)
	c.Assert(err, Equals, ErrFingerprintRejected)
}

func (t *FVTests) TestDialTLSAccept(c *C) {
	addr, l := t.setupTLSServer(c)
	defer l.Close()
	fpv := &FingerprintVerifier{AcceptFingerprint: testCertFp}
	conn, err := fpv.DialTLS("tcp", addr)
	c.Assert(err, IsNil)
	r, err := ioutil.ReadAll(conn)
	c.Assert(err, IsNil)
	c.Assert(r, DeepEquals, []byte("test"))
}

const testCertFp = "9f79df7d821ea16d89c09e026074e81f89540aa7fbfda1b0b3f5ba7dcab88d71b944a49bb0c8a5c8abf42308d8ae060bf7437831e7a5f21b3c7718f04578680b"

func (t *FVTests) makeTestCert(c *C) (*x509.Certificate, []byte, *ecdsa.PrivateKey) {
	entropy := bytes.NewBufferString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
	priv, err := ecdsa.GenerateKey(elliptic.P521(), entropy)
	c.Assert(err, IsNil)

	template := x509.Certificate{
		SerialNumber: big.NewInt(1),
	}

	derBytes, err := x509.CreateCertificate(entropy, &template, &template,
		&priv.PublicKey, priv)
	c.Assert(err, IsNil)
	cert, err := x509.ParseCertificate(derBytes)
	c.Assert(err, IsNil)
	return cert, derBytes, priv
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2018 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package v1

import (
	"bytes"
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/loadimpact/k6/core"
	"github.com/loadimpact/k6/core/local"
	"github.com/loadimpact/k6/js"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/types"
	"github.com/manyminds/api2go/jsonapi"
	"github.com/spf13/afero"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	null "gopkg.in/guregu/null.v3"
)

func TestSetupData(t *testing.T) {
	t.Parallel()
	var testCases = []struct {
		name      string
		script    []byte
		setupRuns [][3]string
	}{
		{
			name: "setupReturns",
			script: []byte(`
			export function setup() {
				return {"v": 1};
			}

			export default function(data) {
				if (data !== undefined) {
					throw new Error("incorrect data: " + JSON.stringify(data));
				}
			};

			export function teardown(data) {
				if (data !== undefined) {
					throw new Error("incorrect teardown data: " + JSON.stringify(data));
				}
			} `),
			setupRuns: [][3]string{
				{"GET", "", "{}"},
				{"POST", "", `{"data": {"v":1}}`},
				{"GET", "", `{"data": {"v":1}}`},
				{"PUT", `{"v":2, "test":"mest"}`, `{"data": {"v":2, "test":"mest"}}`},
				{"GET", "", `{"data": {"v":2, "test":"mest"}}`},
				{"PUT", "", `{}`},
				{"GET", "", `{}`},
			},
		}, {

			name: "noSetup",
			script: []byte(`
			export default function(data) {
				if (!data || data.v != 2) {
					throw new Error("incorrect data: " + JSON.stringify(data));
				}
			};

			export function teardown(data) {
				if (!data || data.v != 2) {
					throw new Error("incorrect teardown data: " + JSON.stringify(data));
				}
			} `),
			setupRuns: [][3]string{
				{"GET", "", "{}"},
				{"POST", "", `{}`},
				{"GET", "", `{}`},
				{"PUT", `{"v":2, "test":"mest"}`, `{"data": {"v":2, "test":"mest"}}`},
				{"GET", "", `{"data": {"v":2, "test":"mest"}}`},
				{"PUT", "", `{}`},
				{"GET", "", `{}`},
				{"PUT", `{"v":2, "test":"mest"}`, `{"data": {"v":2, "test":"mest"}}`},
				{"GET", "", `{"data": {"v":2, "test":"mest"}}`},
			},
		}, {
			name: "setupNoReturn",
			script: []byte(`
			export function setup() {
				let a = {"v": 1};
			}
			export default function(data) {
				if (data === undefined || data !== "") {
					throw new Error("incorrect data: " + JSON.stringify(data));
				}
			};

			export function teardown(data) {
				if (data === undefined || data !== "") {
					throw new Error("incorrect teardown data: " + JSON.stringify(data));
				}
			} `),
			setupRuns: [][3]string{
				{"GET", "", "{}"},
				{"POST", "", `{}`},
				{"GET", "", `{}`},
				{"PUT", `{"v":2, "test":"mest"}`, `{"data": {"v":2, "test":"mest"}}`},
				{"GET", "", `{"data": {"v":2, "test":"mest"}}`},
				{"PUT", "\"\"", `{"data": ""}`},
				{"GET", "", `{"data": ""}`},
			},
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			runner, err := js.New(
				&lib.SourceData{Filename: "/script.js", Data: testCase.script},
				afero.NewMemMapFs(),
				lib.RuntimeOptions{},
			)
			require.NoError(t, err)
			runner.SetOptions(lib.Options{
				Paused:          null.BoolFrom(true),
				VUs:             null.IntFrom(2),
				VUsMax:          null.IntFrom(2),
				Iterations:      null.IntFrom(3),
				SetupTimeout:    types.NullDurationFrom(1 * time.Second),
				TeardownTimeout: types.NullDurationFrom(1 * time.Second),
			})
			executor := local.New(runner)
			executor.SetRunSetup(false)
			engine, err := core.NewEngine(executor, runner.GetOptions())
			require.NoError(t, err)

			ctx, cancel := context.WithCancel(context.Background())
			errC := make(chan error)
			go func() { errC <- engine.Run(ctx) }()

			handler := NewHandler()

			checkSetup := func(method, body, expResult string) {
				rw := httptest.NewRecorder()
				handler.ServeHTTP(rw, newRequestWithEngine(engine, method, "/v1/setup", bytes.NewBufferString(body)))
				res := rw.Result()
				assert.Equal(t, http.StatusOK, res.StatusCode)

				var doc jsonapi.Document
				assert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &doc))
				require.NotNil(t, doc.Data)
				require.NotNil(t, doc.Data.DataObject)
				assert.Equal(t, "setupData", doc.Data.DataObject.Type)
				assert.JSONEq(t, expResult, string(doc.Data.DataObject.Attributes))
			}

			for _, setupRun := range testCase.setupRuns {
				checkSetup(setupRun[0], setupRun[1], setupRun[2])
			}

			engine.Executor.SetPaused(false)

			select {
			case <-time.After(10 * time.Second):
				cancel()
				t.Fatal("Test timed out")
			case err := <-errC:
				cancel()
				require.NoError(t, err)
			}
		})
	}
}
<commit_msg>Log body when api returns wrong status in tests<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2018 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package v1

import (
	"bytes"
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/loadimpact/k6/core"
	"github.com/loadimpact/k6/core/local"
	"github.com/loadimpact/k6/js"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/lib/types"
	"github.com/manyminds/api2go/jsonapi"
	"github.com/spf13/afero"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	null "gopkg.in/guregu/null.v3"
)

func TestSetupData(t *testing.T) {
	t.Parallel()
	var testCases = []struct {
		name      string
		script    []byte
		setupRuns [][3]string
	}{
		{
			name: "setupReturns",
			script: []byte(`
			export function setup() {
				return {"v": 1};
			}

			export default function(data) {
				if (data !== undefined) {
					throw new Error("incorrect data: " + JSON.stringify(data));
				}
			};

			export function teardown(data) {
				if (data !== undefined) {
					throw new Error("incorrect teardown data: " + JSON.stringify(data));
				}
			} `),
			setupRuns: [][3]string{
				{"GET", "", "{}"},
				{"POST", "", `{"data": {"v":1}}`},
				{"GET", "", `{"data": {"v":1}}`},
				{"PUT", `{"v":2, "test":"mest"}`, `{"data": {"v":2, "test":"mest"}}`},
				{"GET", "", `{"data": {"v":2, "test":"mest"}}`},
				{"PUT", "", `{}`},
				{"GET", "", `{}`},
			},
		}, {

			name: "noSetup",
			script: []byte(`
			export default function(data) {
				if (!data || data.v != 2) {
					throw new Error("incorrect data: " + JSON.stringify(data));
				}
			};

			export function teardown(data) {
				if (!data || data.v != 2) {
					throw new Error("incorrect teardown data: " + JSON.stringify(data));
				}
			} `),
			setupRuns: [][3]string{
				{"GET", "", "{}"},
				{"POST", "", `{}`},
				{"GET", "", `{}`},
				{"PUT", `{"v":2, "test":"mest"}`, `{"data": {"v":2, "test":"mest"}}`},
				{"GET", "", `{"data": {"v":2, "test":"mest"}}`},
				{"PUT", "", `{}`},
				{"GET", "", `{}`},
				{"PUT", `{"v":2, "test":"mest"}`, `{"data": {"v":2, "test":"mest"}}`},
				{"GET", "", `{"data": {"v":2, "test":"mest"}}`},
			},
		}, {
			name: "setupNoReturn",
			script: []byte(`
			export function setup() {
				let a = {"v": 1};
			}
			export default function(data) {
				if (data === undefined || data !== "") {
					throw new Error("incorrect data: " + JSON.stringify(data));
				}
			};

			export function teardown(data) {
				if (data === undefined || data !== "") {
					throw new Error("incorrect teardown data: " + JSON.stringify(data));
				}
			} `),
			setupRuns: [][3]string{
				{"GET", "", "{}"},
				{"POST", "", `{}`},
				{"GET", "", `{}`},
				{"PUT", `{"v":2, "test":"mest"}`, `{"data": {"v":2, "test":"mest"}}`},
				{"GET", "", `{"data": {"v":2, "test":"mest"}}`},
				{"PUT", "\"\"", `{"data": ""}`},
				{"GET", "", `{"data": ""}`},
			},
		},
	}
	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			runner, err := js.New(
				&lib.SourceData{Filename: "/script.js", Data: testCase.script},
				afero.NewMemMapFs(),
				lib.RuntimeOptions{},
			)
			require.NoError(t, err)
			runner.SetOptions(lib.Options{
				Paused:          null.BoolFrom(true),
				VUs:             null.IntFrom(2),
				VUsMax:          null.IntFrom(2),
				Iterations:      null.IntFrom(3),
				SetupTimeout:    types.NullDurationFrom(1 * time.Second),
				TeardownTimeout: types.NullDurationFrom(1 * time.Second),
			})
			executor := local.New(runner)
			executor.SetRunSetup(false)
			engine, err := core.NewEngine(executor, runner.GetOptions())
			require.NoError(t, err)

			ctx, cancel := context.WithCancel(context.Background())
			errC := make(chan error)
			go func() { errC <- engine.Run(ctx) }()

			handler := NewHandler()

			checkSetup := func(method, body, expResult string) {
				rw := httptest.NewRecorder()
				handler.ServeHTTP(rw, newRequestWithEngine(engine, method, "/v1/setup", bytes.NewBufferString(body)))
				res := rw.Result()
				if !assert.Equal(t, http.StatusOK, res.StatusCode) {
					t.Logf("body: %s\n", rw.Body.String())
					return
				}

				var doc jsonapi.Document
				assert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &doc))
				require.NotNil(t, doc.Data)
				require.NotNil(t, doc.Data.DataObject)
				assert.Equal(t, "setupData", doc.Data.DataObject.Type)
				assert.JSONEq(t, expResult, string(doc.Data.DataObject.Attributes))
			}

			for _, setupRun := range testCase.setupRuns {
				checkSetup(setupRun[0], setupRun[1], setupRun[2])
			}

			engine.Executor.SetPaused(false)

			select {
			case <-time.After(10 * time.Second):
				cancel()
				t.Fatal("Test timed out")
			case err := <-errC:
				cancel()
				require.NoError(t, err)
			}
		})
	}
}
<|endoftext|>


<commit_before>package noise

import (
	"image"
	"image/color"
	"math/rand"
	"time"

	"github.com/anthonynsimon/bild/parallel"
	"github.com/anthonynsimon/bild/perlin"
)

// Fn is a noise function that generates values between 0 and 255.
type Fn func() uint8

var (
	// Uniform distribution noise function.
	Uniform Fn
	// Binary distribution noise function.
	Binary Fn
	// Gaussian distribution noise function.
	Gaussian Fn
)

func init() {
	Uniform = func() uint8 {
		return uint8(rand.Intn(256))
	}
	Binary = func() uint8 {
		return 0xFF * uint8(rand.Intn(2))
	}
	Gaussian = func() uint8 {
		return uint8(rand.NormFloat64()*32.0 + 128.0)
	}
}

// Options to configure the noise generation.
type Options struct {
	// NoiseFn is a noise function that will be called for each pixel
	// on the image being generated.
	NoiseFn Fn
	// Monochrome sets if the resulting image is grayscale or colored,
	// the latter meaning that each RGB channel was filled with different values.
	Monochrome bool
}

// PerlinGenerate outputs the perlin image of given height and width
// and freqency , freq from 0.1 to 2 is a good range
func PerlinGenerate(height, width int, freq float64) *image.RGBA {
	//keep these values as such
	alpha, beta, n := 2., 2., 3

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	p := perlin.NewPerlin(alpha, beta, n, rand.Int63())

	// serial implimentation
	// works well
	// see output folder
	for x := 0.; x < float64(height); x++ {
		for y := 0.; y < float64(width); y++ {
			t := p.Noise2D((x/10)*freq, (y/10)*freq)
			img.Set(int(x), int(y), color.NRGBA{
				R: uint8((t + 1) * 126),
				G: uint8((t + 1) * 126),
				B: uint8((t + 1) * 126),
				A: 255,
			})
		}
	}
	// parrel implimentation but doesnt work quite well
	// which means output image has pixellated effect
	// could be  useful for somecases
	// see output folder

	// parallel.Line(height, func(start, end int) {
	// 	for y := start; y < end; y++ {
	// 		for x := 0; x < width; x++ {
	// 			t := p.Noise2D(float64(x/10)*freq, float64(y/10)*freq)
	// 			img.Set(int(x), int(y), color.NRGBA{
	// 				R: uint8((t + 1) * 126),
	// 				G: uint8((t + 1) * 126),
	// 				B: uint8((t + 1) * 126),
	// 				A: 255,
	// 			})
	// 		}
	// 	}
	// })

	return img
}

// Generate returns an image of the parameter width and height filled
// with the values from a noise function.
// If no options are provided, defaults will be used.
func Generate(width, height int, o *Options) *image.RGBA {
	dst := image.NewRGBA(image.Rect(0, 0, width, height))

	// Get options or defaults
	noiseFn := Uniform
	monochrome := false
	if o != nil {
		if o.NoiseFn != nil {
			noiseFn = o.NoiseFn
		}
		monochrome = o.Monochrome
	}

	rand.Seed(time.Now().UTC().UnixNano())

	if monochrome {
		fillMonochrome(dst, noiseFn)
	} else {
		fillColored(dst, noiseFn)
	}

	return dst
}

func fillMonochrome(img *image.RGBA, noiseFn Fn) {
	width, height := img.Bounds().Dx(), img.Bounds().Dy()
	parallel.Line(height, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < width; x++ {
				pos := y*img.Stride + x*4
				v := noiseFn()

				img.Pix[pos+0] = v
				img.Pix[pos+1] = v
				img.Pix[pos+2] = v
				img.Pix[pos+3] = 0xFF
			}
		}
	})
}

func fillColored(img *image.RGBA, noiseFn Fn) {
	width, height := img.Bounds().Dx(), img.Bounds().Dy()
	parallel.Line(height, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < width; x++ {
				pos := y*img.Stride + x*4

				img.Pix[pos+0] = noiseFn()
				img.Pix[pos+1] = noiseFn()
				img.Pix[pos+2] = noiseFn()
				img.Pix[pos+3] = 0xFF
			}
		}
	})
}
<commit_msg>Refactor<commit_after>package noise

import (
	"image"
	"image/color"
	"math/rand"
	"time"

	"github.com/anthonynsimon/bild/parallel"
	"github.com/anthonynsimon/bild/perlin"
)

// Fn is a noise function that generates values between 0 and 255.
type Fn func() uint8

var (
	// Uniform distribution noise function.
	Uniform Fn
	// Binary distribution noise function.
	Binary Fn
	// Gaussian distribution noise function.
	Gaussian Fn
)

func init() {
	Uniform = func() uint8 {
		return uint8(rand.Intn(256))
	}
	Binary = func() uint8 {
		return 0xFF * uint8(rand.Intn(2))
	}
	Gaussian = func() uint8 {
		return uint8(rand.NormFloat64()*32.0 + 128.0)
	}
}

// Options to configure the noise generation.
type Options struct {
	// NoiseFn is a noise function that will be called for each pixel
	// on the image being generated.
	NoiseFn Fn
	// Monochrome sets if the resulting image is grayscale or colored,
	// the latter meaning that each RGB channel was filled with different values.
	Monochrome bool
}

// GeneratePerlin outputs the perlin image of given height and width and freqency
func GeneratePerlin(width, height int, frequency float64) *image.RGBA {
	alpha, beta, n := 2., 2., 3

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	p := perlin.NewPerlin(alpha, beta, n, rand.Int63())

	for x := 0.; x < float64(height); x++ {
		for y := 0.; y < float64(width); y++ {
			t := p.Noise2D((x/10)*frequency, (y/10)*frequency)
			img.Set(int(x), int(y), color.NRGBA{
				R: uint8((t + 1) * 126),
				G: uint8((t + 1) * 126),
				B: uint8((t + 1) * 126),
				A: 255,
			})
		}
	}

	return img
}

// Generate returns an image of the parameter width and height filled
// with the values from a noise function.
// If no options are provided, defaults will be used.
func Generate(width, height int, o *Options) *image.RGBA {
	dst := image.NewRGBA(image.Rect(0, 0, width, height))

	// Get options or defaults
	noiseFn := Uniform
	monochrome := false
	if o != nil {
		if o.NoiseFn != nil {
			noiseFn = o.NoiseFn
		}
		monochrome = o.Monochrome
	}

	rand.Seed(time.Now().UTC().UnixNano())

	if monochrome {
		fillMonochrome(dst, noiseFn)
	} else {
		fillColored(dst, noiseFn)
	}

	return dst
}

func fillMonochrome(img *image.RGBA, noiseFn Fn) {
	width, height := img.Bounds().Dx(), img.Bounds().Dy()
	parallel.Line(height, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < width; x++ {
				pos := y*img.Stride + x*4
				v := noiseFn()

				img.Pix[pos+0] = v
				img.Pix[pos+1] = v
				img.Pix[pos+2] = v
				img.Pix[pos+3] = 0xFF
			}
		}
	})
}

func fillColored(img *image.RGBA, noiseFn Fn) {
	width, height := img.Bounds().Dx(), img.Bounds().Dy()
	parallel.Line(height, func(start, end int) {
		for y := start; y < end; y++ {
			for x := 0; x < width; x++ {
				pos := y*img.Stride + x*4

				img.Pix[pos+0] = noiseFn()
				img.Pix[pos+1] = noiseFn()
				img.Pix[pos+2] = noiseFn()
				img.Pix[pos+3] = 0xFF
			}
		}
	})
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package certmanager

import (
	"crypto"
	"crypto/x509"
	"encoding/pem"

	"cloud.google.com/go/compute/metadata"
	"github.com/golang/glog"
)

// TokenFetcher defines the interface to fetch token.
type TokenFetcher interface {
	FetchToken() (string, error)
}

// GcpTokenFetcher implements the token fetcher in GCP.
type GcpTokenFetcher struct {
	// aud is the unique URI agreed upon by both the instance and the system verifying the instance's identity.
	// For more info: https://cloud.google.com/compute/docs/instances/verifying-instance-identity
	aud            string
	serviceAccount string
}

func (fetcher *GcpTokenFetcher) getTokenURI() string {
	// The GCE metadata service URI to get identity token.
	return "instance/service-accounts/" + fetcher.serviceAccount + "/identity?audience=" + fetcher.aud
}

// FetchToken fetchs the GCE VM identity jwt token from its metadata server.
// Note: this function only works in a GCE VM environment.
func (fetcher *GcpTokenFetcher) FetchToken() (string, error) {
	return metadata.Get(fetcher.getTokenURI())
}

// ParsePemEncodedCertificate constructs a `x509.Certificate` object using the
// given a PEM-encoded certificate,
func ParsePemEncodedCertificate(certBytes []byte) *x509.Certificate {
	cb, _ := pem.Decode(certBytes)
	if cb == nil {
		glog.Fatalf("Invalid PEM encoding for the certificate: %s", certBytes)
	}
	cert, err := x509.ParseCertificate(cb.Bytes)
	if err != nil {
		glog.Fatalf("Failed to parse X.509 certificate (error: %s)", err)
	}
	return cert
}

// Given a PEM-encoded key, parse the bytes into a `crypto.PrivateKey`
// according to the provided `x509.PublicKeyAlgorithm`.
func parsePemEncodedKey(algo x509.PublicKeyAlgorithm, keyBytes []byte) crypto.PrivateKey {
	kb, _ := pem.Decode(keyBytes)
	if kb == nil {
		glog.Fatalf("Invalid PEM encoding for the key: %s", keyBytes)
	}

	switch algo {
	case x509.RSA:
		key, err := x509.ParsePKCS1PrivateKey(kb.Bytes)
		if err != nil {
			glog.Fatalf("Failed to parse the RSA private key (error: %s)", err)
		}
		return key
	case x509.ECDSA:
		key, err := x509.ParseECPrivateKey(kb.Bytes)
		if err != nil {
			glog.Fatalf("Failed to parse the ECDSA private key (error: %s)", err)
		}
		return key
	default:
		glog.Fatalf("Unknown public key algorithm: %d", algo)
	}

	return nil
}
<commit_msg>Update getTokenURI() (#173)<commit_after>// Copyright 2017 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package certmanager

import (
	"crypto"
	"crypto/x509"
	"encoding/pem"

	"cloud.google.com/go/compute/metadata"
	"github.com/golang/glog"
)

// TokenFetcher defines the interface to fetch token.
type TokenFetcher interface {
	FetchToken() (string, error)
}

// GcpTokenFetcher implements the token fetcher in GCP.
type GcpTokenFetcher struct {
	// aud is the unique URI agreed upon by both the instance and the system verifying the instance's identity.
	// For more info: https://cloud.google.com/compute/docs/instances/verifying-instance-identity
	aud string
}

func (fetcher *GcpTokenFetcher) getTokenURI() string {
	// The GCE metadata service URI to get identity token of current (i.e., default) service account.
	return "instance/service-accounts/default/identity?audience=" + fetcher.aud
}

// FetchToken fetchs the GCE VM identity jwt token from its metadata server.
// Note: this function only works in a GCE VM environment.
func (fetcher *GcpTokenFetcher) FetchToken() (string, error) {
	return metadata.Get(fetcher.getTokenURI())
}

// ParsePemEncodedCertificate constructs a `x509.Certificate` object using the
// given a PEM-encoded certificate,
func ParsePemEncodedCertificate(certBytes []byte) *x509.Certificate {
	cb, _ := pem.Decode(certBytes)
	if cb == nil {
		glog.Fatalf("Invalid PEM encoding for the certificate: %s", certBytes)
	}
	cert, err := x509.ParseCertificate(cb.Bytes)
	if err != nil {
		glog.Fatalf("Failed to parse X.509 certificate (error: %s)", err)
	}
	return cert
}

// Given a PEM-encoded key, parse the bytes into a `crypto.PrivateKey`
// according to the provided `x509.PublicKeyAlgorithm`.
func parsePemEncodedKey(algo x509.PublicKeyAlgorithm, keyBytes []byte) crypto.PrivateKey {
	kb, _ := pem.Decode(keyBytes)
	if kb == nil {
		glog.Fatalf("Invalid PEM encoding for the key: %s", keyBytes)
	}

	switch algo {
	case x509.RSA:
		key, err := x509.ParsePKCS1PrivateKey(kb.Bytes)
		if err != nil {
			glog.Fatalf("Failed to parse the RSA private key (error: %s)", err)
		}
		return key
	case x509.ECDSA:
		key, err := x509.ParseECPrivateKey(kb.Bytes)
		if err != nil {
			glog.Fatalf("Failed to parse the ECDSA private key (error: %s)", err)
		}
		return key
	default:
		glog.Fatalf("Unknown public key algorithm: %d", algo)
	}

	return nil
}
<|endoftext|>


<commit_before>package certs

import (
	"testing"
	"time"
	"reflect"
	"crypto/x509"
)

func TestNewCert(t *testing.T) {
	x509c, _, err := NewCertificatePair("certy.com", "cert authority", 365 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to generate certificate and key pair, got error: %s", err.Error())
	}

	if err := x509c.VerifyHostname("certy.com"); err != nil {
		t.Errorf("x509c.VerifyHostname(%q): got %v, want no error", "certy.com", err)
	}

	if got, want := x509c.Subject.Organization, []string{"cert authority"}; !reflect.DeepEqual(got, want) {
		t.Errorf("x509c.Subject.Organization: got %v, want %v", got, want)
	}

	if got := x509c.SubjectKeyId; got == nil {
		t.Error("x509c.SubjectKeyId: got nothing, want key ID")
	}
	if !x509c.BasicConstraintsValid {
		t.Error("x509c.BasicConstraintsValid: got false, want true")
	}

	if got, want := x509c.KeyUsage, x509.KeyUsageKeyEncipherment; got&want == 0 {
		t.Error("x509c.KeyUsage: got nothing, want to include x509.KeyUsageKeyEncipherment")
	}
	if got, want := x509c.KeyUsage, x509.KeyUsageDigitalSignature; got&want == 0 {
		t.Error("x509c.KeyUsage: got nothing, want to include x509.KeyUsageDigitalSignature")
	}

	want := []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
	if got := x509c.ExtKeyUsage; !reflect.DeepEqual(got, want) {
		t.Errorf("x509c.ExtKeyUsage: got %v, want %v", got, want)
	}

	if got, want := x509c.DNSNames, []string{"certy.com"}; !reflect.DeepEqual(got, want) {
		t.Errorf("x509c.DNSNames: got %v, want %v", got, want)
	}
}

func TestNewPriv(t *testing.T) {
	_, priv, err := NewCertificatePair("certy.com", "cert authority", 365 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to generate certificate and key pair, got error: %s", err.Error())
	}

	err = priv.Validate()
	if err != nil {
		t.Errorf("Key validation failed, got error: %s", err.Error())
	}
}

func TestTlsCert(t *testing.T) {
	pub, priv, err := NewCertificatePair("certy.com", "cert authority", 365 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to generate certificate and key pair, got error: %s", err.Error())
	}
	tlsc, err := GetTlsCertificate(pub, priv, "hoverfly.proxy", 365 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to get tls cert, got error: %s", err.Error())
	}

	x509c := tlsc.Leaf
	if x509c == nil {
		t.Fatal("x509c: got nil, want *x509.Certificate")
	}
	if got := x509c.SerialNumber; got.Cmp(MaxSerialNumber) >= 0 {
		t.Errorf("x509c.SerialNumber: got %v, want <= MaxSerialNumber", got)
	}
	if got, want := x509c.Subject.CommonName, "hoverfly.proxy"; got != want {
		t.Errorf("X509c.Subject.CommonName: got %q, want %q", got, want)
	}
	if err := x509c.VerifyHostname("hoverfly.proxy"); err != nil {
		t.Errorf("x509c.VerifyHostname(%q): got %v, want no error", "certy.com", err)
	}

}<commit_msg>generate new cert test<commit_after>package certs

import (
	"testing"
	"time"
	"reflect"
	"crypto/x509"
	"os"
)

func TestNewCert(t *testing.T) {
	x509c, _, err := NewCertificatePair("certy.com", "cert authority", 365 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to generate certificate and key pair, got error: %s", err.Error())
	}

	if err := x509c.VerifyHostname("certy.com"); err != nil {
		t.Errorf("x509c.VerifyHostname(%q): got %v, want no error", "certy.com", err)
	}

	if got, want := x509c.Subject.Organization, []string{"cert authority"}; !reflect.DeepEqual(got, want) {
		t.Errorf("x509c.Subject.Organization: got %v, want %v", got, want)
	}

	if got := x509c.SubjectKeyId; got == nil {
		t.Error("x509c.SubjectKeyId: got nothing, want key ID")
	}
	if !x509c.BasicConstraintsValid {
		t.Error("x509c.BasicConstraintsValid: got false, want true")
	}

	if got, want := x509c.KeyUsage, x509.KeyUsageKeyEncipherment; got&want == 0 {
		t.Error("x509c.KeyUsage: got nothing, want to include x509.KeyUsageKeyEncipherment")
	}
	if got, want := x509c.KeyUsage, x509.KeyUsageDigitalSignature; got&want == 0 {
		t.Error("x509c.KeyUsage: got nothing, want to include x509.KeyUsageDigitalSignature")
	}

	want := []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
	if got := x509c.ExtKeyUsage; !reflect.DeepEqual(got, want) {
		t.Errorf("x509c.ExtKeyUsage: got %v, want %v", got, want)
	}

	if got, want := x509c.DNSNames, []string{"certy.com"}; !reflect.DeepEqual(got, want) {
		t.Errorf("x509c.DNSNames: got %v, want %v", got, want)
	}
}

func TestNewPriv(t *testing.T) {
	_, priv, err := NewCertificatePair("certy.com", "cert authority", 365 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to generate certificate and key pair, got error: %s", err.Error())
	}

	err = priv.Validate()
	if err != nil {
		t.Errorf("Key validation failed, got error: %s", err.Error())
	}
}

func TestTlsCert(t *testing.T) {
	pub, priv, err := NewCertificatePair("certy.com", "cert authority", 365 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to generate certificate and key pair, got error: %s", err.Error())
	}
	tlsc, err := GetTlsCertificate(pub, priv, "hoverfly.proxy", 365 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to get tls cert, got error: %s", err.Error())
	}

	x509c := tlsc.Leaf
	if x509c == nil {
		t.Fatal("x509c: got nil, want *x509.Certificate")
	}
	if got := x509c.SerialNumber; got.Cmp(MaxSerialNumber) >= 0 {
		t.Errorf("x509c.SerialNumber: got %v, want <= MaxSerialNumber", got)
	}
	if got, want := x509c.Subject.CommonName, "hoverfly.proxy"; got != want {
		t.Errorf("X509c.Subject.CommonName: got %q, want %q", got, want)
	}
	if err := x509c.VerifyHostname("hoverfly.proxy"); err != nil {
		t.Errorf("x509c.VerifyHostname(%q): got %v, want no error", "certy.com", err)
	}

}

func TestGenerateAndSave(t *testing.T) {
	tlsc, err := GenerateAndSave("certy", "cert authority", 1 * 24 * time.Hour)
	if err != nil {
		t.Errorf("Failed to generate tls certificate, got error: %s", err.Error())
	}
	x509c := tlsc.Leaf
	if x509c == nil {
		t.Errorf("x509c: got nil, want *x509.Certificate")
	}

	if _, err := os.Stat("cert.pem"); os.IsNotExist(err) {
		t.Errorf("expected to find it but cert.pem was not created!")
	} else {
		os.Remove("cert.pem")
	}

	if _, err := os.Stat("key.pem"); os.IsNotExist(err) {
		t.Errorf("expected to find it but key.pem was not created!")
	} else {
		os.Remove("key.pem")
	}

}<|endoftext|>


<commit_before>// Package flagconfig provides a flag to specifiy a config file which
// will in turn be used to read unspecified flag values.
package flagconfig

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

var configFile = flag.String(
	"c", defaultConfig(), "Config file to read flags from.")

func Usage() {
	Parse()
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	flag.VisitAll(func(f *flag.Flag) {
		fmt.Fprintf(os.Stderr, "  -%s=%s: %s\n", f.Name, f.Value.String(), f.Usage)
	})
}

func defaultConfig() string {
	home := os.Getenv("HOME")
	basename := filepath.Base(os.Args[0])
	path := filepath.Join(home, ".config", basename, "config")
	_, err := os.Open(path)
	if err == nil {
		return path
	}
	path = filepath.Join("/", "etc", "conf.d", basename)
	_, err = os.Open(path)
	if err == nil {
		return path
	}
	return ""
}

func contains(list []*flag.Flag, f *flag.Flag) bool {
	for _, i := range list {
		if i == f {
			return true
		}
	}
	return false
}

func readConfig() map[string]string {
	bytes, err := ioutil.ReadFile(*configFile)
	if err != nil {
		log.Fatalf("Failed to read config file %s: %s", *configFile, err)
	}
	lines := strings.Split(string(bytes), "\n")
	result := make(map[string]string, len(lines))
	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if trimmed == "" || trimmed[0] == '#' {
			continue
		}
		parts := strings.Split(line, "=")
		if len(parts) != 2 {
			log.Fatalf("Invalid config line: %s", line)
		}
		result[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
	}
	return result
}

func Parse() {
	if *configFile == "" {
		return
	}
	config := readConfig()
	explicit := make([]*flag.Flag, 0)
	all := make([]*flag.Flag, 0)
	flag.Visit(func(f *flag.Flag) {
		explicit = append(explicit, f)
	})
	flag.VisitAll(func(f *flag.Flag) {
		all = append(all, f)
		if !contains(explicit, f) {
			val := config[f.Name]
			if val != "" {
				err := f.Value.Set(val)
				if err != nil {
					log.Fatalf("Failed to set flag %s with value %s", f.Name, val)
				}
			}
		}
	})
Outer:
	for name, val := range config {
		for _, f := range all {
			if f.Name == name {
				continue Outer
			}
		}
		log.Fatalf("Unknown flag %s=%s in config file.", name, val)
	}
}
<commit_msg>Add ParseSet to add support for flag.FlagSet<commit_after>// Package flagconfig provides a flag to specifiy a config file which
// will in turn be used to read unspecified flag values.
package flagconfig

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

var configFile = flag.String(
	"c", defaultConfig(), "Config file to read flags from.")

func Usage() {
	Parse()
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	flag.VisitAll(func(f *flag.Flag) {
		fmt.Fprintf(os.Stderr, "  -%s=%s: %s\n", f.Name, f.Value.String(), f.Usage)
	})
}

func defaultConfig() string {
	home := os.Getenv("HOME")
	basename := filepath.Base(os.Args[0])
	path := filepath.Join(home, ".config", basename, "config")
	_, err := os.Open(path)
	if err == nil {
		return path
	}
	path = filepath.Join("/", "etc", "conf.d", basename)
	_, err = os.Open(path)
	if err == nil {
		return path
	}
	return ""
}

func contains(list []*flag.Flag, f *flag.Flag) bool {
	for _, i := range list {
		if i == f {
			return true
		}
	}
	return false
}

func readConfig() map[string]string {
	bytes, err := ioutil.ReadFile(*configFile)
	if err != nil {
		log.Fatalf("Failed to read config file %s: %s", *configFile, err)
	}
	lines := strings.Split(string(bytes), "\n")
	result := make(map[string]string, len(lines))
	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if trimmed == "" || trimmed[0] == '#' {
			continue
		}
		parts := strings.Split(line, "=")
		if len(parts) != 2 {
			log.Fatalf("Invalid config line: %s", line)
		}
		result[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
	}
	return result
}

func Parse() {
	ParseSet(flag.CommandLine)
}

func ParseSet(set *flag.FlagSet) {
	if *configFile == "" {
		return
	}
	config := readConfig()
	explicit := make([]*flag.Flag, 0)
	all := make([]*flag.Flag, 0)
	set.Visit(func(f *flag.Flag) {
		explicit = append(explicit, f)
	})
	set.VisitAll(func(f *flag.Flag) {
		all = append(all, f)
		if !contains(explicit, f) {
			val := config[f.Name]
			if val != "" {
				err := f.Value.Set(val)
				if err != nil {
					log.Fatalf("Failed to set flag %s with value %s", f.Name, val)
				}
			}
		}
	})
Outer:
	for name, val := range config {
		for _, f := range all {
			if f.Name == name {
				continue Outer
			}
		}
		log.Fatalf("Unknown flag %s=%s in config file.", name, val)
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package flow

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

	"github.com/golang/protobuf/proto"
	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/filters"
	"github.com/skydive-project/skydive/logging"
)

// TableQuery contains a type and a query obj as an array of bytes.
// The query can be encoded in different ways according the type.
type TableQuery struct {
	Type string
	Obj  []byte
}

// TableReply is the response to a TableQuery containing a Status and an array
// of replies that can be encoded in many ways, ex: json, protobuf.
type TableReply struct {
	Obj    [][]byte
	status int
}

type ExpireUpdateFunc func(f []*Flow)

type FlowHandler struct {
	callback ExpireUpdateFunc
	every    time.Duration
}

func NewFlowHandler(callback ExpireUpdateFunc, every time.Duration) *FlowHandler {
	return &FlowHandler{
		callback: callback,
		every:    every,
	}
}

type Table struct {
	PacketsChan   chan *FlowPackets
	table         map[string]*Flow
	stats         map[string]*FlowMetric
	flush         chan bool
	flushDone     chan bool
	query         chan *TableQuery
	reply         chan *TableReply
	state         int64
	lockState     sync.RWMutex
	wg            sync.WaitGroup
	updateHandler *FlowHandler
	lastUpdate    int64
	expireHandler *FlowHandler
	lastExpire    int64
	tableClock    int64
	nodeTID       string
	pipeline      *FlowEnhancerPipeline
}

func NewTable(updateHandler *FlowHandler, expireHandler *FlowHandler, pipeline *FlowEnhancerPipeline) *Table {
	t := &Table{
		PacketsChan:   make(chan *FlowPackets, 1000),
		table:         make(map[string]*Flow),
		stats:         make(map[string]*FlowMetric),
		flush:         make(chan bool),
		flushDone:     make(chan bool),
		state:         common.StoppedState,
		updateHandler: updateHandler,
		expireHandler: expireHandler,
		pipeline:      pipeline,
	}
	t.tableClock = common.UnixMillis(time.Now())
	return t
}

func (ft *Table) SetNodeTID(tid string) {
	ft.nodeTID = tid
}

func (ft *Table) getFlows(query *filters.SearchQuery) *FlowSet {
	flowset := NewFlowSet()
	for _, f := range ft.table {
		if query == nil || query.Filter == nil || query.Filter.Eval(f) {
			if flowset.Start == 0 || flowset.Start > f.Start {
				flowset.Start = f.Start
			}
			if flowset.End == 0 || flowset.Start < f.Last {
				flowset.End = f.Last
			}
			flowset.Flows = append(flowset.Flows, f)
		}
	}
	return flowset
}

func (ft *Table) getOrCreateFlow(key string) (*Flow, bool) {
	if flow, found := ft.table[key]; found {
		return flow, false
	}

	new := &Flow{
		Metric:           &FlowMetric{},
		LastUpdateMetric: &FlowMetric{},
	}
	ft.table[key] = new

	return new, true
}

func (ft *Table) expire(expireBefore int64) {
	var expiredFlows []*Flow
	flowTableSzBefore := len(ft.table)
	for k, f := range ft.table {
		if f.Last < expireBefore {
			duration := time.Duration(f.Last - f.Start)
			if f.Last >= ft.lastUpdate {
				ft.updateMetric(f, ft.lastUpdate, f.Last)
			}

			logging.GetLogger().Debugf("Expire flow %s Duration %v", f.UUID, duration)
			expiredFlows = append(expiredFlows, f)

			// need to use the key as the key could be not equal to the UUID
			delete(ft.table, k)

			// stats are always indexed by UUID
			delete(ft.stats, f.UUID)
		}
	}
	/* Advise Clients */
	if ft.expireHandler.callback != nil {
		ft.expireHandler.callback(expiredFlows)
	}

	flowTableSz := len(ft.table)
	logging.GetLogger().Debugf("Expire Flow : removed %v ; new size %v", flowTableSzBefore-flowTableSz, flowTableSz)
}

func (ft *Table) updateAt(now time.Time) {
	updateTime := common.UnixMillis(now)
	ft.update(ft.lastUpdate, updateTime)
	ft.lastUpdate = updateTime
}

func (ft *Table) updateMetric(f *Flow, start, last int64) {
	f.LastUpdateMetric.ABPackets = f.Metric.ABPackets
	f.LastUpdateMetric.ABBytes = f.Metric.ABBytes
	f.LastUpdateMetric.BAPackets = f.Metric.BAPackets
	f.LastUpdateMetric.BABytes = f.Metric.BABytes

	// subtract previous values to get the diff so that we store the
	// amount of data between two updates
	if s, ok := ft.stats[f.UUID]; ok {
		f.LastUpdateMetric.ABPackets -= s.ABPackets
		f.LastUpdateMetric.ABBytes -= s.ABBytes
		f.LastUpdateMetric.BAPackets -= s.BAPackets
		f.LastUpdateMetric.BABytes -= s.BABytes
		f.LastUpdateStart = start
	} else {
		f.LastUpdateStart = f.Start
	}

	f.LastUpdateLast = last
}

func (ft *Table) update(updateFrom, updateTime int64) {
	var updatedFlows []*Flow
	for _, f := range ft.table {
		if f.Last > updateFrom {
			ft.updateMetric(f, updateFrom, updateTime)
			updatedFlows = append(updatedFlows, f)
		} else {
			f.LastUpdateMetric = &FlowMetric{}
			f.LastUpdateStart = updateFrom
			f.LastUpdateLast = updateTime
		}

		ft.stats[f.UUID] = f.Metric.Copy()
	}

	/* Advise Clients */
	if ft.updateHandler.callback != nil {
		ft.updateHandler.callback(updatedFlows)
	}
	logging.GetLogger().Debugf("Send updated Flow %d", len(updatedFlows))
}

func (ft *Table) expireNow() {
	const Now = int64(^uint64(0) >> 1)
	ft.expire(Now)
}

func (ft *Table) expireAt(now time.Time) {
	ft.expire(ft.lastExpire)
	ft.lastExpire = common.UnixMillis(now)
}

func (ft *Table) Flush() {
	ft.flush <- true
	<-ft.flushDone
}

func (ft *Table) onSearchQueryMessage(fsq *filters.SearchQuery) (*FlowSearchReply, int) {
	flowset := ft.getFlows(fsq)
	if len(flowset.Flows) == 0 {
		return &FlowSearchReply{
			FlowSet: flowset,
		}, http.StatusNoContent
	}

	if fsq.Sort {
		flowset.Sort(fsq.SortBy)
	}

	if fsq.Dedup {
		flowset.Dedup(fsq.DedupBy)
	}

	if fsq.PaginationRange != nil {
		flowset.Slice(int(fsq.PaginationRange.From), int(fsq.PaginationRange.To))
	}

	return &FlowSearchReply{
		FlowSet: flowset,
	}, http.StatusOK
}

func (ft *Table) onQuery(query *TableQuery) *TableReply {
	reply := &TableReply{
		status: http.StatusBadRequest,
		Obj:    make([][]byte, 0),
	}

	switch query.Type {
	case "SearchQuery":
		var fsq filters.SearchQuery
		if err := proto.Unmarshal(query.Obj, &fsq); err != nil {
			logging.GetLogger().Errorf("Unable to decode the flow search query: %s", err.Error())
			break
		}

		fsr, status := ft.onSearchQueryMessage(&fsq)
		if status != http.StatusOK {
			reply.status = status
			break
		}
		pb, _ := proto.Marshal(fsr)

		// TableReply returns an array of replies so in that case an array of
		// protobuf replies
		reply.Obj = append(reply.Obj, pb)

		reply.status = http.StatusOK
	}

	return reply
}

func (ft *Table) Query(query *TableQuery) *TableReply {
	ft.lockState.Lock()
	defer ft.lockState.Unlock()

	if atomic.LoadInt64(&ft.state) == common.RunningState {
		ft.query <- query

		timer := time.NewTicker(1 * time.Second)
		defer timer.Stop()

		for {
			select {
			case r := <-ft.reply:
				return r
			case <-timer.C:
				if atomic.LoadInt64(&ft.state) != common.RunningState {
					return nil
				}
			}
		}
	}
	return nil
}

func (ft *Table) FlowPacketToFlow(packet *FlowPacket, parentUUID string, t int64, L2ID int64, L3ID int64) *Flow {
	key := FlowKeyFromGoPacket(packet.gopacket, parentUUID).String()
	flow, new := ft.getOrCreateFlow(key)
	if new {
		flow.Init(key, t, packet.gopacket, packet.length, ft.nodeTID, parentUUID, L2ID, L3ID)
		ft.pipeline.EnhanceFlow(flow)
	} else {
		flow.Update(t, packet.gopacket, packet.length)
	}
	return flow
}

func (ft *Table) FlowPacketsToFlow(flowPackets *FlowPackets) {
	t := flowPackets.Timestamp
	if t == -1 {
		t = ft.tableClock
	}

	var parentUUID string
	var L2ID int64
	var L3ID int64
	logging.GetLogger().Debugf("%d FlowPackets received for capture node %s", len(flowPackets.Packets), ft.nodeTID)
	for _, packet := range flowPackets.Packets {
		f := ft.FlowPacketToFlow(&packet, parentUUID, t, L2ID, L3ID)
		parentUUID = f.UUID
		if f.Link != nil {
			L2ID = f.Link.ID
		}
		if f.Network != nil {
			L3ID = f.Network.ID
		}
	}
}

func (ft *Table) Run() {
	ft.wg.Add(1)
	defer ft.wg.Done()

	updateTicker := time.NewTicker(ft.updateHandler.every)
	defer updateTicker.Stop()

	expireTicker := time.NewTicker(ft.expireHandler.every)
	defer expireTicker.Stop()

	nowTicker := time.NewTicker(time.Second * 1)
	defer nowTicker.Stop()

	ft.lastUpdate = common.UnixMillis(time.Now())
	ft.query = make(chan *TableQuery, 100)
	ft.reply = make(chan *TableReply, 100)

	atomic.StoreInt64(&ft.state, common.RunningState)
	for atomic.LoadInt64(&ft.state) == common.RunningState {
		select {
		case now := <-expireTicker.C:
			ft.expireAt(now)
		case now := <-updateTicker.C:
			ft.updateAt(now)
		case <-ft.flush:
			ft.expireNow()
			ft.flushDone <- true
		case query, ok := <-ft.query:
			if ok {
				ft.reply <- ft.onQuery(query)
			}
		case now := <-nowTicker.C:
			ft.tableClock = common.UnixMillis(now)
		case packets := <-ft.PacketsChan:
			ft.FlowPacketsToFlow(packets)
		}
	}
}

func (ft *Table) Start() chan *FlowPackets {
	go ft.Run()
	return ft.PacketsChan
}

func (ft *Table) Stop() {
	ft.lockState.Lock()
	defer ft.lockState.Unlock()

	if atomic.CompareAndSwapInt64(&ft.state, common.RunningState, common.StoppingState) {
		ft.wg.Wait()

		close(ft.query)
		close(ft.reply)
		close(ft.PacketsChan)
	}

	ft.expireNow()
}
<commit_msg>flow: set update time at table creation<commit_after>/*
 * Copyright (C) 2016 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package flow

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

	"github.com/golang/protobuf/proto"
	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/filters"
	"github.com/skydive-project/skydive/logging"
)

// TableQuery contains a type and a query obj as an array of bytes.
// The query can be encoded in different ways according the type.
type TableQuery struct {
	Type string
	Obj  []byte
}

// TableReply is the response to a TableQuery containing a Status and an array
// of replies that can be encoded in many ways, ex: json, protobuf.
type TableReply struct {
	Obj    [][]byte
	status int
}

type ExpireUpdateFunc func(f []*Flow)

type FlowHandler struct {
	callback ExpireUpdateFunc
	every    time.Duration
}

func NewFlowHandler(callback ExpireUpdateFunc, every time.Duration) *FlowHandler {
	return &FlowHandler{
		callback: callback,
		every:    every,
	}
}

type Table struct {
	PacketsChan   chan *FlowPackets
	table         map[string]*Flow
	stats         map[string]*FlowMetric
	flush         chan bool
	flushDone     chan bool
	query         chan *TableQuery
	reply         chan *TableReply
	state         int64
	lockState     sync.RWMutex
	wg            sync.WaitGroup
	updateHandler *FlowHandler
	lastUpdate    int64
	expireHandler *FlowHandler
	lastExpire    int64
	tableClock    int64
	nodeTID       string
	pipeline      *FlowEnhancerPipeline
}

func NewTable(updateHandler *FlowHandler, expireHandler *FlowHandler, pipeline *FlowEnhancerPipeline) *Table {
	t := &Table{
		PacketsChan:   make(chan *FlowPackets, 1000),
		table:         make(map[string]*Flow),
		stats:         make(map[string]*FlowMetric),
		flush:         make(chan bool),
		flushDone:     make(chan bool),
		state:         common.StoppedState,
		updateHandler: updateHandler,
		expireHandler: expireHandler,
		pipeline:      pipeline,
	}
	t.tableClock = common.UnixMillis(time.Now())
	t.lastUpdate = t.tableClock
	return t
}

func (ft *Table) SetNodeTID(tid string) {
	ft.nodeTID = tid
}

func (ft *Table) getFlows(query *filters.SearchQuery) *FlowSet {
	flowset := NewFlowSet()
	for _, f := range ft.table {
		if query == nil || query.Filter == nil || query.Filter.Eval(f) {
			if flowset.Start == 0 || flowset.Start > f.Start {
				flowset.Start = f.Start
			}
			if flowset.End == 0 || flowset.Start < f.Last {
				flowset.End = f.Last
			}
			flowset.Flows = append(flowset.Flows, f)
		}
	}
	return flowset
}

func (ft *Table) getOrCreateFlow(key string) (*Flow, bool) {
	if flow, found := ft.table[key]; found {
		return flow, false
	}

	new := &Flow{
		Metric:           &FlowMetric{},
		LastUpdateMetric: &FlowMetric{},
	}
	ft.table[key] = new

	return new, true
}

func (ft *Table) expire(expireBefore int64) {
	var expiredFlows []*Flow
	flowTableSzBefore := len(ft.table)
	for k, f := range ft.table {
		if f.Last < expireBefore {
			duration := time.Duration(f.Last - f.Start)
			if f.Last >= ft.lastUpdate {
				ft.updateMetric(f, ft.lastUpdate, f.Last)
			}

			logging.GetLogger().Debugf("Expire flow %s Duration %v", f.UUID, duration)
			expiredFlows = append(expiredFlows, f)

			// need to use the key as the key could be not equal to the UUID
			delete(ft.table, k)

			// stats are always indexed by UUID
			delete(ft.stats, f.UUID)
		}
	}
	/* Advise Clients */
	if ft.expireHandler.callback != nil {
		ft.expireHandler.callback(expiredFlows)
	}

	flowTableSz := len(ft.table)
	logging.GetLogger().Debugf("Expire Flow : removed %v ; new size %v", flowTableSzBefore-flowTableSz, flowTableSz)
}

func (ft *Table) updateAt(now time.Time) {
	updateTime := common.UnixMillis(now)
	ft.update(ft.lastUpdate, updateTime)
	ft.lastUpdate = updateTime
}

func (ft *Table) updateMetric(f *Flow, start, last int64) {
	f.LastUpdateMetric.ABPackets = f.Metric.ABPackets
	f.LastUpdateMetric.ABBytes = f.Metric.ABBytes
	f.LastUpdateMetric.BAPackets = f.Metric.BAPackets
	f.LastUpdateMetric.BABytes = f.Metric.BABytes

	// subtract previous values to get the diff so that we store the
	// amount of data between two updates
	if s, ok := ft.stats[f.UUID]; ok {
		f.LastUpdateMetric.ABPackets -= s.ABPackets
		f.LastUpdateMetric.ABBytes -= s.ABBytes
		f.LastUpdateMetric.BAPackets -= s.BAPackets
		f.LastUpdateMetric.BABytes -= s.BABytes
		f.LastUpdateStart = start
	} else {
		f.LastUpdateStart = f.Start
	}

	f.LastUpdateLast = last
}

func (ft *Table) update(updateFrom, updateTime int64) {
	var updatedFlows []*Flow
	for _, f := range ft.table {
		if f.Last > updateFrom {
			ft.updateMetric(f, updateFrom, updateTime)
			updatedFlows = append(updatedFlows, f)
		} else {
			f.LastUpdateMetric = &FlowMetric{}
			f.LastUpdateStart = updateFrom
			f.LastUpdateLast = updateTime
		}

		ft.stats[f.UUID] = f.Metric.Copy()
	}

	/* Advise Clients */
	if ft.updateHandler.callback != nil {
		ft.updateHandler.callback(updatedFlows)
	}
	logging.GetLogger().Debugf("Send updated Flow %d", len(updatedFlows))
}

func (ft *Table) expireNow() {
	const Now = int64(^uint64(0) >> 1)
	ft.expire(Now)
}

func (ft *Table) expireAt(now time.Time) {
	ft.expire(ft.lastExpire)
	ft.lastExpire = common.UnixMillis(now)
}

func (ft *Table) Flush() {
	ft.flush <- true
	<-ft.flushDone
}

func (ft *Table) onSearchQueryMessage(fsq *filters.SearchQuery) (*FlowSearchReply, int) {
	flowset := ft.getFlows(fsq)
	if len(flowset.Flows) == 0 {
		return &FlowSearchReply{
			FlowSet: flowset,
		}, http.StatusNoContent
	}

	if fsq.Sort {
		flowset.Sort(fsq.SortBy)
	}

	if fsq.Dedup {
		flowset.Dedup(fsq.DedupBy)
	}

	if fsq.PaginationRange != nil {
		flowset.Slice(int(fsq.PaginationRange.From), int(fsq.PaginationRange.To))
	}

	return &FlowSearchReply{
		FlowSet: flowset,
	}, http.StatusOK
}

func (ft *Table) onQuery(query *TableQuery) *TableReply {
	reply := &TableReply{
		status: http.StatusBadRequest,
		Obj:    make([][]byte, 0),
	}

	switch query.Type {
	case "SearchQuery":
		var fsq filters.SearchQuery
		if err := proto.Unmarshal(query.Obj, &fsq); err != nil {
			logging.GetLogger().Errorf("Unable to decode the flow search query: %s", err.Error())
			break
		}

		fsr, status := ft.onSearchQueryMessage(&fsq)
		if status != http.StatusOK {
			reply.status = status
			break
		}
		pb, _ := proto.Marshal(fsr)

		// TableReply returns an array of replies so in that case an array of
		// protobuf replies
		reply.Obj = append(reply.Obj, pb)

		reply.status = http.StatusOK
	}

	return reply
}

func (ft *Table) Query(query *TableQuery) *TableReply {
	ft.lockState.Lock()
	defer ft.lockState.Unlock()

	if atomic.LoadInt64(&ft.state) == common.RunningState {
		ft.query <- query

		timer := time.NewTicker(1 * time.Second)
		defer timer.Stop()

		for {
			select {
			case r := <-ft.reply:
				return r
			case <-timer.C:
				if atomic.LoadInt64(&ft.state) != common.RunningState {
					return nil
				}
			}
		}
	}
	return nil
}

func (ft *Table) FlowPacketToFlow(packet *FlowPacket, parentUUID string, t int64, L2ID int64, L3ID int64) *Flow {
	key := FlowKeyFromGoPacket(packet.gopacket, parentUUID).String()
	flow, new := ft.getOrCreateFlow(key)
	if new {
		flow.Init(key, t, packet.gopacket, packet.length, ft.nodeTID, parentUUID, L2ID, L3ID)
		ft.pipeline.EnhanceFlow(flow)
	} else {
		flow.Update(t, packet.gopacket, packet.length)
	}
	return flow
}

func (ft *Table) FlowPacketsToFlow(flowPackets *FlowPackets) {
	t := flowPackets.Timestamp
	if t == -1 {
		t = ft.tableClock
	}

	var parentUUID string
	var L2ID int64
	var L3ID int64
	logging.GetLogger().Debugf("%d FlowPackets received for capture node %s", len(flowPackets.Packets), ft.nodeTID)
	for _, packet := range flowPackets.Packets {
		f := ft.FlowPacketToFlow(&packet, parentUUID, t, L2ID, L3ID)
		parentUUID = f.UUID
		if f.Link != nil {
			L2ID = f.Link.ID
		}
		if f.Network != nil {
			L3ID = f.Network.ID
		}
	}
}

func (ft *Table) Run() {
	ft.wg.Add(1)
	defer ft.wg.Done()

	updateTicker := time.NewTicker(ft.updateHandler.every)
	defer updateTicker.Stop()

	expireTicker := time.NewTicker(ft.expireHandler.every)
	defer expireTicker.Stop()

	nowTicker := time.NewTicker(time.Second * 1)
	defer nowTicker.Stop()

	ft.query = make(chan *TableQuery, 100)
	ft.reply = make(chan *TableReply, 100)

	atomic.StoreInt64(&ft.state, common.RunningState)
	for atomic.LoadInt64(&ft.state) == common.RunningState {
		select {
		case now := <-expireTicker.C:
			ft.expireAt(now)
		case now := <-updateTicker.C:
			ft.updateAt(now)
		case <-ft.flush:
			ft.expireNow()
			ft.flushDone <- true
		case query, ok := <-ft.query:
			if ok {
				ft.reply <- ft.onQuery(query)
			}
		case now := <-nowTicker.C:
			ft.tableClock = common.UnixMillis(now)
		case packets := <-ft.PacketsChan:
			ft.FlowPacketsToFlow(packets)
		}
	}
}

func (ft *Table) Start() chan *FlowPackets {
	go ft.Run()
	return ft.PacketsChan
}

func (ft *Table) Stop() {
	ft.lockState.Lock()
	defer ft.lockState.Unlock()

	if atomic.CompareAndSwapInt64(&ft.state, common.RunningState, common.StoppingState) {
		ft.wg.Wait()

		close(ft.query)
		close(ft.reply)
		close(ft.PacketsChan)
	}

	ft.expireNow()
}
<|endoftext|>


<commit_before>package foursquarego

import (
	"encoding/json"
	"net/http"

	"github.com/dghubble/sling"
)

const (
	baseURL = "https://api.foursquare.com/v2/"
	version = "20161213"
	//MODE    = "foursquare"
)

// Client is a Foursquare client for making Foursquare API requests.
type Client struct {
	sling  *sling.Sling
	Venues *VenueService
}

// NewClient returns a new Client.
func NewClient(mode, clientID, clientSecret, accessToken string) *Client {
	httpClient := http.DefaultClient
	return newClient(httpClient, mode, clientID, clientSecret, accessToken)
}

func newClient(httpClient *http.Client, mode, clientID, clientSecret, accessToken string) *Client {
	b := sling.New().Client(httpClient).Base(baseURL)
	b.QueryStruct(struct {
		V            string `url:"v"`
		M            string `url:"m"`
		ClientID     string `url:"client_id"`
		ClientSecret string `url:"client_secret,omitempty"`
		AccessToken  string `url:"access_token,omitempty"`
	}{
		V:            version,
		M:            mode,
		ClientID:     clientID,
		ClientSecret: clientSecret,
		AccessToken:  accessToken,
	})

	return &Client{
		sling:  b,
		Venues: newVenueService(b.New()),
	}
}

// Response is a typical foursquare response
// https://developer.foursquare.com/overview/responses
type Response struct {
	Meta          Meta            `json:"meta"`
	Notifications []Notification  `json:"notifications"`
	Response      json.RawMessage `json:"response"`
}

type Meta struct {
	Code        int    `json:"code"`
	ErrorType   string `json:"errorType"`
	ErrorDetail string `json:"errorDetail"`
	RequestID   string `json:"requestId"`
}

type Notification struct {
	Type string          `json:"type"`
	Item json.RawMessage `json:"item"`
}

type Group struct {
	Type  string `json:"type"`
	Name  string `json:"name"`
	Count int    `json:"count"`
}

type Count struct {
	Count int `json:"count"`
}

// Omitted is for fields that do not have a known datastructure. If you find
// an example where this field is used please let me know. You will need to handle
// this in your application until that time.
type Omitted interface{}
<commit_msg>add rawrequest to ask for any endpoint<commit_after>package foursquarego

import (
	"encoding/json"
	"net/http"

	"github.com/dghubble/sling"
)

const (
	baseURL = "https://api.foursquare.com/v2/"
	version = "20161213"
	//MODE    = "foursquare"
)

// Client is a Foursquare client for making Foursquare API requests.
type Client struct {
	sling  *sling.Sling
	Venues *VenueService
}

// NewClient returns a new Client.
func NewClient(mode, clientID, clientSecret, accessToken string) *Client {
	httpClient := http.DefaultClient
	return newClient(httpClient, mode, clientID, clientSecret, accessToken)
}

func newClient(httpClient *http.Client, mode, clientID, clientSecret, accessToken string) *Client {
	b := sling.New().Client(httpClient).Base(baseURL)
	b.QueryStruct(struct {
		V            string `url:"v"`
		M            string `url:"m"`
		ClientID     string `url:"client_id"`
		ClientSecret string `url:"client_secret,omitempty"`
		AccessToken  string `url:"access_token,omitempty"`
	}{
		V:            version,
		M:            mode,
		ClientID:     clientID,
		ClientSecret: clientSecret,
		AccessToken:  accessToken,
	})

	return &Client{
		sling:  b,
		Venues: newVenueService(b.New()),
	}
}

// RawRequest allows you to make any request you want. This will automatically add
// the client/user tokens. Gives back exactly the response from foursquare.
func (c *Client) RawRequest(url string) (*Response, *http.Response, error) {
	response := new(Response)
	resp, err := c.sling.New().Get(url).Receive(response, response)
	return response, resp, relevantError(err, *response)
}

// Response is a typical foursquare response
// https://developer.foursquare.com/overview/responses
type Response struct {
	Meta          Meta            `json:"meta"`
	Notifications []Notification  `json:"notifications"`
	Response      json.RawMessage `json:"response"`
}

type Meta struct {
	Code        int    `json:"code"`
	ErrorType   string `json:"errorType"`
	ErrorDetail string `json:"errorDetail"`
	RequestID   string `json:"requestId"`
}

type Notification struct {
	Type string          `json:"type"`
	Item json.RawMessage `json:"item"`
}

type Group struct {
	Type  string `json:"type"`
	Name  string `json:"name"`
	Count int    `json:"count"`
}

type Count struct {
	Count int `json:"count"`
}

// Omitted is for fields that do not have a known datastructure. If you find
// an example where this field is used please let me know. You will need to handle
// this in your application until that time.
type Omitted interface{}
<|endoftext|>


<commit_before>package freddo

import (
	"crypto/hmac"
	"crypto/sha1"
	"errors"
	"hash"
	"log"
	"os/exec"
	"strings"
)

type App struct {
	Name        string
	Secret      []byte
	Script      string
	UpdateQueue chan string
}

func NewApp(name string) *App {
	app := &App{
		Name:        name,
		UpdateQueue: make(chan string, 1),
	}
	return app
}

func (a *App) HmacEqual(msg []byte, msgSig string) (bool, error) {
	parts := strings.Split(msgSig, "=")
	if len(parts) != 2 {
		return false, errors.New("Invalid signature: " + msgSig)
	}
	var mac hash.Hash
	switch parts[0] {
	case "sha1":
		mac = hmac.New(sha1.New, a.Secret)
	default:
		return false, errors.New("Unsupported hash type: " + parts[0])
	}
	mac.Write(msg)
	expected := mac.Sum(nil)
	return hmac.Equal([]byte(parts[1]), expected), nil
}

func (a *App) QueueUpdate() error {
	select {
	case a.UpdateQueue <- "update":
		return nil
	default:
		return errors.New("Could not queue update for " + a.Name)
	}
}

func (a *App) LoopQueue() {
	for _ = range a.UpdateQueue {
		a.Update()
	}
}

func (a *App) Update() {
	log.Print("Running: ", a.Script)

	out, err := a.RunScript()
	if err != nil {
		log.Print("Failed: ", a.Script)
		log.Print("output: ", string(out))
		log.Print(err)
	}
}

func (a *App) RunScript() ([]byte, error) {
	c := exec.Command("/bin/sh", "-c", a.Script)
	return c.CombinedOutput()
}
<commit_msg>fix hmac compare<commit_after>package freddo

import (
	"crypto/hmac"
	"crypto/sha1"
	"errors"
	"fmt"
	"hash"
	"log"
	"os/exec"
	"strings"
)

type App struct {
	Name        string
	Secret      []byte
	Script      string
	UpdateQueue chan string
}

func NewApp(name string) *App {
	app := &App{
		Name:        name,
		UpdateQueue: make(chan string, 1),
	}
	return app
}

func (a *App) HmacEqual(msg []byte, msgSig string) (bool, error) {
	parts := strings.Split(msgSig, "=")
	if len(parts) != 2 {
		return false, errors.New("Invalid signature: " + msgSig)
	}
	var mac hash.Hash
	switch parts[0] {
	case "sha1":
		mac = hmac.New(sha1.New, a.Secret)
	default:
		return false, errors.New("Unsupported hash type: " + parts[0])
	}
	mac.Write(msg)
	expected := mac.Sum(nil)
	return parts[1] == fmt.Sprintf("%x", expected), nil
}

func (a *App) QueueUpdate() error {
	select {
	case a.UpdateQueue <- "update":
		return nil
	default:
		return errors.New("Could not queue update for " + a.Name)
	}
}

func (a *App) LoopQueue() {
	for _ = range a.UpdateQueue {
		a.Update()
	}
}

func (a *App) Update() {
	log.Print("Running: ", a.Script)

	out, err := a.RunScript()
	if err != nil {
		log.Print("Failed: ", a.Script)
		log.Print("output: ", string(out))
		log.Print(err)
	}
}

func (a *App) RunScript() ([]byte, error) {
	c := exec.Command("/bin/sh", "-c", a.Script)
	return c.CombinedOutput()
}
<|endoftext|>


<commit_before>package jsh

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestObject(t *testing.T) {

	Convey("Object Tests", t, func() {

		testObject := &Object{
			ID:         "ID123",
			Type:       "testObject",
			Attributes: json.RawMessage(`{"foo":"bar"}`),
		}

		request := &http.Request{}

		Convey("->NewObject()", func() {

			Convey("should create a new object with populated attrs", func() {
				attrs := struct {
					Foo string `json:"foo"`
				}{"bar"}

				newObj, err := NewObject(testObject.ID, testObject.Type, attrs)
				So(err, ShouldBeNil)
				So(newObj.Attributes, ShouldNotBeEmpty)
			})
		})

		Convey("->Unmarshal()", func() {

			Convey("non-govalidator structs", func() {

				testConversion := struct {
					ID  string
					Foo string `json:"foo"`
				}{}

				Convey("Should successfully populate a valid struct", func() {
					err := testObject.Unmarshal("testObject", &testConversion)
					So(err, ShouldBeNil)
					So(testConversion.Foo, ShouldEqual, "bar")
				})

				Convey("Should reject a non-matching type", func() {
					err := testObject.Unmarshal("badType", &testConversion)
					So(err, ShouldNotBeNil)
				})

			})

			Convey("govalidator struct unmarshals", func() {

				Convey("should not error if input validates properly", func() {
					testValidation := struct {
						Foo string `json:"foo" valid:"alphanum"`
					}{}

					err := testObject.Unmarshal("testObject", &testValidation)
					So(err, ShouldBeNil)
					So(testValidation.Foo, ShouldEqual, "bar")
				})

				Convey("should return a 422 Error correctly for a validation failure", func() {
					testValidation := struct {
						Foo string `valid:"ipv4,required" json:"foo"`
					}{}

					err := testObject.Unmarshal("testObject", &testValidation)
					So(err, ShouldNotBeNil)
					So(err[0].Source, ShouldNotBeNil)
					So(err[0].Source.Pointer, ShouldEqual, "/data/attributes/foo")
				})

				Convey("should return a 422 Error correctly for multiple validation failures", func() {

					testManyObject := &Object{
						ID:         "ID123",
						Type:       "testObject",
						Attributes: json.RawMessage(`{"foo":"bar", "baz":"4567"}`),
					}

					testManyValidations := struct {
						Foo string `valid:"ipv4,required" json:"foo"`
						Baz string `valid:"alpha,required" json:"baz"`
					}{}

					err := testManyObject.Unmarshal("testObject", &testManyValidations)
					So(err, ShouldNotBeNil)

					So(err[0].Source, ShouldNotBeNil)
					So(err[0].Source.Pointer, ShouldEqual, "/data/attributes/foo")
					So(err[1].Source, ShouldNotBeNil)
					So(err[1].Source.Pointer, ShouldEqual, "/data/attributes/baz")
				})
			})
		})

		Convey("->Marshal()", func() {

			Convey("should properly update attributes", func() {
				attrs := map[string]string{"foo": "baz"}
				err := testObject.Marshal(attrs)
				So(err, ShouldBeNil)

				raw, jsonErr := json.MarshalIndent(attrs, "", " ")
				So(jsonErr, ShouldBeNil)
				So(string(testObject.Attributes), ShouldEqual, string(raw))
			})
		})

		Convey("->JSON()", func() {

			Convey("should handle a POST response correctly", func() {
				request.Method = "POST"
				err := testObject.Validate(request, true)
				So(err, ShouldBeNil)
				So(testObject.Status, ShouldEqual, http.StatusCreated)
			})

			Convey("should handle a GET response correctly", func() {
				request.Method = "GET"
				err := testObject.Validate(request, true)
				So(err, ShouldBeNil)
				So(testObject.Status, ShouldEqual, http.StatusOK)
			})

			Convey("should handle a PATCH response correctly", func() {
				request.Method = "PATCH"
				err := testObject.Validate(request, true)
				So(err, ShouldBeNil)
				So(testObject.Status, ShouldEqual, http.StatusOK)
			})

			Convey("should return a formatted Error for an unsupported method Type", func() {
				request.Method = "PUT"
				err := testObject.Validate(request, true)
				So(err, ShouldNotBeNil)
				So(err.Status, ShouldEqual, http.StatusNotAcceptable)
			})
		})

		Convey("->Send(Object)", func() {
			request.Method = "POST"
			writer := httptest.NewRecorder()
			err := Send(writer, request, testObject)
			So(err, ShouldBeNil)
			So(writer.Code, ShouldEqual, http.StatusCreated)
		})
	})
}
<commit_msg>Add spec tests for new feature<commit_after>package jsh

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestObject(t *testing.T) {

	Convey("Object Tests", t, func() {

		testObject := &Object{
			ID:         "ID123",
			Type:       "testObject",
			Attributes: json.RawMessage(`{"foo":"bar"}`),
		}

		request := &http.Request{}

		Convey("->NewObject()", func() {

			Convey("should create a new object with populated attrs", func() {
				attrs := struct {
					Foo string `json:"foo"`
				}{"bar"}

				newObj, err := NewObject(testObject.ID, testObject.Type, attrs)
				So(err, ShouldBeNil)
				So(newObj.Attributes, ShouldNotBeEmpty)
			})
		})

		Convey("->ProcessCreate()", func() {

			Convey("Should reject nil interface", func() {
				f, err := testObject.ProcessCreate("testObject", nil)
				So(err, ShouldNotBeNil)
				So(err, ShouldHaveLength, 1)
				So(f, ShouldBeNil)
			})

			Convey("Should reject non-pointer type", func() {
				f, err := testObject.ProcessCreate("testObject", "invalid type")
				So(err, ShouldNotBeNil)
				So(err, ShouldHaveLength, 1)
				So(f, ShouldBeNil)
			})

			Convey("Should reject pointers to non-struct types", func() {
				testConversion := "non-struct type"

				f, err := testObject.ProcessCreate("testObject", &testConversion)
				So(err, ShouldNotBeNil)
				So(err, ShouldHaveLength, 1)
				So(f, ShouldBeNil)
			})

			Convey("Should reject attributes with no jsh create tag", func() {
				testConversion := struct {
					Foo string `json:"foo"`
				}{}

				f, err := testObject.ProcessCreate("testObject", &testConversion)
				So(err, ShouldNotBeNil)
				So(err, ShouldHaveLength, 1)
				So(err[0].StatusCode(), ShouldEqual, http.StatusForbidden)
				So(err[0].Source, ShouldNotBeNil)
				So(err[0].Source.Pointer, ShouldEqual, "/data/attributes/foo")
				So(f, ShouldBeNil)
				// XXX: Foo == bar
			})

			Convey("Should reject attributes with invalid jsh tag", func() {
				testConversion := struct {
					Foo string `json:"foo" jsh:"invalid"`
				}{}

				f, err := testObject.ProcessCreate("testObject", &testConversion)
				So(err, ShouldNotBeNil)
				So(err, ShouldHaveLength, 1)
				So(err[0].StatusCode(), ShouldEqual, http.StatusForbidden)
				So(err[0].Source, ShouldNotBeNil)
				So(err[0].Source.Pointer, ShouldEqual, "/data/attributes/foo")
				So(f, ShouldBeNil)
				// XXX: Foo == bar
			})

			Convey("Should ignore attributes with json '-' tag", func() {
				testConversion := struct {
					Foo string `json:"-"`
				}{
					Foo: "shouldNotBeOverriden",
				}

				f, err := testObject.ProcessCreate("testObject", &testConversion)
				So(err, ShouldBeNil)
				So(f, ShouldBeEmpty)
				So(testConversion.Foo, ShouldEqual, "shouldNotBeOverriden")
			})

			Convey("Should accept attributes with jsh 'create' tag", func() {
				testConversion := struct {
					Foo string `json:"foo" jsh:"create"`
				}{
					Foo: "shouldBeOverriden",
				}

				f, err := testObject.ProcessCreate("testObject", &testConversion)
				So(err, ShouldBeNil)
				So(f, ShouldContain, "Foo")
				So(testConversion.Foo, ShouldEqual, "bar")
			})

			Convey("Should ignore private attributes", func() {
				testConversion := struct {
					foo string `json:"foo" jsh:"create"`
				}{
					foo: "shouldNotBeOverriden",
				}

				f, err := testObject.ProcessCreate("testObject", &testConversion)
				So(err, ShouldBeNil)
				So(f, ShouldBeEmpty)
				So(testConversion.foo, ShouldEqual, "shouldNotBeOverriden")
			})

			Convey("Should reject attributes with missing required field", func() {
				testConversion := struct {
					Foo string `json:"foo" jsh:"create/required"`
					Bar string `json:"bar" jsh:"create/required"`
				}{}

				f, err := testObject.ProcessCreate("testObject", &testConversion)
				So(err, ShouldNotBeNil)
				So(err, ShouldHaveLength, 1)
				So(err[0].StatusCode(), ShouldEqual, 422)
				So(err[0].Source, ShouldNotBeNil)
				So(err[0].Source.Pointer, ShouldEqual, "/data/attributes/bar")
				So(f, ShouldBeNil)
			})

			Convey("Should detect zero/non-zero value for all type kinds", func() {
				testConversion := struct {
					Foo       string         `json:"foo" jsh:"create"`
					Ptr       *string        `json:"ptr"`
					Array     [2]int         `json:"array"`
					Slice     []int          `json:"slice"`
					Map       map[string]int `json:"map"`
					Interface interface{}    `json:"interface"`
					Struct    struct {
						B bool `json:"b"`
						N int  `json:"n"`
					} `json:"struct"`
				}{}

				Convey("Should detect and ignore zero value for all type kinds", func() {
					f, err := testObject.ProcessCreate("testObject", &testConversion)
					So(err, ShouldBeNil)
					So(testConversion.Foo, ShouldEqual, "bar")
					So(f, ShouldContain, "Foo")
				})

				Convey("Should detect non-zero value for all type kinds", func() {
					var errlist ErrorList
					var attr string

					Convey("Should detect non-zero value for pointers", func() {
						str := "bar"
						attrs := struct {
							Ptr *string `json:"ptr"`
						}{&str}
						newObj, err := NewObject(testObject.ID, testObject.Type, attrs)
						So(err, ShouldBeNil)

						_, errlist = newObj.ProcessCreate("testObject", &testConversion)
						attr = "ptr"
					})

					Convey("Should detect non-zero value for arrays", func() {
						array := [2]int{0, 1}
						attrs := struct {
							Array [2]int `json:"array"`
						}{array}
						newObj, err := NewObject(testObject.ID, testObject.Type, attrs)
						So(err, ShouldBeNil)

						_, errlist = newObj.ProcessCreate("testObject", &testConversion)
						attr = "array"
					})

					Convey("Should detect non-zero value for slices", func() {
						slice := []int{0, 1}
						attrs := struct {
							Slice []int `json:"slice"`
						}{slice}
						newObj, err := NewObject(testObject.ID, testObject.Type, attrs)
						So(err, ShouldBeNil)

						_, errlist = newObj.ProcessCreate("testObject", &testConversion)
						attr = "slice"
					})

					Convey("Should detect non-zero value for maps", func() {
						m := map[string]int{"a": 0, "b": 1}
						attrs := struct {
							Map map[string]int `json:"map"`
						}{m}
						newObj, err := NewObject(testObject.ID, testObject.Type, attrs)
						So(err, ShouldBeNil)

						_, errlist = newObj.ProcessCreate("testObject", &testConversion)
						attr = "map"
					})

					Convey("Should detect non-zero value for interfaces", func() {
						i := struct{}{}
						attrs := struct {
							Interface interface{} `json:"interface"`
						}{i}
						newObj, err := NewObject(testObject.ID, testObject.Type, attrs)
						So(err, ShouldBeNil)

						_, errlist = newObj.ProcessCreate("testObject", &testConversion)
						attr = "interface"
					})

					So(errlist, ShouldNotBeNil)
					So(errlist, ShouldHaveLength, 1)
					So(errlist[0].StatusCode(), ShouldEqual, http.StatusForbidden)
					So(errlist[0].Source, ShouldNotBeNil)
					So(errlist[0].Source.Pointer, ShouldEqual, "/data/attributes/"+attr)
				})
			})
		})

		// ProcessUpdate has the same requirements than ProcessCreate plus a few specific ones
		Convey("->ProcessUpdate()", func() {

			Convey("Should reject different types", func() {
				f, err := testObject.ProcessUpdate("testObject", &struct{}{}, &struct{ int }{})
				So(err, ShouldNotBeNil)
				So(err, ShouldHaveLength, 1)
				So(f, ShouldBeNil)
			})

			Convey("Should accept nil model and simply validate fields", func() {
				f, err := testObject.ProcessUpdate("testObject", &struct{}{}, nil)
				So(err, ShouldBeNil)
				So(f, ShouldBeEmpty)
			})

			Convey("Should reject attributes with missing required field", func() {
				testConversion := [2]struct {
					Foo string `json:"foo" jsh:"update/required"`
					Bar string `json:"bar" jsh:"update/required"`
				}{}

				f, err := testObject.ProcessUpdate("testObject", &testConversion[0], &testConversion[1])
				So(err, ShouldNotBeNil)
				So(err, ShouldHaveLength, 1)
				So(err[0].StatusCode(), ShouldEqual, 422)
				So(err[0].Source, ShouldNotBeNil)
				So(err[0].Source.Pointer, ShouldEqual, "/data/attributes/bar")
				So(f, ShouldBeNil)
			})

			Convey("Should accept attribute with jsh 'update' tag", func() {
				testConversion := [2]struct {
					Foo string `json:"foo" jsh:"update"`
					Bar string `json:"bar" jsh:"update"`
				}{}
				f, err := testObject.ProcessUpdate("testObject", &testConversion[0], &testConversion[1])
				So(err, ShouldBeNil)
				So(f, ShouldHaveLength, 1)
				So(f, ShouldContain, "Foo")
				So(testConversion[1].Foo, ShouldEqual, "bar")
				So(testConversion[1].Bar, ShouldBeEmpty)
			})

			Convey("Should accept multiple attributes with jsh 'update' tag", func() {
				testConversion := [3]struct {
					Foo string  `json:"foo" jsh:"update"`
					Bar *string `json:"bar" jsh:"update"`
				}{}
				str := "foo"
				testConversion[0].Bar = &str
				testConversion[0].Foo = "bar"
				newObj, err := NewObject(testObject.ID, testObject.Type, &testConversion[0])
				So(err, ShouldBeNil)

				f, errlist := newObj.ProcessUpdate("testObject", &testConversion[1], &testConversion[2])
				So(errlist, ShouldBeNil)
				So(f, ShouldHaveLength, 2)
				So(f, ShouldContain, "Foo")
				So(f, ShouldContain, "Bar")
				So(testConversion[2].Foo, ShouldEqual, "bar")
				So(*testConversion[2].Bar, ShouldEqual, "foo")
			})
		})

		Convey("->Unmarshal()", func() {

			Convey("non-govalidator structs", func() {

				testConversion := struct {
					ID  string
					Foo string `json:"foo"`
				}{}

				Convey("Should successfully populate a valid struct", func() {
					err := testObject.Unmarshal("testObject", &testConversion)
					So(err, ShouldBeNil)
					So(testConversion.Foo, ShouldEqual, "bar")
				})

				Convey("Should reject a non-matching type", func() {
					err := testObject.Unmarshal("badType", &testConversion)
					So(err, ShouldNotBeNil)
				})

			})

			Convey("govalidator struct unmarshals", func() {

				Convey("should not error if input validates properly", func() {
					testValidation := struct {
						Foo string `json:"foo" valid:"alphanum"`
					}{}

					err := testObject.Unmarshal("testObject", &testValidation)
					So(err, ShouldBeNil)
					So(testValidation.Foo, ShouldEqual, "bar")
				})

				Convey("should return a 422 Error correctly for a validation failure", func() {
					testValidation := struct {
						Foo string `valid:"ipv4,required" json:"foo"`
					}{}

					err := testObject.Unmarshal("testObject", &testValidation)
					So(err, ShouldNotBeNil)
					So(err[0].Source, ShouldNotBeNil)
					So(err[0].Source.Pointer, ShouldEqual, "/data/attributes/foo")
				})

				Convey("should return a 422 Error correctly for multiple validation failures", func() {

					testManyObject := &Object{
						ID:         "ID123",
						Type:       "testObject",
						Attributes: json.RawMessage(`{"foo":"bar", "baz":"4567"}`),
					}

					testManyValidations := struct {
						Foo string `valid:"ipv4,required" json:"foo"`
						Baz string `valid:"alpha,required" json:"baz"`
					}{}

					err := testManyObject.Unmarshal("testObject", &testManyValidations)
					So(err, ShouldNotBeNil)

					So(err[0].Source, ShouldNotBeNil)
					So(err[0].Source.Pointer, ShouldEqual, "/data/attributes/foo")
					So(err[1].Source, ShouldNotBeNil)
					So(err[1].Source.Pointer, ShouldEqual, "/data/attributes/baz")
				})
			})
		})

		Convey("->Marshal()", func() {

			Convey("should properly update attributes", func() {
				attrs := map[string]string{"foo": "baz"}
				err := testObject.Marshal(attrs)
				So(err, ShouldBeNil)

				raw, jsonErr := json.MarshalIndent(attrs, "", " ")
				So(jsonErr, ShouldBeNil)
				So(string(testObject.Attributes), ShouldEqual, string(raw))
			})
		})

		Convey("->JSON()", func() {

			Convey("should handle a POST response correctly", func() {
				request.Method = "POST"
				err := testObject.Validate(request, true)
				So(err, ShouldBeNil)
				So(testObject.Status, ShouldEqual, http.StatusCreated)
			})

			Convey("should handle a GET response correctly", func() {
				request.Method = "GET"
				err := testObject.Validate(request, true)
				So(err, ShouldBeNil)
				So(testObject.Status, ShouldEqual, http.StatusOK)
			})

			Convey("should handle a PATCH response correctly", func() {
				request.Method = "PATCH"
				err := testObject.Validate(request, true)
				So(err, ShouldBeNil)
				So(testObject.Status, ShouldEqual, http.StatusOK)
			})

			Convey("should return a formatted Error for an unsupported method Type", func() {
				request.Method = "PUT"
				err := testObject.Validate(request, true)
				So(err, ShouldNotBeNil)
				So(err.Status, ShouldEqual, http.StatusNotAcceptable)
			})
		})

		Convey("->Send(Object)", func() {
			request.Method = "POST"
			writer := httptest.NewRecorder()
			err := Send(writer, request, testObject)
			So(err, ShouldBeNil)
			So(writer.Code, ShouldEqual, http.StatusCreated)
		})
	})
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
// Licensed under the Mozilla Public License v2.0

package oci

import (
	"log"
)

const Version = "3.81.0"

func PrintVersion() {
	log.Printf("[INFO] terraform-provider-oci %s\n", Version)
}
<commit_msg>Finalize changelog and release for version v3.82.0<commit_after>// Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
// Licensed under the Mozilla Public License v2.0

package oci

import (
	"log"
)

const Version = "3.82.0"

func PrintVersion() {
	log.Printf("[INFO] terraform-provider-oci %s\n", Version)
}
<|endoftext|>


<commit_before>package oembed

import (
	"encoding/json"
	"io"
	"io/ioutil"

	"github.com/jeffail/gabs"
)

// Info returns information for embedding website
type Info struct {
	Status          int    `json:"-"`
	Type            string `json:"type"`
	URL             string `json:"url"`
	ProviderURL     string `json:"provider_url"`
	ProviderName    string `json:"provider_name"`
	Title           string `json:"title"`
	Description     string `json:"description"`
	Width           uint64 `json:"width"`
	Height          uint64 `json:"height"`
	ThumbnailURL    string `json:"thumbnail_url"`
	ThumbnailWidth  uint64 `json:"thumbnail_width"`
	ThumbnailHeight uint64 `json:"thumbnail_height"`
	AuthorName      string `json:"author_name"`
	AuthorURL       string `json:"author_url"`
	HTML            string `json:"html"`
}

// NewInfo creater new instance of oembed.Info
func NewInfo() *Info {
	return &Info{}
}

// FillFromJSON fills the structure from provided Oembed JSON
func (info *Info) FillFromJSON(r io.Reader) error {
	data, err := ioutil.ReadAll(r)

	if err != nil {
		return err
	}

	// We are not using standard json parsing into struct mechanism because it sucks in real life..
	// when you expect a string some sites will return string, some will return null but some will return false
	// when you expect an integer, some will return integer, some will return string but some will return null or false..
	jsonParsed, err := gabs.ParseJSON(data)

	if err != nil {
		return err
	}

	var strVal string
	var intVal uint64
	var ok bool

	if strVal, ok = jsonParsed.Path("type").Data().(string); ok {
		info.Type = strVal
	}

	if strVal, ok = jsonParsed.Path("url").Data().(string); ok {
		info.URL = strVal
	}

	if strVal, ok = jsonParsed.Path("provider_url").Data().(string); ok {
		info.ProviderURL = strVal
	}

	if strVal, ok = jsonParsed.Path("provider_name").Data().(string); ok {
		info.ProviderName = strVal
	}

	if strVal, ok = jsonParsed.Path("title").Data().(string); ok {
		info.Title = strVal
	}

	if strVal, ok = jsonParsed.Path("description").Data().(string); ok {
		info.Description = strVal
	}

	if strVal, ok = jsonParsed.Path("thumbnail_url").Data().(string); ok {
		info.ThumbnailURL = strVal
	}

	if strVal, ok = jsonParsed.Path("author_name").Data().(string); ok {
		info.AuthorName = strVal
	}

	if strVal, ok = jsonParsed.Path("author_url").Data().(string); ok {
		info.AuthorURL = strVal
	}

	if strVal, ok = jsonParsed.Path("html").Data().(string); ok {
		info.HTML = strVal
	}

	if intVal, ok = jsonParsed.Path("width").Data().(uint64); ok {
		info.Width = intVal
	}

	if intVal, ok = jsonParsed.Path("height").Data().(uint64); ok {
		info.Height = intVal
	}

	if intVal, ok = jsonParsed.Path("thumbnail_width").Data().(uint64); ok {
		info.ThumbnailWidth = intVal
	}

	if intVal, ok = jsonParsed.Path("thumbnail_height").Data().(uint64); ok {
		info.ThumbnailHeight = intVal
	}

	return nil
}

// MergeWith adds missing data to the structure from another oembed.Info structure
func (info *Info) MergeWith(base *Info) {
	if len(info.Type) == 0 {
		info.Type = base.Type
	}
	if len(info.URL) == 0 {
		info.URL = base.URL
	}
	if len(info.ProviderURL) == 0 {
		info.ProviderURL = base.ProviderURL
	}
	if len(info.ProviderName) == 0 {
		info.ProviderName = base.ProviderName
	}
	if len(info.Title) == 0 {
		info.Title = base.Title
	}
	if len(info.Description) == 0 {
		info.Description = base.Description
	}
	if len(info.ThumbnailURL) == 0 {
		info.ThumbnailURL = base.ThumbnailURL
		info.ThumbnailWidth = base.ThumbnailWidth
		info.ThumbnailHeight = base.ThumbnailHeight
	}
}

// ToJSON a simple wrapper around json.Marshal
func (info *Info) ToJSON() ([]byte, error) {
	return json.Marshal(info)
}

// String return json representation of structure, or error string
func (info *Info) String() string {
	data, err := info.ToJSON()

	if err != nil {
		return err.Error()
	}

	return string(data[:])
}
<commit_msg>Minor fixes<commit_after>package oembed

import (
	"encoding/json"
	"io"

	"github.com/jeffail/gabs"
)

// Info returns information for embedding website
type Info struct {
	Status          int    `json:"-,omitempty"`
	Type            string `json:"type,omitempty"`
	CacheAge        int64  `json:"cache_age,omitempty"`
	URL             string `json:"url,omitempty"`
	ProviderURL     string `json:"provider_url,omitempty"`
	ProviderName    string `json:"provider_name,omitempty"`
	Title           string `json:"title,omitempty"`
	Description     string `json:"description,omitempty"`
	Width           int64  `json:"width,omitempty"`
	Height          int64  `json:"height,omitempty"`
	ThumbnailURL    string `json:"thumbnail_url,omitempty"`
	ThumbnailWidth  int64  `json:"thumbnail_width,omitempty"`
	ThumbnailHeight int64  `json:"thumbnail_height,omitempty"`
	AuthorName      string `json:"author_name,omitempty"`
	AuthorURL       string `json:"author_url,omitempty"`
	HTML            string `json:"html,omitempty"`
}

// NewInfo creater new instance of oembed.Info
func NewInfo() *Info {
	return &Info{}
}

// FillFromJSON fills the structure from provided Oembed JSON
func (info *Info) FillFromJSON(r io.Reader) error {
	data := json.NewDecoder(r)
	data.UseNumber()

	// We are not using standard json parsing into struct mechanism because it sucks in real life..
	// when you expect a string some sites will return string, some will return null but some will return false
	// when you expect an integer, some will return integer, some will return string but some will return null or false..
	jsonParsed, err := gabs.ParseJSONDecoder(data)

	if err != nil {
		return err
	}

	var strVal string
	var jsonNumberVal json.Number
	var jsonNumber int64
	var ok bool

	if strVal, ok = jsonParsed.Path("type").Data().(string); ok {
		info.Type = strVal
	}

	if jsonNumberVal, ok = jsonParsed.Path("cache_age").Data().(json.Number); ok {
		if jsonNumber, err = jsonNumberVal.Int64(); err != nil {
			return err
		}
		info.CacheAge = jsonNumber
	}

	if strVal, ok = jsonParsed.Path("url").Data().(string); ok {
		info.URL = strVal
	}

	if strVal, ok = jsonParsed.Path("provider_url").Data().(string); ok {
		info.ProviderURL = strVal
	}

	if strVal, ok = jsonParsed.Path("provider_name").Data().(string); ok {
		info.ProviderName = strVal
	}

	if strVal, ok = jsonParsed.Path("title").Data().(string); ok {
		info.Title = strVal
	}

	if strVal, ok = jsonParsed.Path("description").Data().(string); ok {
		info.Description = strVal
	}

	if strVal, ok = jsonParsed.Path("summary").Data().(string); ok {
		info.Description = strVal // stupid nyt oembed uses summary not description
	}

	if strVal, ok = jsonParsed.Path("thumbnail_url").Data().(string); ok {
		info.ThumbnailURL = strVal
	}

	if strVal, ok = jsonParsed.Path("author_name").Data().(string); ok {
		info.AuthorName = strVal
	}

	if strVal, ok = jsonParsed.Path("author_url").Data().(string); ok {
		info.AuthorURL = strVal
	}

	if strVal, ok = jsonParsed.Path("html").Data().(string); ok {
		info.HTML = strVal
	}

	if jsonNumberVal, ok = jsonParsed.Path("width").Data().(json.Number); ok {
		if jsonNumber, err = jsonNumberVal.Int64(); err != nil {
			return err
		}
		info.Width = jsonNumber
	}

	if jsonNumberVal, ok = jsonParsed.Path("height").Data().(json.Number); ok {
		if jsonNumber, err = jsonNumberVal.Int64(); err != nil {
			return err
		}
		info.Height = jsonNumber
	}

	if jsonNumberVal, ok = jsonParsed.Path("thumbnail_width").Data().(json.Number); ok {
		if jsonNumber, err = jsonNumberVal.Int64(); err != nil {
			return err
		}
		info.ThumbnailWidth = jsonNumber
	}

	if jsonNumberVal, ok = jsonParsed.Path("thumbnail_height").Data().(json.Number); ok {
		if jsonNumber, err = jsonNumberVal.Int64(); err != nil {
			return err
		}
		info.ThumbnailHeight = jsonNumber
	}

	return nil
}

// MergeWith adds missing data to the structure from another oembed.Info structure
func (info *Info) MergeWith(base *Info) {
	if len(info.Type) == 0 {
		info.Type = base.Type
	}
	if len(info.URL) == 0 {
		info.URL = base.URL
	}
	if len(info.ProviderURL) == 0 {
		info.ProviderURL = base.ProviderURL
	}
	if len(info.ProviderName) == 0 {
		info.ProviderName = base.ProviderName
	}
	if len(info.Title) == 0 {
		info.Title = base.Title
	}
	if len(info.Description) == 0 {
		info.Description = base.Description
	}
	if len(info.ThumbnailURL) == 0 {
		info.ThumbnailURL = base.ThumbnailURL
		info.ThumbnailWidth = base.ThumbnailWidth
		info.ThumbnailHeight = base.ThumbnailHeight
	}
}

// ToJSON a simple wrapper around json.Marshal
func (info *Info) ToJSON() ([]byte, error) {
	return json.Marshal(info)
}

// String return json representation of structure, or error string
func (info *Info) String() string {
	data, err := info.ToJSON()

	if err != nil {
		return err.Error()
	}

	return string(data[:])
}
<|endoftext|>