<commit_before>package main

import (
	"fmt"
	glfw "github.com/go-gl/glfw3"
	"github.com/tedsta/gosfml"
)

var (
	window           *glfw.Window
	target           *sf.RenderTarget
	p1, p2, ball     *Object
	p1Score, p2Score int
)

func main() {
	window, err := glfw.CreateWindow(800, 600, "Golang SFML Pong", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()
	window.SetFramebufferSizeCallback(onResize)
	window.SetKeyCallback(onKey)

	target = sf.NewRenderTarget(sf.Vector2{float32(800), float32(600)})

	p1 = NewObject(5, 5, 16, 64)
	p2 = NewObject(795-16, 5, 16, 64)
	ball = NewObject(400-8, 300-8, 16, 16)

	ball.vel = sf.Vector2{300, 300}

	clock := sf.NewClock()
	for !window.ShouldClose() {
		glfw.PollEvents()

		dt := float32(clock.Restart().Seconds())

		if ball.pos.X < 0 {
			ball.vel.X = 300
			p2Score++
			fmt.Println("Player 1: ", p1Score)
			fmt.Println("Player 2: ", p2Score)
			fmt.Println()
		}
		if ball.pos.X+ball.dim.X >= 800 {
			ball.vel.X = -300
			p1Score++
			fmt.Println("Player 1: ", p1Score)
			fmt.Println("Player 2: ", p2Score)
			fmt.Println()
		}
		if ball.pos.Y < 0 {
			ball.vel.Y = 300
		}
		if ball.pos.Y+ball.dim.Y >= 600 {
			ball.vel.Y = -300
		}

		if p1.Collision(ball) {
			ball.vel.X = 300
		}
		if p2.Collision(ball) {
			ball.vel.X = -300
		}

		p1.pos.X += p1.vel.X * dt
		p1.pos.Y += p1.vel.Y * dt
		p2.pos.X += p2.vel.X * dt
		p2.pos.Y += p2.vel.Y * dt
		ball.pos.X += ball.vel.X * dt
		ball.pos.Y += ball.vel.Y * dt

		// Render
		target.Clear(sf.Color{0, 0, 0, 0})
		p1.Render()
		p2.Render()
		ball.Render()
		window.SwapBuffers()
	}
}

// #############################################################################
// Object

type Object struct {
	pos sf.Vector2
	dim sf.Vector2
	vel sf.Vector2
}

func NewObject(x, y, w, h float32) *Object {
	return &Object{sf.Vector2{x, y}, sf.Vector2{w, h}, sf.Vector2{}}
}

func (o *Object) Collision(o2 *Object) bool {
	if o.pos.X+o.dim.X >= o2.pos.X && o.pos.X <= o2.pos.X+o2.dim.X &&
		o.pos.Y+o.dim.Y >= o2.pos.Y && o.pos.Y <= o2.pos.Y+o2.dim.Y {
		return true
	}
	return false
}

func (o *Object) Render() {
	var verts [4]sf.Vertex
	verts[0] = sf.Vertex{sf.Vector2{},
		sf.Color{255, 255, 255, 255},
		sf.Vector2{}}
	verts[1] = sf.Vertex{sf.Vector2{0, o.dim.Y},
		sf.Color{255, 255, 255, 255},
		sf.Vector2{0, o.dim.Y}}
	verts[2] = sf.Vertex{o.dim,
		sf.Color{255, 255, 255, 255},
		o.dim}
	verts[3] = sf.Vertex{sf.Vector2{o.dim.X, 0},
		sf.Color{255, 255, 255, 255},
		sf.Vector2{o.dim.X, 0}}

	states := sf.RenderStates{sf.BlendAlpha, sf.IdentityTransform(), nil}
	states.Transform.Translate(o.pos)
	target.Render(verts[:], sf.Quads, states)
}

// #############################################################################
// Callbacks

func onResize(wnd *glfw.Window, w, h int) {
	target.Size.X = float32(w)
	target.Size.Y = float32(h)
}

func onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if action == glfw.Press {
		switch key {
		case glfw.KeyW:
			p1.vel.Y = -300
		case glfw.KeyS:
			p1.vel.Y = 300
		case glfw.KeyUp:
			p2.vel.Y = -300
		case glfw.KeyDown:
			p2.vel.Y = 300
		}
	} else if action == glfw.Release {
		switch key {
		case glfw.KeyW, glfw.KeyS:
			p1.vel.Y = 0
		case glfw.KeyUp, glfw.KeyDown:
			p2.vel.Y = 0
		}
	}
}
<commit_msg>for issue 5 github.com/tedsta/gosfml/issues/5<commit_after>package main

import (
	"fmt"
	glfw "github.com/go-gl/glfw3"
	"github.com/tedsta/gosfml"
)

var (
	window           *glfw.Window
	target           *sf.RenderTarget
	p1, p2, ball     *Object
	p1Score, p2Score int
)

func main() {
	window, err := glfw.CreateWindow(800, 600, "Golang SFML Pong", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()
	window.SetFramebufferSizeCallback(onResize)
	window.SetKeyCallback(onKey)

	target = sf.NewRenderTarget(sf.Vector2{float32(800), float32(600)})

	p1 = NewObject(5, 5, 16, 64)
	p2 = NewObject(795-16, 5, 16, 64)
	ball = NewObject(400-8, 300-8, 16, 16)

	ball.vel = sf.Vector2{300, 300}

	clock := sf.NewClock()
	for !window.ShouldClose() {
		glfw.PollEvents()

		dt := float32(clock.Restart().Seconds())

		if ball.pos.X < 0 {
			ball.vel.X = 300
			p2Score++
			fmt.Println("Player 1: ", p1Score)
			fmt.Println("Player 2: ", p2Score)
			fmt.Println()
		}
		if ball.pos.X+ball.dim.X >= 800 {
			ball.vel.X = -300
			p1Score++
			fmt.Println("Player 1: ", p1Score)
			fmt.Println("Player 2: ", p2Score)
			fmt.Println()
		}
		if ball.pos.Y < 0 {
			ball.vel.Y = 300
		}
		if ball.pos.Y+ball.dim.Y >= 600 {
			ball.vel.Y = -300
		}

		if p1.Collision(ball) {
			ball.vel.X = 300
		}
		if p2.Collision(ball) {
			ball.vel.X = -300
		}

		p1.pos.X += p1.vel.X * dt
		p1.pos.Y += p1.vel.Y * dt
		p2.pos.X += p2.vel.X * dt
		p2.pos.Y += p2.vel.Y * dt
		ball.pos.X += ball.vel.X * dt
		ball.pos.Y += ball.vel.Y * dt

		// Render
		target.Clear(sf.Color{0, 0, 0, 0})
		p1.Render()
		p2.Render()
		ball.Render()
		window.SwapBuffers()
	}
}

// #############################################################################
// Object

type Object struct {
	pos sf.Vector2
	dim sf.Vector2
	vel sf.Vector2
}

func NewObject(x, y, w, h float32) *Object {
	return &Object{sf.Vector2{x, y}, sf.Vector2{w, h}, sf.Vector2{}}
}

func (o *Object) Collision(o2 *Object) bool {
	if o.pos.X+o.dim.X >= o2.pos.X && o.pos.X <= o2.pos.X+o2.dim.X &&
		o.pos.Y+o.dim.Y >= o2.pos.Y && o.pos.Y <= o2.pos.Y+o2.dim.Y {
		return true
	}
	return false
}

func (o *Object) Render() {
	var verts [4]sf.Vertex
	verts[0] = sf.Vertex{sf.Vector2{},
		sf.Color{255, 255, 255, 255},
		sf.Vector2{}}
	verts[1] = sf.Vertex{sf.Vector2{0, o.dim.Y},
		sf.Color{255, 255, 255, 255},
		sf.Vector2{0, o.dim.Y}}
	verts[2] = sf.Vertex{o.dim,
		sf.Color{255, 255, 255, 255},
		o.dim}
	verts[3] = sf.Vertex{sf.Vector2{o.dim.X, 0},
		sf.Color{255, 255, 255, 255},
		sf.Vector2{o.dim.X, 0}}

	states := sf.RenderStates{sf.BlendAlpha, sf.IdentityTransform(), nil}
	states.Transform.Translate(o.pos)
	target.Render(verts[:], sf.Quads, states)
}

// #############################################################################
// Callbacks

func onResize(wnd *glfw.Window, w, h int) {
         tmp1 := target.Size()
         tmp1.X = float32(w)
         tmp1.Y = float32(h)

	//target.Size.X = float32(w)
	//target.Size.Y = float32(h)
}

func onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if action == glfw.Press {
		switch key {
		case glfw.KeyW:
			p1.vel.Y = -300
		case glfw.KeyS:
			p1.vel.Y = 300
		case glfw.KeyUp:
			p2.vel.Y = -300
		case glfw.KeyDown:
			p2.vel.Y = 300
		}
	} else if action == glfw.Release {
		switch key {
		case glfw.KeyW, glfw.KeyS:
			p1.vel.Y = 0
		case glfw.KeyUp, glfw.KeyDown:
			p2.vel.Y = 0
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const BaseUrl string = "https://mandrillapp.com/api/1.0/"
const SendEndpoint string = "messages/send.json"

type Configuration struct {
	Host     string
	Port     int
	Username string
	Password string
}

type Email struct {
	Key     string  `json:"key"`
	Message Message `json:"message"`
}

type Message struct {
	Html        string       `json:"html"`
	Text        string       `json:"text"`
	Subject     string       `json:"subject"`
	FromEmail   string       `json:"from_email"`
	FromName    string       `json:"from_name"`
	To          []To         `json:"to"`
	Attachments []Attachment `json:"attachments"`
}

type Attachment struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}

type To struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Type  string `json:"type"`
}

func getConfiguration() Configuration {
	file, _ := os.Open("configuration.json")
	decoder := json.NewDecoder(file)
	configuration := &Configuration{}
	decoder.Decode(&configuration)
	return *configuration
}

func createAttachment(mime, name, filepath string) Attachment {
	file, err := ioutil.ReadFile(filepath)
	if err != nil {
		panic(err)
	}
	content := base64.URLEncoding.EncodeToString(file)
	attachment := Attachment{
		Type:    mime,
		Name:    name,
		Content: content,
	}
	return attachment
}

func main() {
	configuration := getConfiguration()

	attachments := make([]Attachment, 1)
	attachment := createAttachment("text/plain", "mailchimp.go", "mailchimp.go")

	if len(os.Args) != 2 {
		os.Stderr.Write([]byte("Not enough arguments\n"))
		os.Stderr.Write([]byte(fmt.Sprintf("usage: %s email\n", os.Args[0])))
		return
	}

	recipients := make([]To, 1)
	recipient := To{
		Email: os.Args[1],
		Name:  "Mailchimp",
		Type:  "to",
	}

	message := Message{
		Html:        "Hey there, here is my Go code that uses the Mandrill API to send itself as an attachment in this email. I'm sending this as an application for your Software Engineer Intern position. The code for this can also be found on my Github at github.com/dkua/mandrill_application. Cheers!",
		Text:        "Hey there, here is my Go code that uses the Mandrill API to send itself as an attachment in this email. I'm sending this as an application for your Software Engineer Intern position. The code for this can also be found on my Github at github.com/dkua/mandrill_application. Cheers!",
		Subject:     "Code Sample - David Kua",
		FromEmail:   configuration.Username,
		To:          append(recipients, recipient),
		Attachments: append(attachments, attachment),
	}

	email := Email{
		Key:     configuration.Password,
		Message: message,
	}

	content, err := json.Marshal(email)
	if err != nil {
		fmt.Println("Error:", err)
	}
	fmt.Println(string(content))
	resp, err := http.Post(BaseUrl+SendEndpoint, "application/json", bytes.NewBuffer(content))
	if err != nil {
		fmt.Println("Error:", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}
	fmt.Printf("%s\n", string(contents))
}
<commit_msg>Fixed formating of emails.<commit_after>package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const BaseUrl string = "https://mandrillapp.com/api/1.0/"
const SendEndpoint string = "messages/send.json"

type Configuration struct {
	Host     string
	Port     int
	Username string
	Password string
}

type Email struct {
	Key     string  `json:"key"`
	Message Message `json:"message"`
}

type Message struct {
	Html        string       `json:"html"`
	Text        string       `json:"text"`
	Subject     string       `json:"subject"`
	FromEmail   string       `json:"from_email"`
	FromName    string       `json:"from_name"`
	To          []To         `json:"to"`
	Attachments []Attachment `json:"attachments"`
}

type Attachment struct {
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}

type To struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Type  string `json:"type"`
}

func getConfiguration() Configuration {
	file, _ := os.Open("configuration.json")
	decoder := json.NewDecoder(file)
	configuration := &Configuration{}
	decoder.Decode(&configuration)
	return *configuration
}

func createAttachment(mime, name, filepath string) Attachment {
	file, err := ioutil.ReadFile(filepath)
	if err != nil {
		panic(err)
	}
	content := base64.URLEncoding.EncodeToString(file)
	attachment := Attachment{
		Type:    mime,
		Name:    name,
		Content: content,
	}
	return attachment
}

func main() {
	configuration := getConfiguration()

	attachments := make([]Attachment, 1)
	attachment := createAttachment("text/plain", "mailchimp.go", "mailchimp.go")

	if len(os.Args) != 2 {
		os.Stderr.Write([]byte("Not enough arguments\n"))
		os.Stderr.Write([]byte(fmt.Sprintf("usage: %s email\n", os.Args[0])))
		return
	}

	recipients := make([]To, 1)
	recipient := To{
		Email: os.Args[1],
		Name:  "Mailchimp",
		Type:  "to",
	}

	message := Message{
		Html:        "Hey there,

Here is my Go code that uses the Mandrill API to send itself as an attachment in this email. I'm sending this as an application for your Software Engineer Intern position. The code for this can also be found on my Github at github.com/dkua/mailchimp_application.

Cheers!
",
		Text:        "Hey there,\nHere is my Go code that uses the Mandrill API to send itself as an attachment in this email. I'm sending this as an application for your Software Engineer Intern position. The code for this can also be found on my Github at github.com/dkua/mailchimp_application.\nCheers!",
		Subject:     "Code Sample - David Kua",
		FromEmail:   configuration.Username,
		To:          append(recipients, recipient),
		Attachments: append(attachments, attachment),
	}

	email := Email{
		Key:     configuration.Password,
		Message: message,
	}

	content, err := json.Marshal(email)
	if err != nil {
		fmt.Println("Error:", err)
	}
	fmt.Println(string(content))
	resp, err := http.Post(BaseUrl+SendEndpoint, "application/json", bytes.NewBuffer(content))
	if err != nil {
		fmt.Println("Error:", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	}
	fmt.Println(string(contents))
}
<|endoftext|>


<commit_before>// Package gostrftime formats time.Time using strftime(3) conventions.
package gostrftime

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"
	"time"
)

func strftime(b *bytes.Buffer, c rune, t time.Time) error {
	switch c {
	case 'A':
		b.WriteString(t.Weekday().String())
	case 'a':
		b.WriteString(t.Weekday().String()[:3])
	case 'B':
		b.WriteString(t.Month().String())
	case 'b':
		b.WriteString(t.Month().String()[:3])
	case 'C':
		fmt.Fprintf(b, "%02d", t.Year())
	case 'D':
		y, m, d := t.Date()
		fmt.Fprintf(b, "%02d/%02d/%02d", m, d, y%100)
	case 'd':
		fmt.Fprintf(b, "%02d", t.Day())
	case 'e':
		fmt.Fprintf(b, "%2d", t.Day())
	case 'F':
		y, m, d := t.Date()
		fmt.Fprintf(b, "%04d-%02d-%02d", y, m, d)
	case 'f':
		usec := t.Nanosecond() / 1e3
		fmt.Fprintf(b, "%06d", int(usec))
	case 'H':
		fmt.Fprintf(b, "%02d", t.Hour())
	case 'h':
		b.WriteString(t.Month().String()[:3])
	case 'I':
		hr := t.Hour() % 12
		if hr == 0 {
			hr = 12
		}
		fmt.Fprintf(b, "%02d", hr)
	case 'j':
		fmt.Fprintf(b, "%03d", t.YearDay())
	case 'k':
		fmt.Fprintf(b, "%2d", t.Hour())
	case 'l':
		hr := t.Hour() % 12
		if hr == 0 {
			hr = 12
		}
		fmt.Fprintf(b, "%2d", hr)
	case 'M':
		fmt.Fprintf(b, "%02d", t.Minute())
	case 'm':
		fmt.Fprintf(b, "%02d", t.Month())
	case 'n':
		b.WriteByte('\n')
	case 'P':
		if t.Hour() < 12 {
			b.WriteString("am")
		} else {
			b.WriteString("pm")
		}
	case 'p':
		if t.Hour() < 12 {
			b.WriteString("AM")
		} else {
			b.WriteString("PM")
		}
	case 'R':
		h, m, _ := t.Clock()
		fmt.Fprintf(b, "%02d:%02d", h, m)
	case 'r':
		h, m, s := t.Clock()

		var tm string
		if h < 12 {
			tm = "AM"
		} else {
			tm = "PM"
		}

		hr := h % 12
		if hr == 0 {
			hr = 12
		}

		fmt.Fprintf(b, "%02d:%02d:%02d %s", hr, m, s, tm)
	case 'S':
		fmt.Fprintf(b, "%02d", t.Second())
	case 's':
		b.WriteString(strconv.FormatInt(t.Unix(), 10))
	case 'T':
		h, m, s := t.Clock()
		fmt.Fprintf(b, "%02d:%02d:%02d", h, m, s)
	case 't':
		b.WriteByte('\t')
	case 'v':
		fmt.Fprintf(b, "%2d-%s-%04d", t.Day(), t.Month().String()[:3], t.Year())
	case 'w':
		fmt.Fprintf(b, "%d", t.Weekday())
	case 'Y':
		fmt.Fprintf(b, "%04d", t.Year())
	case 'y':
		fmt.Fprintf(b, "%02d", t.Year()%100)
	case 'Z':
		zone, _ := t.Zone()
		b.WriteString(zone)
	case 'z':
		_, offset := t.Zone()
		allMinutes := int(offset/60)
		fmt.Fprintf(b, "%+03d%02d", int(allMinutes / 60), int(allMinutes % 60))
	default:
		return fmt.Errorf("No valid replacement")
	}

	return nil
}

// Format returns a textual representation of the time value
// formatting according to format. format supports most of the formatting
// methods defined in strftime(3), minus the GNU libc extensions and POSIX
// locale extensions.
//
// List of accepted format expansion values:
//  %A  replaced by full weekday name (Sunday)
//  %a  replaced by abbreviated weekday name (Sun)
//  %B  replaced by full month name (September)
//  %b  replaced by abbreviated month name (Sep)
//  %C  replaced by (year / 100) as number. Single digits are preceded by zero (20)
//  %D  equivalent to %m/%d/%y (09/21/14)
//  %d  replaced by day of month as number. Single digits are preceded by zero (21)
//  %e  replaced by day of month as number. Signle digits are preceded by a blank (21)
//  %F  equivalent to %Y-%m-%d (2014-09-21)
//  %H  replaced by the hour (24 hour clock) as a number. Single digits are preceded by zero (15)
//  %h  same as %b
//  %I  replaced by the hour (12 hour clock) as a number. Single digits are preceded by zero (03)
//  %j  replaced by the day of the year as a decimal number. Single digits are preced by zeros (264)
//  %k  replaced by the hour (24 hour clock) as a number. Single digits are preceded by a blank (15)
//  %l  replaced by the hour (12 hour clock) as a number. Single digits are preceded by blank ( 3)
//  %M  replaced by the minute as a decimal number. Single digits are preceded by a zero (32)
//  %m  replaced by the month as a decimal number. Single digits are preceded by a zero (09)
//  %n  replaced by a newline (\n)
//  %P  replaced by am or pm as appropriate
//  %p  replaced by AM or PM as appropriate
//  %R  equivalent to %H:%M
//  %r  equivalent to %I:%M:%S %p
//  %S  replaced by the second as a number. Single digits are preceded by a zero (05)
//  %s  replaced by the number of seconds since the Epoch, UTC
//  %T  equivalant to %H:%M:%S
//  %t  replaced by a tab (\t)
//  %v  equivalent to %e-%b-%Y
//  %w  replaced by the weekday (Sunday as first day of the week) as a number. (0)
//  %Y  replaced by the year with century as a number (2014)
//  %y  replaced by year without century as a number. Single digits are preceded by zero (14)
//  %Z  replaced by time zone name (UTC)
//  %z  replaced by the time zone offset from UTC (-0700)
func Format(format string, t time.Time) string {
	if !strings.Contains(format, "%") {
		return format
	}

	outBuf := &bytes.Buffer{}
	rr := strings.NewReader(format)
	for {
		r, _, err := rr.ReadRune()
		if err != nil {
			break
		}

		if r != '%' {
			outBuf.WriteRune(r)
			continue
		}

		nr, _, err := rr.ReadRune()
		if err != nil {
			// got a percent, but then end of string
			// just append % and finish
			outBuf.WriteByte('%')
			break
		}
		if nr == '%' {
			outBuf.WriteByte('%')
			continue
		}

		err = strftime(outBuf, nr, t)
		if err != nil {
			outBuf.WriteByte('%')
			outBuf.WriteRune(nr)
			continue
		}
	}
	return outBuf.String()
}

// Alias for Format
func Strftime(format string, t time.Time) string {
	return Format(format, t)
}
<commit_msg>gofmt<commit_after>// Package gostrftime formats time.Time using strftime(3) conventions.
package gostrftime

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"
	"time"
)

func strftime(b *bytes.Buffer, c rune, t time.Time) error {
	switch c {
	case 'A':
		b.WriteString(t.Weekday().String())
	case 'a':
		b.WriteString(t.Weekday().String()[:3])
	case 'B':
		b.WriteString(t.Month().String())
	case 'b':
		b.WriteString(t.Month().String()[:3])
	case 'C':
		fmt.Fprintf(b, "%02d", t.Year())
	case 'D':
		y, m, d := t.Date()
		fmt.Fprintf(b, "%02d/%02d/%02d", m, d, y%100)
	case 'd':
		fmt.Fprintf(b, "%02d", t.Day())
	case 'e':
		fmt.Fprintf(b, "%2d", t.Day())
	case 'F':
		y, m, d := t.Date()
		fmt.Fprintf(b, "%04d-%02d-%02d", y, m, d)
	case 'f':
		usec := t.Nanosecond() / 1e3
		fmt.Fprintf(b, "%06d", int(usec))
	case 'H':
		fmt.Fprintf(b, "%02d", t.Hour())
	case 'h':
		b.WriteString(t.Month().String()[:3])
	case 'I':
		hr := t.Hour() % 12
		if hr == 0 {
			hr = 12
		}
		fmt.Fprintf(b, "%02d", hr)
	case 'j':
		fmt.Fprintf(b, "%03d", t.YearDay())
	case 'k':
		fmt.Fprintf(b, "%2d", t.Hour())
	case 'l':
		hr := t.Hour() % 12
		if hr == 0 {
			hr = 12
		}
		fmt.Fprintf(b, "%2d", hr)
	case 'M':
		fmt.Fprintf(b, "%02d", t.Minute())
	case 'm':
		fmt.Fprintf(b, "%02d", t.Month())
	case 'n':
		b.WriteByte('\n')
	case 'P':
		if t.Hour() < 12 {
			b.WriteString("am")
		} else {
			b.WriteString("pm")
		}
	case 'p':
		if t.Hour() < 12 {
			b.WriteString("AM")
		} else {
			b.WriteString("PM")
		}
	case 'R':
		h, m, _ := t.Clock()
		fmt.Fprintf(b, "%02d:%02d", h, m)
	case 'r':
		h, m, s := t.Clock()

		var tm string
		if h < 12 {
			tm = "AM"
		} else {
			tm = "PM"
		}

		hr := h % 12
		if hr == 0 {
			hr = 12
		}

		fmt.Fprintf(b, "%02d:%02d:%02d %s", hr, m, s, tm)
	case 'S':
		fmt.Fprintf(b, "%02d", t.Second())
	case 's':
		b.WriteString(strconv.FormatInt(t.Unix(), 10))
	case 'T':
		h, m, s := t.Clock()
		fmt.Fprintf(b, "%02d:%02d:%02d", h, m, s)
	case 't':
		b.WriteByte('\t')
	case 'v':
		fmt.Fprintf(b, "%2d-%s-%04d", t.Day(), t.Month().String()[:3], t.Year())
	case 'w':
		fmt.Fprintf(b, "%d", t.Weekday())
	case 'Y':
		fmt.Fprintf(b, "%04d", t.Year())
	case 'y':
		fmt.Fprintf(b, "%02d", t.Year()%100)
	case 'Z':
		zone, _ := t.Zone()
		b.WriteString(zone)
	case 'z':
		_, offset := t.Zone()
		allMinutes := int(offset / 60)
		fmt.Fprintf(b, "%+03d%02d", int(allMinutes/60), int(allMinutes%60))
	default:
		return fmt.Errorf("No valid replacement")
	}

	return nil
}

// Format returns a textual representation of the time value
// formatting according to format. format supports most of the formatting
// methods defined in strftime(3), minus the GNU libc extensions and POSIX
// locale extensions.
//
// List of accepted format expansion values:
//  %A  replaced by full weekday name (Sunday)
//  %a  replaced by abbreviated weekday name (Sun)
//  %B  replaced by full month name (September)
//  %b  replaced by abbreviated month name (Sep)
//  %C  replaced by (year / 100) as number. Single digits are preceded by zero (20)
//  %D  equivalent to %m/%d/%y (09/21/14)
//  %d  replaced by day of month as number. Single digits are preceded by zero (21)
//  %e  replaced by day of month as number. Signle digits are preceded by a blank (21)
//  %F  equivalent to %Y-%m-%d (2014-09-21)
//  %H  replaced by the hour (24 hour clock) as a number. Single digits are preceded by zero (15)
//  %h  same as %b
//  %I  replaced by the hour (12 hour clock) as a number. Single digits are preceded by zero (03)
//  %j  replaced by the day of the year as a decimal number. Single digits are preced by zeros (264)
//  %k  replaced by the hour (24 hour clock) as a number. Single digits are preceded by a blank (15)
//  %l  replaced by the hour (12 hour clock) as a number. Single digits are preceded by blank ( 3)
//  %M  replaced by the minute as a decimal number. Single digits are preceded by a zero (32)
//  %m  replaced by the month as a decimal number. Single digits are preceded by a zero (09)
//  %n  replaced by a newline (\n)
//  %P  replaced by am or pm as appropriate
//  %p  replaced by AM or PM as appropriate
//  %R  equivalent to %H:%M
//  %r  equivalent to %I:%M:%S %p
//  %S  replaced by the second as a number. Single digits are preceded by a zero (05)
//  %s  replaced by the number of seconds since the Epoch, UTC
//  %T  equivalant to %H:%M:%S
//  %t  replaced by a tab (\t)
//  %v  equivalent to %e-%b-%Y
//  %w  replaced by the weekday (Sunday as first day of the week) as a number. (0)
//  %Y  replaced by the year with century as a number (2014)
//  %y  replaced by year without century as a number. Single digits are preceded by zero (14)
//  %Z  replaced by time zone name (UTC)
//  %z  replaced by the time zone offset from UTC (-0700)
func Format(format string, t time.Time) string {
	if !strings.Contains(format, "%") {
		return format
	}

	outBuf := &bytes.Buffer{}
	rr := strings.NewReader(format)
	for {
		r, _, err := rr.ReadRune()
		if err != nil {
			break
		}

		if r != '%' {
			outBuf.WriteRune(r)
			continue
		}

		nr, _, err := rr.ReadRune()
		if err != nil {
			// got a percent, but then end of string
			// just append % and finish
			outBuf.WriteByte('%')
			break
		}
		if nr == '%' {
			outBuf.WriteByte('%')
			continue
		}

		err = strftime(outBuf, nr, t)
		if err != nil {
			outBuf.WriteByte('%')
			outBuf.WriteRune(nr)
			continue
		}
	}
	return outBuf.String()
}

// Alias for Format
func Strftime(format string, t time.Time) string {
	return Format(format, t)
}
<|endoftext|>


<commit_before>package job

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"strings"
)

type HashPath struct {
	BasePath  string
	Namespace string
	Hash      string
	parts     []string
}

func HashesToPaths(input io.Reader, basePath string, namespace string) io.Reader {
	hashPaths := HashPaths(input, basePath, namespace)
	list := HashPathJoin(hashPaths, "original")
	return HashPathReader(list)
}

func HashPaths(input io.Reader, basePath string, namespace string) []HashPath {
	reader := bufio.NewReader(input)
	hashPaths := []HashPath{}

	line, err := reader.ReadString('\n')
	for err != io.EOF {
		hashPaths = append(hashPaths, HashPath{
			BasePath:  basePath,
			Namespace: namespace,
			Hash:      strings.TrimSpace(line),
		})
		line, err = reader.ReadString('\n')
	}

	return hashPaths
}

func HashPathJoin(list []HashPath, joined string) []HashPath {
	output := []HashPath{}
	for _, item := range list {
		output = append(output, *item.Join(joined))
	}
	return output
}

func HashPathReader(list []HashPath) io.Reader {
	var buffer bytes.Buffer
	for _, item := range list {
		buffer.WriteString(item.ToMantaPath() + "\n")
	}
	return strings.NewReader(buffer.String())
}

func (h *HashPath) ToMantaPath() string {
	var partitions = []string{h.Hash[0:3], h.Hash[3:6], h.Hash[6:9], h.Hash[9:32]}
	var joinedPartitions = strings.Join(partitions, "/")
	var joinedParts = strings.Join(append([]string{""}, h.parts...), "/")
	return fmt.Sprintf("%s/%s/%s%s", h.BasePath, h.Namespace, joinedPartitions, joinedParts)
}

func (h *HashPath) Join(part string) *HashPath {
	return &HashPath{
		BasePath:  h.BasePath,
		Namespace: h.Namespace,
		Hash:      h.Hash,
		parts:     append(h.parts, part),
	}
}
<commit_msg>Ensure that the batch item is a hash<commit_after>package job

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"strings"
)

type HashPath struct {
	BasePath  string
	Namespace string
	Hash      string
	parts     []string
}

func HashesToPaths(input io.Reader, basePath string, namespace string) io.Reader {
	hashPaths := HashPaths(input, basePath, namespace)
	list := HashPathJoin(hashPaths, "original")
	return HashPathReader(list)
}

func HashPaths(input io.Reader, basePath string, namespace string) []HashPath {
	reader := bufio.NewReader(input)
	hashPaths := []HashPath{}

	line, err := reader.ReadString('\n')
	for err != io.EOF {
		hash := strings.TrimSpace(line)
		if len(hash) == 32 {
			hashPaths = append(hashPaths, HashPath{
				BasePath:  basePath,
				Namespace: namespace,
				Hash:      hash,
			})
		}
		line, err = reader.ReadString('\n')
	}

	return hashPaths
}

func HashPathJoin(list []HashPath, joined string) []HashPath {
	output := []HashPath{}
	for _, item := range list {
		output = append(output, *item.Join(joined))
	}
	return output
}

func HashPathReader(list []HashPath) io.Reader {
	var buffer bytes.Buffer
	for _, item := range list {
		buffer.WriteString(item.ToMantaPath() + "\n")
	}
	return strings.NewReader(buffer.String())
}

func (h *HashPath) ToMantaPath() string {
	var partitions = []string{h.Hash[0:3], h.Hash[3:6], h.Hash[6:9], h.Hash[9:32]}
	var joinedPartitions = strings.Join(partitions, "/")
	var joinedParts = strings.Join(append([]string{""}, h.parts...), "/")
	return fmt.Sprintf("%s/%s/%s%s", h.BasePath, h.Namespace, joinedPartitions, joinedParts)
}

func (h *HashPath) Join(part string) *HashPath {
	return &HashPath{
		BasePath:  h.BasePath,
		Namespace: h.Namespace,
		Hash:      h.Hash,
		parts:     append(h.parts, part),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"runtime/debug"
	"strings"
	"time"

	"github.com/codegangsta/cli"

	"github.com/cloudfoundry/cli/cf"
	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/app"
	"github.com/cloudfoundry/cli/cf/command_factory"
	"github.com/cloudfoundry/cli/cf/command_runner"
	"github.com/cloudfoundry/cli/cf/configuration"
	"github.com/cloudfoundry/cli/cf/manifest"
	"github.com/cloudfoundry/cli/cf/net"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/cf/trace"
)

type cliDependencies struct {
	termUI         terminal.UI
	configRepo     configuration.Repository
	manifestRepo   manifest.ManifestRepository
	apiRepoLocator api.RepositoryLocator
	gateways       map[string]net.Gateway
}

func setupDependencies() (deps *cliDependencies) {
	deps = new(cliDependencies)

	deps.termUI = terminal.NewUI(os.Stdin)

	deps.manifestRepo = manifest.NewManifestDiskRepository()

	deps.configRepo = configuration.NewRepositoryFromFilepath(configuration.DefaultFilePath(), func(err error) {
		if err != nil {
			deps.termUI.Failed(fmt.Sprintf("Config error: %s", err))
		}
	})

	terminal.UserAskedForColors = deps.configRepo.ColorEnabled()
	terminal.InitColorSupport()

	if os.Getenv("CF_TRACE") != "" {
		trace.Logger = trace.NewLogger(os.Getenv("CF_TRACE"))
	} else {
		trace.Logger = trace.NewLogger(deps.configRepo.Trace())
	}

	deps.gateways = map[string]net.Gateway{
		"auth":             net.NewUAAGateway(deps.configRepo),
		"cloud-controller": net.NewCloudControllerGateway(deps.configRepo, time.Now),
		"uaa":              net.NewUAAGateway(deps.configRepo),
	}
	deps.apiRepoLocator = api.NewRepositoryLocator(deps.configRepo, deps.gateways)

	return
}

func main() {
	defer handlePanics()

	deps := setupDependencies()
	defer deps.configRepo.Close()

	cmdFactory := command_factory.NewFactory(deps.termUI, deps.configRepo, deps.manifestRepo, deps.apiRepoLocator)
	requirementsFactory := requirements.NewFactory(deps.termUI, deps.configRepo, deps.apiRepoLocator)
	cmdRunner := command_runner.NewRunner(cmdFactory, requirementsFactory)

	app.NewApp(cmdRunner, cmdFactory.CommandMetadatas()...).Run(os.Args)

	gateways := gatewaySliceFromMap(deps.gateways)
	net.NewWarningsCollector(deps.termUI, gateways...).PrintWarnings()
}

func gatewaySliceFromMap(gateway_map map[string]net.Gateway) []net.WarningProducer {
	gateways := []net.WarningProducer{}
	for _, gateway := range gateway_map {
		gateways = append(gateways, gateway)
	}
	return gateways
}

func init() {
	cli.AppHelpTemplate = `NAME:
   {{.Name}} - {{.Usage}}

USAGE:
   [environment variables] {{.Name}} [global options] command [arguments...] [command options]

VERSION:
   {{.Version}}

COMMANDS:
   {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Description}}
   {{end}}
GLOBAL OPTIONS:
   {{range .Flags}}{{.}}
   {{end}}
ENVIRONMENT VARIABLES:
   CF_COLOR=false - will not colorize output
   CF_HOME=path/to/config/ override default config directory
   CF_STAGING_TIMEOUT=15 max wait time for buildpack staging, in minutes
   CF_STARTUP_TIMEOUT=5 max wait time for app instance startup, in minutes
   CF_TRACE=true - print API request diagnostics to stdout
   CF_TRACE=path/to/trace.log - append API request diagnostics to a log file
   HTTP_PROXY=http://proxy.example.com:8080 - enable HTTP proxying for API requests
`

	cli.CommandHelpTemplate = `NAME:
   {{.Name}} - {{.Description}}
{{with .ShortName}}
ALIAS:
   {{.}}
{{end}}
USAGE:
   {{.Usage}}{{with .Flags}}

OPTIONS:
{{range .}}   {{.}}
{{end}}{{else}}
{{end}}`

}

func handlePanics() {
	err := recover()
	if err != nil && err != terminal.FailedWasCalled {
		switch err := err.(type) {
		case error:
			displayCrashDialog(err.Error())
		case string:
			displayCrashDialog(err)
		default:
			displayCrashDialog("An unexpected type of error")
		}
	}

	if err != nil {
		os.Exit(1)
	}
}

func displayCrashDialog(errorMessage string) {
	formattedString := `

Aww shucks.

Something completely unexpected happened. This is a bug in %s.
Please file this bug : https://github.com/cloudfoundry/cli/issues
Tell us that you ran this command:

	%s

this error occurred:

	%s

and this stack trace:

%s
	`

	stackTrace := "\t" + strings.Replace(string(debug.Stack()), "\n", "\n\t", -1)
	println(fmt.Sprintf(formattedString, cf.Name(), strings.Join(os.Args, " "), errorMessage, stackTrace))
}
<commit_msg>Patch for cloudfoundry-cli#182 - replace deprecated code with calls to runtime.Stack()<commit_after>package main

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/codegangsta/cli"

	"github.com/cloudfoundry/cli/cf"
	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/app"
	"github.com/cloudfoundry/cli/cf/command_factory"
	"github.com/cloudfoundry/cli/cf/command_runner"
	"github.com/cloudfoundry/cli/cf/configuration"
	"github.com/cloudfoundry/cli/cf/manifest"
	"github.com/cloudfoundry/cli/cf/net"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/cf/trace"
)

type cliDependencies struct {
	termUI         terminal.UI
	configRepo     configuration.Repository
	manifestRepo   manifest.ManifestRepository
	apiRepoLocator api.RepositoryLocator
	gateways       map[string]net.Gateway
}

func setupDependencies() (deps *cliDependencies) {
	deps = new(cliDependencies)

	deps.termUI = terminal.NewUI(os.Stdin)

	deps.manifestRepo = manifest.NewManifestDiskRepository()

	deps.configRepo = configuration.NewRepositoryFromFilepath(configuration.DefaultFilePath(), func(err error) {
		if err != nil {
			deps.termUI.Failed(fmt.Sprintf("Config error: %s", err))
		}
	})

	terminal.UserAskedForColors = deps.configRepo.ColorEnabled()
	terminal.InitColorSupport()

	if os.Getenv("CF_TRACE") != "" {
		trace.Logger = trace.NewLogger(os.Getenv("CF_TRACE"))
	} else {
		trace.Logger = trace.NewLogger(deps.configRepo.Trace())
	}

	deps.gateways = map[string]net.Gateway{
		"auth":             net.NewUAAGateway(deps.configRepo),
		"cloud-controller": net.NewCloudControllerGateway(deps.configRepo, time.Now),
		"uaa":              net.NewUAAGateway(deps.configRepo),
	}
	deps.apiRepoLocator = api.NewRepositoryLocator(deps.configRepo, deps.gateways)

	return
}

func main() {
	defer handlePanics()

	deps := setupDependencies()
	defer deps.configRepo.Close()

	cmdFactory := command_factory.NewFactory(deps.termUI, deps.configRepo, deps.manifestRepo, deps.apiRepoLocator)
	requirementsFactory := requirements.NewFactory(deps.termUI, deps.configRepo, deps.apiRepoLocator)
	cmdRunner := command_runner.NewRunner(cmdFactory, requirementsFactory)

	app.NewApp(cmdRunner, cmdFactory.CommandMetadatas()...).Run(os.Args)

	gateways := gatewaySliceFromMap(deps.gateways)
	net.NewWarningsCollector(deps.termUI, gateways...).PrintWarnings()
}

func gatewaySliceFromMap(gateway_map map[string]net.Gateway) []net.WarningProducer {
	gateways := []net.WarningProducer{}
	for _, gateway := range gateway_map {
		gateways = append(gateways, gateway)
	}
	return gateways
}

func init() {
	cli.AppHelpTemplate = `NAME:
   {{.Name}} - {{.Usage}}

USAGE:
   [environment variables] {{.Name}} [global options] command [arguments...] [command options]

VERSION:
   {{.Version}}

COMMANDS:
   {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Description}}
   {{end}}
GLOBAL OPTIONS:
   {{range .Flags}}{{.}}
   {{end}}
ENVIRONMENT VARIABLES:
   CF_COLOR=false - will not colorize output
   CF_HOME=path/to/config/ override default config directory
   CF_STAGING_TIMEOUT=15 max wait time for buildpack staging, in minutes
   CF_STARTUP_TIMEOUT=5 max wait time for app instance startup, in minutes
   CF_TRACE=true - print API request diagnostics to stdout
   CF_TRACE=path/to/trace.log - append API request diagnostics to a log file
   HTTP_PROXY=http://proxy.example.com:8080 - enable HTTP proxying for API requests
`

	cli.CommandHelpTemplate = `NAME:
   {{.Name}} - {{.Description}}
{{with .ShortName}}
ALIAS:
   {{.}}
{{end}}
USAGE:
   {{.Usage}}{{with .Flags}}

OPTIONS:
{{range .}}   {{.}}
{{end}}{{else}}
{{end}}`

}

func handlePanics() {
	err := recover()
	if err != nil && err != terminal.FailedWasCalled {
		switch err := err.(type) {
		case error:
			displayCrashDialog(err.Error())
		case string:
			displayCrashDialog(err)
		default:
			displayCrashDialog("An unexpected type of error")
		}
	}

	if err != nil {
		os.Exit(1)
	}
}

func displayCrashDialog(errorMessage string) {
	formattedString := `

Aww shucks.

Something completely unexpected happened. This is a bug in %s.
Please file this bug : https://github.com/cloudfoundry/cli/issues
Tell us that you ran this command:

	%s

this error occurred:

	%s

and this stack trace:

%s
	`

	var bytes []byte
	runtime.Stack(bytes, true)
	stackTrace := "\t" + strings.Replace(string(bytes), "\n", "\n\t", -1)
	println(fmt.Sprintf(formattedString, cf.Name(), strings.Join(os.Args, " "), errorMessage, stackTrace))
}
<|endoftext|>


<commit_before>package main

import (
	. "github.com/go-func/stream"
	"github.com/go-func/stream/collectors"
	"fmt"
)

func main() {
	list := make([]interface{}, 100)
	for i := 0; i < 100; i++ {
		list[i] = i * 2
	}
	tmp := NewParallelStream(list).Filter(func(item interface{}) bool {
		if item.(int) < 100 {
			return false
		}
		return true
	}).Map(func(item interface{}) interface{} {
		value := item.(int)
		value /= 2
		return value
	}).Collect(&collectors.GroupingBy{Classifier: func(item interface{}) interface{} {
		return item.(int)%2 == 0
	}, DownStream: &collectors.PartitioningBy{Predicate: func(item interface{}) bool {
		return item.(int)%3 == 0
	}, DownStream: &collectors.SummarizingFloat64{Mapper: func(item interface{}) float64 {
		return float64(item.(int))
	}}}})
	/*
		.Collect(&collectors.PartitioningBy{Predicate: func(item interface{}) bool {
			return item.(int)%3 == 0
		}})
		.Collect(&collectors.GroupingBy{Classifier: func(item interface{}) interface{} {
			return item.(int)%3 == 0
		}})
		.Collect(&collectors.Joining{Prefix: "[", Suffix: "]", Delimiter: ","})
		.Collect(&collectors.Counting{})
		.Collect(&collectors.AveragingFloat64{Mapper: func(item interface{}) float64 {
			return float64(item.(int))
		}})
		.Collect(&collectors.ToMap{KeyMapper: func(item interface{}) interface{} {
			return item.(int) * 2
		}, ValueMapper: func(item interface{}) interface{} {
			return item
		}})
		.Collect(&collectors.SummarizingFloat64{Mapper: func(item interface{}) float64 {
			return float64(item.(int))
		}})
	*/
	fmt.Println(tmp)
}
<commit_msg>Update main.go<commit_after>package main

import (
	. "github.com/go-func/stream"
	"github.com/go-func/stream/collectors"
	"fmt"
)

func main() {
	list := make([]interface{}, 100)
	for i := 0; i < 100; i++ {
		list[i] = i * 2
	}
	tmp := NewStream(list).Filter(func(item interface{}) bool {
		if item.(int) < 100 {
			return false
		}
		return true
	}).Map(func(item interface{}) interface{} {
		value := item.(int)
		value /= 2
		return value
	}).Collect(&collectors.GroupingBy{Classifier: func(item interface{}) interface{} {
		return item.(int)%2 == 0
	}, DownStream: &collectors.PartitioningBy{Predicate: func(item interface{}) bool {
		return item.(int)%3 == 0
	}, DownStream: &collectors.SummarizingFloat64{Mapper: func(item interface{}) float64 {
		return float64(item.(int))
	}}}})
	/*
		.Collect(&collectors.PartitioningBy{Predicate: func(item interface{}) bool {
			return item.(int)%3 == 0
		}})
		.Collect(&collectors.GroupingBy{Classifier: func(item interface{}) interface{} {
			return item.(int)%3 == 0
		}})
		.Collect(&collectors.Joining{Prefix: "[", Suffix: "]", Delimiter: ","})
		.Collect(&collectors.Counting{})
		.Collect(&collectors.AveragingFloat64{Mapper: func(item interface{}) float64 {
			return float64(item.(int))
		}})
		.Collect(&collectors.ToMap{KeyMapper: func(item interface{}) interface{} {
			return item.(int) * 2
		}, ValueMapper: func(item interface{}) interface{} {
			return item
		}})
		.Collect(&collectors.SummarizingFloat64{Mapper: func(item interface{}) float64 {
			return float64(item.(int))
		}})
	*/
	fmt.Println(tmp)
}
<|endoftext|>


<commit_before>package gpio

import (
	"fmt"
	"os"
	"strconv"
)

//Constants

//By default, pins 14 and 15 boot to UART mode, so they are going to be ignored for now.
//We can add them in later as necessary.

const (
	GPIO0  = 0
	GPIO1  = 1
	GPIO2  = 2
	GPIO3  = 3
	GPIO4  = 4
	GPIO7  = 7
	GPIO8  = 8
	GPIO9  = 9
	GPIO10 = 10
	GPIO11 = 11
	GPIO17 = 17
	GPIO18 = 18
	GPIO22 = 22
	GPIO23 = 23
	GPIO24 = 24
	GPIO25 = 25
)

const (
	exportPath      = "/sys/class/gpio/export"
	unexportPath    = "/sys/class/gpio/unexport"
	gpioPathPrefix  = "/sys/class/gpio/gpio"
	modePathSuffix  = "/direction"
	valuePathSuffix = "/value"
)

var (
	BytesSet   = []byte{'1'}
	BytesClear = []byte{'0'}
)

// pin represents a GPIO pin.
type pin struct {
	number        int      // the pin number
	numberAsBytes []byte   // the pin number as a byte array to avoid converting each time
	modePath      string   // the path to the /direction FD to avoid string joining each time
	valueFile     *os.File // the file handle for the value file
	err           error    //the last error
}

// OpenPin exports the pin, creating the virtual files necessary for interacting with the pin.
// It also sets the mode for the pin, making it ready for use.
func OpenPin(number int, mode Mode) (Pin, error) {
	numString := strconv.Itoa(number)
	p := &pin{
		number:        number,
		numberAsBytes: []byte(numString),
		modePath:      fmt.Sprintf("%s%s%s", gpioPathPrefix, numString, modePathSuffix),
	}

	// export this pin to create the virtual files on the system
	exportFile, err := os.OpenFile(exportPath, os.O_WRONLY, 0200)
	exportFile.Write(p.numberAsBytes)
	exportFile.Close()
	p.err = err

	if err == nil {
		p.SetMode(mode)
		valueFile, err := os.Create(fmt.Sprintf("%s%s%s", gpioPathPrefix, numString, valuePathSuffix))
		p.valueFile = valueFile
		p.err = err
	}

	return p, p.err

}

// write opens a file for writing, writes the byte slice to it and closes the
// file.
func write(bytes []byte, path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}

	file.Write(bytes)

	return file.Close()
}

// read opens a file for reading, reads the bytes slice from it and closes the file.
func read(bytes *[]byte, path string) error {
	file, err := os.Open(path)
	if err != nil {
		return err
	}

	file.Read(*bytes)

	return file.Close()
}

// Close destroys the virtual files on the filesystem, unexporting the pin.
func (p *pin) Close() error {
	p.valueFile.Close()
	err := write(p.numberAsBytes, unexportPath)
	p.err = err
	return err
}

// Mode retrieves the current mode of the pin.
func (p *pin) Mode() Mode {
	bytes := make([]byte, 3)
	p.err = read(&bytes, p.modePath)
	return Mode(bytes)
}

// SetMode sets the mode of the pin.
func (p *pin) SetMode(mode Mode) {
	p.err = write([]byte(mode), p.modePath)
}

// Set sets the pin level high.
func (p *pin) Set() {
	p.valueFile.Write(BytesSet)
}

// Clear sets the pin level low.
func (p *pin) Clear() {
	p.valueFile.Write(BytesClear)
}

// Get retrieves the current pin level.
func (p *pin) Get() bool {
	bytes := make([]byte, 1)
	p.valueFile.Read(bytes)

	return bytes[0] != 0
}

// Watch waits for the edge level to be triggered and then calls the callback
func (p *pin) Watch(callback IRQEvent) {
	panic("Watch is not yet implemented!")
}

// Wait blocks while waits for the pin state to match the condition, then returns.
func (p *pin) Wait(condition bool) {
	panic("Wait is not yet implemented!")
}

// Err returns the last error encountered.
func (p *pin) Err() error {
	return p.err
}
<commit_msg>Fix error handling in gpio.OpenPin<commit_after>package gpio

import (
	"fmt"
	"os"
	"strconv"
)

//Constants

//By default, pins 14 and 15 boot to UART mode, so they are going to be ignored for now.
//We can add them in later as necessary.

const (
	GPIO0  = 0
	GPIO1  = 1
	GPIO2  = 2
	GPIO3  = 3
	GPIO4  = 4
	GPIO7  = 7
	GPIO8  = 8
	GPIO9  = 9
	GPIO10 = 10
	GPIO11 = 11
	GPIO17 = 17
	GPIO18 = 18
	GPIO22 = 22
	GPIO23 = 23
	GPIO24 = 24
	GPIO25 = 25
)

const (
	exportPath      = "/sys/class/gpio/export"
	unexportPath    = "/sys/class/gpio/unexport"
	gpioPathPrefix  = "/sys/class/gpio/gpio"
	modePathSuffix  = "/direction"
	valuePathSuffix = "/value"
)

var (
	BytesSet   = []byte{'1'}
	BytesClear = []byte{'0'}
)

// pin represents a GPIO pin.
type pin struct {
	number        int      // the pin number
	numberAsBytes []byte   // the pin number as a byte array to avoid converting each time
	modePath      string   // the path to the /direction FD to avoid string joining each time
	valueFile     *os.File // the file handle for the value file
	err           error    //the last error
}

// OpenPin exports the pin, creating the virtual files necessary for interacting with the pin.
// It also sets the mode for the pin, making it ready for use.
func OpenPin(number int, mode Mode) (Pin, error) {
	numString := strconv.Itoa(number)
	p := &pin{
		number:        number,
		numberAsBytes: []byte(numString),
		modePath:      fmt.Sprintf("%s%s%s", gpioPathPrefix, numString, modePathSuffix),
	}

	// export this pin to create the virtual files on the system
	exportFile, err := os.OpenFile(exportPath, os.O_WRONLY, 0200)
	if err != nil {
		return nil, err
	}
	defer exportFile.Close()
	if _, err := exportFile.Write(p.numberAsBytes); err != nil {
		return nil, err
	}
	p.SetMode(mode)
	valueFile, err := os.Create(fmt.Sprintf("%s%s%s", gpioPathPrefix, numString, valuePathSuffix))
	p.valueFile = valueFile
	p.err = err

	return p, nil

}

// write opens a file for writing, writes the byte slice to it and closes the
// file.
func write(bytes []byte, path string) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}

	file.Write(bytes)

	return file.Close()
}

// read opens a file for reading, reads the bytes slice from it and closes the file.
func read(bytes *[]byte, path string) error {
	file, err := os.Open(path)
	if err != nil {
		return err
	}

	file.Read(*bytes)

	return file.Close()
}

// Close destroys the virtual files on the filesystem, unexporting the pin.
func (p *pin) Close() error {
	p.valueFile.Close()
	err := write(p.numberAsBytes, unexportPath)
	p.err = err
	return err
}

// Mode retrieves the current mode of the pin.
func (p *pin) Mode() Mode {
	bytes := make([]byte, 3)
	p.err = read(&bytes, p.modePath)
	return Mode(bytes)
}

// SetMode sets the mode of the pin.
func (p *pin) SetMode(mode Mode) {
	p.err = write([]byte(mode), p.modePath)
}

// Set sets the pin level high.
func (p *pin) Set() {
	p.valueFile.Write(BytesSet)
}

// Clear sets the pin level low.
func (p *pin) Clear() {
	p.valueFile.Write(BytesClear)
}

// Get retrieves the current pin level.
func (p *pin) Get() bool {
	bytes := make([]byte, 1)
	p.valueFile.Read(bytes)

	return bytes[0] != 0
}

// Watch waits for the edge level to be triggered and then calls the callback
func (p *pin) Watch(callback IRQEvent) {
	panic("Watch is not yet implemented!")
}

// Wait blocks while waits for the pin state to match the condition, then returns.
func (p *pin) Wait(condition bool) {
	panic("Wait is not yet implemented!")
}

// Err returns the last error encountered.
func (p *pin) Err() error {
	return p.err
}
<|endoftext|>


<commit_before>package gsm

import (
	"encoding/json"
	"errors"
	"github.com/FarmRadioHangar/fessboxconfig"
	"io"
)

// Ast is an abstract syntax tree for a configuration object. The configuration
// format should be section based( or you can say namespacing).
type Ast struct {
	sections []*nodeSection
}

//Section returns the section named name or an error if the section is not found
//in the Ast
func (a *Ast) Section(name string) (*nodeSection, error) {
	for _, v := range a.sections {
		if v.name == name {
			return v, nil
		}
	}
	return nil, errors.New("section not found")
}

//ToJSON marhalls *Ast to a json string and writes the result to dst
func (a *Ast) ToJSON(dst io.Writer) error {
	o := make(map[string]interface{})
	for _, v := range a.sections {
		sec := make(map[string]interface{})
		for _, value := range v.values {
			sec[value.key] = value.value
		}
		o[v.name] = sec
	}
	return json.NewEncoder(dst).Encode(o)
}

//nodeSection represent a section in the configuration object. Sections are name
//spaces that contains configurations definitions under them.
type nodeSection struct {
	name   string
	line   int
	values []*nodeIdent
}

//Get access the key definition and returns its value or an error if the key is
//not part of the section.
func (n *nodeSection) Get(key string) (string, error) {
	for _, v := range n.values {
		if v.key == key {
			return v.value, nil
		}
	}
	return "", errors.New("key not found")
}

//nodeIdent represents a configuration definition, which can be the key value
//definition.
type nodeIdent struct {
	key   string
	value string
	line  int
}

// parser is a parser for configuration files. It supports utf-8 encoded
// configuration files.
//
// Only modem configuration files are supported for the momment.
type parser struct {
	tokens  []*config.Token
	Ast     *Ast
	currPos int
}

//newParser returns a new parser that parses input from src. The returned parser
//supports gsm modem configuration format only.
func newParser(src io.Reader) (*parser, error) {
	s := config.NewScanner(src)
	var toks []*config.Token
	var err error
	var tok *config.Token
	for err == nil {
		tok, err = s.Scan()
		if err != nil {
			if err.Error() != io.EOF.Error() {
				return nil, err
			}

			// we are at the end of the input
			break
		}
		if tok != nil {
			switch tok.Type {
			case config.WhiteSpace, config.Comment:

				// Skip comments and whitespaces but preserve the newlines to aid in
				// parsing
				continue
			default:
				toks = append(toks, tok)
			}

		}
	}
	return &parser{tokens: toks, Ast: &Ast{}}, nil
}

func (p *parser) parse() (*Ast, error) {
	var err error
	if err != nil {
		return nil, err
	}
	mainSec := &nodeSection{name: "main"}
END:
	for {
		tok := p.next()
		if tok.Type == config.EOF {
			break END
		}
		switch tok.Type {
		case config.OpenBrace:
			p.rewind()
			err = p.parseSection()
			if err != nil {
				break END
			}
		case config.Ident:
			p.rewind()
			err = p.parseIdent(mainSec)
			if err != nil {
				break END
			}

		}
	}
	if err != nil {
		return nil, err
	}
	p.Ast.sections = append([]*nodeSection{mainSec}, p.Ast.sections...)
	return p.Ast, err
}

func (p *parser) next() *config.Token {
	if p.currPos >= len(p.tokens)-1 {
		return &config.Token{Type: config.EOF}
	}
	t := p.tokens[p.currPos]
	p.currPos++
	return t
}

func (p *parser) seek(at int) {
	p.currPos = at
}

func (p *parser) parseSection() (err error) {
	left := p.next()
	if left.Type != config.OpenBrace {
		return errors.New("bad token")
	}
	ns := &nodeSection{}
	completeName := false
END:
	for {
	BEGIN:
		tok := p.next()
		if tok.Type == config.EOF {
			p.rewind()
			break END
		}

		if !completeName {
			switch tok.Type {
			case config.Ident:
				ns.name = ns.name + tok.Text
				goto BEGIN
			case config.ClosingBrace:
				completeName = true
				goto BEGIN
			}
		}
		switch tok.Type {
		case config.NewLine:
			n1 := p.next()
			if n1.Type == config.NewLine {
				n2 := p.next()
				if n2.Type == config.NewLine {
					break END
				}
				p.rewind()
				goto BEGIN
			}
			goto BEGIN
		case config.Ident:
			p.rewind()
			err = p.parseIdent(ns)
			if err != nil {
				break END
			}
		default:
			break END
		}
	}
	if err == nil {
		p.Ast.sections = append(p.Ast.sections, ns)
	}
	return
}

func (p *parser) rewind() {
	p.currPos--
}

func (p *parser) parseIdent(sec *nodeSection) (err error) {
	n := &nodeIdent{}
	doneKey := false
END:
	for {
	BEGIN:
		tok := p.next()
		if tok.Type == config.EOF {
			p.rewind()
			break END
		}

		if !doneKey {
			switch tok.Type {
			case config.Ident:
				n.key = n.key + tok.Text
				goto BEGIN
			case config.Operand:
				doneKey = true
				goto BEGIN
			default:
				err = errors.New("some fish")
				break END
			}

		}
		switch tok.Type {
		case config.Ident:
			n.value = n.value + tok.Text
			goto BEGIN
		case config.NewLine:
			break END
		default:
			err = errors.New("some fish")
			break END
		}
	}
	if err == nil {
		sec.values = append(sec.values, n)
	}

	return
}
<commit_msg>Export nodeSection<commit_after>package gsm

import (
	"encoding/json"
	"errors"
	"github.com/FarmRadioHangar/fessboxconfig"
	"io"
)

// Ast is an abstract syntax tree for a configuration object. The configuration
// format should be section based( or you can say namespacing).
type Ast struct {
	sections []*NodeSection
}

//Section returns the section named name or an error if the section is not found
//in the Ast
func (a *Ast) Section(name string) (*NodeSection, error) {
	for _, v := range a.sections {
		if v.name == name {
			return v, nil
		}
	}
	return nil, errors.New("section not found")
}

//ToJSON marhalls *Ast to a json string and writes the result to dst
func (a *Ast) ToJSON(dst io.Writer) error {
	o := make(map[string]interface{})
	for _, v := range a.sections {
		sec := make(map[string]interface{})
		for _, value := range v.values {
			sec[value.key] = value.value
		}
		o[v.name] = sec
	}
	return json.NewEncoder(dst).Encode(o)
}

//NodeSection represent a section in the configuration object. Sections are name
//spaces that contains configurations definitions under them.
type NodeSection struct {
	name   string
	line   int
	values []*nodeIdent
}

//Get access the key definition and returns its value or an error if the key is
//not part of the section.
func (n *NodeSection) Get(key string) (string, error) {
	for _, v := range n.values {
		if v.key == key {
			return v.value, nil
		}
	}
	return "", errors.New("key not found")
}

//nodeIdent represents a configuration definition, which can be the key value
//definition.
type nodeIdent struct {
	key   string
	value string
	line  int
}

// parser is a parser for configuration files. It supports utf-8 encoded
// configuration files.
//
// Only modem configuration files are supported for the momment.
type parser struct {
	tokens  []*config.Token
	Ast     *Ast
	currPos int
}

//newParser returns a new parser that parses input from src. The returned parser
//supports gsm modem configuration format only.
func newParser(src io.Reader) (*parser, error) {
	s := config.NewScanner(src)
	var toks []*config.Token
	var err error
	var tok *config.Token
	for err == nil {
		tok, err = s.Scan()
		if err != nil {
			if err.Error() != io.EOF.Error() {
				return nil, err
			}

			// we are at the end of the input
			break
		}
		if tok != nil {
			switch tok.Type {
			case config.WhiteSpace, config.Comment:

				// Skip comments and whitespaces but preserve the newlines to aid in
				// parsing
				continue
			default:
				toks = append(toks, tok)
			}

		}
	}
	return &parser{tokens: toks, Ast: &Ast{}}, nil
}

func (p *parser) parse() (*Ast, error) {
	var err error
	if err != nil {
		return nil, err
	}
	mainSec := &NodeSection{name: "main"}
END:
	for {
		tok := p.next()
		if tok.Type == config.EOF {
			break END
		}
		switch tok.Type {
		case config.OpenBrace:
			p.rewind()
			err = p.parseSection()
			if err != nil {
				break END
			}
		case config.Ident:
			p.rewind()
			err = p.parseIdent(mainSec)
			if err != nil {
				break END
			}

		}
	}
	if err != nil {
		return nil, err
	}
	p.Ast.sections = append([]*NodeSection{mainSec}, p.Ast.sections...)
	return p.Ast, err
}

func (p *parser) next() *config.Token {
	if p.currPos >= len(p.tokens)-1 {
		return &config.Token{Type: config.EOF}
	}
	t := p.tokens[p.currPos]
	p.currPos++
	return t
}

func (p *parser) seek(at int) {
	p.currPos = at
}

func (p *parser) parseSection() (err error) {
	left := p.next()
	if left.Type != config.OpenBrace {
		return errors.New("bad token")
	}
	ns := &NodeSection{}
	completeName := false
END:
	for {
	BEGIN:
		tok := p.next()
		if tok.Type == config.EOF {
			p.rewind()
			break END
		}

		if !completeName {
			switch tok.Type {
			case config.Ident:
				ns.name = ns.name + tok.Text
				goto BEGIN
			case config.ClosingBrace:
				completeName = true
				goto BEGIN
			}
		}
		switch tok.Type {
		case config.NewLine:
			n1 := p.next()
			if n1.Type == config.NewLine {
				n2 := p.next()
				if n2.Type == config.NewLine {
					break END
				}
				p.rewind()
				goto BEGIN
			}
			goto BEGIN
		case config.Ident:
			p.rewind()
			err = p.parseIdent(ns)
			if err != nil {
				break END
			}
		default:
			break END
		}
	}
	if err == nil {
		p.Ast.sections = append(p.Ast.sections, ns)
	}
	return
}

func (p *parser) rewind() {
	p.currPos--
}

func (p *parser) parseIdent(sec *NodeSection) (err error) {
	n := &nodeIdent{}
	doneKey := false
END:
	for {
	BEGIN:
		tok := p.next()
		if tok.Type == config.EOF {
			p.rewind()
			break END
		}

		if !doneKey {
			switch tok.Type {
			case config.Ident:
				n.key = n.key + tok.Text
				goto BEGIN
			case config.Operand:
				doneKey = true
				goto BEGIN
			default:
				err = errors.New("some fish")
				break END
			}

		}
		switch tok.Type {
		case config.Ident:
			n.value = n.value + tok.Text
			goto BEGIN
		case config.NewLine:
			break END
		default:
			err = errors.New("some fish")
			break END
		}
	}
	if err == nil {
		sec.values = append(sec.values, n)
	}

	return
}
<|endoftext|>


<commit_before>package kontrol

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/hashicorp/go-version"
	"github.com/koding/kite"
	kontrolprotocol "github.com/koding/kite/kontrol/protocol"
	"github.com/koding/kite/protocol"
)

// keyOrder defines the order of the query paramaters.
var keyOrder = []string{
	"username",
	"environment",
	"name",
	"version",
	"region",
	"hostname",
	"id",
}

// Etcd implements the Storage interface
type Etcd struct {
	client *etcd.Client
	log    kite.Logger
}

func NewEtcd(machines []string, log kite.Logger) *Etcd {
	if machines == nil || len(machines) == 0 {
		machines = []string{"127.0.0.1:4001"}
	}

	client := etcd.NewClient(machines)
	ok := client.SetCluster(machines)
	if !ok {
		panic("cannot connect to etcd cluster: " + strings.Join(machines, ","))
	}

	return &Etcd{
		client: client,
		log:    log,
	}
}

func (e *Etcd) Delete(k *protocol.Kite) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	_, err := e.client.Delete(etcdKey, true)
	_, err = e.client.Delete(etcdIDKey, true)
	return err
}

func (e *Etcd) Clear() error {
	_, err := e.client.Delete(KitesPrefix, true)
	return err
}

func (e *Etcd) Upsert(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	return e.Add(k, value)
}

func (e *Etcd) Add(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	valueBytes, err := json.Marshal(value)
	if err != nil {
		return err
	}

	valueString := string(valueBytes)

	// Set the kite key.
	// Example "/koding/production/os/0.0.1/sj/kontainer1.sj.koding.com/1234asdf..."
	_, err = e.client.Set(etcdKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Also store the the kite.Key Id for easy lookup
	_, err = e.client.Set(etcdIDKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	return nil
}

func (e *Etcd) Update(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	valueBytes, err := json.Marshal(value)
	if err != nil {
		return err
	}

	valueString := string(valueBytes)

	// update the kite key.
	// Example "/koding/production/os/0.0.1/sj/kontainer1.sj.koding.com/1234asdf..."
	_, err = e.client.Update(etcdKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Also update the the kite.Key Id for easy lookup
	_, err = e.client.Update(etcdIDKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Set the TTL for the username. Otherwise, empty dirs remain in etcd.
	_, err = e.client.Update(KitesPrefix+"/"+k.Username,
		"", uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	return nil
}

func (e *Etcd) Get(query *protocol.KontrolQuery) (Kites, error) {
	// We will make a get request to etcd store with this key. So get a "etcd"
	// key from the given query so that we can use it to query from Etcd.
	etcdKey, err := e.etcdKey(query)
	if err != nil {
		return nil, err
	}

	// If version field contains a constraint we need no make a new query up to
	// "name" field and filter the results after getting all versions.
	// NewVersion returns an error if it's a constraint, like: ">= 1.0, < 1.4"
	// Because NewConstraint doesn't return an error for version's like "0.0.1"
	// we check it with the NewVersion function.
	var hasVersionConstraint bool // does query contains a constraint on version?
	var keyRest string            // query key after the version field
	var versionConstraint version.Constraints
	_, err = version.NewVersion(query.Version)
	if err != nil && query.Version != "" {
		// now parse our constraint
		versionConstraint, err = version.NewConstraint(query.Version)
		if err != nil {
			// version is a malformed, just return the error
			return nil, err
		}

		hasVersionConstraint = true
		nameQuery := &protocol.KontrolQuery{
			Username:    query.Username,
			Environment: query.Environment,
			Name:        query.Name,
		}
		// We will make a get request to all nodes under this name
		// and filter the result later.
		etcdKey, _ = GetQueryKey(nameQuery)

		// Rest of the key after version field
		keyRest = "/" + strings.TrimRight(
			query.Region+"/"+query.Hostname+"/"+query.ID, "/")
	}

	resp, err := e.client.Get(KitesPrefix+etcdKey, false, true)
	if err != nil {
		// if it's something else just return
		return nil, err
	}

	kites := make(Kites, 0)

	node := NewNode(resp.Node)

	// means a query with all fields were made or a query with an ID was made,
	// in which case also returns a full path. This path has a value that
	// contains the final kite URL. Therefore this is a single kite result,
	// create it and pass it back.
	if node.HasValue() {
		oneKite, err := node.Kite()
		if err != nil {
			return nil, err
		}

		kites = append(kites, oneKite)
	} else {
		kites, err = node.Kites()
		if err != nil {
			return nil, err
		}

		// Filter kites by version constraint
		if hasVersionConstraint {
			kites.Filter(versionConstraint, keyRest)
		}
	}

	// Shuffle the list
	kites.Shuffle()

	return kites, nil
}

func (e *Etcd) etcdKey(query *protocol.KontrolQuery) (string, error) {
	if onlyIDQuery(query) {
		resp, err := e.client.Get(KitesPrefix+"/"+query.ID, false, true)
		if err != nil {
			return "", err
		}

		return resp.Node.Value, nil
	}

	return GetQueryKey(query)
}

// RegisterValue is the type of the value that is saved to etcd.
type RegisterValue struct {
	URL string `json:"url"`
}

// validateKiteKey returns a string representing the kite uniquely
// that is suitable to use as a key for etcd.
func validateKiteKey(k *protocol.Kite) error {
	fields := k.Query().Fields()

	// Validate fields.
	for k, v := range fields {
		if v == "" {
			return fmt.Errorf("Empty Kite field: %s", k)
		}
		if strings.ContainsRune(v, '/') {
			return fmt.Errorf("Field \"%s\" must not contain '/'", k)
		}
	}

	return nil
}

// onlyIDQuery returns true if the query contains only a non-empty ID and all
// others keys are empty
func onlyIDQuery(q *protocol.KontrolQuery) bool {
	fields := q.Fields()

	// check if any other key exist, if yes return a false
	for _, k := range keyOrder {
		v := fields[k]
		if k != "id" && v != "" {
			return false
		}
	}

	// now all other keys are empty, check finally for our ID
	if fields["id"] != "" {
		return true
	}

	// ID is empty too!
	return false
}

// getQueryKey returns the etcd key for the query.
func GetQueryKey(q *protocol.KontrolQuery) (string, error) {
	fields := q.Fields()

	if q.Username == "" {
		return "", errors.New("Empty username field")
	}

	// Validate query and build key.
	path := "/"

	empty := false   // encountered with empty field?
	empytField := "" // for error log

	// http://golang.org/doc/go1.3#map, order is important and we can't rely on
	// maps because the keys are not ordered :)
	for _, key := range keyOrder {
		v := fields[key]
		if v == "" {
			empty = true
			empytField = key
			continue
		}

		if empty && v != "" {
			return "", fmt.Errorf("Invalid query. Query option is not set: %s", empytField)
		}

		path = path + v + "/"
	}

	path = strings.TrimSuffix(path, "/")

	return path, nil
}

func getAudience(q *protocol.KontrolQuery) string {
	if q.Name != "" {
		return "/" + q.Username + "/" + q.Environment + "/" + q.Name
	} else if q.Environment != "" {
		return "/" + q.Username + "/" + q.Environment
	} else {
		return "/" + q.Username
	}
}
<commit_msg>kontrol: re-add when update fails<commit_after>package kontrol

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/hashicorp/go-version"
	"github.com/koding/kite"
	kontrolprotocol "github.com/koding/kite/kontrol/protocol"
	"github.com/koding/kite/protocol"
)

// keyOrder defines the order of the query paramaters.
var keyOrder = []string{
	"username",
	"environment",
	"name",
	"version",
	"region",
	"hostname",
	"id",
}

// Etcd implements the Storage interface
type Etcd struct {
	client *etcd.Client
	log    kite.Logger
}

func NewEtcd(machines []string, log kite.Logger) *Etcd {
	if machines == nil || len(machines) == 0 {
		machines = []string{"127.0.0.1:4001"}
	}

	client := etcd.NewClient(machines)
	ok := client.SetCluster(machines)
	if !ok {
		panic("cannot connect to etcd cluster: " + strings.Join(machines, ","))
	}

	return &Etcd{
		client: client,
		log:    log,
	}
}

func (e *Etcd) Delete(k *protocol.Kite) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	_, err := e.client.Delete(etcdKey, true)
	_, err = e.client.Delete(etcdIDKey, true)
	return err
}

func (e *Etcd) Clear() error {
	_, err := e.client.Delete(KitesPrefix, true)
	return err
}

func (e *Etcd) Upsert(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	return e.Add(k, value)
}

func (e *Etcd) Add(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	valueBytes, err := json.Marshal(value)
	if err != nil {
		return err
	}

	valueString := string(valueBytes)

	// Set the kite key.
	// Example "/koding/production/os/0.0.1/sj/kontainer1.sj.koding.com/1234asdf..."
	_, err = e.client.Set(etcdKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Also store the the kite.Key Id for easy lookup
	_, err = e.client.Set(etcdIDKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	return nil
}

func (e *Etcd) Update(k *protocol.Kite, value *kontrolprotocol.RegisterValue) error {
	etcdKey := KitesPrefix + k.String()
	etcdIDKey := KitesPrefix + "/" + k.ID

	valueBytes, err := json.Marshal(value)
	if err != nil {
		return err
	}

	valueString := string(valueBytes)

	// update the kite key.
	// Example "/koding/production/os/0.0.1/sj/kontainer1.sj.koding.com/1234asdf..."
	_, err = e.client.Update(etcdKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		err = e.Add(k, value)
		if err != nil {
			return err
		}
		return nil
	}

	// Also update the the kite.Key Id for easy lookup
	_, err = e.client.Update(etcdIDKey, valueString, uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	// Set the TTL for the username. Otherwise, empty dirs remain in etcd.
	_, err = e.client.Update(KitesPrefix+"/"+k.Username,
		"", uint64(KeyTTL/time.Second))
	if err != nil {
		return err
	}

	return nil
}

func (e *Etcd) Get(query *protocol.KontrolQuery) (Kites, error) {
	// We will make a get request to etcd store with this key. So get a "etcd"
	// key from the given query so that we can use it to query from Etcd.
	etcdKey, err := e.etcdKey(query)
	if err != nil {
		return nil, err
	}

	// If version field contains a constraint we need no make a new query up to
	// "name" field and filter the results after getting all versions.
	// NewVersion returns an error if it's a constraint, like: ">= 1.0, < 1.4"
	// Because NewConstraint doesn't return an error for version's like "0.0.1"
	// we check it with the NewVersion function.
	var hasVersionConstraint bool // does query contains a constraint on version?
	var keyRest string            // query key after the version field
	var versionConstraint version.Constraints
	_, err = version.NewVersion(query.Version)
	if err != nil && query.Version != "" {
		// now parse our constraint
		versionConstraint, err = version.NewConstraint(query.Version)
		if err != nil {
			// version is a malformed, just return the error
			return nil, err
		}

		hasVersionConstraint = true
		nameQuery := &protocol.KontrolQuery{
			Username:    query.Username,
			Environment: query.Environment,
			Name:        query.Name,
		}
		// We will make a get request to all nodes under this name
		// and filter the result later.
		etcdKey, _ = GetQueryKey(nameQuery)

		// Rest of the key after version field
		keyRest = "/" + strings.TrimRight(
			query.Region+"/"+query.Hostname+"/"+query.ID, "/")
	}

	resp, err := e.client.Get(KitesPrefix+etcdKey, false, true)
	if err != nil {
		// if it's something else just return
		return nil, err
	}

	kites := make(Kites, 0)

	node := NewNode(resp.Node)

	// means a query with all fields were made or a query with an ID was made,
	// in which case also returns a full path. This path has a value that
	// contains the final kite URL. Therefore this is a single kite result,
	// create it and pass it back.
	if node.HasValue() {
		oneKite, err := node.Kite()
		if err != nil {
			return nil, err
		}

		kites = append(kites, oneKite)
	} else {
		kites, err = node.Kites()
		if err != nil {
			return nil, err
		}

		// Filter kites by version constraint
		if hasVersionConstraint {
			kites.Filter(versionConstraint, keyRest)
		}
	}

	// Shuffle the list
	kites.Shuffle()

	return kites, nil
}

func (e *Etcd) etcdKey(query *protocol.KontrolQuery) (string, error) {
	if onlyIDQuery(query) {
		resp, err := e.client.Get(KitesPrefix+"/"+query.ID, false, true)
		if err != nil {
			return "", err
		}

		return resp.Node.Value, nil
	}

	return GetQueryKey(query)
}

// RegisterValue is the type of the value that is saved to etcd.
type RegisterValue struct {
	URL string `json:"url"`
}

// validateKiteKey returns a string representing the kite uniquely
// that is suitable to use as a key for etcd.
func validateKiteKey(k *protocol.Kite) error {
	fields := k.Query().Fields()

	// Validate fields.
	for k, v := range fields {
		if v == "" {
			return fmt.Errorf("Empty Kite field: %s", k)
		}
		if strings.ContainsRune(v, '/') {
			return fmt.Errorf("Field \"%s\" must not contain '/'", k)
		}
	}

	return nil
}

// onlyIDQuery returns true if the query contains only a non-empty ID and all
// others keys are empty
func onlyIDQuery(q *protocol.KontrolQuery) bool {
	fields := q.Fields()

	// check if any other key exist, if yes return a false
	for _, k := range keyOrder {
		v := fields[k]
		if k != "id" && v != "" {
			return false
		}
	}

	// now all other keys are empty, check finally for our ID
	if fields["id"] != "" {
		return true
	}

	// ID is empty too!
	return false
}

// getQueryKey returns the etcd key for the query.
func GetQueryKey(q *protocol.KontrolQuery) (string, error) {
	fields := q.Fields()

	if q.Username == "" {
		return "", errors.New("Empty username field")
	}

	// Validate query and build key.
	path := "/"

	empty := false   // encountered with empty field?
	empytField := "" // for error log

	// http://golang.org/doc/go1.3#map, order is important and we can't rely on
	// maps because the keys are not ordered :)
	for _, key := range keyOrder {
		v := fields[key]
		if v == "" {
			empty = true
			empytField = key
			continue
		}

		if empty && v != "" {
			return "", fmt.Errorf("Invalid query. Query option is not set: %s", empytField)
		}

		path = path + v + "/"
	}

	path = strings.TrimSuffix(path, "/")

	return path, nil
}

func getAudience(q *protocol.KontrolQuery) string {
	if q.Name != "" {
		return "/" + q.Username + "/" + q.Environment + "/" + q.Name
	} else if q.Environment != "" {
		return "/" + q.Username + "/" + q.Environment
	} else {
		return "/" + q.Username
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Cockroach 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.
//
// Author: joezxy (joe.zxy@foxmail.com)

package kv

import (
	"errors"
	"net"
	netrpc "net/rpc"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/roachpb"
	"github.com/cockroachdb/cockroach/rpc"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/hlc"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/retry"
	"github.com/cockroachdb/cockroach/util/stop"
	"github.com/cockroachdb/cockroach/util/tracing"
	"github.com/gogo/protobuf/proto"
	"github.com/opentracing/opentracing-go"
)

// newNodeTestContext returns a rpc.Context for testing.
// It is meant to be used by nodes.
func newNodeTestContext(clock *hlc.Clock, stopper *stop.Stopper) *rpc.Context {
	if clock == nil {
		clock = hlc.NewClock(hlc.UnixNano)
	}
	ctx := rpc.NewContext(testutils.NewNodeTestBaseContext(), clock, stopper)
	ctx.HeartbeatInterval = 10 * time.Millisecond
	ctx.HeartbeatTimeout = 5 * time.Second
	return ctx
}

func newTestServer(t *testing.T, ctx *rpc.Context) (*rpc.Server, net.Listener) {
	s := rpc.NewServer(ctx)

	tlsConfig, err := ctx.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}

	// We may be called in a loop, meaning tlsConfig is may be in used by a
	// running server during a call to `util.ListenAndServe`, which may
	// mutate it (due to http2.ConfigureServer). Make a copy to avoid trouble.
	tlsConfigCopy := *tlsConfig

	addr := util.CreateTestAddr("tcp")
	ln, err := util.ListenAndServe(ctx.Stopper, s, addr, &tlsConfigCopy)
	if err != nil {
		t.Fatal(err)
	}

	return s, ln
}

type Node time.Duration

func registerBatch(t *testing.T, s *rpc.Server, d time.Duration) {
	if err := s.RegisterPublic("Node.Batch", Node(d).Batch, &roachpb.BatchRequest{}); err != nil {
		t.Fatal(err)
	}
}

func (n Node) Batch(args proto.Message) (proto.Message, error) {
	if n > 0 {
		time.Sleep(time.Duration(n))
	}
	return &roachpb.BatchResponse{}, nil
}

func TestInvalidAddrLength(t *testing.T) {
	defer leaktest.AfterTest(t)()

	// The provided replicas is nil, so its length will be always less than the
	// specified response number
	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()
	opts := SendOptions{Trace: sp}
	ret, err := send(opts, nil, roachpb.BatchRequest{}, nil)

	// the expected return is nil and SendError
	if _, ok := err.(*roachpb.SendError); !ok || ret != nil {
		t.Fatalf("Shorter replicas should return nil and SendError.")
	}
}

// TestSendToOneClient verifies that Send correctly sends a request
// to one server using the heartbeat RPC.
func TestSendToOneClient(t *testing.T) {
	defer leaktest.AfterTest(t)()

	stopper := stop.NewStopper()
	defer stopper.Stop()

	ctx := newNodeTestContext(nil, stopper)
	s, ln := newTestServer(t, ctx)
	registerBatch(t, s, 0)

	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()

	opts := SendOptions{
		Ordering:        orderStable,
		SendNextTimeout: 1 * time.Second,
		Timeout:         10 * time.Second,
		Trace:           sp,
	}
	reply, err := sendBatch(opts, []net.Addr{ln.Addr()}, ctx)
	if err != nil {
		t.Fatal(err)
	}
	if reply == nil {
		t.Errorf("expected reply")
	}
}

// TestRetryableError verifies that Send returns a retryable error
// when it hits an RPC error.
func TestRetryableError(t *testing.T) {
	defer leaktest.AfterTest(t)()

	clientStopper := stop.NewStopper()
	defer clientStopper.Stop()
	clientContext := newNodeTestContext(nil, clientStopper)
	clientContext.HeartbeatTimeout = 10 * clientContext.HeartbeatInterval

	serverStopper := stop.NewStopper()
	serverContext := newNodeTestContext(nil, serverStopper)

	s, ln := newTestServer(t, serverContext)
	registerBatch(t, s, 0)

	c := rpc.NewClient(ln.Addr(), clientContext)
	// Wait until the client becomes healthy and shut down the server.
	<-c.Healthy()
	serverStopper.Stop()
	// Wait until the client becomes unhealthy.
	func() {
		for r := retry.Start(retry.Options{}); r.Next(); {
			select {
			case <-c.Healthy():
			case <-time.After(1 * time.Nanosecond):
				return
			}
		}
	}()

	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()

	opts := SendOptions{
		Ordering:        orderStable,
		SendNextTimeout: 100 * time.Millisecond,
		Timeout:         100 * time.Millisecond,
		Trace:           sp,
	}
	if _, err := sendBatch(opts, []net.Addr{ln.Addr()}, clientContext); err != nil {
		retryErr, ok := err.(retry.Retryable)
		if !ok {
			t.Fatalf("Unexpected error type: %v", err)
		}
		if !retryErr.CanRetry() {
			t.Errorf("Expected retryable error: %v", retryErr)
		}
	} else {
		t.Fatalf("Unexpected success")
	}
}

// TestUnretryableError verifies that Send returns an unretryable
// error when it hits a critical error.
func TestUnretryableError(t *testing.T) {
	defer leaktest.AfterTest(t)()

	stopper := stop.NewStopper()
	defer stopper.Stop()

	nodeContext := newNodeTestContext(nil, stopper)
	_, ln := newTestServer(t, nodeContext)

	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()

	opts := SendOptions{
		Ordering:        orderStable,
		SendNextTimeout: 1 * time.Second,
		Timeout:         10 * time.Second,
		Trace:           sp,
	}

	sendOneFn = func(client *batchClient, timeout time.Duration,
		context *rpc.Context, trace opentracing.Span, done chan *netrpc.Call) {
		call := netrpc.Call{
			Reply: &roachpb.BatchResponse{},
		}
		call.Error = errors.New("unretryable")
		done <- &call
	}
	defer func() { sendOneFn = sendOne }()

	_, err := sendBatch(opts, []net.Addr{ln.Addr()}, nodeContext)
	if err == nil {
		t.Fatalf("Unexpected success")
	}
	retryErr, ok := err.(retry.Retryable)
	if !ok {
		t.Fatalf("Unexpected error type: %v", err)
	}
	if retryErr.CanRetry() {
		t.Errorf("Unexpected retryable error: %v", retryErr)
	}
}

// TestClientNotReady verifies that Send gets an RPC error when a client
// does not become ready.
func TestClientNotReady(t *testing.T) {
	defer leaktest.AfterTest(t)()

	stopper := stop.NewStopper()
	defer stopper.Stop()

	nodeContext := newNodeTestContext(nil, stopper)

	// Construct a server that listens but doesn't do anything.
	s, ln := newTestServer(t, nodeContext)
	registerBatch(t, s, 50*time.Millisecond)

	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()

	opts := SendOptions{
		Ordering:        orderStable,
		SendNextTimeout: 100 * time.Nanosecond,
		Timeout:         100 * time.Nanosecond,
		Trace:           sp,
	}

	// Send RPC to an address where no server is running.
	if _, err := sendBatch(opts, []net.Addr{ln.Addr()}, nodeContext); err != nil {
		retryErr, ok := err.(retry.Retryable)
		if !ok {
			t.Fatalf("Unexpected error type: %v", err)
		}
		if !retryErr.CanRetry() {
			t.Errorf("Expected retryable error: %v", retryErr)
		}
	} else {
		t.Fatalf("Unexpected success")
	}

	// Send the RPC again with no timeout.
	opts.SendNextTimeout = 0
	opts.Timeout = 0
	c := make(chan error)
	go func() {
		if _, err := sendBatch(opts, []net.Addr{ln.Addr()}, nodeContext); err == nil {
			c <- util.Errorf("expected error when client is closed")
		} else if !strings.Contains(err.Error(), "failed as client connection was closed") {
			c <- err
		}
		close(c)
	}()

	select {
	case <-c:
		t.Fatalf("Unexpected end of rpc call")
	case <-time.After(1 * time.Millisecond):
	}

	// Grab the client for our invalid address and close it. This will cause the
	// blocked ping RPC to finish.
	rpc.NewClient(ln.Addr(), nodeContext).Close()
	if err := <-c; err != nil {
		t.Fatal(err)
	}
}

// TestComplexScenarios verifies various complex success/failure scenarios by
// mocking sendOne.
func TestComplexScenarios(t *testing.T) {
	defer leaktest.AfterTest(t)()

	stopper := stop.NewStopper()
	defer stopper.Stop()

	nodeContext := newNodeTestContext(nil, stopper)

	testCases := []struct {
		numServers               int
		numErrors                int
		numRetryableErrors       int
		success                  bool
		isRetryableErrorExpected bool
	}{
		// --- Success scenarios ---
		{1, 0, 0, true, false},
		{5, 0, 0, true, false},
		// There are some errors, but enough RPCs succeed.
		{5, 1, 0, true, false},
		{5, 4, 0, true, false},
		{5, 2, 0, true, false},

		// --- Failure scenarios ---
		// All RPCs fail.
		{5, 5, 0, false, false},
		// All RPCs fail, but some of the errors are retryable.
		{5, 5, 1, false, true},
		{5, 5, 3, false, true},
		// Some RPCs fail, but we do have enough remaining clients and recoverable errors.
		{5, 5, 2, false, true},
	}
	for i, test := range testCases {
		// Copy the values to avoid data race. sendOneFn might
		// be called after this test case finishes.
		numErrors := test.numErrors
		numRetryableErrors := test.numRetryableErrors

		var serverAddrs []net.Addr
		for j := 0; j < test.numServers; j++ {
			_, ln := newTestServer(t, nodeContext)
			serverAddrs = append(serverAddrs, ln.Addr())
		}

		sp := tracing.NewTracer().StartSpan("node test")
		defer sp.Finish()

		opts := SendOptions{
			Ordering:        orderStable,
			SendNextTimeout: 1 * time.Second,
			Timeout:         10 * time.Second,
			Trace:           sp,
		}

		// Mock sendOne.
		sendOneFn = func(client *batchClient, timeout time.Duration,
			context *rpc.Context, trace opentracing.Span, done chan *netrpc.Call) {
			addr := client.RemoteAddr()
			addrID := -1
			for serverAddrID, serverAddr := range serverAddrs {
				if serverAddr.String() == addr.String() {
					addrID = serverAddrID
					break
				}
			}
			if addrID == -1 {
				t.Fatalf("%d: %v is not found in serverAddrs: %v", i, addr, serverAddrs)
			}
			call := netrpc.Call{
				Reply: &roachpb.BatchResponse{},
			}
			if addrID < numErrors {
				call.Error = roachpb.NewSendError("test", addrID < numRetryableErrors)
			}
			done <- &call
		}
		defer func() { sendOneFn = sendOne }()

		reply, err := sendBatch(opts, serverAddrs, nodeContext)
		if test.success {
			if reply == nil {
				t.Errorf("%d: expected reply", i)
			}
			continue
		}

		retryErr, ok := err.(retry.Retryable)
		if !ok {
			t.Fatalf("%d: Unexpected error type: %v", i, err)
		}
		if retryErr.CanRetry() != test.isRetryableErrorExpected {
			t.Errorf("%d: Unexpected error: %v", i, retryErr)
		}
	}
}

func makeReplicas(addrs ...net.Addr) ReplicaSlice {
	replicas := make(ReplicaSlice, len(addrs))
	for i, addr := range addrs {
		replicas[i].NodeDesc = &roachpb.NodeDescriptor{
			Address: util.MakeUnresolvedAddr(addr.Network(), addr.String()),
		}
	}
	return replicas
}

// sendBatch sends Batch requests to specified addresses using send.
func sendBatch(opts SendOptions, addrs []net.Addr, rpcContext *rpc.Context) (proto.Message, error) {
	return send(opts, makeReplicas(addrs...), roachpb.BatchRequest{}, rpcContext)
}
<commit_msg>kv: disable flaky test TestClientNotReady<commit_after>// Copyright 2015 The Cockroach 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.
//
// Author: joezxy (joe.zxy@foxmail.com)

package kv

import (
	"errors"
	"net"
	netrpc "net/rpc"
	"strings"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/roachpb"
	"github.com/cockroachdb/cockroach/rpc"
	"github.com/cockroachdb/cockroach/testutils"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/hlc"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/retry"
	"github.com/cockroachdb/cockroach/util/stop"
	"github.com/cockroachdb/cockroach/util/tracing"
	"github.com/gogo/protobuf/proto"
	"github.com/opentracing/opentracing-go"
)

// newNodeTestContext returns a rpc.Context for testing.
// It is meant to be used by nodes.
func newNodeTestContext(clock *hlc.Clock, stopper *stop.Stopper) *rpc.Context {
	if clock == nil {
		clock = hlc.NewClock(hlc.UnixNano)
	}
	ctx := rpc.NewContext(testutils.NewNodeTestBaseContext(), clock, stopper)
	ctx.HeartbeatInterval = 10 * time.Millisecond
	ctx.HeartbeatTimeout = 5 * time.Second
	return ctx
}

func newTestServer(t *testing.T, ctx *rpc.Context) (*rpc.Server, net.Listener) {
	s := rpc.NewServer(ctx)

	tlsConfig, err := ctx.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}

	// We may be called in a loop, meaning tlsConfig is may be in used by a
	// running server during a call to `util.ListenAndServe`, which may
	// mutate it (due to http2.ConfigureServer). Make a copy to avoid trouble.
	tlsConfigCopy := *tlsConfig

	addr := util.CreateTestAddr("tcp")
	ln, err := util.ListenAndServe(ctx.Stopper, s, addr, &tlsConfigCopy)
	if err != nil {
		t.Fatal(err)
	}

	return s, ln
}

type Node time.Duration

func registerBatch(t *testing.T, s *rpc.Server, d time.Duration) {
	if err := s.RegisterPublic("Node.Batch", Node(d).Batch, &roachpb.BatchRequest{}); err != nil {
		t.Fatal(err)
	}
}

func (n Node) Batch(args proto.Message) (proto.Message, error) {
	if n > 0 {
		time.Sleep(time.Duration(n))
	}
	return &roachpb.BatchResponse{}, nil
}

func TestInvalidAddrLength(t *testing.T) {
	defer leaktest.AfterTest(t)()

	// The provided replicas is nil, so its length will be always less than the
	// specified response number
	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()
	opts := SendOptions{Trace: sp}
	ret, err := send(opts, nil, roachpb.BatchRequest{}, nil)

	// the expected return is nil and SendError
	if _, ok := err.(*roachpb.SendError); !ok || ret != nil {
		t.Fatalf("Shorter replicas should return nil and SendError.")
	}
}

// TestSendToOneClient verifies that Send correctly sends a request
// to one server using the heartbeat RPC.
func TestSendToOneClient(t *testing.T) {
	defer leaktest.AfterTest(t)()

	stopper := stop.NewStopper()
	defer stopper.Stop()

	ctx := newNodeTestContext(nil, stopper)
	s, ln := newTestServer(t, ctx)
	registerBatch(t, s, 0)

	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()

	opts := SendOptions{
		Ordering:        orderStable,
		SendNextTimeout: 1 * time.Second,
		Timeout:         10 * time.Second,
		Trace:           sp,
	}
	reply, err := sendBatch(opts, []net.Addr{ln.Addr()}, ctx)
	if err != nil {
		t.Fatal(err)
	}
	if reply == nil {
		t.Errorf("expected reply")
	}
}

// TestRetryableError verifies that Send returns a retryable error
// when it hits an RPC error.
func TestRetryableError(t *testing.T) {
	defer leaktest.AfterTest(t)()

	clientStopper := stop.NewStopper()
	defer clientStopper.Stop()
	clientContext := newNodeTestContext(nil, clientStopper)
	clientContext.HeartbeatTimeout = 10 * clientContext.HeartbeatInterval

	serverStopper := stop.NewStopper()
	serverContext := newNodeTestContext(nil, serverStopper)

	s, ln := newTestServer(t, serverContext)
	registerBatch(t, s, 0)

	c := rpc.NewClient(ln.Addr(), clientContext)
	// Wait until the client becomes healthy and shut down the server.
	<-c.Healthy()
	serverStopper.Stop()
	// Wait until the client becomes unhealthy.
	func() {
		for r := retry.Start(retry.Options{}); r.Next(); {
			select {
			case <-c.Healthy():
			case <-time.After(1 * time.Nanosecond):
				return
			}
		}
	}()

	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()

	opts := SendOptions{
		Ordering:        orderStable,
		SendNextTimeout: 100 * time.Millisecond,
		Timeout:         100 * time.Millisecond,
		Trace:           sp,
	}
	if _, err := sendBatch(opts, []net.Addr{ln.Addr()}, clientContext); err != nil {
		retryErr, ok := err.(retry.Retryable)
		if !ok {
			t.Fatalf("Unexpected error type: %v", err)
		}
		if !retryErr.CanRetry() {
			t.Errorf("Expected retryable error: %v", retryErr)
		}
	} else {
		t.Fatalf("Unexpected success")
	}
}

// TestUnretryableError verifies that Send returns an unretryable
// error when it hits a critical error.
func TestUnretryableError(t *testing.T) {
	defer leaktest.AfterTest(t)()

	stopper := stop.NewStopper()
	defer stopper.Stop()

	nodeContext := newNodeTestContext(nil, stopper)
	_, ln := newTestServer(t, nodeContext)

	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()

	opts := SendOptions{
		Ordering:        orderStable,
		SendNextTimeout: 1 * time.Second,
		Timeout:         10 * time.Second,
		Trace:           sp,
	}

	sendOneFn = func(client *batchClient, timeout time.Duration,
		context *rpc.Context, trace opentracing.Span, done chan *netrpc.Call) {
		call := netrpc.Call{
			Reply: &roachpb.BatchResponse{},
		}
		call.Error = errors.New("unretryable")
		done <- &call
	}
	defer func() { sendOneFn = sendOne }()

	_, err := sendBatch(opts, []net.Addr{ln.Addr()}, nodeContext)
	if err == nil {
		t.Fatalf("Unexpected success")
	}
	retryErr, ok := err.(retry.Retryable)
	if !ok {
		t.Fatalf("Unexpected error type: %v", err)
	}
	if retryErr.CanRetry() {
		t.Errorf("Unexpected retryable error: %v", retryErr)
	}
}

// TestClientNotReady verifies that Send gets an RPC error when a client
// does not become ready.
func TestClientNotReady(t *testing.T) {
	defer leaktest.AfterTest(t)()
	t.Skip("TODO(tamird): #3942")

	stopper := stop.NewStopper()
	defer stopper.Stop()

	nodeContext := newNodeTestContext(nil, stopper)

	// Construct a server that listens but doesn't do anything.
	s, ln := newTestServer(t, nodeContext)
	registerBatch(t, s, 50*time.Millisecond)

	sp := tracing.NewTracer().StartSpan("node test")
	defer sp.Finish()

	opts := SendOptions{
		Ordering:        orderStable,
		SendNextTimeout: 100 * time.Nanosecond,
		Timeout:         100 * time.Nanosecond,
		Trace:           sp,
	}

	// Send RPC to an address where no server is running.
	if _, err := sendBatch(opts, []net.Addr{ln.Addr()}, nodeContext); err != nil {
		retryErr, ok := err.(retry.Retryable)
		if !ok {
			t.Fatalf("Unexpected error type: %v", err)
		}
		if !retryErr.CanRetry() {
			t.Errorf("Expected retryable error: %v", retryErr)
		}
	} else {
		t.Fatalf("Unexpected success")
	}

	// Send the RPC again with no timeout.
	opts.SendNextTimeout = 0
	opts.Timeout = 0
	c := make(chan error)
	go func() {
		if _, err := sendBatch(opts, []net.Addr{ln.Addr()}, nodeContext); err == nil {
			c <- util.Errorf("expected error when client is closed")
		} else if !strings.Contains(err.Error(), "failed as client connection was closed") {
			c <- err
		}
		close(c)
	}()

	select {
	case <-c:
		t.Fatalf("Unexpected end of rpc call")
	case <-time.After(1 * time.Millisecond):
	}

	// Grab the client for our invalid address and close it. This will cause the
	// blocked ping RPC to finish.
	rpc.NewClient(ln.Addr(), nodeContext).Close()
	if err := <-c; err != nil {
		t.Fatal(err)
	}
}

// TestComplexScenarios verifies various complex success/failure scenarios by
// mocking sendOne.
func TestComplexScenarios(t *testing.T) {
	defer leaktest.AfterTest(t)()

	stopper := stop.NewStopper()
	defer stopper.Stop()

	nodeContext := newNodeTestContext(nil, stopper)

	testCases := []struct {
		numServers               int
		numErrors                int
		numRetryableErrors       int
		success                  bool
		isRetryableErrorExpected bool
	}{
		// --- Success scenarios ---
		{1, 0, 0, true, false},
		{5, 0, 0, true, false},
		// There are some errors, but enough RPCs succeed.
		{5, 1, 0, true, false},
		{5, 4, 0, true, false},
		{5, 2, 0, true, false},

		// --- Failure scenarios ---
		// All RPCs fail.
		{5, 5, 0, false, false},
		// All RPCs fail, but some of the errors are retryable.
		{5, 5, 1, false, true},
		{5, 5, 3, false, true},
		// Some RPCs fail, but we do have enough remaining clients and recoverable errors.
		{5, 5, 2, false, true},
	}
	for i, test := range testCases {
		// Copy the values to avoid data race. sendOneFn might
		// be called after this test case finishes.
		numErrors := test.numErrors
		numRetryableErrors := test.numRetryableErrors

		var serverAddrs []net.Addr
		for j := 0; j < test.numServers; j++ {
			_, ln := newTestServer(t, nodeContext)
			serverAddrs = append(serverAddrs, ln.Addr())
		}

		sp := tracing.NewTracer().StartSpan("node test")
		defer sp.Finish()

		opts := SendOptions{
			Ordering:        orderStable,
			SendNextTimeout: 1 * time.Second,
			Timeout:         10 * time.Second,
			Trace:           sp,
		}

		// Mock sendOne.
		sendOneFn = func(client *batchClient, timeout time.Duration,
			context *rpc.Context, trace opentracing.Span, done chan *netrpc.Call) {
			addr := client.RemoteAddr()
			addrID := -1
			for serverAddrID, serverAddr := range serverAddrs {
				if serverAddr.String() == addr.String() {
					addrID = serverAddrID
					break
				}
			}
			if addrID == -1 {
				t.Fatalf("%d: %v is not found in serverAddrs: %v", i, addr, serverAddrs)
			}
			call := netrpc.Call{
				Reply: &roachpb.BatchResponse{},
			}
			if addrID < numErrors {
				call.Error = roachpb.NewSendError("test", addrID < numRetryableErrors)
			}
			done <- &call
		}
		defer func() { sendOneFn = sendOne }()

		reply, err := sendBatch(opts, serverAddrs, nodeContext)
		if test.success {
			if reply == nil {
				t.Errorf("%d: expected reply", i)
			}
			continue
		}

		retryErr, ok := err.(retry.Retryable)
		if !ok {
			t.Fatalf("%d: Unexpected error type: %v", i, err)
		}
		if retryErr.CanRetry() != test.isRetryableErrorExpected {
			t.Errorf("%d: Unexpected error: %v", i, retryErr)
		}
	}
}

func makeReplicas(addrs ...net.Addr) ReplicaSlice {
	replicas := make(ReplicaSlice, len(addrs))
	for i, addr := range addrs {
		replicas[i].NodeDesc = &roachpb.NodeDescriptor{
			Address: util.MakeUnresolvedAddr(addr.Network(), addr.String()),
		}
	}
	return replicas
}

// sendBatch sends Batch requests to specified addresses using send.
func sendBatch(opts SendOptions, addrs []net.Addr, rpcContext *rpc.Context) (proto.Message, error) {
	return send(opts, makeReplicas(addrs...), roachpb.BatchRequest{}, rpcContext)
}
<|endoftext|>