<commit_before>package frame

import (
	"image"
	"image/draw"
)

// Insert inserts the contents of s at index p0 in
// the frame and returns the number of characters
// written.
func (f *Frame) Insert(s []byte, p0 int64) (wrote int) {
	type Pts [2]image.Point
	if p0 > f.Nchars || len(s) == 0 || f.b == nil {
		return
	}

	// find p0, it's box, and its point in the box its in
	b0 := f.Find(0, 0, p0)
	eb := f.StartCell(b0)
	//ob0 := b0
	cb0 := p0
	b1 := b0
	pt0 := f.pointOfBox(p0, b0)

	// find p1
	ppt0, pt1 := f.boxscan(s, pt0)
	opt0 := pt0
	ppt1 := pt1
	// Line wrap
	if b0 < f.Nbox {
		b := &f.Box[b0]
		pt0 = f.wrapMax(pt0, b)
		ppt1 = f.wrapMin(ppt1, b)
	}
	f.modified = true

	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), false)
	}

	cb0, b0, pt0, pt1 = f.boxalign(cb0, b0, pt0, pt1)
	f.boxpush(p0, b0, b1, pt0, pt1, ppt1)
	f.bitblt(cb0, b0, pt0, pt1, opt0)
	text, back := f.pick(p0, f.p0+1, f.p1+1)
	f.Paint(ppt0, ppt1, back)
	f.redrawRun0(f.ir, ppt0, text, back)
	f.Run.Combine(f.ir, b1)
	if b1 > 0 && f.Box[b1-1].Nrune >= 0 && ppt0.X-f.Box[b1-1].Width >= f.r.Min.X {
		b1--
		ppt0.X -= f.Box[b1].Width
	}
	b0 += f.ir.Nbox
	if b0 < f.Nbox-1 {
		b0++
	}
	f.clean(ppt0, b1, b0)
	f.Nchars += f.ir.Nchars
	if ForceElasticTabstopExperiment {
		for b := f.Nbox; b > eb; b = f.Stretch(b) {
		}
		f.Stretch(eb)
		f.Refresh()
	}
	f.p0, f.p1 = coInsert(p0, p0+f.Nchars, f.p0, f.p1)
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(f.p0), true)
	}
	return int(f.ir.Nchars)
}

// Mark marks the frame as dirty
func (f *Frame) Mark() {
	f.modified = true
}

// boxalign collects a list of pts of each box
// on the frame before and after an insertion occurs
func (f *Frame) boxalign(cb0 int64, b0 int, pt0, pt1 image.Point) (int64, int, image.Point, image.Point) {
	type Pts [2]image.Point
	f.pts = f.pts[:0]

	// collect the start pts for each box on the plane
	// before and after the insertion
	for {
		if pt0.X == pt1.X || pt1.Y == f.r.Max.Y || b0 == f.Nbox {
			break
		}
		b := &f.Box[b0]
		pt0 = f.wrapMax(pt0, b)
		pt1 = f.wrapMin(pt1, b)
		if b.Nrune > 0 {
			if n := f.fits(pt1, b); n != b.Nrune {
				f.Split(b0, n)
				b = &f.Box[b0]
			}
		}

		// early exit - point went off the frame
		if pt1.Y == f.r.Max.Y {
			break
		}

		f.pts = append(f.pts, Pts{pt0, pt1})

		pt0 = f.advance(pt0, b)
		pt1.X += f.plot(pt1, b)

		cb0 += int64(b.Len())
		b0++
	}
	return cb0, b0, pt0, pt1
}

// boxpush moves boxes down the frame to make room for an insertion
// from pt0 to pt1
func (f *Frame) boxpush(p0 int64, b0, b1 int, pt0, pt1, ppt1 image.Point) {

	// delete boxes that ran off the frame
	// and update the char count
	if pt1.Y == f.r.Max.Y && b0 < f.Nbox {
		f.Nchars -= f.Count(b0)
		f.Run.Delete(b0, f.Nbox-1)
	}

	// update the line count
	if b0 == f.Nbox {
		f.Nlines = (pt1.Y - f.r.Min.Y) / f.Font.Dy()
		if pt1.X > f.r.Min.X {
			f.Nlines++
		}
		return
	}

	if pt1.Y == pt0.Y {
		// insertion won't propagate down
		return
	}

	qt0 := pt0.Y + f.Font.Dy()
	qt1 := pt1.Y + f.Font.Dy()
	f.Nlines += (qt1 - qt0) / f.Font.Dy()
	if f.Nlines > f.maxlines {
		f.trim(ppt1, p0, b1)
	}

	// shift down the existing boxes
	// on the bitmap
	if r := f.r; pt1.Y < r.Max.Y {
		r.Min.Y = qt1

		// rectangular group of boxes
		if qt1 < f.r.Max.Y {
			f.Draw(f.b, r, f.b, image.Pt(f.r.Min.X, qt0), f.op)
		}

		// partial line
		r.Min = pt1
		r.Max.X = pt1.X + (f.r.Max.X - pt0.X)
		r.Max.Y = qt1
		f.Draw(f.b, r, f.b, pt0, f.op)
	}
}

func (f *Frame) bitblt(cb0 int64, b0 int, pt0, pt1, opt0 image.Point) {
	h := f.Font.Dy()
	y := 0
	if pt1.Y == f.r.Max.Y {
		y = pt1.Y
	}
	x := len(f.pts)
	run := f.Box[b0-x:]
	x--
	_, back := f.pick(cb0, f.p0, f.p1)
	for ; x >= 0; x-- {
		b := &run[x]
		br := image.Rect(0, 0, b.Width, h)
		pt := f.pts[x]
		if b.Nrune > 0 {
			f.Draw(f.b, br.Add(pt[1]), f.b, pt[0], f.op)
			// clear bit hanging off right
			if x == 0 && pt[1].Y > pt0.Y {

				// new char was wider than the old
				// one so the line wrapped anyway

				_, back = f.pick(cb0, f.p0, f.p1)
				r := br.Add(opt0)
				r.Max.X = f.r.Max.X
				f.Draw(f.b, r, back, r.Min, f.op)

			} else if pt[1].Y < y {

				// copy from left to right, bottom to top

				_, back = f.pick(cb0, f.p0, f.p1)
				r := image.ZR.Add(pt[1])
				r.Min.X += b.Width
				r.Max.X += f.r.Max.X
				r.Max.Y += h
				f.Draw(f.b, r, back, r.Min, f.op)

			}
			y = pt[1].Y
			cb0 -= int64(b.Nrune)
		} else {
			r := br.Add(pt[1])
			if r.Max.X >= f.r.Max.X {
				r.Max.X = f.r.Max.X
			}
			cb0--
			_, back = f.pick(cb0, f.p0, f.p1)
			f.Draw(f.b, r, back, r.Min, f.op)
			y = 0
			if pt[1].X == f.r.Min.X {
				y = pt[1].Y
			}
		}
	}
}

func (f *Frame) pick(c, p0, p1 int64) (text, back image.Image) {
	if p0 <= c && c < p1 {
		return f.Color.Hi.Text, f.Color.Hi.Back
	}
	return f.Color.Text, f.Color.Back
}

func region(c, p0, p1 int64) int {
	if c < p0 {
		return -1
	}
	if c >= p1 {
		return 1
	}
	return 0
}

//
// Below ideas

type offset struct {
	p0   int64
	b0   int
	cb0  int64
	b1   int64
	pt0  image.Point
	pt1  image.Point
	opt0 image.Point
}

func (f *Frame) zInsertElastic(s []byte, p0 int64) (wrote int) {
	type Pts [2]image.Point
	if p0 > f.Nchars || len(s) == 0 || f.b == nil {
		return
	}

	// find p0, it's box, and its point in the box its in
	b0 := f.Find(0, 0, p0)
	cb0 := p0

	eb0 := f.StartCell(b0)
	pt0 := f.pointOfBox(p0, b0)
	ppt0, pt1 := f.boxscan(s, pt0)
	//	ept0 := f.pointOfBox(p0, eb0)
	f.Box = append(f.Box[:b0], append(f.ir.Box[:f.ir.Nbox], f.Box[b0:]...)...)
	f.Nbox += f.ir.Nbox

	b1 := b0

	for bn := f.NextCell(b1 + f.ir.Nbox); bn > eb0; bn = f.Stretch(bn) {
	}
	f.Stretch(eb0)

	//		pt0 = f.pointOfBox(p0, b0)
	//		pt1 = f.pointOfBox(65535, b1)

	opt0 := pt0
	ppt1 := pt1
	// Line wrap
	if b0 < f.Nbox {
		b := &f.Box[b0]
		pt0 = f.wrapMax(pt0, b)
		ppt1 = f.wrapMin(ppt1, b)
	}
	f.modified = true

	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), false)
	}

	cb0, b0, pt0, pt1 = f.boxalign(cb0, b0+f.ir.Nbox, pt0, pt1)
	f.boxpush(p0, b0+f.ir.Nbox, b1+f.ir.Nbox, pt0, pt1, ppt1)
	f.bitblt(cb0, b0, pt0, pt1, opt0)
	text, back := f.pick(p0, f.p0+1, f.p1+1)
	f.Paint(ppt0, ppt1, back)
	f.redrawRun0(f.ir, ppt0, text, back)

	b1 = b0
	if b1 > 0 && f.Box[b1-1].Nrune >= 0 && ppt0.X-f.Box[b1-1].Width >= f.r.Min.X {
		b1--
		ppt0.X -= f.Box[b1].Width
	}

	b0 += f.ir.Nbox
	if b0 < f.Nbox-1 {
		b0++
	}
	f.clean(f.pointOfBox(p0, b1), b0, b1)
	f.Nchars += f.ir.Nchars

	f.p0, f.p1 = coInsert(p0, p0+f.Nchars, f.p0, f.p1)
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(f.p0), true)
	}
	return int(f.ir.Nchars)

}

func drawBorder(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point, thick int) {
	draw.Draw(dst, image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+thick), src, sp, draw.Src)
	draw.Draw(dst, image.Rect(r.Min.X, r.Max.Y-thick, r.Max.X, r.Max.Y), src, sp, draw.Src)
	draw.Draw(dst, image.Rect(r.Min.X, r.Min.Y, r.Min.X+thick, r.Max.Y), src, sp, draw.Src)
	draw.Draw(dst, image.Rect(r.Max.X-thick, r.Min.Y, r.Max.X, r.Max.Y), src, sp, draw.Src)
}
<commit_msg>remove smart algorithm<commit_after>package frame

import (
	"image"
	"image/draw"
)

// Insert inserts the contents of s at index p0 in
// the frame and returns the number of characters
// written.
func (f *Frame) Insert(s []byte, p0 int64) (wrote int) {
	type Pts [2]image.Point
	if p0 > f.Nchars || len(s) == 0 || f.b == nil {
		return
	}

	// find p0, it's box, and its point in the box its in
	b0 := f.Find(0, 0, p0)
//	eb := f.StartCell(b0)
	//ob0 := b0
	cb0 := p0
	b1 := b0
	pt0 := f.pointOfBox(p0, b0)

	// find p1
	ppt0, pt1 := f.boxscan(s, pt0)
	opt0 := pt0
	ppt1 := pt1
	// Line wrap
	if b0 < f.Nbox {
		b := &f.Box[b0]
		pt0 = f.wrapMax(pt0, b)
		ppt1 = f.wrapMin(ppt1, b)
	}
	f.modified = true

	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), false)
	}

	cb0, b0, pt0, pt1 = f.boxalign(cb0, b0, pt0, pt1)
	f.boxpush(p0, b0, b1, pt0, pt1, ppt1)
	f.bitblt(cb0, b0, pt0, pt1, opt0)
	text, back := f.pick(p0, f.p0+1, f.p1+1)
	f.Paint(ppt0, ppt1, back)
	f.redrawRun0(f.ir, ppt0, text, back)
	f.Run.Combine(f.ir, b1)
	if b1 > 0 && f.Box[b1-1].Nrune >= 0 && ppt0.X-f.Box[b1-1].Width >= f.r.Min.X {
		b1--
		ppt0.X -= f.Box[b1].Width
	}
	b0 += f.ir.Nbox
	if b0 < f.Nbox-1 {
		b0++
	}
	f.clean(ppt0, b1, b0)
	f.Nchars += f.ir.Nchars
	f.p0, f.p1 = coInsert(p0, p0+f.Nchars, f.p0, f.p1)
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(f.p0), true)
	}
	f.badElasticAlg()
	return int(f.ir.Nchars)
}

func (f *Frame) badElasticAlg(){
	if ForceElasticTabstopExperiment {
		if f.Nbox <=1{
			return
		}
		b := 0
		b1:=0
		for b != f.Nbox{
		println(11)
			b1=b
			//f.Stretch(b)
			println("nextcell")
			b = f.NextCell(b)
			println("xxxxxxxxxxnextcell")
			if b == 0 || b == b1 {
				break
			}
		}
		f.Stretch(f.Nbox)
		b=b1
		for ; b1 > 1; b1 = f.Stretch(b1) {
		println(22)
			if b==b1{
				break
			}
			b=b1
		}
		f.Stretch(b1)
		f.Refresh()
	}
}

// Mark marks the frame as dirty
func (f *Frame) Mark() {
	f.modified = true
}

// boxalign collects a list of pts of each box
// on the frame before and after an insertion occurs
func (f *Frame) boxalign(cb0 int64, b0 int, pt0, pt1 image.Point) (int64, int, image.Point, image.Point) {
	type Pts [2]image.Point
	f.pts = f.pts[:0]

	// collect the start pts for each box on the plane
	// before and after the insertion
	for {
		if pt0.X == pt1.X || pt1.Y == f.r.Max.Y || b0 == f.Nbox {
			break
		}
		b := &f.Box[b0]
		pt0 = f.wrapMax(pt0, b)
		pt1 = f.wrapMin(pt1, b)
		if b.Nrune > 0 {
			if n := f.fits(pt1, b); n != b.Nrune {
				f.Split(b0, n)
				b = &f.Box[b0]
			}
		}

		// early exit - point went off the frame
		if pt1.Y == f.r.Max.Y {
			break
		}

		f.pts = append(f.pts, Pts{pt0, pt1})

		pt0 = f.advance(pt0, b)
		pt1.X += f.plot(pt1, b)

		cb0 += int64(b.Len())
		b0++
	}
	return cb0, b0, pt0, pt1
}

// boxpush moves boxes down the frame to make room for an insertion
// from pt0 to pt1
func (f *Frame) boxpush(p0 int64, b0, b1 int, pt0, pt1, ppt1 image.Point) {

	// delete boxes that ran off the frame
	// and update the char count
	if pt1.Y == f.r.Max.Y && b0 < f.Nbox {
		f.Nchars -= f.Count(b0)
		f.Run.Delete(b0, f.Nbox-1)
	}

	// update the line count
	if b0 == f.Nbox {
		f.Nlines = (pt1.Y - f.r.Min.Y) / f.Font.Dy()
		if pt1.X > f.r.Min.X {
			f.Nlines++
		}
		return
	}

	if pt1.Y == pt0.Y {
		// insertion won't propagate down
		return
	}

	qt0 := pt0.Y + f.Font.Dy()
	qt1 := pt1.Y + f.Font.Dy()
	f.Nlines += (qt1 - qt0) / f.Font.Dy()
	if f.Nlines > f.maxlines {
		f.trim(ppt1, p0, b1)
	}

	// shift down the existing boxes
	// on the bitmap
	if r := f.r; pt1.Y < r.Max.Y {
		r.Min.Y = qt1

		// rectangular group of boxes
		if qt1 < f.r.Max.Y {
			f.Draw(f.b, r, f.b, image.Pt(f.r.Min.X, qt0), f.op)
		}

		// partial line
		r.Min = pt1
		r.Max.X = pt1.X + (f.r.Max.X - pt0.X)
		r.Max.Y = qt1
		f.Draw(f.b, r, f.b, pt0, f.op)
	}
}

func (f *Frame) bitblt(cb0 int64, b0 int, pt0, pt1, opt0 image.Point) {
	h := f.Font.Dy()
	y := 0
	if pt1.Y == f.r.Max.Y {
		y = pt1.Y
	}
	x := len(f.pts)
	run := f.Box[b0-x:]
	x--
	_, back := f.pick(cb0, f.p0, f.p1)
	for ; x >= 0; x-- {
		b := &run[x]
		br := image.Rect(0, 0, b.Width, h)
		pt := f.pts[x]
		if b.Nrune > 0 {
			f.Draw(f.b, br.Add(pt[1]), f.b, pt[0], f.op)
			// clear bit hanging off right
			if x == 0 && pt[1].Y > pt0.Y {

				// new char was wider than the old
				// one so the line wrapped anyway

				_, back = f.pick(cb0, f.p0, f.p1)
				r := br.Add(opt0)
				r.Max.X = f.r.Max.X
				f.Draw(f.b, r, back, r.Min, f.op)

			} else if pt[1].Y < y {

				// copy from left to right, bottom to top

				_, back = f.pick(cb0, f.p0, f.p1)
				r := image.ZR.Add(pt[1])
				r.Min.X += b.Width
				r.Max.X += f.r.Max.X
				r.Max.Y += h
				f.Draw(f.b, r, back, r.Min, f.op)

			}
			y = pt[1].Y
			cb0 -= int64(b.Nrune)
		} else {
			r := br.Add(pt[1])
			if r.Max.X >= f.r.Max.X {
				r.Max.X = f.r.Max.X
			}
			cb0--
			_, back = f.pick(cb0, f.p0, f.p1)
			f.Draw(f.b, r, back, r.Min, f.op)
			y = 0
			if pt[1].X == f.r.Min.X {
				y = pt[1].Y
			}
		}
	}
}

func (f *Frame) pick(c, p0, p1 int64) (text, back image.Image) {
	if p0 <= c && c < p1 {
		return f.Color.Hi.Text, f.Color.Hi.Back
	}
	return f.Color.Text, f.Color.Back
}

func region(c, p0, p1 int64) int {
	if c < p0 {
		return -1
	}
	if c >= p1 {
		return 1
	}
	return 0
}

//
// Below ideas

type offset struct {
	p0   int64
	b0   int
	cb0  int64
	b1   int64
	pt0  image.Point
	pt1  image.Point
	opt0 image.Point
}

func (f *Frame) zInsertElastic(s []byte, p0 int64) (wrote int) {
	type Pts [2]image.Point
	if p0 > f.Nchars || len(s) == 0 || f.b == nil {
		return
	}

	// find p0, it's box, and its point in the box its in
	b0 := f.Find(0, 0, p0)
	cb0 := p0

	eb0 := f.StartCell(b0)
	pt0 := f.pointOfBox(p0, b0)
	ppt0, pt1 := f.boxscan(s, pt0)
	//	ept0 := f.pointOfBox(p0, eb0)
	f.Box = append(f.Box[:b0], append(f.ir.Box[:f.ir.Nbox], f.Box[b0:]...)...)
	f.Nbox += f.ir.Nbox

	b1 := b0

	for bn := f.NextCell(b1 + f.ir.Nbox); bn > eb0; bn = f.Stretch(bn) {
	}
	f.Stretch(eb0)

	//		pt0 = f.pointOfBox(p0, b0)
	//		pt1 = f.pointOfBox(65535, b1)

	opt0 := pt0
	ppt1 := pt1
	// Line wrap
	if b0 < f.Nbox {
		b := &f.Box[b0]
		pt0 = f.wrapMax(pt0, b)
		ppt1 = f.wrapMin(ppt1, b)
	}
	f.modified = true

	if f.p0 == f.p1 {
		f.tickat(f.PointOf(int64(f.p0)), false)
	}

	cb0, b0, pt0, pt1 = f.boxalign(cb0, b0+f.ir.Nbox, pt0, pt1)
	f.boxpush(p0, b0+f.ir.Nbox, b1+f.ir.Nbox, pt0, pt1, ppt1)
	f.bitblt(cb0, b0, pt0, pt1, opt0)
	text, back := f.pick(p0, f.p0+1, f.p1+1)
	f.Paint(ppt0, ppt1, back)
	f.redrawRun0(f.ir, ppt0, text, back)

	b1 = b0
	if b1 > 0 && f.Box[b1-1].Nrune >= 0 && ppt0.X-f.Box[b1-1].Width >= f.r.Min.X {
		b1--
		ppt0.X -= f.Box[b1].Width
	}

	b0 += f.ir.Nbox
	if b0 < f.Nbox-1 {
		b0++
	}
	f.clean(f.pointOfBox(p0, b1), b0, b1)
	f.Nchars += f.ir.Nchars

	f.p0, f.p1 = coInsert(p0, p0+f.Nchars, f.p0, f.p1)
	if f.p0 == f.p1 {
		f.tickat(f.PointOf(f.p0), true)
	}
	return int(f.ir.Nchars)

}

func drawBorder(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point, thick int) {
	draw.Draw(dst, image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+thick), src, sp, draw.Src)
	draw.Draw(dst, image.Rect(r.Min.X, r.Max.Y-thick, r.Max.X, r.Max.Y), src, sp, draw.Src)
	draw.Draw(dst, image.Rect(r.Min.X, r.Min.Y, r.Min.X+thick, r.Max.Y), src, sp, draw.Src)
	draw.Draw(dst, image.Rect(r.Max.X-thick, r.Min.Y, r.Max.X, r.Max.Y), src, sp, draw.Src)
}
<|endoftext|>


<commit_before>package helper

import (
	"net/http"
	"reflect"
	"testing"

	"github.com/ansel1/merry"
)

func TestMergeHttpErrors(t *testing.T) {
	type args struct {
	}
	tests := []struct {
		name     string
		errors   []merry.Error
		wantCode int
		want     []string
	}{
		{
			name:     "NotFound",
			errors:   []merry.Error{},
			wantCode: http.StatusNotFound,
			want:     []string{},
		},
		{
			name: "ServiceUnavailable",
			errors: []merry.Error{
				merry.New("unavaliable").WithHTTPCode(http.StatusServiceUnavailable),
			},
			wantCode: http.StatusServiceUnavailable,
			want:     []string{"unavaliable"},
		},
		{
			name: "GatewayTimeout and ServiceUnavailable",
			errors: []merry.Error{
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
				merry.New("unavaliable").WithHTTPCode(http.StatusServiceUnavailable),
			},
			wantCode: http.StatusServiceUnavailable,
			want:     []string{"timeout", "unavaliable"},
		},
		{
			name: "ServiceUnavailable and GatewayTimeout",
			errors: []merry.Error{
				merry.New("unavaliable").WithHTTPCode(http.StatusServiceUnavailable),
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
			},
			wantCode: http.StatusServiceUnavailable,
			want:     []string{"unavaliable", "timeout"},
		},
		{
			name: "Forbidden and GatewayTimeout",
			errors: []merry.Error{
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
			},
			wantCode: http.StatusForbidden,
			want:     []string{"limit", "timeout"},
		},
		{
			name: "GatewayTimeout and Forbidden",
			errors: []merry.Error{
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
			},
			wantCode: http.StatusForbidden,
			want:     []string{"timeout", "limit"},
		},
		{
			name: "InternalServerError and Forbidden",
			errors: []merry.Error{
				merry.New("error").WithHTTPCode(http.StatusInternalServerError),
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
			},
			wantCode: http.StatusForbidden,
			want:     []string{"error", "limit"},
		},
		{
			name: "InternalServerError and GatewayTimeout",
			errors: []merry.Error{
				merry.New("error").WithHTTPCode(http.StatusInternalServerError),
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
			},
			wantCode: http.StatusInternalServerError,
			want:     []string{"error", "timeout"},
		},
		{
			name: "GatewayTimeout and InternalServerError",
			errors: []merry.Error{
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
				merry.New("error").WithHTTPCode(http.StatusInternalServerError),
			},
			wantCode: http.StatusInternalServerError,
			want:     []string{"timeout", "error"},
		},
		{
			name: "BadRequest and Forbidden",
			errors: []merry.Error{
				merry.New("error").WithHTTPCode(http.StatusBadRequest),
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
			},
			wantCode: http.StatusForbidden, // Last win
			want:     []string{"error", "limit"},
		},
		{
			name: "Forbidden and BadRequest",
			errors: []merry.Error{
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
				merry.New("error").WithHTTPCode(http.StatusBadRequest),
			},
			wantCode: http.StatusBadRequest, // Last win
			want:     []string{"limit", "error"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotCode, got := MergeHttpErrors(tt.errors)
			if gotCode != tt.wantCode {
				t.Errorf("MergeHttpErrors() gotCode = %v, want %v", gotCode, tt.wantCode)
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("MergeHttpErrors() got = %v, want %v", got, tt.want)
			}
		})
	}
}
<commit_msg>tests: fix zipper requests net error (encapsulated)<commit_after>package helper

import (
	"fmt"
	"net"
	"net/http"
	"reflect"
	"testing"

	"github.com/ansel1/merry"
	"github.com/go-graphite/carbonapi/zipper/types"
)

func TestMergeHttpErrors(t *testing.T) {
	type args struct {
	}
	tests := []struct {
		name     string
		errors   []merry.Error
		wantCode int
		want     []string
	}{
		{
			name:     "NotFound",
			errors:   []merry.Error{},
			wantCode: http.StatusNotFound,
			want:     []string{},
		},
		{
			name: "NetErr",
			errors: []merry.Error{
				types.ErrBackendError.WithValue("server", "test").WithCause(&net.OpError{Op: "connect", Err: fmt.Errorf("refused")}).WithHTTPCode(http.StatusServiceUnavailable),
			},
			wantCode: http.StatusServiceUnavailable,
			want:     []string{"connect: refused"},
		},
		{
			name: "NetErr (incapsulated)",
			errors: []merry.Error{
				types.ErrMaxTriesExceeded.WithCause(types.ErrBackendError.WithValue("server", "test").WithCause(&net.OpError{Op: "connect", Err: fmt.Errorf("refused")})).WithHTTPCode(http.StatusServiceUnavailable),
			},
			wantCode: http.StatusServiceUnavailable,
			want:     []string{"connect: refused"},
		},
		{
			name: "ServiceUnavailable",
			errors: []merry.Error{
				merry.New("unavaliable").WithHTTPCode(http.StatusServiceUnavailable),
			},
			wantCode: http.StatusServiceUnavailable,
			want:     []string{"unavaliable"},
		},
		{
			name: "GatewayTimeout and ServiceUnavailable",
			errors: []merry.Error{
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
				merry.New("unavaliable").WithHTTPCode(http.StatusServiceUnavailable),
			},
			wantCode: http.StatusServiceUnavailable,
			want:     []string{"timeout", "unavaliable"},
		},
		{
			name: "ServiceUnavailable and GatewayTimeout",
			errors: []merry.Error{
				merry.New("unavaliable").WithHTTPCode(http.StatusServiceUnavailable),
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
			},
			wantCode: http.StatusServiceUnavailable,
			want:     []string{"unavaliable", "timeout"},
		},
		{
			name: "Forbidden and GatewayTimeout",
			errors: []merry.Error{
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
			},
			wantCode: http.StatusForbidden,
			want:     []string{"limit", "timeout"},
		},
		{
			name: "GatewayTimeout and Forbidden",
			errors: []merry.Error{
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
			},
			wantCode: http.StatusForbidden,
			want:     []string{"timeout", "limit"},
		},
		{
			name: "InternalServerError and Forbidden",
			errors: []merry.Error{
				merry.New("error").WithHTTPCode(http.StatusInternalServerError),
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
			},
			wantCode: http.StatusForbidden,
			want:     []string{"error", "limit"},
		},
		{
			name: "InternalServerError and GatewayTimeout",
			errors: []merry.Error{
				merry.New("error").WithHTTPCode(http.StatusInternalServerError),
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
			},
			wantCode: http.StatusInternalServerError,
			want:     []string{"error", "timeout"},
		},
		{
			name: "GatewayTimeout and InternalServerError",
			errors: []merry.Error{
				merry.New("timeout").WithHTTPCode(http.StatusGatewayTimeout),
				merry.New("error").WithHTTPCode(http.StatusInternalServerError),
			},
			wantCode: http.StatusInternalServerError,
			want:     []string{"timeout", "error"},
		},
		{
			name: "BadRequest and Forbidden",
			errors: []merry.Error{
				merry.New("error").WithHTTPCode(http.StatusBadRequest),
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
			},
			wantCode: http.StatusForbidden, // Last win
			want:     []string{"error", "limit"},
		},
		{
			name: "Forbidden and BadRequest",
			errors: []merry.Error{
				merry.New("limit").WithHTTPCode(http.StatusForbidden),
				merry.New("error").WithHTTPCode(http.StatusBadRequest),
			},
			wantCode: http.StatusBadRequest, // Last win
			want:     []string{"limit", "error"},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			gotCode, got := MergeHttpErrors(tt.errors)
			if gotCode != tt.wantCode {
				t.Errorf("MergeHttpErrors() gotCode = %v, want %v", gotCode, tt.wantCode)
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("MergeHttpErrors() got = %v, want %v", got, tt.want)
			}
		})
	}
}
<|endoftext|>


<commit_before>package host

import (
	"errors"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// announce creates an announcement transaction and submits it to the network.
func (h *Host) announce(addr modules.NetAddress) error {
	// Generate an unlock hash, if necessary.
	if h.settings.UnlockHash == (types.UnlockHash{}) {
		uc, err := h.wallet.NextAddress()
		if err != nil {
			return err
		}
		h.settings.UnlockHash = uc.UnlockHash()
		err = h.save()
		if err != nil {
			return err
		}
	}

	// Create a transaction with a host announcement.
	txnBuilder := h.wallet.StartTransaction()
	announcement := encoding.Marshal(modules.HostAnnouncement{
		IPAddress: addr,
	})
	_ = txnBuilder.AddArbitraryData(append(modules.PrefixHostAnnouncement[:], announcement...))
	txn, parents := txnBuilder.View()
	txnSet := append(parents, txn)

	// Add the transaction to the transaction pool.
	err := h.tpool.AcceptTransactionSet(txnSet)
	if err == modules.ErrDuplicateTransactionSet {
		return errors.New("you have already announced yourself")
	}
	if err != nil {
		return err
	}
	h.log.Printf("INFO: Successfully announced as %v", addr)

	return nil
}

// Announce creates a host announcement transaction, adding information to the
// arbitrary data, signing the transaction, and submitting it to the
// transaction pool.
func (h *Host) Announce() error {
	// As an exported function that needs resources, Annouce holds the resource
	// lock throughout its operation.
	h.resourceLock.RLock()
	defer h.resourceLock.RUnlock()

	// Get the external IP again; it may have changed.
	h.learnHostname()
	h.mu.RLock()
	addr := h.netAddress
	h.mu.RUnlock()

	// Check that the host's ip address is known.
	if addr.IsLoopback() && build.Release != "testing" {
		return errors.New("can't announce without knowing external IP")
	}

	return h.announce(addr)
}

// AnnounceAddress submits a host announcement to the blockchain to announce a
// specific address. No checks for validity are performed on the address.
func (h *Host) AnnounceAddress(addr modules.NetAddress) error {
	// As an exported function that needs resources, AnnouceAddress holds the
	// resource lock throughout its operation.
	h.resourceLock.RLock()
	defer h.resourceLock.RUnlock()
	return h.announce(addr)
}
<commit_msg>proper rejection of Announce calls if the host is closed<commit_after>package host

import (
	"errors"

	"github.com/NebulousLabs/Sia/build"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// announce creates an announcement transaction and submits it to the network.
func (h *Host) announce(addr modules.NetAddress) error {
	// Generate an unlock hash, if necessary.
	if h.settings.UnlockHash == (types.UnlockHash{}) {
		uc, err := h.wallet.NextAddress()
		if err != nil {
			return err
		}
		h.settings.UnlockHash = uc.UnlockHash()
		err = h.save()
		if err != nil {
			return err
		}
	}

	// Create a transaction with a host announcement.
	txnBuilder := h.wallet.StartTransaction()
	announcement := encoding.Marshal(modules.HostAnnouncement{
		IPAddress: addr,
	})
	_ = txnBuilder.AddArbitraryData(append(modules.PrefixHostAnnouncement[:], announcement...))
	txn, parents := txnBuilder.View()
	txnSet := append(parents, txn)

	// Add the transaction to the transaction pool.
	err := h.tpool.AcceptTransactionSet(txnSet)
	if err == modules.ErrDuplicateTransactionSet {
		return errors.New("you have already announced yourself")
	}
	if err != nil {
		return err
	}
	h.log.Printf("INFO: Successfully announced as %v", addr)

	return nil
}

// Announce creates a host announcement transaction, adding information to the
// arbitrary data, signing the transaction, and submitting it to the
// transaction pool.
func (h *Host) Announce() error {
	// As an exported function that needs resources, Annouce holds the resource
	// lock throughout its operation.
	h.resourceLock.RLock()
	defer h.resourceLock.RUnlock()
	if h.closed {
		return errHostClosed
	}

	// Get the external IP again; it may have changed.
	h.learnHostname()
	h.mu.RLock()
	addr := h.netAddress
	h.mu.RUnlock()

	// Check that the host's ip address is known.
	if addr.IsLoopback() && build.Release != "testing" {
		return errors.New("can't announce without knowing external IP")
	}

	return h.announce(addr)
}

// AnnounceAddress submits a host announcement to the blockchain to announce a
// specific address. No checks for validity are performed on the address.
func (h *Host) AnnounceAddress(addr modules.NetAddress) error {
	// As an exported function that needs resources, AnnouceAddress holds the
	// resource lock throughout its operation.
	h.resourceLock.RLock()
	defer h.resourceLock.RUnlock()
	if h.closed {
		return errHostClosed
	}
	return h.announce(addr)
}
<|endoftext|>


<commit_before>package multi

import (
	"fmt"
	"github.com/bcurren/go-hue"
	"time"
)

type rGetLights struct {
	lights []hue.Light
	err    error
}

type rGetNewLights struct {
	lights   []hue.Light
	lastScan time.Time
	err      error
}

type rSearchForNewLights struct {
	err error
}

// GetLights() is same as hue.User.GetLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetLights() ([]hue.Light, error) {
	c := make(chan rGetLights)
	for _, api := range m.apis {
		go gGetLights(c, api)
	}
	return lGetLights(c, len(m.apis))
}

func gGetLights(c chan rGetLights, api hue.API) {
	lights, err := api.GetLights()
	c <- rGetLights{mapLightIds(api, lights), err}
}

func lGetLights(c chan rGetLights, nResponses int) ([]hue.Light, error) {
	lErrors := make([]error, 0, 1)
	lLights := make([][]hue.Light, 0, nResponses)

	for i := 0; i < nResponses; i++ {
		result := <-c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		} else {
			lLights = append(lLights, result.lights)
		}
	}

	return mergeLights(lLights), mergeErrors(lErrors)
}

// GetNewLights() is same as hue.User.GetNewLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetNewLights() ([]hue.Light, time.Time, error) {
	c := make(chan rGetNewLights)
	for _, api := range m.apis {
		go gGetNewLights(c, api)
	}
	return lGetNewLights(c, len(m.apis))
}

func gGetNewLights(c chan rGetNewLights, api hue.API) {
	lights, lastScan, err := api.GetNewLights()
	c <- rGetNewLights{mapLightIds(api, lights), lastScan, err}
}

func lGetNewLights(c chan rGetNewLights, nResponses int) ([]hue.Light, time.Time, error) {
	lErrors := make([]error, 0, 1)
	lLights := make([][]hue.Light, 0, nResponses)
	lLastScan := make([]time.Time, 0, nResponses)

	for i := 0; i < nResponses; i++ {
		result := <-c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		}
		if result.lights != nil {
			lLights = append(lLights, result.lights)
		}
		lLastScan = append(lLastScan, result.lastScan)
	}

	return mergeLights(lLights), mergeTime(lLastScan), mergeErrors(lErrors)
}

// SearchForNewLights() is same as hue.User.SearchForNewLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SearchForNewLights() error {
	c := make(chan rSearchForNewLights)
	for _, api := range m.apis {
		go gSearchForNewLights(c, api)
	}
	return lSearchForNewLights(c, len(m.apis))
}

func gSearchForNewLights(c chan rSearchForNewLights, api hue.API) {
	err := api.SearchForNewLights()
	c <- rSearchForNewLights{err}
}

func lSearchForNewLights(c chan rSearchForNewLights, nResponses int) error {
	lErrors := make([]error, 0, 1)

	for i := 0; i < nResponses; i++ {
		result := <-c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		}
	}

	return mergeErrors(lErrors)
}

// GetLightAttributes() is same as hue.User.GetLightAttributes() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetLightAttributes(lightId string) (*hue.LightAttributes, error) {
	api, newLightId, err := m.findAPIAndLightId(lightId)
	if err != nil {
		return nil, err
	}
	return api.GetLightAttributes(newLightId)
}

// SetLightName() is same as hue.User.SetLightName() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SetLightName(lightId string, name string) error {
	api, newLightId, err := m.findAPIAndLightId(lightId)
	if err != nil {
		return err
	}
	return api.SetLightName(newLightId, name)
}

// SetLightState() is same as hue.User.SetLightState() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SetLightState(lightId string, state *hue.LightState) error {
	api, newLightId, err := m.findAPIAndLightId(lightId)
	if err != nil {
		return err
	}
	return api.SetLightState(newLightId, state)
}

func mergeLights(lLights [][]hue.Light) []hue.Light {
	countOfLights := 0
	for _, lights := range lLights {
		countOfLights += len(lights)
	}

	mLights := make([]hue.Light, countOfLights)
	copyTo := 0
	for _, lights := range lLights {
		copy(mLights[copyTo:], lights)
		copyTo += len(lights)
	}

	return mLights
}

func mergeErrors(lErrors []error) error {
	if lErrors == nil || len(lErrors) <= 0 {
		return nil
	}

	apiErrorDetails := make([]hue.APIErrorDetail, 0, len(lErrors))

	// Collect all error details and exit if non API error found
	// TODO: Collect all non API Errors for an array of errors return type
	for _, err := range lErrors {
		if apiError, ok := err.(*hue.APIError); ok {
			for _, apiErrorDetail := range apiError.Errors {
				apiErrorDetails = append(apiErrorDetails, apiErrorDetail)
			}
		} else {
			return err
		}
	}
	return &hue.APIError{apiErrorDetails}
}

func mergeTime(lTime []time.Time) time.Time {
	return lTime[0]
}

func mapLightIds(api hue.API, lLights []hue.Light) []hue.Light {
	return lLights
}

func (m *MultiAPI) findAPIAndLightId(lightId string) (hue.API, string, error) {
	return m.apis[0], lightId, nil
}

func createResourceNotAvailableAPIError(resourceId, address string) error {
	apiError := &hue.APIError{}
	apiError.Errors = make([]hue.APIErrorDetail, 1, 1)
	apiError.Errors[0].Type = hue.ResourceNotAvailableErrorType
	apiError.Errors[0].Address = address
	apiError.Errors[0].Description = fmt.Sprintf("resource, %s, not available", resourceId)

	return apiError
}
<commit_msg>map lights<commit_after>package multi

import (
	"fmt"
	"github.com/bcurren/go-hue"
	"strconv"
	"strings"
	"time"
)

type rGetLights struct {
	lights []hue.Light
	err    error
}

type rGetNewLights struct {
	lights   []hue.Light
	lastScan time.Time
	err      error
}

type rSearchForNewLights struct {
	err error
}

// GetLights() is same as hue.User.GetLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetLights() ([]hue.Light, error) {
	c := make(chan rGetLights)
	for _, api := range m.apis {
		go m.gGetLights(c, api)
	}
	return m.lGetLights(c, len(m.apis))
}

func (m *MultiAPI) gGetLights(c chan rGetLights, api hue.API) {
	lights, err := api.GetLights()
	c <- rGetLights{m.mapLightIds(api, lights), err}
}

func (m *MultiAPI) lGetLights(c chan rGetLights, nResponses int) ([]hue.Light, error) {
	lErrors := make([]error, 0, 1)
	lLights := make([][]hue.Light, 0, nResponses)

	for i := 0; i < nResponses; i++ {
		result := <-c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		} else {
			lLights = append(lLights, result.lights)
		}
	}

	return mergeLights(lLights), mergeErrors(lErrors)
}

// GetNewLights() is same as hue.User.GetNewLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetNewLights() ([]hue.Light, time.Time, error) {
	c := make(chan rGetNewLights)
	for _, api := range m.apis {
		go m.gGetNewLights(c, api)
	}
	return m.lGetNewLights(c, len(m.apis))
}

func (m *MultiAPI) gGetNewLights(c chan rGetNewLights, api hue.API) {
	lights, lastScan, err := api.GetNewLights()
	c <- rGetNewLights{m.mapLightIds(api, lights), lastScan, err}
}

func (m *MultiAPI) lGetNewLights(c chan rGetNewLights, nResponses int) ([]hue.Light, time.Time, error) {
	lErrors := make([]error, 0, 1)
	lLights := make([][]hue.Light, 0, nResponses)
	lLastScan := make([]time.Time, 0, nResponses)

	for i := 0; i < nResponses; i++ {
		result := <-c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		}
		if result.lights != nil {
			lLights = append(lLights, result.lights)
		}
		lLastScan = append(lLastScan, result.lastScan)
	}

	return mergeLights(lLights), mergeTime(lLastScan), mergeErrors(lErrors)
}

// SearchForNewLights() is same as hue.User.SearchForNewLights() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SearchForNewLights() error {
	c := make(chan rSearchForNewLights)
	for _, api := range m.apis {
		go m.gSearchForNewLights(c, api)
	}
	return m.lSearchForNewLights(c, len(m.apis))
}

func (m *MultiAPI) gSearchForNewLights(c chan rSearchForNewLights, api hue.API) {
	err := api.SearchForNewLights()
	c <- rSearchForNewLights{err}
}

func (m *MultiAPI) lSearchForNewLights(c chan rSearchForNewLights, nResponses int) error {
	lErrors := make([]error, 0, 1)

	for i := 0; i < nResponses; i++ {
		result := <-c
		if result.err != nil {
			lErrors = append(lErrors, result.err)
		}
	}

	return mergeErrors(lErrors)
}

// GetLightAttributes() is same as hue.User.GetLightAttributes() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) GetLightAttributes(lightId string) (*hue.LightAttributes, error) {
	api, newLightId, err := m.findAPIAndLightId(lightId, fmt.Sprintf("/lights/%s", lightId))
	if err != nil {
		return nil, err
	}
	return api.GetLightAttributes(newLightId)
}

// SetLightName() is same as hue.User.SetLightName() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SetLightName(lightId string, name string) error {
	api, newLightId, err := m.findAPIAndLightId(lightId, fmt.Sprintf("/lights/%s", lightId))
	if err != nil {
		return err
	}
	return api.SetLightName(newLightId, name)
}

// SetLightState() is same as hue.User.SetLightState() except all light ids are mapped to
// socket ids.
func (m *MultiAPI) SetLightState(lightId string, state *hue.LightState) error {
	api, newLightId, err := m.findAPIAndLightId(lightId, fmt.Sprintf("/lights/%s/state", lightId))
	if err != nil {
		return err
	}
	return api.SetLightState(newLightId, state)
}

func mergeLights(lLights [][]hue.Light) []hue.Light {
	countOfLights := 0
	for _, lights := range lLights {
		countOfLights += len(lights)
	}

	mLights := make([]hue.Light, countOfLights)
	copyTo := 0
	for _, lights := range lLights {
		copy(mLights[copyTo:], lights)
		copyTo += len(lights)
	}

	return mLights
}

func mergeErrors(lErrors []error) error {
	if lErrors == nil || len(lErrors) <= 0 {
		return nil
	}

	apiErrorDetails := make([]hue.APIErrorDetail, 0, len(lErrors))

	// Collect all error details and exit if non API error found
	// TODO: Collect all non API Errors for an array of errors return type
	for _, err := range lErrors {
		if apiError, ok := err.(*hue.APIError); ok {
			for _, apiErrorDetail := range apiError.Errors {
				apiErrorDetails = append(apiErrorDetails, apiErrorDetail)
			}
		} else {
			return err
		}
	}
	return &hue.APIError{apiErrorDetails}
}

func mergeTime(lTime []time.Time) time.Time {
	return lTime[0]
}

func (m *MultiAPI) mapLightIds(api hue.API, lights []hue.Light) []hue.Light {
	for i, light := range lights {
		lights[i].Id = m.mapAPIAndLightId(api, light.Id)
	}
	return lights
}

func (m *MultiAPI) apiToId(api hue.API) string {
	for i, checkApi := range m.apis {
		if api == checkApi {
			return strconv.Itoa(i)
		}
	}
	return ""
}

func (m *MultiAPI) idToApi(id string) hue.API {
	idAsInt, err := strconv.Atoi(id)
	if err != nil {
		return nil
	}
	if idAsInt < 0 || idAsInt >= len(m.apis) {
		return nil
	}

	return m.apis[idAsInt]
}

func (m *MultiAPI) mapAPIAndLightId(api hue.API, lightId string) string {
	return fmt.Sprintf("%s#%s", m.apiToId(api), lightId)
}

func (m *MultiAPI) findAPIAndLightId(lightId, address string) (hue.API, string, error) {
	splitLightId := strings.Split(lightId, "#")
	api := m.idToApi(splitLightId[0])
	if api == nil {
		return nil, "", createResourceNotAvailableAPIError(lightId, address)
	}

	return api, splitLightId[1], nil
}

func createResourceNotAvailableAPIError(resourceId, address string) error {
	apiError := &hue.APIError{}
	apiError.Errors = make([]hue.APIErrorDetail, 1, 1)
	apiError.Errors[0].Type = hue.ResourceNotAvailableErrorType
	apiError.Errors[0].Address = address
	apiError.Errors[0].Description = fmt.Sprintf("resource, %s, not available", resourceId)

	return apiError
}
<|endoftext|>


<commit_before>package mux

import (
	"bytes"
	"gnd.la/cache"
	"gnd.la/orm"
	"html/template"
	"strconv"
)

const (
	debugCacheKey = "cache"
	debugOrmKey   = "orm"
)

// DebugComment returns an HTML comment with some debug information,
// including the time when the template was rendered, the time it
// took to serve the request and the number of queries to the cache
// and the ORM. It is intended to be used in the templates like e.g.
//
//    </html>
//    {{ $Context.DebugComment }}
//
// Keep in mind that the comment will only include the number of ORM and
// cache queries when debug is enabled in the mux, because otherwise the
// cache and ORM are shared among all contexts and counting the queries
// per request is not possible.
func (c *Context) DebugComment() template.HTML {
	var buf bytes.Buffer
	buf.WriteString("<!-- generated on ")
	buf.WriteString(c.started.String())
	buf.WriteString(" - took ")
	buf.WriteString(c.Elapsed().String())
	if c.debugStorage != nil {
		o, _ := c.debugStorage[debugOrmKey].(*orm.Orm)
		if o != nil {
			buf.WriteString(" - ")
			buf.WriteString(strconv.Itoa(o.NumQueries()))
			buf.WriteString(" ORM queries")
		}
		ca, _ := c.debugStorage[debugCacheKey].(*cache.Cache)
		if ca != nil {
			buf.WriteString(" - ")
			buf.WriteString(strconv.Itoa(ca.NumQueries()))
			buf.WriteString(" cache queries")
		}
	}
	buf.WriteString(" -->")
	return template.HTML(buf.String())
}

func (c *Context) storeDebug(name string, val interface{}) {
	if c.debugStorage == nil {
		c.debugStorage = make(map[string]interface{})
	}
	c.debugStorage[name] = val
}

func (c *Context) getDebug(name string) interface{} {
	return c.debugStorage[name]
}
<commit_msg>Fix example in comment<commit_after>package mux

import (
	"bytes"
	"gnd.la/cache"
	"gnd.la/orm"
	"html/template"
	"strconv"
)

const (
	debugCacheKey = "cache"
	debugOrmKey   = "orm"
)

// DebugComment returns an HTML comment with some debug information,
// including the time when the template was rendered, the time it
// took to serve the request and the number of queries to the cache
// and the ORM. It is intended to be used in the templates like e.g.
//
//    </html>
//    {{ $Ctx.DebugComment }}
//
// Keep in mind that the comment will only include the number of ORM and
// cache queries when debug is enabled in the Mux, because otherwise the
// cache and ORM are shared among all contexts and counting the queries
// per request is not possible.
func (c *Context) DebugComment() template.HTML {
	var buf bytes.Buffer
	buf.WriteString("<!-- generated on ")
	buf.WriteString(c.started.String())
	buf.WriteString(" - took ")
	buf.WriteString(c.Elapsed().String())
	if c.debugStorage != nil {
		o, _ := c.debugStorage[debugOrmKey].(*orm.Orm)
		if o != nil {
			buf.WriteString(" - ")
			buf.WriteString(strconv.Itoa(o.NumQueries()))
			buf.WriteString(" ORM queries")
		}
		ca, _ := c.debugStorage[debugCacheKey].(*cache.Cache)
		if ca != nil {
			buf.WriteString(" - ")
			buf.WriteString(strconv.Itoa(ca.NumQueries()))
			buf.WriteString(" cache queries")
		}
	}
	buf.WriteString(" -->")
	return template.HTML(buf.String())
}

func (c *Context) storeDebug(name string, val interface{}) {
	if c.debugStorage == nil {
		c.debugStorage = make(map[string]interface{})
	}
	c.debugStorage[name] = val
}

func (c *Context) getDebug(name string) interface{} {
	return c.debugStorage[name]
}
<|endoftext|>


<commit_before>package main

import (
	_ "log"

	"github.com/muesli/ircflu/app"

	"github.com/muesli/ircflu/commands"
	_ "github.com/muesli/ircflu/commands/alias"
	_ "github.com/muesli/ircflu/commands/auth"
	_ "github.com/muesli/ircflu/commands/exec"
	_ "github.com/muesli/ircflu/commands/join"
	_ "github.com/muesli/ircflu/commands/part"
	_ "github.com/muesli/ircflu/commands/send"

	"github.com/muesli/ircflu/msgsystem"
	_ "github.com/muesli/ircflu/msgsystem/catserver"
	_ "github.com/muesli/ircflu/msgsystem/irc"
	//	_ "github.com/muesli/ircflu/msgsystem/jabber"
	_ "github.com/muesli/ircflu/msgsystem/web"
	_ "github.com/muesli/ircflu/msgsystem/web/hooks"
	_ "github.com/muesli/ircflu/msgsystem/web/hooks/github"
	_ "github.com/muesli/ircflu/msgsystem/web/hooks/gitlab"
	_ "github.com/richardpeng/ircflu/msgsystem/web/hooks/jira"
)

func main() {
	// Parse command-line args for all registered sub modules
	app.Run()

	// Initialize commands and messaging sub-systems
	commands.StartCommands()
	msgsystem.StartSubSystems()

	// Keep app alive
	ch := make(chan bool)
	<-ch
}
<commit_msg>* Fixed import for main-repo.<commit_after>package main

import (
	_ "log"

	"github.com/muesli/ircflu/app"

	"github.com/muesli/ircflu/commands"
	_ "github.com/muesli/ircflu/commands/alias"
	_ "github.com/muesli/ircflu/commands/auth"
	_ "github.com/muesli/ircflu/commands/exec"
	_ "github.com/muesli/ircflu/commands/join"
	_ "github.com/muesli/ircflu/commands/part"
	_ "github.com/muesli/ircflu/commands/send"

	"github.com/muesli/ircflu/msgsystem"
	_ "github.com/muesli/ircflu/msgsystem/catserver"
	_ "github.com/muesli/ircflu/msgsystem/irc"
	//	_ "github.com/muesli/ircflu/msgsystem/jabber"
	_ "github.com/muesli/ircflu/msgsystem/web"
	_ "github.com/muesli/ircflu/msgsystem/web/hooks"
	_ "github.com/muesli/ircflu/msgsystem/web/hooks/github"
	_ "github.com/muesli/ircflu/msgsystem/web/hooks/gitlab"
	_ "github.com/muesli/ircflu/msgsystem/web/hooks/jira"
)

func main() {
	// Parse command-line args for all registered sub modules
	app.Run()

	// Initialize commands and messaging sub-systems
	commands.StartCommands()
	msgsystem.StartSubSystems()

	// Keep app alive
	ch := make(chan bool)
	<-ch
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2017 Alexander Klauer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package queue

import(
	"reflect"
	"testing"
)

func TestCapacity( t *testing.T ) {
	for i := -3; i < 4; i++ {
		f := newSimpleQueueFactory( i ).( *simpleQueueFactory )
		if f.capacityPerBuffer < 1 {
			t.Errorf( "Too low buffer capacity: %d (requested: %d)", f.capacityPerBuffer, i )
		}
	}
}

func TestSimpleQueue( t *testing.T ) {
	// Build queue
	f := newSimpleQueueFactory( 0 )
	f.prepare()
	var enqueue func( int )
	var dequeue func() ( int, bool )
	enqueue = f.makeEnqueue( reflect.TypeOf( enqueue ) ).Interface().( func( int ) )
	dequeue = f.makeDequeue( reflect.TypeOf( dequeue ) ).Interface().( func() ( int, bool ) )
	f.commit()
	f.reset()
	// Empty dequeue check
	x, ok := dequeue()
	if ok {
		t.Error( "Dequeue succeeds on empty queue" )
	}
	if x != 0 {
		t.Errorf( "Failed dequeue does not return zero value: %d", x )
	}
	// Single enqueue, double dequeue check
	enqueue( 42 )
	x, ok = dequeue()
	if !ok {
		t.Error( "Dequeue on non-empty queue failed" )
	}
	if x != 42 {
		t.Errorf( "Dequeue returned wrong value: %d instead of 42", x )
	}
	x, ok = dequeue()
	if ok {
		t.Error( "Dequeue succeeds on now-empty queue" )
	}
	if x != 0 {
		t.Errorf( "Failed dequeue does not return zero value: %d", x )
	}
	// queue order check
	for i := 0; i < 100; i++ {
		enqueue( i )
	}
	for i := 0; i < 100; i++ {
		x, ok = dequeue()
		if !ok {
			t.Error( "Dequeue fails on non-empty queue" )
		}
		if x != i {
			t.Errorf( "Dequeue returned wrong value: %d instead of %d", x, i )
		}
	}
}
<commit_msg>simple queue: rename capacity test<commit_after>/*
Copyright (c) 2017 Alexander Klauer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package queue

import(
	"reflect"
	"testing"
)

func TestSimpleCapacity( t *testing.T ) {
	for i := -3; i < 4; i++ {
		f := newSimpleQueueFactory( i ).( *simpleQueueFactory )
		if f.capacityPerBuffer < 1 {
			t.Errorf( "Too low buffer capacity: %d (requested: %d)", f.capacityPerBuffer, i )
		}
	}
}

func TestSimpleQueue( t *testing.T ) {
	// Build queue
	f := newSimpleQueueFactory( 0 )
	f.prepare()
	var enqueue func( int )
	var dequeue func() ( int, bool )
	enqueue = f.makeEnqueue( reflect.TypeOf( enqueue ) ).Interface().( func( int ) )
	dequeue = f.makeDequeue( reflect.TypeOf( dequeue ) ).Interface().( func() ( int, bool ) )
	f.commit()
	f.reset()
	// Empty dequeue check
	x, ok := dequeue()
	if ok {
		t.Error( "Dequeue succeeds on empty queue" )
	}
	if x != 0 {
		t.Errorf( "Failed dequeue does not return zero value: %d", x )
	}
	// Single enqueue, double dequeue check
	enqueue( 42 )
	x, ok = dequeue()
	if !ok {
		t.Error( "Dequeue on non-empty queue failed" )
	}
	if x != 42 {
		t.Errorf( "Dequeue returned wrong value: %d instead of 42", x )
	}
	x, ok = dequeue()
	if ok {
		t.Error( "Dequeue succeeds on now-empty queue" )
	}
	if x != 0 {
		t.Errorf( "Failed dequeue does not return zero value: %d", x )
	}
	// queue order check
	for i := 0; i < 100; i++ {
		enqueue( i )
	}
	for i := 0; i < 100; i++ {
		x, ok = dequeue()
		if !ok {
			t.Error( "Dequeue fails on non-empty queue" )
		}
		if x != i {
			t.Errorf( "Dequeue returned wrong value: %d instead of %d", x, i )
		}
	}
}
<|endoftext|>


<commit_before>package cmd

// Version defines the current Pop version.
const Version = "v4.9.4-rc.2"
<commit_msg>version bump: v4.9.4<commit_after>package cmd

// Version defines the current Pop version.
const Version = "v4.9.4"
<|endoftext|>


<commit_before>package renter

import (
	"crypto/rand"
	"errors"
	"time"

	"github.com/NebulousLabs/Sia/modules"
)

const (
	maxUploadAttempts = 8
)

// threadedUploadPiece will upload the piece of a file to a randomly chosen
// host. If the wallet has insufficient balance to support uploading,
// uploadPiece will give up. The file uploading can be continued using a repair
// tool. Upon completion, the memory containg the piece's information is
// updated.
func (r *Renter) threadedUploadPiece(up modules.UploadParams, piece *FilePiece) {
	// Set 'Repairing' for the piece to true.
	r.mu.Lock()
	piece.Repairing = true
	r.mu.Unlock()

	// Try 'maxUploadAttempts' hosts before giving up.
	for attempts := 0; attempts < maxUploadAttempts; attempts++ {
		// Select a host. An error here is unrecoverable.
		host, err := r.hostDB.RandomHost()
		if err != nil {
			return
		}

		// Negotiate the contract with the host. If the negotiation is
		// unsuccessful, we need to try again with a new host. Otherwise, the
		// file will be uploaded and we'll be done.
		contract, contractID, err := r.negotiateContract(host, up)
		if err != nil {
			// The previous attempt didn't work. We will try again after
			// sleeping for a randomized amount of time to increase our chances
			// of success. This will help spread things out if there are
			// problems with network congestion or other randomized issues.
			randSource := make([]byte, 1)
			rand.Read(randSource)
			time.Sleep(time.Duration(attempts) * time.Duration(attempts) * 250 * time.Millisecond * time.Duration(randSource[0]))
			continue
		}

		r.mu.Lock()
		*piece = FilePiece{
			Active:     true,
			Repairing:  false,
			Contract:   contract,
			ContractID: contractID,
			HostIP:     host.IPAddress,
		}
		r.save()
		r.mu.Unlock()
		return
	}
}

// Upload takes an upload parameters, which contain a file to upload, and then
// creates a redundant copy of the file on the Sia network.
func (r *Renter) Upload(up modules.UploadParams) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	// Check for a nickname conflict.
	_, exists := r.files[up.Nickname]
	if exists {
		return errors.New("file with that nickname already exists")
	}

	// Check that the hostdb is sufficiently large to support an upload. Right
	// now that value is set to 3, but in the future the logic will be a bit
	// more complex; once there is erasure coding we'll want to hit the minimum
	// number of pieces plus some buffer before we decide that an upload is
	// okay.
	if len(r.hostDB.ActiveHosts()) < 1 {
		return errors.New("not enough hosts on the network to upload a file :( - maybe you need to upgrade your software")
	}

	// Upload a piece to every host on the network.
	r.files[up.Nickname] = File{
		nickname:     up.Nickname,
		pieces:       make([]FilePiece, up.Pieces),
		startHeight:  r.state.Height() + up.Duration,
		renter:       r,
		uploadParams: up,
	}
	for i := range r.files[up.Nickname].pieces {
		// threadedUploadPiece will change the memory that the piece points to,
		// which is useful because it means the file itself can be renamed but
		// will still point to the same underlying pieces.
		go r.threadedUploadPiece(up, &r.files[up.Nickname].pieces[i])
	}
	r.save()

	return nil
}
<commit_msg>return error if balance is too low to upload<commit_after>package renter

import (
	"crypto/rand"
	"errors"
	"os"
	"time"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

const (
	maxUploadAttempts = 8
)

// checkWalletBalance looks at an upload and determines if there is enough
// money in the wallet to support such an upload. An error is returned if it is
// determined that there is not enough money.
func (r *Renter) checkWalletBalance(up modules.UploadParams) error {
	// Get the size of the file.
	fileInfo, err := os.Stat(up.Filename)
	if err != nil {
		return err
	}
	curSize := types.NewCurrency64(uint64(fileInfo.Size()))

	// TODO: Change average to median so that outliers are ignored.
	sampleSize := 12
	var averagePrice types.Currency
	for i := 0; i < sampleSize; i++ {
		potentialHost, err := r.hostDB.RandomHost()
		if err != nil {
			return err
		}
		averagePrice = averagePrice.Add(potentialHost.Price)
	}
	averagePrice = averagePrice.Div(types.NewCurrency64(uint64(sampleSize)))
	estimatedCost := averagePrice.Mul(types.NewCurrency64(uint64(up.Duration))).Mul(curSize)
	bufferedCost := estimatedCost.Mul(types.NewCurrency64(2))

	if bufferedCost.Cmp(r.wallet.Balance(false)) > 0 {
		return errors.New("insufficient balance for upload")
	}
	return nil
}

// threadedUploadPiece will upload the piece of a file to a randomly chosen
// host. If the wallet has insufficient balance to support uploading,
// uploadPiece will give up. The file uploading can be continued using a repair
// tool. Upon completion, the memory containg the piece's information is
// updated.
func (r *Renter) threadedUploadPiece(up modules.UploadParams, piece *FilePiece) {
	// Set 'Repairing' for the piece to true.
	r.mu.Lock()
	piece.Repairing = true
	r.mu.Unlock()

	// Try 'maxUploadAttempts' hosts before giving up.
	for attempts := 0; attempts < maxUploadAttempts; attempts++ {
		// Select a host. An error here is unrecoverable.
		host, err := r.hostDB.RandomHost()
		if err != nil {
			return
		}

		// Negotiate the contract with the host. If the negotiation is
		// unsuccessful, we need to try again with a new host. Otherwise, the
		// file will be uploaded and we'll be done.
		contract, contractID, err := r.negotiateContract(host, up)
		if err != nil {
			// The previous attempt didn't work. We will try again after
			// sleeping for a randomized amount of time to increase our chances
			// of success. This will help spread things out if there are
			// problems with network congestion or other randomized issues.
			randSource := make([]byte, 1)
			rand.Read(randSource)
			time.Sleep(time.Duration(attempts) * time.Duration(attempts) * 250 * time.Millisecond * time.Duration(randSource[0]))
			continue
		}

		r.mu.Lock()
		*piece = FilePiece{
			Active:     true,
			Repairing:  false,
			Contract:   contract,
			ContractID: contractID,
			HostIP:     host.IPAddress,
		}
		r.save()
		r.mu.Unlock()
		return
	}
}

// Upload takes an upload parameters, which contain a file to upload, and then
// creates a redundant copy of the file on the Sia network.
func (r *Renter) Upload(up modules.UploadParams) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	err := r.checkWalletBalance(up)
	if err != nil {
		return err
	}

	// Check for a nickname conflict.
	_, exists := r.files[up.Nickname]
	if exists {
		return errors.New("file with that nickname already exists")
	}

	// Check that the hostdb is sufficiently large to support an upload. Right
	// now that value is set to 3, but in the future the logic will be a bit
	// more complex; once there is erasure coding we'll want to hit the minimum
	// number of pieces plus some buffer before we decide that an upload is
	// okay.
	if len(r.hostDB.ActiveHosts()) < 1 {
		return errors.New("not enough hosts on the network to upload a file :( - maybe you need to upgrade your software")
	}

	// Upload a piece to every host on the network.
	r.files[up.Nickname] = File{
		nickname:     up.Nickname,
		pieces:       make([]FilePiece, up.Pieces),
		startHeight:  r.state.Height() + up.Duration,
		renter:       r,
		uploadParams: up,
	}
	for i := range r.files[up.Nickname].pieces {
		// threadedUploadPiece will change the memory that the piece points to,
		// which is useful because it means the file itself can be renamed but
		// will still point to the same underlying pieces.
		go r.threadedUploadPiece(up, &r.files[up.Nickname].pieces[i])
	}
	r.save()

	return nil
}
<|endoftext|>


<commit_before>package daemon

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/container"
	"github.com/docker/docker/image"
	"github.com/docker/docker/pkg/graphdb"
	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/filters"
	"github.com/docker/go-connections/nat"
)

// iterationAction represents possible outcomes happening during the container iteration.
type iterationAction int

// containerReducer represents a reducer for a container.
// Returns the object to serialize by the api.
type containerReducer func(*container.Container, *listContext) (*types.Container, error)

const (
	// includeContainer is the action to include a container in the reducer.
	includeContainer iterationAction = iota
	// excludeContainer is the action to exclude a container in the reducer.
	excludeContainer
	// stopIteration is the action to stop iterating over the list of containers.
	stopIteration
)

// errStopIteration makes the iterator to stop without returning an error.
var errStopIteration = errors.New("container list iteration stopped")

// List returns an array of all containers registered in the daemon.
func (daemon *Daemon) List() []*container.Container {
	return daemon.containers.List()
}

// ContainersConfig is the filtering specified by the user to iterate over containers.
type ContainersConfig struct {
	// if true show all containers, otherwise only running containers.
	All bool
	// show all containers created after this container id
	Since string
	// show all containers created before this container id
	Before string
	// number of containers to return at most
	Limit int
	// if true include the sizes of the containers
	Size bool
	// return only containers that match filters
	Filters string
}

// listContext is the daemon generated filtering to iterate over containers.
// This is created based on the user specification.
type listContext struct {
	// idx is the container iteration index for this context
	idx int
	// ancestorFilter tells whether it should check ancestors or not
	ancestorFilter bool
	// names is a list of container names to filter with
	names map[string][]string
	// images is a list of images to filter with
	images map[image.ID]bool
	// filters is a collection of arguments to filter with, specified by the user
	filters filters.Args
	// exitAllowed is a list of exit codes allowed to filter with
	exitAllowed []int
	// beforeFilter is a filter to ignore containers that appear before the one given
	// this is used for --filter=before= and --before=, the latter is deprecated.
	beforeFilter *container.Container
	// sinceFilter is a filter to stop the filtering when the iterator arrive to the given container
	// this is used for --filter=since= and --since=, the latter is deprecated.
	sinceFilter *container.Container
	// ContainersConfig is the filters set by the user
	*ContainersConfig
}

// Containers returns the list of containers to show given the user's filtering.
func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container, error) {
	return daemon.reduceContainers(config, daemon.transformContainer)
}

// reduceContainer parses the user filtering and generates the list of containers to return based on a reducer.
func (daemon *Daemon) reduceContainers(config *ContainersConfig, reducer containerReducer) ([]*types.Container, error) {
	containers := []*types.Container{}

	ctx, err := daemon.foldFilter(config)
	if err != nil {
		return nil, err
	}

	for _, container := range daemon.List() {
		t, err := daemon.reducePsContainer(container, ctx, reducer)
		if err != nil {
			if err != errStopIteration {
				return nil, err
			}
			break
		}
		if t != nil {
			containers = append(containers, t)
			ctx.idx++
		}
	}
	return containers, nil
}

// reducePsContainer is the basic representation for a container as expected by the ps command.
func (daemon *Daemon) reducePsContainer(container *container.Container, ctx *listContext, reducer containerReducer) (*types.Container, error) {
	container.Lock()
	defer container.Unlock()

	// filter containers to return
	action := includeContainerInList(container, ctx)
	switch action {
	case excludeContainer:
		return nil, nil
	case stopIteration:
		return nil, errStopIteration
	}

	// transform internal container struct into api structs
	return reducer(container, ctx)
}

// foldFilter generates the container filter based in the user's filtering options.
func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error) {
	psFilters, err := filters.FromParam(config.Filters)
	if err != nil {
		return nil, err
	}

	var filtExited []int
	err = psFilters.WalkValues("exited", func(value string) error {
		code, err := strconv.Atoi(value)
		if err != nil {
			return err
		}
		filtExited = append(filtExited, code)
		return nil
	})
	if err != nil {
		return nil, err
	}

	err = psFilters.WalkValues("status", func(value string) error {
		if !container.IsValidStateString(value) {
			return fmt.Errorf("Unrecognised filter value for status: %s", value)
		}

		config.All = true
		return nil
	})
	if err != nil {
		return nil, err
	}

	var beforeContFilter, sinceContFilter *container.Container
	err = psFilters.WalkValues("before", func(value string) error {
		beforeContFilter, err = daemon.GetContainer(value)
		return err
	})
	if err != nil {
		return nil, err
	}

	err = psFilters.WalkValues("since", func(value string) error {
		sinceContFilter, err = daemon.GetContainer(value)
		return err
	})
	if err != nil {
		return nil, err
	}

	imagesFilter := map[image.ID]bool{}
	var ancestorFilter bool
	if psFilters.Include("ancestor") {
		ancestorFilter = true
		psFilters.WalkValues("ancestor", func(ancestor string) error {
			id, err := daemon.GetImageID(ancestor)
			if err != nil {
				logrus.Warnf("Error while looking up for image %v", ancestor)
				return nil
			}
			if imagesFilter[id] {
				// Already seen this ancestor, skip it
				return nil
			}
			// Then walk down the graph and put the imageIds in imagesFilter
			populateImageFilterByParents(imagesFilter, id, daemon.imageStore.Children)
			return nil
		})
	}

	names := make(map[string][]string)
	daemon.containerGraph().Walk("/", func(p string, e *graphdb.Entity) error {
		names[e.ID()] = append(names[e.ID()], p)
		return nil
	}, 1)

	if config.Before != "" && beforeContFilter == nil {
		beforeContFilter, err = daemon.GetContainer(config.Before)
		if err != nil {
			return nil, err
		}
	}

	if config.Since != "" && sinceContFilter == nil {
		sinceContFilter, err = daemon.GetContainer(config.Since)
		if err != nil {
			return nil, err
		}
	}

	return &listContext{
		filters:          psFilters,
		ancestorFilter:   ancestorFilter,
		names:            names,
		images:           imagesFilter,
		exitAllowed:      filtExited,
		beforeFilter:     beforeContFilter,
		sinceFilter:      sinceContFilter,
		ContainersConfig: config,
	}, nil
}

// includeContainerInList decides whether a containers should be include in the output or not based in the filter.
// It also decides if the iteration should be stopped or not.
func includeContainerInList(container *container.Container, ctx *listContext) iterationAction {
	// Do not include container if it's stopped and we're not filters
	if !container.Running && !ctx.All && ctx.Limit <= 0 && ctx.beforeFilter == nil && ctx.sinceFilter == nil {
		return excludeContainer
	}

	// Do not include container if the name doesn't match
	if !ctx.filters.Match("name", container.Name) {
		return excludeContainer
	}

	// Do not include container if the id doesn't match
	if !ctx.filters.Match("id", container.ID) {
		return excludeContainer
	}

	// Do not include container if any of the labels don't match
	if !ctx.filters.MatchKVList("label", container.Config.Labels) {
		return excludeContainer
	}

	// Do not include container if the isolation mode doesn't match
	if excludeContainer == excludeByIsolation(container, ctx) {
		return excludeContainer
	}

	// Do not include container if it's in the list before the filter container.
	// Set the filter container to nil to include the rest of containers after this one.
	if ctx.beforeFilter != nil {
		if container.ID == ctx.beforeFilter.ID {
			ctx.beforeFilter = nil
		}
		return excludeContainer
	}

	// Stop iteration when the container arrives to the filter container
	if ctx.sinceFilter != nil {
		if container.ID == ctx.sinceFilter.ID {
			return stopIteration
		}
	}

	// Stop iteration when the index is over the limit
	if ctx.Limit > 0 && ctx.idx == ctx.Limit {
		return stopIteration
	}

	// Do not include container if its exit code is not in the filter
	if len(ctx.exitAllowed) > 0 {
		shouldSkip := true
		for _, code := range ctx.exitAllowed {
			if code == container.ExitCode && !container.Running {
				shouldSkip = false
				break
			}
		}
		if shouldSkip {
			return excludeContainer
		}
	}

	// Do not include container if its status doesn't match the filter
	if !ctx.filters.Match("status", container.State.StateString()) {
		return excludeContainer
	}

	if ctx.ancestorFilter {
		if len(ctx.images) == 0 {
			return excludeContainer
		}
		if !ctx.images[container.ImageID] {
			return excludeContainer
		}
	}

	return includeContainer
}

// transformContainer generates the container type expected by the docker ps command.
func (daemon *Daemon) transformContainer(container *container.Container, ctx *listContext) (*types.Container, error) {
	newC := &types.Container{
		ID:      container.ID,
		Names:   ctx.names[container.ID],
		ImageID: container.ImageID.String(),
	}
	if newC.Names == nil {
		// Dead containers will often have no name, so make sure the response isn't  null
		newC.Names = []string{}
	}

	image := container.Config.Image // if possible keep the original ref
	if image != container.ImageID.String() {
		id, err := daemon.GetImageID(image)
		if _, isDNE := err.(ErrImageDoesNotExist); err != nil && !isDNE {
			return nil, err
		}
		if err != nil || id != container.ImageID {
			image = container.ImageID.String()
		}
	}
	newC.Image = image

	if len(container.Args) > 0 {
		args := []string{}
		for _, arg := range container.Args {
			if strings.Contains(arg, " ") {
				args = append(args, fmt.Sprintf("'%s'", arg))
			} else {
				args = append(args, arg)
			}
		}
		argsAsString := strings.Join(args, " ")

		newC.Command = fmt.Sprintf("%s %s", container.Path, argsAsString)
	} else {
		newC.Command = container.Path
	}
	newC.Created = container.Created.Unix()
	newC.Status = container.State.String()
	newC.HostConfig.NetworkMode = string(container.HostConfig.NetworkMode)
	newC.NetworkSettings = &types.SummaryNetworkSettings{container.NetworkSettings.Networks}

	newC.Ports = []types.Port{}
	for port, bindings := range container.NetworkSettings.Ports {
		p, err := nat.ParsePort(port.Port())
		if err != nil {
			return nil, err
		}
		if len(bindings) == 0 {
			newC.Ports = append(newC.Ports, types.Port{
				PrivatePort: p,
				Type:        port.Proto(),
			})
			continue
		}
		for _, binding := range bindings {
			h, err := nat.ParsePort(binding.HostPort)
			if err != nil {
				return nil, err
			}
			newC.Ports = append(newC.Ports, types.Port{
				PrivatePort: p,
				PublicPort:  h,
				Type:        port.Proto(),
				IP:          binding.HostIP,
			})
		}
	}

	if ctx.Size {
		sizeRw, sizeRootFs := daemon.getSize(container)
		newC.SizeRw = sizeRw
		newC.SizeRootFs = sizeRootFs
	}
	newC.Labels = container.Config.Labels

	return newC, nil
}

// Volumes lists known volumes, using the filter to restrict the range
// of volumes returned.
func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) {
	var volumesOut []*types.Volume
	volFilters, err := filters.FromParam(filter)
	if err != nil {
		return nil, nil, err
	}

	filterUsed := volFilters.Include("dangling") &&
		(volFilters.ExactMatch("dangling", "true") || volFilters.ExactMatch("dangling", "1"))

	volumes, warnings, err := daemon.volumes.List()
	if err != nil {
		return nil, nil, err
	}
	if filterUsed {
		volumes = daemon.volumes.FilterByUsed(volumes)
	}
	for _, v := range volumes {
		volumesOut = append(volumesOut, volumeToAPIType(v))
	}
	return volumesOut, warnings, nil
}

func populateImageFilterByParents(ancestorMap map[image.ID]bool, imageID image.ID, getChildren func(image.ID) []image.ID) {
	if !ancestorMap[imageID] {
		for _, id := range getChildren(imageID) {
			populateImageFilterByParents(ancestorMap, id, getChildren)
		}
		ancestorMap[imageID] = true
	}
}
<commit_msg>Fix race on reading endpoint data<commit_after>package daemon

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/container"
	"github.com/docker/docker/image"
	"github.com/docker/docker/pkg/graphdb"
	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/filters"
	networktypes "github.com/docker/engine-api/types/network"
	"github.com/docker/go-connections/nat"
)

// iterationAction represents possible outcomes happening during the container iteration.
type iterationAction int

// containerReducer represents a reducer for a container.
// Returns the object to serialize by the api.
type containerReducer func(*container.Container, *listContext) (*types.Container, error)

const (
	// includeContainer is the action to include a container in the reducer.
	includeContainer iterationAction = iota
	// excludeContainer is the action to exclude a container in the reducer.
	excludeContainer
	// stopIteration is the action to stop iterating over the list of containers.
	stopIteration
)

// errStopIteration makes the iterator to stop without returning an error.
var errStopIteration = errors.New("container list iteration stopped")

// List returns an array of all containers registered in the daemon.
func (daemon *Daemon) List() []*container.Container {
	return daemon.containers.List()
}

// ContainersConfig is the filtering specified by the user to iterate over containers.
type ContainersConfig struct {
	// if true show all containers, otherwise only running containers.
	All bool
	// show all containers created after this container id
	Since string
	// show all containers created before this container id
	Before string
	// number of containers to return at most
	Limit int
	// if true include the sizes of the containers
	Size bool
	// return only containers that match filters
	Filters string
}

// listContext is the daemon generated filtering to iterate over containers.
// This is created based on the user specification.
type listContext struct {
	// idx is the container iteration index for this context
	idx int
	// ancestorFilter tells whether it should check ancestors or not
	ancestorFilter bool
	// names is a list of container names to filter with
	names map[string][]string
	// images is a list of images to filter with
	images map[image.ID]bool
	// filters is a collection of arguments to filter with, specified by the user
	filters filters.Args
	// exitAllowed is a list of exit codes allowed to filter with
	exitAllowed []int
	// beforeFilter is a filter to ignore containers that appear before the one given
	// this is used for --filter=before= and --before=, the latter is deprecated.
	beforeFilter *container.Container
	// sinceFilter is a filter to stop the filtering when the iterator arrive to the given container
	// this is used for --filter=since= and --since=, the latter is deprecated.
	sinceFilter *container.Container
	// ContainersConfig is the filters set by the user
	*ContainersConfig
}

// Containers returns the list of containers to show given the user's filtering.
func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container, error) {
	return daemon.reduceContainers(config, daemon.transformContainer)
}

// reduceContainer parses the user filtering and generates the list of containers to return based on a reducer.
func (daemon *Daemon) reduceContainers(config *ContainersConfig, reducer containerReducer) ([]*types.Container, error) {
	containers := []*types.Container{}

	ctx, err := daemon.foldFilter(config)
	if err != nil {
		return nil, err
	}

	for _, container := range daemon.List() {
		t, err := daemon.reducePsContainer(container, ctx, reducer)
		if err != nil {
			if err != errStopIteration {
				return nil, err
			}
			break
		}
		if t != nil {
			containers = append(containers, t)
			ctx.idx++
		}
	}
	return containers, nil
}

// reducePsContainer is the basic representation for a container as expected by the ps command.
func (daemon *Daemon) reducePsContainer(container *container.Container, ctx *listContext, reducer containerReducer) (*types.Container, error) {
	container.Lock()
	defer container.Unlock()

	// filter containers to return
	action := includeContainerInList(container, ctx)
	switch action {
	case excludeContainer:
		return nil, nil
	case stopIteration:
		return nil, errStopIteration
	}

	// transform internal container struct into api structs
	return reducer(container, ctx)
}

// foldFilter generates the container filter based in the user's filtering options.
func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error) {
	psFilters, err := filters.FromParam(config.Filters)
	if err != nil {
		return nil, err
	}

	var filtExited []int
	err = psFilters.WalkValues("exited", func(value string) error {
		code, err := strconv.Atoi(value)
		if err != nil {
			return err
		}
		filtExited = append(filtExited, code)
		return nil
	})
	if err != nil {
		return nil, err
	}

	err = psFilters.WalkValues("status", func(value string) error {
		if !container.IsValidStateString(value) {
			return fmt.Errorf("Unrecognised filter value for status: %s", value)
		}

		config.All = true
		return nil
	})
	if err != nil {
		return nil, err
	}

	var beforeContFilter, sinceContFilter *container.Container
	err = psFilters.WalkValues("before", func(value string) error {
		beforeContFilter, err = daemon.GetContainer(value)
		return err
	})
	if err != nil {
		return nil, err
	}

	err = psFilters.WalkValues("since", func(value string) error {
		sinceContFilter, err = daemon.GetContainer(value)
		return err
	})
	if err != nil {
		return nil, err
	}

	imagesFilter := map[image.ID]bool{}
	var ancestorFilter bool
	if psFilters.Include("ancestor") {
		ancestorFilter = true
		psFilters.WalkValues("ancestor", func(ancestor string) error {
			id, err := daemon.GetImageID(ancestor)
			if err != nil {
				logrus.Warnf("Error while looking up for image %v", ancestor)
				return nil
			}
			if imagesFilter[id] {
				// Already seen this ancestor, skip it
				return nil
			}
			// Then walk down the graph and put the imageIds in imagesFilter
			populateImageFilterByParents(imagesFilter, id, daemon.imageStore.Children)
			return nil
		})
	}

	names := make(map[string][]string)
	daemon.containerGraph().Walk("/", func(p string, e *graphdb.Entity) error {
		names[e.ID()] = append(names[e.ID()], p)
		return nil
	}, 1)

	if config.Before != "" && beforeContFilter == nil {
		beforeContFilter, err = daemon.GetContainer(config.Before)
		if err != nil {
			return nil, err
		}
	}

	if config.Since != "" && sinceContFilter == nil {
		sinceContFilter, err = daemon.GetContainer(config.Since)
		if err != nil {
			return nil, err
		}
	}

	return &listContext{
		filters:          psFilters,
		ancestorFilter:   ancestorFilter,
		names:            names,
		images:           imagesFilter,
		exitAllowed:      filtExited,
		beforeFilter:     beforeContFilter,
		sinceFilter:      sinceContFilter,
		ContainersConfig: config,
	}, nil
}

// includeContainerInList decides whether a containers should be include in the output or not based in the filter.
// It also decides if the iteration should be stopped or not.
func includeContainerInList(container *container.Container, ctx *listContext) iterationAction {
	// Do not include container if it's stopped and we're not filters
	if !container.Running && !ctx.All && ctx.Limit <= 0 && ctx.beforeFilter == nil && ctx.sinceFilter == nil {
		return excludeContainer
	}

	// Do not include container if the name doesn't match
	if !ctx.filters.Match("name", container.Name) {
		return excludeContainer
	}

	// Do not include container if the id doesn't match
	if !ctx.filters.Match("id", container.ID) {
		return excludeContainer
	}

	// Do not include container if any of the labels don't match
	if !ctx.filters.MatchKVList("label", container.Config.Labels) {
		return excludeContainer
	}

	// Do not include container if the isolation mode doesn't match
	if excludeContainer == excludeByIsolation(container, ctx) {
		return excludeContainer
	}

	// Do not include container if it's in the list before the filter container.
	// Set the filter container to nil to include the rest of containers after this one.
	if ctx.beforeFilter != nil {
		if container.ID == ctx.beforeFilter.ID {
			ctx.beforeFilter = nil
		}
		return excludeContainer
	}

	// Stop iteration when the container arrives to the filter container
	if ctx.sinceFilter != nil {
		if container.ID == ctx.sinceFilter.ID {
			return stopIteration
		}
	}

	// Stop iteration when the index is over the limit
	if ctx.Limit > 0 && ctx.idx == ctx.Limit {
		return stopIteration
	}

	// Do not include container if its exit code is not in the filter
	if len(ctx.exitAllowed) > 0 {
		shouldSkip := true
		for _, code := range ctx.exitAllowed {
			if code == container.ExitCode && !container.Running {
				shouldSkip = false
				break
			}
		}
		if shouldSkip {
			return excludeContainer
		}
	}

	// Do not include container if its status doesn't match the filter
	if !ctx.filters.Match("status", container.State.StateString()) {
		return excludeContainer
	}

	if ctx.ancestorFilter {
		if len(ctx.images) == 0 {
			return excludeContainer
		}
		if !ctx.images[container.ImageID] {
			return excludeContainer
		}
	}

	return includeContainer
}

// transformContainer generates the container type expected by the docker ps command.
func (daemon *Daemon) transformContainer(container *container.Container, ctx *listContext) (*types.Container, error) {
	newC := &types.Container{
		ID:      container.ID,
		Names:   ctx.names[container.ID],
		ImageID: container.ImageID.String(),
	}
	if newC.Names == nil {
		// Dead containers will often have no name, so make sure the response isn't  null
		newC.Names = []string{}
	}

	image := container.Config.Image // if possible keep the original ref
	if image != container.ImageID.String() {
		id, err := daemon.GetImageID(image)
		if _, isDNE := err.(ErrImageDoesNotExist); err != nil && !isDNE {
			return nil, err
		}
		if err != nil || id != container.ImageID {
			image = container.ImageID.String()
		}
	}
	newC.Image = image

	if len(container.Args) > 0 {
		args := []string{}
		for _, arg := range container.Args {
			if strings.Contains(arg, " ") {
				args = append(args, fmt.Sprintf("'%s'", arg))
			} else {
				args = append(args, arg)
			}
		}
		argsAsString := strings.Join(args, " ")

		newC.Command = fmt.Sprintf("%s %s", container.Path, argsAsString)
	} else {
		newC.Command = container.Path
	}
	newC.Created = container.Created.Unix()
	newC.Status = container.State.String()
	newC.HostConfig.NetworkMode = string(container.HostConfig.NetworkMode)
	// copy networks to avoid races
	networks := make(map[string]*networktypes.EndpointSettings)
	for name, network := range container.NetworkSettings.Networks {
		if network == nil {
			continue
		}
		networks[name] = &networktypes.EndpointSettings{
			EndpointID:          network.EndpointID,
			Gateway:             network.Gateway,
			IPAddress:           network.IPAddress,
			IPPrefixLen:         network.IPPrefixLen,
			IPv6Gateway:         network.IPv6Gateway,
			GlobalIPv6Address:   network.GlobalIPv6Address,
			GlobalIPv6PrefixLen: network.GlobalIPv6PrefixLen,
			MacAddress:          network.MacAddress,
		}
		if network.IPAMConfig != nil {
			networks[name].IPAMConfig = &networktypes.EndpointIPAMConfig{
				IPv4Address: network.IPAMConfig.IPv4Address,
				IPv6Address: network.IPAMConfig.IPv6Address,
			}
		}
	}
	newC.NetworkSettings = &types.SummaryNetworkSettings{Networks: networks}

	newC.Ports = []types.Port{}
	for port, bindings := range container.NetworkSettings.Ports {
		p, err := nat.ParsePort(port.Port())
		if err != nil {
			return nil, err
		}
		if len(bindings) == 0 {
			newC.Ports = append(newC.Ports, types.Port{
				PrivatePort: p,
				Type:        port.Proto(),
			})
			continue
		}
		for _, binding := range bindings {
			h, err := nat.ParsePort(binding.HostPort)
			if err != nil {
				return nil, err
			}
			newC.Ports = append(newC.Ports, types.Port{
				PrivatePort: p,
				PublicPort:  h,
				Type:        port.Proto(),
				IP:          binding.HostIP,
			})
		}
	}

	if ctx.Size {
		sizeRw, sizeRootFs := daemon.getSize(container)
		newC.SizeRw = sizeRw
		newC.SizeRootFs = sizeRootFs
	}
	newC.Labels = container.Config.Labels

	return newC, nil
}

// Volumes lists known volumes, using the filter to restrict the range
// of volumes returned.
func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) {
	var volumesOut []*types.Volume
	volFilters, err := filters.FromParam(filter)
	if err != nil {
		return nil, nil, err
	}

	filterUsed := volFilters.Include("dangling") &&
		(volFilters.ExactMatch("dangling", "true") || volFilters.ExactMatch("dangling", "1"))

	volumes, warnings, err := daemon.volumes.List()
	if err != nil {
		return nil, nil, err
	}
	if filterUsed {
		volumes = daemon.volumes.FilterByUsed(volumes)
	}
	for _, v := range volumes {
		volumesOut = append(volumesOut, volumeToAPIType(v))
	}
	return volumesOut, warnings, nil
}

func populateImageFilterByParents(ancestorMap map[image.ID]bool, imageID image.ID, getChildren func(image.ID) []image.ID) {
	if !ancestorMap[imageID] {
		for _, id := range getChildren(imageID) {
			populateImageFilterByParents(ancestorMap, id, getChildren)
		}
		ancestorMap[imageID] = true
	}
}
<|endoftext|>