<commit_before>// Package mdata stands for "managed data" or "metrics data" if you will
// it has all the stuff to keep metric data in memory, store it, and synchronize
// save states over the network
package mdata

import (
	"flag"
	"io/ioutil"

	"github.com/raintank/metrictank/conf"
	"github.com/raintank/metrictank/stats"
	"github.com/raintank/worldping-api/pkg/log"
	"github.com/rakyll/globalconf"
)

var (
	LogLevel int

	// metric tank.chunk_operations.create is a counter of how many chunks are created
	chunkCreate = stats.NewCounter32("tank.chunk_operations.create")

	// metric tank.chunk_operations.clear is a counter of how many chunks are cleared (replaced by new chunks)
	chunkClear = stats.NewCounter32("tank.chunk_operations.clear")

	// metric tank.metrics_too_old is points that go back in time.
	// E.g. for any given series, when a point has a timestamp
	// that is not higher than the timestamp of the last written timestamp for that series.
	metricsTooOld = stats.NewCounter32("tank.metrics_too_old")

	// metric tank.add_to_closed_chunk is points received for the most recent chunk
	// when that chunk is already being "closed", ie the end-of-stream marker has been written to the chunk.
	// this indicates that your GC is actively sealing chunks and saving them before you have the chance to send
	// your (infrequent) updates.  Any points revcieved for a chunk that has already been closed are discarded.
	addToClosedChunk = stats.NewCounter32("tank.add_to_closed_chunk")

	// metric mem.to_iter is how long it takes to transform in-memory chunks to iterators
	memToIterDuration = stats.NewLatencyHistogram15s32("mem.to_iter")

	// metric tank.persist is how long it takes to persist a chunk (and chunks preceding it)
	// this is subject to backpressure from the store when the store's queue runs full
	persistDuration = stats.NewLatencyHistogram15s32("tank.persist")

	// metric tank.metrics_active is the number of currently known metrics (excl rollup series), measured every second
	metricsActive = stats.NewGauge32("tank.metrics_active")

	// metric tank.gc_metric is the number of times the metrics GC is about to inspect a metric (series)
	gcMetric = stats.NewCounter32("tank.gc_metric")

	// set either via ConfigProcess or from the unit tests. other code should not touch
	Schemas      conf.Schemas
	Aggregations conf.Aggregations

	schemasFile = "/etc/metrictank/storage-schemas.conf"
	aggFile     = "/etc/metrictank/storage-aggregation.conf"
)

func ConfigSetup() {
	retentionConf := flag.NewFlagSet("retention", flag.ExitOnError)
	retentionConf.StringVar(&schemasFile, "schemas-file", "/etc/metrictank/storage-schemas.conf", "path to storage-schemas.conf file")
	retentionConf.StringVar(&aggFile, "aggrgations-file", "/etc/metrictank/storage-aggregation.conf", "path to storage-aggregation.conf file")
	globalconf.Register("retention", retentionConf)
}

func ConfigProcess() {
	var err error

	// === read storage-schemas.conf ===

	// graphite behavior: abort on any config reading errors, but skip any rules that have problems.
	// at the end, add a default schema of 7 days of minutely data.
	// we are stricter and don't tolerate any errors, that seems in the user's best interest.

	Schemas, err = conf.ReadSchemas(schemasFile)
	if err != nil {
		log.Fatal(3, "can't read schemas file %q: %s", schemasFile, err.Error())
	}

	// === read storage-aggregation.conf ===

	// graphite behavior:
	// continue if file can't be read. (e.g. file is optional) but quit if other error reading config
	// always add a default rule with xFilesFactor None and aggregationMethod None
	// (which get interpreted by whisper as 0.5 and avg) at the end.

	// since we can't distinguish errors reading vs parsing, we'll just try a read separately first
	_, err = ioutil.ReadFile(aggFile)
	if err == nil {
		Aggregations, err = conf.ReadAggregations(aggFile)
		if err != nil {
			log.Fatal(3, "can't read storage-aggregation file %q: %s", aggFile, err.Error())
		}
	} else {
		log.Info("Could not read %s: %s: using defaults", aggFile, err)
		Aggregations = conf.NewAggregations()
	}
}
<commit_msg>fix parameter name of storage-aggregations file.<commit_after>// Package mdata stands for "managed data" or "metrics data" if you will
// it has all the stuff to keep metric data in memory, store it, and synchronize
// save states over the network
package mdata

import (
	"flag"
	"io/ioutil"

	"github.com/raintank/metrictank/conf"
	"github.com/raintank/metrictank/stats"
	"github.com/raintank/worldping-api/pkg/log"
	"github.com/rakyll/globalconf"
)

var (
	LogLevel int

	// metric tank.chunk_operations.create is a counter of how many chunks are created
	chunkCreate = stats.NewCounter32("tank.chunk_operations.create")

	// metric tank.chunk_operations.clear is a counter of how many chunks are cleared (replaced by new chunks)
	chunkClear = stats.NewCounter32("tank.chunk_operations.clear")

	// metric tank.metrics_too_old is points that go back in time.
	// E.g. for any given series, when a point has a timestamp
	// that is not higher than the timestamp of the last written timestamp for that series.
	metricsTooOld = stats.NewCounter32("tank.metrics_too_old")

	// metric tank.add_to_closed_chunk is points received for the most recent chunk
	// when that chunk is already being "closed", ie the end-of-stream marker has been written to the chunk.
	// this indicates that your GC is actively sealing chunks and saving them before you have the chance to send
	// your (infrequent) updates.  Any points revcieved for a chunk that has already been closed are discarded.
	addToClosedChunk = stats.NewCounter32("tank.add_to_closed_chunk")

	// metric mem.to_iter is how long it takes to transform in-memory chunks to iterators
	memToIterDuration = stats.NewLatencyHistogram15s32("mem.to_iter")

	// metric tank.persist is how long it takes to persist a chunk (and chunks preceding it)
	// this is subject to backpressure from the store when the store's queue runs full
	persistDuration = stats.NewLatencyHistogram15s32("tank.persist")

	// metric tank.metrics_active is the number of currently known metrics (excl rollup series), measured every second
	metricsActive = stats.NewGauge32("tank.metrics_active")

	// metric tank.gc_metric is the number of times the metrics GC is about to inspect a metric (series)
	gcMetric = stats.NewCounter32("tank.gc_metric")

	// set either via ConfigProcess or from the unit tests. other code should not touch
	Schemas      conf.Schemas
	Aggregations conf.Aggregations

	schemasFile = "/etc/metrictank/storage-schemas.conf"
	aggFile     = "/etc/metrictank/storage-aggregation.conf"
)

func ConfigSetup() {
	retentionConf := flag.NewFlagSet("retention", flag.ExitOnError)
	retentionConf.StringVar(&schemasFile, "schemas-file", "/etc/metrictank/storage-schemas.conf", "path to storage-schemas.conf file")
	retentionConf.StringVar(&aggFile, "aggregations-file", "/etc/metrictank/storage-aggregation.conf", "path to storage-aggregation.conf file")
	globalconf.Register("retention", retentionConf)
}

func ConfigProcess() {
	var err error

	// === read storage-schemas.conf ===

	// graphite behavior: abort on any config reading errors, but skip any rules that have problems.
	// at the end, add a default schema of 7 days of minutely data.
	// we are stricter and don't tolerate any errors, that seems in the user's best interest.

	Schemas, err = conf.ReadSchemas(schemasFile)
	if err != nil {
		log.Fatal(3, "can't read schemas file %q: %s", schemasFile, err.Error())
	}

	// === read storage-aggregation.conf ===

	// graphite behavior:
	// continue if file can't be read. (e.g. file is optional) but quit if other error reading config
	// always add a default rule with xFilesFactor None and aggregationMethod None
	// (which get interpreted by whisper as 0.5 and avg) at the end.

	// since we can't distinguish errors reading vs parsing, we'll just try a read separately first
	_, err = ioutil.ReadFile(aggFile)
	if err == nil {
		Aggregations, err = conf.ReadAggregations(aggFile)
		if err != nil {
			log.Fatal(3, "can't read storage-aggregation file %q: %s", aggFile, err.Error())
		}
	} else {
		log.Info("Could not read %s: %s: using defaults", aggFile, err)
		Aggregations = conf.NewAggregations()
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Dario Castañé. All rights reserved.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mergo

import (
	"gopkg.in/yaml.v1"
	"io/ioutil"
	"reflect"
	"testing"
)

type simpleTest struct {
	Value int
}

type complexTest struct {
	St simpleTest
	sz int
	Id string
}

type moreComplextText struct {
	Ct complexTest
	St simpleTest
	Nt simpleTest
}

type pointerTest struct {
	C *simpleTest
}

type sliceTest struct {
	S []int
}

func TestNil(t *testing.T) {
	if err := Merge(nil, nil); err != ErrNilArguments {
		t.Fail()
	}
}

func TestDifferentTypes(t *testing.T) {
	a := simpleTest{42}
	b := 42
	if err := Merge(&a, b); err != ErrDifferentArgumentsTypes {
		t.Fail()
	}
}

func TestSimpleStruct(t *testing.T) {
	a := simpleTest{}
	b := simpleTest{42}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if a.Value != 42 {
		t.Fatalf("b not merged in a properly: a.Value(%d) != b.Value(%d)", a.Value, b.Value)
	}
	if !reflect.DeepEqual(a, b) {
		t.FailNow()
	}
}

func TestComplexStruct(t *testing.T) {
	a := complexTest{}
	a.Id = "athing"
	b := complexTest{simpleTest{42}, 1, "bthing"}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if a.St.Value != 42 {
		t.Fatalf("b not merged in a properly: a.St.Value(%d) != b.St.Value(%d)", a.St.Value, b.St.Value)
	}
	if a.sz == 1 {
		t.Fatalf("a's private field sz not preserved from merge: a.sz(%d) == b.sz(%d)", a.sz, b.sz)
	}
	if a.Id != b.Id {
		t.Fatalf("a's field Id not merged properly: a.Id(%s) != b.Id(%s)", a.Id, b.Id)
	}
}

func TestComplexStructWithOverwrite(t *testing.T) {
	a := complexTest{simpleTest{1}, 1, "do-not-overwrite-with-empty-value"}
	b := complexTest{simpleTest{42}, 2, ""}

	expect := complexTest{simpleTest{42}, 1, "do-not-overwrite-with-empty-value"}
	if err := MergeWithOverwrite(&a, b); err != nil {
		t.FailNow()
	}

	if !reflect.DeepEqual(a, expect) {
		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", a, expect)
	}
}

func TestPointerStruct(t *testing.T) {
	s1 := simpleTest{}
	s2 := simpleTest{19}
	a := pointerTest{&s1}
	b := pointerTest{&s2}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if a.C.Value != b.C.Value {
		//t.Fatalf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
	}
}

type embeddingStruct struct {
	embeddedStruct
}

type embeddedStruct struct {
	A string
}

func TestEmbeddedStruct(t *testing.T) {
	tests := []struct {
		src      embeddingStruct
		dst      embeddingStruct
		expected embeddingStruct
	}{
		{
			src: embeddingStruct{
				embeddedStruct{"foo"},
			},
			dst: embeddingStruct{
				embeddedStruct{""},
			},
			expected: embeddingStruct{
				embeddedStruct{"foo"},
			},
		},
		{
			src: embeddingStruct{
				embeddedStruct{""},
			},
			dst: embeddingStruct{
				embeddedStruct{"bar"},
			},
			expected: embeddingStruct{
				embeddedStruct{"bar"},
			},
		},
		{
			src: embeddingStruct{
				embeddedStruct{"foo"},
			},
			dst: embeddingStruct{
				embeddedStruct{"bar"},
			},
			expected: embeddingStruct{
				embeddedStruct{"bar"},
			},
		},
	}

	for _, test := range tests {
		err := Merge(&test.dst, test.src)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		if !reflect.DeepEqual(test.dst, test.expected) {
			t.Errorf("unexpected output\nexpected:\n%+v\nsaw:\n%+v\n", test.expected, test.dst)
		}
	}
}

func TestPointerStructNil(t *testing.T) {
	a := pointerTest{nil}
	b := pointerTest{&simpleTest{19}}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if a.C.Value != b.C.Value {
		t.Fatalf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
	}
}

func TestSliceStruct(t *testing.T) {
	a := sliceTest{}
	b := sliceTest{[]int{1, 2, 3}}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if len(b.S) != 3 {
		t.FailNow()
	}
	if len(a.S) != len(b.S) {
		t.Fatalf("b not merged in a properly %d != %d", len(a.S), len(b.S))
	}

	a = sliceTest{[]int{1}}
	b = sliceTest{[]int{1, 2, 3}}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if len(b.S) != 3 {
		t.FailNow()
	}
	if len(a.S) != len(b.S) {
		t.Fatalf("b not merged in a properly %d != %d", len(a.S), len(b.S))
	}
}

func TestMapsWithOverwrite(t *testing.T) {
	m := map[string]simpleTest{
		"a": simpleTest{},   // overwritten by 16
		"b": simpleTest{42}, // not overwritten by empty value
		"c": simpleTest{13}, // overwritten by 12
		"d": simpleTest{61},
	}
	n := map[string]simpleTest{
		"a": simpleTest{16},
		"b": simpleTest{},
		"c": simpleTest{12},
		"e": simpleTest{14},
	}
	expect := map[string]simpleTest{
		"a": simpleTest{16},
		"b": simpleTest{},
		"c": simpleTest{12},
		"d": simpleTest{61},
		"e": simpleTest{14},
	}

	if err := MergeWithOverwrite(&m, n); err != nil {
		t.Fatalf(err.Error())
	}

	if !reflect.DeepEqual(m, expect) {
		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
	}
}

func TestMaps(t *testing.T) {
	m := map[string]simpleTest{
		"a": simpleTest{},
		"b": simpleTest{42},
		"c": simpleTest{13},
		"d": simpleTest{61},
	}
	n := map[string]simpleTest{
		"a": simpleTest{16},
		"b": simpleTest{},
		"c": simpleTest{12},
		"e": simpleTest{14},
	}
	expect := map[string]simpleTest{
		"a": simpleTest{0},
		"b": simpleTest{42},
		"c": simpleTest{13},
		"d": simpleTest{61},
		"e": simpleTest{14},
	}

	if err := Merge(&m, n); err != nil {
		t.Fatalf(err.Error())
	}

	if !reflect.DeepEqual(m, expect) {
		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
	}
	if m["a"].Value != 0 {
		t.Fatalf(`n merged in m because I solved non-addressable map values TODO: m["a"].Value(%d) != n["a"].Value(%d)`, m["a"].Value, n["a"].Value)
	}
	if m["b"].Value != 42 {
		t.Fatalf(`n wrongly merged in m: m["b"].Value(%d) != n["b"].Value(%d)`, m["b"].Value, n["b"].Value)
	}
	if m["c"].Value != 13 {
		t.Fatalf(`n overwritten in m: m["c"].Value(%d) != n["c"].Value(%d)`, m["c"].Value, n["c"].Value)
	}
}

func TestYAMLMaps(t *testing.T) {
	thing := loadYAML("testdata/thing.yml")
	license := loadYAML("testdata/license.yml")
	ft := thing["fields"].(map[interface{}]interface{})
	fl := license["fields"].(map[interface{}]interface{})
	expectedLength := len(ft) + len(fl)
	if err := Merge(&license, thing); err != nil {
		t.Fatal(err.Error())
	}
	currentLength := len(license["fields"].(map[interface{}]interface{}))
	if currentLength != expectedLength {
		t.Fatalf(`thing not merged in license properly, license must have %d elements instead of %d`, expectedLength, currentLength)
	}
	fields := license["fields"].(map[interface{}]interface{})
	if _, ok := fields["id"]; !ok {
		t.Fatalf(`thing not merged in license properly, license must have a new id field from thing`)
	}
}

func TestTwoPointerValues(t *testing.T) {
	a := &simpleTest{}
	b := &simpleTest{42}
	if err := Merge(a, b); err != nil {
		t.Fatalf(`Boom. You crossed the streams: %s`, err)
	}
}

func TestMap(t *testing.T) {
	a := complexTest{}
	a.Id = "athing"
	c := moreComplextText{a, simpleTest{}, simpleTest{}}
	b := map[string]interface{}{
		"ct": map[string]interface{}{
			"st": map[string]interface{}{
				"value": 42,
			},
			"sz": 1,
			"id": "bthing",
		},
		"st": &simpleTest{144}, // Mapping a reference
		"zt": simpleTest{299},  // Mapping a missing field (zt doesn't exist)
		"nt": simpleTest{3},
	}
	if err := Map(&c, b); err != nil {
		t.FailNow()
	}
	m := b["ct"].(map[string]interface{})
	n := m["st"].(map[string]interface{})
	o := b["st"].(*simpleTest)
	p := b["nt"].(simpleTest)
	if c.Ct.St.Value != 42 {
		t.Fatalf("b not merged in a properly: c.Ct.St.Value(%d) != b.Ct.St.Value(%d)", c.Ct.St.Value, n["value"])
	}
	if c.St.Value != 144 {
		t.Fatalf("b not merged in a properly: c.St.Value(%d) != b.St.Value(%d)", c.St.Value, o.Value)
	}
	if c.Nt.Value != 3 {
		t.Fatalf("b not merged in a properly: c.Nt.Value(%d) != b.Nt.Value(%d)", c.St.Value, p.Value)
	}
	if c.Ct.sz == 1 {
		t.Fatalf("a's private field sz not preserved from merge: c.Ct.sz(%d) == b.Ct.sz(%d)", c.Ct.sz, m["sz"])
	}
	if c.Ct.Id != m["id"] {
		t.Fatalf("a's field Id not merged properly: c.Ct.Id(%s) != b.Ct.Id(%s)", c.Ct.Id, m["id"])
	}
}

func TestSimpleMap(t *testing.T) {
	a := simpleTest{}
	b := map[string]interface{}{
		"value": 42,
	}
	if err := Map(&a, b); err != nil {
		t.FailNow()
	}
	if a.Value != 42 {
		t.Fatalf("b not merged in a properly: a.Value(%d) != b.Value(%v)", a.Value, b["value"])
	}
}

type pointerMapTest struct {
	A      int
	hidden int
	B      *simpleTest
}

func TestBackAndForth(t *testing.T) {
	pt := pointerMapTest{42, 1, &simpleTest{66}}
	m := make(map[string]interface{})
	if err := Map(&m, pt); err != nil {
		t.FailNow()
	}
	var (
		v  interface{}
		ok bool
	)
	if v, ok = m["a"]; v.(int) != pt.A || !ok {
		t.Fatalf("pt not merged properly: m[`a`](%d) != pt.A(%d)", v, pt.A)
	}
	if v, ok = m["b"]; !ok {
		t.Fatalf("pt not merged properly: B is missing in m")
	}
	var st *simpleTest
	if st = v.(*simpleTest); st.Value != 66 {
		t.Fatalf("something went wrong while mapping pt on m, B wasn't copied")
	}
	bpt := pointerMapTest{}
	if err := Map(&bpt, m); err != nil {
		t.Fatal(err)
	}
	if bpt.A != pt.A {
		t.Fatalf("pt not merged properly: bpt.A(%d) != pt.A(%d)", bpt.A, pt.A)
	}
	if bpt.hidden == pt.hidden {
		t.Fatalf("pt unexpectedly merged: bpt.hidden(%d) == pt.hidden(%d)", bpt.hidden, pt.hidden)
	}
	if bpt.B.Value != pt.B.Value {
		t.Fatalf("pt not merged properly: bpt.B.Value(%d) != pt.B.Value(%d)", bpt.B.Value, pt.B.Value)
	}
}

func loadYAML(path string) (m map[string]interface{}) {
	m = make(map[string]interface{})
	raw, _ := ioutil.ReadFile(path)
	_ = yaml.Unmarshal(raw, &m)
	return
}
<commit_msg>Previous test was based in a lil' misconception.<commit_after>// Copyright 2013 Dario Castañé. All rights reserved.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mergo

import (
	"gopkg.in/yaml.v1"
	"io/ioutil"
	"reflect"
	"testing"
)

type simpleTest struct {
	Value int
}

type complexTest struct {
	St simpleTest
	sz int
	Id string
}

type moreComplextText struct {
	Ct complexTest
	St simpleTest
	Nt simpleTest
}

type pointerTest struct {
	C *simpleTest
}

type sliceTest struct {
	S []int
}

func TestNil(t *testing.T) {
	if err := Merge(nil, nil); err != ErrNilArguments {
		t.Fail()
	}
}

func TestDifferentTypes(t *testing.T) {
	a := simpleTest{42}
	b := 42
	if err := Merge(&a, b); err != ErrDifferentArgumentsTypes {
		t.Fail()
	}
}

func TestSimpleStruct(t *testing.T) {
	a := simpleTest{}
	b := simpleTest{42}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if a.Value != 42 {
		t.Fatalf("b not merged in a properly: a.Value(%d) != b.Value(%d)", a.Value, b.Value)
	}
	if !reflect.DeepEqual(a, b) {
		t.FailNow()
	}
}

func TestComplexStruct(t *testing.T) {
	a := complexTest{}
	a.Id = "athing"
	b := complexTest{simpleTest{42}, 1, "bthing"}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if a.St.Value != 42 {
		t.Fatalf("b not merged in a properly: a.St.Value(%d) != b.St.Value(%d)", a.St.Value, b.St.Value)
	}
	if a.sz == 1 {
		t.Fatalf("a's private field sz not preserved from merge: a.sz(%d) == b.sz(%d)", a.sz, b.sz)
	}
	if a.Id != b.Id {
		t.Fatalf("a's field Id not merged properly: a.Id(%s) != b.Id(%s)", a.Id, b.Id)
	}
}

func TestComplexStructWithOverwrite(t *testing.T) {
	a := complexTest{simpleTest{1}, 1, "do-not-overwrite-with-empty-value"}
	b := complexTest{simpleTest{42}, 2, ""}

	expect := complexTest{simpleTest{42}, 1, "do-not-overwrite-with-empty-value"}
	if err := MergeWithOverwrite(&a, b); err != nil {
		t.FailNow()
	}

	if !reflect.DeepEqual(a, expect) {
		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", a, expect)
	}
}

func TestPointerStruct(t *testing.T) {
	s1 := simpleTest{}
	s2 := simpleTest{19}
	a := pointerTest{&s1}
	b := pointerTest{&s2}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if a.C.Value != b.C.Value {
		//t.Fatalf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
	}
}

type embeddingStruct struct {
	embeddedStruct
}

type embeddedStruct struct {
	A string
}

func TestEmbeddedStruct(t *testing.T) {
	tests := []struct {
		src      embeddingStruct
		dst      embeddingStruct
		expected embeddingStruct
	}{
		{
			src: embeddingStruct{
				embeddedStruct{"foo"},
			},
			dst: embeddingStruct{
				embeddedStruct{""},
			},
			expected: embeddingStruct{
				embeddedStruct{"foo"},
			},
		},
		{
			src: embeddingStruct{
				embeddedStruct{""},
			},
			dst: embeddingStruct{
				embeddedStruct{"bar"},
			},
			expected: embeddingStruct{
				embeddedStruct{"bar"},
			},
		},
		{
			src: embeddingStruct{
				embeddedStruct{"foo"},
			},
			dst: embeddingStruct{
				embeddedStruct{"bar"},
			},
			expected: embeddingStruct{
				embeddedStruct{"foo"},
			},
		},
	}

	for _, test := range tests {
		err := Merge(&test.dst, test.src)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		if !reflect.DeepEqual(test.dst, test.expected) {
			t.Errorf("unexpected output\nexpected:\n%+v\nsaw:\n%+v\n", test.expected, test.dst)
		}
	}
}

func TestPointerStructNil(t *testing.T) {
	a := pointerTest{nil}
	b := pointerTest{&simpleTest{19}}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if a.C.Value != b.C.Value {
		t.Fatalf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value)
	}
}

func TestSliceStruct(t *testing.T) {
	a := sliceTest{}
	b := sliceTest{[]int{1, 2, 3}}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if len(b.S) != 3 {
		t.FailNow()
	}
	if len(a.S) != len(b.S) {
		t.Fatalf("b not merged in a properly %d != %d", len(a.S), len(b.S))
	}

	a = sliceTest{[]int{1}}
	b = sliceTest{[]int{1, 2, 3}}
	if err := Merge(&a, b); err != nil {
		t.FailNow()
	}
	if len(b.S) != 3 {
		t.FailNow()
	}
	if len(a.S) != len(b.S) {
		t.Fatalf("b not merged in a properly %d != %d", len(a.S), len(b.S))
	}
}

func TestMapsWithOverwrite(t *testing.T) {
	m := map[string]simpleTest{
		"a": simpleTest{},   // overwritten by 16
		"b": simpleTest{42}, // not overwritten by empty value
		"c": simpleTest{13}, // overwritten by 12
		"d": simpleTest{61},
	}
	n := map[string]simpleTest{
		"a": simpleTest{16},
		"b": simpleTest{},
		"c": simpleTest{12},
		"e": simpleTest{14},
	}
	expect := map[string]simpleTest{
		"a": simpleTest{16},
		"b": simpleTest{},
		"c": simpleTest{12},
		"d": simpleTest{61},
		"e": simpleTest{14},
	}

	if err := MergeWithOverwrite(&m, n); err != nil {
		t.Fatalf(err.Error())
	}

	if !reflect.DeepEqual(m, expect) {
		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
	}
}

func TestMaps(t *testing.T) {
	m := map[string]simpleTest{
		"a": simpleTest{},
		"b": simpleTest{42},
		"c": simpleTest{13},
		"d": simpleTest{61},
	}
	n := map[string]simpleTest{
		"a": simpleTest{16},
		"b": simpleTest{},
		"c": simpleTest{12},
		"e": simpleTest{14},
	}
	expect := map[string]simpleTest{
		"a": simpleTest{0},
		"b": simpleTest{42},
		"c": simpleTest{13},
		"d": simpleTest{61},
		"e": simpleTest{14},
	}

	if err := Merge(&m, n); err != nil {
		t.Fatalf(err.Error())
	}

	if !reflect.DeepEqual(m, expect) {
		t.Fatalf("Test failed:\ngot  :\n%#v\n\nwant :\n%#v\n\n", m, expect)
	}
	if m["a"].Value != 0 {
		t.Fatalf(`n merged in m because I solved non-addressable map values TODO: m["a"].Value(%d) != n["a"].Value(%d)`, m["a"].Value, n["a"].Value)
	}
	if m["b"].Value != 42 {
		t.Fatalf(`n wrongly merged in m: m["b"].Value(%d) != n["b"].Value(%d)`, m["b"].Value, n["b"].Value)
	}
	if m["c"].Value != 13 {
		t.Fatalf(`n overwritten in m: m["c"].Value(%d) != n["c"].Value(%d)`, m["c"].Value, n["c"].Value)
	}
}

func TestYAMLMaps(t *testing.T) {
	thing := loadYAML("testdata/thing.yml")
	license := loadYAML("testdata/license.yml")
	ft := thing["fields"].(map[interface{}]interface{})
	fl := license["fields"].(map[interface{}]interface{})
	expectedLength := len(ft) + len(fl)
	if err := Merge(&license, thing); err != nil {
		t.Fatal(err.Error())
	}
	currentLength := len(license["fields"].(map[interface{}]interface{}))
	if currentLength != expectedLength {
		t.Fatalf(`thing not merged in license properly, license must have %d elements instead of %d`, expectedLength, currentLength)
	}
	fields := license["fields"].(map[interface{}]interface{})
	if _, ok := fields["id"]; !ok {
		t.Fatalf(`thing not merged in license properly, license must have a new id field from thing`)
	}
}

func TestTwoPointerValues(t *testing.T) {
	a := &simpleTest{}
	b := &simpleTest{42}
	if err := Merge(a, b); err != nil {
		t.Fatalf(`Boom. You crossed the streams: %s`, err)
	}
}

func TestMap(t *testing.T) {
	a := complexTest{}
	a.Id = "athing"
	c := moreComplextText{a, simpleTest{}, simpleTest{}}
	b := map[string]interface{}{
		"ct": map[string]interface{}{
			"st": map[string]interface{}{
				"value": 42,
			},
			"sz": 1,
			"id": "bthing",
		},
		"st": &simpleTest{144}, // Mapping a reference
		"zt": simpleTest{299},  // Mapping a missing field (zt doesn't exist)
		"nt": simpleTest{3},
	}
	if err := Map(&c, b); err != nil {
		t.FailNow()
	}
	m := b["ct"].(map[string]interface{})
	n := m["st"].(map[string]interface{})
	o := b["st"].(*simpleTest)
	p := b["nt"].(simpleTest)
	if c.Ct.St.Value != 42 {
		t.Fatalf("b not merged in a properly: c.Ct.St.Value(%d) != b.Ct.St.Value(%d)", c.Ct.St.Value, n["value"])
	}
	if c.St.Value != 144 {
		t.Fatalf("b not merged in a properly: c.St.Value(%d) != b.St.Value(%d)", c.St.Value, o.Value)
	}
	if c.Nt.Value != 3 {
		t.Fatalf("b not merged in a properly: c.Nt.Value(%d) != b.Nt.Value(%d)", c.St.Value, p.Value)
	}
	if c.Ct.sz == 1 {
		t.Fatalf("a's private field sz not preserved from merge: c.Ct.sz(%d) == b.Ct.sz(%d)", c.Ct.sz, m["sz"])
	}
	if c.Ct.Id != m["id"] {
		t.Fatalf("a's field Id not merged properly: c.Ct.Id(%s) != b.Ct.Id(%s)", c.Ct.Id, m["id"])
	}
}

func TestSimpleMap(t *testing.T) {
	a := simpleTest{}
	b := map[string]interface{}{
		"value": 42,
	}
	if err := Map(&a, b); err != nil {
		t.FailNow()
	}
	if a.Value != 42 {
		t.Fatalf("b not merged in a properly: a.Value(%d) != b.Value(%v)", a.Value, b["value"])
	}
}

type pointerMapTest struct {
	A      int
	hidden int
	B      *simpleTest
}

func TestBackAndForth(t *testing.T) {
	pt := pointerMapTest{42, 1, &simpleTest{66}}
	m := make(map[string]interface{})
	if err := Map(&m, pt); err != nil {
		t.FailNow()
	}
	var (
		v  interface{}
		ok bool
	)
	if v, ok = m["a"]; v.(int) != pt.A || !ok {
		t.Fatalf("pt not merged properly: m[`a`](%d) != pt.A(%d)", v, pt.A)
	}
	if v, ok = m["b"]; !ok {
		t.Fatalf("pt not merged properly: B is missing in m")
	}
	var st *simpleTest
	if st = v.(*simpleTest); st.Value != 66 {
		t.Fatalf("something went wrong while mapping pt on m, B wasn't copied")
	}
	bpt := pointerMapTest{}
	if err := Map(&bpt, m); err != nil {
		t.Fatal(err)
	}
	if bpt.A != pt.A {
		t.Fatalf("pt not merged properly: bpt.A(%d) != pt.A(%d)", bpt.A, pt.A)
	}
	if bpt.hidden == pt.hidden {
		t.Fatalf("pt unexpectedly merged: bpt.hidden(%d) == pt.hidden(%d)", bpt.hidden, pt.hidden)
	}
	if bpt.B.Value != pt.B.Value {
		t.Fatalf("pt not merged properly: bpt.B.Value(%d) != pt.B.Value(%d)", bpt.B.Value, pt.B.Value)
	}
}

func loadYAML(path string) (m map[string]interface{}) {
	m = make(map[string]interface{})
	raw, _ := ioutil.ReadFile(path)
	_ = yaml.Unmarshal(raw, &m)
	return
}
<|endoftext|>


<commit_before>package mesos

import (
	"encoding/json"
	"errors"

	"github.com/Dataman-Cloud/swan/mesosproto"
	"github.com/Dataman-Cloud/swan/types"
)

// runtime Task object
type Task struct {
	mesosproto.TaskInfo

	updates chan *mesosproto.TaskStatus

	cfg *types.TaskConfig
}

func NewTask(cfg *types.TaskConfig, id, name string) *Task {
	task := &Task{
		cfg:     cfg,
		updates: make(chan *mesosproto.TaskStatus),
	}

	task.Name = &name
	task.TaskId = &mesosproto.TaskID{Value: &id}

	return task
}

func (t *Task) ID() string {
	return t.TaskId.GetValue()
}

func (t *Task) Build() {
	t.Resources = t.cfg.BuildResources()
	t.Command = t.cfg.BuildCommand()
	t.Container = t.cfg.BuildContainer()
	if t.cfg.HealthCheck != nil && !t.cfg.HealthCheck.IsEmpty() {
		t.HealthCheck = t.cfg.BuildHealthCheck()
	}
	//t.KillPolicy = t.cfg.BuildKillPolicy()
	t.Labels = t.cfg.BuildLabels(t.GetName())
}

// SendStatus method writes the task status in the updates channel
func (t *Task) SendStatus(status *mesosproto.TaskStatus) {
	t.updates <- status
}

// GetStatus method reads the task status on the updates channel
func (t *Task) GetStatus() chan *mesosproto.TaskStatus {
	return t.updates
}

// IsDone check that if a task is done or not according by task status.
func (t *Task) IsDone(status *mesosproto.TaskStatus) bool {
	state := status.GetState()

	switch state {
	case mesosproto.TaskState_TASK_RUNNING,
		mesosproto.TaskState_TASK_FINISHED,
		mesosproto.TaskState_TASK_FAILED,
		mesosproto.TaskState_TASK_KILLED,
		mesosproto.TaskState_TASK_ERROR,
		mesosproto.TaskState_TASK_LOST,
		mesosproto.TaskState_TASK_DROPPED,
		mesosproto.TaskState_TASK_GONE:

		return true
	}

	return false
}

func (t *Task) IsKilled(status *mesosproto.TaskStatus) bool {
	state := status.GetState()
	switch state {
	case mesosproto.TaskState_TASK_FINISHED,
		mesosproto.TaskState_TASK_KILLED,
		mesosproto.TaskState_TASK_FAILED,
		mesosproto.TaskState_TASK_UNKNOWN,
		mesosproto.TaskState_TASK_UNREACHABLE:

		return true
	}

	return false
}

func (t *Task) DetectError(status *mesosproto.TaskStatus) error {
	var (
		state = status.GetState()
		//data  = status.GetData() // docker container inspect result
	)

	switch state {
	case mesosproto.TaskState_TASK_FAILED,
		mesosproto.TaskState_TASK_ERROR,
		mesosproto.TaskState_TASK_LOST,
		mesosproto.TaskState_TASK_DROPPED,
		mesosproto.TaskState_TASK_UNREACHABLE,
		mesosproto.TaskState_TASK_GONE,
		mesosproto.TaskState_TASK_GONE_BY_OPERATOR,
		mesosproto.TaskState_TASK_UNKNOWN:
		bs, _ := json.Marshal(map[string]interface{}{
			"message": status.GetMessage(),
			"reason":  status.GetReason().String(),
		})

		return errors.New(string(bs))
	}

	return nil
}
<commit_msg>fix channel usage to avoid potential block for runtime tasks<commit_after>package mesos

import (
	"encoding/json"
	"errors"

	"github.com/Dataman-Cloud/swan/mesosproto"
	"github.com/Dataman-Cloud/swan/types"
)

// runtime Task object
type Task struct {
	mesosproto.TaskInfo

	updates chan *mesosproto.TaskStatus

	cfg *types.TaskConfig
}

func NewTask(cfg *types.TaskConfig, id, name string) *Task {
	task := &Task{
		cfg:     cfg,
		updates: make(chan *mesosproto.TaskStatus, 1024),
	}

	task.Name = &name
	task.TaskId = &mesosproto.TaskID{Value: &id}

	return task
}

func (t *Task) ID() string {
	return t.TaskId.GetValue()
}

func (t *Task) Build() {
	t.Resources = t.cfg.BuildResources()
	t.Command = t.cfg.BuildCommand()
	t.Container = t.cfg.BuildContainer()
	if t.cfg.HealthCheck != nil && !t.cfg.HealthCheck.IsEmpty() {
		t.HealthCheck = t.cfg.BuildHealthCheck()
	}
	//t.KillPolicy = t.cfg.BuildKillPolicy()
	t.Labels = t.cfg.BuildLabels(t.GetName())
}

// SendStatus method writes the task status in the updates channel
func (t *Task) SendStatus(status *mesosproto.TaskStatus) {
	select {
	case t.updates <- status:
	default:
	}
}

// GetStatus method reads the task status on the updates channel
func (t *Task) GetStatus() chan *mesosproto.TaskStatus {
	return t.updates
}

// IsDone check that if a task is done or not according by task status.
func (t *Task) IsDone(status *mesosproto.TaskStatus) bool {
	state := status.GetState()

	switch state {
	case mesosproto.TaskState_TASK_RUNNING,
		mesosproto.TaskState_TASK_FINISHED,
		mesosproto.TaskState_TASK_FAILED,
		mesosproto.TaskState_TASK_KILLED,
		mesosproto.TaskState_TASK_ERROR,
		mesosproto.TaskState_TASK_LOST,
		mesosproto.TaskState_TASK_DROPPED,
		mesosproto.TaskState_TASK_GONE:

		return true
	}

	return false
}

func (t *Task) IsKilled(status *mesosproto.TaskStatus) bool {
	state := status.GetState()
	switch state {
	case mesosproto.TaskState_TASK_FINISHED,
		mesosproto.TaskState_TASK_KILLED,
		mesosproto.TaskState_TASK_FAILED,
		mesosproto.TaskState_TASK_UNKNOWN,
		mesosproto.TaskState_TASK_UNREACHABLE:

		return true
	}

	return false
}

func (t *Task) DetectError(status *mesosproto.TaskStatus) error {
	var (
		state = status.GetState()
		//data  = status.GetData() // docker container inspect result
	)

	switch state {
	case mesosproto.TaskState_TASK_FAILED,
		mesosproto.TaskState_TASK_ERROR,
		mesosproto.TaskState_TASK_LOST,
		mesosproto.TaskState_TASK_DROPPED,
		mesosproto.TaskState_TASK_UNREACHABLE,
		mesosproto.TaskState_TASK_GONE,
		mesosproto.TaskState_TASK_GONE_BY_OPERATOR,
		mesosproto.TaskState_TASK_UNKNOWN:
		bs, _ := json.Marshal(map[string]interface{}{
			"message": status.GetMessage(),
			"reason":  status.GetReason().String(),
		})

		return errors.New(string(bs))
	}

	return nil
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/PhiCode/l10n_check/config/properties"
	"github.com/PhiCode/l10n_check/validate"
)

type result struct {
	file  string
	props *properties.Properties
	valid *validate.Results
}

var verbose *bool = flag.Bool("v", false, "verbose")

func main() {
	flag.Usage = usage

	flag.Parse()
	if flag.NArg() < 1 {
		usage()
	}
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("caught error:", err)
			os.Exit(3)
		}
	}()

	anyFault := false
	args := flag.Args()
	results := make([]result, 0, len(args))
	for _, file := range args {
		props, valid, err := properties.ReadAndParse(file)
		if err != nil {
			fmt.Println(err)
			anyFault = true
			continue
		}
		r := result{file, props, valid}
		results = append(results, r)
		//fmt.Printf(r.String())
	}

	for _, result := range results {
		fmt.Printf("%s: %d keys\n", result.file, len(result.props.ByKey))
		if *verbose {
			result.props.PrintAll("\t")
		}
	}

	fmt.Println()

	for _, result := range results {
		fmt.Println(result.valid)
		anyFault = anyFault || result.valid.Any()
	}

	if len(results) > 1 {
		master := results[0]
		for _, other := range results[1:] {
			n := properties.AnalyzeAll(master.props, other.props)
			anyFault = anyFault || n > 0
		}
	}

	if anyFault {
		os.Exit(2)
	}
	os.Exit(0)
}

func usage() {
	fmt.Printf("usage: %s [-v] <file-name> [<file-name> ...]\n", os.Args[0])
	flag.PrintDefaults()
	os.Exit(1)
}

func (r *result) String() string {
	return fmt.Sprintf("file: %s\nprops:\n%s\nvalid:\n%s\n", r.file, r.props, r.valid)
}
<commit_msg>put the usage function inline<commit_after>/*
 * Copyright (c) 2006-2011 Philipp Meinen <philipp@bind.ch>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software
 * is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
 * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/PhiCode/l10n_check/config/properties"
	"github.com/PhiCode/l10n_check/validate"
)

type result struct {
	file  string
	props *properties.Properties
	valid *validate.Results
}

var verbose *bool = flag.Bool("v", false, "enable verbose mode")

func main() {
	flag.Usage = func() {
		fmt.Printf("usage: %s [-v] <file-name> [<file-name> ...]\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(1)
	}
	flag.Parse()
	if flag.NArg() < 1 {
		flag.Usage()
	}
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("caught error:", err)
			os.Exit(3)
		}
	}()

	anyFault := false
	args := flag.Args()
	results := make([]result, 0, len(args))
	for _, file := range args {
		props, valid, err := properties.ReadAndParse(file)
		if err != nil {
			fmt.Println(err)
			anyFault = true
			continue
		}
		r := result{file, props, valid}
		results = append(results, r)
		//fmt.Printf(r.String())
	}

	for _, result := range results {
		fmt.Printf("%s: %d keys\n", result.file, len(result.props.ByKey))
		if *verbose {
			result.props.PrintAll("\t")
		}
	}

	fmt.Println()

	for _, result := range results {
		fmt.Println(result.valid)
		anyFault = anyFault || result.valid.Any()
	}

	if len(results) > 1 {
		master := results[0]
		for _, other := range results[1:] {
			n := properties.AnalyzeAll(master.props, other.props)
			anyFault = anyFault || n > 0
		}
	}

	if anyFault {
		os.Exit(2)
	}
	os.Exit(0)
}

func (r *result) String() string {
	return fmt.Sprintf("file: %s\nprops:\n%s\nvalid:\n%s\n", r.file, r.props, r.valid)
}
<|endoftext|>


<commit_before>// Copyright 2016 Mender Software AS
//
//    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 main

import (
	"mime"
	"net/http"

	"github.com/ant0ine/go-json-rest/rest"
	"github.com/mendersoftware/deployments/config"
	"github.com/mendersoftware/go-lib-micro/accesslog"
	"github.com/mendersoftware/go-lib-micro/customheader"
	"github.com/mendersoftware/go-lib-micro/requestid"
	"github.com/mendersoftware/go-lib-micro/requestlog"
)

const (
	HttpHeaderContentType                 string = "Content-type"
	HttpHeaderOrigin                      string = "Origin"
	HttpHeaderAuthorization               string = "Authorization"
	HttpHeaderAcceptEncoding              string = "Accept-Encoding"
	HttpHeaderAccessControlRequestHeaders string = "Access-Control-Request-Headers"
	HttpHeaderAccessControlRequestMethod  string = "Access-Control-Request-Method"
	HttpHeaderLastModified                string = "Last-Modified"
	HttpHeaderExpires                     string = "Expires"
	HttpHeaderLocation                    string = "Location"
	HttpHeaderAllow                       string = "Allow"
	HttpHeaderAccept                      string = "Accept"

	EnvProd string = "prod"
	EnvDev  string = "dev"
)

var DefaultDevStack = []rest.Middleware{

	// logging
	&requestlog.RequestLogMiddleware{},
	&accesslog.AccessLogMiddleware{Format: accesslog.SimpleLogFormat},
	&rest.TimerMiddleware{},
	&rest.RecorderMiddleware{},

	// catches the panic errors that occur with stack trace
	&rest.RecoverMiddleware{
		EnableResponseStackTrace: true,
	},

	// json pretty print
	&rest.JsonIndentMiddleware{},
	&requestid.RequestIdMiddleware{},
}

var DefaultProdStack = []rest.Middleware{

	// logging
	&requestlog.RequestLogMiddleware{},
	&accesslog.AccessLogMiddleware{Format: accesslog.SimpleLogFormat},
	&rest.TimerMiddleware{},
	&rest.RecorderMiddleware{},

	// catches the panic errorsx
	&rest.RecoverMiddleware{},

	// response compression
	&rest.GzipMiddleware{},
	&requestid.RequestIdMiddleware{},
}

func SetupMiddleware(c config.ConfigReader, api *rest.Api) {

	api.Use(&customheader.CustomHeaderMiddleware{
		HeaderName:  "X-DEPLOYMENTS-VERSION",
		HeaderValue: CreateVersionString(),
	})

	mwtype := c.GetString(SettingMiddleware)
	if mwtype == EnvDev {
		api.Use(DefaultDevStack...)
	} else {
		api.Use(DefaultProdStack...)
	}

	// Verifies the request Content-Type header if the content is non-null.
	// For the POST /api/0.0.1/images request expected Content-Type is 'multipart/form-data'.
	// For the rest of the requests expected Content-Type is 'application/json'.
	api.Use(&rest.IfMiddleware{
		Condition: func(r *rest.Request) bool {
			if r.URL.Path == "/api/0.0.1/artifacts" && r.Method == http.MethodPost {
				return true
			} else {
				return false
			}
		},
		IfTrue: rest.MiddlewareSimple(func(handler rest.HandlerFunc) rest.HandlerFunc {
			return func(w rest.ResponseWriter, r *rest.Request) {
				mediatype, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
				if r.ContentLength > 0 && !(mediatype == "multipart/form-data") {
					rest.Error(w, "Bad Content-Type, expected 'multipart/form-data'", http.StatusUnsupportedMediaType)
					return
				}
				// call the wrapped handler
				handler(w, r)
			}
		}),
		IfFalse: &rest.ContentTypeCheckerMiddleware{},
	})

	api.Use(&rest.CorsMiddleware{
		RejectNonCorsRequests: false,

		// Should be tested with some list
		OriginValidator: func(origin string, request *rest.Request) bool {
			// Accept all requests
			return true
		},

		// Preflight request cache lenght
		AccessControlMaxAge: 60,

		// Allow authentication requests
		AccessControlAllowCredentials: true,

		// Allowed headers
		AllowedMethods: []string{
			http.MethodGet,
			http.MethodPost,
			http.MethodPut,
			http.MethodDelete,
			http.MethodOptions,
		},

		// Allowed heardes
		AllowedHeaders: []string{
			HttpHeaderAccept,
			HttpHeaderAllow,
			HttpHeaderContentType,
			HttpHeaderOrigin,
			HttpHeaderAuthorization,
			HttpHeaderAcceptEncoding,
			HttpHeaderAccessControlRequestHeaders,
			HttpHeaderAccessControlRequestMethod,
		},

		// Headers that can be exposed to JS
		AccessControlExposeHeaders: []string{
			HttpHeaderLocation,
		},
	})
}
<commit_msg>middleware: expose link header<commit_after>// Copyright 2016 Mender Software AS
//
//    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 main

import (
	"mime"
	"net/http"

	"github.com/ant0ine/go-json-rest/rest"
	"github.com/mendersoftware/deployments/config"
	"github.com/mendersoftware/go-lib-micro/accesslog"
	"github.com/mendersoftware/go-lib-micro/customheader"
	"github.com/mendersoftware/go-lib-micro/requestid"
	"github.com/mendersoftware/go-lib-micro/requestlog"
)

const (
	HttpHeaderContentType                 string = "Content-type"
	HttpHeaderOrigin                      string = "Origin"
	HttpHeaderAuthorization               string = "Authorization"
	HttpHeaderAcceptEncoding              string = "Accept-Encoding"
	HttpHeaderAccessControlRequestHeaders string = "Access-Control-Request-Headers"
	HttpHeaderAccessControlRequestMethod  string = "Access-Control-Request-Method"
	HttpHeaderLastModified                string = "Last-Modified"
	HttpHeaderExpires                     string = "Expires"
	HttpHeaderLocation                    string = "Location"
	HttpHeaderLink                        string = "Link"
	HttpHeaderAllow                       string = "Allow"
	HttpHeaderAccept                      string = "Accept"

	EnvProd string = "prod"
	EnvDev  string = "dev"
)

var DefaultDevStack = []rest.Middleware{

	// logging
	&requestlog.RequestLogMiddleware{},
	&accesslog.AccessLogMiddleware{Format: accesslog.SimpleLogFormat},
	&rest.TimerMiddleware{},
	&rest.RecorderMiddleware{},

	// catches the panic errors that occur with stack trace
	&rest.RecoverMiddleware{
		EnableResponseStackTrace: true,
	},

	// json pretty print
	&rest.JsonIndentMiddleware{},
	&requestid.RequestIdMiddleware{},
}

var DefaultProdStack = []rest.Middleware{

	// logging
	&requestlog.RequestLogMiddleware{},
	&accesslog.AccessLogMiddleware{Format: accesslog.SimpleLogFormat},
	&rest.TimerMiddleware{},
	&rest.RecorderMiddleware{},

	// catches the panic errorsx
	&rest.RecoverMiddleware{},

	// response compression
	&rest.GzipMiddleware{},
	&requestid.RequestIdMiddleware{},
}

func SetupMiddleware(c config.ConfigReader, api *rest.Api) {

	api.Use(&customheader.CustomHeaderMiddleware{
		HeaderName:  "X-DEPLOYMENTS-VERSION",
		HeaderValue: CreateVersionString(),
	})

	mwtype := c.GetString(SettingMiddleware)
	if mwtype == EnvDev {
		api.Use(DefaultDevStack...)
	} else {
		api.Use(DefaultProdStack...)
	}

	// Verifies the request Content-Type header if the content is non-null.
	// For the POST /api/0.0.1/images request expected Content-Type is 'multipart/form-data'.
	// For the rest of the requests expected Content-Type is 'application/json'.
	api.Use(&rest.IfMiddleware{
		Condition: func(r *rest.Request) bool {
			if r.URL.Path == "/api/0.0.1/artifacts" && r.Method == http.MethodPost {
				return true
			} else {
				return false
			}
		},
		IfTrue: rest.MiddlewareSimple(func(handler rest.HandlerFunc) rest.HandlerFunc {
			return func(w rest.ResponseWriter, r *rest.Request) {
				mediatype, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
				if r.ContentLength > 0 && !(mediatype == "multipart/form-data") {
					rest.Error(w, "Bad Content-Type, expected 'multipart/form-data'", http.StatusUnsupportedMediaType)
					return
				}
				// call the wrapped handler
				handler(w, r)
			}
		}),
		IfFalse: &rest.ContentTypeCheckerMiddleware{},
	})

	api.Use(&rest.CorsMiddleware{
		RejectNonCorsRequests: false,

		// Should be tested with some list
		OriginValidator: func(origin string, request *rest.Request) bool {
			// Accept all requests
			return true
		},

		// Preflight request cache lenght
		AccessControlMaxAge: 60,

		// Allow authentication requests
		AccessControlAllowCredentials: true,

		// Allowed headers
		AllowedMethods: []string{
			http.MethodGet,
			http.MethodPost,
			http.MethodPut,
			http.MethodDelete,
			http.MethodOptions,
		},

		// Allowed heardes
		AllowedHeaders: []string{
			HttpHeaderAccept,
			HttpHeaderAllow,
			HttpHeaderContentType,
			HttpHeaderOrigin,
			HttpHeaderAuthorization,
			HttpHeaderAcceptEncoding,
			HttpHeaderAccessControlRequestHeaders,
			HttpHeaderAccessControlRequestMethod,
		},

		// Headers that can be exposed to JS
		AccessControlExposeHeaders: []string{
			HttpHeaderLocation,
			HttpHeaderLink,
		},
	})
}
<|endoftext|>


<commit_before>package ginpongo2

import (
	"net/http"

	"github.com/flosch/pongo2"
	. "github.com/gin-gonic/gin"
)

func Pongo2() HandlerFunc {
	return func(c *Context) {
		c.Next()

		templateName, templateNameError := c.Get("template")
		templateNameValue, isString := templateName.(string)

		if templateNameError == nil && isString {
			templateData, templateDataError := c.Get("data")
			var template = pongo2.Must(pongo2.FromCache(templateNameValue))
			err := template.ExecuteWriter(getContext(templateData, templateDataError), c.Writer)
			if err != nil {
				http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
			}
		}
	}
}

func getContext(templateData interface{}, err error) pongo2.Context {
	if templateData == nil || err != nil {
		return nil
	}
	contextData, isMap := templateData.(map[string]interface{})
	if isMap {
		return contextData
	}
	return nil
}
<commit_msg>Compatible with Gin 1.0 API changes<commit_after>package ginpongo2

import (
	"net/http"

	"github.com/flosch/pongo2"
	"github.com/gin-gonic/gin"
)

func Pongo2() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Next()

		templateName, exist := c.Get("template")
		templateNameValue, isString := templateName.(string)

		if exist && isString {
			templateData, exist := c.Get("data")
			var template = pongo2.Must(pongo2.FromCache(templateNameValue))
			err := template.ExecuteWriter(getContext(templateData, exist), c.Writer)
			if err != nil {
				http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
			}
		}
	}
}

func getContext(templateData interface{}, exist bool) pongo2.Context {
	if templateData == nil || !exist {
		return nil
	}
	contextData, isMap := templateData.(map[string]interface{})
	if isMap {
		return contextData
	}
	return nil
}
<|endoftext|>


<commit_before>package readraptor

import (
	"bytes"
	"database/sql"
	"encoding/base64"
	"fmt"
	"net/http"
	"os"
	"strings"
	"text/template"
	"time"

	"github.com/codegangsta/martini"
	"github.com/cupcake/gokiq"
	pq "github.com/lib/pq"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/sessionauth"
	"github.com/martini-contrib/sessions"
	"github.com/technoweenie/grohl"
)

func GetAccount(r render.Render, user sessionauth.User) {
	data := struct {
		StripeKey string
		Account   *Account
	}{
		os.Getenv("STRIPE_PUBLISHABLE"),
		user.(*Account),
	}
	r.HTML(200, "account", data)
}

func PostAccounts(client *gokiq.ClientConfig, rw http.ResponseWriter, req *http.Request) {
	if err := req.ParseForm(); err != nil {
		panic(err)
	}

	account := NewAccount(req.PostForm["email"][0])
	err := dbmap.Insert(account)
	if err != nil {
		if _, ok := err.(*pq.Error); ok {
			if strings.Index(err.Error(), `duplicate key value violates unique constraint "accounts_email_key"`) > -1 {
				rw.Write([]byte("Email is already taken"))
				return
			}
		}
		panic(err)
	}

	account.SendNewAccountEmail(client)

	template, err := template.ParseFiles("templates/welcome.txt.tmpl")
	if err != nil {
		panic(err)
	}

	var buf bytes.Buffer
	err = template.Execute(&buf, nil)
	if err != nil {
		panic(err)
	}

	fmt.Fprintln(rw, buf.String())
}

func PostAccountBilling(rw http.ResponseWriter, req *http.Request, user sessionauth.User) {
	account := user.(*Account)

	if err := req.ParseForm(); err != nil {
		panic(err)
	}

	token := req.PostForm["stripeToken"][0]

	err := account.CreateStripeCustomer(token)
	if err != nil {
		panic(err)
	}

	http.Redirect(rw, req, "/setup", http.StatusFound)
}

func GetConfirmAccount(session sessions.Session, rw http.ResponseWriter, req *http.Request, params martini.Params) {
	account, err := FindAccountByConfirmationToken(params["confirmation_token"])
	if err != nil {
		panic(err)
	}

	_, err = dbmap.Exec(
		"update accounts set confirmed_at = $1 where id = $2",
		time.Now(),
		account.Id,
	)
	if err != nil {
		panic(err)
	}

	err = sessionauth.AuthenticateSession(session, account)
	if err != nil {
		panic(err)
	}

	http.Redirect(rw, req, "/account", http.StatusFound)
}

func GetSetup(r render.Render, user sessionauth.User, rw http.ResponseWriter, req *http.Request) {
	account := user.(*Account)
	if account.CustomerId == nil {
		http.Redirect(rw, req, "/account", http.StatusFound)
	} else {
		data := struct {
			Account   *Account
			Signature string
		}{
			user.(*Account),
			signature(account.PrivateKey, account.PublicKey, "article_1", "user_1"),
		}
		r.HTML(200, "setup", data)
	}
}

func AuthAccount(rw http.ResponseWriter, req *http.Request, c martini.Context) {
	splits := strings.Split(req.Header.Get("Authorization"), " ")
	dec, err := base64.StdEncoding.DecodeString(splits[1])
	if err != nil {
		panic(err)
	}

	privateKey := string(dec[:len(dec)-1])

	var account Account
	err = dbmap.SelectOne(&account, "select * from accounts where private_key = $1 limit 1", privateKey)
	if err == sql.ErrNoRows {
		rw.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
		http.Error(rw, "Not Authorized", http.StatusUnauthorized)
	} else if err != nil {
		panic(err)
	}

	c.Map(&account)

	grohl.AddContext("account", account.Id)
}

func GetSignout(r render.Render, user sessionauth.User, session sessions.Session) {
	sessionauth.Logout(session, user)
	r.Redirect("/", http.StatusFound)
}

func RedirectAuthenticated(path string) martini.Handler {
	return func(r render.Render, user sessionauth.User, req *http.Request) {
		if user.IsAuthenticated() {
			r.Redirect(path, http.StatusFound)
		}
	}
}
<commit_msg>do some basic email validation<commit_after>package readraptor

import (
	"bytes"
	"database/sql"
	"encoding/base64"
	"fmt"
	"net/http"
	"os"
	"strings"
	"text/template"
	"time"

	"github.com/codegangsta/martini"
	"github.com/cupcake/gokiq"
	"github.com/lib/pq"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/sessionauth"
	"github.com/martini-contrib/sessions"
	"github.com/technoweenie/grohl"
)

func GetAccount(r render.Render, user sessionauth.User) {
	data := struct {
		StripeKey string
		Account   *Account
	}{
		os.Getenv("STRIPE_PUBLISHABLE"),
		user.(*Account),
	}
	r.HTML(200, "account", data)
}

func PostAccounts(client *gokiq.ClientConfig, rw http.ResponseWriter, req *http.Request) {
	if err := req.ParseForm(); err != nil {
		panic(err)
	}

	email := strings.Replace(req.PostForm["email"][0], " ", "", -1)

	if strings.Index(email, "@") == -1 {
		rw.Write([]byte("Email is invalid"))
		return
	}

	account := NewAccount(email)
	err := dbmap.Insert(account)
	if err != nil {
		if _, ok := err.(*pq.Error); ok {
			if strings.Index(err.Error(), `duplicate key value violates unique constraint "accounts_email_key"`) > -1 {
				rw.Write([]byte("Email is already taken"))
				return
			}
		}
		panic(err)
	}

	account.SendNewAccountEmail(client)

	template, err := template.ParseFiles("templates/welcome.txt.tmpl")
	if err != nil {
		panic(err)
	}

	var buf bytes.Buffer
	err = template.Execute(&buf, nil)
	if err != nil {
		panic(err)
	}

	fmt.Fprintln(rw, buf.String())
}

func PostAccountBilling(rw http.ResponseWriter, req *http.Request, user sessionauth.User) {
	account := user.(*Account)

	if err := req.ParseForm(); err != nil {
		panic(err)
	}

	token := req.PostForm["stripeToken"][0]

	err := account.CreateStripeCustomer(token)
	if err != nil {
		panic(err)
	}

	http.Redirect(rw, req, "/setup", http.StatusFound)
}

func GetConfirmAccount(session sessions.Session, rw http.ResponseWriter, req *http.Request, params martini.Params) {
	account, err := FindAccountByConfirmationToken(params["confirmation_token"])
	if err != nil {
		panic(err)
	}

	_, err = dbmap.Exec(
		"update accounts set confirmed_at = $1 where id = $2",
		time.Now(),
		account.Id,
	)
	if err != nil {
		panic(err)
	}

	err = sessionauth.AuthenticateSession(session, account)
	if err != nil {
		panic(err)
	}

	http.Redirect(rw, req, "/account", http.StatusFound)
}

func GetSetup(r render.Render, user sessionauth.User, rw http.ResponseWriter, req *http.Request) {
	account := user.(*Account)
	if account.CustomerId == nil {
		http.Redirect(rw, req, "/account", http.StatusFound)
	} else {
		data := struct {
			Account   *Account
			Signature string
		}{
			user.(*Account),
			signature(account.PrivateKey, account.PublicKey, "article_1", "user_1"),
		}
		r.HTML(200, "setup", data)
	}
}

func AuthAccount(rw http.ResponseWriter, req *http.Request, c martini.Context) {
	splits := strings.Split(req.Header.Get("Authorization"), " ")
	dec, err := base64.StdEncoding.DecodeString(splits[1])
	if err != nil {
		panic(err)
	}

	privateKey := string(dec[:len(dec)-1])

	var account Account
	err = dbmap.SelectOne(&account, "select * from accounts where private_key = $1 limit 1", privateKey)
	if err == sql.ErrNoRows {
		rw.Header().Set("WWW-Authenticate", "Basic realm=\"Authorization Required\"")
		http.Error(rw, "Not Authorized", http.StatusUnauthorized)
	} else if err != nil {
		panic(err)
	}

	c.Map(&account)

	grohl.AddContext("account", account.Id)
}

func GetSignout(r render.Render, user sessionauth.User, session sessions.Session) {
	sessionauth.Logout(session, user)
	r.Redirect("/", http.StatusFound)
}

func RedirectAuthenticated(path string) martini.Handler {
	return func(r render.Render, user sessionauth.User, req *http.Request) {
		if user.IsAuthenticated() {
			r.Redirect(path, http.StatusFound)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Vadim Kravcenko
//
// 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 gojenkins

import (
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
)

// Represents an Artifact
type Artifact struct {
	Jenkins  *Jenkins
	Build    *Build
	FileName string
	Path     string
}

// Get raw byte data of Artifact
func (a Artifact) GetData() ([]byte, error) {
	var data string
	response, err := a.Jenkins.Requester.Get(a.Path, &data, nil)

	if err != nil {
		return nil, err
	}

	code := response.StatusCode
	if code != 200 {
		Error.Printf("Jenkins responded with StatusCode: %d", code)
		return nil, errors.New("Could not get File Contents")
	}
	return []byte(data), nil
}

// Save artifact to a specific path, using your own filename.
func (a Artifact) Save(path string) (bool, error) {
	data, err := a.GetData()

	if err != nil {
		return false, errors.New("No Data received, not saving file.")
	}

	if _, err = os.Stat(path); err == nil {
		Warning.Println("Local Copy already exists, Overwriting...")
	}

	err = ioutil.WriteFile(path, data, 0644)
	a.validateDownload(path)

	if err != nil {
		return false, err
	}
	return true, nil
}

// Save Artifact to directory using Artifact filename.
func (a Artifact) SaveToDir(dir string) (bool, error) {
	if _, err := os.Stat(dir); err != nil {
		Error.Printf("can't save artifact: directory %s does not exist", dir)
		return false, fmt.Errorf("can't save artifact: directory %s does not exist", dir)
	}
	saved, err := a.Save(path.Join(dir, a.FileName))
	if err != nil {
		return saved, nil
	}
	return saved, nil
}

// Compare Remote and local MD5
func (a Artifact) validateDownload(path string) (bool, error) {
	localHash := a.getMD5local(path)

	fp := FingerPrint{Jenkins: a.Jenkins, Base: "/fingerprint/", Id: localHash, Raw: new(FingerPrintResponse)}

	valid, err := fp.ValidateForBuild(a.FileName, a.Build)

	if err != nil {
		return false, err
	}
	if !valid {
		return false, errors.New("FingerPrint of the downloaded artifact could not be verified")
	}
	return true, nil
}

// Get Local MD5
func (a Artifact) getMD5local(path string) string {
	h := md5.New()
	localFile, err := os.Open(path)
	if err != nil {
		return ""
	}
	buffer := make([]byte, 2^20)
	n, err := localFile.Read(buffer)
	defer localFile.Close()
	for err == nil {
		io.WriteString(h, string(buffer[0:n]))
		n, err = localFile.Read(buffer)
	}
	return fmt.Sprintf("%x", h.Sum(nil))
}
<commit_msg>Fix likely typo of exclusive-or for exponentiation<commit_after>// Copyright 2015 Vadim Kravcenko
//
// 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 gojenkins

import (
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
)

// Represents an Artifact
type Artifact struct {
	Jenkins  *Jenkins
	Build    *Build
	FileName string
	Path     string
}

// Get raw byte data of Artifact
func (a Artifact) GetData() ([]byte, error) {
	var data string
	response, err := a.Jenkins.Requester.Get(a.Path, &data, nil)

	if err != nil {
		return nil, err
	}

	code := response.StatusCode
	if code != 200 {
		Error.Printf("Jenkins responded with StatusCode: %d", code)
		return nil, errors.New("Could not get File Contents")
	}
	return []byte(data), nil
}

// Save artifact to a specific path, using your own filename.
func (a Artifact) Save(path string) (bool, error) {
	data, err := a.GetData()

	if err != nil {
		return false, errors.New("No Data received, not saving file.")
	}

	if _, err = os.Stat(path); err == nil {
		Warning.Println("Local Copy already exists, Overwriting...")
	}

	err = ioutil.WriteFile(path, data, 0644)
	a.validateDownload(path)

	if err != nil {
		return false, err
	}
	return true, nil
}

// Save Artifact to directory using Artifact filename.
func (a Artifact) SaveToDir(dir string) (bool, error) {
	if _, err := os.Stat(dir); err != nil {
		Error.Printf("can't save artifact: directory %s does not exist", dir)
		return false, fmt.Errorf("can't save artifact: directory %s does not exist", dir)
	}
	saved, err := a.Save(path.Join(dir, a.FileName))
	if err != nil {
		return saved, nil
	}
	return saved, nil
}

// Compare Remote and local MD5
func (a Artifact) validateDownload(path string) (bool, error) {
	localHash := a.getMD5local(path)

	fp := FingerPrint{Jenkins: a.Jenkins, Base: "/fingerprint/", Id: localHash, Raw: new(FingerPrintResponse)}

	valid, err := fp.ValidateForBuild(a.FileName, a.Build)

	if err != nil {
		return false, err
	}
	if !valid {
		return false, errors.New("FingerPrint of the downloaded artifact could not be verified")
	}
	return true, nil
}

// Get Local MD5
func (a Artifact) getMD5local(path string) string {
	h := md5.New()
	localFile, err := os.Open(path)
	if err != nil {
		return ""
	}
	buffer := make([]byte, 1<<20)
	n, err := localFile.Read(buffer)
	defer localFile.Close()
	for err == nil {
		io.WriteString(h, string(buffer[0:n]))
		n, err = localFile.Read(buffer)
	}
	return fmt.Sprintf("%x", h.Sum(nil))
}
<|endoftext|>


<commit_before>package registry

import "time"
import "gopkg.in/mgo.v2"
import "gopkg.in/mgo.v2/bson"

type MongoStore struct {
    connection *mgo.Collection
    err error
}

func NewMongoStore(server string,
                    database string,
                    collection string) MongoStore {
    session, error := mgo.Dial(server);

    if (error != nil) {
        return MongoStore{connection: nil, err: error}
    }
    defer session.Close();

    connection := session.DB(database).C(collection)
    return MongoStore{connection: connection, err: nil}
}

func (store MongoStore) GetTemplate(name string) (Template, error) {
    result := Template{}
    error := store.connection.Find(bson.M{"name": name}).One(&result)
    if (error != nil) {
       return Template{}, UnavailableTemplateError
    }
    return result, nil
}

func (store MongoStore) RegisterTemplate(tmpl Template) (Template, error) {
    result, err := store.GetTemplate(tmpl.Name)
    if (err != nil && result != Template{}) {
        // This template is already in the database
        return Template{}, ExistingTemplateError
    }

    tmpl.TimeModified = time.Now().UTC()
    tmpl.TimeCreated = tmpl.TimeModified

    error := store.connection.Insert(&tmpl)

    if (error != nil) {
        return Template{}, error
    }

    return tmpl, nil
}

func (store MongoStore) ListTemplates() ([]Template, error) {
    var results []Template

    err := store.connection.Find(bson.M{}).All(&results)

    if (err != nil) {
        return results, err
    }

    return results, nil
}

func (store MongoStore) UpdateTemplate(name string,
                                    update map[string]int) (Template, error) {
    updates := bson.M{"$set": update}
    filter := bson.M{"name": name}
    var result Template

    err := store.connection.Update(filter, updates)

    if (err != nil) {
        return Template{}, err
    }

    return result, nil
}
<commit_msg>Added DeleteTemplate function<commit_after>package registry

import "time"
import "gopkg.in/mgo.v2"
import "gopkg.in/mgo.v2/bson"

type MongoStore struct {
    connection *mgo.Collection
    err error
}

func NewMongoStore(server string,
                    database string,
                    collection string) MongoStore {
    session, error := mgo.Dial(server);

    if (error != nil) {
        return MongoStore{connection: nil, err: error}
    }
    defer session.Close();

    connection := session.DB(database).C(collection)
    return MongoStore{connection: connection, err: nil}
}

func (store MongoStore) GetTemplate(name string) (Template, error) {
    result := Template{}
    error := store.connection.Find(bson.M{"name": name}).One(&result)
    if (error != nil) {
       return Template{}, UnavailableTemplateError
    }
    return result, nil
}

func (store MongoStore) RegisterTemplate(tmpl Template) (Template, error) {
    result, err := store.GetTemplate(tmpl.Name)
    if (err != nil && result != Template{}) {
        // This template is already in the database
        return Template{}, ExistingTemplateError
    }

    tmpl.TimeModified = time.Now().UTC()
    tmpl.TimeCreated = tmpl.TimeModified

    error := store.connection.Insert(&tmpl)

    if (error != nil) {
        return Template{}, error
    }

    return tmpl, nil
}

func (store MongoStore) ListTemplates() ([]Template, error) {
    var results []Template

    err := store.connection.Find(bson.M{}).All(&results)

    if (err != nil) {
        return results, err
    }

    return results, nil
}

func (store MongoStore) UpdateTemplate(name string,
                                    update map[string]int) (Template, error) {
    updates := bson.M{"$set": update}
    filter := bson.M{"name": name}
    var result Template

    err := store.connection.Update(filter, updates)

    if (err != nil) {
        return Template{}, err
    }

    return result, nil
}

func (store MongoStore) DeleteTemplate(name string) error {
    filter := bson.M{"name": name}

    err := store.connection.Remove(filter)

    if (err != nil) {
        return err
    }

    return nil
}
<|endoftext|>


<commit_before>package ldap

import (
	"fmt"
)

type UserInfo struct {
	ID    string
	Name  string
	Email string
}

type UserStore struct {
	pool            Pool
	displayNameAttr string
	emailAttr       string
}

func NewUserStore(pool Pool, config Config) *UserStore {
	displayNameAttr := config.DisplayNameAttr
	if len(displayNameAttr) == 0 {
		displayNameAttr = "displayName"
	}
	emailAttr := config.EmailAttr
	if len(emailAttr) == 0 {
		emailAttr = "mail"
	}
	return &UserStore{
		pool:            pool,
		displayNameAttr: displayNameAttr,
		emailAttr:       emailAttr,
	}
}

func (us *UserStore) ValidateCredentials(username, password string) (*UserInfo, error) {
	client, err := us.pool.Get()
	if err != nil {
		return nil, err
	}
	defer us.pool.Put(client)
	ok, attrs, err := client.Authenticate(username, password)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, fmt.Errorf("ldap auth failed for user '%s'", username)
	}
	return us.makeUser(username, attrs), nil
}

func (us *UserStore) FindUserByID(userID string) (*UserInfo, error) {
	client, err := us.pool.Get()
	if err != nil {
		return nil, err
	}
	defer us.pool.Put(client)
	attrs, err := client.FindUser(userID)
	if err != nil {
		return nil, err
	}
	return us.makeUser(userID, attrs), nil
}

func (us *UserStore) Close() {
	if us.pool != nil {
		us.pool.Close()
		us.pool = nil
	}
}

func (us *UserStore) makeUser(id string, attrs map[string]string) *UserInfo {
	displayName, _ := attrs[us.displayNameAttr]
	email, _ := attrs[us.emailAttr]
	return &UserInfo{
		ID:    id,
		Name:  displayName,
		Email: email,
	}
}
<commit_msg>include all LDAP entry attributes to the UserInfo<commit_after>package ldap

import (
	"fmt"
)

type UserInfo struct {
	ID         string
	Name       string
	Email      string
	Attributes map[string]string
}

type UserStore struct {
	pool            Pool
	displayNameAttr string
	emailAttr       string
}

func NewUserStore(pool Pool, config Config) *UserStore {
	displayNameAttr := config.DisplayNameAttr
	if len(displayNameAttr) == 0 {
		displayNameAttr = "displayName"
	}
	emailAttr := config.EmailAttr
	if len(emailAttr) == 0 {
		emailAttr = "mail"
	}
	return &UserStore{
		pool:            pool,
		displayNameAttr: displayNameAttr,
		emailAttr:       emailAttr,
	}
}

func (us *UserStore) ValidateCredentials(username, password string) (*UserInfo, error) {
	client, err := us.pool.Get()
	if err != nil {
		return nil, err
	}
	defer us.pool.Put(client)
	ok, attrs, err := client.Authenticate(username, password)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, fmt.Errorf("ldap auth failed for user '%s'", username)
	}
	return us.makeUser(username, attrs), nil
}

func (us *UserStore) FindUserByID(userID string) (*UserInfo, error) {
	client, err := us.pool.Get()
	if err != nil {
		return nil, err
	}
	defer us.pool.Put(client)
	attrs, err := client.FindUser(userID)
	if err != nil {
		return nil, err
	}
	return us.makeUser(userID, attrs), nil
}

func (us *UserStore) Close() {
	if us.pool != nil {
		us.pool.Close()
		us.pool = nil
	}
}

func (us *UserStore) makeUser(id string, attrs map[string]string) *UserInfo {
	displayName, _ := attrs[us.displayNameAttr]
	email, _ := attrs[us.emailAttr]
	return &UserInfo{
		ID:         id,
		Name:       displayName,
		Email:      email,
		Attributes: attrs,
	}
}
<|endoftext|>


<commit_before>package ndp

import (
"fmt"
"net"
"encoding/binary"
)

// https://tools.ietf.org/html/rfc4861#section-4.6
type ICMPOption struct {
    Type   ICMPOptionType
    Length uint8
}

// https://tools.ietf.org/html/rfc4861#section-4.6.1
type ICMPOptionSourceLinkLayerAddress struct {
    ICMPOption
    LinkLayerAddress net.HardwareAddr
}

type ICMPOptionTargetLinkLayerAddress struct {
    ICMPOption
    LinkLayerAddress net.HardwareAddr
}

// https://tools.ietf.org/html/rfc4861#section-4.6.2
type ICMPOptionPrefixInformation struct {
    ICMPOption
    PrefixLength      uint8
    OnLink            bool
    Auto              bool
    ValidLifetime     uint32
    PreferredLifetime uint32
    Prefix            net.IP
}

func (o *ICMPOption) Marshal(proto int) ([]byte, error) {
    b := make([]byte, 8)
    b[0] ^= byte(o.Type)
    b[1] ^= byte(o.Length)
    return b, nil
}

func ParseOptions(b []byte) ([]ICMPOption, error) {
    // empty container
    var icmpOptions = []ICMPOption {}
OptionParser:
	for {
		if len(b) < 8 {
			fmt.Printf("options has only %d length left, done parsing\n", len(b))
			break
		}

		optionType := ICMPOptionType(b[0])
		optionLength := uint8(b[1])

		switch optionType {
			case ICMPOptionTypeSourceLinkLayerAddress:
				if optionLength != 1 {
					fmt.Printf("incorrect length of %d\n", optionLength)
					continue
				}

                currentOption := &ICMPOptionSourceLinkLayerAddress{
                    ICMPOption:       ICMPOption{
                        Type:   optionType,
                        Length: optionLength,
                    },
                    LinkLayerAddress: b[2:8],
                }

				fmt.Printf("source address: %s\n", currentOption.LinkLayerAddress.String())

                // chop option bytes off
				b = b[8:]

			case ICMPOptionTypeTargetLinkLayerAddress:
				if optionLength != 1 {
					fmt.Printf("incorrect length of %d\n", optionLength)
					continue
				}

                currentOption := &ICMPOptionTargetLinkLayerAddress{
                    ICMPOption:       ICMPOption{
                        Type:   optionType,
                        Length: optionLength,
                    },
                    LinkLayerAddress: b[2:8],
                }

				fmt.Printf("target address: %s\n", currentOption.LinkLayerAddress.String())

                // chop options bytes off
				b = b[8:]

			case ICMPOptionTypePrefixInformation:
				if optionLength != 4 {
					fmt.Printf("incorrect length of %d\n", optionLength)
					continue
				}

                currentOption := &ICMPOptionPrefixInformation{
                    ICMPOption:        ICMPOption{
                        Type:   optionType,
                        Length: optionLength,
                    },
                    PrefixLength:      uint8(b[2]),
                    OnLink:            (b[3] & 0x80 > 0),
                    Auto:              (b[3] & 0x40 > 0),
                    ValidLifetime:     binary.BigEndian.Uint32(b[4:8]),
                    PreferredLifetime: binary.BigEndian.Uint32(b[8:12]),
                    Prefix:            net.IP(b[16:32]),
                }

				fmt.Printf("prefix: %s/%d, onlink: %t, auto: %t, valid: %d, preferred: %d\n", currentOption.Prefix.String(), currentOption.PrefixLength, currentOption.OnLink, currentOption.Auto, currentOption.ValidLifetime, currentOption.PreferredLifetime)

                // chop options bytes off
				b = b[32:]

			default:
				fmt.Printf("unhandled icmp option %d\n", optionType)
				switch optionLength {
					case 1:
						b = b[8:]
					case 2:
						b = b[16:]
					case 5:
						b = b[40:]
					default:
						fmt.Printf("unhandled option length: %d\n", optionLength)
						break OptionParser
				}
		}

	}
    return icmpOptions, nil
}
<commit_msg>cleaned up option parsing<commit_after>package ndp

import (
"fmt"
"net"
"encoding/binary"
)

// https://tools.ietf.org/html/rfc4861#section-4.6
type ICMPOption struct {
    Type   ICMPOptionType
    Length uint8
}

// https://tools.ietf.org/html/rfc4861#section-4.6.1
type ICMPOptionSourceLinkLayerAddress struct {
    ICMPOption
    LinkLayerAddress net.HardwareAddr
}

type ICMPOptionTargetLinkLayerAddress struct {
    ICMPOption
    LinkLayerAddress net.HardwareAddr
}

// https://tools.ietf.org/html/rfc4861#section-4.6.2
type ICMPOptionPrefixInformation struct {
    ICMPOption
    PrefixLength      uint8
    OnLink            bool
    Auto              bool
    ValidLifetime     uint32
    PreferredLifetime uint32
    Prefix            net.IP
}

func (o *ICMPOption) Marshal(proto int) ([]byte, error) {
    b := make([]byte, 8)
    b[0] ^= byte(o.Type)
    b[1] ^= byte(o.Length)
    return b, nil
}

func ParseOptions(b []byte) ([]ICMPOption, error) {
    // empty container
    var icmpOptions = []ICMPOption {}

    for {
        if len(b) < 8 {
            fmt.Printf("options has only %d length left, done parsing\n", len(b))
            break
        }

        optionType := ICMPOptionType(b[0])
        optionLength := uint8(b[1])

        switch optionType {
            case ICMPOptionTypeSourceLinkLayerAddress:
                if optionLength != 1 {
                    fmt.Printf("incorrect length of %d\n", optionLength)
                    goto cleanup
                }

                currentOption := &ICMPOptionSourceLinkLayerAddress{
                    ICMPOption:       ICMPOption{
                        Type:   optionType,
                        Length: optionLength,
                    },
                    LinkLayerAddress: b[2:8],
                }

                fmt.Printf("source address: %s\n", currentOption.LinkLayerAddress.String())

            case ICMPOptionTypeTargetLinkLayerAddress:
                if optionLength != 1 {
                    fmt.Printf("incorrect length of %d\n", optionLength)
                    goto cleanup
                }

                currentOption := &ICMPOptionTargetLinkLayerAddress{
                    ICMPOption:       ICMPOption{
                        Type:   optionType,
                        Length: optionLength,
                    },
                    LinkLayerAddress: b[2:8],
                }

                fmt.Printf("target address: %s\n", currentOption.LinkLayerAddress.String())

            case ICMPOptionTypePrefixInformation:
                if optionLength != 4 {
                    fmt.Printf("incorrect length of %d\n", optionLength)
                    goto cleanup
                }

                currentOption := &ICMPOptionPrefixInformation{
                    ICMPOption:        ICMPOption{
                        Type:   optionType,
                        Length: optionLength,
                    },
                    PrefixLength:      uint8(b[2]),
                    OnLink:            (b[3] & 0x80 > 0),
                    Auto:              (b[3] & 0x40 > 0),
                    ValidLifetime:     binary.BigEndian.Uint32(b[4:8]),
                    PreferredLifetime: binary.BigEndian.Uint32(b[8:12]),
                    Prefix:            net.IP(b[16:32]),
                }

                fmt.Printf("prefix: %s/%d, onlink: %t, auto: %t, valid: %d, preferred: %d\n", currentOption.Prefix.String(), currentOption.PrefixLength, currentOption.OnLink, currentOption.Auto, currentOption.ValidLifetime, currentOption.PreferredLifetime)

            default:
                fmt.Printf("unhandled icmp option %d\n", optionType)
        }

cleanup:
        // chop off bytes for this option
        b = b[(optionLength * 8):]
    }

    return icmpOptions, nil
}
<|endoftext|>


<commit_before>package imageserver_test

import (
	. "github.com/pierrre/imageserver"
	"github.com/pierrre/imageserver/testdata"
	"reflect"
	"testing"
)

func TestImage(t *testing.T) {
	for _, image := range testdata.Images {
		data, err := image.MarshalBinary()
		if err != nil {
			t.Fatal(err)
		}

		newImage, err := NewImageUnmarshalBinary(data)
		if err != nil {
			t.Fatal(err)
		}

		if !reflect.DeepEqual(newImage, image) {
			t.Fatal("image not equals")
		}
	}
}

func TestImageUnmarshalBinaryError(t *testing.T) {
	for _, image := range testdata.Images {
		data, err := image.MarshalBinary()
		if err != nil {
			t.Fatal(err)
		}

		index := -1 // Always truncate 1 byte
		for _, offset := range []int{
			4,
			len(image.Format),
			4,
			len(image.Data),
		} {
			index += offset
			errorData := data[0:index]
			_, err = NewImageUnmarshalBinary(errorData)
			if err == nil {
				t.Fatal("no error")
			}
		}
	}
}

func BenchmarkMarshalBinarySmall(b *testing.B) {
	benchmarkMarshalBinary(b, testdata.Small)
}

func BenchmarkMarshalBinaryMedium(b *testing.B) {
	benchmarkMarshalBinary(b, testdata.Medium)
}

func BenchmarkMarshalBinaryLarge(b *testing.B) {
	benchmarkMarshalBinary(b, testdata.Large)
}

func BenchmarkMarshalBinaryHuge(b *testing.B) {
	benchmarkMarshalBinary(b, testdata.Huge)
}

func BenchmarkMarshalBinaryAnimated(b *testing.B) {
	benchmarkMarshalBinary(b, testdata.Animated)
}

func benchmarkMarshalBinary(b *testing.B, image *Image) {
	for i := 0; i < b.N; i++ {
		_, err := image.MarshalBinary()
		if err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>add benchmark for image unmarshal<commit_after>package imageserver_test

import (
	. "github.com/pierrre/imageserver"
	"github.com/pierrre/imageserver/testdata"
	"reflect"
	"testing"
)

func TestImage(t *testing.T) {
	for _, image := range testdata.Images {
		data, err := image.MarshalBinary()
		if err != nil {
			t.Fatal(err)
		}

		newImage, err := NewImageUnmarshalBinary(data)
		if err != nil {
			t.Fatal(err)
		}

		if !reflect.DeepEqual(newImage, image) {
			t.Fatal("image not equals")
		}
	}
}

func TestImageUnmarshalBinaryError(t *testing.T) {
	for _, image := range testdata.Images {
		data, err := image.MarshalBinary()
		if err != nil {
			t.Fatal(err)
		}

		index := -1 // Always truncate 1 byte
		for _, offset := range []int{
			4,
			len(image.Format),
			4,
			len(image.Data),
		} {
			index += offset
			errorData := data[0:index]
			_, err = NewImageUnmarshalBinary(errorData)
			if err == nil {
				t.Fatal("no error")
			}
		}
	}
}

func BenchmarkImageMarshalBinarySmall(b *testing.B) {
	benchmarkImageMarshalBinary(b, testdata.Small)
}

func BenchmarkImageMarshalBinaryMedium(b *testing.B) {
	benchmarkImageMarshalBinary(b, testdata.Medium)
}

func BenchmarkImageMarshalBinaryLarge(b *testing.B) {
	benchmarkImageMarshalBinary(b, testdata.Large)
}

func BenchmarkImageMarshalBinaryHuge(b *testing.B) {
	benchmarkImageMarshalBinary(b, testdata.Huge)
}

func BenchmarkImageMarshalBinaryAnimated(b *testing.B) {
	benchmarkImageMarshalBinary(b, testdata.Animated)
}

func benchmarkImageMarshalBinary(b *testing.B, image *Image) {
	for i := 0; i < b.N; i++ {
		_, err := image.MarshalBinary()
		if err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkNewImageUnmarshalBinarySmall(b *testing.B) {
	benchmarkNewImageUnmarshalBinary(b, testdata.Small)
}

func BenchmarkNewImageUnmarshalBinaryMedium(b *testing.B) {
	benchmarkNewImageUnmarshalBinary(b, testdata.Medium)
}

func BenchmarkNewImageUnmarshalBinaryLarge(b *testing.B) {
	benchmarkNewImageUnmarshalBinary(b, testdata.Large)
}

func BenchmarkNewImageUnmarshalBinaryHuge(b *testing.B) {
	benchmarkNewImageUnmarshalBinary(b, testdata.Huge)
}

func BenchmarkNewImageUnmarshalBinaryAnimated(b *testing.B) {
	benchmarkNewImageUnmarshalBinary(b, testdata.Animated)
}

func benchmarkNewImageUnmarshalBinary(b *testing.B, image *Image) {
	data, err := image.MarshalBinary()
	if err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		_, err := NewImageUnmarshalBinary(data)
		if err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/gorilla/websocket"
	"io/ioutil"
	"net/http"
  "crypto/tls"
  "crypto/x509"
  "encoding/pem"
	"strconv"
)

type Api struct {
  OauthToken string
  UserAgent string
}

type OkResponse struct {
	Ok int
}

type ErrorResponse struct {
	Error string
}

func (api *Api) apiUrl(path string) string {
	return "https://beta-api.mongohq.com" + path
}

func (api *Api) gopherUrl(path string) string {
	return "https://beta-api.mongohq.com/mongo" + path
}

func (api *Api) gopherSocketUrl(path string) string {
	return "wss://beta-api.mongohq.com/mongo" + path + "?token=Bearer%20" + api.OauthToken
}

func decodePem(certInput string) tls.Certificate {
  var cert tls.Certificate
  certPEMBlock := []byte(certInput)
  var certDERBlock *pem.Block
  for {
    certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
    if certDERBlock == nil {
      break
    }
    if certDERBlock != nil && certDERBlock.Type == "CERTIFICATE" {
      cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
    }
  }
  return cert
}

func (api *Api) sendRequest(request *http.Request) ([]byte, error) {
  certChain := decodePem(chain)
  conf := tls.Config{}
  conf.RootCAs = x509.NewCertPool()

  for _, cert := range certChain.Certificate {
    x509Cert, err := x509.ParseCertificate(cert)
    if err != nil {
      return nil, err
    }
    conf.RootCAs.AddCert(x509Cert)
  }
  conf.BuildNameToCertificate()

  tr := http.Transport{TLSClientConfig: &conf}
  client := &http.Client{Transport: &tr}

  if api.OauthToken == "" {
    return nil, errors.New("Unknown oauth token.  Please run `mongohq logout`, then rerun your command.")
  }

	request.Header.Add("Authorization", "Bearer "+api.OauthToken)
	request.Header.Add("User-Agent", api.UserAgent)
	request.Header.Add("Content-Type", "application/json")
	response, err := client.Do(request)

	if err != nil {
		return nil, err
	}

	responseBody, _ := ioutil.ReadAll(response.Body)
	response.Body.Close()

	if string(responseBody) == "NOT FOUND" {
		return responseBody, errors.New("Object not found")
	} else if response.StatusCode >= 400 {
		var errorResponse ErrorResponse
		err := json.Unmarshal(responseBody, &errorResponse)

		if err != nil {
			return responseBody, err
		}
		return responseBody, errors.New("Response status " + response.Status + " with error " + errorResponse.Error)
  } else if response.Header.Get("X-User-Agent-Deprecated") == "true" {
    return responseBody, errors.New(response.Header.Get("X-User-Agent-Deprecation-Message"))
	}

	return responseBody, nil
}

func (api *Api) restGet(urlString string) ([]byte, error) {
	request, err := http.NewRequest("GET", urlString, nil)
	if err != nil {
		return nil, err
	}
	return api.sendRequest(request)
}

func (api *Api) restPost(urlString string, data []byte) ([]byte, error) {
	request, err := http.NewRequest("POST", urlString, bytes.NewReader(data))
	if err != nil {
		return nil, err
	}
	return api.sendRequest(request)
}

func (api *Api) restPatch(urlString string, data []byte) ([]byte, error) {
	request, err := http.NewRequest("PATCH", urlString, bytes.NewReader(data))
	if err != nil {
		return nil, err
	}
	return api.sendRequest(request)
}

func (api *Api) restDelete(urlString string) ([]byte, error) {
	request, err := http.NewRequest("DELETE", urlString, nil)
	if err != nil {
		return nil, err
	}
	return api.sendRequest(request)
}

func (api *Api) openWebsocket(message SocketMessage) (*websocket.Conn, error) {
	dialer := websocket.Dialer{}
	header := http.Header{}
	header.Add("User-Agent", api.UserAgent)
	client, _, err := dialer.Dial(api.gopherSocketUrl("/ws"), header)
	if err != nil {
		return client, errors.New("Error initiating connection to websocket.")
	}
	jsonMessage, err := json.Marshal(message)
	if err != nil {
		return client, errors.New("Error marshalling websocket message.")
	}
	err = client.WriteMessage(websocket.TextMessage, jsonMessage)
	if err != nil {
		return client, errors.New("Error subscribing to websocket feed.")
	}
	return client, nil
}

var kb = 1024.0
var mb = kb * 1024.0
var gb = mb * 1024.0
var tb = gb * 1024.0

func includeSignificantDigits(size float64) string {
	if size < 10 {
		return strconv.FormatFloat(size, 'f', 2, 64)
	} else if size < 100 {
		return strconv.FormatFloat(size, 'f', 1, 64)
	} else {
		return strconv.FormatFloat(size, 'f', 0, 64)
	}
}

func prettySize(size float64) string {
	if size < kb {
		return includeSignificantDigits(size) + "b"
	} else if size < mb {
		return includeSignificantDigits(size/kb) + "k"
	} else if size < gb {
		return includeSignificantDigits(size/mb) + "m"
	} else if size < tb {
		return includeSignificantDigits(size/gb) + "g"
	} else {
		return includeSignificantDigits(size/tb) + "t"
	}
}
<commit_msg>Add nicer error messages for disconnected internet<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/gorilla/websocket"
	"io/ioutil"
	"net/http"
  "crypto/tls"
  "crypto/x509"
  "encoding/pem"
	"strconv"
  "fmt"
  "os"
  "regexp"
)

type Api struct {
  OauthToken string
  UserAgent string
}

type OkResponse struct {
	Ok int
}

type ErrorResponse struct {
	Error string
}

func (api *Api) apiUrl(path string) string {
	return "https://beta-api.mongohq.com" + path
}

func (api *Api) gopherUrl(path string) string {
	return "https://beta-api.mongohq.com/mongo" + path
}

func (api *Api) gopherSocketUrl(path string) string {
	return "wss://beta-api.mongohq.com/mongo" + path + "?token=Bearer%20" + api.OauthToken
}

func decodePem(certInput string) tls.Certificate {
  var cert tls.Certificate
  certPEMBlock := []byte(certInput)
  var certDERBlock *pem.Block
  for {
    certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
    if certDERBlock == nil {
      break
    }
    if certDERBlock != nil && certDERBlock.Type == "CERTIFICATE" {
      cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
    }
  }
  return cert
}

func (api *Api) sendRequest(request *http.Request) ([]byte, error) {
  certChain := decodePem(chain)
  conf := tls.Config{}
  conf.RootCAs = x509.NewCertPool()

  for _, cert := range certChain.Certificate {
    x509Cert, err := x509.ParseCertificate(cert)
    if err != nil {
      return nil, err
    }
    conf.RootCAs.AddCert(x509Cert)
  }
  conf.BuildNameToCertificate()

  tr := http.Transport{TLSClientConfig: &conf}
  client := &http.Client{Transport: &tr}

  if api.OauthToken == "" {
    return nil, errors.New("Unknown oauth token.  Please run `mongohq logout`, then rerun your command.")
  }

	request.Header.Add("Authorization", "Bearer "+api.OauthToken)
	request.Header.Add("User-Agent", api.UserAgent)
	request.Header.Add("Content-Type", "application/json")
	response, err := client.Do(request)

	if err != nil {
    noConnection := regexp.MustCompile("no such host")
    if noConnection.Match([]byte(err.Error())) {
      fmt.Println("We couldn't find the MongoHQ host.  Typically, this means your internet connections has gone AWOL.")
      os.Exit(1)
    } else {
      return nil, err
    }
	}

	responseBody, _ := ioutil.ReadAll(response.Body)
	response.Body.Close()

	if string(responseBody) == "NOT FOUND" {
		return responseBody, errors.New("Object not found")
  } else if response.StatusCode == 500 {
    return responseBody, errors.New("MongoHQ service returned an error. Please try again, or check our status page: https://status.mongohq.com.")
	} else if response.StatusCode >= 400 {
		var errorResponse ErrorResponse
		err := json.Unmarshal(responseBody, &errorResponse)

		if err != nil {
			return responseBody, err
		}
		return responseBody, errors.New("Response status " + response.Status + " with error " + errorResponse.Error)
  } else if response.Header.Get("X-User-Agent-Deprecated") == "true" {
    return responseBody, errors.New(response.Header.Get("X-User-Agent-Deprecation-Message"))
	}

	return responseBody, nil
}

func (api *Api) restGet(urlString string) ([]byte, error) {
	request, err := http.NewRequest("GET", urlString, nil)
	if err != nil {
		return nil, err
	}
	return api.sendRequest(request)
}

func (api *Api) restPost(urlString string, data []byte) ([]byte, error) {
	request, err := http.NewRequest("POST", urlString, bytes.NewReader(data))
	if err != nil {
		return nil, err
	}
	return api.sendRequest(request)
}

func (api *Api) restPatch(urlString string, data []byte) ([]byte, error) {
	request, err := http.NewRequest("PATCH", urlString, bytes.NewReader(data))
	if err != nil {
		return nil, err
	}
	return api.sendRequest(request)
}

func (api *Api) restDelete(urlString string) ([]byte, error) {
	request, err := http.NewRequest("DELETE", urlString, nil)
	if err != nil {
		return nil, err
	}
	return api.sendRequest(request)
}

func (api *Api) openWebsocket(message SocketMessage) (*websocket.Conn, error) {
	dialer := websocket.Dialer{}
	header := http.Header{}
	header.Add("User-Agent", api.UserAgent)
	client, _, err := dialer.Dial(api.gopherSocketUrl("/ws"), header)
	if err != nil {
		return client, errors.New("Error initiating connection to websocket.")
	}
	jsonMessage, err := json.Marshal(message)
	if err != nil {
		return client, errors.New("Error marshalling websocket message.")
	}
	err = client.WriteMessage(websocket.TextMessage, jsonMessage)
	if err != nil {
		return client, errors.New("Error subscribing to websocket feed.")
	}
	return client, nil
}

var kb = 1024.0
var mb = kb * 1024.0
var gb = mb * 1024.0
var tb = gb * 1024.0

func includeSignificantDigits(size float64) string {
	if size < 10 {
		return strconv.FormatFloat(size, 'f', 2, 64)
	} else if size < 100 {
		return strconv.FormatFloat(size, 'f', 1, 64)
	} else {
		return strconv.FormatFloat(size, 'f', 0, 64)
	}
}

func prettySize(size float64) string {
	if size < kb {
		return includeSignificantDigits(size) + "b"
	} else if size < mb {
		return includeSignificantDigits(size/kb) + "k"
	} else if size < gb {
		return includeSignificantDigits(size/mb) + "m"
	} else if size < tb {
		return includeSignificantDigits(size/gb) + "g"
	} else {
		return includeSignificantDigits(size/tb) + "t"
	}
}
<|endoftext|>


<commit_before>package dax

import (
	"github.com/dlespiau/dax/math"
)

type Camera interface {
	GetProjection() *math.Mat4
}

type BaseCamera struct {
	Node
	projection math.Mat4
}

func (camera *BaseCamera) GetProjection() *math.Mat4 {
	return &camera.projection
}

type orthographicCamera struct {
	BaseCamera
}

func NewOrthographicCamera(left, right, bottom, top, near, far float32) Camera {
	camera := new(orthographicCamera)

	camera.projection = math.Ortho(left, right, bottom, top, near, far)
	return camera
}

type perspectiveCamera struct {
	BaseCamera
}

func NewPerspectiveCamera(fovy, aspect, near, far float32) Camera {
	camera := new(perspectiveCamera)

	camera.projection = math.Perspective(fovy, aspect, near, far)
	return camera
}
<commit_msg>camera: Prefer returning struct pointers rather than interface<commit_after>package dax

import (
	"github.com/dlespiau/dax/math"
)

type Camera interface {
	GetProjection() *math.Mat4
}

type BaseCamera struct {
	Node
	projection math.Mat4
}

func (camera *BaseCamera) GetProjection() *math.Mat4 {
	return &camera.projection
}

type orthographicCamera struct {
	BaseCamera
}

func NewOrthographicCamera(left, right, bottom, top, near, far float32) *orthographicCamera {
	camera := new(orthographicCamera)

	camera.projection = math.Ortho(left, right, bottom, top, near, far)
	return camera
}

type perspectiveCamera struct {
	BaseCamera
}

func NewPerspectiveCamera(fovy, aspect, near, far float32) *perspectiveCamera {
	camera := new(perspectiveCamera)

	camera.projection = math.Perspective(fovy, aspect, near, far)
	return camera
}
<|endoftext|>