<commit_before>package chart

import (
	"bytes"
	"math"
	"testing"

	assert "github.com/blendlabs/go-assert"
)

func TestBarChartProps(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}

	assert.Equal(DefaultDPI, bc.GetDPI())
	bc.DPI = 100
	assert.Equal(100, bc.GetDPI())

	assert.Nil(bc.GetFont())
	f, err := GetDefaultFont()
	assert.Nil(err)
	bc.Font = f
	assert.NotNil(bc.GetFont())

	assert.Equal(DefaultChartWidth, bc.GetWidth())
	bc.Width = DefaultChartWidth - 1
	assert.Equal(DefaultChartWidth-1, bc.GetWidth())

	assert.Equal(DefaultChartHeight, bc.GetHeight())
	bc.Height = DefaultChartHeight - 1
	assert.Equal(DefaultChartHeight-1, bc.GetHeight())

	assert.Equal(DefaultBarSpacing, bc.GetBarSpacing())
	bc.BarSpacing = 150
	assert.Equal(150, bc.GetBarSpacing())

	assert.Equal(DefaultBarWidth, bc.GetBarWidth())
	bc.BarWidth = 75
	assert.Equal(75, bc.GetBarWidth())
}

func TestBarChartRenderNoBars(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	err := bc.Render(PNG, bytes.NewBuffer([]byte{}))
	assert.NotNil(err)
}

func TestBarChartGetRanges(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}

	yr := bc.getRanges()
	assert.NotNil(yr)
	assert.False(yr.IsZero())

	assert.Equal(-math.MaxFloat64, yr.GetMax())
	assert.Equal(math.MaxFloat64, yr.GetMin())
}

func TestBarChartGetRangesBarsMinMax(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		Bars: []Value{
			{Value: 1.0},
			{Value: 10.0},
		},
	}

	yr := bc.getRanges()
	assert.NotNil(yr)
	assert.False(yr.IsZero())

	assert.Equal(10, yr.GetMax())
	assert.Equal(1, yr.GetMin())
}

func TestBarChartGetRangesMinMax(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		YAxis: YAxis{
			Range: &ContinuousRange{
				Min: 5.0,
				Max: 15.0,
			},
			Ticks: []Tick{
				{Value: 7.0, Label: "Foo"},
				{Value: 11.0, Label: "Foo2"},
			},
		},
		Bars: []Value{
			{Value: 1.0},
			{Value: 10.0},
		},
	}

	yr := bc.getRanges()
	assert.NotNil(yr)
	assert.False(yr.IsZero())

	assert.Equal(15, yr.GetMax())
	assert.Equal(5, yr.GetMin())
}

func TestBarChartGetRangesTicksMinMax(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		YAxis: YAxis{
			Ticks: []Tick{
				{Value: 7.0, Label: "Foo"},
				{Value: 11.0, Label: "Foo2"},
			},
		},
		Bars: []Value{
			{Value: 1.0},
			{Value: 10.0},
		},
	}

	yr := bc.getRanges()
	assert.NotNil(yr)
	assert.False(yr.IsZero())

	assert.Equal(11, yr.GetMax())
	assert.Equal(7, yr.GetMin())
}

func TestBarChartHasAxes(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	assert.False(bc.hasAxes())
	bc.YAxis = YAxis{
		Style: StyleShow(),
	}

	assert.True(bc.hasAxes())
}

func TestBarChartGetDefaultCanvasBox(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	b := bc.getDefaultCanvasBox()
	assert.False(b.IsZero())
}

func TestBarChartSetRangeDomains(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	cb := bc.box()
	yr := bc.getRanges()
	yr2 := bc.setRangeDomains(cb, yr)
	assert.NotZero(yr2.GetDomain())
}

func TestBarChartGetValueFormatters(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	vf := bc.getValueFormatters()
	assert.NotNil(vf)
	assert.Equal("1234.00", vf(1234.0))

	bc.YAxis.ValueFormatter = func(_ interface{}) string { return "test" }
	assert.Equal("test", bc.getValueFormatters()(1234))
}

func TestBarChartGetAxesTicks(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		Bars: []Value{
			{Value: 1.0},
			{Value: 2.0},
			{Value: 3.0},
		},
	}

	r, err := PNG(128, 128)
	assert.Nil(err)
	yr := bc.getRanges()
	yf := bc.getValueFormatters()

	ticks := bc.getAxesTicks(r, yr, yf)
	assert.Empty(ticks)

	bc.YAxis.Style.Show = true
	ticks = bc.getAxesTicks(r, yr, yf)
	assert.Len(ticks, 2)
}

func TestBarChartCalculateEffectiveBarSpacing(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		Width:    1024,
		BarWidth: 10,
		Bars: []Value{
			{Value: 1.0, Label: "One"},
			{Value: 2.0, Label: "Two"},
			{Value: 3.0, Label: "Three"},
			{Value: 4.0, Label: "Four"},
			{Value: 5.0, Label: "Five"},
		},
	}

	spacing := bc.calculateEffectiveBarSpacing(bc.box())
	assert.NotZero(spacing)

	bc.BarWidth = 250
	spacing = bc.calculateEffectiveBarSpacing(bc.box())
	assert.Zero(spacing)
}

func TestBarChartCalculateEffectiveBarWidth(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		Width:    1024,
		BarWidth: 10,
		Bars: []Value{
			{Value: 1.0, Label: "One"},
			{Value: 2.0, Label: "Two"},
			{Value: 3.0, Label: "Three"},
			{Value: 4.0, Label: "Four"},
			{Value: 5.0, Label: "Five"},
		},
	}

	spacing := bc.calculateEffectiveBarSpacing(bc.box())
	assert.NotZero(spacing)

	barWidth := bc.calculateEffectiveBarWidth(bc.box(), spacing)
	assert.Equal(10, barWidth)

	bc.BarWidth = 250
	spacing = bc.calculateEffectiveBarSpacing(bc.box())
	barWidth = bc.calculateEffectiveBarWidth(bc.box(), spacing)
	assert.Equal(199, barWidth)

	assert.Equal(1024, bc.calculateTotalBarWidth(barWidth, spacing))
}
<commit_msg>tests catching bugs.<commit_after>package chart

import (
	"bytes"
	"math"
	"testing"

	assert "github.com/blendlabs/go-assert"
)

func TestBarChartProps(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}

	assert.Equal(DefaultDPI, bc.GetDPI())
	bc.DPI = 100
	assert.Equal(100, bc.GetDPI())

	assert.Nil(bc.GetFont())
	f, err := GetDefaultFont()
	assert.Nil(err)
	bc.Font = f
	assert.NotNil(bc.GetFont())

	assert.Equal(DefaultChartWidth, bc.GetWidth())
	bc.Width = DefaultChartWidth - 1
	assert.Equal(DefaultChartWidth-1, bc.GetWidth())

	assert.Equal(DefaultChartHeight, bc.GetHeight())
	bc.Height = DefaultChartHeight - 1
	assert.Equal(DefaultChartHeight-1, bc.GetHeight())

	assert.Equal(DefaultBarSpacing, bc.GetBarSpacing())
	bc.BarSpacing = 150
	assert.Equal(150, bc.GetBarSpacing())

	assert.Equal(DefaultBarWidth, bc.GetBarWidth())
	bc.BarWidth = 75
	assert.Equal(75, bc.GetBarWidth())
}

func TestBarChartRenderNoBars(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	err := bc.Render(PNG, bytes.NewBuffer([]byte{}))
	assert.NotNil(err)
}

func TestBarChartGetRanges(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}

	yr := bc.getRanges()
	assert.NotNil(yr)
	assert.False(yr.IsZero())

	assert.Equal(-math.MaxFloat64, yr.GetMax())
	assert.Equal(math.MaxFloat64, yr.GetMin())
}

func TestBarChartGetRangesBarsMinMax(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		Bars: []Value{
			{Value: 1.0},
			{Value: 10.0},
		},
	}

	yr := bc.getRanges()
	assert.NotNil(yr)
	assert.False(yr.IsZero())

	assert.Equal(10, yr.GetMax())
	assert.Equal(1, yr.GetMin())
}

func TestBarChartGetRangesMinMax(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		YAxis: YAxis{
			Range: &ContinuousRange{
				Min: 5.0,
				Max: 15.0,
			},
			Ticks: []Tick{
				{Value: 7.0, Label: "Foo"},
				{Value: 11.0, Label: "Foo2"},
			},
		},
		Bars: []Value{
			{Value: 1.0},
			{Value: 10.0},
		},
	}

	yr := bc.getRanges()
	assert.NotNil(yr)
	assert.False(yr.IsZero())

	assert.Equal(15, yr.GetMax())
	assert.Equal(5, yr.GetMin())
}

func TestBarChartGetRangesTicksMinMax(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		YAxis: YAxis{
			Ticks: []Tick{
				{Value: 7.0, Label: "Foo"},
				{Value: 11.0, Label: "Foo2"},
			},
		},
		Bars: []Value{
			{Value: 1.0},
			{Value: 10.0},
		},
	}

	yr := bc.getRanges()
	assert.NotNil(yr)
	assert.False(yr.IsZero())

	assert.Equal(11, yr.GetMax())
	assert.Equal(7, yr.GetMin())
}

func TestBarChartHasAxes(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	assert.False(bc.hasAxes())
	bc.YAxis = YAxis{
		Style: StyleShow(),
	}

	assert.True(bc.hasAxes())
}

func TestBarChartGetDefaultCanvasBox(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	b := bc.getDefaultCanvasBox()
	assert.False(b.IsZero())
}

func TestBarChartSetRangeDomains(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	cb := bc.box()
	yr := bc.getRanges()
	yr2 := bc.setRangeDomains(cb, yr)
	assert.NotZero(yr2.GetDomain())
}

func TestBarChartGetValueFormatters(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{}
	vf := bc.getValueFormatters()
	assert.NotNil(vf)
	assert.Equal("1234.00", vf(1234.0))

	bc.YAxis.ValueFormatter = func(_ interface{}) string { return "test" }
	assert.Equal("test", bc.getValueFormatters()(1234))
}

func TestBarChartGetAxesTicks(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		Bars: []Value{
			{Value: 1.0},
			{Value: 2.0},
			{Value: 3.0},
		},
	}

	r, err := PNG(128, 128)
	assert.Nil(err)
	yr := bc.getRanges()
	yf := bc.getValueFormatters()

	ticks := bc.getAxesTicks(r, yr, yf)
	assert.Empty(ticks)

	bc.YAxis.Style.Show = true
	ticks = bc.getAxesTicks(r, yr, yf)
	assert.Len(ticks, 2)
}

func TestBarChartCalculateEffectiveBarSpacing(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		Width:    1024,
		BarWidth: 10,
		Bars: []Value{
			{Value: 1.0, Label: "One"},
			{Value: 2.0, Label: "Two"},
			{Value: 3.0, Label: "Three"},
			{Value: 4.0, Label: "Four"},
			{Value: 5.0, Label: "Five"},
		},
	}

	spacing := bc.calculateEffectiveBarSpacing(bc.box())
	assert.NotZero(spacing)

	bc.BarWidth = 250
	spacing = bc.calculateEffectiveBarSpacing(bc.box())
	assert.Zero(spacing)
}

func TestBarChartCalculateEffectiveBarWidth(t *testing.T) {
	assert := assert.New(t)

	bc := BarChart{
		Width:    1024,
		BarWidth: 10,
		Bars: []Value{
			{Value: 1.0, Label: "One"},
			{Value: 2.0, Label: "Two"},
			{Value: 3.0, Label: "Three"},
			{Value: 4.0, Label: "Four"},
			{Value: 5.0, Label: "Five"},
		},
	}

	cb := bc.box()

	spacing := bc.calculateEffectiveBarSpacing(bc.box())
	assert.NotZero(spacing)

	barWidth := bc.calculateEffectiveBarWidth(bc.box(), spacing)
	assert.Equal(10, barWidth)

	bc.BarWidth = 250
	spacing = bc.calculateEffectiveBarSpacing(bc.box())
	assert.Zero(spacing)
	barWidth = bc.calculateEffectiveBarWidth(bc.box(), spacing)
	assert.Equal(199, barWidth)

	assert.Equal(cb.Width()+1, bc.calculateTotalBarWidth(barWidth, spacing))

	bw, bs, total := bc.calculateScaledTotalWidth(cb)
	assert.Equal(spacing, bs)
	assert.Equal(barWidth, bw)
	assert.Equal(cb.Width()+1, total)

}
<|endoftext|>


<commit_before>package mpb

import (
	"io"

	"github.com/acarl005/stripansi"
	"github.com/mattn/go-runewidth"
	"github.com/vbauerster/mpb/v7/decor"
	"github.com/vbauerster/mpb/v7/internal"
)

const (
	iLbound = iota
	iRbound
	iFiller
	iRefiller
	iPadding
	components
)

// BarStyleComposer interface.
type BarStyleComposer interface {
	BarFillerBuilder
	Lbound(string) BarStyleComposer
	Rbound(string) BarStyleComposer
	Filler(string) BarStyleComposer
	Refiller(string) BarStyleComposer
	Padding(string) BarStyleComposer
	TipOnComplete(string) BarStyleComposer
	Tip(frames ...string) BarStyleComposer
	Reverse() BarStyleComposer
}

type bFiller struct {
	components [components]*component
	tip        struct {
		count      uint
		onComplete *component
		frames     []*component
	}
	flush func(dst io.Writer, filling, padding [][]byte)
}

type component struct {
	width int
	bytes []byte
}

type barStyle struct {
	lbound        string
	rbound        string
	filler        string
	refiller      string
	padding       string
	tipOnComplete string
	tipFrames     []string
	rev           bool
}

// BarStyle constructs default bar style which can be altered via
// BarStyleComposer interface.
func BarStyle() BarStyleComposer {
	return &barStyle{
		lbound:    "[",
		rbound:    "]",
		filler:    "=",
		refiller:  "+",
		padding:   "-",
		tipFrames: []string{">"},
	}
}

func (s *barStyle) Lbound(bound string) BarStyleComposer {
	s.lbound = bound
	return s
}

func (s *barStyle) Rbound(bound string) BarStyleComposer {
	s.rbound = bound
	return s
}

func (s *barStyle) Filler(filler string) BarStyleComposer {
	s.filler = filler
	return s
}

func (s *barStyle) Refiller(refiller string) BarStyleComposer {
	s.refiller = refiller
	return s
}

func (s *barStyle) Padding(padding string) BarStyleComposer {
	s.padding = padding
	return s
}

func (s *barStyle) TipOnComplete(tip string) BarStyleComposer {
	s.tipOnComplete = tip
	return s
}

func (s *barStyle) Tip(frames ...string) BarStyleComposer {
	if len(frames) != 0 {
		s.tipFrames = append(s.tipFrames[:0], frames...)
	}
	return s
}

func (s *barStyle) Reverse() BarStyleComposer {
	s.rev = true
	return s
}

func (s *barStyle) Build() BarFiller {
	bf := new(bFiller)
	if s.rev {
		bf.flush = func(dst io.Writer, filling, padding [][]byte) {
			flush(dst, padding, filling)
		}
	} else {
		bf.flush = flush
	}
	bf.components[iLbound] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.lbound)),
		bytes: []byte(s.lbound),
	}
	bf.components[iRbound] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.rbound)),
		bytes: []byte(s.rbound),
	}
	bf.components[iFiller] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.filler)),
		bytes: []byte(s.filler),
	}
	bf.components[iRefiller] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.refiller)),
		bytes: []byte(s.refiller),
	}
	bf.components[iPadding] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.padding)),
		bytes: []byte(s.padding),
	}
	bf.tip.onComplete = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.tipOnComplete)),
		bytes: []byte(s.tipOnComplete),
	}
	bf.tip.frames = make([]*component, len(s.tipFrames))
	for i, t := range s.tipFrames {
		bf.tip.frames[i] = &component{
			width: runewidth.StringWidth(stripansi.Strip(t)),
			bytes: []byte(t),
		}
	}
	return bf
}

func (s *bFiller) Fill(w io.Writer, width int, stat decor.Statistics) {
	width = internal.CheckRequestedWidth(width, stat.AvailableWidth)
	brackets := s.components[iLbound].width + s.components[iRbound].width
	// don't count brackets as progress
	width -= brackets
	if width < 0 {
		return
	}

	w.Write(s.components[iLbound].bytes)
	defer w.Write(s.components[iRbound].bytes)

	if width == 0 {
		return
	}

	var filling [][]byte
	var padding [][]byte
	var tip *component
	var filled int
	var refWidth int
	curWidth := int(internal.PercentageRound(stat.Total, stat.Current, uint(width)))

	if stat.Current >= stat.Total {
		tip = s.tip.onComplete
	} else {
		tip = s.tip.frames[s.tip.count%uint(len(s.tip.frames))]
	}

	if curWidth > 0 {
		filling = append(filling, tip.bytes)
		filled += tip.width
		s.tip.count++
	}

	if stat.Refill > 0 {
		refWidth = int(internal.PercentageRound(stat.Total, stat.Refill, uint(width)))
		curWidth -= refWidth
		refWidth += curWidth
	}

	for filled < curWidth {
		if curWidth-filled >= s.components[iFiller].width {
			filling = append(filling, s.components[iFiller].bytes)
			if s.components[iFiller].width == 0 {
				break
			}
			filled += s.components[iFiller].width
		} else {
			filling = append(filling, []byte("…"))
			filled++
		}
	}

	for filled < refWidth {
		if refWidth-filled >= s.components[iRefiller].width {
			filling = append(filling, s.components[iRefiller].bytes)
			if s.components[iRefiller].width == 0 {
				break
			}
			filled += s.components[iRefiller].width
		} else {
			filling = append(filling, []byte("…"))
			filled++
		}
	}

	padWidth := width - filled
	for padWidth > 0 && padWidth >= s.components[iPadding].width {
		padding = append(padding, s.components[iPadding].bytes)
		if s.components[iPadding].width == 0 {
			break
		}
		padWidth -= s.components[iPadding].width
	}

	for padWidth > 0 {
		padding = append(padding, []byte("…"))
		padWidth--
	}

	s.flush(w, filling, padding)
}

func flush(dst io.Writer, filling, padding [][]byte) {
	for i := len(filling) - 1; i >= 0; i-- {
		dst.Write(filling[i])
	}
	for i := 0; i < len(padding); i++ {
		dst.Write(padding[i])
	}
}
<commit_msg>single padWidth loop<commit_after>package mpb

import (
	"io"

	"github.com/acarl005/stripansi"
	"github.com/mattn/go-runewidth"
	"github.com/vbauerster/mpb/v7/decor"
	"github.com/vbauerster/mpb/v7/internal"
)

const (
	iLbound = iota
	iRbound
	iFiller
	iRefiller
	iPadding
	components
)

// BarStyleComposer interface.
type BarStyleComposer interface {
	BarFillerBuilder
	Lbound(string) BarStyleComposer
	Rbound(string) BarStyleComposer
	Filler(string) BarStyleComposer
	Refiller(string) BarStyleComposer
	Padding(string) BarStyleComposer
	TipOnComplete(string) BarStyleComposer
	Tip(frames ...string) BarStyleComposer
	Reverse() BarStyleComposer
}

type bFiller struct {
	components [components]*component
	tip        struct {
		count      uint
		onComplete *component
		frames     []*component
	}
	flush func(dst io.Writer, filling, padding [][]byte)
}

type component struct {
	width int
	bytes []byte
}

type barStyle struct {
	lbound        string
	rbound        string
	filler        string
	refiller      string
	padding       string
	tipOnComplete string
	tipFrames     []string
	rev           bool
}

// BarStyle constructs default bar style which can be altered via
// BarStyleComposer interface.
func BarStyle() BarStyleComposer {
	return &barStyle{
		lbound:    "[",
		rbound:    "]",
		filler:    "=",
		refiller:  "+",
		padding:   "-",
		tipFrames: []string{">"},
	}
}

func (s *barStyle) Lbound(bound string) BarStyleComposer {
	s.lbound = bound
	return s
}

func (s *barStyle) Rbound(bound string) BarStyleComposer {
	s.rbound = bound
	return s
}

func (s *barStyle) Filler(filler string) BarStyleComposer {
	s.filler = filler
	return s
}

func (s *barStyle) Refiller(refiller string) BarStyleComposer {
	s.refiller = refiller
	return s
}

func (s *barStyle) Padding(padding string) BarStyleComposer {
	s.padding = padding
	return s
}

func (s *barStyle) TipOnComplete(tip string) BarStyleComposer {
	s.tipOnComplete = tip
	return s
}

func (s *barStyle) Tip(frames ...string) BarStyleComposer {
	if len(frames) != 0 {
		s.tipFrames = append(s.tipFrames[:0], frames...)
	}
	return s
}

func (s *barStyle) Reverse() BarStyleComposer {
	s.rev = true
	return s
}

func (s *barStyle) Build() BarFiller {
	bf := new(bFiller)
	if s.rev {
		bf.flush = func(dst io.Writer, filling, padding [][]byte) {
			flush(dst, padding, filling)
		}
	} else {
		bf.flush = flush
	}
	bf.components[iLbound] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.lbound)),
		bytes: []byte(s.lbound),
	}
	bf.components[iRbound] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.rbound)),
		bytes: []byte(s.rbound),
	}
	bf.components[iFiller] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.filler)),
		bytes: []byte(s.filler),
	}
	bf.components[iRefiller] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.refiller)),
		bytes: []byte(s.refiller),
	}
	bf.components[iPadding] = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.padding)),
		bytes: []byte(s.padding),
	}
	bf.tip.onComplete = &component{
		width: runewidth.StringWidth(stripansi.Strip(s.tipOnComplete)),
		bytes: []byte(s.tipOnComplete),
	}
	bf.tip.frames = make([]*component, len(s.tipFrames))
	for i, t := range s.tipFrames {
		bf.tip.frames[i] = &component{
			width: runewidth.StringWidth(stripansi.Strip(t)),
			bytes: []byte(t),
		}
	}
	return bf
}

func (s *bFiller) Fill(w io.Writer, width int, stat decor.Statistics) {
	width = internal.CheckRequestedWidth(width, stat.AvailableWidth)
	brackets := s.components[iLbound].width + s.components[iRbound].width
	// don't count brackets as progress
	width -= brackets
	if width < 0 {
		return
	}

	w.Write(s.components[iLbound].bytes)
	defer w.Write(s.components[iRbound].bytes)

	if width == 0 {
		return
	}

	var filling [][]byte
	var padding [][]byte
	var tip *component
	var filled int
	var refWidth int
	curWidth := int(internal.PercentageRound(stat.Total, stat.Current, uint(width)))

	if stat.Current >= stat.Total {
		tip = s.tip.onComplete
	} else {
		tip = s.tip.frames[s.tip.count%uint(len(s.tip.frames))]
	}

	if curWidth > 0 {
		filling = append(filling, tip.bytes)
		filled += tip.width
		s.tip.count++
	}

	if stat.Refill > 0 {
		refWidth = int(internal.PercentageRound(stat.Total, stat.Refill, uint(width)))
		curWidth -= refWidth
		refWidth += curWidth
	}

	for filled < curWidth {
		if curWidth-filled >= s.components[iFiller].width {
			filling = append(filling, s.components[iFiller].bytes)
			if s.components[iFiller].width == 0 {
				break
			}
			filled += s.components[iFiller].width
		} else {
			filling = append(filling, []byte("…"))
			filled++
		}
	}

	for filled < refWidth {
		if refWidth-filled >= s.components[iRefiller].width {
			filling = append(filling, s.components[iRefiller].bytes)
			if s.components[iRefiller].width == 0 {
				break
			}
			filled += s.components[iRefiller].width
		} else {
			filling = append(filling, []byte("…"))
			filled++
		}
	}

	padWidth := width - filled
	for padWidth > 0 {
		if padWidth >= s.components[iPadding].width {
			padding = append(padding, s.components[iPadding].bytes)
			if s.components[iPadding].width == 0 {
				break
			}
			padWidth -= s.components[iPadding].width
		} else {
			padding = append(padding, []byte("…"))
			padWidth--
		}
	}

	s.flush(w, filling, padding)
}

func flush(dst io.Writer, filling, padding [][]byte) {
	for i := len(filling) - 1; i >= 0; i-- {
		dst.Write(filling[i])
	}
	for i := 0; i < len(padding); i++ {
		dst.Write(padding[i])
	}
}
<|endoftext|>


<commit_before>package golangdb

/* Defines a type of database engine */
type DatabaseEngine int

/* Constants used to specify a type of database connection */
const (
	NONE DatabaseEngine = iota
	SQLITE
	MYSQL
	MSSQL
	TESTDB
)

var databaseEngineNames = map[DatabaseEngine]string{
	NONE:   "None",
	SQLITE: "SQLite",
	MYSQL:  "MySQL",
	MSSQL:  "MSSQL",
	TESTDB: "Test (fake) DB",
}

func (this *DatabaseEngine) ToString() string {
	return databaseEngineNames[*this]
}<commit_msg>Added function to get DatabaseEngineType from string name<commit_after>package golangdb

/* Defines a type of database engine */
type DatabaseEngine int

/* Constants used to specify a type of database connection */
const (
	NONE DatabaseEngine = iota
	SQLITE
	MYSQL
	MSSQL
	TESTDB
)

var databaseEngineNames = map[DatabaseEngine]string{
	NONE:   "None",
	SQLITE: "SQLite",
	MYSQL:  "MySQL",
	MSSQL:  "MSSQL",
	TESTDB: "Test (fake) DB",
}

func GetDatabaseEngineFromName(name string) DatabaseEngine {
	for k, v := range databaseEngineNames {
		if v == name {
			return k
		}
	}

	return NONE
}

func (this *DatabaseEngine) ToString() string {
	return databaseEngineNames[*this]
}<|endoftext|>


<commit_before>package mk2if

import (
	"errors"
	"fmt"
	"io"
	"log"
	"math"
	"sync"
	"time"
)

type scaling struct {
	scale  float64
	offset float64
}

type mk2Ser struct {
	info   *Mk2Info
	report *Mk2Info
	p      io.ReadWriter
	sc     []scaling
	scN    int
	run    chan struct{}
	locked bool
	sync.RWMutex
}

func NewMk2Connection(dev io.ReadWriter) (Mk2If, error) {
	mk2 := &mk2Ser{}
	mk2.p = dev
	mk2.info = &Mk2Info{}
	mk2.report = &Mk2Info{}
	mk2.scN = 0
	mk2.locked = false
	mk2.sc = make([]scaling, 0)
	mk2.setTarget()
	mk2.run = make(chan struct{})
	go mk2.frameLock()
	return mk2, nil
}

// Locks to incoming frame.
func (mk2 *mk2Ser) frameLock() {

	frame := make([]byte, 256)
	var size byte
	for {
		select {
		case <-mk2.run:
			break
		default:
			if mk2.locked {
				size = mk2.readByte()
				l, err := io.ReadFull(mk2.p, frame[0:int(size)+1])
				if err != nil {
					mk2.addError(fmt.Errorf("Read Error: %v", err))
					mk2.locked = false
				} else if l != int(size)+1 {
					mk2.addError(errors.New("Read Length Error"))
					mk2.locked = false
				} else {
					mk2.handleFrame(size, frame[0:int(size+1)])
				}
			} else {
				tmp := mk2.readByte()
				if tmp == 0xff || tmp == 0x20 {
					l, err := io.ReadFull(mk2.p, frame[0:int(size)])
					if err != nil {
						mk2.addError(fmt.Errorf("Read Error: %v", err))
						time.Sleep(1 * time.Second)
					} else if l != int(size) {
						mk2.addError(errors.New("Read Length Error"))
					} else {
						if checkChecksum(size, tmp, frame[0:int(size)]) {
							mk2.locked = true
							log.Printf("Locked")
						}
					}
				}
				size = tmp
			}
		}
	}
}

// Close Mk2
func (mk2 *mk2Ser) Close() {
	close(mk2.run)
}

// Returns last known state with all reported errors since previous poll.
// Mk2Info.Valid will be false if no polling has completed.
func (mk2 *mk2Ser) GetMk2Info() *Mk2Info {
	mk2.RLock()
	defer mk2.RUnlock()
	return mk2.report
}

func (mk2 *mk2Ser) readByte() byte {
	buffer := make([]byte, 1)
	_, err := io.ReadFull(mk2.p, buffer)
	if err != nil {
		mk2.addError(fmt.Errorf("Read error: %v", err))
		return 0
	}
	return buffer[0]
}

// Adds error to error slice.
func (mk2 *mk2Ser) addError(err error) {
	if mk2.info.Errors == nil {
		mk2.info.Errors = make([]error, 0)
	}
	mk2.info.Errors = append(mk2.info.Errors, err)
	mk2.info.Valid = false
}

// Updates report.
func (mk2 *mk2Ser) updateReport() {
	mk2.Lock()
	defer mk2.Unlock()
	*mk2.report = *mk2.info
	mk2.info.Errors = nil
}

// Checks for valid frame and chooses decoding.
func (mk2 *mk2Ser) handleFrame(l byte, frame []byte) {
	if checkChecksum(l, frame[0], frame[1:]) {
		switch frame[0] {
		case 0xff:
			switch frame[1] {
			case 0x56: // V
				mk2.versionDecode(frame[2:])
			case 0x57:
				switch frame[2] {
				case 0x8e:
					mk2.scaleDecode(frame[2:])
				case 0x85:
					mk2.stateDecode(frame[2:])
				}

			case 0x4C: // L
				mk2.ledDecode(frame[2:])
			}

		case 0x20:
			switch frame[5] {
			case 0x0C:
				mk2.dcDecode(frame[1:])
			case 0x08:
				mk2.acDecode(frame[1:])
			}
		}
	} else {
		log.Printf("Failed")
		mk2.locked = false
	}
}

// Set the target VBus device.
func (mk *mk2Ser) setTarget() {
	cmd := make([]byte, 3)
	cmd[0] = 0x41 // A
	cmd[1] = 0x01
	cmd[2] = 0x00
	mk.sendCommand(cmd)
}

// Request the scaling factor for entry 'in'.
func (mk *mk2Ser) reqScaleFactor(in byte) {
	cmd := make([]byte, 4)
	cmd[0] = 0x57 // W
	cmd[1] = 0x36
	cmd[2] = in
	mk.sendCommand(cmd)
}

// Decode the scale factor frame.
func (mk *mk2Ser) scaleDecode(frame []byte) {
	scl := uint16(frame[2])<<8 + uint16(frame[1])
	ofs := int16(uint16(frame[5])<<8 + uint16(frame[4]))

	tmp := scaling{}
	tmp.offset = float64(ofs)
	if scl >= 0x4000 {
		tmp.scale = math.Abs(1 / (0x8000 - float64(scl)))
	} else {
		tmp.scale = math.Abs(float64(scl))
	}
	mk.sc = append(mk.sc, tmp)

	mk.scN++
	if mk.scN < 14 {
		mk.reqScaleFactor(byte(mk.scN))
	} else {
		log.Print("Monitoring starting.")
	}

}

// Decode the version number
func (mk *mk2Ser) versionDecode(frame []byte) {
	mk.info.Version = 0
	mk.info.Valid = true
	for i := 0; i < 4; i++ {
		mk.info.Version += uint32(frame[i]) << uint(i) * 8
	}

	if mk.scN < 14 {
		log.Print("Get scaling factors.")
		mk.reqScaleFactor(byte(mk.scN))
	} else {
		// Send DC status request
		cmd := make([]byte, 2)
		cmd[0] = 0x46 //F
		cmd[1] = 0
		mk.sendCommand(cmd)
	}
}

// Apply scaling to float
func (mk *mk2Ser) applyScale(value float64, scale int) float64 {
	return mk.sc[scale].scale * (value + mk.sc[scale].offset)
}

// Convert bytes->int16->float
func getSigned(data []byte) float64 {
	return float64(int16(data[0]) + int16(data[1])<<8)
}

// Convert bytes->uint32->float
func getUnsigned(data []byte) float64 {
	return float64(uint32(data[0]) + uint32(data[1])<<8 + uint32(data[2])<<16)
}

// Decodes DC frame.
func (mk *mk2Ser) dcDecode(frame []byte) {
	mk.info.BatVoltage = mk.applyScale(getSigned(frame[5:7]), 4)

	usedC := mk.applyScale(getUnsigned(frame[7:10]), 5)
	chargeC := mk.applyScale(getUnsigned(frame[10:13]), 5)
	mk.info.BatCurrent = usedC - chargeC

	mk.info.OutFrequency = 10 / (mk.applyScale(float64(frame[13]), 7))

	// Send L1 status request
	cmd := make([]byte, 2)
	cmd[0] = 0x46 //F
	cmd[1] = 1
	mk.sendCommand(cmd)
}

// Decodes AC frame.
func (mk *mk2Ser) acDecode(frame []byte) {
	mk.info.InVoltage = mk.applyScale(getSigned(frame[5:7]), 0)
	mk.info.InCurrent = mk.applyScale(getSigned(frame[7:9]), 1)
	mk.info.OutVoltage = mk.applyScale(getSigned(frame[9:11]), 2)
	mk.info.OutCurrent = mk.applyScale(getSigned(frame[11:13]), 3)

	if frame[13] == 0xff {
		mk.info.InFrequency = 0
	} else {
		mk.info.InFrequency = 10 / (mk.applyScale(float64(frame[13]), 8))
	}

	// Send status request
	cmd := make([]byte, 1)
	cmd[0] = 0x4C //F
	mk.sendCommand(cmd)
}

// Decode charge state of battery.
func (mk *mk2Ser) stateDecode(frame []byte) {
	mk.info.ChargeState = mk.applyScale(getSigned(frame[1:3]), 13)
	mk.updateReport()
}

// Decode the LED state frame.
func (mk *mk2Ser) ledDecode(frame []byte) {
	mk.info.LedListOn = getLeds(frame[0])
	mk.info.LedListBlink = getLeds(frame[1])

	// Send charge state request
	cmd := make([]byte, 4)
	cmd[0] = 0x57 //W
	cmd[1] = 0x30
	cmd[2] = 13
	mk.sendCommand(cmd)
}

// Adds active LEDs to list.
func getLeds(led byte) []int {
	leds := make([]int, 0)
	for i := 0; i < 8; i++ {
		t := (led >> uint(i)) & 1
		if t == 1 {
			leds = append(leds, int(1<<uint(i)))
		}
	}
	return leds
}

// Adds header and trailing crc for frame to send.
func (mk2 *mk2Ser) sendCommand(data []byte) {
	l := len(data)
	dataOut := make([]byte, l+3)
	dataOut[0] = byte(l + 1)
	dataOut[1] = 0xff
	cr := -dataOut[0] - dataOut[1]
	for i := 0; i < len(data); i++ {
		cr = cr - data[i]
		dataOut[i+2] = data[i]
	}
	dataOut[l+2] = cr

	_, err := mk2.p.Write(dataOut)
	if err != nil {
		mk2.addError(fmt.Errorf("Write error: %v", err))
	}
}

// Checks the frame crc.
func checkChecksum(l, t byte, d []byte) bool {
	cr := (uint16(l) + uint16(t)) % 256
	for i := 0; i < len(d); i++ {
		cr = (cr + uint16(d[i])) % 256
	}
	if cr == 0 {
		return true
	}
	return false
}
<commit_msg>Fix data race.<commit_after>package mk2if

import (
	"errors"
	"fmt"
	"io"
	"log"
	"math"
	"sync"
	"time"
)

type scaling struct {
	scale  float64
	offset float64
}

type mk2Ser struct {
	info   *Mk2Info
	report *Mk2Info
	p      io.ReadWriter
	sc     []scaling
	scN    int
	run    chan struct{}
	locked bool
	sync.RWMutex
}

func NewMk2Connection(dev io.ReadWriter) (Mk2If, error) {
	mk2 := &mk2Ser{}
	mk2.p = dev
	mk2.info = &Mk2Info{}
	mk2.report = &Mk2Info{}
	mk2.scN = 0
	mk2.locked = false
	mk2.sc = make([]scaling, 0)
	mk2.setTarget()
	mk2.run = make(chan struct{})
	go mk2.frameLock()
	return mk2, nil
}

// Locks to incoming frame.
func (mk2 *mk2Ser) frameLock() {

	frame := make([]byte, 256)
	var size byte
	for {
		select {
		case <-mk2.run:
			break
		default:
			if mk2.locked {
				size = mk2.readByte()
				l, err := io.ReadFull(mk2.p, frame[0:int(size)+1])
				if err != nil {
					mk2.addError(fmt.Errorf("Read Error: %v", err))
					mk2.locked = false
				} else if l != int(size)+1 {
					mk2.addError(errors.New("Read Length Error"))
					mk2.locked = false
				} else {
					mk2.handleFrame(size, frame[0:int(size+1)])
				}
			} else {
				tmp := mk2.readByte()
				if tmp == 0xff || tmp == 0x20 {
					l, err := io.ReadFull(mk2.p, frame[0:int(size)])
					if err != nil {
						mk2.addError(fmt.Errorf("Read Error: %v", err))
						time.Sleep(1 * time.Second)
					} else if l != int(size) {
						mk2.addError(errors.New("Read Length Error"))
					} else {
						if checkChecksum(size, tmp, frame[0:int(size)]) {
							mk2.locked = true
							log.Printf("Locked")
						}
					}
				}
				size = tmp
			}
		}
	}
}

// Close Mk2
func (mk2 *mk2Ser) Close() {
	close(mk2.run)
}

// Returns last known state with all reported errors since previous poll.
// Mk2Info.Valid will be false if no polling has completed.
func (mk2 *mk2Ser) GetMk2Info() *Mk2Info {
	mk2.RLock()
	defer mk2.RUnlock()
	return mk2.report
}

func (mk2 *mk2Ser) readByte() byte {
	buffer := make([]byte, 1)
	_, err := io.ReadFull(mk2.p, buffer)
	if err != nil {
		mk2.addError(fmt.Errorf("Read error: %v", err))
		return 0
	}
	return buffer[0]
}

// Adds error to error slice.
func (mk2 *mk2Ser) addError(err error) {
	if mk2.info.Errors == nil {
		mk2.info.Errors = make([]error, 0)
	}
	mk2.info.Errors = append(mk2.info.Errors, err)
	mk2.info.Valid = false
}

// Updates report.
func (mk2 *mk2Ser) updateReport() {
	mk2.Lock()
	defer mk2.Unlock()
	mk2.report = mk2.info
	mk2.info = &Mk2Info{}
}

// Checks for valid frame and chooses decoding.
func (mk2 *mk2Ser) handleFrame(l byte, frame []byte) {
	if checkChecksum(l, frame[0], frame[1:]) {
		switch frame[0] {
		case 0xff:
			switch frame[1] {
			case 0x56: // V
				mk2.versionDecode(frame[2:])
			case 0x57:
				switch frame[2] {
				case 0x8e:
					mk2.scaleDecode(frame[2:])
				case 0x85:
					mk2.stateDecode(frame[2:])
				}

			case 0x4C: // L
				mk2.ledDecode(frame[2:])
			}

		case 0x20:
			switch frame[5] {
			case 0x0C:
				mk2.dcDecode(frame[1:])
			case 0x08:
				mk2.acDecode(frame[1:])
			}
		}
	} else {
		log.Printf("Failed")
		mk2.locked = false
	}
}

// Set the target VBus device.
func (mk *mk2Ser) setTarget() {
	cmd := make([]byte, 3)
	cmd[0] = 0x41 // A
	cmd[1] = 0x01
	cmd[2] = 0x00
	mk.sendCommand(cmd)
}

// Request the scaling factor for entry 'in'.
func (mk *mk2Ser) reqScaleFactor(in byte) {
	cmd := make([]byte, 4)
	cmd[0] = 0x57 // W
	cmd[1] = 0x36
	cmd[2] = in
	mk.sendCommand(cmd)
}

// Decode the scale factor frame.
func (mk *mk2Ser) scaleDecode(frame []byte) {
	scl := uint16(frame[2])<<8 + uint16(frame[1])
	ofs := int16(uint16(frame[5])<<8 + uint16(frame[4]))

	tmp := scaling{}
	tmp.offset = float64(ofs)
	if scl >= 0x4000 {
		tmp.scale = math.Abs(1 / (0x8000 - float64(scl)))
	} else {
		tmp.scale = math.Abs(float64(scl))
	}
	mk.sc = append(mk.sc, tmp)

	mk.scN++
	if mk.scN < 14 {
		mk.reqScaleFactor(byte(mk.scN))
	} else {
		log.Print("Monitoring starting.")
	}

}

// Decode the version number
func (mk *mk2Ser) versionDecode(frame []byte) {
	mk.info.Version = 0
	mk.info.Valid = true
	for i := 0; i < 4; i++ {
		mk.info.Version += uint32(frame[i]) << uint(i) * 8
	}

	if mk.scN < 14 {
		log.Print("Get scaling factors.")
		mk.reqScaleFactor(byte(mk.scN))
	} else {
		// Send DC status request
		cmd := make([]byte, 2)
		cmd[0] = 0x46 //F
		cmd[1] = 0
		mk.sendCommand(cmd)
	}
}

// Apply scaling to float
func (mk *mk2Ser) applyScale(value float64, scale int) float64 {
	return mk.sc[scale].scale * (value + mk.sc[scale].offset)
}

// Convert bytes->int16->float
func getSigned(data []byte) float64 {
	return float64(int16(data[0]) + int16(data[1])<<8)
}

// Convert bytes->uint32->float
func getUnsigned(data []byte) float64 {
	return float64(uint32(data[0]) + uint32(data[1])<<8 + uint32(data[2])<<16)
}

// Decodes DC frame.
func (mk *mk2Ser) dcDecode(frame []byte) {
	mk.info.BatVoltage = mk.applyScale(getSigned(frame[5:7]), 4)

	usedC := mk.applyScale(getUnsigned(frame[7:10]), 5)
	chargeC := mk.applyScale(getUnsigned(frame[10:13]), 5)
	mk.info.BatCurrent = usedC - chargeC

	mk.info.OutFrequency = 10 / (mk.applyScale(float64(frame[13]), 7))

	// Send L1 status request
	cmd := make([]byte, 2)
	cmd[0] = 0x46 //F
	cmd[1] = 1
	mk.sendCommand(cmd)
}

// Decodes AC frame.
func (mk *mk2Ser) acDecode(frame []byte) {
	mk.info.InVoltage = mk.applyScale(getSigned(frame[5:7]), 0)
	mk.info.InCurrent = mk.applyScale(getSigned(frame[7:9]), 1)
	mk.info.OutVoltage = mk.applyScale(getSigned(frame[9:11]), 2)
	mk.info.OutCurrent = mk.applyScale(getSigned(frame[11:13]), 3)

	if frame[13] == 0xff {
		mk.info.InFrequency = 0
	} else {
		mk.info.InFrequency = 10 / (mk.applyScale(float64(frame[13]), 8))
	}

	// Send status request
	cmd := make([]byte, 1)
	cmd[0] = 0x4C //F
	mk.sendCommand(cmd)
}

// Decode charge state of battery.
func (mk *mk2Ser) stateDecode(frame []byte) {
	mk.info.ChargeState = mk.applyScale(getSigned(frame[1:3]), 13)
	mk.updateReport()
}

// Decode the LED state frame.
func (mk *mk2Ser) ledDecode(frame []byte) {
	mk.info.LedListOn = getLeds(frame[0])
	mk.info.LedListBlink = getLeds(frame[1])

	// Send charge state request
	cmd := make([]byte, 4)
	cmd[0] = 0x57 //W
	cmd[1] = 0x30
	cmd[2] = 13
	mk.sendCommand(cmd)
}

// Adds active LEDs to list.
func getLeds(led byte) []int {
	leds := make([]int, 0)
	for i := 0; i < 8; i++ {
		t := (led >> uint(i)) & 1
		if t == 1 {
			leds = append(leds, int(1<<uint(i)))
		}
	}
	return leds
}

// Adds header and trailing crc for frame to send.
func (mk2 *mk2Ser) sendCommand(data []byte) {
	l := len(data)
	dataOut := make([]byte, l+3)
	dataOut[0] = byte(l + 1)
	dataOut[1] = 0xff
	cr := -dataOut[0] - dataOut[1]
	for i := 0; i < len(data); i++ {
		cr = cr - data[i]
		dataOut[i+2] = data[i]
	}
	dataOut[l+2] = cr

	_, err := mk2.p.Write(dataOut)
	if err != nil {
		mk2.addError(fmt.Errorf("Write error: %v", err))
	}
}

// Checks the frame crc.
func checkChecksum(l, t byte, d []byte) bool {
	cr := (uint16(l) + uint16(t)) % 256
	for i := 0; i < len(d); i++ {
		cr = (cr + uint16(d[i])) % 256
	}
	if cr == 0 {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Escalator
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct {
}

type Ticket struct {
	TicketID        string
	Timestamp       string // time of ticket creation
	Trainstation    string
	Platform        string
	Device          string // the device in need of repairs (i.e. left upwards escalator)
	Status          string // current ticket status (not repair status), i.e. "OPEN". TODO: rework as some sort of enum to limit input.
	TechPart        string // representing the defective part of the escalator
	ErrorID         string
	ErrorMessage    string
	ServiceProvider string // the assigned service provider thats commissioned to do the repairs
	SpEmployee      string // repairman assigned by service_provider
	SpeCommentary   string // additional commentary, optionally to be filled out by the sp_employee
	EstRepairTime   string
	RepairStatus    string
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	err := stub.PutState("counter", []byte("0"))
	if err != nil {
		return nil, err
	}
	return nil, nil
}

//Invoke is the entry point for all other asset altering functions called by an CC invocation
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	switch function {
	case "createTicket":
		return t.createTicket(stub, args)
	case "assignTicket":
		return t.assignTicket(stub, args)
		//	case "acceptTicket":
		//		return t.acceptTicket(stub, args)
	case "assignMechanic":
		return t.assignMechanic(stub, args)
	case "startJourney":
		return t.startJourney(stub, args)
	case "onArrival":
		return t.onArrival(stub, args)
	case "startRepair":
		return t.startRepair(stub, args)
	case "finishRepair":
		return t.finishRepair(stub, args)
	case "createDefaultTicket":
		return t.createDefaultTicket(stub, args)
	}

	return nil, errors.New("Received unknown function invocation: " + function)

}
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	switch function {
	case "getFullTicket":
		return t.getFullTicket(stub, args)
	case "getCounter":
		return t.getCounter(stub, args)
	case "getTicketsByRange":
		return t.getTicketsByRange(stub, args)
	case "getAllTickets":
		return t.getAllTickets(stub, args)
	}
	fmt.Println("query did not find func: " + function)
	return nil, errors.New("Received unknown function query")
}

func (t *SimpleChaincode) getCounter(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	counterAsByteArr, err := stub.GetState("counter")
	if err != nil {
		return nil, errors.New("Query failure for getCounter")
	}
	return counterAsByteArr, nil
}

func (t *SimpleChaincode) getFullTicket(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Wrong number of arguments. Must be (1): TicketID")
	}

	//	var ticketAsByteArr []byte

	ticketAsByteArr, err := stub.GetState(args[0])

	if err != nil {
		return nil, errors.New("Query failure for getFullTicket")
	}

	return ticketAsByteArr, nil
}

//returns a collection of Tickets with a given Status. Expects either "EINGETROFFEN", "ZUGEWIESEN", or "ERLEDIGT" as single input argument.
func (t *SimpleChaincode) getTicketsByStatus(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1: Status")
	}

	//construct iterator
	startKey := "1"
	endKey, _ := stub.GetState("counter")

	resultsIterator, err := stub.RangeQueryState(startKey, endKey)
	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()
	//----------------------------------------------
	// buffer is a JSON array containing QueryResults
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false

	var tempTicket Ticket //place to unmarshall our Tickets in []byte-Form into.

	for resultsIterator.HasNext() {
		_, queryResultValue, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}

		json.Unmarshal(queryResultValue, &tempTicket)

		if strings.EqualFold(tempTicket.Status, arg[0]) {

			// Add a comma before array members, suppress it for the first array member
			if bArrayMemberAlreadyWritten == true {
				buffer.WriteString(",")
			}
			buffer.WriteString("{")
			//		buffer.WriteString("\"")
			//		buffer.WriteString(queryResultKey)
			//		buffer.WriteString("\"")

			//		buffer.WriteString(", \"Ticket\":")

			buffer.WriteString(string(queryResultValue))
			buffer.WriteString("}")
			bArrayMemberAlreadyWritten = true
		}
	}
	buffer.WriteString("]")
	//----------------------------------------------
	return buffer.Bytes(), nil
}

func (t *SimpleChaincode) getTicketsByRange(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	startKey := args[0]
	endKey := args[1]

	resultsIterator, err := stub.RangeQueryState(startKey, endKey)
	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()

	// buffer is a JSON array containing QueryResults
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		_, queryResultValue, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}
		// Add a comma before array members, suppress it for the first array member
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}

		buffer.WriteString("{")
		//		buffer.WriteString("\"")
		//		buffer.WriteString(queryResultKey)
		//		buffer.WriteString("\"")

		//		buffer.WriteString(", \"Ticket\":")

		buffer.WriteString(string(queryResultValue))
		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")

	return buffer.Bytes(), nil
}

func (t *SimpleChaincode) getAllTickets(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	counterAsByteArr, err := stub.GetState("counter")
	s := string(counterAsByteArr[:])
	if err != nil {
		return nil, err
	}

	return t.getTicketsByRange(stub, []string{"1", s})
}

// Create a new ticket and store it on the ledger with ticket_id as key.
//
func (t *SimpleChaincode) createTicket(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 7 {
		return nil, errors.New("Wrong number of arguments, must be 7: Timestamp, Trainstation, Platform, Device, TechPart, ErrorID and ErrorMessage")
	}

	idAsBytes, _ := stub.GetState("counter") // get highest current ticket id number from worldstate, increment, and set as
	str := string(idAsBytes[:])              //	TicketID for newly created Ticket & update highest running ticket number.
	idAsInt, _ := strconv.Atoi(str)          // TODO This seems unnecessarily complicated.
	idAsInt++                                //
	idAsString := strconv.Itoa(idAsInt)
	err := stub.PutState("counter", []byte(idAsString))

	var ticket = Ticket{
		TicketID:     idAsString,
		Timestamp:    args[0],
		Trainstation: args[1],
		Platform:     args[2],
		Device:       args[3],
		Status:       "EINGETROFFEN",
		TechPart:     args[4],
		ErrorID:      args[5],
		ErrorMessage: args[6],
	}

	state, _ := json.Marshal(ticket)

	stub.PutState(idAsString, state)
	if err != nil {
		return nil, err
	}
	return nil, nil
}

// Creates a default ticket. Maybe change to just call createTicket with arguments.
//
func (t *SimpleChaincode) createDefaultTicket(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {

	idAsBytes, _ := stub.GetState("counter") // get highest current ticket id number from worldstate, increment and set as
	str := string(idAsBytes[:])              //	TicketID for newly created Ticket & update highest running ticket number.
	idAsInt, _ := strconv.Atoi(str)          //
	idAsInt++                                // TODO This seems unnecessarily complicated.
	idAsString := strconv.Itoa(idAsInt)
	err := stub.PutState("counter", []byte(idAsString))

	var ticket = Ticket{
		TicketID:     idAsString,
		Timestamp:    "2017-12-03T12:35:00.000Z",
		Trainstation: "Bonn Hbf",
		Platform:     "Gleis 5",
		Device:       "Rolltreppe nach oben",
		Status:       "Eingetroffen",
		TechPart:     "Motor RTM-X 64",
		ErrorID:      "#2356-102",
		ErrorMessage: "Totalausfall",
	}
	state, _ := json.Marshal(ticket)

	stub.PutState(idAsString, state)
	if err != nil {
		return nil, err
	}
	return nil, nil
}

// Assign an existing Ticket to a ServiceProvider. Arguments should be TicketID and the name of the serviceprovider that the ticket gets assigned to.
func (t *SimpleChaincode) assignTicket(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 2 {
		return nil, errors.New("Wrong number of arguments, must be 2: TicketID and ServiceProvider")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0]) //get ticket from world state as byte array
	if err != nil {
		return nil, err
	}
	ticket := new(Ticket)
	json.Unmarshal(state, ticket)    // translate back to struct (well, to "pointer to struct" actually)
	ticket.ServiceProvider = args[1] //set new  ServiceProvider
	ticket.Status = "ZUGEWIESEN"     //update status to "assigned"
	ticket.RepairStatus = "Wird geprueft"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}

func (t *SimpleChaincode) assignMechanic(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 2 {
		return nil, errors.New("Wrong number of arguments, must be 2: TicketID and SpEmployee ")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.SpEmployee = args[1]
	ticket.RepairStatus = "Ticket erhalten"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}

func (t *SimpleChaincode) startJourney(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Wrong number of arguments, must be 1: TicketID")
	}

	var state []byte
	var err error
	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.RepairStatus = "Techniker in Anfahrt"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}

func (t *SimpleChaincode) onArrival(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 3 {
		return nil, errors.New("Wrong number of arguments, must be 2: TicketID,EstRepairTime and SpeCommentary ")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.SpeCommentary = args[1]
	ticket.EstRepairTime = args[2]
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}
func (t *SimpleChaincode) startRepair(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Wrong number of arguments, must be 1: TicketID")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.RepairStatus = "Reparatur begonnen"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}

func (t *SimpleChaincode) finishRepair(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Wrong number of arguments, must be 1: TicketID")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.RepairStatus = "Reparatur abgeschlossen"
	ticket.Status = "ERLEDIGT"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}
<commit_msg>fix endKey for Iterator<commit_after>// Escalator
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct {
}

type Ticket struct {
	TicketID        string
	Timestamp       string // time of ticket creation
	Trainstation    string
	Platform        string
	Device          string // the device in need of repairs (i.e. left upwards escalator)
	Status          string // current ticket status (not repair status), i.e. "OPEN". TODO: rework as some sort of enum to limit input.
	TechPart        string // representing the defective part of the escalator
	ErrorID         string
	ErrorMessage    string
	ServiceProvider string // the assigned service provider thats commissioned to do the repairs
	SpEmployee      string // repairman assigned by service_provider
	SpeCommentary   string // additional commentary, optionally to be filled out by the sp_employee
	EstRepairTime   string
	RepairStatus    string
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	err := stub.PutState("counter", []byte("0"))
	if err != nil {
		return nil, err
	}
	return nil, nil
}

//Invoke is the entry point for all other asset altering functions called by an CC invocation
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	switch function {
	case "createTicket":
		return t.createTicket(stub, args)
	case "assignTicket":
		return t.assignTicket(stub, args)
		//	case "acceptTicket":
		//		return t.acceptTicket(stub, args)
	case "assignMechanic":
		return t.assignMechanic(stub, args)
	case "startJourney":
		return t.startJourney(stub, args)
	case "onArrival":
		return t.onArrival(stub, args)
	case "startRepair":
		return t.startRepair(stub, args)
	case "finishRepair":
		return t.finishRepair(stub, args)
	case "createDefaultTicket":
		return t.createDefaultTicket(stub, args)
	}

	return nil, errors.New("Received unknown function invocation: " + function)

}
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	switch function {
	case "getFullTicket":
		return t.getFullTicket(stub, args)
	case "getCounter":
		return t.getCounter(stub, args)
	case "getTicketsByRange":
		return t.getTicketsByRange(stub, args)
	case "getAllTickets":
		return t.getAllTickets(stub, args)
	}
	fmt.Println("query did not find func: " + function)
	return nil, errors.New("Received unknown function query")
}

func (t *SimpleChaincode) getCounter(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	counterAsByteArr, err := stub.GetState("counter")
	if err != nil {
		return nil, errors.New("Query failure for getCounter")
	}
	return counterAsByteArr, nil
}

func (t *SimpleChaincode) getFullTicket(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Wrong number of arguments. Must be (1): TicketID")
	}

	//	var ticketAsByteArr []byte

	ticketAsByteArr, err := stub.GetState(args[0])

	if err != nil {
		return nil, errors.New("Query failure for getFullTicket")
	}

	return ticketAsByteArr, nil
}

//returns a collection of Tickets with a given Status. Expects either "EINGETROFFEN", "ZUGEWIESEN", or "ERLEDIGT" as single input argument.
func (t *SimpleChaincode) getTicketsByStatus(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1: Status")
	}

	//construct iterator
	startKey := "1"
	MaxIdAsBytes, _ := stub.GetState("counter")
	endKey := string(MaxIdAsBytes[:])

	resultsIterator, err := stub.RangeQueryState(startKey, endKey)
	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()
	//----------------------------------------------
	// buffer is a JSON array containing QueryResults
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false

	var tempTicket Ticket //place to unmarshall our Tickets in []byte-Form into.

	for resultsIterator.HasNext() {
		_, queryResultValue, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}

		json.Unmarshal(queryResultValue, &tempTicket)

		if strings.EqualFold(tempTicket.Status, arg[0]) {

			// Add a comma before array members, suppress it for the first array member
			if bArrayMemberAlreadyWritten == true {
				buffer.WriteString(",")
			}
			buffer.WriteString("{")
			//		buffer.WriteString("\"")
			//		buffer.WriteString(queryResultKey)
			//		buffer.WriteString("\"")

			//		buffer.WriteString(", \"Ticket\":")

			buffer.WriteString(string(queryResultValue))
			buffer.WriteString("}")
			bArrayMemberAlreadyWritten = true
		}
	}
	buffer.WriteString("]")
	//----------------------------------------------
	return buffer.Bytes(), nil
}

func (t *SimpleChaincode) getTicketsByRange(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}

	startKey := args[0]
	endKey := args[1]

	resultsIterator, err := stub.RangeQueryState(startKey, endKey)
	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()

	// buffer is a JSON array containing QueryResults
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		_, queryResultValue, err := resultsIterator.Next()
		if err != nil {
			return nil, err
		}
		// Add a comma before array members, suppress it for the first array member
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}

		buffer.WriteString("{")
		//		buffer.WriteString("\"")
		//		buffer.WriteString(queryResultKey)
		//		buffer.WriteString("\"")

		//		buffer.WriteString(", \"Ticket\":")

		buffer.WriteString(string(queryResultValue))
		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")

	return buffer.Bytes(), nil
}

func (t *SimpleChaincode) getAllTickets(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	counterAsByteArr, err := stub.GetState("counter")
	s := string(counterAsByteArr[:])
	if err != nil {
		return nil, err
	}

	return t.getTicketsByRange(stub, []string{"1", s})
}

// Create a new ticket and store it on the ledger with ticket_id as key.
//
func (t *SimpleChaincode) createTicket(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 7 {
		return nil, errors.New("Wrong number of arguments, must be 7: Timestamp, Trainstation, Platform, Device, TechPart, ErrorID and ErrorMessage")
	}

	idAsBytes, _ := stub.GetState("counter") // get highest current ticket id number from worldstate, increment, and set as
	str := string(idAsBytes[:])              //	TicketID for newly created Ticket & update highest running ticket number.
	idAsInt, _ := strconv.Atoi(str)          // TODO This seems unnecessarily complicated.
	idAsInt++                                //
	idAsString := strconv.Itoa(idAsInt)
	err := stub.PutState("counter", []byte(idAsString))

	var ticket = Ticket{
		TicketID:     idAsString,
		Timestamp:    args[0],
		Trainstation: args[1],
		Platform:     args[2],
		Device:       args[3],
		Status:       "EINGETROFFEN",
		TechPart:     args[4],
		ErrorID:      args[5],
		ErrorMessage: args[6],
	}

	state, _ := json.Marshal(ticket)

	stub.PutState(idAsString, state)
	if err != nil {
		return nil, err
	}
	return nil, nil
}

// Creates a default ticket. Maybe change to just call createTicket with arguments.
//
func (t *SimpleChaincode) createDefaultTicket(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {

	idAsBytes, _ := stub.GetState("counter") // get highest current ticket id number from worldstate, increment and set as
	str := string(idAsBytes[:])              //	TicketID for newly created Ticket & update highest running ticket number.
	idAsInt, _ := strconv.Atoi(str)          //
	idAsInt++                                // TODO This seems unnecessarily complicated.
	idAsString := strconv.Itoa(idAsInt)
	err := stub.PutState("counter", []byte(idAsString))

	var ticket = Ticket{
		TicketID:     idAsString,
		Timestamp:    "2017-12-03T12:35:00.000Z",
		Trainstation: "Bonn Hbf",
		Platform:     "Gleis 5",
		Device:       "Rolltreppe nach oben",
		Status:       "Eingetroffen",
		TechPart:     "Motor RTM-X 64",
		ErrorID:      "#2356-102",
		ErrorMessage: "Totalausfall",
	}
	state, _ := json.Marshal(ticket)

	stub.PutState(idAsString, state)
	if err != nil {
		return nil, err
	}
	return nil, nil
}

// Assign an existing Ticket to a ServiceProvider. Arguments should be TicketID and the name of the serviceprovider that the ticket gets assigned to.
func (t *SimpleChaincode) assignTicket(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 2 {
		return nil, errors.New("Wrong number of arguments, must be 2: TicketID and ServiceProvider")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0]) //get ticket from world state as byte array
	if err != nil {
		return nil, err
	}
	ticket := new(Ticket)
	json.Unmarshal(state, ticket)    // translate back to struct (well, to "pointer to struct" actually)
	ticket.ServiceProvider = args[1] //set new  ServiceProvider
	ticket.Status = "ZUGEWIESEN"     //update status to "assigned"
	ticket.RepairStatus = "Wird geprueft"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}

func (t *SimpleChaincode) assignMechanic(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 2 {
		return nil, errors.New("Wrong number of arguments, must be 2: TicketID and SpEmployee ")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.SpEmployee = args[1]
	ticket.RepairStatus = "Ticket erhalten"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}

func (t *SimpleChaincode) startJourney(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Wrong number of arguments, must be 1: TicketID")
	}

	var state []byte
	var err error
	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.RepairStatus = "Techniker in Anfahrt"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}

func (t *SimpleChaincode) onArrival(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 3 {
		return nil, errors.New("Wrong number of arguments, must be 2: TicketID,EstRepairTime and SpeCommentary ")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.SpeCommentary = args[1]
	ticket.EstRepairTime = args[2]
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}
func (t *SimpleChaincode) startRepair(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Wrong number of arguments, must be 1: TicketID")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.RepairStatus = "Reparatur begonnen"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}

func (t *SimpleChaincode) finishRepair(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	if len(args) != 1 {
		return nil, errors.New("Wrong number of arguments, must be 1: TicketID")
	}

	var state []byte
	var err error

	state, err = stub.GetState(args[0])
	if err != nil {
		return nil, err
	}

	ticket := new(Ticket)
	json.Unmarshal(state, ticket)
	ticket.RepairStatus = "Reparatur abgeschlossen"
	ticket.Status = "ERLEDIGT"
	state, err = json.Marshal(ticket)
	if err != nil {
		return nil, err
	}
	stub.PutState(args[0], state) //write updated ticket to world state again

	return nil, nil
}
<|endoftext|>


<commit_before>package main

import (
	"../../api"
	"errors"
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

type Handler struct {
	path string
}

// Configure the provider.
func (h *Handler) Configure(config api.Config) error {
	if config != nil {
		if pathInt, ok := config["path"]; ok {
			if pathStr, ok := pathInt.(string); ok {
				h.path = pathStr
				return nil
			} else {
				return fmt.Errorf("invalid path: %v", pathInt)
			}
		}
	}
	return errors.New("path is required")
}

// Get the current disk stats.
func (h *Handler) Get() (metrics api.Metrics, err error) {
	var out []byte
	cmd := exec.Command("stat", "--format=%S %b %a", "-f", h.path)
	if out, err = cmd.Output(); err != nil {
		return
	}
	parts := strings.Split(strings.TrimSpace(string(out)), " ")
	if len(parts) < 3 {
		err = errors.New("invalid stat string")
		return
	}

	var blockSize, totalBlocks, freeBlocks int64
	if blockSize, err = strconv.ParseInt(parts[0], 10, 64); err != nil {
		return
	}
	if totalBlocks, err = strconv.ParseInt(parts[1], 10, 64); err != nil {
		return
	}
	if freeBlocks, err = strconv.ParseInt(parts[2], 10, 64); err != nil {
		return
	}

	gbTotal := float64(blockSize*totalBlocks) / 1073741824
	gbFree := float64(blockSize*freeBlocks) / 1073741824

	now := time.Now().UTC()
	metadata := map[string]string{"Path": h.path}
	metrics.Add("DiskSpaceTotal", gbTotal, api.UNIT_GIGABYTES, now, metadata)
	metrics.Add("DiskSpaceFree", gbFree, api.UNIT_GIGABYTES, now, metadata)

	pctUsed := 100 * float64(totalBlocks-freeBlocks) / float64(totalBlocks)
	metrics.Add("DiskBytesUtilization", pctUsed, api.UNIT_PERCENT, now, metadata)
	return
}

// Return an error.
func (h *Handler) Put(metrics api.Metrics) error {
	return errors.New("source only provider")
}

// Run the provider.
func main() {
	api.RunProvider(&Handler{})
}
<commit_msg>Fix disk utilization name.<commit_after>package main

import (
	"../../api"
	"errors"
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

type Handler struct {
	path string
}

// Configure the provider.
func (h *Handler) Configure(config api.Config) error {
	if config != nil {
		if pathInt, ok := config["path"]; ok {
			if pathStr, ok := pathInt.(string); ok {
				h.path = pathStr
				return nil
			} else {
				return fmt.Errorf("invalid path: %v", pathInt)
			}
		}
	}
	return errors.New("path is required")
}

// Get the current disk stats.
func (h *Handler) Get() (metrics api.Metrics, err error) {
	var out []byte
	cmd := exec.Command("stat", "--format=%S %b %a", "-f", h.path)
	if out, err = cmd.Output(); err != nil {
		return
	}
	parts := strings.Split(strings.TrimSpace(string(out)), " ")
	if len(parts) < 3 {
		err = errors.New("invalid stat string")
		return
	}

	var blockSize, totalBlocks, freeBlocks int64
	if blockSize, err = strconv.ParseInt(parts[0], 10, 64); err != nil {
		return
	}
	if totalBlocks, err = strconv.ParseInt(parts[1], 10, 64); err != nil {
		return
	}
	if freeBlocks, err = strconv.ParseInt(parts[2], 10, 64); err != nil {
		return
	}

	gbTotal := float64(blockSize*totalBlocks) / 1073741824
	gbFree := float64(blockSize*freeBlocks) / 1073741824

	now := time.Now().UTC()
	metadata := map[string]string{"Path": h.path}
	metrics.Add("DiskSpaceTotal", gbTotal, api.UNIT_GIGABYTES, now, metadata)
	metrics.Add("DiskSpaceFree", gbFree, api.UNIT_GIGABYTES, now, metadata)

	pctUsed := 100 * float64(totalBlocks-freeBlocks) / float64(totalBlocks)
	metrics.Add("DiskSpaceUtilization", pctUsed, api.UNIT_PERCENT, now, metadata)
	return
}

// Return an error.
func (h *Handler) Put(metrics api.Metrics) error {
	return errors.New("source only provider")
}

// Run the provider.
func main() {
	api.RunProvider(&Handler{})
}
<|endoftext|>


<commit_before>package providers

import (
	"context"
	"encoding/binary"
	"fmt"
	"strings"
	"time"

	lru "github.com/hashicorp/golang-lru"
	cid "github.com/ipfs/go-cid"
	ds "github.com/ipfs/go-datastore"
	autobatch "github.com/ipfs/go-datastore/autobatch"
	dsq "github.com/ipfs/go-datastore/query"
	logging "github.com/ipfs/go-log"
	goprocess "github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"
	peer "github.com/libp2p/go-libp2p-peer"
	base32 "github.com/whyrusleeping/base32"
)

var batchBufferSize = 256

var log = logging.Logger("providers")

var lruCacheSize = 256
var ProvideValidity = time.Hour * 24
var defaultCleanupInterval = time.Hour

type ProviderManager struct {
	// all non channel fields are meant to be accessed only within
	// the run method
	providers *lru.Cache
	dstore    ds.Datastore

	newprovs chan *addProv
	getprovs chan *getProv
	proc     goprocess.Process

	cleanupInterval time.Duration
}

type providerSet struct {
	providers []peer.ID
	set       map[peer.ID]time.Time
}

type addProv struct {
	k   cid.Cid
	val peer.ID
}

type getProv struct {
	k    cid.Cid
	resp chan []peer.ID
}

func NewProviderManager(ctx context.Context, local peer.ID, dstore ds.Batching) *ProviderManager {
	pm := new(ProviderManager)
	pm.getprovs = make(chan *getProv)
	pm.newprovs = make(chan *addProv)
	pm.dstore = autobatch.NewAutoBatching(dstore, batchBufferSize)
	cache, err := lru.New(lruCacheSize)
	if err != nil {
		panic(err) //only happens if negative value is passed to lru constructor
	}
	pm.providers = cache

	pm.proc = goprocessctx.WithContext(ctx)
	pm.cleanupInterval = defaultCleanupInterval
	pm.proc.Go(func(p goprocess.Process) { pm.run() })

	return pm
}

const providersKeyPrefix = "/providers/"

func mkProvKey(k cid.Cid) string {
	return providersKeyPrefix + base32.RawStdEncoding.EncodeToString(k.Bytes())
}

func (pm *ProviderManager) Process() goprocess.Process {
	return pm.proc
}

func (pm *ProviderManager) providersForKey(k cid.Cid) ([]peer.ID, error) {
	pset, err := pm.getProvSet(k)
	if err != nil {
		return nil, err
	}
	return pset.providers, nil
}

func (pm *ProviderManager) getProvSet(k cid.Cid) (*providerSet, error) {
	cached, ok := pm.providers.Get(k)
	if ok {
		return cached.(*providerSet), nil
	}

	pset, err := loadProvSet(pm.dstore, k)
	if err != nil {
		return nil, err
	}

	if len(pset.providers) > 0 {
		pm.providers.Add(k, pset)
	}

	return pset, nil
}

func loadProvSet(dstore ds.Datastore, k cid.Cid) (*providerSet, error) {
	res, err := dstore.Query(dsq.Query{Prefix: mkProvKey(k)})
	if err != nil {
		return nil, err
	}

	out := newProviderSet()
	for {
		e, ok := res.NextSync()
		if !ok {
			break
		}
		if e.Error != nil {
			log.Error("got an error: ", e.Error)
			continue
		}

		lix := strings.LastIndex(e.Key, "/")

		decstr, err := base32.RawStdEncoding.DecodeString(e.Key[lix+1:])
		if err != nil {
			log.Error("base32 decoding error: ", err)
			continue
		}

		pid := peer.ID(decstr)

		t, err := readTimeValue(e.Value)
		if err != nil {
			log.Warning("parsing providers record from disk: ", err)
			continue
		}

		out.setVal(pid, t)
	}

	return out, nil
}

func readTimeValue(i interface{}) (time.Time, error) {
	data, ok := i.([]byte)
	if !ok {
		return time.Time{}, fmt.Errorf("data was not a []byte")
	}

	nsec, _ := binary.Varint(data)

	return time.Unix(0, nsec), nil
}

func (pm *ProviderManager) addProv(k cid.Cid, p peer.ID) error {
	now := time.Now()
	if provs, ok := pm.providers.Get(k); ok {
		provs.(*providerSet).setVal(p, now)
	} // else not cached, just write through

	return writeProviderEntry(pm.dstore, k, p, now)
}

func writeProviderEntry(dstore ds.Datastore, k cid.Cid, p peer.ID, t time.Time) error {
	dsk := mkProvKey(k) + "/" + base32.RawStdEncoding.EncodeToString([]byte(p))

	buf := make([]byte, 16)
	n := binary.PutVarint(buf, t.UnixNano())

	return dstore.Put(ds.NewKey(dsk), buf[:n])
}

func (pm *ProviderManager) deleteProvSet(k cid.Cid) error {
	pm.providers.Remove(k)

	res, err := pm.dstore.Query(dsq.Query{
		KeysOnly: true,
		Prefix:   mkProvKey(k),
	})
	if err != nil {
		return err
	}

	entries, err := res.Rest()
	if err != nil {
		return err
	}

	for _, e := range entries {
		err := pm.dstore.Delete(ds.NewKey(e.Key))
		if err != nil {
			log.Error("deleting provider set: ", err)
		}
	}
	return nil
}

func (pm *ProviderManager) getProvKeys() (func() (cid.Cid, bool), error) {
	res, err := pm.dstore.Query(dsq.Query{
		KeysOnly: true,
		Prefix:   providersKeyPrefix,
	})
	if err != nil {
		return nil, err
	}

	iter := func() (cid.Cid, bool) {
		for e := range res.Next() {
			parts := strings.Split(e.Key, "/")
			if len(parts) != 4 {
				log.Warningf("incorrectly formatted provider entry in datastore: %s", e.Key)
				continue
			}
			decoded, err := base32.RawStdEncoding.DecodeString(parts[2])
			if err != nil {
				log.Warning("error decoding base32 provider key: %s: %s", parts[2], err)
				continue
			}

			c, err := cid.Cast(decoded)
			if err != nil {
				log.Warning("error casting key to cid from datastore key: %s", err)
				continue
			}

			return c, true
		}
		return cid.Cid{}, false
	}

	return iter, nil
}

func (pm *ProviderManager) run() {
	tick := time.NewTicker(pm.cleanupInterval)
	for {
		select {
		case np := <-pm.newprovs:
			err := pm.addProv(np.k, np.val)
			if err != nil {
				log.Error("error adding new providers: ", err)
			}
		case gp := <-pm.getprovs:
			provs, err := pm.providersForKey(gp.k)
			if err != nil && err != ds.ErrNotFound {
				log.Error("error reading providers: ", err)
			}

			gp.resp <- provs
		case <-tick.C:
			keys, err := pm.getProvKeys()
			if err != nil {
				log.Error("Error loading provider keys: ", err)
				continue
			}
			now := time.Now()
			for {
				k, ok := keys()
				if !ok {
					break
				}

				provs, err := pm.getProvSet(k)
				if err != nil {
					log.Error("error loading known provset: ", err)
					continue
				}
				for p, t := range provs.set {
					if now.Sub(t) > ProvideValidity {
						delete(provs.set, p)
					}
				}
				// have we run out of providers?
				if len(provs.set) == 0 {
					provs.providers = nil
					err := pm.deleteProvSet(k)
					if err != nil {
						log.Error("error deleting provider set: ", err)
					}
				} else if len(provs.set) < len(provs.providers) {
					// We must have modified the providers set, recompute.
					provs.providers = make([]peer.ID, 0, len(provs.set))
					for p := range provs.set {
						provs.providers = append(provs.providers, p)
					}
				}
			}
		case <-pm.proc.Closing():
			tick.Stop()
			return
		}
	}
}

func (pm *ProviderManager) AddProvider(ctx context.Context, k cid.Cid, val peer.ID) {
	prov := &addProv{
		k:   k,
		val: val,
	}
	select {
	case pm.newprovs <- prov:
	case <-ctx.Done():
	}
}

func (pm *ProviderManager) GetProviders(ctx context.Context, k cid.Cid) []peer.ID {
	gp := &getProv{
		k:    k,
		resp: make(chan []peer.ID, 1), // buffered to prevent sender from blocking
	}
	select {
	case <-ctx.Done():
		return nil
	case pm.getprovs <- gp:
	}
	select {
	case <-ctx.Done():
		return nil
	case peers := <-gp.resp:
		return peers
	}
}

func newProviderSet() *providerSet {
	return &providerSet{
		set: make(map[peer.ID]time.Time),
	}
}

func (ps *providerSet) Add(p peer.ID) {
	ps.setVal(p, time.Now())
}

func (ps *providerSet) setVal(p peer.ID, t time.Time) {
	_, found := ps.set[p]
	if !found {
		ps.providers = append(ps.providers, p)
	}

	ps.set[p] = t
}
<commit_msg>providers: improve time parsing error checking<commit_after>package providers

import (
	"context"
	"encoding/binary"
	"fmt"
	"strings"
	"time"

	lru "github.com/hashicorp/golang-lru"
	cid "github.com/ipfs/go-cid"
	ds "github.com/ipfs/go-datastore"
	autobatch "github.com/ipfs/go-datastore/autobatch"
	dsq "github.com/ipfs/go-datastore/query"
	logging "github.com/ipfs/go-log"
	goprocess "github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"
	peer "github.com/libp2p/go-libp2p-peer"
	base32 "github.com/whyrusleeping/base32"
)

var batchBufferSize = 256

var log = logging.Logger("providers")

var lruCacheSize = 256
var ProvideValidity = time.Hour * 24
var defaultCleanupInterval = time.Hour

type ProviderManager struct {
	// all non channel fields are meant to be accessed only within
	// the run method
	providers *lru.Cache
	dstore    ds.Datastore

	newprovs chan *addProv
	getprovs chan *getProv
	proc     goprocess.Process

	cleanupInterval time.Duration
}

type providerSet struct {
	providers []peer.ID
	set       map[peer.ID]time.Time
}

type addProv struct {
	k   cid.Cid
	val peer.ID
}

type getProv struct {
	k    cid.Cid
	resp chan []peer.ID
}

func NewProviderManager(ctx context.Context, local peer.ID, dstore ds.Batching) *ProviderManager {
	pm := new(ProviderManager)
	pm.getprovs = make(chan *getProv)
	pm.newprovs = make(chan *addProv)
	pm.dstore = autobatch.NewAutoBatching(dstore, batchBufferSize)
	cache, err := lru.New(lruCacheSize)
	if err != nil {
		panic(err) //only happens if negative value is passed to lru constructor
	}
	pm.providers = cache

	pm.proc = goprocessctx.WithContext(ctx)
	pm.cleanupInterval = defaultCleanupInterval
	pm.proc.Go(func(p goprocess.Process) { pm.run() })

	return pm
}

const providersKeyPrefix = "/providers/"

func mkProvKey(k cid.Cid) string {
	return providersKeyPrefix + base32.RawStdEncoding.EncodeToString(k.Bytes())
}

func (pm *ProviderManager) Process() goprocess.Process {
	return pm.proc
}

func (pm *ProviderManager) providersForKey(k cid.Cid) ([]peer.ID, error) {
	pset, err := pm.getProvSet(k)
	if err != nil {
		return nil, err
	}
	return pset.providers, nil
}

func (pm *ProviderManager) getProvSet(k cid.Cid) (*providerSet, error) {
	cached, ok := pm.providers.Get(k)
	if ok {
		return cached.(*providerSet), nil
	}

	pset, err := loadProvSet(pm.dstore, k)
	if err != nil {
		return nil, err
	}

	if len(pset.providers) > 0 {
		pm.providers.Add(k, pset)
	}

	return pset, nil
}

func loadProvSet(dstore ds.Datastore, k cid.Cid) (*providerSet, error) {
	res, err := dstore.Query(dsq.Query{Prefix: mkProvKey(k)})
	if err != nil {
		return nil, err
	}

	out := newProviderSet()
	for {
		e, ok := res.NextSync()
		if !ok {
			break
		}
		if e.Error != nil {
			log.Error("got an error: ", e.Error)
			continue
		}

		lix := strings.LastIndex(e.Key, "/")

		decstr, err := base32.RawStdEncoding.DecodeString(e.Key[lix+1:])
		if err != nil {
			log.Error("base32 decoding error: ", err)
			continue
		}

		pid := peer.ID(decstr)

		t, err := readTimeValue(e.Value)
		if err != nil {
			log.Warning("parsing providers record from disk: ", err)
			continue
		}

		out.setVal(pid, t)
	}

	return out, nil
}

func readTimeValue(data []byte) (time.Time, error) {
	nsec, n := binary.Varint(data)
	if n <= 0 {
		return time.Time{}, fmt.Errorf("failed to parse time")
	}

	return time.Unix(0, nsec), nil
}

func (pm *ProviderManager) addProv(k cid.Cid, p peer.ID) error {
	now := time.Now()
	if provs, ok := pm.providers.Get(k); ok {
		provs.(*providerSet).setVal(p, now)
	} // else not cached, just write through

	return writeProviderEntry(pm.dstore, k, p, now)
}

func writeProviderEntry(dstore ds.Datastore, k cid.Cid, p peer.ID, t time.Time) error {
	dsk := mkProvKey(k) + "/" + base32.RawStdEncoding.EncodeToString([]byte(p))

	buf := make([]byte, 16)
	n := binary.PutVarint(buf, t.UnixNano())

	return dstore.Put(ds.NewKey(dsk), buf[:n])
}

func (pm *ProviderManager) deleteProvSet(k cid.Cid) error {
	pm.providers.Remove(k)

	res, err := pm.dstore.Query(dsq.Query{
		KeysOnly: true,
		Prefix:   mkProvKey(k),
	})
	if err != nil {
		return err
	}

	entries, err := res.Rest()
	if err != nil {
		return err
	}

	for _, e := range entries {
		err := pm.dstore.Delete(ds.NewKey(e.Key))
		if err != nil {
			log.Error("deleting provider set: ", err)
		}
	}
	return nil
}

func (pm *ProviderManager) getProvKeys() (func() (cid.Cid, bool), error) {
	res, err := pm.dstore.Query(dsq.Query{
		KeysOnly: true,
		Prefix:   providersKeyPrefix,
	})
	if err != nil {
		return nil, err
	}

	iter := func() (cid.Cid, bool) {
		for e := range res.Next() {
			parts := strings.Split(e.Key, "/")
			if len(parts) != 4 {
				log.Warningf("incorrectly formatted provider entry in datastore: %s", e.Key)
				continue
			}
			decoded, err := base32.RawStdEncoding.DecodeString(parts[2])
			if err != nil {
				log.Warning("error decoding base32 provider key: %s: %s", parts[2], err)
				continue
			}

			c, err := cid.Cast(decoded)
			if err != nil {
				log.Warning("error casting key to cid from datastore key: %s", err)
				continue
			}

			return c, true
		}
		return cid.Cid{}, false
	}

	return iter, nil
}

func (pm *ProviderManager) run() {
	tick := time.NewTicker(pm.cleanupInterval)
	for {
		select {
		case np := <-pm.newprovs:
			err := pm.addProv(np.k, np.val)
			if err != nil {
				log.Error("error adding new providers: ", err)
			}
		case gp := <-pm.getprovs:
			provs, err := pm.providersForKey(gp.k)
			if err != nil && err != ds.ErrNotFound {
				log.Error("error reading providers: ", err)
			}

			gp.resp <- provs
		case <-tick.C:
			keys, err := pm.getProvKeys()
			if err != nil {
				log.Error("Error loading provider keys: ", err)
				continue
			}
			now := time.Now()
			for {
				k, ok := keys()
				if !ok {
					break
				}

				provs, err := pm.getProvSet(k)
				if err != nil {
					log.Error("error loading known provset: ", err)
					continue
				}
				for p, t := range provs.set {
					if now.Sub(t) > ProvideValidity {
						delete(provs.set, p)
					}
				}
				// have we run out of providers?
				if len(provs.set) == 0 {
					provs.providers = nil
					err := pm.deleteProvSet(k)
					if err != nil {
						log.Error("error deleting provider set: ", err)
					}
				} else if len(provs.set) < len(provs.providers) {
					// We must have modified the providers set, recompute.
					provs.providers = make([]peer.ID, 0, len(provs.set))
					for p := range provs.set {
						provs.providers = append(provs.providers, p)
					}
				}
			}
		case <-pm.proc.Closing():
			tick.Stop()
			return
		}
	}
}

func (pm *ProviderManager) AddProvider(ctx context.Context, k cid.Cid, val peer.ID) {
	prov := &addProv{
		k:   k,
		val: val,
	}
	select {
	case pm.newprovs <- prov:
	case <-ctx.Done():
	}
}

func (pm *ProviderManager) GetProviders(ctx context.Context, k cid.Cid) []peer.ID {
	gp := &getProv{
		k:    k,
		resp: make(chan []peer.ID, 1), // buffered to prevent sender from blocking
	}
	select {
	case <-ctx.Done():
		return nil
	case pm.getprovs <- gp:
	}
	select {
	case <-ctx.Done():
		return nil
	case peers := <-gp.resp:
		return peers
	}
}

func newProviderSet() *providerSet {
	return &providerSet{
		set: make(map[peer.ID]time.Time),
	}
}

func (ps *providerSet) Add(p peer.ID) {
	ps.setVal(p, time.Now())
}

func (ps *providerSet) setVal(p peer.ID, t time.Time) {
	_, found := ps.set[p]
	if !found {
		ps.providers = append(ps.providers, p)
	}

	ps.set[p] = t
}
<|endoftext|>


<commit_before>package trousseau

import (
	"encoding/json"
	"errors"
	"fmt"
	crypto "github.com/oleiade/trousseau/crypto"
	openpgp "github.com/oleiade/trousseau/crypto/openpgp"
	"os"
	"reflect"
)

type Store struct {
	*DataStore
	path           string
	encryptionOpts *crypto.Options
}

type DataStore struct {
	KVStore
	Meta      Meta                   `json:"_meta"`
	Container map[string]interface{} `json:"data"`
}

type KVStore interface {
	Get(string) (interface{}, error)
	Set(string, interface{}) error
	Del(string) error
	Keys() ([]string, error)
	Items() ([]KVPair, error)
}

type KVPair struct {
	Key   string
	Value interface{}
}

type Encodable interface {
	FromJson([]byte) error
	ToJson() ([]byte, error)
}

// LoadStore reads and decrypt a trousseau data store from the
// provided path, using the provided encryption options.
func LoadStore(path string, opts *crypto.Options) (*Store, error) {
	var store *Store = NewStore(path, opts)
	var err error = nil

	switch opts.Algorithm {
	case crypto.GPG_ENCRYPTION:
		var f *openpgp.GpgFile
		var jsonData []byte

		f, err = openpgp.OpenFile(path, os.O_RDONLY, opts.Passphrase, opts.Recipients)
		if err != nil {
			return nil, fmt.Errorf("trousseau data store not found (%s)", err.(*os.PathError).Path)
		}
		defer f.Close()

		jsonData, err = f.ReadAll()
		if err != nil {
			return nil, err
		}

		err = store.FromJson(jsonData)
		if err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("Invalid encryption method provided")
	}

	return store, nil
}

// Sync encrypts the store content and writes it to the disk
func (s *Store) Sync() error {
	switch s.encryptionOpts.Algorithm {
	case crypto.GPG_ENCRYPTION:
		var f *openpgp.GpgFile
		var err error

		f, err = openpgp.OpenFile(s.path,
			os.O_CREATE|os.O_WRONLY,
			s.encryptionOpts.Passphrase,
			s.Meta.Recipients)
		if err != nil {
			return err
		}
		defer f.Close()

		jsonData, err := s.ToJson()
		if err != nil {
			return err
		}

		_, err = f.Write([]byte(jsonData))
		if err != nil {
			return err
		}
	default:
		return fmt.Errorf("Invalid encryption method provided")
	}

	return nil
}

func NewStore(path string, encryptionOpts *crypto.Options) *Store {
	return &Store{
		DataStore:      NewDataStore(),
		path:           path,
		encryptionOpts: encryptionOpts,
	}
}

func NewKVPair(key string, value interface{}) *KVPair {
	return &KVPair{
		Key:   key,
		Value: value,
	}
}

func NewDataStore() *DataStore {
	return &DataStore{
		Container: make(map[string]interface{}),
	}
}

func (ds *DataStore) ToJson() (string, error) {
	encodedStore, err := json.Marshal(ds)
	if err != nil {
		return "", err
	}

	return string(encodedStore), nil
}

func (ds *DataStore) FromJson(jsonData []byte) error {
	err := json.Unmarshal(jsonData, &ds)
	if err != nil {
		return err
	}

	return nil
}

// CreateStoreFile creates a trousseau file at $HOME/.trousseau
func CreateStoreFile(path string, opts *crypto.Options, meta *Meta) (err error) {
	// if the store file already exists, return an error
	if _, err = os.Stat(path); err == nil {
		return errors.New("Store file already exists")
	}

	store := NewStore(path, opts)
	store.Meta = *meta

	err = store.Sync()
	if err != nil {
		return err
	}

	return nil
}

// GetStoreKey fetches a key from the trousseau file store
func (ds *DataStore) Get(key string) (interface{}, error) {
	value, ok := ds.Container[key]
	if !ok {
		return "", errors.New(fmt.Sprintf("Key %s does not exist", key))
	}

	return value, nil
}

// SetStoreKey sets a key value pair in the store
func (ds *DataStore) Set(key string, value interface{}) error {
	ds.Container[key] = value

	return nil
}

// DelStoreKey deletes a key value pair from the trousseau file
func (ds *DataStore) Del(key string) error {
	delete(ds.Container, key)

	return nil
}

// ListStoreKeys lists the keys contained in the trousseau store file
func (ds *DataStore) Keys() ([]string, error) {
	index := 0
	keys := make([]string, len(ds.Container))

	for key, _ := range ds.Container {
		keys[index] = key
		index++
	}

	return keys, nil
}

func (ds *DataStore) Items() ([]KVPair, error) {
	index := 0
	pairs := make([]KVPair, len(ds.Container))

	for key, value := range ds.Container {
		pairs[index] = *NewKVPair(key, value)
		index++
	}

	return pairs, nil
}

func (s *Store) Metadata() ([]KVPair, error) {
	metaType := reflect.TypeOf(s.DataStore.Meta)
	metaValue := reflect.ValueOf(s.DataStore.Meta)
	pairs := make([]KVPair, metaType.NumField())

	for i := 0; i < metaType.NumField(); i++ {
		key := metaType.Field(i).Name
		value := metaValue.FieldByName(key).Interface()
		pairs[i] = *NewKVPair(key, value)
	}

	return pairs, nil
}
<commit_msg>Sort output of "troussau keys" in alphabetical order<commit_after>package trousseau

import (
	"encoding/json"
	"errors"
	"fmt"
	crypto "github.com/oleiade/trousseau/crypto"
	openpgp "github.com/oleiade/trousseau/crypto/openpgp"
	"os"
	"reflect"
	"sort"
)

type Store struct {
	*DataStore
	path           string
	encryptionOpts *crypto.Options
}

type DataStore struct {
	KVStore
	Meta      Meta                   `json:"_meta"`
	Container map[string]interface{} `json:"data"`
}

type KVStore interface {
	Get(string) (interface{}, error)
	Set(string, interface{}) error
	Del(string) error
	Keys() ([]string, error)
	Items() ([]KVPair, error)
}

type KVPair struct {
	Key   string
	Value interface{}
}

type Encodable interface {
	FromJson([]byte) error
	ToJson() ([]byte, error)
}

// LoadStore reads and decrypt a trousseau data store from the
// provided path, using the provided encryption options.
func LoadStore(path string, opts *crypto.Options) (*Store, error) {
	var store *Store = NewStore(path, opts)
	var err error = nil

	switch opts.Algorithm {
	case crypto.GPG_ENCRYPTION:
		var f *openpgp.GpgFile
		var jsonData []byte

		f, err = openpgp.OpenFile(path, os.O_RDONLY, opts.Passphrase, opts.Recipients)
		if err != nil {
			return nil, fmt.Errorf("trousseau data store not found (%s)", err.(*os.PathError).Path)
		}
		defer f.Close()

		jsonData, err = f.ReadAll()
		if err != nil {
			return nil, err
		}

		err = store.FromJson(jsonData)
		if err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("Invalid encryption method provided")
	}

	return store, nil
}

// Sync encrypts the store content and writes it to the disk
func (s *Store) Sync() error {
	switch s.encryptionOpts.Algorithm {
	case crypto.GPG_ENCRYPTION:
		var f *openpgp.GpgFile
		var err error

		f, err = openpgp.OpenFile(s.path,
			os.O_CREATE|os.O_WRONLY,
			s.encryptionOpts.Passphrase,
			s.Meta.Recipients)
		if err != nil {
			return err
		}
		defer f.Close()

		jsonData, err := s.ToJson()
		if err != nil {
			return err
		}

		_, err = f.Write([]byte(jsonData))
		if err != nil {
			return err
		}
	default:
		return fmt.Errorf("Invalid encryption method provided")
	}

	return nil
}

func NewStore(path string, encryptionOpts *crypto.Options) *Store {
	return &Store{
		DataStore:      NewDataStore(),
		path:           path,
		encryptionOpts: encryptionOpts,
	}
}

func NewKVPair(key string, value interface{}) *KVPair {
	return &KVPair{
		Key:   key,
		Value: value,
	}
}

func NewDataStore() *DataStore {
	return &DataStore{
		Container: make(map[string]interface{}),
	}
}

func (ds *DataStore) ToJson() (string, error) {
	encodedStore, err := json.Marshal(ds)
	if err != nil {
		return "", err
	}

	return string(encodedStore), nil
}

func (ds *DataStore) FromJson(jsonData []byte) error {
	err := json.Unmarshal(jsonData, &ds)
	if err != nil {
		return err
	}

	return nil
}

// CreateStoreFile creates a trousseau file at $HOME/.trousseau
func CreateStoreFile(path string, opts *crypto.Options, meta *Meta) (err error) {
	// if the store file already exists, return an error
	if _, err = os.Stat(path); err == nil {
		return errors.New("Store file already exists")
	}

	store := NewStore(path, opts)
	store.Meta = *meta

	err = store.Sync()
	if err != nil {
		return err
	}

	return nil
}

// GetStoreKey fetches a key from the trousseau file store
func (ds *DataStore) Get(key string) (interface{}, error) {
	value, ok := ds.Container[key]
	if !ok {
		return "", errors.New(fmt.Sprintf("Key %s does not exist", key))
	}

	return value, nil
}

// SetStoreKey sets a key value pair in the store
func (ds *DataStore) Set(key string, value interface{}) error {
	ds.Container[key] = value

	return nil
}

// DelStoreKey deletes a key value pair from the trousseau file
func (ds *DataStore) Del(key string) error {
	delete(ds.Container, key)

	return nil
}

// ListStoreKeys lists the keys contained in the trousseau store file
func (ds *DataStore) Keys() ([]string, error) {
	index := 0
	keys := make([]string, len(ds.Container))

	for key, _ := range ds.Container {
		keys[index] = key
		index++
	}

	// Sort in alphabetical order
	sort.Strings(keys)
	return keys, nil
}

func (ds *DataStore) Items() ([]KVPair, error) {
	index := 0
	pairs := make([]KVPair, len(ds.Container))

	for key, value := range ds.Container {
		pairs[index] = *NewKVPair(key, value)
		index++
	}

	return pairs, nil
}

func (s *Store) Metadata() ([]KVPair, error) {
	metaType := reflect.TypeOf(s.DataStore.Meta)
	metaValue := reflect.ValueOf(s.DataStore.Meta)
	pairs := make([]KVPair, metaType.NumField())

	for i := 0; i < metaType.NumField(); i++ {
		key := metaType.Field(i).Name
		value := metaValue.FieldByName(key).Interface()
		pairs[i] = *NewKVPair(key, value)
	}

	return pairs, nil
}
<|endoftext|>


<commit_before>// Copyright 2017 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/gt/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package conf

import (
	"log"
	"sync"

	// "time"

	"github.com/fsnotify/fsnotify"
)

var (
	// config     Config
	confLock = new(sync.RWMutex)
)

// NewWatcher new fsnotify watcher
func NewWatcher(paths string, config interface{}) {
	Watch(paths, config)
}

// Watch new fsnotify watcher
func Watch(paths string, config interface{}) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal("fsnotify.NewWatcher() error: ", err)
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				log.Println("fsnotify watcher events: ", event)

				// if event.Op&fsnotify.Chmod == fsnotify.Chmod {
				// 	log.Println("fsnotify watcher.Events: ignore CHMOD event: ", event)
				// 	continue
				// }

				if event.Op&fsnotify.Write == fsnotify.Write {
					// log.Println("modified file: ", event.Name)
					err := Init(paths, config)
					if err == nil {
						log.Println("fsnotify watch config: ", config)
					}
				}
			case err := <-watcher.Errors:
				log.Println("fsnotify watcher.Errors error: ", err)
			}
		}
	}()

	err = watcher.Add(paths)
	if err != nil {
		log.Fatal("fsnotify watcher.Add: ", err)
	}
	<-done
}
<commit_msg>add go watch function support<commit_after>// Copyright 2017 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/gt/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package conf

import (
	"log"
	"sync"

	// "time"

	"github.com/fsnotify/fsnotify"
)

var (
	// config     Config
	confLock = new(sync.RWMutex)
)

// GoWatch go watch the paths
func GoWatch(paths string, cf interface{}) {
	Init(paths, cf)
	go Watch(paths, cf)
}

// NewWatcher new fsnotify watcher
func NewWatcher(paths string, config interface{}) {
	Watch(paths, config)
}

// Watch new fsnotify watcher
func Watch(paths string, config interface{}) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal("fsnotify.NewWatcher() error: ", err)
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				log.Println("fsnotify watcher events: ", event)

				// if event.Op&fsnotify.Chmod == fsnotify.Chmod {
				// 	log.Println("fsnotify watcher.Events: ignore CHMOD event: ", event)
				// 	continue
				// }

				if event.Op&fsnotify.Write == fsnotify.Write {
					// log.Println("modified file: ", event.Name)
					err := Init(paths, config)
					if err == nil {
						log.Println("fsnotify watch config: ", config)
					}
				}
			case err := <-watcher.Errors:
				log.Println("fsnotify watcher.Errors error: ", err)
			}
		}
	}()

	err = watcher.Add(paths)
	if err != nil {
		log.Fatal("fsnotify watcher.Add: ", err)
	}
	<-done
}
<|endoftext|>