<commit_before>package chart

import (
	"bytes"
	"fmt"
	"io"
	"math"
	"strings"

	"golang.org/x/image/font"

	"github.com/golang/freetype/truetype"
	"github.com/wcharczuk/go-chart/drawing"
)

// SVG returns a new png/raster renderer.
func SVG(width, height int) (Renderer, error) {
	buffer := bytes.NewBuffer([]byte{})
	canvas := newCanvas(buffer)
	canvas.Start(width, height)
	return &vectorRenderer{
		b: buffer,
		c: canvas,
		s: &Style{},
		p: []string{},
	}, nil
}

// vectorRenderer renders chart commands to a bitmap.
type vectorRenderer struct {
	dpi float64
	b   *bytes.Buffer
	c   *canvas
	s   *Style
	p   []string
	fc  *font.Drawer
}

func (vr *vectorRenderer) ResetStyle() {
	vr.s = &Style{Font: vr.s.Font}
	vr.fc = nil
}

// GetDPI returns the dpi.
func (vr *vectorRenderer) GetDPI() float64 {
	return vr.dpi
}

// SetDPI implements the interface method.
func (vr *vectorRenderer) SetDPI(dpi float64) {
	vr.dpi = dpi
	vr.c.dpi = dpi
}

// SetStrokeColor implements the interface method.
func (vr *vectorRenderer) SetStrokeColor(c drawing.Color) {
	vr.s.StrokeColor = c
}

// SetFillColor implements the interface method.
func (vr *vectorRenderer) SetFillColor(c drawing.Color) {
	vr.s.FillColor = c
}

// SetLineWidth implements the interface method.
func (vr *vectorRenderer) SetStrokeWidth(width float64) {
	vr.s.StrokeWidth = width
}

// StrokeDashArray sets the stroke dash array.
func (vr *vectorRenderer) SetStrokeDashArray(dashArray []float64) {
	vr.s.StrokeDashArray = dashArray
}

// MoveTo implements the interface method.
func (vr *vectorRenderer) MoveTo(x, y int) {
	vr.p = append(vr.p, fmt.Sprintf("M %d %d", x, y))
}

// LineTo implements the interface method.
func (vr *vectorRenderer) LineTo(x, y int) {
	vr.p = append(vr.p, fmt.Sprintf("L %d %d", x, y))
}

// QuadCurveTo draws a quad curve.
func (vr *vectorRenderer) QuadCurveTo(cx, cy, x, y int) {
	vr.p = append(vr.p, fmt.Sprintf("Q%d,%d %d,%d", cx, cy, x, y))
}

func (vr *vectorRenderer) ArcTo(cx, cy int, rx, ry, startAngle, delta float64) {
	startAngle = Math.RadianAdd(startAngle, _pi2)
	endAngle := Math.RadianAdd(startAngle, delta)

	startx := cx + int(rx*math.Sin(startAngle))
	starty := cy - int(ry*math.Cos(startAngle))

	if len(vr.p) > 0 {
		vr.p = append(vr.p, fmt.Sprintf("L %d %d", startx, starty))
	} else {
		vr.p = append(vr.p, fmt.Sprintf("M %d %d", startx, starty))
	}

	endx := cx + int(rx*math.Sin(endAngle))
	endy := cy - int(ry*math.Cos(endAngle))

	dd := Math.RadiansToDegrees(delta)

	vr.p = append(vr.p, fmt.Sprintf("A %d %d %0.2f 0 1 %d %d", int(rx), int(ry), dd, endx, endy))
}

// Close closes a shape.
func (vr *vectorRenderer) Close() {
	vr.p = append(vr.p, fmt.Sprintf("Z"))
}

// Stroke draws the path with no fill.
func (vr *vectorRenderer) Stroke() {
	vr.drawPath(vr.s.GetStrokeOptions())
}

// Fill draws the path with no stroke.
func (vr *vectorRenderer) Fill() {
	vr.drawPath(vr.s.GetFillOptions())
}

// FillStroke draws the path with both fill and stroke.
func (vr *vectorRenderer) FillStroke() {
	vr.drawPath(vr.s.GetFillAndStrokeOptions())
}

// drawPath draws a path.
func (vr *vectorRenderer) drawPath(s Style) {
	vr.c.Path(strings.Join(vr.p, "\n"), vr.s.GetFillAndStrokeOptions())
	vr.p = []string{} // clear the path
}

// Circle implements the interface method.
func (vr *vectorRenderer) Circle(radius float64, x, y int) {
	vr.c.Circle(x, y, int(radius), vr.s.GetFillAndStrokeOptions())
}

// SetFont implements the interface method.
func (vr *vectorRenderer) SetFont(f *truetype.Font) {
	vr.s.Font = f
}

// SetFontColor implements the interface method.
func (vr *vectorRenderer) SetFontColor(c drawing.Color) {
	vr.s.FontColor = c
}

// SetFontSize implements the interface method.
func (vr *vectorRenderer) SetFontSize(size float64) {
	vr.s.FontSize = size
}

// Text draws a text blob.
func (vr *vectorRenderer) Text(body string, x, y int) {
	vr.c.Text(x, y, body, vr.s.GetTextOptions())
}

// MeasureText uses the truetype font drawer to measure the width of text.
func (vr *vectorRenderer) MeasureText(body string) (box Box) {
	if vr.s.GetFont() != nil {
		vr.fc = &font.Drawer{
			Face: truetype.NewFace(vr.s.GetFont(), &truetype.Options{
				DPI:  vr.dpi,
				Size: vr.s.FontSize,
			}),
		}
		w := vr.fc.MeasureString(body).Ceil()

		box.Right = w
		box.Bottom = int(drawing.PointsToPixels(vr.dpi, vr.s.FontSize))
		if vr.c.textTheta == nil {
			return
		}
		box = box.Corners().Rotate(Math.RadiansToDegrees(*vr.c.textTheta)).Box()
	}
	return
}

// SetTextRotation sets the text rotation.
func (vr *vectorRenderer) SetTextRotation(radians float64) {
	vr.c.textTheta = &radians
}

// ClearTextRotation clears the text rotation.
func (vr *vectorRenderer) ClearTextRotation() {
	vr.c.textTheta = nil
}

// Save saves the renderer's contents to a writer.
func (vr *vectorRenderer) Save(w io.Writer) error {
	vr.c.End()
	_, err := w.Write(vr.b.Bytes())
	return err
}

func newCanvas(w io.Writer) *canvas {
	return &canvas{
		w: w,
	}
}

type canvas struct {
	w         io.Writer
	dpi       float64
	textTheta *float64
	width     int
	height    int
}

func (c *canvas) Start(width, height int) {
	c.width = width
	c.height = height
	c.w.Write([]byte(fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="%d" height="%d">\n`, c.width, c.height)))
}

func (c *canvas) Path(d string, style Style) {
	var strokeDashArrayProperty string
	if len(style.StrokeDashArray) > 0 {
		strokeDashArrayProperty = c.getStrokeDashArray(style)
	}
	c.w.Write([]byte(fmt.Sprintf(`<path %s d="%s" style="%s"/>`, strokeDashArrayProperty, d, c.styleAsSVG(style))))
}

func (c *canvas) Text(x, y int, body string, style Style) {
	if c.textTheta == nil {
		c.w.Write([]byte(fmt.Sprintf(`<text x="%d" y="%d" style="%s">%s</text>`, x, y, c.styleAsSVG(style), body)))
	} else {
		transform := fmt.Sprintf(` transform="rotate(%0.2f,%d,%d)"`, Math.RadiansToDegrees(*c.textTheta), x, y)
		c.w.Write([]byte(fmt.Sprintf(`<text x="%d" y="%d" style="%s"%s>%s</text>`, x, y, c.styleAsSVG(style), transform, body)))
	}
}

func (c *canvas) Circle(x, y, r int, style Style) {
	c.w.Write([]byte(fmt.Sprintf(`<circle cx="%d" cy="%d" r="%d" style="%s"/>`, x, y, r, c.styleAsSVG(style))))
}

func (c *canvas) End() {
	c.w.Write([]byte("</svg>"))
}

// getStrokeDashArray returns the stroke-dasharray property of a style.
func (c *canvas) getStrokeDashArray(s Style) string {
	if len(s.StrokeDashArray) > 0 {
		var values []string
		for _, v := range s.StrokeDashArray {
			values = append(values, fmt.Sprintf("%0.1f", v))
		}
		return "stroke-dasharray=\"" + strings.Join(values, ", ") + "\""
	}
	return ""
}

// GetFontFace returns the font face for the style.
func (c *canvas) getFontFace(s Style) string {
	family := "sans-serif"
	if s.GetFont() != nil {
		name := s.GetFont().Name(truetype.NameIDFontFamily)
		if len(name) != 0 {
			family = fmt.Sprintf(`'%s',%s`, name, family)
		}
	}
	return fmt.Sprintf("font-family:%s", family)
}

// styleAsSVG returns the style as a svg style string.
func (c *canvas) styleAsSVG(s Style) string {
	sw := s.StrokeWidth
	sc := s.StrokeColor
	fc := s.FillColor
	fs := s.FontSize
	fnc := s.FontColor

	var pieces []string

	if sw != 0 {
		pieces = append(pieces, "stroke-width:"+fmt.Sprintf("%d", int(sw)))
	} else {
		pieces = append(pieces, "stroke-width:0")
	}

	if !sc.IsZero() {
		pieces = append(pieces, "stroke:"+sc.String())
	} else {
		pieces = append(pieces, "stroke:none")
	}

	if !fc.IsZero() {
		pieces = append(pieces, "fill:"+fc.String())
	} else {
		pieces = append(pieces, "fill:none")
	}

	if fs != 0 {
		pieces = append(pieces, "font-size:"+fmt.Sprintf("%.1fpx", drawing.PointsToPixels(c.dpi, fs)))
	}

	if !fnc.IsZero() {
		pieces = append(pieces, "fill:"+fnc.String())
	}

	if s.Font != nil {
		pieces = append(pieces, c.getFontFace(s))
	}
	return strings.Join(pieces, ";")
}
<commit_msg>adding helper<commit_after>package chart

import (
	"bytes"
	"fmt"
	"io"
	"math"
	"strings"

	"golang.org/x/image/font"

	"github.com/golang/freetype/truetype"
	"github.com/wcharczuk/go-chart/drawing"
)

// SVG returns a new png/raster renderer.
func SVG(width, height int) (Renderer, error) {
	buffer := bytes.NewBuffer([]byte{})
	canvas := newCanvas(buffer)
	canvas.Start(width, height)
	return &vectorRenderer{
		b:   buffer,
		c:   canvas,
		s:   &Style{},
		p:   []string{},
		dpi: DefaultDPI,
	}, nil
}

// vectorRenderer renders chart commands to a bitmap.
type vectorRenderer struct {
	dpi float64
	b   *bytes.Buffer
	c   *canvas
	s   *Style
	p   []string
	fc  *font.Drawer
}

func (vr *vectorRenderer) ResetStyle() {
	vr.s = &Style{Font: vr.s.Font}
	vr.fc = nil
}

// GetDPI returns the dpi.
func (vr *vectorRenderer) GetDPI() float64 {
	return vr.dpi
}

// SetDPI implements the interface method.
func (vr *vectorRenderer) SetDPI(dpi float64) {
	vr.dpi = dpi
	vr.c.dpi = dpi
}

// SetStrokeColor implements the interface method.
func (vr *vectorRenderer) SetStrokeColor(c drawing.Color) {
	vr.s.StrokeColor = c
}

// SetFillColor implements the interface method.
func (vr *vectorRenderer) SetFillColor(c drawing.Color) {
	vr.s.FillColor = c
}

// SetLineWidth implements the interface method.
func (vr *vectorRenderer) SetStrokeWidth(width float64) {
	vr.s.StrokeWidth = width
}

// StrokeDashArray sets the stroke dash array.
func (vr *vectorRenderer) SetStrokeDashArray(dashArray []float64) {
	vr.s.StrokeDashArray = dashArray
}

// MoveTo implements the interface method.
func (vr *vectorRenderer) MoveTo(x, y int) {
	vr.p = append(vr.p, fmt.Sprintf("M %d %d", x, y))
}

// LineTo implements the interface method.
func (vr *vectorRenderer) LineTo(x, y int) {
	vr.p = append(vr.p, fmt.Sprintf("L %d %d", x, y))
}

// QuadCurveTo draws a quad curve.
func (vr *vectorRenderer) QuadCurveTo(cx, cy, x, y int) {
	vr.p = append(vr.p, fmt.Sprintf("Q%d,%d %d,%d", cx, cy, x, y))
}

func (vr *vectorRenderer) ArcTo(cx, cy int, rx, ry, startAngle, delta float64) {
	startAngle = Math.RadianAdd(startAngle, _pi2)
	endAngle := Math.RadianAdd(startAngle, delta)

	startx := cx + int(rx*math.Sin(startAngle))
	starty := cy - int(ry*math.Cos(startAngle))

	if len(vr.p) > 0 {
		vr.p = append(vr.p, fmt.Sprintf("L %d %d", startx, starty))
	} else {
		vr.p = append(vr.p, fmt.Sprintf("M %d %d", startx, starty))
	}

	endx := cx + int(rx*math.Sin(endAngle))
	endy := cy - int(ry*math.Cos(endAngle))

	dd := Math.RadiansToDegrees(delta)

	vr.p = append(vr.p, fmt.Sprintf("A %d %d %0.2f 0 1 %d %d", int(rx), int(ry), dd, endx, endy))
}

// Close closes a shape.
func (vr *vectorRenderer) Close() {
	vr.p = append(vr.p, fmt.Sprintf("Z"))
}

// Stroke draws the path with no fill.
func (vr *vectorRenderer) Stroke() {
	vr.drawPath(vr.s.GetStrokeOptions())
}

// Fill draws the path with no stroke.
func (vr *vectorRenderer) Fill() {
	vr.drawPath(vr.s.GetFillOptions())
}

// FillStroke draws the path with both fill and stroke.
func (vr *vectorRenderer) FillStroke() {
	vr.drawPath(vr.s.GetFillAndStrokeOptions())
}

// drawPath draws a path.
func (vr *vectorRenderer) drawPath(s Style) {
	vr.c.Path(strings.Join(vr.p, "\n"), vr.s.GetFillAndStrokeOptions())
	vr.p = []string{} // clear the path
}

// Circle implements the interface method.
func (vr *vectorRenderer) Circle(radius float64, x, y int) {
	vr.c.Circle(x, y, int(radius), vr.s.GetFillAndStrokeOptions())
}

// SetFont implements the interface method.
func (vr *vectorRenderer) SetFont(f *truetype.Font) {
	vr.s.Font = f
}

// SetFontColor implements the interface method.
func (vr *vectorRenderer) SetFontColor(c drawing.Color) {
	vr.s.FontColor = c
}

// SetFontSize implements the interface method.
func (vr *vectorRenderer) SetFontSize(size float64) {
	vr.s.FontSize = size
}

// Text draws a text blob.
func (vr *vectorRenderer) Text(body string, x, y int) {
	vr.c.Text(x, y, body, vr.s.GetTextOptions())
}

// MeasureText uses the truetype font drawer to measure the width of text.
func (vr *vectorRenderer) MeasureText(body string) (box Box) {
	if vr.s.GetFont() != nil {
		vr.fc = &font.Drawer{
			Face: truetype.NewFace(vr.s.GetFont(), &truetype.Options{
				DPI:  vr.dpi,
				Size: vr.s.FontSize,
			}),
		}
		w := vr.fc.MeasureString(body).Ceil()

		box.Right = w
		box.Bottom = int(drawing.PointsToPixels(vr.dpi, vr.s.FontSize))
		if vr.c.textTheta == nil {
			return
		}
		box = box.Corners().Rotate(Math.RadiansToDegrees(*vr.c.textTheta)).Box()
	}
	return
}

// SetTextRotation sets the text rotation.
func (vr *vectorRenderer) SetTextRotation(radians float64) {
	vr.c.textTheta = &radians
}

// ClearTextRotation clears the text rotation.
func (vr *vectorRenderer) ClearTextRotation() {
	vr.c.textTheta = nil
}

// Save saves the renderer's contents to a writer.
func (vr *vectorRenderer) Save(w io.Writer) error {
	vr.c.End()
	_, err := w.Write(vr.b.Bytes())
	return err
}

func newCanvas(w io.Writer) *canvas {
	return &canvas{
		w: w,
	}
}

type canvas struct {
	w         io.Writer
	dpi       float64
	textTheta *float64
	width     int
	height    int
}

func (c *canvas) Start(width, height int) {
	c.width = width
	c.height = height
	c.w.Write([]byte(fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="%d" height="%d">\n`, c.width, c.height)))
}

func (c *canvas) Path(d string, style Style) {
	var strokeDashArrayProperty string
	if len(style.StrokeDashArray) > 0 {
		strokeDashArrayProperty = c.getStrokeDashArray(style)
	}
	c.w.Write([]byte(fmt.Sprintf(`<path %s d="%s" style="%s"/>`, strokeDashArrayProperty, d, c.styleAsSVG(style))))
}

func (c *canvas) Text(x, y int, body string, style Style) {
	if c.textTheta == nil {
		c.w.Write([]byte(fmt.Sprintf(`<text x="%d" y="%d" style="%s">%s</text>`, x, y, c.styleAsSVG(style), body)))
	} else {
		transform := fmt.Sprintf(` transform="rotate(%0.2f,%d,%d)"`, Math.RadiansToDegrees(*c.textTheta), x, y)
		c.w.Write([]byte(fmt.Sprintf(`<text x="%d" y="%d" style="%s"%s>%s</text>`, x, y, c.styleAsSVG(style), transform, body)))
	}
}

func (c *canvas) Circle(x, y, r int, style Style) {
	c.w.Write([]byte(fmt.Sprintf(`<circle cx="%d" cy="%d" r="%d" style="%s"/>`, x, y, r, c.styleAsSVG(style))))
}

func (c *canvas) End() {
	c.w.Write([]byte("</svg>"))
}

// getStrokeDashArray returns the stroke-dasharray property of a style.
func (c *canvas) getStrokeDashArray(s Style) string {
	if len(s.StrokeDashArray) > 0 {
		var values []string
		for _, v := range s.StrokeDashArray {
			values = append(values, fmt.Sprintf("%0.1f", v))
		}
		return "stroke-dasharray=\"" + strings.Join(values, ", ") + "\""
	}
	return ""
}

// GetFontFace returns the font face for the style.
func (c *canvas) getFontFace(s Style) string {
	family := "sans-serif"
	if s.GetFont() != nil {
		name := s.GetFont().Name(truetype.NameIDFontFamily)
		if len(name) != 0 {
			family = fmt.Sprintf(`'%s',%s`, name, family)
		}
	}
	return fmt.Sprintf("font-family:%s", family)
}

// styleAsSVG returns the style as a svg style string.
func (c *canvas) styleAsSVG(s Style) string {
	sw := s.StrokeWidth
	sc := s.StrokeColor
	fc := s.FillColor
	fs := s.FontSize
	fnc := s.FontColor

	var pieces []string

	if sw != 0 {
		pieces = append(pieces, "stroke-width:"+fmt.Sprintf("%d", int(sw)))
	} else {
		pieces = append(pieces, "stroke-width:0")
	}

	if !sc.IsZero() {
		pieces = append(pieces, "stroke:"+sc.String())
	} else {
		pieces = append(pieces, "stroke:none")
	}

	if !fnc.IsZero() {
		pieces = append(pieces, "fill:"+fnc.String())
	} else if !fc.IsZero() {
		pieces = append(pieces, "fill:"+fc.String())
	} else {
		pieces = append(pieces, "fill:none")
	}

	if fs != 0 {
		pieces = append(pieces, "font-size:"+fmt.Sprintf("%.1fpx", drawing.PointsToPixels(c.dpi, fs)))
	}

	if s.Font != nil {
		pieces = append(pieces, c.getFontFace(s))
	}
	return strings.Join(pieces, ";")
}
<|endoftext|>


<commit_before>package tests

import (
	"database/sql"
	"log"
	"os"
	"reflect"
	"testing"

	_ "github.com/mattn/go-sqlite3"
	"github.com/monochromegane/argen"
)

func TestMain(m *testing.M) {
	db, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	Use(db)
	sqlStmt := `
	create table users (id integer not null primary key, name text);
	create table posts (id integer not null primary key, user_id integer, name text);
	`
	_, err = db.Exec(sqlStmt)
	if err != nil {
		log.Fatal(err, sqlStmt)
	}

	os.Exit(m.Run())
}

func TestSelect(t *testing.T) {
	u := &User{Name: "test"}
	u.Save()
	defer User{}.DeleteAll()

	u, err := User{}.Select("id").First()
	assertError(t, err)

	if !ar.IsZero(u.Name) {
		t.Errorf("column value should be empty, but %s", u.Name)
	}
}

func TestFind(t *testing.T) {
	expect := &User{Name: "test"}
	expect.Save()
	defer User{}.DeleteAll()

	u, err := User{}.Find(1)
	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestFindBy(t *testing.T) {
	expect := &User{Name: "test"}
	expect.Save()
	defer User{}.DeleteAll()

	u, err := User{}.FindBy("name", "test")
	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestFirst(t *testing.T) {
	for _, name := range []string{"test1", "test2"} {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	expect, _ := User{}.Where("name", "test1").QueryRow()

	u, err := User{}.First()
	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestLast(t *testing.T) {
	for _, name := range []string{"test1", "test2"} {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	expect, _ := User{}.Where("name", "test2").QueryRow()

	u, err := User{}.Last()
	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestWhere(t *testing.T) {
	expect := &User{Name: "test"}
	expect.Save()
	defer User{}.DeleteAll()

	u, err := User{}.Where("name", "test").And("id", 1).QueryRow()

	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestOrder(t *testing.T) {
	expects := []string{"test1", "test2"}
	for _, name := range expects {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	users, err := User{}.Order("name", "ASC").Query()

	assertError(t, err)
	for i, u := range users {
		if u.Name != expects[i] {
			t.Errorf("column value should be %v, but %v", expects[i], u.Name)
		}
	}
}

func TestLimitAndOffset(t *testing.T) {
	for _, name := range []string{"test1", "test2", "test3"} {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	users, err := User{}.Limit(2).Offset(1).Order("name", "ASC").Query()

	assertError(t, err)
	expects := []string{"test2", "test3"}
	for i, u := range users {
		if u.Name != expects[i] {
			t.Errorf("column value should be %v, but %v", expects[i], u.Name)
		}
	}
}

func TestGroupByAndHaving(t *testing.T) {
	for _, name := range []string{"testA", "testB", "testB"} {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	users, err := User{}.Group("name").Having("count(name)", 2).Query()

	assertError(t, err)
	expects := []string{"testB"}
	for i, u := range users {
		if u.Name != expects[i] {
			t.Errorf("column value should be %v, but %v", expects[i], u.Name)
		}
	}
}

func TestExplain(t *testing.T) {
	err := User{}.Where("name", "test").Explain()
	assertError(t, err)
}

func TestIsValid(t *testing.T) {
	p := &Post{Name: "abc"}
	_, errs := p.IsValid()

	if len(errs.Messages["name"]) != 2 {
		t.Errorf("errors count should be 2, but %d", len(errs.Messages["name"]))
	}
}

func TestCreate(t *testing.T) {
	u, errs := User{}.Create(UserParams{
		Name: "TestCreate",
	})
	assertErrors(t, errs)

	expect, _ := User{}.FindBy("name", "TestCreate")
	assertEqualStruct(t, expect, u)
}

func assertEqualStruct(t *testing.T, expect, actual interface{}) {
	if !reflect.DeepEqual(expect, actual) {
		t.Errorf("struct should be equal to %v, but %v", expect, actual)
	}
}

func assertErrors(t *testing.T, errs *ar.Errors) {
	if errs != nil {
		t.Errorf("errors should be nil, but %v", errs)
	}
}

func assertError(t *testing.T, err error) {
	if err != nil {
		t.Errorf("error should be nil, but %v", err)
	}
}
<commit_msg>Added IsNewRecord and IsPersistent tests.<commit_after>package tests

import (
	"database/sql"
	"log"
	"os"
	"reflect"
	"testing"

	_ "github.com/mattn/go-sqlite3"
	"github.com/monochromegane/argen"
)

func TestMain(m *testing.M) {
	db, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	Use(db)
	sqlStmt := `
	create table users (id integer not null primary key, name text);
	create table posts (id integer not null primary key, user_id integer, name text);
	`
	_, err = db.Exec(sqlStmt)
	if err != nil {
		log.Fatal(err, sqlStmt)
	}

	os.Exit(m.Run())
}

func TestSelect(t *testing.T) {
	u := &User{Name: "test"}
	u.Save()
	defer User{}.DeleteAll()

	u, err := User{}.Select("id").First()
	assertError(t, err)

	if !ar.IsZero(u.Name) {
		t.Errorf("column value should be empty, but %s", u.Name)
	}
}

func TestFind(t *testing.T) {
	expect := &User{Name: "test"}
	expect.Save()
	defer User{}.DeleteAll()

	u, err := User{}.Find(1)
	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestFindBy(t *testing.T) {
	expect := &User{Name: "test"}
	expect.Save()
	defer User{}.DeleteAll()

	u, err := User{}.FindBy("name", "test")
	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestFirst(t *testing.T) {
	for _, name := range []string{"test1", "test2"} {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	expect, _ := User{}.Where("name", "test1").QueryRow()

	u, err := User{}.First()
	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestLast(t *testing.T) {
	for _, name := range []string{"test1", "test2"} {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	expect, _ := User{}.Where("name", "test2").QueryRow()

	u, err := User{}.Last()
	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestWhere(t *testing.T) {
	expect := &User{Name: "test"}
	expect.Save()
	defer User{}.DeleteAll()

	u, err := User{}.Where("name", "test").And("id", 1).QueryRow()

	assertError(t, err)
	assertEqualStruct(t, expect, u)
}

func TestOrder(t *testing.T) {
	expects := []string{"test1", "test2"}
	for _, name := range expects {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	users, err := User{}.Order("name", "ASC").Query()

	assertError(t, err)
	for i, u := range users {
		if u.Name != expects[i] {
			t.Errorf("column value should be %v, but %v", expects[i], u.Name)
		}
	}
}

func TestLimitAndOffset(t *testing.T) {
	for _, name := range []string{"test1", "test2", "test3"} {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	users, err := User{}.Limit(2).Offset(1).Order("name", "ASC").Query()

	assertError(t, err)
	expects := []string{"test2", "test3"}
	for i, u := range users {
		if u.Name != expects[i] {
			t.Errorf("column value should be %v, but %v", expects[i], u.Name)
		}
	}
}

func TestGroupByAndHaving(t *testing.T) {
	for _, name := range []string{"testA", "testB", "testB"} {
		u := &User{Name: name}
		u.Save()
	}
	defer User{}.DeleteAll()

	users, err := User{}.Group("name").Having("count(name)", 2).Query()

	assertError(t, err)
	expects := []string{"testB"}
	for i, u := range users {
		if u.Name != expects[i] {
			t.Errorf("column value should be %v, but %v", expects[i], u.Name)
		}
	}
}

func TestExplain(t *testing.T) {
	err := User{}.Where("name", "test").Explain()
	assertError(t, err)
}

func TestIsValid(t *testing.T) {
	p := &Post{Name: "abc"}
	_, errs := p.IsValid()

	if len(errs.Messages["name"]) != 2 {
		t.Errorf("errors count should be 2, but %d", len(errs.Messages["name"]))
	}
}

func TestCreate(t *testing.T) {
	u, errs := User{}.Create(UserParams{
		Name: "TestCreate",
	})
	defer User{}.DeleteAll()

	assertErrors(t, errs)

	expect, _ := User{}.FindBy("name", "TestCreate")
	assertEqualStruct(t, expect, u)
}

func TestIsNewRecordAndIsPresistent(t *testing.T) {
	defer User{}.DeleteAll()

	u := &User{Name: "test"}
	if !u.IsNewRecord() {
		t.Errorf("struct is new record, but isn't new record.")
	}

	u.Save()
	if !u.IsPersistent() {
		t.Errorf("struct is persistent, but isn't persistent.")
	}
}

func assertEqualStruct(t *testing.T, expect, actual interface{}) {
	if !reflect.DeepEqual(expect, actual) {
		t.Errorf("struct should be equal to %v, but %v", expect, actual)
	}
}

func assertErrors(t *testing.T, errs *ar.Errors) {
	if errs != nil {
		t.Errorf("errors should be nil, but %v", errs)
	}
}

func assertError(t *testing.T, err error) {
	if err != nil {
		t.Errorf("error should be nil, but %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io"
	"log"
	"os"
)

var (
	logLevel      = flag.Int("loglevel", 1, "0 = no output, 1 = standard log, 2 = verbose log")
	logTarget     = flag.String("logtarget", "/dev/stdout", "log target")
	logPermission = flag.Int("logperm", 0600, "permission for log file, default in ocatal: 0600")

	logTargetWriter io.Writer

	logger      *log.Logger
	debugLogger *log.Logger

	emptyLogf = func(fmt string, args ...interface{}) {}
	stdLogf   = func(fmt string, args ...interface{}) { logger.Printf(fmt, args...) }
	debugLogf = func(fmt string, args ...interface{}) { debugLogger.Printf(fmt, args...) }

	logf   = stdLogf
	debugf = emptyLogf
)

func main() {
	var err error

	flag.Parse()

	// Set logTarget
	var logFile *os.File
	fileMode := os.FileMode(*logPermission)
	_, err = os.Stat(*logTarget)
	if os.IsNotExist(err) {
		logFile, err = os.Create(*logTarget)
		if err != nil {
			log.Fatalln("fatal: unable to create log target", err)
		}

		err = os.Chmod(*logTarget, fileMode)
		if err != nil {
			log.Fatalln("fatal: unable to set file permissions", err)
		}
	} else {
		logFile, err = os.OpenFile(*logTarget, os.O_WRONLY|os.O_APPEND, fileMode)
		if err != nil {
			log.Fatalln("fatal: unable to open log target", err)
		}
	}
	defer logFile.Close()
	logTargetWriter = io.Writer(logFile)

	// Check if logTarget is writable
	_, err = logTargetWriter.Write([]byte(""))
	if err != nil {
		log.Fatalln("fatal: unable to write to log target")
	}

	logger = log.New(logTargetWriter, "LOG   ", log.LstdFlags)
	debugLogger = log.New(logTargetWriter, "DEBUG ", log.LstdFlags)

	// Set log-function based on log level
	switch *logLevel {
	case 0:
		logf = emptyLogf
	case 2:
		debugf = debugLogf
	default:
	}

	// Write example log lines
	logf("log output %s, %d", "string1", 10)
	debugf("debug output %s, %d", "string1", 10)
}
<commit_msg>Make default logtarget platform independent<commit_after>package main

import (
	"flag"
	"io"
	"log"
	"os"
)

var (
	logLevel      = flag.Int("loglevel", 1, "0 = no output, 1 = standard log, 2 = verbose log")
	logTarget     = flag.String("logtarget", "", "log target, default: stdout")
	logPermission = flag.Int("logperm", 0600, "permission for log file, default in ocatal: 0600")

	logTargetWriter io.Writer

	logger      *log.Logger
	debugLogger *log.Logger

	emptyLogf = func(fmt string, args ...interface{}) {}
	stdLogf   = func(fmt string, args ...interface{}) { logger.Printf(fmt, args...) }
	debugLogf = func(fmt string, args ...interface{}) { debugLogger.Printf(fmt, args...) }

	logf   = stdLogf
	debugf = emptyLogf
)

func main() {
	var err error

	flag.Parse()

	// Set logTarget
	if *logTarget == "" {
		logger = log.New(os.Stdout, "LOG   ", log.LstdFlags)
		debugLogger = log.New(os.Stdout, "DEBUG ", log.LstdFlags)
	} else {
		var logFile *os.File
		fileMode := os.FileMode(*logPermission)
		_, err = os.Stat(*logTarget)
		if os.IsNotExist(err) {
			logFile, err = os.Create(*logTarget)
			if err != nil {
				log.Fatalln("fatal: unable to create log target", err)
			}

			err = os.Chmod(*logTarget, fileMode)
			if err != nil {
				log.Fatalln("fatal: unable to set file permissions", err)
			}
		} else {
			logFile, err = os.OpenFile(*logTarget, os.O_WRONLY|os.O_APPEND, fileMode)
			if err != nil {
				log.Fatalln("fatal: unable to open log target", err)
			}
		}
		defer logFile.Close()
		logTargetWriter = io.Writer(logFile)

		// Check if logTarget is writable
		_, err = logTargetWriter.Write([]byte(""))
		if err != nil {
			log.Fatalln("fatal: unable to write to log target")
		}

		logger = log.New(logTargetWriter, "LOG   ", log.LstdFlags)
		debugLogger = log.New(logTargetWriter, "DEBUG ", log.LstdFlags)
	}

	// Set log-function based on log level
	switch *logLevel {
	case 0:
		logf = emptyLogf
	case 2:
		debugf = debugLogf
	default:
	}

	// Write example log lines
	logf("log output %s, %d", "string1", 10)
	debugf("debug output %s, %d", "string1", 10)
}
<|endoftext|>


<commit_before>package raft

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"path"
	"time"
)

// Parts from this transporter were heavily influenced by Peter Bougon's
// raft implementation: https://github.com/peterbourgon/raft

//------------------------------------------------------------------------------
//
// Typedefs
//
//------------------------------------------------------------------------------

// An HTTPTransporter is a default transport layer used to communicate between
// multiple servers.
type HTTPTransporter struct {
	DisableKeepAlives    bool
	prefix               string
	appendEntriesPath    string
	requestVotePath      string
	snapshotPath         string
	snapshotRecoveryPath string
	httpClient           http.Client
	Transport            *http.Transport
	RoundTripper         http.RoundTripper
}

type HTTPMuxer interface {
	HandleFunc(string, func(http.ResponseWriter, *http.Request))
}

//------------------------------------------------------------------------------
//
// Constructor
//
//------------------------------------------------------------------------------

// 使用一个指定的路径"/raft"创建一个HTTP transporter
// Creates a new HTTP transporter with the given path prefix.
func NewHTTPTransporter(prefix string, timeout time.Duration) *HTTPTransporter {
	t := &HTTPTransporter{
		DisableKeepAlives:    false,
		prefix:               prefix,
		appendEntriesPath:    joinPath(prefix, "/appendEntries"),
		requestVotePath:      joinPath(prefix, "/requestVote"),
		snapshotPath:         joinPath(prefix, "/snapshot"),
		snapshotRecoveryPath: joinPath(prefix, "/snapshotRecovery"),
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout:   500 * time.Second,
				KeepAlive: 500 * time.Second,
			}).Dial,
		},
	}
	t.httpClient.Transport = t.Transport
	t.Transport.ResponseHeaderTimeout = timeout
	t.RoundTripper = t.Transport
	return t
}

//------------------------------------------------------------------------------
//
// Accessors
//
//------------------------------------------------------------------------------

// Retrieves the path prefix used by the transporter.
func (t *HTTPTransporter) Prefix() string {
	return t.prefix
}

// Retrieves the AppendEntries path.
func (t *HTTPTransporter) AppendEntriesPath() string {
	return t.appendEntriesPath
}

// Retrieves the RequestVote path.
func (t *HTTPTransporter) RequestVotePath() string {
	return t.requestVotePath
}

// Retrieves the Snapshot path.
func (t *HTTPTransporter) SnapshotPath() string {
	return t.snapshotPath
}

// Retrieves the SnapshotRecovery path.
func (t *HTTPTransporter) SnapshotRecoveryPath() string {
	return t.snapshotRecoveryPath
}

//------------------------------------------------------------------------------
//
// Methods
//
//------------------------------------------------------------------------------

//--------------------------------------
// Installation
//--------------------------------------

// 将处理各种请求的URL绑定到路由处理器上
// Applies Raft routes to an HTTP router for a given server.
func (t *HTTPTransporter) Install(server Server, mux HTTPMuxer) {
	mux.HandleFunc(t.AppendEntriesPath(), t.appendEntriesHandler(server))
	mux.HandleFunc(t.RequestVotePath(), t.requestVoteHandler(server))
	mux.HandleFunc(t.SnapshotPath(), t.snapshotHandler(server))
	mux.HandleFunc(t.SnapshotRecoveryPath(), t.snapshotRecoveryHandler(server))
}

//--------------------------------------
// Outgoing
//--------------------------------------

// Sends an AppendEntries RPC to a peer.
func (t *HTTPTransporter) SendAppendEntriesRequest(server Server, peer *Peer, req *AppendEntriesRequest) *AppendEntriesResponse {
	var b bytes.Buffer
	var local_req *http.Request
	var httpResp *http.Response
	var err error

	if _, err := req.Encode(&b); err != nil {
		traceln("transporter.ae.encoding.error:", err)
		return nil
	}

	url := joinPath(peer.ConnectionString, t.AppendEntriesPath())
	traceln(server.Name(), "POST", url)

	local_req, err = http.NewRequest("POST", url, &b)
	if err != nil {
		traceln("transporter.ae.newrequest.error:", err)
		return nil
	}

	local_req.Close = true
	local_req.Header.Add("Content-Type", "application/protobuf")

	if httpResp, err = t.RoundTripper.RoundTrip(local_req); err != nil || httpResp == nil {
		traceln("transporter.ae.response.error:", err)
		return nil
	}
	defer httpResp.Body.Close()

	resp := &AppendEntriesResponse{}
	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
		traceln("transporter.ae.decoding.error:", err)
		return nil
	}

	return resp
}

// Sends a RequestVote RPC to a peer.
func (t *HTTPTransporter) SendVoteRequest(server Server, peer *Peer, req *RequestVoteRequest) *RequestVoteResponse {
	var b bytes.Buffer
	var local_req *http.Request
	var httpResp *http.Response
	var err error

	if _, err := req.Encode(&b); err != nil {
		traceln("transporter.rv.encoding.error:", err)
		return nil
	}

	url := fmt.Sprintf("%s%s", peer.ConnectionString, t.RequestVotePath())
	traceln(server.Name(), "POST", url)

	local_req, err = http.NewRequest("POST", url, &b)
	if err != nil {
		traceln("transporter.rv.newrequest.error:", err)
		return nil
	}

	local_req.Close = true
	local_req.Header.Add("Content-Type", "application/protobuf")

	if httpResp, err = t.RoundTripper.RoundTrip(local_req); err != nil || httpResp == nil {
		traceln("transporter.rv.response.error:", err)
		return nil
	}
	defer httpResp.Body.Close()

	resp := &RequestVoteResponse{}
	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
		traceln("transporter.rv.decoding.error:", err)
		return nil
	}

	return resp
}

func joinPath(connectionString, thePath string) string {
	u, err := url.Parse(connectionString)
	if err != nil {
		panic(err)
	}
	u.Path = path.Join(u.Path, thePath)
	return u.String()
}

// Sends a SnapshotRequest RPC to a peer.
func (t *HTTPTransporter) SendSnapshotRequest(server Server, peer *Peer, req *SnapshotRequest) *SnapshotResponse {
	var b bytes.Buffer
	var local_req *http.Request
	var httpResp *http.Response
	var err error

	if _, err := req.Encode(&b); err != nil {
		traceln("transporter.rv.encoding.error:", err)
		return nil
	}

	url := joinPath(peer.ConnectionString, t.snapshotPath)
	traceln(server.Name(), "POST", url)

	local_req, err = http.NewRequest("POST", url, &b)
	if err != nil {
		traceln("transporter.rv.newrequest.error:", err)
		return nil
	}

	local_req.Close = true
	local_req.Header.Add("Content-Type", "application/protobuf")

	if httpResp, err = t.RoundTripper.RoundTrip(local_req); err != nil || httpResp == nil {
		traceln("transporter.rv.response.error:", err)
		return nil
	}
	defer httpResp.Body.Close()

	resp := &SnapshotResponse{}
	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
		traceln("transporter.rv.decoding.error:", err)
		return nil
	}

	return resp
}

// Sends a SnapshotRequest RPC to a peer.
func (t *HTTPTransporter) SendSnapshotRecoveryRequest(server Server, peer *Peer, req *SnapshotRecoveryRequest) *SnapshotRecoveryResponse {
	var b bytes.Buffer
	var local_req *http.Request
	var httpResp *http.Response
	var err error

	if _, err := req.Encode(&b); err != nil {
		traceln("transporter.rv.encoding.error:", err)
		return nil
	}

	url := joinPath(peer.ConnectionString, t.snapshotRecoveryPath)
	traceln(server.Name(), "POST", url)

	local_req, err = http.NewRequest("POST", url, &b)
	if err != nil {
		traceln("transporter.rv.newrequest.error:", err)
		return nil
	}

	local_req.Close = true
	local_req.Header.Add("Content-Type", "application/protobuf")

	if httpResp, err = t.RoundTripper.RoundTrip(local_req); err != nil || httpResp == nil {
		traceln("transporter.rv.response.error:", err)
		return nil
	}
	defer httpResp.Body.Close()

	resp := &SnapshotRecoveryResponse{}
	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
		traceln("transporter.rv.decoding.error:", err)
		return nil
	}

	return resp
}

//--------------------------------------
// Incoming
//--------------------------------------

// Handles incoming AppendEntries requests.
func (t *HTTPTransporter) appendEntriesHandler(server Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		traceln(server.Name(), "RECV /appendEntries")

		req := &AppendEntriesRequest{}
		if _, err := req.Decode(r.Body); err != nil {
			http.Error(w, "", http.StatusBadRequest)
			return
		}

		entries := req.Entries
		debugln("********************** log start **********************")
		tracef("Term: %d, PrevLogIndex: %d, CommitIndex: %d, LeaderName: %s", req.Term, req.PrevLogIndex, req.CommitIndex, req.LeaderName)
		for index := range entries {
			item := entries[index]
			debugln("Index: ", *(item.Index), "Term: ", *(item.Term), "CommandName: ", *(item.CommandName), "Command: ", string(item.Command))
		}
		debugln("*********************** log end ************************")

		resp := server.AppendEntries(req)
		if resp == nil {
			http.Error(w, "Failed creating response.", http.StatusInternalServerError)
			return
		}
		if _, err := resp.Encode(w); err != nil {
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
}

// Handles incoming RequestVote requests.
func (t *HTTPTransporter) requestVoteHandler(server Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		traceln(server.Name(), "RECV /requestVote")

		req := &RequestVoteRequest{}
		if _, err := req.Decode(r.Body); err != nil {
			http.Error(w, "", http.StatusBadRequest)
			return
		}

		resp := server.RequestVote(req)
		if resp == nil {
			http.Error(w, "Failed creating response.", http.StatusInternalServerError)
			return
		}
		if _, err := resp.Encode(w); err != nil {
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
}

// Handles incoming Snapshot requests.
func (t *HTTPTransporter) snapshotHandler(server Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		traceln(server.Name(), "RECV /snapshot")

		req := &SnapshotRequest{}
		if _, err := req.Decode(r.Body); err != nil {
			http.Error(w, "", http.StatusBadRequest)
			return
		}

		resp := server.RequestSnapshot(req)
		if resp == nil {
			http.Error(w, "Failed creating response.", http.StatusInternalServerError)
			return
		}
		if _, err := resp.Encode(w); err != nil {
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
}

// Handles incoming SnapshotRecovery requests.
func (t *HTTPTransporter) snapshotRecoveryHandler(server Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		traceln(server.Name(), "RECV /snapshotRecovery")

		req := &SnapshotRecoveryRequest{}
		if _, err := req.Decode(r.Body); err != nil {
			http.Error(w, "", http.StatusBadRequest)
			return
		}

		resp := server.SnapshotRecoveryRequest(req)
		if resp == nil {
			http.Error(w, "Failed creating response.", http.StatusInternalServerError)
			return
		}
		if _, err := resp.Encode(w); err != nil {
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
}
<commit_msg>修改KeepAlive的时间为30ms<commit_after>package raft

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"path"
	"time"
)

// Parts from this transporter were heavily influenced by Peter Bougon's
// raft implementation: https://github.com/peterbourgon/raft

//------------------------------------------------------------------------------
//
// Typedefs
//
//------------------------------------------------------------------------------

// An HTTPTransporter is a default transport layer used to communicate between
// multiple servers.
type HTTPTransporter struct {
	DisableKeepAlives    bool
	prefix               string
	appendEntriesPath    string
	requestVotePath      string
	snapshotPath         string
	snapshotRecoveryPath string
	httpClient           http.Client
	Transport            *http.Transport
	RoundTripper         http.RoundTripper
}

type HTTPMuxer interface {
	HandleFunc(string, func(http.ResponseWriter, *http.Request))
}

//------------------------------------------------------------------------------
//
// Constructor
//
//------------------------------------------------------------------------------

// 使用一个指定的路径"/raft"创建一个HTTP transporter
// Creates a new HTTP transporter with the given path prefix.
func NewHTTPTransporter(prefix string, timeout time.Duration) *HTTPTransporter {
	t := &HTTPTransporter{
		DisableKeepAlives:    false,
		prefix:               prefix,
		appendEntriesPath:    joinPath(prefix, "/appendEntries"),
		requestVotePath:      joinPath(prefix, "/requestVote"),
		snapshotPath:         joinPath(prefix, "/snapshot"),
		snapshotRecoveryPath: joinPath(prefix, "/snapshotRecovery"),
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout:   500 * time.Second,
				KeepAlive: 30 * time.Second,
			}).Dial,
		},
	}
	t.httpClient.Transport = t.Transport
	t.Transport.ResponseHeaderTimeout = timeout
	t.RoundTripper = t.Transport
	return t
}

//------------------------------------------------------------------------------
//
// Accessors
//
//------------------------------------------------------------------------------

// Retrieves the path prefix used by the transporter.
func (t *HTTPTransporter) Prefix() string {
	return t.prefix
}

// Retrieves the AppendEntries path.
func (t *HTTPTransporter) AppendEntriesPath() string {
	return t.appendEntriesPath
}

// Retrieves the RequestVote path.
func (t *HTTPTransporter) RequestVotePath() string {
	return t.requestVotePath
}

// Retrieves the Snapshot path.
func (t *HTTPTransporter) SnapshotPath() string {
	return t.snapshotPath
}

// Retrieves the SnapshotRecovery path.
func (t *HTTPTransporter) SnapshotRecoveryPath() string {
	return t.snapshotRecoveryPath
}

//------------------------------------------------------------------------------
//
// Methods
//
//------------------------------------------------------------------------------

//--------------------------------------
// Installation
//--------------------------------------

// 将处理各种请求的URL绑定到路由处理器上
// Applies Raft routes to an HTTP router for a given server.
func (t *HTTPTransporter) Install(server Server, mux HTTPMuxer) {
	mux.HandleFunc(t.AppendEntriesPath(), t.appendEntriesHandler(server))
	mux.HandleFunc(t.RequestVotePath(), t.requestVoteHandler(server))
	mux.HandleFunc(t.SnapshotPath(), t.snapshotHandler(server))
	mux.HandleFunc(t.SnapshotRecoveryPath(), t.snapshotRecoveryHandler(server))
}

//--------------------------------------
// Outgoing
//--------------------------------------

// Sends an AppendEntries RPC to a peer.
func (t *HTTPTransporter) SendAppendEntriesRequest(server Server, peer *Peer, req *AppendEntriesRequest) *AppendEntriesResponse {
	var b bytes.Buffer
	var local_req *http.Request
	var httpResp *http.Response
	var err error

	if _, err := req.Encode(&b); err != nil {
		traceln("transporter.ae.encoding.error:", err)
		return nil
	}

	url := joinPath(peer.ConnectionString, t.AppendEntriesPath())
	traceln(server.Name(), "POST", url)

	local_req, err = http.NewRequest("POST", url, &b)
	if err != nil {
		traceln("transporter.ae.newrequest.error:", err)
		return nil
	}

	local_req.Close = true
	local_req.Header.Add("Content-Type", "application/protobuf")

	if httpResp, err = t.RoundTripper.RoundTrip(local_req); err != nil || httpResp == nil {
		traceln("transporter.ae.response.error:", err)
		return nil
	}
	defer httpResp.Body.Close()

	resp := &AppendEntriesResponse{}
	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
		traceln("transporter.ae.decoding.error:", err)
		return nil
	}

	return resp
}

// Sends a RequestVote RPC to a peer.
func (t *HTTPTransporter) SendVoteRequest(server Server, peer *Peer, req *RequestVoteRequest) *RequestVoteResponse {
	var b bytes.Buffer
	var local_req *http.Request
	var httpResp *http.Response
	var err error

	if _, err := req.Encode(&b); err != nil {
		traceln("transporter.rv.encoding.error:", err)
		return nil
	}

	url := fmt.Sprintf("%s%s", peer.ConnectionString, t.RequestVotePath())
	traceln(server.Name(), "POST", url)

	local_req, err = http.NewRequest("POST", url, &b)
	if err != nil {
		traceln("transporter.rv.newrequest.error:", err)
		return nil
	}

	local_req.Close = true
	local_req.Header.Add("Content-Type", "application/protobuf")

	if httpResp, err = t.RoundTripper.RoundTrip(local_req); err != nil || httpResp == nil {
		traceln("transporter.rv.response.error:", err)
		return nil
	}
	defer httpResp.Body.Close()

	resp := &RequestVoteResponse{}
	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
		traceln("transporter.rv.decoding.error:", err)
		return nil
	}

	return resp
}

func joinPath(connectionString, thePath string) string {
	u, err := url.Parse(connectionString)
	if err != nil {
		panic(err)
	}
	u.Path = path.Join(u.Path, thePath)
	return u.String()
}

// Sends a SnapshotRequest RPC to a peer.
func (t *HTTPTransporter) SendSnapshotRequest(server Server, peer *Peer, req *SnapshotRequest) *SnapshotResponse {
	var b bytes.Buffer
	var local_req *http.Request
	var httpResp *http.Response
	var err error

	if _, err := req.Encode(&b); err != nil {
		traceln("transporter.rv.encoding.error:", err)
		return nil
	}

	url := joinPath(peer.ConnectionString, t.snapshotPath)
	traceln(server.Name(), "POST", url)

	local_req, err = http.NewRequest("POST", url, &b)
	if err != nil {
		traceln("transporter.rv.newrequest.error:", err)
		return nil
	}

	local_req.Close = true
	local_req.Header.Add("Content-Type", "application/protobuf")

	if httpResp, err = t.RoundTripper.RoundTrip(local_req); err != nil || httpResp == nil {
		traceln("transporter.rv.response.error:", err)
		return nil
	}
	defer httpResp.Body.Close()

	resp := &SnapshotResponse{}
	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
		traceln("transporter.rv.decoding.error:", err)
		return nil
	}

	return resp
}

// Sends a SnapshotRequest RPC to a peer.
func (t *HTTPTransporter) SendSnapshotRecoveryRequest(server Server, peer *Peer, req *SnapshotRecoveryRequest) *SnapshotRecoveryResponse {
	var b bytes.Buffer
	var local_req *http.Request
	var httpResp *http.Response
	var err error

	if _, err := req.Encode(&b); err != nil {
		traceln("transporter.rv.encoding.error:", err)
		return nil
	}

	url := joinPath(peer.ConnectionString, t.snapshotRecoveryPath)
	traceln(server.Name(), "POST", url)

	local_req, err = http.NewRequest("POST", url, &b)
	if err != nil {
		traceln("transporter.rv.newrequest.error:", err)
		return nil
	}

	local_req.Close = true
	local_req.Header.Add("Content-Type", "application/protobuf")

	if httpResp, err = t.RoundTripper.RoundTrip(local_req); err != nil || httpResp == nil {
		traceln("transporter.rv.response.error:", err)
		return nil
	}
	defer httpResp.Body.Close()

	resp := &SnapshotRecoveryResponse{}
	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
		traceln("transporter.rv.decoding.error:", err)
		return nil
	}

	return resp
}

//--------------------------------------
// Incoming
//--------------------------------------

// Handles incoming AppendEntries requests.
func (t *HTTPTransporter) appendEntriesHandler(server Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		traceln(server.Name(), "RECV /appendEntries")

		req := &AppendEntriesRequest{}
		if _, err := req.Decode(r.Body); err != nil {
			http.Error(w, "", http.StatusBadRequest)
			return
		}

		entries := req.Entries
		debugln("********************** log start **********************")
		tracef("Term: %d, PrevLogIndex: %d, CommitIndex: %d, LeaderName: %s", req.Term, req.PrevLogIndex, req.CommitIndex, req.LeaderName)
		for index := range entries {
			item := entries[index]
			debugln("Index: ", *(item.Index), "Term: ", *(item.Term), "CommandName: ", *(item.CommandName), "Command: ", string(item.Command))
		}
		debugln("*********************** log end ************************")

		resp := server.AppendEntries(req)
		if resp == nil {
			http.Error(w, "Failed creating response.", http.StatusInternalServerError)
			return
		}
		if _, err := resp.Encode(w); err != nil {
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
}

// Handles incoming RequestVote requests.
func (t *HTTPTransporter) requestVoteHandler(server Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		traceln(server.Name(), "RECV /requestVote")

		req := &RequestVoteRequest{}
		if _, err := req.Decode(r.Body); err != nil {
			http.Error(w, "", http.StatusBadRequest)
			return
		}

		resp := server.RequestVote(req)
		if resp == nil {
			http.Error(w, "Failed creating response.", http.StatusInternalServerError)
			return
		}
		if _, err := resp.Encode(w); err != nil {
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
}

// Handles incoming Snapshot requests.
func (t *HTTPTransporter) snapshotHandler(server Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		traceln(server.Name(), "RECV /snapshot")

		req := &SnapshotRequest{}
		if _, err := req.Decode(r.Body); err != nil {
			http.Error(w, "", http.StatusBadRequest)
			return
		}

		resp := server.RequestSnapshot(req)
		if resp == nil {
			http.Error(w, "Failed creating response.", http.StatusInternalServerError)
			return
		}
		if _, err := resp.Encode(w); err != nil {
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
}

// Handles incoming SnapshotRecovery requests.
func (t *HTTPTransporter) snapshotRecoveryHandler(server Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		traceln(server.Name(), "RECV /snapshotRecovery")

		req := &SnapshotRecoveryRequest{}
		if _, err := req.Decode(r.Body); err != nil {
			http.Error(w, "", http.StatusBadRequest)
			return
		}

		resp := server.SnapshotRecoveryRequest(req)
		if resp == nil {
			http.Error(w, "Failed creating response.", http.StatusInternalServerError)
			return
		}
		if _, err := resp.Encode(w); err != nil {
			http.Error(w, "", http.StatusInternalServerError)
			return
		}
	}
}
<|endoftext|>


<commit_before>package httpexport

import (
	"bufio"
	"fmt"
	"github.com/arnehormann/mirror"
	"net/http"
	"reflect"
	"strings"
)

func NewTypeServer(addr string) chan<- interface{} {
	typechan := make(chan interface{})
	go func(addr string, inchan <-chan interface{}) {
		server := typeServer{feed: inchan, write: htmlTypeWriter}
		err := http.ListenAndServe(addr, server)
		if err != nil {
			panic(err)
		}
	}(addr, typechan)
	return typechan
}

type typeWriter func(s *typeSession, t *reflect.Type) error

type typeServer struct {
	feed  <-chan interface{}
	write typeWriter
}

type typeSession struct {
	depth int
	buf   *bufio.Writer
	err   error
}

func (server typeServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	session := &typeSession{
		depth: 0,
		buf:   bufio.NewWriter(resp),
	}
	var t *reflect.Type
	if req.Method == "POST" {
		readType := reflect.TypeOf(<-server.feed)
		t = &readType
	}
	err := server.write(session, t)
	if err != nil {
		panic(err)
	}
	session.buf.Flush()
}

func (session *typeSession) Concat(text string) {
	if session.err != nil {
		return
	}
	_, err := session.buf.WriteString(text)
	session.err = err
}

func (session *typeSession) Concatf(format string, args ...interface{}) {
	if session.err != nil {
		return
	}
	_, err := session.buf.WriteString(fmt.Sprintf(format, args...))
	session.err = err
}

// code for html type export

func htmlTypeWriter(session *typeSession, t *reflect.Type) error {
	const submit = `<form method="post"><button type="submit">Next</button></form>`
	if t == nil {
		// serve form on GET requests so favicon.ico and co don't skip object under inspection
		session.Concat(`<!DOCTYPE html><html><body>` + submit + `</body></html>`)
		return session.err
	}
	// write leading...
	session.Concatf(`
<!DOCTYPE html>
<title>Go: '%s'</title>%s`, *t, submit)
	typeToHtml := func(t *reflect.StructField, typeIndex, depth int) error {
		// for now, we are error-ignorant
		// close open tags
		if session.depth > depth {
			session.Concat(strings.Repeat("
", session.depth-depth))
		}
		// close this tag later
		session.depth = depth + 1
		// if no type is given, return
		if t == nil {
			return nil
		}
		tt := t.Type
		session.Concatf(
			`<div data-kind="%s" data-type="%s" data-size="%d" data-typeid="%d"`,
			tt.Kind(), tt, tt.Size(), typeIndex)
		if len(t.Index) > 0 {
			session.Concatf(
				` data-field="%s" data-index="%v" data-offset="%d" data-tag="%s"`,
				t.Name, t.Index, t.Offset, t.Tag)
		}
		switch tt.Kind() {
		case reflect.Chan:
			var direction string
			switch tt.ChanDir() {
			case reflect.RecvDir:
				direction = "receive"
			case reflect.SendDir:
				direction = "send"
			case reflect.BothDir:
				direction = "both"
			}
			session.Concat(` data-direction="` + direction + `"`)
		case reflect.Map:
			session.Concatf(` data-keytype="%s"`, tt.Key())
		case reflect.Array:
			session.Concatf(` data-length="%d"`, tt.Len())
		case reflect.Func:
			session.Concatf(` data-args-in="%d" data-args-out="%d"`, tt.NumIn(), tt.NumOut())
		}
		session.Concat(`>`)
		return session.err
	}
	// ignore errors for the calls; we can't reasonably handle them unless we add a buffer
	session.err = mirror.Walk(*t, typeToHtml)
	if session.err != nil {
		return session.err
	}
	// close all tags
	session.err = typeToHtml(nil, 0, 0)
	// write closing code...
	session.Concat(`</body></html>`)
	return session.err
}
<commit_msg>have to quote unsafe.Pointer in css<commit_after>package httpexport

import (
	"bufio"
	"fmt"
	"github.com/arnehormann/mirror"
	"net/http"
	"reflect"
	"strings"
)

func NewTypeServer(addr string) chan<- interface{} {
	typechan := make(chan interface{})
	go func(addr string, inchan <-chan interface{}) {
		server := typeServer{feed: inchan, write: htmlTypeWriter}
		err := http.ListenAndServe(addr, server)
		if err != nil {
			panic(err)
		}
	}(addr, typechan)
	return typechan
}

type typeWriter func(s *typeSession, t *reflect.Type) error

type typeServer struct {
	feed  <-chan interface{}
	write typeWriter
}

type typeSession struct {
	depth int
	buf   *bufio.Writer
	err   error
}

func (server typeServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	session := &typeSession{
		depth: 0,
		buf:   bufio.NewWriter(resp),
	}
	var t *reflect.Type
	if req.Method == "POST" {
		readType := reflect.TypeOf(<-server.feed)
		t = &readType
	}
	err := server.write(session, t)
	if err != nil {
		panic(err)
	}
	session.buf.Flush()
}

func (session *typeSession) Concat(text string) {
	if session.err != nil {
		return
	}
	_, err := session.buf.WriteString(text)
	session.err = err
}

func (session *typeSession) Concatf(format string, args ...interface{}) {
	if session.err != nil {
		return
	}
	_, err := session.buf.WriteString(fmt.Sprintf(format, args...))
	session.err = err
}

// code for html type export

func htmlTypeWriter(session *typeSession, t *reflect.Type) error {
	const submit = `<form method="post"><button type="submit">Next</button></form>`
	if t == nil {
		// serve form on GET requests so favicon.ico and co don't skip object under inspection
		session.Concat(`<!DOCTYPE html><html><body>` + submit + `</body></html>`)
		return session.err
	}
	// write leading...
	session.Concatf(`
<!DOCTYPE html>
<title>Go: '%s'</title>%s`, *t, submit)
	typeToHtml := func(t *reflect.StructField, typeIndex, depth int) error {
		// for now, we are error-ignorant
		// close open tags
		if session.depth > depth {
			session.Concat(strings.Repeat("
", session.depth-depth))
		}
		// close this tag later
		session.depth = depth + 1
		// if no type is given, return
		if t == nil {
			return nil
		}
		tt := t.Type
		session.Concatf(
			`<div data-kind="%s" data-type="%s" data-size="%d" data-typeid="%d"`,
			tt.Kind(), tt, tt.Size(), typeIndex)
		if len(t.Index) > 0 {
			session.Concatf(
				` data-field="%s" data-index="%v" data-offset="%d" data-tag="%s"`,
				t.Name, t.Index, t.Offset, t.Tag)
		}
		switch tt.Kind() {
		case reflect.Chan:
			var direction string
			switch tt.ChanDir() {
			case reflect.RecvDir:
				direction = "receive"
			case reflect.SendDir:
				direction = "send"
			case reflect.BothDir:
				direction = "both"
			}
			session.Concat(` data-direction="` + direction + `"`)
		case reflect.Map:
			session.Concatf(` data-keytype="%s"`, tt.Key())
		case reflect.Array:
			session.Concatf(` data-length="%d"`, tt.Len())
		case reflect.Func:
			session.Concatf(` data-args-in="%d" data-args-out="%d"`, tt.NumIn(), tt.NumOut())
		}
		session.Concat(`>`)
		return session.err
	}
	// ignore errors for the calls; we can't reasonably handle them unless we add a buffer
	session.err = mirror.Walk(*t, typeToHtml)
	if session.err != nil {
		return session.err
	}
	// close all tags
	session.err = typeToHtml(nil, 0, 0)
	// write closing code...
	session.Concat(`</body></html>`)
	return session.err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

func main(){

	elevation := 4000
	destinationNorth := 1000
	destinationWest := 1000

	windNorth := -4
	windWest := -4

	deployChuteAtElevation := 1000

	ladingLocation := simDrop(elevation,
							destinationNorth,
							destinationWest,
							windNorth,
							windWest,
							deployChuteAtElevation)

	fmt.Println("Initiate deploy at:",
				deployChuteAtElevation,
				"meters -", ladingLocation)
}

func simDrop(elevation int,
			dest_north int,
			dest_west int,
			windNorth int,
			windWest int,
			deployChuteAtElevation int) string {

	locationNorth := 0
	locationWest := 0
	locationNorth -=-1
	fmt.Println(locationNorth,locationWest)
	deployed := false
	for elevation > 0 {
		if elevation == deployChuteAtElevation {
			deployed = true
		}
		if !deployed {
			locationNorth -= windNorth / 4
			locationWest -= windWest / 4
		} else {
			//fmt.Println("Before wind: North, West -",locationNorth, locationWest)
			locationNorth -= windNorth
			locationWest -= windWest
			//fmt.Println("After wind: North, West -",locationNorth, locationWest)
		}
		elevation -= 10
	}
	fmt.Println("North:", locationNorth,
				"West:", locationWest)
	ladingLocation := "You missed the target!"
	if locationNorth == dest_north && locationWest == dest_west {
		ladingLocation = "You hit the target!"
	}

	return ladingLocation
}<commit_msg>Explanation added<commit_after>package main

import (
	"fmt"
)

func main(){

	elevation := 4000
	destinationNorth := 1000
	destinationWest := 1000

	windNorth := -4
	windWest := -4

	deployChuteAtElevation := 2000

	ladingLocation := simDrop(elevation,
							destinationNorth,
							destinationWest,
							windNorth,
							windWest,
							deployChuteAtElevation)

	fmt.Println("Initiate deploy at:",
				deployChuteAtElevation,
				"meters -", ladingLocation)
}

func simDrop(elevation int,
			dest_north int,
			dest_west int,
			windNorth int,
			windWest int,
			deployChuteAtElevation int) string {

	locationNorth := 0
	locationWest := 0
	deployed := false
/*
So we had 400 tacts. In one tact we have +1 or +4 on variable locationNorth and locationWest. 1*x+4*y = 1000 and x+y=400
x = 200 y = 200
After 200 tacts we should deployed. Thats all - deployChuteAtElevation := 200
*/
	for elevation > 0 {
		if elevation == deployChuteAtElevation {
			deployed = true
		}
		if !deployed {
//Because we have a negative number in windNorth (-4) and apply decrement operation(-=) in result we had a positive number in locationNorth
			locationNorth -= windNorth / 4
			locationWest -= windWest / 4
		} else {
			locationNorth -= windNorth
			locationWest -= windWest
		}
		elevation -= 10
	}
	fmt.Println("North:", locationNorth,
				"West:", locationWest)
	ladingLocation := "You missed the target!"
	if locationNorth == dest_north && locationWest == dest_west {
		ladingLocation = "You hit the target!"
	}

	return ladingLocation
}

//Result deployChuteAtElevation := 2000<|endoftext|>


<commit_before>package mailserver

import (
	"airdispat.ch/identity"
	"airdispat.ch/message"
	"airdispat.ch/routing"
	"airdispat.ch/server"
	"airdispat.ch/wire"
	"errors"
	"github.com/airdispatch/dpl"
	"github.com/robfig/revel"
	"melange/app/models"
	"net"
	"os"
	"strings"
)

var ServerLocation string

func getServerLocation() string {
	s, _ := os.Hostname()
	ips, _ := net.LookupHost(s)
	return ips[0] + ":2048"
}

func Init() {
	def := getServerLocation()
	ServerLocation = revel.Config.StringDefault("server.location", def)
}

func Messages(r routing.Router,
	db models.Selectable,
	from *identity.Identity,
	fromUser *models.User,
	public bool, private bool, self bool, since int64) ([]dpl.Message, error) {

	var out []dpl.Message
	var err error

	if public {
		var s []*models.UserSubscription
		_, err := db.Select(&s, "select * from dispatch_subscription where userid = $1", fromUser.UserId)
		if err != nil {
			return nil, err
		}

		for _, v := range s {
			msg, err := DownloadPublicMail(r, uint64(since), from, v.Address) // from, to)
			if err != nil {
				return nil, err
			}
			for _, txn := range msg.Content {
				rmsg, err := DownloadMessage(r, txn.Name, nil, v.Address, txn.Location)
				if err != nil {
					return nil, err
				}
				out = append(out, &PluginMail{rmsg})
			}
		}
	}

	if private {
		var ale []*models.Alert
		_, err = db.Select(&ale, "select * from dispatch_alerts where \"to\" = $1 and timestamp > $2", from.Address.String(), since)
		if err != nil {
			return nil, err
		}
		for _, v := range ale {
			msg, err := v.DownloadMessageFromAlert(db, r)
			if err != nil {
				return nil, err
			}
			out = append(out, &PluginMail{msg})
		}
	}

	if self {
		var msg []*models.Message
		_, err = db.Select(&msg, "select * from dispatch_messages where \"from\" = $1 and timestamp > $2", from.Address.String(), since)
		if err != nil {
			return nil, err
		}
		for _, v := range msg {
			dmsg, err := v.ToDispatch(db, strings.Split(v.To, ",")[0])
			if err != nil {
				return nil, err
			}
			out = append(out, &PluginMail{dmsg})
		}
	}

	return out, nil
}

func SendAlert(r routing.Router, msgName string, from *identity.Identity, to string) error {
	addr, err := r.LookupAlias(to)
	if err != nil {
		return err
	}

	msgDescription := server.CreateMessageDescription(msgName, ServerLocation, from.Address, addr)
	err = message.SignAndSend(msgDescription, from, addr)
	if err != nil {
		return err
	}
	return nil
}

func DownloadMessage(r routing.Router, msgName string, from *identity.Identity, to string, toServer string) (*message.Mail, error) {
	addr, err := r.LookupAlias(to)
	if err != nil {
		return nil, err
	}
	addr.Location = toServer

	txMsg := server.CreateTransferMessage(msgName, from.Address, addr)
	bytes, typ, h, err := message.SendMessageAndReceive(txMsg, from, addr)
	if err != nil {
		return nil, err
	}

	if typ != wire.MailCode {
		return nil, errors.New("Wrong message type.")
	}

	return message.CreateMailFromBytes(bytes, h)
}

func DownloadMessageList(r routing.Router, m *server.MessageList, from *identity.Identity, to string) ([]*message.Mail, error) {
	output := make([]*message.Mail, len(m.Content))
	for i, v := range m.Content {
		var err error
		output[i], err = DownloadMessage(r, v.Name, from, to, v.Location)
		if err != nil {
			return nil, err
		}
	}
	return output, nil
}

func DownloadPublicMail(r routing.Router, since uint64, from *identity.Identity, to string) (*server.MessageList, error) {
	addr, err := r.LookupAlias(to)
	if err != nil {
		return nil, err
	}

	txMsg := server.CreateTransferMessageList(since, from.Address, addr)
	bytes, typ, h, err := message.SendMessageAndReceive(txMsg, from, addr)
	if err != nil {
		return nil, err
	}

	if typ != wire.MessageListCode {
		return nil, errors.New("Wrong message type.")
	}

	if bytes == nil {
		// No messages available.
		return &server.MessageList{make([]*server.MessageDescription, 0)}, nil
	}
	return server.CreateMessageListFromBytes(bytes, h)
}
<commit_msg>Fixed Last Commit<commit_after>package mailserver

import (
	"airdispat.ch/identity"
	"airdispat.ch/message"
	"airdispat.ch/routing"
	"airdispat.ch/server"
	"airdispat.ch/wire"
	"errors"
	"github.com/airdispatch/dpl"
	"github.com/robfig/revel"
	"melange/app/models"
	"net"
	"os"
	"strings"
)

var ServerLocation string

func getServerLocation() string {
	s, _ := os.Hostname()
	ips, _ := net.LookupHost(s)
	return ips[0] + ":2048"
}

func Init() {
	def := getServerLocation()
	ServerLocation = revel.Config.StringDefault("server.location", def)
}

func Messages(r routing.Router,
	db models.Selectable,
	from *identity.Identity,
	fromUser *models.User,
	public bool, private bool, self bool, since int64) ([]dpl.Message, error) {

	var out []dpl.Message
	var err error

	if public {
		var s []*models.UserSubscription
		_, err := db.Select(&s, "select * from dispatch_subscription where userid = $1", fromUser.UserId)
		if err != nil {
			return nil, err
		}

		for _, v := range s {
			msg, err := DownloadPublicMail(r, uint64(since), from, v.Address) // from, to)
			if err != nil {
				return nil, err
			}
			for _, txn := range msg.Content {
				rmsg, err := DownloadMessage(r, txn.Name, nil, v.Address, txn.Location)
				if err != nil {
					return nil, err
				}
				out = append(out, &PluginMail{rmsg})
			}
		}
	}

	if private {
		var ale []*models.Alert
		_, err = db.Select(&ale, "select * from dispatch_alerts where \"to\" = $1 and timestamp > $2", from.Address.String(), since)
		if err != nil {
			return nil, err
		}
		for _, v := range ale {
			msg, err := v.DownloadMessageFromAlert(db, r)
			if err != nil {
				return nil, err
			}
			out = append(out, &PluginMail{msg})
		}
	}

	if self {
		var msg []*models.Message
		_, err = db.Select(&msg, "select * from dispatch_messages where \"from\" = $1 and timestamp > $2", from.Address.String(), since)
		if err != nil {
			return nil, err
		}
		for _, v := range msg {
			dmsg, err := v.ToDispatch(db, strings.Split(v.To, ",")[0])
			if err != nil {
				return nil, err
			}
			out = append(out, &PluginMail{dmsg})
		}
	}

	return out, nil
}

func SendAlert(r routing.Router, msgName string, from *identity.Identity, to string) error {
	addr, err := r.LookupAlias(to)
	if err != nil {
		return err
	}

	msgDescription := server.CreateMessageDescription(msgName, ServerLocation, from.Address, addr)
	err = message.SignAndSend(msgDescription, from, addr)
	if err != nil {
		return err
	}
	return nil
}

func DownloadMessage(r routing.Router, msgName string, from *identity.Identity, to string, toServer string) (*message.Mail, error) {
	addr, err := r.LookupAlias(to)
	if err != nil {
		return nil, err
	}
	addr.Location = toServer

	txMsg := server.CreateTransferMessage(msgName, from.Address, addr)
	bytes, typ, h, err := message.SendMessageAndReceive(txMsg, from, addr)
	if err != nil {
		return nil, err
	}

	if typ != wire.MailCode {
		return nil, errors.New("Wrong message type.")
	}

	return message.CreateMailFromBytes(bytes, h)
}

func DownloadMessageList(r routing.Router, m *server.MessageList, from *identity.Identity, to string) ([]*message.Mail, error) {
	output := make([]*message.Mail, len(m.Content))
	for i, v := range m.Content {
		var err error
		output[i], err = DownloadMessage(r, v.Name, from, to, v.Location)
		if err != nil {
			return nil, err
		}
	}
	return output, nil
}

func DownloadPublicMail(r routing.Router, since uint64, from *identity.Identity, to string) (*server.MessageList, error) {
	addr, err := r.LookupAlias(to)
	if err != nil {
		return nil, err
	}

	txMsg := server.CreateTransferMessageList(since, from.Address, addr)
	bytes, typ, h, err := message.SendMessageAndReceive(txMsg, from, addr)
	if err != nil {
		return nil, err
	}

	if typ != wire.MessageListCode {
		return nil, errors.New("Wrong message type.")
	}

	if bytes == nil {
		// No messages available.
		return &server.MessageList{
			Content: make([]*server.MessageDescription, 0),
		}, nil
	}
	return server.CreateMessageListFromBytes(bytes, h)
}
<|endoftext|>


<commit_before>package mdata

import (
	"gopkg.in/raintank/schema.v1"
)

/*
 * The reorder buffer keeps a window of data during which it is ok to send data out of order.
 * Once the reorder window has passed Add() will return the old data and delete it from the buffer.
 * The reorder buffer itself is not thread safe because it is only used by AggMetric,
 * which is thread safe, so there is no locking in the buffer.
 */
type ReorderBuffer struct {
	len      uint32         // length of buffer in number of datapoints
	newest   uint32         // index of newest buffer entry
	interval uint32         // metric interval
	buf      []schema.Point // the actual buffer holding the data
}

func NewReorderBuffer(reorderWindow uint32, interval int) *ReorderBuffer {
	buf := &ReorderBuffer{
		len:      reorderWindow,
		interval: uint32(interval),
		buf:      make([]schema.Point, reorderWindow),
	}
	return buf
}

func (rob *ReorderBuffer) Add(ts uint32, val float64) []schema.Point {
	ts = aggBoundary(ts, rob.interval)

	// out of order and too old
	if rob.buf[rob.newest].Ts != 0 && ts <= rob.buf[rob.newest].Ts-(rob.len*rob.interval) {
		metricsTooOld.Inc()
		return nil
	}

	var res []schema.Point
	oldest := (rob.newest + 1) % rob.len
	index := (ts / rob.interval) % rob.len
	if ts > rob.buf[rob.newest].Ts {
		flushCount := (ts - rob.buf[rob.newest].Ts) / rob.interval
		if flushCount > rob.len {
			flushCount = rob.len
		}

		for i := uint32(0); i < flushCount; i++ {
			if rob.buf[oldest].Ts != 0 {
				res = append(res, rob.buf[oldest])
			}
			rob.buf[oldest].Ts = 0
			rob.buf[oldest].Val = 0
			oldest = (oldest + 1) % rob.len
		}
		rob.buf[index].Ts = ts
		rob.buf[index].Val = val
		rob.newest = index
	} else {
		rob.buf[index].Ts = ts
		rob.buf[index].Val = val
	}

	return res
}

// returns all the data in the buffer as a raw list of points
func (rob *ReorderBuffer) Get() []schema.Point {
	res := make([]schema.Point, 0, rob.len)
	oldest := (rob.newest + 1) % rob.len

	for {
		if rob.buf[oldest].Ts != 0 {
			res = append(res, rob.buf[oldest])
		}
		if oldest == rob.newest {
			break
		}
		oldest = (oldest + 1) % rob.len
	}

	return res
}
<commit_msg>fix comment<commit_after>package mdata

import (
	"gopkg.in/raintank/schema.v1"
)

// ReorderBuffer keeps a window of data during which it is ok to send data out of order.
// Once the reorder window has passed Add() will return the old data and delete it from the buffer.
// The reorder buffer itself is not thread safe because it is only used by AggMetric,
// which is thread safe, so there is no locking in the buffer.
type ReorderBuffer struct {
	len      uint32         // length of buffer in number of datapoints
	newest   uint32         // index of newest buffer entry
	interval uint32         // metric interval
	buf      []schema.Point // the actual buffer holding the data
}

func NewReorderBuffer(reorderWindow uint32, interval int) *ReorderBuffer {
	buf := &ReorderBuffer{
		len:      reorderWindow,
		interval: uint32(interval),
		buf:      make([]schema.Point, reorderWindow),
	}
	return buf
}

func (rob *ReorderBuffer) Add(ts uint32, val float64) []schema.Point {
	ts = aggBoundary(ts, rob.interval)

	// out of order and too old
	if rob.buf[rob.newest].Ts != 0 && ts <= rob.buf[rob.newest].Ts-(rob.len*rob.interval) {
		metricsTooOld.Inc()
		return nil
	}

	var res []schema.Point
	oldest := (rob.newest + 1) % rob.len
	index := (ts / rob.interval) % rob.len
	if ts > rob.buf[rob.newest].Ts {
		flushCount := (ts - rob.buf[rob.newest].Ts) / rob.interval
		if flushCount > rob.len {
			flushCount = rob.len
		}

		for i := uint32(0); i < flushCount; i++ {
			if rob.buf[oldest].Ts != 0 {
				res = append(res, rob.buf[oldest])
			}
			rob.buf[oldest].Ts = 0
			rob.buf[oldest].Val = 0
			oldest = (oldest + 1) % rob.len
		}
		rob.buf[index].Ts = ts
		rob.buf[index].Val = val
		rob.newest = index
	} else {
		rob.buf[index].Ts = ts
		rob.buf[index].Val = val
	}

	return res
}

// returns all the data in the buffer as a raw list of points
func (rob *ReorderBuffer) Get() []schema.Point {
	res := make([]schema.Point, 0, rob.len)
	oldest := (rob.newest + 1) % rob.len

	for {
		if rob.buf[oldest].Ts != 0 {
			res = append(res, rob.buf[oldest])
		}
		if oldest == rob.newest {
			break
		}
		oldest = (oldest + 1) % rob.len
	}

	return res
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
// Copyright (c) 2017 Hiraaki Nakamura
//
// 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 ltsv

import (
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/uber-go/zap"
)

const (
	// For JSON-escaping; see jsonEncoder.safeAddString below.
	_hex = "0123456789abcdef"
	// Initial buffer size for encoders.
	_initialBufSize = 1024
)

var (
	// errNilSink signals that Encoder.WriteEntry was called with a nil WriteSyncer.
	errNilSink = errors.New("can't write encoded message a nil WriteSyncer")
)

type Replacer interface {
	Replace(s string) string
}

var ltsvPool = sync.Pool{New: func() interface{} {
	return &ltsvEncoder{
		bytes:        make([]byte, 0, _initialBufSize),
		timeLabel:    "time",
		levelLabel:   "level",
		messageLabel: "msg",
		replacer: strings.NewReplacer(
			"\t", "\\t",
			"\n", "\\n",
			"\r", "\\r",
		),
	}
}}

type ltsvEncoder struct {
	bytes        []byte
	timeLabel    string
	timeFmt      string
	levelLabel   string
	messageLabel string
	nestedLevel  int
	replacer     Replacer
}

// NewLTSVEncoder creates a line-oriented LTSV encoder.
// See http://ltsv.org/ for LTSV (Labeled Tab-separated Values).
// By default, the encoder uses RFC3339-formatted timestamps.
func NewLTSVEncoder(options ...LTSVOption) zap.Encoder {
	enc := ltsvPool.Get().(*ltsvEncoder)
	enc.truncate()
	enc.timeFmt = time.RFC3339
	for _, opt := range options {
		opt.apply(enc)
	}
	return enc
}

func (enc *ltsvEncoder) Free() {
	ltsvPool.Put(enc)
}

func (enc *ltsvEncoder) AddString(key, val string) {
	enc.addKey(key)
	if enc.nestedLevel > 0 {
		enc.bytes = append(enc.bytes, '"')
		enc.safeAddJSONString(val)
		enc.bytes = append(enc.bytes, '"')
	} else {
		enc.safeAddString(val)
	}
}

func (enc *ltsvEncoder) AddBool(key string, val bool) {
	enc.addKey(key)
	enc.bytes = strconv.AppendBool(enc.bytes, val)
}

func (enc *ltsvEncoder) AddInt(key string, val int) {
	enc.AddInt64(key, int64(val))
}

func (enc *ltsvEncoder) AddInt64(key string, val int64) {
	enc.addKey(key)
	enc.bytes = strconv.AppendInt(enc.bytes, val, 10)
}

func (enc *ltsvEncoder) AddUint(key string, val uint) {
	enc.AddUint64(key, uint64(val))
}

func (enc *ltsvEncoder) AddUint64(key string, val uint64) {
	enc.addKey(key)
	enc.bytes = strconv.AppendUint(enc.bytes, val, 10)
}

func (enc *ltsvEncoder) AddUintptr(key string, val uintptr) {
	enc.addKey(key)
	enc.bytes = append(enc.bytes, "0x"...)
	enc.bytes = strconv.AppendUint(enc.bytes, uint64(val), 16)
}

func (enc *ltsvEncoder) AddFloat64(key string, val float64) {
	enc.addKey(key)
	enc.bytes = strconv.AppendFloat(enc.bytes, val, 'f', -1, 64)
}

func (enc *ltsvEncoder) AddMarshaler(key string, obj zap.LogMarshaler) error {
	enc.addKey(key)
	enc.nestedLevel++
	enc.bytes = append(enc.bytes, '{')
	err := obj.MarshalLog(enc)
	enc.bytes = append(enc.bytes, '}')
	enc.nestedLevel--
	return err
}

func (enc *ltsvEncoder) AddObject(key string, obj interface{}) error {
	enc.AddString(key, fmt.Sprintf("%+v", obj))
	return nil
}

func (enc *ltsvEncoder) Clone() zap.Encoder {
	clone := ltsvPool.Get().(*ltsvEncoder)
	clone.truncate()
	clone.bytes = append(clone.bytes, enc.bytes...)
	clone.timeLabel = enc.timeLabel
	clone.timeFmt = enc.timeFmt
	clone.levelLabel = enc.levelLabel
	clone.messageLabel = enc.messageLabel
	clone.nestedLevel = enc.nestedLevel
	clone.replacer = enc.replacer
	return clone
}

func (enc *ltsvEncoder) WriteEntry(sink io.Writer, msg string, lvl zap.Level, t time.Time) error {
	if sink == nil {
		return errNilSink
	}

	final := ltsvPool.Get().(*ltsvEncoder)
	final.truncate()
	enc.addTime(final, t)
	enc.addLevel(final, lvl)
	enc.addMessage(final, msg)

	if len(enc.bytes) > 0 {
		final.bytes = append(final.bytes, '\t')
		final.bytes = append(final.bytes, enc.bytes...)
	}
	final.bytes = append(final.bytes, '\n')

	expectedBytes := len(final.bytes)
	n, err := sink.Write(final.bytes)
	final.Free()
	if err != nil {
		return err
	}
	if n != expectedBytes {
		return fmt.Errorf("incomplete write: only wrote %v of %v bytes", n, expectedBytes)
	}
	return nil
}

func (enc *ltsvEncoder) truncate() {
	enc.bytes = enc.bytes[:0]
}

func (enc *ltsvEncoder) addKey(key string) {
	if enc.nestedLevel > 0 {
		last := len(enc.bytes) - 1
		// At some point, we'll also want to support arrays.
		if last >= 0 && enc.bytes[last] != '{' {
			enc.bytes = append(enc.bytes, ',')
		}
		enc.bytes = append(enc.bytes, '"')
		enc.safeAddJSONString(key)
		enc.bytes = append(enc.bytes, '"', ':')
	} else {
		if len(enc.bytes) > 0 {
			enc.bytes = append(enc.bytes, '\t')
		}
		enc.safeAddString(key)
		enc.bytes = append(enc.bytes, ':')
	}
}

func (enc *ltsvEncoder) addLevel(final *ltsvEncoder, lvl zap.Level) {
	final.addKey(enc.levelLabel)
	switch lvl {
	case zap.DebugLevel:
		final.bytes = append(final.bytes, 'D')
	case zap.InfoLevel:
		final.bytes = append(final.bytes, 'I')
	case zap.WarnLevel:
		final.bytes = append(final.bytes, 'W')
	case zap.ErrorLevel:
		final.bytes = append(final.bytes, 'E')
	case zap.PanicLevel:
		final.bytes = append(final.bytes, 'P')
	case zap.FatalLevel:
		final.bytes = append(final.bytes, 'F')
	default:
		final.bytes = strconv.AppendInt(final.bytes, int64(lvl), 10)
	}
}

func (enc *ltsvEncoder) addTime(final *ltsvEncoder, t time.Time) {
	if enc.timeFmt == "" {
		return
	}
	final.addKey(enc.timeLabel)
	final.bytes = t.AppendFormat(final.bytes, enc.timeFmt)
}

func (enc *ltsvEncoder) addMessage(final *ltsvEncoder, msg string) {
	final.addKey(enc.messageLabel)
	final.safeAddString(msg)
}

func (enc *ltsvEncoder) safeAddString(s string) {
	enc.bytes = append(enc.bytes, enc.replacer.Replace(s)...)
}

// safeAddString JSON-escapes a string and appends it to the internal buffer.
// Unlike the standard library's escaping function, it doesn't attempt to
// protect the user from browser vulnerabilities or JSONP-related problems.
func (enc *ltsvEncoder) safeAddJSONString(s string) {
	for i := 0; i < len(s); {
		if b := s[i]; b < utf8.RuneSelf {
			i++
			if 0x20 <= b && b != '\\' && b != '"' {
				enc.bytes = append(enc.bytes, b)
				continue
			}
			switch b {
			case '\\', '"':
				enc.bytes = append(enc.bytes, '\\', b)
			case '\n':
				enc.bytes = append(enc.bytes, '\\', 'n')
			case '\r':
				enc.bytes = append(enc.bytes, '\\', 'r')
			case '\t':
				enc.bytes = append(enc.bytes, '\\', 't')
			default:
				// Encode bytes < 0x20, except for the escape sequences above.
				enc.bytes = append(enc.bytes, `\u00`...)
				enc.bytes = append(enc.bytes, _hex[b>>4], _hex[b&0xF])
			}
			continue
		}
		c, size := utf8.DecodeRuneInString(s[i:])
		if c == utf8.RuneError && size == 1 {
			enc.bytes = append(enc.bytes, `\ufffd`...)
			i++
			continue
		}
		enc.bytes = append(enc.bytes, s[i:i+size]...)
		i += size
	}
}

// A LTSVOption is used to set options for a LTSV encoder.
type LTSVOption interface {
	apply(*ltsvEncoder)
}

type ltsvOptionFunc func(*ltsvEncoder)

func (opt ltsvOptionFunc) apply(enc *ltsvEncoder) {
	opt(enc)
}

// LTSVTimeFormat sets the format for log timestamps, using the same layout
// strings supported by time.Parse.
func LTSVTimeFormat(layout string) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.timeFmt = layout
	})
}

// LTSVNoTime omits timestamps from the serialized log entries.
func LTSVNoTime() LTSVOption {
	return LTSVTimeFormat("")
}

// LTSVTimeLabel sets the label for log timestamps.
func LTSVTimeLabel(label string) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.timeLabel = label
	})
}

// LTSVLevelLabel sets the label for log levels.
func LTSVLevelLabel(label string) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.levelLabel = label
	})
}

// LTSVNoLevel omit levels from the serialized log entries.
func LTSVNoLevel() LTSVOption {
	return LTSVLevelLabel("")
}

// LTSVMessageLabel sets the label for log messages.
func LTSVMessageLabel(label string) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.messageLabel = label
	})
}
<commit_msg>Add LTSVReplacer option<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
// Copyright (c) 2017 Hiraaki Nakamura
//
// 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 ltsv

import (
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/uber-go/zap"
)

const (
	// For JSON-escaping; see jsonEncoder.safeAddString below.
	_hex = "0123456789abcdef"
	// Initial buffer size for encoders.
	_initialBufSize = 1024
)

var (
	// errNilSink signals that Encoder.WriteEntry was called with a nil WriteSyncer.
	errNilSink = errors.New("can't write encoded message a nil WriteSyncer")
)

type Replacer interface {
	Replace(s string) string
}

var ltsvPool = sync.Pool{New: func() interface{} {
	return &ltsvEncoder{
		bytes:        make([]byte, 0, _initialBufSize),
		timeLabel:    "time",
		levelLabel:   "level",
		messageLabel: "msg",
		replacer: strings.NewReplacer(
			"\t", "\\t",
			"\n", "\\n",
			"\r", "\\r",
		),
	}
}}

type ltsvEncoder struct {
	bytes        []byte
	timeLabel    string
	timeFmt      string
	levelLabel   string
	messageLabel string
	nestedLevel  int
	replacer     Replacer
}

// NewLTSVEncoder creates a line-oriented LTSV encoder.
// See http://ltsv.org/ for LTSV (Labeled Tab-separated Values).
// By default, the encoder uses RFC3339-formatted timestamps.
func NewLTSVEncoder(options ...LTSVOption) zap.Encoder {
	enc := ltsvPool.Get().(*ltsvEncoder)
	enc.truncate()
	enc.timeFmt = time.RFC3339
	for _, opt := range options {
		opt.apply(enc)
	}
	return enc
}

func (enc *ltsvEncoder) Free() {
	ltsvPool.Put(enc)
}

func (enc *ltsvEncoder) AddString(key, val string) {
	enc.addKey(key)
	if enc.nestedLevel > 0 {
		enc.bytes = append(enc.bytes, '"')
		enc.safeAddJSONString(val)
		enc.bytes = append(enc.bytes, '"')
	} else {
		enc.safeAddString(val)
	}
}

func (enc *ltsvEncoder) AddBool(key string, val bool) {
	enc.addKey(key)
	enc.bytes = strconv.AppendBool(enc.bytes, val)
}

func (enc *ltsvEncoder) AddInt(key string, val int) {
	enc.AddInt64(key, int64(val))
}

func (enc *ltsvEncoder) AddInt64(key string, val int64) {
	enc.addKey(key)
	enc.bytes = strconv.AppendInt(enc.bytes, val, 10)
}

func (enc *ltsvEncoder) AddUint(key string, val uint) {
	enc.AddUint64(key, uint64(val))
}

func (enc *ltsvEncoder) AddUint64(key string, val uint64) {
	enc.addKey(key)
	enc.bytes = strconv.AppendUint(enc.bytes, val, 10)
}

func (enc *ltsvEncoder) AddUintptr(key string, val uintptr) {
	enc.addKey(key)
	enc.bytes = append(enc.bytes, "0x"...)
	enc.bytes = strconv.AppendUint(enc.bytes, uint64(val), 16)
}

func (enc *ltsvEncoder) AddFloat64(key string, val float64) {
	enc.addKey(key)
	enc.bytes = strconv.AppendFloat(enc.bytes, val, 'f', -1, 64)
}

func (enc *ltsvEncoder) AddMarshaler(key string, obj zap.LogMarshaler) error {
	enc.addKey(key)
	enc.nestedLevel++
	enc.bytes = append(enc.bytes, '{')
	err := obj.MarshalLog(enc)
	enc.bytes = append(enc.bytes, '}')
	enc.nestedLevel--
	return err
}

func (enc *ltsvEncoder) AddObject(key string, obj interface{}) error {
	enc.AddString(key, fmt.Sprintf("%+v", obj))
	return nil
}

func (enc *ltsvEncoder) Clone() zap.Encoder {
	clone := ltsvPool.Get().(*ltsvEncoder)
	clone.truncate()
	clone.bytes = append(clone.bytes, enc.bytes...)
	clone.timeLabel = enc.timeLabel
	clone.timeFmt = enc.timeFmt
	clone.levelLabel = enc.levelLabel
	clone.messageLabel = enc.messageLabel
	clone.nestedLevel = enc.nestedLevel
	clone.replacer = enc.replacer
	return clone
}

func (enc *ltsvEncoder) WriteEntry(sink io.Writer, msg string, lvl zap.Level, t time.Time) error {
	if sink == nil {
		return errNilSink
	}

	final := ltsvPool.Get().(*ltsvEncoder)
	final.truncate()
	enc.addTime(final, t)
	enc.addLevel(final, lvl)
	enc.addMessage(final, msg)

	if len(enc.bytes) > 0 {
		final.bytes = append(final.bytes, '\t')
		final.bytes = append(final.bytes, enc.bytes...)
	}
	final.bytes = append(final.bytes, '\n')

	expectedBytes := len(final.bytes)
	n, err := sink.Write(final.bytes)
	final.Free()
	if err != nil {
		return err
	}
	if n != expectedBytes {
		return fmt.Errorf("incomplete write: only wrote %v of %v bytes", n, expectedBytes)
	}
	return nil
}

func (enc *ltsvEncoder) truncate() {
	enc.bytes = enc.bytes[:0]
}

func (enc *ltsvEncoder) addKey(key string) {
	if enc.nestedLevel > 0 {
		last := len(enc.bytes) - 1
		// At some point, we'll also want to support arrays.
		if last >= 0 && enc.bytes[last] != '{' {
			enc.bytes = append(enc.bytes, ',')
		}
		enc.bytes = append(enc.bytes, '"')
		enc.safeAddJSONString(key)
		enc.bytes = append(enc.bytes, '"', ':')
	} else {
		if len(enc.bytes) > 0 {
			enc.bytes = append(enc.bytes, '\t')
		}
		enc.safeAddString(key)
		enc.bytes = append(enc.bytes, ':')
	}
}

func (enc *ltsvEncoder) addLevel(final *ltsvEncoder, lvl zap.Level) {
	final.addKey(enc.levelLabel)
	switch lvl {
	case zap.DebugLevel:
		final.bytes = append(final.bytes, 'D')
	case zap.InfoLevel:
		final.bytes = append(final.bytes, 'I')
	case zap.WarnLevel:
		final.bytes = append(final.bytes, 'W')
	case zap.ErrorLevel:
		final.bytes = append(final.bytes, 'E')
	case zap.PanicLevel:
		final.bytes = append(final.bytes, 'P')
	case zap.FatalLevel:
		final.bytes = append(final.bytes, 'F')
	default:
		final.bytes = strconv.AppendInt(final.bytes, int64(lvl), 10)
	}
}

func (enc *ltsvEncoder) addTime(final *ltsvEncoder, t time.Time) {
	if enc.timeFmt == "" {
		return
	}
	final.addKey(enc.timeLabel)
	final.bytes = t.AppendFormat(final.bytes, enc.timeFmt)
}

func (enc *ltsvEncoder) addMessage(final *ltsvEncoder, msg string) {
	final.addKey(enc.messageLabel)
	final.safeAddString(msg)
}

func (enc *ltsvEncoder) safeAddString(s string) {
	enc.bytes = append(enc.bytes, enc.replacer.Replace(s)...)
}

// safeAddString JSON-escapes a string and appends it to the internal buffer.
// Unlike the standard library's escaping function, it doesn't attempt to
// protect the user from browser vulnerabilities or JSONP-related problems.
func (enc *ltsvEncoder) safeAddJSONString(s string) {
	for i := 0; i < len(s); {
		if b := s[i]; b < utf8.RuneSelf {
			i++
			if 0x20 <= b && b != '\\' && b != '"' {
				enc.bytes = append(enc.bytes, b)
				continue
			}
			switch b {
			case '\\', '"':
				enc.bytes = append(enc.bytes, '\\', b)
			case '\n':
				enc.bytes = append(enc.bytes, '\\', 'n')
			case '\r':
				enc.bytes = append(enc.bytes, '\\', 'r')
			case '\t':
				enc.bytes = append(enc.bytes, '\\', 't')
			default:
				// Encode bytes < 0x20, except for the escape sequences above.
				enc.bytes = append(enc.bytes, `\u00`...)
				enc.bytes = append(enc.bytes, _hex[b>>4], _hex[b&0xF])
			}
			continue
		}
		c, size := utf8.DecodeRuneInString(s[i:])
		if c == utf8.RuneError && size == 1 {
			enc.bytes = append(enc.bytes, `\ufffd`...)
			i++
			continue
		}
		enc.bytes = append(enc.bytes, s[i:i+size]...)
		i += size
	}
}

// A LTSVOption is used to set options for a LTSV encoder.
type LTSVOption interface {
	apply(*ltsvEncoder)
}

type ltsvOptionFunc func(*ltsvEncoder)

func (opt ltsvOptionFunc) apply(enc *ltsvEncoder) {
	opt(enc)
}

// LTSVTimeFormat sets the format for log timestamps, using the same layout
// strings supported by time.Parse.
func LTSVTimeFormat(layout string) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.timeFmt = layout
	})
}

// LTSVNoTime omits timestamps from the serialized log entries.
func LTSVNoTime() LTSVOption {
	return LTSVTimeFormat("")
}

// LTSVTimeLabel sets the label for log timestamps.
func LTSVTimeLabel(label string) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.timeLabel = label
	})
}

// LTSVLevelLabel sets the label for log levels.
func LTSVLevelLabel(label string) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.levelLabel = label
	})
}

// LTSVNoLevel omit levels from the serialized log entries.
func LTSVNoLevel() LTSVOption {
	return LTSVLevelLabel("")
}

// LTSVMessageLabel sets the label for log messages.
func LTSVMessageLabel(label string) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.messageLabel = label
	})
}

// LTSVReplacer sets the replacer for log values.
func LTSVReplacer(replacer Replacer) LTSVOption {
	return ltsvOptionFunc(func(enc *ltsvEncoder) {
		enc.replacer = replacer
	})
}
<|endoftext|>


<commit_before>// Copyright 2014 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tcp

import (
	"os"
	"syscall"
)

func (c *Conn) setMaxKeepAliveProbes(max int) error {
	return errOpNoSupport
}

func (c *Conn) setCork(on bool) error {
	fd, err := c.sysfd()
	if err != nil {
		return err
	}
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolTCP, sysTCP_NOPUSH, boolint(on)))
}

func (c *Conn) info() (*Info, error) {
	return nil, errOpNoSupport
}
<commit_msg>tcp: add support for SetMaxKeepAliveProbes on darwin<commit_after>// Copyright 2014 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tcp

import (
	"os"
	"syscall"
)

func (c *Conn) setMaxKeepAliveProbes(max int) error {
	fd, err := c.sysfd()
	if err != nil {
		return err
	}
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolTCP, sysTCP_KEEPCNT, max))
}

func (c *Conn) setCork(on bool) error {
	fd, err := c.sysfd()
	if err != nil {
		return err
	}
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolTCP, sysTCP_NOPUSH, boolint(on)))
}

func (c *Conn) info() (*Info, error) {
	return nil, errOpNoSupport
}
<|endoftext|>