<commit_before>package scaffold

import (
	"bytes"
	"strings"
	"testing"
)

func TestSplitFilename(t *testing.T) {

	tests := []struct {
		input string
		bare  string
		ext   string
	}{
		{"test.txt", "test", ".txt"},
		{"test.a.b", "test.a", ".b"},
	}

	for _, test := range tests {
		bare, ext := splitFilename(test.input)

		if bare != test.bare || ext != test.ext {
			t.Errorf("splitFilename(%#v) = %#v, %#v; want %#v, %#v", test.input, bare, ext, test.bare, test.ext)
		}
	}

}

func TestIsLowercase(t *testing.T) {

	tests := []struct {
		input    string
		expected bool
	}{
		{"A", false},
		{"B", false},
		{"C", false},
		{"D", false},
		{"X", false},
		{"Y", false},
		{"Z", false},
		{"a", true},
		{"b", true},
		{"c", true},
		{"d", true},
		{"x", true},
		{"y", true},
		{"z", true},
	}

	for _, test := range tests {

		if got, want := isLowercase(test.input), test.expected; got != want {
			t.Errorf("isLowercase(%#v) = %v; want %v", test.input, got, want)
		}
	}

}

func TestFileName(t *testing.T) {

	/*
		([^-a-zA-Z_0-9])
	*/

	tests := []struct {
		input, expected string
	}{
		{" \\A/ want's 853 : until . # * +-0?@µ ", "A-wants-853-until-0"},
	}

	for _, test := range tests {

		if got, want := FileName(test.input), test.expected; got != want {
			t.Errorf("FileName(%#v) = %#v; want %#v", test.input, got, want)
		}
	}

}

func TestCamelCase1(t *testing.T) {

	tests := []struct {
		input, expected string
	}{
		{"field_name", "FieldName"},
		{"FieldName", "FieldName"},
		{"Field_name", "FieldName"},
		{"field_Name", "FieldName"},
		{"fieldname", "Fieldname"},
	}

	for _, test := range tests {

		if got, want := CamelCase1(test.input), test.expected; got != want {
			t.Errorf("CamelCase1(%v) = %v; want %v", test.input, got, want)
		}
	}

}

func TestCamelCase2(t *testing.T) {

	tests := []struct {
		input, expected string
	}{
		{"field_name", "fieldName"},
		{"FieldName", "FieldName"},
		{"Field_name", "FieldName"},
		{"field_Name", "fieldName"},
		{"fieldname", "fieldname"},
	}

	for _, test := range tests {

		if got, want := CamelCase2(test.input), test.expected; got != want {
			t.Errorf("CamelCase2(%#v) = %#v; want %#v", test.input, got, want)
		}
	}

}

func TestReplace(t *testing.T) {

	tests := []struct {
		input, src, dest, expected string
	}{
		{"field_name", "_", "*", "field*name"},
		{"field_name_x", "_", "*", "field*name*x"},
		{"_field_name_", "_", "*", "*field*name*"},
	}

	for _, test := range tests {

		if got, want := Replace(test.input, test.src, test.dest), test.expected; got != want {
			t.Errorf("Replace(%#v, %#v, %#v) = %#v; want %#v", test.input, test.src, test.dest, got, want)
		}
	}

}

var validHead = `{
	"Models": [
		{
			"Name": "",
			"Fields": [
				{"Name": "", "Type": ""}
			]
		}
	]
}`

var validBody = `{{range .Models}}
>>>models/
>>>{{toLower .Name}}/
>>>model.go
package {{replace .Name "_" "."}}

type {{camelCase1 .Name}} struct {
{{range .Fields}}
	{{camelCase1 .Name}} {{.Type}}
{{end}}
}

<<<model.go
<<<{{toLower .Name}}/
<<<models/
{{end}}`

var validJSON = `
{
	"Models": [
		{
			"Name": "person",
			"Fields": [
				{
					"Name": "first_name",
					"Type": "string"
				},
				{
					"Name": "last_name",
					"Type": "string"
				}
			]
		},
		{
			"Name": "address",
			"Fields": [
				{
					"Name": "street_no",
					"Type": "string"
				},
				{
					"Name": "city",
					"Type": "string"
				}
			]
		}
	]
}
`

var validTemplate = validHead + "\n\n" + validBody

func TestSplitTemplate(t *testing.T) {
	h, b := SplitTemplate(validTemplate)

	if h != validHead {
		t.Errorf("wrong head: %#v, expecting %#v", h, validHead)
	}

	if b != validBody {
		t.Errorf("wrong body: %#v, expecting %#v", b, validBody)
	}
}

func TestRun(t *testing.T) {

	tests := []struct {
		dir, body, json, expected string
	}{
		{
			"start",
			">>>file.txt\n<<<file.txt",
			`{}`,
			"start/file.txt\n",
		},
		{
			"start",
			">>>file1.txt\n<<<file1.txt\n>>>file2.txt\n<<<file2.txt",
			`{}`,
			"start/file1.txt\nstart/file2.txt\n",
		},
		{
			"start",
			">>>a/\n>>>b/\n>>>file1.txt\n<<<file1.txt\n>>>file2.txt\n<<<file2.txt\n<<<b/\n<<<a/\n",
			`{}`,
			"start/a/b/file1.txt\nstart/a/b/file2.txt\n",
		},
		{
			"a/dir",
			"{{range .Files}}>>>{{.Name}}.txt\n<<<{{.Name}}.txt\n{{end}}",
			`{"Files": [{"Name": "file1"},{"Name": "file2"}]}`,
			"a/dir/file1.txt\na/dir/file2.txt\n",
		},
		{
			"start/dir",
			validBody,
			validJSON,
			"start/dir/models/person/model.go\nstart/dir/models/address/model.go\n",
		},
	}

	for _, test := range tests {
		var log bytes.Buffer
		err := Run(test.dir, test.body, strings.NewReader(test.json), &log, true)
		if err != nil {
			t.Errorf("Run(%#v, %#v, %#v,...) returned error: %v", test.dir, test.body, test.json, err)
			continue
		}
		expected := strings.Replace(test.expected, `\`, "/", -1)
		if got, want := log.String(), expected; got != want {
			t.Errorf("Run(%#v, %#v, %#v,...) = %#v; want %#v", test.dir, test.body, test.json, got, want)
		}
	}
}

func TestRunErrors(t *testing.T) {

	tests := []struct {
		dir, body, json string
	}{
		{
			"start",
			">>>file.txt\n<<<file.txt",
			`{`,
		},
		{
			"start",
			">>file.txt\n<<<file.txt",
			`{}`,
		},
		{
			"start",
			">>>file1.txt\n<<<file2.txt",
			`{}`,
		},
		{
			"start",
			">>>a/\n>>>b\n>>>file1.txt\n<<<file1.txt\n<<<a/\n<<<b\n",
			`{}`,
		},
		{
			"start",
			">>>file1.txt\nho\n>>>file2.txt\nhu<<<file2.txt\n<<<file1.txt\n",
			`{}`,
		},
		{
			"start",
			"{{range .x}}",
			`{}`,
		},
	}

	for _, test := range tests {
		var log bytes.Buffer
		err := Run(test.dir, test.body, strings.NewReader(test.json), &log, true)
		if err == nil {
			t.Errorf("Run(%#v, %#v, %#v,...) returned no error", test.dir, test.body, test.json)
		}
	}
}
<commit_msg>now fix damned path<commit_after>package scaffold

import (
	"bytes"
	"strings"
	"testing"
)

func TestSplitFilename(t *testing.T) {

	tests := []struct {
		input string
		bare  string
		ext   string
	}{
		{"test.txt", "test", ".txt"},
		{"test.a.b", "test.a", ".b"},
	}

	for _, test := range tests {
		bare, ext := splitFilename(test.input)

		if bare != test.bare || ext != test.ext {
			t.Errorf("splitFilename(%#v) = %#v, %#v; want %#v, %#v", test.input, bare, ext, test.bare, test.ext)
		}
	}

}

func TestIsLowercase(t *testing.T) {

	tests := []struct {
		input    string
		expected bool
	}{
		{"A", false},
		{"B", false},
		{"C", false},
		{"D", false},
		{"X", false},
		{"Y", false},
		{"Z", false},
		{"a", true},
		{"b", true},
		{"c", true},
		{"d", true},
		{"x", true},
		{"y", true},
		{"z", true},
	}

	for _, test := range tests {

		if got, want := isLowercase(test.input), test.expected; got != want {
			t.Errorf("isLowercase(%#v) = %v; want %v", test.input, got, want)
		}
	}

}

func TestFileName(t *testing.T) {

	/*
		([^-a-zA-Z_0-9])
	*/

	tests := []struct {
		input, expected string
	}{
		{" \\A/ want's 853 : until . # * +-0?@µ ", "A-wants-853-until-0"},
	}

	for _, test := range tests {

		if got, want := FileName(test.input), test.expected; got != want {
			t.Errorf("FileName(%#v) = %#v; want %#v", test.input, got, want)
		}
	}

}

func TestCamelCase1(t *testing.T) {

	tests := []struct {
		input, expected string
	}{
		{"field_name", "FieldName"},
		{"FieldName", "FieldName"},
		{"Field_name", "FieldName"},
		{"field_Name", "FieldName"},
		{"fieldname", "Fieldname"},
	}

	for _, test := range tests {

		if got, want := CamelCase1(test.input), test.expected; got != want {
			t.Errorf("CamelCase1(%v) = %v; want %v", test.input, got, want)
		}
	}

}

func TestCamelCase2(t *testing.T) {

	tests := []struct {
		input, expected string
	}{
		{"field_name", "fieldName"},
		{"FieldName", "FieldName"},
		{"Field_name", "FieldName"},
		{"field_Name", "fieldName"},
		{"fieldname", "fieldname"},
	}

	for _, test := range tests {

		if got, want := CamelCase2(test.input), test.expected; got != want {
			t.Errorf("CamelCase2(%#v) = %#v; want %#v", test.input, got, want)
		}
	}

}

func TestReplace(t *testing.T) {

	tests := []struct {
		input, src, dest, expected string
	}{
		{"field_name", "_", "*", "field*name"},
		{"field_name_x", "_", "*", "field*name*x"},
		{"_field_name_", "_", "*", "*field*name*"},
	}

	for _, test := range tests {

		if got, want := Replace(test.input, test.src, test.dest), test.expected; got != want {
			t.Errorf("Replace(%#v, %#v, %#v) = %#v; want %#v", test.input, test.src, test.dest, got, want)
		}
	}

}

var validHead = `{
	"Models": [
		{
			"Name": "",
			"Fields": [
				{"Name": "", "Type": ""}
			]
		}
	]
}`

var validBody = `{{range .Models}}
>>>models/
>>>{{toLower .Name}}/
>>>model.go
package {{replace .Name "_" "."}}

type {{camelCase1 .Name}} struct {
{{range .Fields}}
	{{camelCase1 .Name}} {{.Type}}
{{end}}
}

<<<model.go
<<<{{toLower .Name}}/
<<<models/
{{end}}`

var validJSON = `
{
	"Models": [
		{
			"Name": "person",
			"Fields": [
				{
					"Name": "first_name",
					"Type": "string"
				},
				{
					"Name": "last_name",
					"Type": "string"
				}
			]
		},
		{
			"Name": "address",
			"Fields": [
				{
					"Name": "street_no",
					"Type": "string"
				},
				{
					"Name": "city",
					"Type": "string"
				}
			]
		}
	]
}
`

var validTemplate = validHead + "\n\n" + validBody

func TestSplitTemplate(t *testing.T) {
	h, b := SplitTemplate(validTemplate)

	if h != validHead {
		t.Errorf("wrong head: %#v, expecting %#v", h, validHead)
	}

	if b != validBody {
		t.Errorf("wrong body: %#v, expecting %#v", b, validBody)
	}
}

func TestRun(t *testing.T) {

	tests := []struct {
		dir, body, json, expected string
	}{
		{
			"start",
			">>>file.txt\n<<<file.txt",
			`{}`,
			"start/file.txt\n",
		},
		{
			"start",
			">>>file1.txt\n<<<file1.txt\n>>>file2.txt\n<<<file2.txt",
			`{}`,
			"start/file1.txt\nstart/file2.txt\n",
		},
		{
			"start",
			">>>a/\n>>>b/\n>>>file1.txt\n<<<file1.txt\n>>>file2.txt\n<<<file2.txt\n<<<b/\n<<<a/\n",
			`{}`,
			"start/a/b/file1.txt\nstart/a/b/file2.txt\n",
		},
		{
			"a/dir",
			"{{range .Files}}>>>{{.Name}}.txt\n<<<{{.Name}}.txt\n{{end}}",
			`{"Files": [{"Name": "file1"},{"Name": "file2"}]}`,
			"a/dir/file1.txt\na/dir/file2.txt\n",
		},
		{
			"start/dir",
			validBody,
			validJSON,
			"start/dir/models/person/model.go\nstart/dir/models/address/model.go\n",
		},
	}

	for _, test := range tests {
		var log bytes.Buffer
		err := Run(test.dir, test.body, strings.NewReader(test.json), &log, true)
		if err != nil {
			t.Errorf("Run(%#v, %#v, %#v,...) returned error: %v", test.dir, test.body, test.json, err)
			continue
		}
		if got, want := strings.Replace(log.String(), "\\", "/", -1), test.expected; got != want {
			t.Errorf("Run(%#v, %#v, %#v,...) = %#v; want %#v", test.dir, test.body, test.json, got, want)
		}
	}
}

func TestRunErrors(t *testing.T) {

	tests := []struct {
		dir, body, json string
	}{
		{
			"start",
			">>>file.txt\n<<<file.txt",
			`{`,
		},
		{
			"start",
			">>file.txt\n<<<file.txt",
			`{}`,
		},
		{
			"start",
			">>>file1.txt\n<<<file2.txt",
			`{}`,
		},
		{
			"start",
			">>>a/\n>>>b\n>>>file1.txt\n<<<file1.txt\n<<<a/\n<<<b\n",
			`{}`,
		},
		{
			"start",
			">>>file1.txt\nho\n>>>file2.txt\nhu<<<file2.txt\n<<<file1.txt\n",
			`{}`,
		},
		{
			"start",
			"{{range .x}}",
			`{}`,
		},
	}

	for _, test := range tests {
		var log bytes.Buffer
		err := Run(test.dir, test.body, strings.NewReader(test.json), &log, true)
		if err == nil {
			t.Errorf("Run(%#v, %#v, %#v,...) returned no error", test.dir, test.body, test.json)
		}
	}
}
<|endoftext|>


<commit_before>package schedule

import (
	"errors"
	"github.com/0xfoo/punchcard/git"
	"github.com/0xfoo/punchcard/utils"
	"strings"
	"time"
)

const (
	SCHEDULE_WIDTH = 53
)

// TextSchedule creates commits over the past 365/366 days to build the given text.
// These commits will be created in the given git repo using the FileGenerator.
func TextSchedule(text string, repo git.Git, filegen utils.FileGenerator) error {
	messageBase := GetCommitMessageBase()
	days := GetDaysSinceNowMinusOneYear()
	commits, err := getTextCommitSchedule(text, days, messageBase)
	if err != nil {
		return err
	}
	for _, commit := range commits {
		repo.Add(filegen.CreateFile())
		repo.Commit(commit.Message, commit.DateTime.String())
	}
	return err
}

func getTextCommitSchedule(text string, days []time.Time, messageBase []string) ([]Commit, error) {
	if !textFits(text) {
		return nil, errors.New("Text does not fit.")
	}
	schedule := buildTextCommitSchedule(days, text)
	commits := convertScheduleToCommits(schedule)
	return commits, nil
}

func textFits(text string) bool {
	textWidth := getTextWidth(text)
	textIsNotToWide := textWidth <= SCHEDULE_WIDTH-2 // adjust for margins
	textIsNotEmpty := textWidth > 0
	return textIsNotEmpty && textIsNotToWide
}

func getTextWidth(text string) int {
	width := 0
	for _, char := range strings.Split(text, "") {
		letter, _ := utils.TranslateLetter(char)
		width += len(letter[0]) + 1 // adjust for space between letters
	}
	return width - 1 // last letter does not need and extra space
}

func convertScheduleToCommits(schedule CommitSchedule) []Commit {
	var commits []Commit
	return commits
}

func buildTextCommitSchedule(days []time.Time, text string) CommitSchedule {
	schedule := BuildCommitSchedule(days)
	mapTextOntoCommitSchedule(text, &schedule)
	return schedule
}

func mapTextOntoCommitSchedule(text string, schedule *CommitSchedule) {
	letters := buildTextFields(text)
	rightShift := 0
	for _, fields := range letters {
		for rowIndex, row := range fields {
			for columnIndex, field := range row {
				schedule[rowIndex][columnIndex+rightShift] = field
			}
			rightShift += len(row)
		}
	}
}

func buildTextFields(text string) [][][]int {
	var letters [][][]int
	space, _ := utils.TranslateLetter(" ")
	length := len(text)
	for index, char := range strings.Split(text, "") {
		letter, _ := utils.TranslateLetter(char)
		if index == length-1 {
			letters = append(letters, letter)
		} else {

			letters = append(letters, letter, space)
		}
	}
	return letters
}
<commit_msg>Refactor build text, avoiding if else.<commit_after>package schedule

import (
	"errors"
	"github.com/0xfoo/punchcard/git"
	"github.com/0xfoo/punchcard/utils"
	"strings"
	"time"
)

const (
	SCHEDULE_WIDTH = 53
)

// TextSchedule creates commits over the past 365/366 days to build the given text.
// These commits will be created in the given git repo using the FileGenerator.
func TextSchedule(text string, repo git.Git, filegen utils.FileGenerator) error {
	messageBase := GetCommitMessageBase()
	days := GetDaysSinceNowMinusOneYear()
	commits, err := getTextCommitSchedule(text, days, messageBase)
	if err != nil {
		return err
	}
	for _, commit := range commits {
		repo.Add(filegen.CreateFile())
		repo.Commit(commit.Message, commit.DateTime.String())
	}
	return err
}

func getTextCommitSchedule(text string, days []time.Time, messageBase []string) ([]Commit, error) {
	if !textFits(text) {
		return nil, errors.New("Text does not fit.")
	}
	schedule := buildTextCommitSchedule(days, text)
	commits := convertScheduleToCommits(schedule)
	return commits, nil
}

func textFits(text string) bool {
	textWidth := getTextWidth(text)
	textIsNotToWide := textWidth <= SCHEDULE_WIDTH-2 // adjust for margins
	textIsNotEmpty := textWidth > 0
	return textIsNotEmpty && textIsNotToWide
}

func getTextWidth(text string) int {
	width := 0
	for _, char := range strings.Split(text, "") {
		letter, _ := utils.TranslateLetter(char)
		width += len(letter[0]) + 1 // adjust for space between letters
	}
	return width - 1 // last letter does not need and extra space
}

func convertScheduleToCommits(schedule CommitSchedule) []Commit {
	var commits []Commit
	return commits
}

func buildTextCommitSchedule(days []time.Time, text string) CommitSchedule {
	schedule := BuildCommitSchedule(days)
	mapTextOntoCommitSchedule(text, &schedule)
	return schedule
}

func mapTextOntoCommitSchedule(text string, schedule *CommitSchedule) {
	letters := buildTextFields(text)
	rightShift := 0
	for _, fields := range letters {
		for rowIndex, row := range fields {
			for columnIndex, field := range row {
				schedule[rowIndex][columnIndex+rightShift] = field
			}
			rightShift += len(row)
		}
	}
}

func buildTextFields(text string) [][][]int {
	var letters [][][]int
	if text == "" {
		return letters
	}
	space, _ := utils.TranslateLetter(" ")
	for _, char := range strings.Split(text, "") {
		letter, _ := utils.TranslateLetter(char)
		letters = append(letters, letter, space)
	}
	return letters[0 : len(letters)-1] // remove last extra space
}
<|endoftext|>


<commit_before>package schema

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/actgardner/gogen-avro/generator"
)

const recordStructDefTemplate = `
%v
type %v struct {
%v
}
`

const recordSchemaTemplate = `func (r %v) Schema() string {
 return %v
}
`

const recordConstructorTemplate = `
func %v %v {
	return &%v{}
}
`

const recordStructPublicSerializerTemplate = `
func (r %v) Serialize(w io.Writer) error {
	return %v(r, w)
}
`

const recordStructPublicDeserializerTemplate = `
func %v(r io.Reader) (%v, error) {
	t := %v

	deser, err := compiler.CompileSchemaBytes([]byte(t.Schema()), []byte(t.Schema()))
        if err != nil {
		return nil, err
	}

        err = vm.Eval(r, deser, t)
	return t, err
}
`

const recordWriterTemplate = `
func %v(writer io.Writer, codec container.Codec, recordsPerBlock int64) (*container.Writer, error) {
	str := &%v{}
	return container.NewWriter(writer, codec, recordsPerBlock, str.Schema())
}
`

const recordStructDeserializerTemplate = `
func %v(r io.Reader) (%v, error) {
	var str = &%v{}
	var err error
	%v
	return str, nil
}
`

const recordFieldTemplate = `
func (_ %[1]v) SetBoolean(v bool) { panic("Unsupported operation") }
func (_ %[1]v) SetInt(v int32) { panic("Unsupported operation") }
func (_ %[1]v) SetLong(v int64) { panic("Unsupported operation") }
func (_ %[1]v) SetFloat(v float32) { panic("Unsupported operation") }
func (_ %[1]v) SetDouble(v float64) { panic("Unsupported operation") }
func (_ %[1]v) SetBytes(v []byte) { panic("Unsupported operation") }
func (_ %[1]v) SetString(v string) { panic("Unsupported operation") }
func (_ %[1]v) SetUnionElem(v int64) { panic("Unsupported operation") }
func (r %[1]v) Get(i int) types.Field {
	switch (i) {
		%[2]v
	}
	panic("Unknown field index")
}
func (r %[1]v) SetDefault(i int) {
	switch (i) {
		%[3]v
	}
	panic("Unknown field index")
}
func (_ %[1]v) AppendMap(key string) types.Field { panic("Unsupported operation") }
func (_ %[1]v) AppendArray() types.Field { panic("Unsupported operation") }
func (_ %[1]v) Finalize() { }
`

const recordReaderTemplate = `
type %[1]v struct {
	r io.Reader
	p *vm.Program
}

func New%[1]v(r io.Reader) (*%[1]v, error){
	containerReader, err := container.NewReader(r)
	if err != nil {
		return nil, err
	}

	t := %[3]v
	deser, err := compiler.CompileSchemaBytes([]byte(containerReader.AvroContainerSchema()), []byte(t.Schema()))
	if err != nil {
		return nil, err
	}

	return &%[1]v{
		r: containerReader,
		p: deser,
	}, nil
}

func (r *%[1]v) Read() (%[2]v, error) {
	t := %[3]v
        err := vm.Eval(r.r, r.p, t)
	return t, err
}
`

type RecordDefinition struct {
	name     QualifiedName
	aliases  []QualifiedName
	fields   []*Field
	doc      string
	metadata map[string]interface{}
}

func NewRecordDefinition(name QualifiedName, aliases []QualifiedName, fields []*Field, doc string, metadata map[string]interface{}) *RecordDefinition {
	return &RecordDefinition{
		name:     name,
		aliases:  aliases,
		fields:   fields,
		doc:      doc,
		metadata: metadata,
	}
}

func (r *RecordDefinition) AvroName() QualifiedName {
	return r.name
}

func (r *RecordDefinition) Name() string {
	return generator.ToPublicName(r.name.String())
}

func (r *RecordDefinition) SimpleName() string {
	return generator.ToPublicName(r.name.Name)
}

func (r *RecordDefinition) GoType() string {
	return fmt.Sprintf("*%v", r.Name())
}

func (r *RecordDefinition) Aliases() []QualifiedName {
	return r.aliases
}

func (r *RecordDefinition) structFields() string {
	var definitions string
	for _, f := range r.fields {
		var field string

		// Prepend doc if exists
		if f.Doc() != "" {
			field += fmt.Sprintf("\n// %v\n", f.Doc())
		}

		field += fmt.Sprintf("%v %v", f.SimpleName(), f.Type().GoType())

		if f.Tags() != "" {
			field += " `" + f.Tags() + "`"
		}

		definitions += field + "\n"
	}

	return definitions
}

func (r *RecordDefinition) fieldSerializers() string {
	if r.fields == nil || len(r.fields) == 0 {
		//in case the record has no fields just return empty fieldSerializers
		return ""
	}
	serializerMethods := "var err error\n"
	for _, f := range r.fields {
		serializerMethods += fmt.Sprintf("err = %v(r.%v, w)\nif err != nil {return err}\n", f.Type().SerializerMethod(), f.GoName())
	}
	return serializerMethods
}

func (r *RecordDefinition) structDefinition() string {
	var doc string
	if r.doc != "" {
		doc = fmt.Sprintf("// %v", r.doc)
	}
	return fmt.Sprintf(recordStructDefTemplate, doc, r.Name(), r.structFields())
}

func (r *RecordDefinition) serializerMethodDef() string {
	return fmt.Sprintf("func %v(r %v, w io.Writer) error {\n%v\nreturn nil\n}", r.SerializerMethod(), r.GoType(), r.fieldSerializers())
}

func (r *RecordDefinition) SerializerMethod() string {
	return fmt.Sprintf("write%v", r.Name())
}

func (r *RecordDefinition) recordWriterMethod() string {
	return fmt.Sprintf("New%vWriter", r.Name())
}

func (r *RecordDefinition) recordWriterMethodDef() string {
	return fmt.Sprintf(recordWriterTemplate, r.recordWriterMethod(), r.Name())
}

func (r *RecordDefinition) publicSerializerMethodDef() string {
	return fmt.Sprintf(recordStructPublicSerializerTemplate, r.GoType(), r.SerializerMethod())
}

func (r *RecordDefinition) filename() string {
	return generator.ToSnake(r.Name()) + ".go"
}

func (r *RecordDefinition) schemaMethodDef() (string, error) {
	def, err := r.Definition(make(map[QualifiedName]interface{}))
	if err != nil {
		return "", err
	}

	schemaJson, _ := json.Marshal(def)
	return fmt.Sprintf(recordSchemaTemplate, r.GoType(), strconv.Quote(string(schemaJson))), nil
}

func (r *RecordDefinition) publicDeserializerMethod() string {
	return fmt.Sprintf("Deserialize%v", r.Name())
}

func (r *RecordDefinition) publicDeserializerMethodDef() string {
	return fmt.Sprintf(recordStructPublicDeserializerTemplate, r.publicDeserializerMethod(), r.GoType(), r.ConstructorMethod())
}

func (r *RecordDefinition) AddStruct(p *generator.Package, containers bool) error {
	// Import guard, to avoid circular dependencies
	if !p.HasStruct(r.filename(), r.GoType()) {
		p.AddStruct(r.filename(), r.GoType(), r.structDefinition())
		schemaDef, err := r.schemaMethodDef()
		if err != nil {
			return err
		}

		p.AddFunction(r.filename(), r.GoType(), "Schema", schemaDef)
		constructorMethodDef, err := r.ConstructorMethodDef()
		if err != nil {
			return err
		}

		if containers {
			p.AddImport(r.filename(), "github.com/actgardner/gogen-avro/container")
			p.AddFunction(r.filename(), "", r.recordWriterMethod(), r.recordWriterMethodDef())
		}

		p.AddImport(r.filename(), "github.com/actgardner/gogen-avro/vm/types")
		p.AddImport(r.filename(), "github.com/actgardner/gogen-avro/vm")
		p.AddImport(r.filename(), "github.com/actgardner/gogen-avro/compiler")
		p.AddFunction(r.filename(), r.GoType(), "fieldTemplate", r.FieldsMethodDef())
		p.AddFunction(r.filename(), r.GoType(), "recordReader", r.recordReaderDef())
		p.AddFunction(r.filename(), r.GoType(), r.ConstructorMethod(), constructorMethodDef)
		p.AddFunction(r.filename(), r.GoType(), r.publicDeserializerMethod(), r.publicDeserializerMethodDef())
		for _, f := range r.fields {
			f.Type().AddStruct(p, containers)
		}
	}
	return nil
}

func (r *RecordDefinition) AddSerializer(p *generator.Package) {
	// Import guard, to avoid circular dependencies
	if !p.HasFunction(UTIL_FILE, "", r.SerializerMethod()) {
		p.AddImport(r.filename(), "io")
		p.AddFunction(UTIL_FILE, "", r.SerializerMethod(), r.serializerMethodDef())
		p.AddFunction(r.filename(), r.GoType(), "Serialize", r.publicSerializerMethodDef())
		for _, f := range r.fields {
			f.Type().AddSerializer(p)
		}
	}
}

func (r *RecordDefinition) ResolveReferences(n *Namespace) error {
	var err error
	for _, f := range r.fields {
		err = f.Type().ResolveReferences(n)
		if err != nil {
			return err
		}
	}
	return nil
}

func (r *RecordDefinition) Definition(scope map[QualifiedName]interface{}) (interface{}, error) {
	if _, ok := scope[r.name]; ok {
		return r.name.String(), nil
	}
	scope[r.name] = 1
	fields := make([]map[string]interface{}, 0)
	for _, f := range r.fields {
		def, err := f.Definition(scope)
		if err != nil {
			return nil, err
		}
		fields = append(fields, def)
	}

	r.metadata["fields"] = fields
	return r.metadata, nil
}

func (r *RecordDefinition) ConstructorMethod() string {
	return fmt.Sprintf("New%v()", r.Name())
}

func (r *RecordDefinition) fieldConstructors() (string, error) {
	constructors := ""
	for _, f := range r.fields {
		if constructor, ok := getConstructableForType(f.Type()); ok {
			constructors += fmt.Sprintf("%v: %v,\n", f.GoName(), constructor.ConstructorMethod())
		}
	}
	return constructors, nil
}

func (r *RecordDefinition) defaultMethodDef() (string, error) {
	defaults := ""
	for i, f := range r.fields {
		if f.hasDef {
			defaults += fmt.Sprintf("case %v:\n", i)
			def, err := f.Type().DefaultValue(fmt.Sprintf("r.%v", f.GoName()), f.Default())
			if err != nil {
				return "", err
			}
			defaults += def + "\nreturn\n"
		}
	}
	return defaults, nil
}

func (r *RecordDefinition) getMethodDef() string {
	getBody := ""
	for i, f := range r.fields {
		getBody += fmt.Sprintf("case %v:\n", i)
		if constructor, ok := getConstructableForType(f.Type()); ok {
			getBody += fmt.Sprintf("r.%v = %v\n", f.GoName(), constructor.ConstructorMethod())
		}
		if f.Type().WrapperType() == "" {
			getBody += fmt.Sprintf("return r.%v\n", f.GoName())
		} else {
			getBody += fmt.Sprintf("return (*%v)(&r.%v)\n", f.Type().WrapperType(), f.GoName())
		}
	}
	return getBody
}

func (r *RecordDefinition) FieldsMethodDef() string {
	getBody := r.getMethodDef()
	defaultBody, _ := r.defaultMethodDef()
	return fmt.Sprintf(recordFieldTemplate, r.GoType(), getBody, defaultBody)
}

func (r *RecordDefinition) ConstructorMethodDef() (string, error) {
	return fmt.Sprintf(recordConstructorTemplate, r.ConstructorMethod(), r.GoType(), r.Name()), nil
}

func (r *RecordDefinition) recordReaderTypeName() string {
	return r.Name() + "Reader"
}

func (r *RecordDefinition) recordReaderDef() string {
	return fmt.Sprintf(recordReaderTemplate, r.recordReaderTypeName(), r.GoType(), r.ConstructorMethod())
}

func (r *RecordDefinition) FieldByName(name string) *Field {
	for _, f := range r.fields {
		if f.Name() == name {
			return f
		}
	}
	return nil
}

func (r *RecordDefinition) DefaultValue(lvalue string, rvalue interface{}) (string, error) {
	items := rvalue.(map[string]interface{})
	fieldSetters := ""
	for k, v := range items {
		field := r.FieldByName(k)
		fieldSetter, err := field.Type().DefaultValue(fmt.Sprintf("%v.%v", lvalue, field.GoName()), v)
		if err != nil {
			return "", err
		}

		fieldSetters += fieldSetter + "\n"
	}
	return fieldSetters, nil
}

func (r *RecordDefinition) Fields() []*Field {
	return r.fields
}

func (s *RecordDefinition) IsReadableBy(d Definition) bool {
	reader, ok := d.(*RecordDefinition)
	return ok && reader.name == s.name
}

func (s *RecordDefinition) WrapperType() string {
	return ""
}
<commit_msg>Add a schema name function for objects (#75)<commit_after>package schema

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/actgardner/gogen-avro/generator"
)

const recordStructDefTemplate = `
%v
type %v struct {
%v
}
`

const recordSchemaTemplate = `func (r %v) Schema() string {
 return %v
}
`

const recordSchemaNameTemplate = `func (r %v) SchemaName() string {
 return %v
}
`

const recordConstructorTemplate = `
func %v %v {
	return &%v{}
}
`

const recordStructPublicSerializerTemplate = `
func (r %v) Serialize(w io.Writer) error {
	return %v(r, w)
}
`

const recordStructPublicDeserializerTemplate = `
func %v(r io.Reader) (%v, error) {
	t := %v

	deser, err := compiler.CompileSchemaBytes([]byte(t.Schema()), []byte(t.Schema()))
        if err != nil {
		return nil, err
	}

        err = vm.Eval(r, deser, t)
	return t, err
}
`

const recordWriterTemplate = `
func %v(writer io.Writer, codec container.Codec, recordsPerBlock int64) (*container.Writer, error) {
	str := &%v{}
	return container.NewWriter(writer, codec, recordsPerBlock, str.Schema())
}
`

const recordStructDeserializerTemplate = `
func %v(r io.Reader) (%v, error) {
	var str = &%v{}
	var err error
	%v
	return str, nil
}
`

const recordFieldTemplate = `
func (_ %[1]v) SetBoolean(v bool) { panic("Unsupported operation") }
func (_ %[1]v) SetInt(v int32) { panic("Unsupported operation") }
func (_ %[1]v) SetLong(v int64) { panic("Unsupported operation") }
func (_ %[1]v) SetFloat(v float32) { panic("Unsupported operation") }
func (_ %[1]v) SetDouble(v float64) { panic("Unsupported operation") }
func (_ %[1]v) SetBytes(v []byte) { panic("Unsupported operation") }
func (_ %[1]v) SetString(v string) { panic("Unsupported operation") }
func (_ %[1]v) SetUnionElem(v int64) { panic("Unsupported operation") }
func (r %[1]v) Get(i int) types.Field {
	switch (i) {
		%[2]v
	}
	panic("Unknown field index")
}
func (r %[1]v) SetDefault(i int) {
	switch (i) {
		%[3]v
	}
	panic("Unknown field index")
}
func (_ %[1]v) AppendMap(key string) types.Field { panic("Unsupported operation") }
func (_ %[1]v) AppendArray() types.Field { panic("Unsupported operation") }
func (_ %[1]v) Finalize() { }
`

const recordReaderTemplate = `
type %[1]v struct {
	r io.Reader
	p *vm.Program
}

func New%[1]v(r io.Reader) (*%[1]v, error){
	containerReader, err := container.NewReader(r)
	if err != nil {
		return nil, err
	}

	t := %[3]v
	deser, err := compiler.CompileSchemaBytes([]byte(containerReader.AvroContainerSchema()), []byte(t.Schema()))
	if err != nil {
		return nil, err
	}

	return &%[1]v{
		r: containerReader,
		p: deser,
	}, nil
}

func (r *%[1]v) Read() (%[2]v, error) {
	t := %[3]v
        err := vm.Eval(r.r, r.p, t)
	return t, err
}
`

type RecordDefinition struct {
	name     QualifiedName
	aliases  []QualifiedName
	fields   []*Field
	doc      string
	metadata map[string]interface{}
}

func NewRecordDefinition(name QualifiedName, aliases []QualifiedName, fields []*Field, doc string, metadata map[string]interface{}) *RecordDefinition {
	return &RecordDefinition{
		name:     name,
		aliases:  aliases,
		fields:   fields,
		doc:      doc,
		metadata: metadata,
	}
}

func (r *RecordDefinition) AvroName() QualifiedName {
	return r.name
}

func (r *RecordDefinition) Name() string {
	return generator.ToPublicName(r.name.String())
}

func (r *RecordDefinition) SimpleName() string {
	return generator.ToPublicName(r.name.Name)
}

func (r *RecordDefinition) GoType() string {
	return fmt.Sprintf("*%v", r.Name())
}

func (r *RecordDefinition) Aliases() []QualifiedName {
	return r.aliases
}

func (r *RecordDefinition) structFields() string {
	var definitions string
	for _, f := range r.fields {
		var field string

		// Prepend doc if exists
		if f.Doc() != "" {
			field += fmt.Sprintf("\n// %v\n", f.Doc())
		}

		field += fmt.Sprintf("%v %v", f.SimpleName(), f.Type().GoType())

		if f.Tags() != "" {
			field += " `" + f.Tags() + "`"
		}

		definitions += field + "\n"
	}

	return definitions
}

func (r *RecordDefinition) fieldSerializers() string {
	if r.fields == nil || len(r.fields) == 0 {
		//in case the record has no fields just return empty fieldSerializers
		return ""
	}
	serializerMethods := "var err error\n"
	for _, f := range r.fields {
		serializerMethods += fmt.Sprintf("err = %v(r.%v, w)\nif err != nil {return err}\n", f.Type().SerializerMethod(), f.GoName())
	}
	return serializerMethods
}

func (r *RecordDefinition) structDefinition() string {
	var doc string
	if r.doc != "" {
		doc = fmt.Sprintf("// %v", r.doc)
	}
	return fmt.Sprintf(recordStructDefTemplate, doc, r.Name(), r.structFields())
}

func (r *RecordDefinition) serializerMethodDef() string {
	return fmt.Sprintf("func %v(r %v, w io.Writer) error {\n%v\nreturn nil\n}", r.SerializerMethod(), r.GoType(), r.fieldSerializers())
}

func (r *RecordDefinition) SerializerMethod() string {
	return fmt.Sprintf("write%v", r.Name())
}

func (r *RecordDefinition) recordWriterMethod() string {
	return fmt.Sprintf("New%vWriter", r.Name())
}

func (r *RecordDefinition) recordWriterMethodDef() string {
	return fmt.Sprintf(recordWriterTemplate, r.recordWriterMethod(), r.Name())
}

func (r *RecordDefinition) publicSerializerMethodDef() string {
	return fmt.Sprintf(recordStructPublicSerializerTemplate, r.GoType(), r.SerializerMethod())
}

func (r *RecordDefinition) filename() string {
	return generator.ToSnake(r.Name()) + ".go"
}

func (r *RecordDefinition) schemaMethodDef() (string, error) {
	def, err := r.Definition(make(map[QualifiedName]interface{}))
	if err != nil {
		return "", err
	}

	schemaJson, _ := json.Marshal(def)
	return fmt.Sprintf(recordSchemaTemplate, r.GoType(), strconv.Quote(string(schemaJson))), nil
}

func (r *RecordDefinition) publicDeserializerMethod() string {
	return fmt.Sprintf("Deserialize%v", r.Name())
}

func (r *RecordDefinition) publicDeserializerMethodDef() string {
	return fmt.Sprintf(recordStructPublicDeserializerTemplate, r.publicDeserializerMethod(), r.GoType(), r.ConstructorMethod())
}

func (r *RecordDefinition) schemaNameMethodDef() (string, error) {
	return fmt.Sprintf(recordSchemaNameTemplate, r.GoType(), strconv.Quote(r.name.String())), nil
}

func (r *RecordDefinition) AddStruct(p *generator.Package, containers bool) error {
	// Import guard, to avoid circular dependencies
	if !p.HasStruct(r.filename(), r.GoType()) {
		p.AddStruct(r.filename(), r.GoType(), r.structDefinition())
		schemaDef, err := r.schemaMethodDef()
		if err != nil {
			return err
		}

		p.AddFunction(r.filename(), r.GoType(), "Schema", schemaDef)
		constructorMethodDef, err := r.ConstructorMethodDef()
		if err != nil {
			return err
		}

		schemaNameDef, err := r.schemaNameMethodDef()
		if err != nil {
			return err
		}

		p.AddFunction(r.filename(), r.GoType(), "SchemaName", schemaNameDef)

		if containers {
			p.AddImport(r.filename(), "github.com/actgardner/gogen-avro/container")
			p.AddFunction(r.filename(), "", r.recordWriterMethod(), r.recordWriterMethodDef())
		}

		p.AddImport(r.filename(), "github.com/actgardner/gogen-avro/vm/types")
		p.AddImport(r.filename(), "github.com/actgardner/gogen-avro/vm")
		p.AddImport(r.filename(), "github.com/actgardner/gogen-avro/compiler")
		p.AddFunction(r.filename(), r.GoType(), "fieldTemplate", r.FieldsMethodDef())
		p.AddFunction(r.filename(), r.GoType(), "recordReader", r.recordReaderDef())
		p.AddFunction(r.filename(), r.GoType(), r.ConstructorMethod(), constructorMethodDef)
		p.AddFunction(r.filename(), r.GoType(), r.publicDeserializerMethod(), r.publicDeserializerMethodDef())
		for _, f := range r.fields {
			f.Type().AddStruct(p, containers)
		}
	}
	return nil
}

func (r *RecordDefinition) AddSerializer(p *generator.Package) {
	// Import guard, to avoid circular dependencies
	if !p.HasFunction(UTIL_FILE, "", r.SerializerMethod()) {
		p.AddImport(r.filename(), "io")
		p.AddFunction(UTIL_FILE, "", r.SerializerMethod(), r.serializerMethodDef())
		p.AddFunction(r.filename(), r.GoType(), "Serialize", r.publicSerializerMethodDef())
		for _, f := range r.fields {
			f.Type().AddSerializer(p)
		}
	}
}

func (r *RecordDefinition) ResolveReferences(n *Namespace) error {
	var err error
	for _, f := range r.fields {
		err = f.Type().ResolveReferences(n)
		if err != nil {
			return err
		}
	}
	return nil
}

func (r *RecordDefinition) Definition(scope map[QualifiedName]interface{}) (interface{}, error) {
	if _, ok := scope[r.name]; ok {
		return r.name.String(), nil
	}
	scope[r.name] = 1
	fields := make([]map[string]interface{}, 0)
	for _, f := range r.fields {
		def, err := f.Definition(scope)
		if err != nil {
			return nil, err
		}
		fields = append(fields, def)
	}

	r.metadata["fields"] = fields
	return r.metadata, nil
}

func (r *RecordDefinition) ConstructorMethod() string {
	return fmt.Sprintf("New%v()", r.Name())
}

func (r *RecordDefinition) fieldConstructors() (string, error) {
	constructors := ""
	for _, f := range r.fields {
		if constructor, ok := getConstructableForType(f.Type()); ok {
			constructors += fmt.Sprintf("%v: %v,\n", f.GoName(), constructor.ConstructorMethod())
		}
	}
	return constructors, nil
}

func (r *RecordDefinition) defaultMethodDef() (string, error) {
	defaults := ""
	for i, f := range r.fields {
		if f.hasDef {
			defaults += fmt.Sprintf("case %v:\n", i)
			def, err := f.Type().DefaultValue(fmt.Sprintf("r.%v", f.GoName()), f.Default())
			if err != nil {
				return "", err
			}
			defaults += def + "\nreturn\n"
		}
	}
	return defaults, nil
}

func (r *RecordDefinition) getMethodDef() string {
	getBody := ""
	for i, f := range r.fields {
		getBody += fmt.Sprintf("case %v:\n", i)
		if constructor, ok := getConstructableForType(f.Type()); ok {
			getBody += fmt.Sprintf("r.%v = %v\n", f.GoName(), constructor.ConstructorMethod())
		}
		if f.Type().WrapperType() == "" {
			getBody += fmt.Sprintf("return r.%v\n", f.GoName())
		} else {
			getBody += fmt.Sprintf("return (*%v)(&r.%v)\n", f.Type().WrapperType(), f.GoName())
		}
	}
	return getBody
}

func (r *RecordDefinition) FieldsMethodDef() string {
	getBody := r.getMethodDef()
	defaultBody, _ := r.defaultMethodDef()
	return fmt.Sprintf(recordFieldTemplate, r.GoType(), getBody, defaultBody)
}

func (r *RecordDefinition) ConstructorMethodDef() (string, error) {
	return fmt.Sprintf(recordConstructorTemplate, r.ConstructorMethod(), r.GoType(), r.Name()), nil
}

func (r *RecordDefinition) recordReaderTypeName() string {
	return r.Name() + "Reader"
}

func (r *RecordDefinition) recordReaderDef() string {
	return fmt.Sprintf(recordReaderTemplate, r.recordReaderTypeName(), r.GoType(), r.ConstructorMethod())
}

func (r *RecordDefinition) FieldByName(name string) *Field {
	for _, f := range r.fields {
		if f.Name() == name {
			return f
		}
	}
	return nil
}

func (r *RecordDefinition) DefaultValue(lvalue string, rvalue interface{}) (string, error) {
	items := rvalue.(map[string]interface{})
	fieldSetters := ""
	for k, v := range items {
		field := r.FieldByName(k)
		fieldSetter, err := field.Type().DefaultValue(fmt.Sprintf("%v.%v", lvalue, field.GoName()), v)
		if err != nil {
			return "", err
		}

		fieldSetters += fieldSetter + "\n"
	}
	return fieldSetters, nil
}

func (r *RecordDefinition) Fields() []*Field {
	return r.fields
}

func (s *RecordDefinition) IsReadableBy(d Definition) bool {
	reader, ok := d.(*RecordDefinition)
	return ok && reader.name == s.name
}

func (s *RecordDefinition) WrapperType() string {
	return ""
}
<|endoftext|>


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

package v3rpc

import (
	"io"
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/mvcc"
	"github.com/coreos/etcd/mvcc/mvccpb"
)

type watchServer struct {
	clusterID int64
	memberID  int64
	raftTimer etcdserver.RaftTimer
	watchable mvcc.WatchableKV
}

func NewWatchServer(s *etcdserver.EtcdServer) pb.WatchServer {
	return &watchServer{
		clusterID: int64(s.Cluster().ID()),
		memberID:  int64(s.ID()),
		raftTimer: s,
		watchable: s.Watchable(),
	}
}

var (
	// External test can read this with GetProgressReportInterval()
	// and change this to a small value to finish fast with
	// SetProgressReportInterval().
	progressReportInterval   = 10 * time.Minute
	progressReportIntervalMu sync.RWMutex
)

func GetProgressReportInterval() time.Duration {
	progressReportIntervalMu.RLock()
	defer progressReportIntervalMu.RUnlock()
	return progressReportInterval
}

func SetProgressReportInterval(newTimeout time.Duration) {
	progressReportIntervalMu.Lock()
	defer progressReportIntervalMu.Unlock()
	progressReportInterval = newTimeout
}

const (
	// We send ctrl response inside the read loop. We do not want
	// send to block read, but we still want ctrl response we sent to
	// be serialized. Thus we use a buffered chan to solve the problem.
	// A small buffer should be OK for most cases, since we expect the
	// ctrl requests are infrequent.
	ctrlStreamBufLen = 16
)

// serverWatchStream is an etcd server side stream. It receives requests
// from client side gRPC stream. It receives watch events from mvcc.WatchStream,
// and creates responses that forwarded to gRPC stream.
// It also forwards control message like watch created and canceled.
type serverWatchStream struct {
	clusterID int64
	memberID  int64
	raftTimer etcdserver.RaftTimer

	watchable mvcc.WatchableKV

	gRPCStream  pb.Watch_WatchServer
	watchStream mvcc.WatchStream
	ctrlStream  chan *pb.WatchResponse

	// progress tracks the watchID that stream might need to send
	// progress to.
	// TOOD: combine progress and prevKV into a single struct?
	progress map[mvcc.WatchID]bool
	prevKV   map[mvcc.WatchID]bool

	// mu protects progress
	mu sync.Mutex

	// closec indicates the stream is closed.
	closec chan struct{}

	// wg waits for the send loop to complete
	wg sync.WaitGroup
}

func (ws *watchServer) Watch(stream pb.Watch_WatchServer) (err error) {
	sws := serverWatchStream{
		clusterID: ws.clusterID,
		memberID:  ws.memberID,
		raftTimer: ws.raftTimer,

		watchable: ws.watchable,

		gRPCStream:  stream,
		watchStream: ws.watchable.NewWatchStream(),
		// chan for sending control response like watcher created and canceled.
		ctrlStream: make(chan *pb.WatchResponse, ctrlStreamBufLen),
		progress:   make(map[mvcc.WatchID]bool),
		prevKV:     make(map[mvcc.WatchID]bool),
		closec:     make(chan struct{}),
	}

	sws.wg.Add(1)
	go func() {
		sws.sendLoop()
		sws.wg.Done()
	}()

	errc := make(chan error, 1)
	// Ideally recvLoop would also use sws.wg to signal its completion
	// but when stream.Context().Done() is closed, the stream's recv
	// may continue to block since it uses a different context, leading to
	// deadlock when calling sws.close().
	go func() { errc <- sws.recvLoop() }()

	select {
	case err = <-errc:
	case <-stream.Context().Done():
		err = stream.Context().Err()
		// the only server-side cancellation is noleader for now.
		if err == context.Canceled {
			err = rpctypes.ErrGRPCNoLeader
		}
	}
	sws.close()
	return err
}

func (sws *serverWatchStream) recvLoop() error {
	defer close(sws.ctrlStream)
	for {
		req, err := sws.gRPCStream.Recv()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}

		switch uv := req.RequestUnion.(type) {
		case *pb.WatchRequest_CreateRequest:
			if uv.CreateRequest == nil {
				break
			}

			creq := uv.CreateRequest
			if len(creq.Key) == 0 {
				// \x00 is the smallest key
				creq.Key = []byte{0}
			}
			if len(creq.RangeEnd) == 1 && creq.RangeEnd[0] == 0 {
				// support  >= key queries
				creq.RangeEnd = []byte{}
			}
			filters := make([]mvcc.FilterFunc, 0, len(creq.Filters))
			for _, ft := range creq.Filters {
				switch ft {
				case pb.WatchCreateRequest_NOPUT:
					filters = append(filters, filterNoPut)
				case pb.WatchCreateRequest_NODELETE:
					filters = append(filters, filterNoDelete)
				default:
				}
			}

			wsrev := sws.watchStream.Rev()
			rev := creq.StartRevision
			if rev == 0 {
				rev = wsrev + 1
			}
			id := sws.watchStream.Watch(creq.Key, creq.RangeEnd, rev, filters...)
			if id != -1 {
				if creq.ProgressNotify {
					sws.progress[id] = true
				}
				if creq.PrevKv {
					sws.prevKV[id] = true
				}
			}
			wr := &pb.WatchResponse{
				Header:   sws.newResponseHeader(wsrev),
				WatchId:  int64(id),
				Created:  true,
				Canceled: id == -1,
			}
			select {
			case sws.ctrlStream <- wr:
			case <-sws.closec:
				return nil
			}
		case *pb.WatchRequest_CancelRequest:
			if uv.CancelRequest != nil {
				id := uv.CancelRequest.WatchId
				err := sws.watchStream.Cancel(mvcc.WatchID(id))
				if err == nil {
					sws.ctrlStream <- &pb.WatchResponse{
						Header:   sws.newResponseHeader(sws.watchStream.Rev()),
						WatchId:  id,
						Canceled: true,
					}
					sws.mu.Lock()
					delete(sws.progress, mvcc.WatchID(id))
					delete(sws.prevKV, mvcc.WatchID(id))
					sws.mu.Unlock()
				}
			}
		default:
			// we probably should not shutdown the entire stream when
			// receive an valid command.
			// so just do nothing instead.
			continue
		}
	}
}

func (sws *serverWatchStream) sendLoop() {
	// watch ids that are currently active
	ids := make(map[mvcc.WatchID]struct{})
	// watch responses pending on a watch id creation message
	pending := make(map[mvcc.WatchID][]*pb.WatchResponse)

	interval := GetProgressReportInterval()
	progressTicker := time.NewTicker(interval)

	defer func() {
		progressTicker.Stop()
		// drain the chan to clean up pending events
		for ws := range sws.watchStream.Chan() {
			mvcc.ReportEventReceived(len(ws.Events))
		}
		for _, wrs := range pending {
			for _, ws := range wrs {
				mvcc.ReportEventReceived(len(ws.Events))
			}
		}
	}()

	for {
		select {
		case wresp, ok := <-sws.watchStream.Chan():
			if !ok {
				return
			}

			// TODO: evs is []mvccpb.Event type
			// either return []*mvccpb.Event from the mvcc package
			// or define protocol buffer with []mvccpb.Event.
			evs := wresp.Events
			events := make([]*mvccpb.Event, len(evs))
			needPrevKV := sws.prevKV[wresp.WatchID]
			for i := range evs {
				events[i] = &evs[i]

				if needPrevKV {
					opt := mvcc.RangeOptions{Rev: evs[i].Kv.ModRevision - 1}
					r, err := sws.watchable.Range(evs[i].Kv.Key, nil, opt)
					if err == nil && len(r.KVs) != 0 {
						events[i].PrevKv = &(r.KVs[0])
					}
				}
			}

			wr := &pb.WatchResponse{
				Header:          sws.newResponseHeader(wresp.Revision),
				WatchId:         int64(wresp.WatchID),
				Events:          events,
				CompactRevision: wresp.CompactRevision,
			}

			if _, hasId := ids[wresp.WatchID]; !hasId {
				// buffer if id not yet announced
				wrs := append(pending[wresp.WatchID], wr)
				pending[wresp.WatchID] = wrs
				continue
			}

			mvcc.ReportEventReceived(len(evs))
			if err := sws.gRPCStream.Send(wr); err != nil {
				return
			}

			sws.mu.Lock()
			if _, ok := sws.progress[wresp.WatchID]; ok {
				sws.progress[wresp.WatchID] = false
			}
			sws.mu.Unlock()

		case c, ok := <-sws.ctrlStream:
			if !ok {
				return
			}

			if err := sws.gRPCStream.Send(c); err != nil {
				return
			}

			// track id creation
			wid := mvcc.WatchID(c.WatchId)
			if c.Canceled {
				delete(ids, wid)
				continue
			}
			if c.Created {
				// flush buffered events
				ids[wid] = struct{}{}
				for _, v := range pending[wid] {
					mvcc.ReportEventReceived(len(v.Events))
					if err := sws.gRPCStream.Send(v); err != nil {
						return
					}
				}
				delete(pending, wid)
			}
		case <-progressTicker.C:
			for id, ok := range sws.progress {
				if ok {
					sws.watchStream.RequestProgress(id)
				}
				sws.progress[id] = true
			}
		case <-sws.closec:
			return
		}
	}
}

func (sws *serverWatchStream) close() {
	sws.watchStream.Close()
	close(sws.closec)
	sws.wg.Wait()
}

func (sws *serverWatchStream) newResponseHeader(rev int64) *pb.ResponseHeader {
	return &pb.ResponseHeader{
		ClusterId: uint64(sws.clusterID),
		MemberId:  uint64(sws.memberID),
		Revision:  rev,
		RaftTerm:  sws.raftTimer.Term(),
	}
}

func filterNoDelete(e mvccpb.Event) bool {
	return e.Type == mvccpb.DELETE
}

func filterNoPut(e mvccpb.Event) bool {
	return e.Type == mvccpb.PUT
}
<commit_msg>v3rpc: lock progress and prevKV map correctly<commit_after>// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v3rpc

import (
	"io"
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/coreos/etcd/etcdserver"
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"github.com/coreos/etcd/mvcc"
	"github.com/coreos/etcd/mvcc/mvccpb"
)

type watchServer struct {
	clusterID int64
	memberID  int64
	raftTimer etcdserver.RaftTimer
	watchable mvcc.WatchableKV
}

func NewWatchServer(s *etcdserver.EtcdServer) pb.WatchServer {
	return &watchServer{
		clusterID: int64(s.Cluster().ID()),
		memberID:  int64(s.ID()),
		raftTimer: s,
		watchable: s.Watchable(),
	}
}

var (
	// External test can read this with GetProgressReportInterval()
	// and change this to a small value to finish fast with
	// SetProgressReportInterval().
	progressReportInterval   = 10 * time.Minute
	progressReportIntervalMu sync.RWMutex
)

func GetProgressReportInterval() time.Duration {
	progressReportIntervalMu.RLock()
	defer progressReportIntervalMu.RUnlock()
	return progressReportInterval
}

func SetProgressReportInterval(newTimeout time.Duration) {
	progressReportIntervalMu.Lock()
	defer progressReportIntervalMu.Unlock()
	progressReportInterval = newTimeout
}

const (
	// We send ctrl response inside the read loop. We do not want
	// send to block read, but we still want ctrl response we sent to
	// be serialized. Thus we use a buffered chan to solve the problem.
	// A small buffer should be OK for most cases, since we expect the
	// ctrl requests are infrequent.
	ctrlStreamBufLen = 16
)

// serverWatchStream is an etcd server side stream. It receives requests
// from client side gRPC stream. It receives watch events from mvcc.WatchStream,
// and creates responses that forwarded to gRPC stream.
// It also forwards control message like watch created and canceled.
type serverWatchStream struct {
	clusterID int64
	memberID  int64
	raftTimer etcdserver.RaftTimer

	watchable mvcc.WatchableKV

	gRPCStream  pb.Watch_WatchServer
	watchStream mvcc.WatchStream
	ctrlStream  chan *pb.WatchResponse

	// mu protects progress, prevKV
	mu sync.Mutex
	// progress tracks the watchID that stream might need to send
	// progress to.
	// TOOD: combine progress and prevKV into a single struct?
	progress map[mvcc.WatchID]bool
	prevKV   map[mvcc.WatchID]bool

	// closec indicates the stream is closed.
	closec chan struct{}

	// wg waits for the send loop to complete
	wg sync.WaitGroup
}

func (ws *watchServer) Watch(stream pb.Watch_WatchServer) (err error) {
	sws := serverWatchStream{
		clusterID: ws.clusterID,
		memberID:  ws.memberID,
		raftTimer: ws.raftTimer,

		watchable: ws.watchable,

		gRPCStream:  stream,
		watchStream: ws.watchable.NewWatchStream(),
		// chan for sending control response like watcher created and canceled.
		ctrlStream: make(chan *pb.WatchResponse, ctrlStreamBufLen),
		progress:   make(map[mvcc.WatchID]bool),
		prevKV:     make(map[mvcc.WatchID]bool),
		closec:     make(chan struct{}),
	}

	sws.wg.Add(1)
	go func() {
		sws.sendLoop()
		sws.wg.Done()
	}()

	errc := make(chan error, 1)
	// Ideally recvLoop would also use sws.wg to signal its completion
	// but when stream.Context().Done() is closed, the stream's recv
	// may continue to block since it uses a different context, leading to
	// deadlock when calling sws.close().
	go func() { errc <- sws.recvLoop() }()

	select {
	case err = <-errc:
	case <-stream.Context().Done():
		err = stream.Context().Err()
		// the only server-side cancellation is noleader for now.
		if err == context.Canceled {
			err = rpctypes.ErrGRPCNoLeader
		}
	}
	sws.close()
	return err
}

func (sws *serverWatchStream) recvLoop() error {
	defer close(sws.ctrlStream)
	for {
		req, err := sws.gRPCStream.Recv()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}

		switch uv := req.RequestUnion.(type) {
		case *pb.WatchRequest_CreateRequest:
			if uv.CreateRequest == nil {
				break
			}

			creq := uv.CreateRequest
			if len(creq.Key) == 0 {
				// \x00 is the smallest key
				creq.Key = []byte{0}
			}
			if len(creq.RangeEnd) == 1 && creq.RangeEnd[0] == 0 {
				// support  >= key queries
				creq.RangeEnd = []byte{}
			}
			filters := make([]mvcc.FilterFunc, 0, len(creq.Filters))
			for _, ft := range creq.Filters {
				switch ft {
				case pb.WatchCreateRequest_NOPUT:
					filters = append(filters, filterNoPut)
				case pb.WatchCreateRequest_NODELETE:
					filters = append(filters, filterNoDelete)
				default:
				}
			}

			wsrev := sws.watchStream.Rev()
			rev := creq.StartRevision
			if rev == 0 {
				rev = wsrev + 1
			}
			id := sws.watchStream.Watch(creq.Key, creq.RangeEnd, rev, filters...)
			if id != -1 {
				sws.mu.Lock()
				if creq.ProgressNotify {
					sws.progress[id] = true
				}
				if creq.PrevKv {
					sws.prevKV[id] = true
				}
				sws.mu.Unlock()
			}
			wr := &pb.WatchResponse{
				Header:   sws.newResponseHeader(wsrev),
				WatchId:  int64(id),
				Created:  true,
				Canceled: id == -1,
			}
			select {
			case sws.ctrlStream <- wr:
			case <-sws.closec:
				return nil
			}
		case *pb.WatchRequest_CancelRequest:
			if uv.CancelRequest != nil {
				id := uv.CancelRequest.WatchId
				err := sws.watchStream.Cancel(mvcc.WatchID(id))
				if err == nil {
					sws.ctrlStream <- &pb.WatchResponse{
						Header:   sws.newResponseHeader(sws.watchStream.Rev()),
						WatchId:  id,
						Canceled: true,
					}
					sws.mu.Lock()
					delete(sws.progress, mvcc.WatchID(id))
					delete(sws.prevKV, mvcc.WatchID(id))
					sws.mu.Unlock()
				}
			}
		default:
			// we probably should not shutdown the entire stream when
			// receive an valid command.
			// so just do nothing instead.
			continue
		}
	}
}

func (sws *serverWatchStream) sendLoop() {
	// watch ids that are currently active
	ids := make(map[mvcc.WatchID]struct{})
	// watch responses pending on a watch id creation message
	pending := make(map[mvcc.WatchID][]*pb.WatchResponse)

	interval := GetProgressReportInterval()
	progressTicker := time.NewTicker(interval)

	defer func() {
		progressTicker.Stop()
		// drain the chan to clean up pending events
		for ws := range sws.watchStream.Chan() {
			mvcc.ReportEventReceived(len(ws.Events))
		}
		for _, wrs := range pending {
			for _, ws := range wrs {
				mvcc.ReportEventReceived(len(ws.Events))
			}
		}
	}()

	for {
		select {
		case wresp, ok := <-sws.watchStream.Chan():
			if !ok {
				return
			}

			// TODO: evs is []mvccpb.Event type
			// either return []*mvccpb.Event from the mvcc package
			// or define protocol buffer with []mvccpb.Event.
			evs := wresp.Events
			events := make([]*mvccpb.Event, len(evs))
			sws.mu.Lock()
			needPrevKV := sws.prevKV[wresp.WatchID]
			sws.mu.Unlock()
			for i := range evs {
				events[i] = &evs[i]

				if needPrevKV {
					opt := mvcc.RangeOptions{Rev: evs[i].Kv.ModRevision - 1}
					r, err := sws.watchable.Range(evs[i].Kv.Key, nil, opt)
					if err == nil && len(r.KVs) != 0 {
						events[i].PrevKv = &(r.KVs[0])
					}
				}
			}

			wr := &pb.WatchResponse{
				Header:          sws.newResponseHeader(wresp.Revision),
				WatchId:         int64(wresp.WatchID),
				Events:          events,
				CompactRevision: wresp.CompactRevision,
			}

			if _, hasId := ids[wresp.WatchID]; !hasId {
				// buffer if id not yet announced
				wrs := append(pending[wresp.WatchID], wr)
				pending[wresp.WatchID] = wrs
				continue
			}

			mvcc.ReportEventReceived(len(evs))
			if err := sws.gRPCStream.Send(wr); err != nil {
				return
			}

			sws.mu.Lock()
			if _, ok := sws.progress[wresp.WatchID]; ok {
				sws.progress[wresp.WatchID] = false
			}
			sws.mu.Unlock()

		case c, ok := <-sws.ctrlStream:
			if !ok {
				return
			}

			if err := sws.gRPCStream.Send(c); err != nil {
				return
			}

			// track id creation
			wid := mvcc.WatchID(c.WatchId)
			if c.Canceled {
				delete(ids, wid)
				continue
			}
			if c.Created {
				// flush buffered events
				ids[wid] = struct{}{}
				for _, v := range pending[wid] {
					mvcc.ReportEventReceived(len(v.Events))
					if err := sws.gRPCStream.Send(v); err != nil {
						return
					}
				}
				delete(pending, wid)
			}
		case <-progressTicker.C:
			sws.mu.Lock()
			for id, ok := range sws.progress {
				if ok {
					sws.watchStream.RequestProgress(id)
				}
				sws.progress[id] = true
			}
			sws.mu.Unlock()
		case <-sws.closec:
			return
		}
	}
}

func (sws *serverWatchStream) close() {
	sws.watchStream.Close()
	close(sws.closec)
	sws.wg.Wait()
}

func (sws *serverWatchStream) newResponseHeader(rev int64) *pb.ResponseHeader {
	return &pb.ResponseHeader{
		ClusterId: uint64(sws.clusterID),
		MemberId:  uint64(sws.memberID),
		Revision:  rev,
		RaftTerm:  sws.raftTimer.Term(),
	}
}

func filterNoDelete(e mvccpb.Event) bool {
	return e.Type == mvccpb.DELETE
}

func filterNoPut(e mvccpb.Event) bool {
	return e.Type == mvccpb.PUT
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/garyburd/go-websocket/websocket"
	"github.com/ugorji/go/codec"
	"io/ioutil"
	"strconv"
	"time"
)

const (
	MAX_USERS_PER_LOCATION = 20
	MAX_NICKNAME_LENGTH    = 20
	SEND_CHANNEL_SIZE      = 256
	// Time allowed to write a message to the client.
	WRITE_WAIT = 5 * time.Second
	// Time allowed to read the next message from the client.
	READ_WAIT = 15 * time.Second
	// Send pings to client with this period. Must be less than READ_WAIT.
	PING_PERIOD = (READ_WAIT * 9) / 10
	// Maximum message size allowed from client.
	// must be at least 4 * MAX_CHAT_MESSAGE_LENGTH (in script.js)
	MAX_MESSAGE_SIZE = 1024
)

var (
	userIdGenerator chan int
	msgpackHandle   codec.MsgpackHandle
)

type User struct {
	Socket      *websocket.Conn
	sendData    chan<- *[]byte
	recv        <-chan *[]interface{}
	UserId      int
	Nickname    string
	MouseIsDown bool
	PositionX   int
	PositionY   int
	ColorRed    int
	ColorGreen  int
	ColorBlue   int
	UsePen      bool
	kick        chan string
}

func NewUser(ws *websocket.Conn) *User {
	user := new(User)
	user.Socket = ws
	user.UserId = <-userIdGenerator
	user.Nickname = strconv.Itoa(user.UserId)
	user.UsePen = true
	user.sendData = user.sender()
	user.recv = user.receiver()
	user.kick = make(chan string)
	return user
}

func init() {
	userIdGenerator = make(chan int)
	go func() {
		i := 1
		for {
			userIdGenerator <- i
			i += 1
		}
	}()
}

func encodeEvent(event *[]interface{}) (*[]byte, error) {
	var result []byte
	var err = codec.NewEncoderBytes(&result, &msgpackHandle).Encode(event)
	if err != nil {
		Log.Printf("Failed to encode event %v\n", event)
	}
	return &result, err
}

func (user *User) Kick(description string) {
	select {
	case user.kick <- description:
	default:
		// SocketHandler has already returned, avoid blocking
	}
}

func (user *User) Error(description string) {
	user.SendEvent(&[]interface{}{EventTypeError, description})
	user.Kick(description)
}

func (user *User) SendEvent(event *[]interface{}) {
	data, err := encodeEvent(event)
	if err != nil {
		return
	}
	user.SendData(data)
}

func (user *User) SendData(data *[]byte) {
	select {
	case user.sendData <- data:
	default:
		Log.Printf("Buffer full for user %v: kicking.\n", user.UserId)
		user.Kick("Buffer full")
	}
}

func (user *User) mouseMove(x int, y int, duration int) {
	user.PositionX = x
	user.PositionY = y
}

func (user *User) mouseUp() {
	user.MouseIsDown = false
}

func (user *User) mouseDown() {
	user.MouseIsDown = true
}

func (user *User) changeTool(use_pen bool) {
	user.UsePen = use_pen
}

func (user *User) changeColor(red, green, blue int) {
	user.ColorRed = red
	user.ColorGreen = green
	user.ColorBlue = blue
}

func (user *User) changeNickname(nickname string) {
	user.Nickname = nickname
}

func write(ws *websocket.Conn, opCode int, payload []byte) error {
	ws.SetWriteDeadline(time.Now().Add(WRITE_WAIT))
	return ws.WriteMessage(opCode, payload)
}

func (user *User) sender() chan<- *[]byte {
	ch := make(chan *[]byte, SEND_CHANNEL_SIZE)
	go func() {
		ticker := time.NewTicker(PING_PERIOD)
		defer func() {
			ticker.Stop()
		}()
		for {
			select {
			case data, ok := <-ch:
				if !ok {
					write(user.Socket, websocket.OpClose, []byte{})
					return
				}
				if err := write(user.Socket, websocket.OpBinary, *data); err != nil {
					user.Kick(err.Error())
					return
				}
			case <-ticker.C:
				if err := write(user.Socket, websocket.OpPing, []byte{}); err != nil {
					user.Kick(err.Error())
					return
				}
			}
		}
	}()
	return ch
}

func (user *User) receiver() <-chan *[]interface{} {
	// receives and decodes messages from users
	ch := make(chan *[]interface{})
	go func() {
		user.Socket.SetReadLimit(MAX_MESSAGE_SIZE)
		user.Socket.SetReadDeadline(time.Now().Add(READ_WAIT))
		for {
			op, r, err := user.Socket.NextReader()
			if err != nil {
				user.Kick(err.Error())
				break
			}
			switch op {
			case websocket.OpPong:
				user.Socket.SetReadDeadline(time.Now().Add(READ_WAIT))
			case websocket.OpBinary:
				data, err := ioutil.ReadAll(r)
				if err != nil {
					user.Kick(err.Error())
					break
				}
				var event []interface{}
				err = codec.NewDecoderBytes(data, &msgpackHandle).Decode(&event)
				if err != nil {
					user.Kick(err.Error())
					break
				}
				ch <- &event
			default:
				user.Kick(fmt.Sprintf("bad message type: %v", op))
				break
			}
		}
		close(ch)
	}()
	return ch
}

func (user *User) SocketHandler(location *Location) {
	defer func() {
		if location != nil {
			location.Quit <- user
			Log.Printf("user %v left\n", user.UserId)
		}
	}()
	for {
		select {
		case event, ok := <-user.recv:
			if !ok {
				return
			}
			if location != nil {
				location.Message <- &UserAndEvent{user, event}
			}
		case err_msg := <-user.kick:
			Log.Printf("user %v kicked for '%v'\n", user.UserId, err_msg)
			return
		}
	}
}
<commit_msg>longer timeout<commit_after>package main

import (
	"fmt"
	"github.com/garyburd/go-websocket/websocket"
	"github.com/ugorji/go/codec"
	"io/ioutil"
	"strconv"
	"time"
)

const (
	MAX_USERS_PER_LOCATION = 20
	MAX_NICKNAME_LENGTH    = 20
	SEND_CHANNEL_SIZE      = 256
	// Time allowed to write a message to the client.
	WRITE_WAIT = 5 * time.Second
	// Time allowed to read the next message from the client.
	READ_WAIT = 20 * time.Second
	// Send pings to client with this period. Must be less than READ_WAIT.
	PING_PERIOD = READ_WAIT / 2
	// Maximum message size allowed from client.
	// must be at least 4 * MAX_CHAT_MESSAGE_LENGTH (in script.js)
	MAX_MESSAGE_SIZE = 1024
)

var (
	userIdGenerator chan int
	msgpackHandle   codec.MsgpackHandle
)

type User struct {
	Socket      *websocket.Conn
	sendData    chan<- *[]byte
	recv        <-chan *[]interface{}
	UserId      int
	Nickname    string
	MouseIsDown bool
	PositionX   int
	PositionY   int
	ColorRed    int
	ColorGreen  int
	ColorBlue   int
	UsePen      bool
	kick        chan string
}

func NewUser(ws *websocket.Conn) *User {
	user := new(User)
	user.Socket = ws
	user.UserId = <-userIdGenerator
	user.Nickname = strconv.Itoa(user.UserId)
	user.UsePen = true
	user.sendData = user.sender()
	user.recv = user.receiver()
	user.kick = make(chan string)
	return user
}

func init() {
	userIdGenerator = make(chan int)
	go func() {
		i := 1
		for {
			userIdGenerator <- i
			i += 1
		}
	}()
}

func encodeEvent(event *[]interface{}) (*[]byte, error) {
	var result []byte
	var err = codec.NewEncoderBytes(&result, &msgpackHandle).Encode(event)
	if err != nil {
		Log.Printf("Failed to encode event %v\n", event)
	}
	return &result, err
}

func (user *User) Kick(description string) {
	select {
	case user.kick <- description:
	default:
		// SocketHandler has already returned, avoid blocking
	}
}

func (user *User) Error(description string) {
	user.SendEvent(&[]interface{}{EventTypeError, description})
	user.Kick(description)
}

func (user *User) SendEvent(event *[]interface{}) {
	data, err := encodeEvent(event)
	if err != nil {
		return
	}
	user.SendData(data)
}

func (user *User) SendData(data *[]byte) {
	select {
	case user.sendData <- data:
	default:
		Log.Printf("Buffer full for user %v: kicking.\n", user.UserId)
		user.Kick("Buffer full")
	}
}

func (user *User) mouseMove(x int, y int, duration int) {
	user.PositionX = x
	user.PositionY = y
}

func (user *User) mouseUp() {
	user.MouseIsDown = false
}

func (user *User) mouseDown() {
	user.MouseIsDown = true
}

func (user *User) changeTool(use_pen bool) {
	user.UsePen = use_pen
}

func (user *User) changeColor(red, green, blue int) {
	user.ColorRed = red
	user.ColorGreen = green
	user.ColorBlue = blue
}

func (user *User) changeNickname(nickname string) {
	user.Nickname = nickname
}

func write(ws *websocket.Conn, opCode int, payload []byte) error {
	ws.SetWriteDeadline(time.Now().Add(WRITE_WAIT))
	return ws.WriteMessage(opCode, payload)
}

func (user *User) sender() chan<- *[]byte {
	ch := make(chan *[]byte, SEND_CHANNEL_SIZE)
	go func() {
		ticker := time.NewTicker(PING_PERIOD)
		defer func() {
			ticker.Stop()
		}()
		for {
			select {
			case data, ok := <-ch:
				if !ok {
					write(user.Socket, websocket.OpClose, []byte{})
					return
				}
				if err := write(user.Socket, websocket.OpBinary, *data); err != nil {
					user.Kick(err.Error())
					return
				}
			case <-ticker.C:
				if err := write(user.Socket, websocket.OpPing, []byte{}); err != nil {
					user.Kick(err.Error())
					return
				}
			}
		}
	}()
	return ch
}

func (user *User) receiver() <-chan *[]interface{} {
	// receives and decodes messages from users
	ch := make(chan *[]interface{})
	go func() {
		user.Socket.SetReadLimit(MAX_MESSAGE_SIZE)
		user.Socket.SetReadDeadline(time.Now().Add(READ_WAIT))
		for {
			op, r, err := user.Socket.NextReader()
			if err != nil {
				user.Kick(err.Error())
				break
			}
			switch op {
			case websocket.OpPong:
				user.Socket.SetReadDeadline(time.Now().Add(READ_WAIT))
			case websocket.OpBinary:
				data, err := ioutil.ReadAll(r)
				if err != nil {
					user.Kick(err.Error())
					break
				}
				var event []interface{}
				err = codec.NewDecoderBytes(data, &msgpackHandle).Decode(&event)
				if err != nil {
					user.Kick(err.Error())
					break
				}
				ch <- &event
			default:
				user.Kick(fmt.Sprintf("bad message type: %v", op))
				break
			}
		}
		close(ch)
	}()
	return ch
}

func (user *User) SocketHandler(location *Location) {
	defer func() {
		if location != nil {
			location.Quit <- user
			Log.Printf("user %v left\n", user.UserId)
		}
	}()
	for {
		select {
		case event, ok := <-user.recv:
			if !ok {
				return
			}
			if location != nil {
				location.Message <- &UserAndEvent{user, event}
			}
		case err_msg := <-user.kick:
			Log.Printf("user %v kicked for '%v'\n", user.UserId, err_msg)
			return
		}
	}
}
<|endoftext|>


<commit_before>package zd

type User struct {
	ID        *float64 `json:"id,omitempty"`
	Name      *string  `json:"name,omitempty"`
	Active    *bool    `json:"active,omitempty"`
	CreatedAt *string  `json:"created_at,omitempty"`
	UpdatedAt *string  `json:"updated_at,omitempty"`
	Tags      []string `json:"tags,omitempty"`
}

type UsersResponse struct {
	Users    []User  `json:"users,omitempty"`
	Next     *string `json:"next_page,omitempty"`
	Previous *string `json:"previous_page,omitempty"`
	Count    *int    `json:"count,omitempty"`
}

type UserService struct {
	client *Client
}

func (s *UserService) Get() ([]User, error) {
	var resource []User

	rp, next, _, err := s.getPage("")
	if err != nil {
		return nil, err
	}

	resource = append(resource, rp...)

	for next != nil {
		rp, nx, _, err := s.getPage(*next)
		if err != nil {
			return nil, err
		}
		next = nx
		resource = append(resource, rp...)
	}

	return resource, err
}

func (s *UserService) getPage(url string) ([]User, *string, *Response, error) {

	if url == "" {
		url = "users.json"
	}

	req, err := s.client.NewRequest("GET", url, nil)
	if err != nil {
		return nil, nil, nil, err
	}

	response := new(UsersResponse)
	resp, err := s.client.Do(req, response)
	if err != nil {
		return nil, nil, resp, err
	}

	next := response.Next
	resource := response.Users
	return resource, next, resp, err
}
<commit_msg>more user data<commit_after>package zd

import (
	"time"
)

type User struct {
	ID                   *int                   `json:"id,omitempty"`
	URL                  *string                `json:"url,omitempty"`
	Name                 *string                `json:"name,omitempty"`
	Email                *string                `json:"email,omitempty"`
	CreatedAt            *time.Time             `json:"created_at,omitempty"`
	UpdatedAt            *time.Time             `json:"updated_at,omitempty"`
	TimeZone             *string                `json:"time_zone,omitempty"`
	Phone                *string                `json:"phone,omitempty"`
	Photo                *Photo                 `json:"photo,omitempty"`
	LocaleID             *int                   `json:"locale_id,omitempty"`
	Locale               *string                `json:"locale,omitempty"`
	OrganizationID       *int                   `json:"organization_id,omitempty"`
	Role                 *string                `json:"role,omitempty"`
	Verified             *bool                  `json:"verified,omitempty"`
	ExternalID           *string                `json:"external_id,omitempty"`
	Tags                 []string               `json:"tags,omitempty"`
	Alias                *string                `json:"alias,omitempty"`
	Active               *bool                  `json:"active,omitempty"`
	Shared               *bool                  `json:"shared,omitempty"`
	SharedAgent          *bool                  `json:"shared_agent,omitempty"`
	LastLoginAt          *time.Time             `json:"last_login_at,omitempty"`
	TwoFactorAuthEnabled *bool                  `json:"two_factor_auth_enabled,omitempty"`
	Signature            *string                `json:"signature,omitempty"`
	Details              *string                `json:"details,omitempty"`
	Notes                *string                `json:"notes,omitempty"`
	CustomRoleID         *int                   `json:"custom_role_id,omitempty"`
	Moderator            *bool                  `json:"moderator,omitempty"`
	TicketRestriction    *string                `json:"ticket_restriction,omitempty"`
	OnlyPrivateComments  *bool                  `json:"only_private_comments,omitempty"`
	RestrictedAgent      *bool                  `json:"restricted_agent,omitempty"`
	Suspended            *bool                  `json:"suspended,omitempty"`
	ChatOnly             *bool                  `json:"chat_only,omitempty"`
	UserFields           map[string]interface{} `json:"user_fields,omitempty"`
}

type UserResponse struct {
	Users    []User  `json:"users,omitempty"`
	Next     *string `json:"next_page,omitempty"`
	Previous *string `json:"previous_page,omitempty"`
	Count    *int    `json:"count,omitempty"`
}

type UserService struct {
	client *Client
}

type Photo struct {
	URL              *string     `json:"url,omitempty"`
	ID               *int        `json:"id,omitempty"`
	FileName         *string     `json:"file_name,omitempty"`
	ContentURL       *string     `json:"content_url,omitempty"`
	MappedContentURL *string     `json:"mapped_content_url,omitempty"`
	ContentType      *string     `json:"content_type,omitempty"`
	Size             *int        `json:"size,omitempty"`
	Inline           *bool       `json:"inline,omitempty"`
	Thumbnails       []Thumbnail `json:"thumbnails,omitempty"`
}

type Thumbnail struct {
	URL              *string `json:"url,omitempty"`
	ID               *int    `json:"id,omitempty"`
	FileName         *string `json:"file_name,omitempty"`
	ContentURL       *string `json:"content_url,omitempty"`
	MappedContentURL *string `json:"mapped_content_url,omitempty"`
	ContentType      *string `json:"content_type,omitempty"`
	Size             *int    `json:"size,omitempty"`
	Inline           *bool   `json:"inline,omitempty"`
}

func (s *UserService) Get() ([]User, error) {
	var resource []User

	rp, next, _, err := s.getPage("")
	if err != nil {
		return nil, err
	}

	resource = append(resource, rp...)

	for next != nil {
		rp, nx, _, err := s.getPage(*next)
		if err != nil {
			return nil, err
		}
		next = nx
		resource = append(resource, rp...)
	}

	return resource, err
}

func (s *UserService) getPage(url string) ([]User, *string, *Response, error) {

	if url == "" {
		url = "users.json"
	}

	req, err := s.client.NewRequest("GET", url, nil)
	if err != nil {
		return nil, nil, nil, err
	}

	response := new(UserResponse)
	resp, err := s.client.Do(req, response)
	if err != nil {
		return nil, nil, resp, err
	}

	next := response.Next
	resource := response.Users
	return resource, next, resp, err
}
<|endoftext|>


<commit_before>package wildcard

func SplitPattern(path string) []string {
	return []string{}
}

func NormalizePattern(tokens []string) []string {
	return tokens
}
<commit_msg>wildcard: SplitPattern<commit_after>package wildcard

const PATH_SEPARATOR rune = '/'

/**
  Split pattern with saving slashes.

  @param pattern Path pattern.
  @return Path pattern items.
*/
func SplitPattern(path string) []string {
	result := []string{}
	start := 0
	for i, c := range path {
		if c == PATH_SEPARATOR {
			result = append(result, path[start:i+1])
			start = i + 1
		}
	}
	if start != len(path) {
		result = append(result, path[start:])
	}
	return result
}

func NormalizePattern(tokens []string) []string {
	return tokens
}
<|endoftext|>


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

package tikv

import (
	"github.com/pingcap/errors"
	"github.com/pingcap/parser/mysql"
	"github.com/pingcap/parser/terror"
)

var (
	// ErrBodyMissing response body is missing error
	ErrBodyMissing = errors.New("response body is missing")
)

// mismatchClusterID represents the message that the cluster ID of the PD client does not match the PD.
const mismatchClusterID = "mismatch cluster id"

// TiDB decides whether to retry transaction by checking if error message contains
// string "try again later" literally.
// In TiClient we use `errors.Annotate(err, txnRetryableMark)` to direct TiDB to
// restart a transaction.
// Note that it should be only used if i) the error occurs inside a transaction
// and ii) the error is not totally unexpected and hopefully will recover soon.
const txnRetryableMark = "[try again later]"

// MySQL error instances.
var (
	ErrTiKVServerTimeout  = terror.ClassTiKV.New(mysql.ErrTiKVServerTimeout, mysql.MySQLErrName[mysql.ErrTiKVServerTimeout]+txnRetryableMark)
	ErrResolveLockTimeout = terror.ClassTiKV.New(mysql.ErrResolveLockTimeout, mysql.MySQLErrName[mysql.ErrResolveLockTimeout]+txnRetryableMark)
	ErrPDServerTimeout    = terror.ClassTiKV.New(mysql.ErrPDServerTimeout, mysql.MySQLErrName[mysql.ErrPDServerTimeout]+"%v")
	ErrRegionUnavailable  = terror.ClassTiKV.New(mysql.ErrRegionUnavailable, mysql.MySQLErrName[mysql.ErrRegionUnavailable]+txnRetryableMark)
	ErrTiKVServerBusy     = terror.ClassTiKV.New(mysql.ErrTiKVServerBusy, mysql.MySQLErrName[mysql.ErrTiKVServerBusy]+txnRetryableMark)
	ErrGCTooEarly         = terror.ClassTiKV.New(mysql.ErrGCTooEarly, mysql.MySQLErrName[mysql.ErrGCTooEarly])
)

func init() {
	tikvMySQLErrCodes := map[terror.ErrCode]uint16{
		mysql.ErrTiKVServerTimeout:   mysql.ErrTiKVServerTimeout,
		mysql.ErrResolveLockTimeout:  mysql.ErrResolveLockTimeout,
		mysql.ErrPDServerTimeout:     mysql.ErrPDServerTimeout,
		mysql.ErrRegionUnavailable:   mysql.ErrRegionUnavailable,
		mysql.ErrTiKVServerBusy:      mysql.ErrTiKVServerBusy,
		mysql.ErrGCTooEarly:          mysql.ErrGCTooEarly,
		mysql.ErrTruncatedWrongValue: mysql.ErrTruncatedWrongValue,
	}
	terror.ErrClassToMySQLCodes[terror.ClassTiKV] = tikvMySQLErrCodes
}
<commit_msg>add a space to error messages (#10241)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package tikv

import (
	"github.com/pingcap/errors"
	"github.com/pingcap/parser/mysql"
	"github.com/pingcap/parser/terror"
)

var (
	// ErrBodyMissing response body is missing error
	ErrBodyMissing = errors.New("response body is missing")
)

// mismatchClusterID represents the message that the cluster ID of the PD client does not match the PD.
const mismatchClusterID = "mismatch cluster id"

// TiDB decides whether to retry transaction by checking if error message contains
// string "try again later" literally.
// In TiClient we use `errors.Annotate(err, txnRetryableMark)` to direct TiDB to
// restart a transaction.
// Note that it should be only used if i) the error occurs inside a transaction
// and ii) the error is not totally unexpected and hopefully will recover soon.
const txnRetryableMark = "[try again later]"

// MySQL error instances.
var (
	ErrTiKVServerTimeout  = terror.ClassTiKV.New(mysql.ErrTiKVServerTimeout, mysql.MySQLErrName[mysql.ErrTiKVServerTimeout]+" "+txnRetryableMark)
	ErrResolveLockTimeout = terror.ClassTiKV.New(mysql.ErrResolveLockTimeout, mysql.MySQLErrName[mysql.ErrResolveLockTimeout]+" "+txnRetryableMark)
	ErrPDServerTimeout    = terror.ClassTiKV.New(mysql.ErrPDServerTimeout, mysql.MySQLErrName[mysql.ErrPDServerTimeout]+" %v")
	ErrRegionUnavailable  = terror.ClassTiKV.New(mysql.ErrRegionUnavailable, mysql.MySQLErrName[mysql.ErrRegionUnavailable]+" "+txnRetryableMark)
	ErrTiKVServerBusy     = terror.ClassTiKV.New(mysql.ErrTiKVServerBusy, mysql.MySQLErrName[mysql.ErrTiKVServerBusy]+" "+txnRetryableMark)
	ErrGCTooEarly         = terror.ClassTiKV.New(mysql.ErrGCTooEarly, mysql.MySQLErrName[mysql.ErrGCTooEarly])
)

func init() {
	tikvMySQLErrCodes := map[terror.ErrCode]uint16{
		mysql.ErrTiKVServerTimeout:   mysql.ErrTiKVServerTimeout,
		mysql.ErrResolveLockTimeout:  mysql.ErrResolveLockTimeout,
		mysql.ErrPDServerTimeout:     mysql.ErrPDServerTimeout,
		mysql.ErrRegionUnavailable:   mysql.ErrRegionUnavailable,
		mysql.ErrTiKVServerBusy:      mysql.ErrTiKVServerBusy,
		mysql.ErrGCTooEarly:          mysql.ErrGCTooEarly,
		mysql.ErrTruncatedWrongValue: mysql.ErrTruncatedWrongValue,
	}
	terror.ErrClassToMySQLCodes[terror.ClassTiKV] = tikvMySQLErrCodes
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"

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

type SimpleChaincode struct {
}

func main() {
	err := shim.Start(new(SimpleChaincode))

	if err != nil {
		//do nothing
	}
}

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	//added by chenlin@20170308
	if len(args) != 0 {
		return nil, errors.New("incorrect args")
	}
	adminCert, err := stub.GetCallerMetadata()
	if err != nil {
		return nil, errors.New("failed getting metadata")
	}
	if len(adminCert) == 0 {
		return nil, errors.New("invalid admin certificate. Empty")
	}
	stub.PutState("admin", adminCert)
	return nil, nil
}

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	switch function {
	case "putState":
		if len(args) != 2 {
			return nil, errors.New("incorrect args")
		}
		key := args[0]
		value := []byte(args[1])
		err := stub.PutState(key, value)
		if err != nil {
			return nil, err
		}
		return value, err
	case "delState":
		if len(args) != 1 {
			return nil, errors.New("incorrect args")
		}
		key := args[0]
		err := stub.DelState(key)
		if err != nil {
			return nil, err
		}
		result := key + "has been deleted"
		return []byte(result), err

	case "createTable":
		err := stub.CreateTable("AssetsOwnership", []*shim.ColumnDefinition{
			&shim.ColumnDefinition{Name: "Asset", Type: shim.ColumnDefinition_STRING, Key: true},
			&shim.ColumnDefinition{Name: "Owner", Type: shim.ColumnDefinition_BYTES, Key: false},
		})
		if err != nil {
			return nil, errors.New("Failed creating AssetsOnwership table.")
		}
		return nil, nil
	}

	return nil, nil
}

func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	switch function {
	case "getTxID":
		txID := stub.GetTxID()
		result := []byte(txID)
		return result, nil
	case "getTxTimestamp":
		time, err := stub.GetTxTimestamp()
		result := []byte(time.String()) //时间转换为字符串，time.String()
		return result, err
	case "getStringArgs":
		strList := stub.GetStringArgs()
		var result string
		for index := 0; index < len(strList); index++ {
			result += "***" + strList[index] + "***"
		}
		return []byte(result), nil

	case "getState":
		if len(args) != 1 {
			return nil, errors.New("incorrect args")
		}
		key := args[0]
		result, err := stub.GetState(key)

		if err != nil {
			return nil, errors.New("Failed in function getState")
		}
		return result, err

	case "getCallerCert":
		if len(args) != 0 {
			return nil, errors.New("incorrect args")
		}
		result, err := stub.GetCallerCertificate()
		if err != nil {
			return nil, errors.New("Failed in function getCallerCert")
		}
		return result, err

	case "getCallerMetadata":
		if len(args) != 0 {
			return nil, errors.New("incorrect args")
		}
		result, err := stub.GetCallerMetadata()
		if err != nil {
			return nil, errors.New("Failed in function getCallerMetadata")
		}
		fmt.Println(result)
		return result, err
		// return []byte("getCallerMetadata"), err
	case "getBinding":
		if len(args) != 0 {
			return nil, errors.New("incorrect args")
		}
		result, err := stub.GetBinding()

		if err != nil {
			return nil, errors.New("Failed in function getBinding")
		}
		fmt.Println(result)
		return result, err
		// return []byte("getBinding"), err
	case "getPayload":
		if len(args) != 0 {
			return nil, errors.New("incorrect args")
		}
		result, err := stub.GetPayload()

		if err != nil {
			return nil, errors.New("Failed in function getPayload")
		}
		fmt.Println(result)
		return result, err
		// return []byte("getPayload"), err
	}

	return nil, nil
}
<commit_msg>rollback init()<commit_after>package main

import (
	"errors"
	"fmt"

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

type SimpleChaincode struct {
}

func main() {
	err := shim.Start(new(SimpleChaincode))

	if err != nil {
		//do nothing
	}
}

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	//added by chenlin@20170308
	// if len(args) != 0 {
	// 	return nil, errors.New("incorrect args")
	// }
	// adminCert, err := stub.GetCallerMetadata()
	// if err != nil {
	// 	return nil, errors.New("failed getting metadata")
	// }
	// if len(adminCert) == 0 {
	// 	return nil, errors.New("invalid admin certificate. Empty")
	// }
	// stub.PutState("admin", adminCert)
	return nil, nil
}

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	switch function {
	case "putState":
		if len(args) != 2 {
			return nil, errors.New("incorrect args")
		}
		key := args[0]
		value := []byte(args[1])
		err := stub.PutState(key, value)
		if err != nil {
			return nil, err
		}
		return value, err
	case "delState":
		if len(args) != 1 {
			return nil, errors.New("incorrect args")
		}
		key := args[0]
		err := stub.DelState(key)
		if err != nil {
			return nil, err
		}
		result := key + "has been deleted"
		return []byte(result), err

	case "createTable":
		err := stub.CreateTable("AssetsOwnership", []*shim.ColumnDefinition{
			&shim.ColumnDefinition{Name: "Asset", Type: shim.ColumnDefinition_STRING, Key: true},
			&shim.ColumnDefinition{Name: "Owner", Type: shim.ColumnDefinition_BYTES, Key: false},
		})
		if err != nil {
			return nil, errors.New("Failed creating AssetsOnwership table.")
		}
		return nil, nil
	}

	return nil, nil
}

func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	switch function {
	case "getTxID":
		txID := stub.GetTxID()
		result := []byte(txID)
		return result, nil
	case "getTxTimestamp":
		time, err := stub.GetTxTimestamp()
		result := []byte(time.String()) //时间转换为字符串，time.String()
		return result, err
	case "getStringArgs":
		strList := stub.GetStringArgs()
		var result string
		for index := 0; index < len(strList); index++ {
			result += "***" + strList[index] + "***"
		}
		return []byte(result), nil

	case "getState":
		if len(args) != 1 {
			return nil, errors.New("incorrect args")
		}
		key := args[0]
		result, err := stub.GetState(key)

		if err != nil {
			return nil, errors.New("Failed in function getState")
		}
		return result, err

	case "getCallerCert":
		if len(args) != 0 {
			return nil, errors.New("incorrect args")
		}
		result, err := stub.GetCallerCertificate()
		if err != nil {
			return nil, errors.New("Failed in function getCallerCert")
		}
		return result, err

	case "getCallerMetadata":
		if len(args) != 0 {
			return nil, errors.New("incorrect args")
		}
		result, err := stub.GetCallerMetadata()
		if err != nil {
			return nil, errors.New("Failed in function getCallerMetadata")
		}
		fmt.Println(result)
		return result, err
		// return []byte("getCallerMetadata"), err
	case "getBinding":
		if len(args) != 0 {
			return nil, errors.New("incorrect args")
		}
		result, err := stub.GetBinding()

		if err != nil {
			return nil, errors.New("Failed in function getBinding")
		}
		fmt.Println(result)
		return result, err
		// return []byte("getBinding"), err
	case "getPayload":
		if len(args) != 0 {
			return nil, errors.New("incorrect args")
		}
		result, err := stub.GetPayload()

		if err != nil {
			return nil, errors.New("Failed in function getPayload")
		}
		fmt.Println(result)
		return result, err
		// return []byte("getPayload"), err
	}

	return nil, nil
}
<|endoftext|>


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

// Package leaktest provides tools to detect leaked goroutines in tests.
// To use it, call "defer leaktest.AfterTest(t)()" at the beginning of each
// test that may use goroutines.
package leaktest

import (
	"runtime"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/util/timeutil"
)

// interestingGoroutines returns all goroutines we care about for the purpose
// of leak checking. It excludes testing or runtime ones.
func interestingGoroutines() (gs []string) {
	buf := make([]byte, 2<<20)
	buf = buf[:runtime.Stack(buf, true)]
	for _, g := range strings.Split(string(buf), "\n\n") {
		sl := strings.SplitN(g, "\n", 2)
		if len(sl) != 2 {
			continue
		}
		stack := strings.TrimSpace(sl[1])
		if strings.HasPrefix(stack, "testing.RunTests") {
			continue
		}

		if stack == "" ||
			strings.Contains(stack, "github.com/cockroachdb/cockroach/util/log.init") ||
			// Below are the stacks ignored by the upstream leaktest code.
			strings.Contains(stack, "testing.Main(") ||
			strings.Contains(stack, "runtime.goexit") ||
			strings.Contains(stack, "created by runtime.gc") ||
			strings.Contains(stack, "interestingGoroutines") ||
			strings.Contains(stack, "runtime.MHeap_Scavenger") ||
			strings.Contains(stack, "signal.signal_recv") ||
			strings.Contains(stack, "sigterm.handler") ||
			strings.Contains(stack, "runtime_mcall") ||
			strings.Contains(stack, "goroutine in C code") {
			continue
		}
		gs = append(gs, g)
	}
	sort.Strings(gs)
	return
}

// AfterTest snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func AfterTest(t testing.TB) func() {
	orig := map[string]bool{}
	for _, g := range interestingGoroutines() {
		orig[g] = true
	}
	return func() {
		if t.Failed() {
			return
		}
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := timeutil.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for _, g := range interestingGoroutines() {
				if !orig[g] {
					leaked = append(leaked, g)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if timeutil.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
<commit_msg>util/leaktest: ignore new go1.7 testing goroutine<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package leaktest provides tools to detect leaked goroutines in tests.
// To use it, call "defer leaktest.AfterTest(t)()" at the beginning of each
// test that may use goroutines.
package leaktest

import (
	"runtime"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/util/timeutil"
)

// interestingGoroutines returns all goroutines we care about for the purpose
// of leak checking. It excludes testing or runtime ones.
func interestingGoroutines() (gs []string) {
	buf := make([]byte, 2<<20)
	buf = buf[:runtime.Stack(buf, true)]
	for _, g := range strings.Split(string(buf), "\n\n") {
		sl := strings.SplitN(g, "\n", 2)
		if len(sl) != 2 {
			continue
		}
		stack := strings.TrimSpace(sl[1])
		if strings.HasPrefix(stack, "testing.RunTests") {
			continue
		}

		if stack == "" ||
			strings.Contains(stack, "github.com/cockroachdb/cockroach/util/log.init") ||
			// Below are the stacks ignored by the upstream leaktest code.
			strings.Contains(stack, "testing.Main(") ||
			strings.Contains(stack, "testing.tRunner(") ||
			strings.Contains(stack, "runtime.goexit") ||
			strings.Contains(stack, "created by runtime.gc") ||
			strings.Contains(stack, "interestingGoroutines") ||
			strings.Contains(stack, "runtime.MHeap_Scavenger") ||
			strings.Contains(stack, "signal.signal_recv") ||
			strings.Contains(stack, "sigterm.handler") ||
			strings.Contains(stack, "runtime_mcall") ||
			strings.Contains(stack, "goroutine in C code") {
			continue
		}
		gs = append(gs, g)
	}
	sort.Strings(gs)
	return
}

// AfterTest snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func AfterTest(t testing.TB) func() {
	orig := map[string]bool{}
	for _, g := range interestingGoroutines() {
		orig[g] = true
	}
	return func() {
		if t.Failed() {
			return
		}
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := timeutil.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for _, g := range interestingGoroutines() {
				if !orig[g] {
					leaked = append(leaked, g)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if timeutil.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
<|endoftext|>