<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/andrew-d/go-termutil"
	"github.com/cloudfoundry/cli/plugin"
)

type AppStatus struct {
	name           string
	countRunning   int
	countRequested int
	state          string
}

type ScaleoverCmd struct {
	app1     AppStatus
	app2     AppStatus
	maxcount int
}

//GetMetadata returns metatada
func (cmd *ScaleoverCmd) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "scaleover",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 1,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "scaleover",
				HelpText: "Roll http traffic from one application to another",
				UsageDetails: plugin.Usage{
					Usage: "cf scaleover APP1 APP2 ROLLOVER_DURATION",
				},
			},
		},
	}
}

func main() {
	plugin.Start(new(ScaleoverCmd))
}

func (cmd *ScaleoverCmd) usage(args []string) error {
	if 4 != len(args) {
		return errors.New("Usage: cf scaleover\n\tcf scaleover APP1 APP2 ROLLOVER_DURATION")
	}
	return nil
}

func (cmd *ScaleoverCmd) parseTime(duration string) (time.Duration, error) {
	rolloverTime := time.Duration(0)
	var err error
	rolloverTime, err = time.ParseDuration(duration)

	if err != nil {
		return rolloverTime, err
	}
	if 0 > rolloverTime {
		return rolloverTime, errors.New("Duration must be a positive number in the format of 1m")
	}

	return rolloverTime, nil
}

func (cmd *ScaleoverCmd) Run(cliConnection plugin.CliConnection, args []string) {
	if args[0] == "scaleover" {
		cmd.ScaleoverCommand(cliConnection, args)
	}
}

func (cmd *ScaleoverCmd) ScaleoverCommand(cliConnection plugin.CliConnection, args []string) {
	err := cmd.usage(args)
	if nil != err {
		fmt.Println(err)
		os.Exit(1)
	}

	rolloverTime, err := cmd.parseTime(args[3])
	if nil != err {
		fmt.Println(err)
		os.Exit(1)
	}

	// The getAppStatus calls will exit with an error if the named apps don't exist
	cmd.app1, err = cmd.getAppStatus(cliConnection, args[1])
	if nil != err {
		fmt.Println(err)
		os.Exit(1)
	}

	cmd.app2, err = cmd.getAppStatus(cliConnection, args[2])
	if nil != err {
		fmt.Println(err)
		os.Exit(1)
	}

	cmd.showStatus()

	count := cmd.app1.countRequested
	sleepInterval := time.Duration(rolloverTime.Nanoseconds() / int64(count))

	for count > 0 {
		count--
		cmd.app2.scaleUp(cliConnection)
		cmd.app1.scaleDown(cliConnection)
		cmd.showStatus()
		if count > 0 {
			time.Sleep(sleepInterval)
		}
	}
	fmt.Println()
}

func (cmd *ScaleoverCmd) getAppStatus(cliConnection plugin.CliConnection, name string) (AppStatus, error) {
	status := AppStatus{
		name:           name,
		countRunning:   0,
		countRequested: 0,
		state:          "unknown",
	}

	output, _ := cliConnection.CliCommandWithoutTerminalOutput("app", name)

	for idx, v := range output {
		v = strings.TrimSpace(v)
		if strings.HasPrefix(v, "FAILED") {
			e := output[idx+1]
			return status, errors.New(e)
		}
		if strings.HasPrefix(v, "requested state: ") {
			status.state = strings.TrimPrefix(v, "requested state: ")
		}
		if strings.HasPrefix(v, "instances: ") {
			instances := strings.TrimPrefix(v, "instances: ")
			split := strings.Split(instances, "/")
			status.countRunning, _ = strconv.Atoi(split[0])
			status.countRequested, _ = strconv.Atoi(split[1])
		}
	}
	// Compensate for some CF weirdness that leaves the requested instances non-zero
	// even though the app is stopped
	if "stopped" == status.state {
		status.countRequested = 0
	}
	return status, nil
}

func (app *AppStatus) scaleUp(cliConnection plugin.CliConnection) {
	// If not already started, start it
	if app.state != "started" {
		cliConnection.CliCommandWithoutTerminalOutput("start", app.name)
		app.state = "started"
	}
	app.countRequested++
	cliConnection.CliCommandWithoutTerminalOutput("scale", "-i", strconv.Itoa(app.countRequested), app.name)
}

func (app *AppStatus) scaleDown(cliConnection plugin.CliConnection) {
	app.countRequested--
	// If going to zero, stop the app
	if app.countRequested == 0 {
		cliConnection.CliCommandWithoutTerminalOutput("stop", app.name)
		app.state = "stopped"
	} else {
		cliConnection.CliCommandWithoutTerminalOutput("scale", "-i", strconv.Itoa(app.countRequested), app.name)
	}
}

func (cmd *ScaleoverCmd) showStatus() {
	if termutil.Isatty(os.Stdout.Fd()) {
		fmt.Printf("%s (%s) %s %s %s (%s) \r",
			cmd.app1.name,
			cmd.app1.state,
			strings.Repeat("<", cmd.app1.countRequested),
			strings.Repeat(">", cmd.app2.countRequested),
			cmd.app2.name,
			cmd.app2.state,
		)
	} else {
		fmt.Printf("%s (%s) %d instances, %s (%s) %d instances\n",
			cmd.app1.name,
			cmd.app1.state,
			cmd.app1.countRequested,
			cmd.app2.name,
			cmd.app2.state,
			cmd.app2.countRequested,
		)
	}
}
<commit_msg>Proper handling of "Nothing to do"<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/andrew-d/go-termutil"
	"github.com/cloudfoundry/cli/plugin"
)

type AppStatus struct {
	name           string
	countRunning   int
	countRequested int
	state          string
}

type ScaleoverCmd struct {
	app1     AppStatus
	app2     AppStatus
	maxcount int
}

//GetMetadata returns metatada
func (cmd *ScaleoverCmd) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "scaleover",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 1,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "scaleover",
				HelpText: "Roll http traffic from one application to another",
				UsageDetails: plugin.Usage{
					Usage: "cf scaleover APP1 APP2 ROLLOVER_DURATION",
				},
			},
		},
	}
}

func main() {
	plugin.Start(new(ScaleoverCmd))
}

func (cmd *ScaleoverCmd) usage(args []string) error {
	if 4 != len(args) {
		return errors.New("Usage: cf scaleover\n\tcf scaleover APP1 APP2 ROLLOVER_DURATION")
	}
	return nil
}

func (cmd *ScaleoverCmd) parseTime(duration string) (time.Duration, error) {
	rolloverTime := time.Duration(0)
	var err error
	rolloverTime, err = time.ParseDuration(duration)

	if err != nil {
		return rolloverTime, err
	}
	if 0 > rolloverTime {
		return rolloverTime, errors.New("Duration must be a positive number in the format of 1m")
	}

	return rolloverTime, nil
}

func (cmd *ScaleoverCmd) Run(cliConnection plugin.CliConnection, args []string) {
	if args[0] == "scaleover" {
		cmd.ScaleoverCommand(cliConnection, args)
	}
}

func (cmd *ScaleoverCmd) ScaleoverCommand(cliConnection plugin.CliConnection, args []string) {
	err := cmd.usage(args)
	if nil != err {
		fmt.Println(err)
		os.Exit(1)
	}

	rolloverTime, err := cmd.parseTime(args[3])
	if nil != err {
		fmt.Println(err)
		os.Exit(1)
	}

	// The getAppStatus calls will exit with an error if the named apps don't exist
	cmd.app1, err = cmd.getAppStatus(cliConnection, args[1])
	if nil != err {
		fmt.Println(err)
		os.Exit(1)
	}

	cmd.app2, err = cmd.getAppStatus(cliConnection, args[2])
	if nil != err {
		fmt.Println(err)
		os.Exit(1)
	}

	cmd.showStatus()

	count := cmd.app1.countRequested
	if (count == 0) {
		fmt.Println("There are no instances of the source app to scale over")
		os.Exit(0)
	}
	sleepInterval := time.Duration(rolloverTime.Nanoseconds() / int64(count))

	for count > 0 {
		count--
		cmd.app2.scaleUp(cliConnection)
		cmd.app1.scaleDown(cliConnection)
		cmd.showStatus()
		if count > 0 {
			time.Sleep(sleepInterval)
		}
	}
	fmt.Println()
}

func (cmd *ScaleoverCmd) getAppStatus(cliConnection plugin.CliConnection, name string) (AppStatus, error) {
	status := AppStatus{
		name:           name,
		countRunning:   0,
		countRequested: 0,
		state:          "unknown",
	}

	output, _ := cliConnection.CliCommandWithoutTerminalOutput("app", name)

	for idx, v := range output {
		v = strings.TrimSpace(v)
		if strings.HasPrefix(v, "FAILED") {
			e := output[idx+1]
			return status, errors.New(e)
		}
		if strings.HasPrefix(v, "requested state: ") {
			status.state = strings.TrimPrefix(v, "requested state: ")
		}
		if strings.HasPrefix(v, "instances: ") {
			instances := strings.TrimPrefix(v, "instances: ")
			split := strings.Split(instances, "/")
			status.countRunning, _ = strconv.Atoi(split[0])
			status.countRequested, _ = strconv.Atoi(split[1])
		}
	}
	// Compensate for some CF weirdness that leaves the requested instances non-zero
	// even though the app is stopped
	if "stopped" == status.state {
		status.countRequested = 0
	}
	return status, nil
}

func (app *AppStatus) scaleUp(cliConnection plugin.CliConnection) {
	// If not already started, start it
	if app.state != "started" {
		cliConnection.CliCommandWithoutTerminalOutput("start", app.name)
		app.state = "started"
	}
	app.countRequested++
	cliConnection.CliCommandWithoutTerminalOutput("scale", "-i", strconv.Itoa(app.countRequested), app.name)
}

func (app *AppStatus) scaleDown(cliConnection plugin.CliConnection) {
	app.countRequested--
	// If going to zero, stop the app
	if app.countRequested == 0 {
		cliConnection.CliCommandWithoutTerminalOutput("stop", app.name)
		app.state = "stopped"
	} else {
		cliConnection.CliCommandWithoutTerminalOutput("scale", "-i", strconv.Itoa(app.countRequested), app.name)
	}
}

func (cmd *ScaleoverCmd) showStatus() {
	if termutil.Isatty(os.Stdout.Fd()) {
		fmt.Printf("%s (%s) %s %s %s (%s) \r",
			cmd.app1.name,
			cmd.app1.state,
			strings.Repeat("<", cmd.app1.countRequested),
			strings.Repeat(">", cmd.app2.countRequested),
			cmd.app2.name,
			cmd.app2.state,
		)
	} else {
		fmt.Printf("%s (%s) %d instances, %s (%s) %d instances\n",
			cmd.app1.name,
			cmd.app1.state,
			cmd.app1.countRequested,
			cmd.app2.name,
			cmd.app2.state,
			cmd.app2.countRequested,
		)
	}
}
<|endoftext|>


<commit_before>package scamp

import "errors"
import "crypto/tls"
import "fmt"
import "sync"

type msgNoType int64;

type Connection struct {
	conn        *tls.Conn
	Fingerprint string
	msgCnt      msgNoType

	sessDemuxMutex *sync.Mutex
	sessDemux    map[msgNoType](*Session)
	newSessions  (chan *Session)
}

// Establish secure connection to remote service.
// You must use the *connection.Fingerprint to verify the
// remote host
func Connect(connspec string) (conn *Connection, err error) {
	config := &tls.Config{
		InsecureSkipVerify: true,
	}
	config.BuildNameToCertificate()

	tlsConn, err := tls.Dial("tcp", connspec, config)
	if err != nil {
		return
	}

	sessChan := make(chan *Session, 100)

	conn,err = newConnection(tlsConn, sessChan)
	if err != nil {
		return
	}
	go conn.packetRouter(true, false)

	return
}

func newConnection(tlsConn *tls.Conn, sessChan (chan *Session)) (conn *Connection, err error) {
	conn = new(Connection)
	conn.conn = tlsConn

	conn.sessDemuxMutex = new(sync.Mutex)
	conn.sessDemux = make(map[msgNoType](*Session))
	conn.newSessions = sessChan

	// TODO get the end entity certificate instead
	peerCerts := conn.conn.ConnectionState().PeerCertificates
	if len(peerCerts) == 1 {
		peerCert := peerCerts[0]
		conn.Fingerprint = sha1FingerPrint(peerCert)
	}

	return
}

// Demultiplex packets to their proper buffers.
func (conn *Connection) packetRouter(ignoreUnknownSessions bool, isService bool) (err error) {
	var pkt Packet
	var sess *Session

	for {
		pkt, err = ReadPacket(conn.conn)
		if err != nil {
			// TODO: what are the issues with stopping a packet router here?
			// The socket has probably closed
			Error.Printf("err reading packet: `%s`. (EOF is normal). Returning.", err)
			return
		}

		conn.sessDemuxMutex.Lock()
		sess = conn.sessDemux[pkt.msgNo]
		if sess == nil && !ignoreUnknownSessions {
			sess = newSession(pkt.msgNo, conn)
			conn.sessDemux[pkt.msgNo] = sess
			conn.sessDemuxMutex.Unlock()
			conn.newSessions <- sess // Could block and holding the DemuxMutex would block other tasks (namely: sending requests)
		} else {
			conn.sessDemuxMutex.Unlock()
		}

		if sess == nil && ignoreUnknownSessions {
			err = errors.New(fmt.Sprintf("packet (msgNo: %d) has no corresponding session", pkt.msgNo))
			continue
		}

		if pkt.packetType == HEADER {
			Trace.Printf("(incoming SESS %d) HEADER packet\n", pkt.msgNo)
			sess.Append(pkt)
		} else if pkt.packetType == DATA {
			Trace.Printf("(incoming SESS %d) DATA packet (%d bytes)\n", pkt.msgNo, len(pkt.body))
			sess.Append(pkt)
		} else if pkt.packetType == EOF {
			Trace.Printf("(incoming SESS %d) EOF packet\n", pkt.msgNo)
			// TODO: need polymorphism on Req/Reply so they can be delivered
			if isService {
				Trace.Printf("session delivering request")
				sess.DeliverRequest()
			} else {
				Trace.Printf("session delivering reply")
				go sess.DeliverReply()
			}
		} else if pkt.packetType == TXERR {
			Trace.Printf("(incoming SESS %d) TXERR\n`%s`", pkt.msgNo, pkt.body)
			// TODO: need polymorphism on Req/Reply so they can be delivered
			if isService {
				sess.DeliverRequest()
			} else {
				go sess.DeliverReply()
			}
		} else {
			Trace.Printf("(incoming SESS %d) unknown packet type %d\n", pkt.packetType)
		}
	}

	return
}

func (conn *Connection) NewSession() (sess *Session, err error) {
	sess = new(Session)

	sess.conn = conn

	sess.msgNo = conn.msgCnt
	conn.msgCnt = conn.msgCnt + 1

	sess.replyChan = make(chan Reply, 1)

	conn.sessDemux[sess.msgNo] = sess

	return
}

func (conn *Connection) Send(req Request) (sess *Session, err error) {
	// The lock must be held until the first packet is sent.
	// With the current structure it will hold the lock until all
	// packets for req are sent
	conn.sessDemuxMutex.Lock()
	sess,err = conn.NewSession()
	if err != nil {
		return
	}

	err = sess.SendRequest(req)
	Trace.Printf("sending request (%d bytes)", len(req.Blob) )
	if err != nil {
		return
	}
	conn.sessDemuxMutex.Unlock()

	return
}

// Pulls full Requests out of master Request chan
// func (conn *Connection) Recv() Session {
// 	return <-conn.sessionChan
// }

func (conn *Connection) Close() {
	conn.conn.Close()
}

func (conn *Connection) Recv() (sess *Session) {
	sess = <-conn.newSessions
	return
}

func (conn *Connection) Free(sess *Session) {
	conn.sessDemuxMutex.Lock()
	msgNo := sess.packets[0].msgNo
	delete(conn.sessDemux, msgNo)
	conn.sessDemuxMutex.Unlock()
}
<commit_msg>Not a very useful print statement<commit_after>package scamp

import "errors"
import "crypto/tls"
import "fmt"
import "sync"

type msgNoType int64;

type Connection struct {
	conn        *tls.Conn
	Fingerprint string
	msgCnt      msgNoType

	sessDemuxMutex *sync.Mutex
	sessDemux    map[msgNoType](*Session)
	newSessions  (chan *Session)
}

// Establish secure connection to remote service.
// You must use the *connection.Fingerprint to verify the
// remote host
func Connect(connspec string) (conn *Connection, err error) {
	config := &tls.Config{
		InsecureSkipVerify: true,
	}
	config.BuildNameToCertificate()

	tlsConn, err := tls.Dial("tcp", connspec, config)
	if err != nil {
		return
	}

	sessChan := make(chan *Session, 100)

	conn,err = newConnection(tlsConn, sessChan)
	if err != nil {
		return
	}
	go conn.packetRouter(true, false)

	return
}

func newConnection(tlsConn *tls.Conn, sessChan (chan *Session)) (conn *Connection, err error) {
	conn = new(Connection)
	conn.conn = tlsConn

	conn.sessDemuxMutex = new(sync.Mutex)
	conn.sessDemux = make(map[msgNoType](*Session))
	conn.newSessions = sessChan

	// TODO get the end entity certificate instead
	peerCerts := conn.conn.ConnectionState().PeerCertificates
	if len(peerCerts) == 1 {
		peerCert := peerCerts[0]
		conn.Fingerprint = sha1FingerPrint(peerCert)
	}

	return
}

// Demultiplex packets to their proper buffers.
func (conn *Connection) packetRouter(ignoreUnknownSessions bool, isService bool) (err error) {
	var pkt Packet
	var sess *Session

	for {
		pkt, err = ReadPacket(conn.conn)
		if err != nil {
			// TODO: what are the issues with stopping a packet router here?
			// The socket has probably closed
			// Error.Printf("err reading packet: `%s`. (EOF is normal). Returning.", err)
			return
		}

		conn.sessDemuxMutex.Lock()
		sess = conn.sessDemux[pkt.msgNo]
		if sess == nil && !ignoreUnknownSessions {
			sess = newSession(pkt.msgNo, conn)
			conn.sessDemux[pkt.msgNo] = sess
			conn.sessDemuxMutex.Unlock()
			conn.newSessions <- sess // Could block and holding the DemuxMutex would block other tasks (namely: sending requests)
		} else {
			conn.sessDemuxMutex.Unlock()
		}

		if sess == nil && ignoreUnknownSessions {
			err = errors.New(fmt.Sprintf("packet (msgNo: %d) has no corresponding session", pkt.msgNo))
			continue
		}

		if pkt.packetType == HEADER {
			Trace.Printf("(incoming SESS %d) HEADER packet\n", pkt.msgNo)
			sess.Append(pkt)
		} else if pkt.packetType == DATA {
			Trace.Printf("(incoming SESS %d) DATA packet (%d bytes)\n", pkt.msgNo, len(pkt.body))
			sess.Append(pkt)
		} else if pkt.packetType == EOF {
			Trace.Printf("(incoming SESS %d) EOF packet\n", pkt.msgNo)
			// TODO: need polymorphism on Req/Reply so they can be delivered
			if isService {
				Trace.Printf("session delivering request")
				sess.DeliverRequest()
			} else {
				Trace.Printf("session delivering reply")
				go sess.DeliverReply()
			}
		} else if pkt.packetType == TXERR {
			Trace.Printf("(incoming SESS %d) TXERR\n`%s`", pkt.msgNo, pkt.body)
			// TODO: need polymorphism on Req/Reply so they can be delivered
			if isService {
				sess.DeliverRequest()
			} else {
				go sess.DeliverReply()
			}
		} else {
			Trace.Printf("(incoming SESS %d) unknown packet type %d\n", pkt.packetType)
		}
	}

	return
}

func (conn *Connection) NewSession() (sess *Session, err error) {
	sess = new(Session)

	sess.conn = conn

	sess.msgNo = conn.msgCnt
	conn.msgCnt = conn.msgCnt + 1

	sess.replyChan = make(chan Reply, 1)

	conn.sessDemux[sess.msgNo] = sess

	return
}

func (conn *Connection) Send(req Request) (sess *Session, err error) {
	// The lock must be held until the first packet is sent.
	// With the current structure it will hold the lock until all
	// packets for req are sent
	conn.sessDemuxMutex.Lock()
	sess,err = conn.NewSession()
	if err != nil {
		return
	}

	err = sess.SendRequest(req)
	Trace.Printf("sending request (%d bytes)", len(req.Blob) )
	if err != nil {
		return
	}
	conn.sessDemuxMutex.Unlock()

	return
}

// Pulls full Requests out of master Request chan
// func (conn *Connection) Recv() Session {
// 	return <-conn.sessionChan
// }

func (conn *Connection) Close() {
	conn.conn.Close()
}

func (conn *Connection) Recv() (sess *Session) {
	sess = <-conn.newSessions
	return
}

func (conn *Connection) Free(sess *Session) {
	conn.sessDemuxMutex.Lock()
	msgNo := sess.packets[0].msgNo
	delete(conn.sessDemux, msgNo)
	conn.sessDemuxMutex.Unlock()
}
<|endoftext|>


<commit_before>package schedule

import (
	"math/rand"
	"strings"
	"time"
)

type Commit struct {
	DateTime time.Time
	Message  string
}

const (
	COMMIT_MESSAGE_BASE       = `Non eram nescius, Brute, cum, quae summis ingeniis exquisitaque doctrina philosophi Graeco sermone tractavissent, ea Latinis litteris mandaremus, fore ut hic noster labor in varias reprehensiones incurreret. nam quibusdam, et iis quidem non admodum indoctis, totum hoc displicet philosophari. quidam autem non tam id reprehendunt, si remissius agatur, sed tantum studium tamque multam operam ponendam in eo non arbitrantur. erunt etiam, et ii quidem eruditi Graecis litteris, contemnentes Latinas, qui se dicant in Graecis legendis operam malle consumere. postremo aliquos futuros suspicor, qui me ad alias litteras vocent, genus hoc scribendi, etsi sit elegans, personae tamen et dignitatis esse negent.`
	BASE_SEPARATOR            = " "
	MIN_COMMIT_MESSAGE_LENGTH = 1
	MAX_COMMIT_MESSAGE_LENGTH = 8
)

// GenerateRandomCommits returns a channel of random commits for a given day.
// These commits are a random selection of numCommits number of words from
// the given message base.
func GenerateRandomCommits(day time.Time, numCommits int, messageBase []string) <-chan Commit {
	commitChannel := make(chan Commit)
	go func() {
		for i := 0; i < numCommits; i++ {
			commitChannel <- GetRandomCommit(day, messageBase)
		}
		close(commitChannel)
	}()
	return commitChannel
}

// GetRandomCommit returns a commit with a randomly selected string from the
// given message base and a commit time, based on the given day.
func GetRandomCommit(day time.Time, messageBase []string) Commit {
	return Commit{
		DateTime: getRandomTime(day),
		Message:  getRandomCommitMessage(messageBase, MAX_COMMIT_MESSAGE_LENGTH),
	}
}

// GetRandomNumber returns a number in the range of min and max.
func GetRandomNumber(min, max int) int {
	if min == max {
		return min
	}
	return rand.Intn(max-min) + min
}

func GetCommitMessageBase() []string {
	return strings.Split(string(COMMIT_MESSAGE_BASE), BASE_SEPARATOR)
}

// getRandomTime sets a random time on the given date.
func getRandomTime(day time.Time) time.Time {
	hours := time.Duration(GetRandomNumber(0, 23)) * time.Hour
	minutes := time.Duration(GetRandomNumber(0, 59)) * time.Minute
	seconds := time.Duration(GetRandomNumber(0, 59)) * time.Second
	return day.Add(hours + minutes + seconds)
}

// getRandomCommitMessage returns a commit message, no longer than length.
func getRandomCommitMessage(messageBase []string, length int) string {
	commitMessageLength := GetRandomNumber(MIN_COMMIT_MESSAGE_LENGTH, length)
	return getRandomWords(messageBase, commitMessageLength)
}

// getRandomWords returns numWords random elements of the input.
func getRandomWords(inWords []string, numWords int) string {
	outWords := make([]string, numWords)
	for i := 0; i < numWords; i++ {
		randomIndex := GetRandomNumber(0, len(inWords)-1)
		outWords = append(outWords, inWords[randomIndex])
	}
	return strings.TrimSpace(strings.Join(outWords, " "))
}
<commit_msg>Use at least 2 words per commit message.<commit_after>package schedule

import (
	"math/rand"
	"strings"
	"time"
)

type Commit struct {
	DateTime time.Time
	Message  string
}

const (
	COMMIT_MESSAGE_BASE       = `Non eram nescius, Brute, cum, quae summis ingeniis exquisitaque doctrina philosophi Graeco sermone tractavissent, ea Latinis litteris mandaremus, fore ut hic noster labor in varias reprehensiones incurreret. nam quibusdam, et iis quidem non admodum indoctis, totum hoc displicet philosophari. quidam autem non tam id reprehendunt, si remissius agatur, sed tantum studium tamque multam operam ponendam in eo non arbitrantur. erunt etiam, et ii quidem eruditi Graecis litteris, contemnentes Latinas, qui se dicant in Graecis legendis operam malle consumere. postremo aliquos futuros suspicor, qui me ad alias litteras vocent, genus hoc scribendi, etsi sit elegans, personae tamen et dignitatis esse negent.`
	BASE_SEPARATOR            = " "
	MIN_COMMIT_MESSAGE_LENGTH = 2
	MAX_COMMIT_MESSAGE_LENGTH = 8
)

// GenerateRandomCommits returns a channel of random commits for a given day.
// These commits are a random selection of numCommits number of words from
// the given message base.
func GenerateRandomCommits(day time.Time, numCommits int, messageBase []string) <-chan Commit {
	commitChannel := make(chan Commit)
	go func() {
		for i := 0; i < numCommits; i++ {
			commitChannel <- GetRandomCommit(day, messageBase)
		}
		close(commitChannel)
	}()
	return commitChannel
}

// GetRandomCommit returns a commit with a randomly selected string from the
// given message base and a commit time, based on the given day.
func GetRandomCommit(day time.Time, messageBase []string) Commit {
	return Commit{
		DateTime: getRandomTime(day),
		Message:  getRandomCommitMessage(messageBase, MAX_COMMIT_MESSAGE_LENGTH),
	}
}

// GetRandomNumber returns a number in the range of min and max.
func GetRandomNumber(min, max int) int {
	if min == max {
		return min
	}
	return rand.Intn(max-min) + min
}

func GetCommitMessageBase() []string {
	return strings.Split(string(COMMIT_MESSAGE_BASE), BASE_SEPARATOR)
}

// getRandomTime sets a random time on the given date.
func getRandomTime(day time.Time) time.Time {
	hours := time.Duration(GetRandomNumber(0, 23)) * time.Hour
	minutes := time.Duration(GetRandomNumber(0, 59)) * time.Minute
	seconds := time.Duration(GetRandomNumber(0, 59)) * time.Second
	return day.Add(hours + minutes + seconds)
}

// getRandomCommitMessage returns a commit message, no longer than length.
func getRandomCommitMessage(messageBase []string, length int) string {
	commitMessageLength := GetRandomNumber(MIN_COMMIT_MESSAGE_LENGTH, length)
	return getRandomWords(messageBase, commitMessageLength)
}

// getRandomWords returns numWords random elements of the input.
func getRandomWords(inWords []string, numWords int) string {
	outWords := make([]string, numWords)
	for i := 0; i < numWords; i++ {
		randomIndex := GetRandomNumber(0, len(inWords)-1)
		outWords = append(outWords, inWords[randomIndex])
	}
	return strings.TrimSpace(strings.Join(outWords, " "))
}
<|endoftext|>


<commit_before>// +build go1.11

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

// Package main implements a client for Greeter service.
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"time"

	"google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"

	// TODO: change this to xds after the xds package is released.
	_ "google.golang.org/grpc/xds/experimental" // To install the xds resolvers and balancers.
)

const (
	defaultTarget = "localhost:50051"
	defaultName   = "world"
)

var help = flag.Bool("help", false, "Print usage information")

func init() {
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), `
Usage: client [name [target]]

  name
        The name you wish to be greeted by. Defaults to %q
  target
        The URI of the server, e.g. "xds:///helloworld-service". Defaults to %q
`, defaultName, defaultTarget)

		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if *help {
		flag.Usage()
		return
	}
	args := flag.Args()

	if len(args) > 2 {
		flag.Usage()
		return
	}

	name := defaultName
	if len(args) > 0 {
		name = args[0]
	}

	target := defaultTarget
	if len(args) > 1 {
		target = args[1]
	}

	// Set up a connection to the server.
	conn, err := grpc.Dial(target, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}
<commit_msg>examples: change xds example to import xds instead of experimental (#3745)<commit_after>// +build go1.11

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

// Package main implements a client for Greeter service.
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"time"

	"google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"

	_ "google.golang.org/grpc/xds" // To install the xds resolvers and balancers.
)

const (
	defaultTarget = "localhost:50051"
	defaultName   = "world"
)

var help = flag.Bool("help", false, "Print usage information")

func init() {
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), `
Usage: client [name [target]]

  name
        The name you wish to be greeted by. Defaults to %q
  target
        The URI of the server, e.g. "xds:///helloworld-service". Defaults to %q
`, defaultName, defaultTarget)

		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if *help {
		flag.Usage()
		return
	}
	args := flag.Args()

	if len(args) > 2 {
		flag.Usage()
		return
	}

	name := defaultName
	if len(args) > 0 {
		name = args[0]
	}

	target := defaultTarget
	if len(args) > 1 {
		target = args[1]
	}

	// Set up a connection to the server.
	conn, err := grpc.Dial(target, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}
<|endoftext|>


<commit_before>package protein

import (
	"reflect"
	"testing"
)

type codonCase struct {
	input         string
	expected      string
	errorExpected error
}

var codonTestCases = []codonCase{
	{
		"AUG",
		"Methionine",
		nil,
	},
	{
		"UUU",
		"Phenylalanine",
		nil,
	},
	{
		"UUC",
		"Phenylalanine",
		nil,
	},
	{
		"UUA",
		"Leucine",
		nil,
	},
	{
		"UUG",
		"Leucine",
		nil,
	},
	{
		"UCG",
		"Serine",
		nil,
	},
	{
		"UAU",
		"Tyrosine",
		nil,
	},
	{
		"UAC",
		"Tyrosine",
		nil,
	},
	{
		"UGU",
		"Cysteine",
		nil,
	},
	{
		"UGG",
		"Tryptophan",
		nil,
	},
	{
		"UAA",
		"",
		STOP,
	},
	{
		"UAG",
		"",
		STOP,
	},
	{
		"UGA",
		"",
		STOP,
	},
	{
		"ABC",
		"",
		ErrInvalidBase,
	},
}

func TestCodon(t *testing.T) {
	for _, test := range codonTestCases {
		actual, err := FromCodon(test.input)
		if test.errorExpected != nil {
			if test.errorExpected != err {
				t.Fatalf("FAIL: Protein translation test: %s\nExpected error: %q\nActual error: %q",
					test.input, test.errorExpected, err)
			}
		} else if err != nil {
			t.Fatalf("FAIL: Protein translation test: %s\nExpected: %s\nGot error: %q",
				test.input, test.expected, err)
		}
		if actual != test.expected {
			t.Fatalf("FAIL: Protein translation test: %s\nExpected: %s\nActual: %s",
				test.input, test.expected, actual)
		}
		t.Logf("PASS: Protein translation test: %s", test.input)
	}
}

type rnaCase struct {
	input         string
	expected      []string
	errorExpected error
}

var proteinTestCases = []rnaCase{
	{
		"AUGUUUUCUUAAAUG",
		[]string{"Methionine", "Phenylalanine", "Serine"},
		nil,
	},
	{
		"AUGUUUUGG",
		[]string{"Methionine", "Phenylalanine", "Tryptophan"},
		nil,
	},
	{
		"AUGUUUUAA",
		[]string{"Methionine", "Phenylalanine"},
		nil,
	},
	{
		"UGGUGUUAUUAAUGGUUU",
		[]string{"Tryptophan", "Cysteine", "Tyrosine"},
		nil,
	},
	{
		"UGGAGAAUUAAUGGUUU",
		[]string{"Tryptophan"},
		ErrInvalidBase,
	},
}

func TestProtein(t *testing.T) {
	for _, test := range proteinTestCases {
		actual, err := FromRNA(test.input)
		if test.errorExpected != nil {
			if test.errorExpected != err {
				t.Fatalf("FAIL: RNA translation test: %s\nExpected error: %q\nActual error: %q",
					test.input, test.errorExpected, err)
			}
		} else if err != nil {
			t.Fatalf("FAIL: RNA translation test: %s\nExpected: %s\nGot error: %q",
				test.input, test.expected, err)
		}
		if !reflect.DeepEqual(actual, test.expected) {
			t.Fatalf("FAIL: RNA Translation test: %s\nExpected: %q\nActual %q", test.input, test.expected, actual)
		}
		t.Logf("PASS: RNA translation test: %s", test.input)
	}
}
<commit_msg>adding in benchmark to test cases<commit_after>package protein

import (
	"reflect"
	"testing"
)

type codonCase struct {
	input         string
	expected      string
	errorExpected error
}

var codonTestCases = []codonCase{
	{
		"AUG",
		"Methionine",
		nil,
	},
	{
		"UUU",
		"Phenylalanine",
		nil,
	},
	{
		"UUC",
		"Phenylalanine",
		nil,
	},
	{
		"UUA",
		"Leucine",
		nil,
	},
	{
		"UUG",
		"Leucine",
		nil,
	},
	{
		"UCG",
		"Serine",
		nil,
	},
	{
		"UAU",
		"Tyrosine",
		nil,
	},
	{
		"UAC",
		"Tyrosine",
		nil,
	},
	{
		"UGU",
		"Cysteine",
		nil,
	},
	{
		"UGG",
		"Tryptophan",
		nil,
	},
	{
		"UAA",
		"",
		STOP,
	},
	{
		"UAG",
		"",
		STOP,
	},
	{
		"UGA",
		"",
		STOP,
	},
	{
		"ABC",
		"",
		ErrInvalidBase,
	},
}

func TestCodon(t *testing.T) {
	for _, test := range codonTestCases {
		actual, err := FromCodon(test.input)
		if test.errorExpected != nil {
			if test.errorExpected != err {
				t.Fatalf("FAIL: Protein translation test: %s\nExpected error: %q\nActual error: %q",
					test.input, test.errorExpected, err)
			}
		} else if err != nil {
			t.Fatalf("FAIL: Protein translation test: %s\nExpected: %s\nGot error: %q",
				test.input, test.expected, err)
		}
		if actual != test.expected {
			t.Fatalf("FAIL: Protein translation test: %s\nExpected: %s\nActual: %s",
				test.input, test.expected, actual)
		}
		t.Logf("PASS: Protein translation test: %s", test.input)
	}
}

type rnaCase struct {
	input         string
	expected      []string
	errorExpected error
}

var proteinTestCases = []rnaCase{
	{
		"AUGUUUUCUUAAAUG",
		[]string{"Methionine", "Phenylalanine", "Serine"},
		nil,
	},
	{
		"AUGUUUUGG",
		[]string{"Methionine", "Phenylalanine", "Tryptophan"},
		nil,
	},
	{
		"AUGUUUUAA",
		[]string{"Methionine", "Phenylalanine"},
		nil,
	},
	{
		"UGGUGUUAUUAAUGGUUU",
		[]string{"Tryptophan", "Cysteine", "Tyrosine"},
		nil,
	},
	{
		"UGGAGAAUUAAUGGUUU",
		[]string{"Tryptophan"},
		ErrInvalidBase,
	},
}

func TestProtein(t *testing.T) {
	for _, test := range proteinTestCases {
		actual, err := FromRNA(test.input)
		if test.errorExpected != nil {
			if test.errorExpected != err {
				t.Fatalf("FAIL: RNA translation test: %s\nExpected error: %q\nActual error: %q",
					test.input, test.errorExpected, err)
			}
		} else if err != nil {
			t.Fatalf("FAIL: RNA translation test: %s\nExpected: %s\nGot error: %q",
				test.input, test.expected, err)
		}
		if !reflect.DeepEqual(actual, test.expected) {
			t.Fatalf("FAIL: RNA Translation test: %s\nExpected: %q\nActual %q", test.input, test.expected, actual)
		}
		t.Logf("PASS: RNA translation test: %s", test.input)
	}
}

func BenchmarkCodon(b *testing.B) {
	for i := 0; i < b.N; i++ {
		FromCodon(codonTestCases[0].input)
	}
}

func BenchmarkProtein(b *testing.B) {
	for i := 0; i < b.N; i++ {
		FromRNA(proteinTestCases[0].input)
	}
}
<|endoftext|>


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

package asn1

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"reflect"
	"time"
)

// A forkableWriter is an in-memory buffer that can be
// 'forked' to create new forkableWriters that bracket the
// original.  After
//    pre, post := w.fork();
// the overall sequence of bytes represented is logically w+pre+post.
type forkableWriter struct {
	*bytes.Buffer
	pre, post *forkableWriter
}

func newForkableWriter() *forkableWriter {
	return &forkableWriter{bytes.NewBuffer(nil), nil, nil}
}

func (f *forkableWriter) fork() (pre, post *forkableWriter) {
	if f.pre != nil || f.post != nil {
		panic("have already forked")
	}
	f.pre = newForkableWriter()
	f.post = newForkableWriter()
	return f.pre, f.post
}

func (f *forkableWriter) Len() (l int) {
	l += f.Buffer.Len()
	if f.pre != nil {
		l += f.pre.Len()
	}
	if f.post != nil {
		l += f.post.Len()
	}
	return
}

func (f *forkableWriter) writeTo(out io.Writer) (n int, err os.Error) {
	n, err = out.Write(f.Bytes())
	if err != nil {
		return
	}

	var nn int

	if f.pre != nil {
		nn, err = f.pre.writeTo(out)
		n += nn
		if err != nil {
			return
		}
	}

	if f.post != nil {
		nn, err = f.post.writeTo(out)
		n += nn
	}
	return
}

func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
	if n == 0 {
		err = out.WriteByte(0)
		return
	}

	l := 0
	for i := n; i > 0; i >>= 7 {
		l++
	}

	for i := l - 1; i >= 0; i-- {
		o := byte(n >> uint(i*7))
		o &= 0x7f
		if i != 0 {
			o |= 0x80
		}
		err = out.WriteByte(o)
		if err != nil {
			return
		}
	}

	return nil
}

func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
	n := int64Length(i)

	for ; n > 0; n-- {
		err = out.WriteByte(byte(i >> uint((n-1)*8)))
		if err != nil {
			return
		}
	}

	return nil
}

func int64Length(i int64) (numBytes int) {
	numBytes = 1

	for i > 127 {
		numBytes++
		i >>= 8
	}

	for i < -128 {
		numBytes++
		i >>= 8
	}

	return
}

func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err os.Error) {
	b := uint8(t.class) << 6
	if t.isCompound {
		b |= 0x20
	}
	if t.tag >= 31 {
		b |= 0x1f
		err = out.WriteByte(b)
		if err != nil {
			return
		}
		err = marshalBase128Int(out, int64(t.tag))
		if err != nil {
			return
		}
	} else {
		b |= uint8(t.tag)
		err = out.WriteByte(b)
		if err != nil {
			return
		}
	}

	if t.length >= 128 {
		l := int64Length(int64(t.length))
		err = out.WriteByte(0x80 | byte(l))
		if err != nil {
			return
		}
		err = marshalInt64(out, int64(t.length))
		if err != nil {
			return
		}
	} else {
		err = out.WriteByte(byte(t.length))
		if err != nil {
			return
		}
	}

	return nil
}

func marshalBitString(out *forkableWriter, b BitString) (err os.Error) {
	paddingBits := byte((8 - b.BitLength%8) % 8)
	err = out.WriteByte(paddingBits)
	if err != nil {
		return
	}
	_, err = out.Write(b.Bytes)
	return
}

func marshalObjectIdentifier(out *forkableWriter, oid []int) (err os.Error) {
	if len(oid) < 2 || oid[0] > 6 || oid[1] >= 40 {
		return StructuralError{"invalid object identifier"}
	}

	err = out.WriteByte(byte(oid[0]*40 + oid[1]))
	if err != nil {
		return
	}
	for i := 2; i < len(oid); i++ {
		err = marshalBase128Int(out, int64(oid[i]))
		if err != nil {
			return
		}
	}

	return
}

func marshalPrintableString(out *forkableWriter, s string) (err os.Error) {
	b := []byte(s)
	for _, c := range b {
		if !isPrintable(c) {
			return StructuralError{"PrintableString contains invalid character"}
		}
	}

	_, err = out.Write(b)
	return
}

func marshalIA5String(out *forkableWriter, s string) (err os.Error) {
	b := []byte(s)
	for _, c := range b {
		if c > 127 {
			return StructuralError{"IA5String contains invalid character"}
		}
	}

	_, err = out.Write(b)
	return
}

func marshalTwoDigits(out *forkableWriter, v int) (err os.Error) {
	err = out.WriteByte(byte('0' + (v/10)%10))
	if err != nil {
		return
	}
	return out.WriteByte(byte('0' + v%10))
}

func marshalUTCTime(out *forkableWriter, t *time.Time) (err os.Error) {
	switch {
	case 1950 <= t.Year && t.Year < 2000:
		err = marshalTwoDigits(out, int(t.Year-1900))
	case 2000 <= t.Year && t.Year < 2050:
		err = marshalTwoDigits(out, int(t.Year-2000))
	default:
		return StructuralError{"Cannot represent time as UTCTime"}
	}

	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Month)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Day)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Hour)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Minute)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Second)
	if err != nil {
		return
	}

	switch {
	case t.ZoneOffset/60 == 0:
		err = out.WriteByte('Z')
		return
	case t.ZoneOffset > 0:
		err = out.WriteByte('+')
	case t.ZoneOffset < 0:
		err = out.WriteByte('-')
	}

	if err != nil {
		return
	}

	offsetMinutes := t.ZoneOffset / 60
	if offsetMinutes < 0 {
		offsetMinutes = -offsetMinutes
	}

	err = marshalTwoDigits(out, offsetMinutes/60)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, offsetMinutes%60)
	return
}

func stripTagAndLength(in []byte) []byte {
	_, offset, err := parseTagAndLength(in, 0)
	if err != nil {
		return in
	}
	return in[offset:]
}

func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err os.Error) {
	switch value.Type() {
	case timeType:
		return marshalUTCTime(out, value.Interface().(*time.Time))
	case bitStringType:
		return marshalBitString(out, value.Interface().(BitString))
	case objectIdentifierType:
		return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
	}

	switch v := value.(type) {
	case *reflect.BoolValue:
		if v.Get() {
			return out.WriteByte(1)
		} else {
			return out.WriteByte(0)
		}
	case *reflect.IntValue:
		return marshalInt64(out, int64(v.Get()))
	case *reflect.StructValue:
		t := v.Type().(*reflect.StructType)

		startingField := 0

		// If the first element of the structure is a non-empty
		// RawContents, then we don't bother serialising the rest.
		if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
			s := v.Field(0).(*reflect.SliceValue)
			if s.Len() > 0 {
				bytes := make([]byte, s.Len())
				for i := 0; i < s.Len(); i++ {
					bytes[i] = uint8(s.Elem(i).(*reflect.UintValue).Get())
				}
				/* The RawContents will contain the tag and
				 * length fields but we'll also be writing
				 * those outselves, so we strip them out of
				 * bytes */
				_, err = out.Write(stripTagAndLength(bytes))
				return
			} else {
				startingField = 1
			}
		}

		for i := startingField; i < t.NumField(); i++ {
			var pre *forkableWriter
			pre, out = out.fork()
			err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag))
			if err != nil {
				return
			}
		}
		return
	case *reflect.SliceValue:
		sliceType := v.Type().(*reflect.SliceType)
		if sliceType.Elem().Kind() == reflect.Uint8 {
			bytes := make([]byte, v.Len())
			for i := 0; i < v.Len(); i++ {
				bytes[i] = uint8(v.Elem(i).(*reflect.UintValue).Get())
			}
			_, err = out.Write(bytes)
			return
		}

		var params fieldParameters
		for i := 0; i < v.Len(); i++ {
			var pre *forkableWriter
			pre, out = out.fork()
			err = marshalField(pre, v.Elem(i), params)
			if err != nil {
				return
			}
		}
		return
	case *reflect.StringValue:
		if params.stringType == tagIA5String {
			return marshalIA5String(out, v.Get())
		} else {
			return marshalPrintableString(out, v.Get())
		}
		return
	}

	return StructuralError{"unknown Go type"}
}

func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err os.Error) {
	// If the field is an interface{} then recurse into it.
	if v, ok := v.(*reflect.InterfaceValue); ok && v.Type().(*reflect.InterfaceType).NumMethod() == 0 {
		return marshalField(out, v.Elem(), params)
	}

	if v.Type() == rawValueType {
		rv := v.Interface().(RawValue)
		err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
		if err != nil {
			return
		}
		_, err = out.Write(rv.Bytes)
		return
	}

	if params.optional && reflect.DeepEqual(v.Interface(), reflect.MakeZero(v.Type()).Interface()) {
		return
	}

	tag, isCompound, ok := getUniversalType(v.Type())
	if !ok {
		err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
		return
	}
	class := classUniversal

	if params.stringType != 0 {
		if tag != tagPrintableString {
			return StructuralError{"Explicit string type given to non-string member"}
		}
		tag = params.stringType
	}

	if params.set {
		if tag != tagSequence {
			return StructuralError{"Non sequence tagged as set"}
		}
		tag = tagSet
	}

	tags, body := out.fork()

	err = marshalBody(body, v, params)
	if err != nil {
		return
	}

	bodyLen := body.Len()

	var explicitTag *forkableWriter
	if params.explicit {
		explicitTag, tags = tags.fork()
	}

	if !params.explicit && params.tag != nil {
		// implicit tag.
		tag = *params.tag
		class = classContextSpecific
	}

	err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
	if err != nil {
		return
	}

	if params.explicit {
		err = marshalTagAndLength(explicitTag, tagAndLength{
			class:      classContextSpecific,
			tag:        *params.tag,
			length:     bodyLen + tags.Len(),
			isCompound: true,
		})
	}

	return nil
}

// Marshal returns the ASN.1 encoding of val.
func Marshal(val interface{}) ([]byte, os.Error) {
	var out bytes.Buffer
	v := reflect.NewValue(val)
	f := newForkableWriter()
	err := marshalField(f, v, fieldParameters{})
	if err != nil {
		return nil, err
	}
	_, err = f.writeTo(&out)
	return out.Bytes(), nil
}
<commit_msg>asn1: marshal true as 255, not 1.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package asn1

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"reflect"
	"time"
)

// A forkableWriter is an in-memory buffer that can be
// 'forked' to create new forkableWriters that bracket the
// original.  After
//    pre, post := w.fork();
// the overall sequence of bytes represented is logically w+pre+post.
type forkableWriter struct {
	*bytes.Buffer
	pre, post *forkableWriter
}

func newForkableWriter() *forkableWriter {
	return &forkableWriter{bytes.NewBuffer(nil), nil, nil}
}

func (f *forkableWriter) fork() (pre, post *forkableWriter) {
	if f.pre != nil || f.post != nil {
		panic("have already forked")
	}
	f.pre = newForkableWriter()
	f.post = newForkableWriter()
	return f.pre, f.post
}

func (f *forkableWriter) Len() (l int) {
	l += f.Buffer.Len()
	if f.pre != nil {
		l += f.pre.Len()
	}
	if f.post != nil {
		l += f.post.Len()
	}
	return
}

func (f *forkableWriter) writeTo(out io.Writer) (n int, err os.Error) {
	n, err = out.Write(f.Bytes())
	if err != nil {
		return
	}

	var nn int

	if f.pre != nil {
		nn, err = f.pre.writeTo(out)
		n += nn
		if err != nil {
			return
		}
	}

	if f.post != nil {
		nn, err = f.post.writeTo(out)
		n += nn
	}
	return
}

func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
	if n == 0 {
		err = out.WriteByte(0)
		return
	}

	l := 0
	for i := n; i > 0; i >>= 7 {
		l++
	}

	for i := l - 1; i >= 0; i-- {
		o := byte(n >> uint(i*7))
		o &= 0x7f
		if i != 0 {
			o |= 0x80
		}
		err = out.WriteByte(o)
		if err != nil {
			return
		}
	}

	return nil
}

func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
	n := int64Length(i)

	for ; n > 0; n-- {
		err = out.WriteByte(byte(i >> uint((n-1)*8)))
		if err != nil {
			return
		}
	}

	return nil
}

func int64Length(i int64) (numBytes int) {
	numBytes = 1

	for i > 127 {
		numBytes++
		i >>= 8
	}

	for i < -128 {
		numBytes++
		i >>= 8
	}

	return
}

func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err os.Error) {
	b := uint8(t.class) << 6
	if t.isCompound {
		b |= 0x20
	}
	if t.tag >= 31 {
		b |= 0x1f
		err = out.WriteByte(b)
		if err != nil {
			return
		}
		err = marshalBase128Int(out, int64(t.tag))
		if err != nil {
			return
		}
	} else {
		b |= uint8(t.tag)
		err = out.WriteByte(b)
		if err != nil {
			return
		}
	}

	if t.length >= 128 {
		l := int64Length(int64(t.length))
		err = out.WriteByte(0x80 | byte(l))
		if err != nil {
			return
		}
		err = marshalInt64(out, int64(t.length))
		if err != nil {
			return
		}
	} else {
		err = out.WriteByte(byte(t.length))
		if err != nil {
			return
		}
	}

	return nil
}

func marshalBitString(out *forkableWriter, b BitString) (err os.Error) {
	paddingBits := byte((8 - b.BitLength%8) % 8)
	err = out.WriteByte(paddingBits)
	if err != nil {
		return
	}
	_, err = out.Write(b.Bytes)
	return
}

func marshalObjectIdentifier(out *forkableWriter, oid []int) (err os.Error) {
	if len(oid) < 2 || oid[0] > 6 || oid[1] >= 40 {
		return StructuralError{"invalid object identifier"}
	}

	err = out.WriteByte(byte(oid[0]*40 + oid[1]))
	if err != nil {
		return
	}
	for i := 2; i < len(oid); i++ {
		err = marshalBase128Int(out, int64(oid[i]))
		if err != nil {
			return
		}
	}

	return
}

func marshalPrintableString(out *forkableWriter, s string) (err os.Error) {
	b := []byte(s)
	for _, c := range b {
		if !isPrintable(c) {
			return StructuralError{"PrintableString contains invalid character"}
		}
	}

	_, err = out.Write(b)
	return
}

func marshalIA5String(out *forkableWriter, s string) (err os.Error) {
	b := []byte(s)
	for _, c := range b {
		if c > 127 {
			return StructuralError{"IA5String contains invalid character"}
		}
	}

	_, err = out.Write(b)
	return
}

func marshalTwoDigits(out *forkableWriter, v int) (err os.Error) {
	err = out.WriteByte(byte('0' + (v/10)%10))
	if err != nil {
		return
	}
	return out.WriteByte(byte('0' + v%10))
}

func marshalUTCTime(out *forkableWriter, t *time.Time) (err os.Error) {
	switch {
	case 1950 <= t.Year && t.Year < 2000:
		err = marshalTwoDigits(out, int(t.Year-1900))
	case 2000 <= t.Year && t.Year < 2050:
		err = marshalTwoDigits(out, int(t.Year-2000))
	default:
		return StructuralError{"Cannot represent time as UTCTime"}
	}

	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Month)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Day)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Hour)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Minute)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, t.Second)
	if err != nil {
		return
	}

	switch {
	case t.ZoneOffset/60 == 0:
		err = out.WriteByte('Z')
		return
	case t.ZoneOffset > 0:
		err = out.WriteByte('+')
	case t.ZoneOffset < 0:
		err = out.WriteByte('-')
	}

	if err != nil {
		return
	}

	offsetMinutes := t.ZoneOffset / 60
	if offsetMinutes < 0 {
		offsetMinutes = -offsetMinutes
	}

	err = marshalTwoDigits(out, offsetMinutes/60)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, offsetMinutes%60)
	return
}

func stripTagAndLength(in []byte) []byte {
	_, offset, err := parseTagAndLength(in, 0)
	if err != nil {
		return in
	}
	return in[offset:]
}

func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err os.Error) {
	switch value.Type() {
	case timeType:
		return marshalUTCTime(out, value.Interface().(*time.Time))
	case bitStringType:
		return marshalBitString(out, value.Interface().(BitString))
	case objectIdentifierType:
		return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
	}

	switch v := value.(type) {
	case *reflect.BoolValue:
		if v.Get() {
			return out.WriteByte(255)
		} else {
			return out.WriteByte(0)
		}
	case *reflect.IntValue:
		return marshalInt64(out, int64(v.Get()))
	case *reflect.StructValue:
		t := v.Type().(*reflect.StructType)

		startingField := 0

		// If the first element of the structure is a non-empty
		// RawContents, then we don't bother serialising the rest.
		if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
			s := v.Field(0).(*reflect.SliceValue)
			if s.Len() > 0 {
				bytes := make([]byte, s.Len())
				for i := 0; i < s.Len(); i++ {
					bytes[i] = uint8(s.Elem(i).(*reflect.UintValue).Get())
				}
				/* The RawContents will contain the tag and
				 * length fields but we'll also be writing
				 * those outselves, so we strip them out of
				 * bytes */
				_, err = out.Write(stripTagAndLength(bytes))
				return
			} else {
				startingField = 1
			}
		}

		for i := startingField; i < t.NumField(); i++ {
			var pre *forkableWriter
			pre, out = out.fork()
			err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag))
			if err != nil {
				return
			}
		}
		return
	case *reflect.SliceValue:
		sliceType := v.Type().(*reflect.SliceType)
		if sliceType.Elem().Kind() == reflect.Uint8 {
			bytes := make([]byte, v.Len())
			for i := 0; i < v.Len(); i++ {
				bytes[i] = uint8(v.Elem(i).(*reflect.UintValue).Get())
			}
			_, err = out.Write(bytes)
			return
		}

		var params fieldParameters
		for i := 0; i < v.Len(); i++ {
			var pre *forkableWriter
			pre, out = out.fork()
			err = marshalField(pre, v.Elem(i), params)
			if err != nil {
				return
			}
		}
		return
	case *reflect.StringValue:
		if params.stringType == tagIA5String {
			return marshalIA5String(out, v.Get())
		} else {
			return marshalPrintableString(out, v.Get())
		}
		return
	}

	return StructuralError{"unknown Go type"}
}

func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err os.Error) {
	// If the field is an interface{} then recurse into it.
	if v, ok := v.(*reflect.InterfaceValue); ok && v.Type().(*reflect.InterfaceType).NumMethod() == 0 {
		return marshalField(out, v.Elem(), params)
	}

	if v.Type() == rawValueType {
		rv := v.Interface().(RawValue)
		err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
		if err != nil {
			return
		}
		_, err = out.Write(rv.Bytes)
		return
	}

	if params.optional && reflect.DeepEqual(v.Interface(), reflect.MakeZero(v.Type()).Interface()) {
		return
	}

	tag, isCompound, ok := getUniversalType(v.Type())
	if !ok {
		err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
		return
	}
	class := classUniversal

	if params.stringType != 0 {
		if tag != tagPrintableString {
			return StructuralError{"Explicit string type given to non-string member"}
		}
		tag = params.stringType
	}

	if params.set {
		if tag != tagSequence {
			return StructuralError{"Non sequence tagged as set"}
		}
		tag = tagSet
	}

	tags, body := out.fork()

	err = marshalBody(body, v, params)
	if err != nil {
		return
	}

	bodyLen := body.Len()

	var explicitTag *forkableWriter
	if params.explicit {
		explicitTag, tags = tags.fork()
	}

	if !params.explicit && params.tag != nil {
		// implicit tag.
		tag = *params.tag
		class = classContextSpecific
	}

	err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
	if err != nil {
		return
	}

	if params.explicit {
		err = marshalTagAndLength(explicitTag, tagAndLength{
			class:      classContextSpecific,
			tag:        *params.tag,
			length:     bodyLen + tags.Len(),
			isCompound: true,
		})
	}

	return nil
}

// Marshal returns the ASN.1 encoding of val.
func Marshal(val interface{}) ([]byte, os.Error) {
	var out bytes.Buffer
	v := reflect.NewValue(val)
	f := newForkableWriter()
	err := marshalField(f, v, fieldParameters{})
	if err != nil {
		return nil, err
	}
	_, err = f.writeTo(&out)
	return out.Bytes(), nil
}
<|endoftext|>


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

package http

import (
	"bufio"
	"io"
	"net"
	"net/textproto"
	"os"
	"sync"
)

var (
	ErrPersistEOF = &ProtocolError{"persistent connection closed"}
	ErrPipeline   = &ProtocolError{"pipeline error"}
)

// A ServerConn reads requests and sends responses over an underlying
// connection, until the HTTP keepalive logic commands an end. ServerConn
// does not close the underlying connection. Instead, the user calls Close
// and regains control over the connection. ServerConn supports pipe-lining,
// i.e. requests can be read out of sync (but in the same order) while the
// respective responses are sent.
type ServerConn struct {
	c               net.Conn
	r               *bufio.Reader
	clsd            bool     // indicates a graceful close
	re, we          os.Error // read/write errors
	lastbody        io.ReadCloser
	nread, nwritten int
	pipe            textproto.Pipeline
	pipereq         map[*Request]uint
	lk              sync.Mutex // protected read/write to re,we
}

// NewServerConn returns a new ServerConn reading and writing c.  If r is not
// nil, it is the buffer to use when reading c.
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ServerConn{c: c, r: r, pipereq: make(map[*Request]uint)}
}

// Close detaches the ServerConn and returns the underlying connection as well
// as the read-side bufio which may have some left over data. Close may be
// called before Read has signaled the end of the keep-alive logic. The user
// should not call Close while Read or Write is in progress.
func (sc *ServerConn) Close() (c net.Conn, r *bufio.Reader) {
	sc.lk.Lock()
	defer sc.lk.Unlock()
	c = sc.c
	r = sc.r
	sc.c = nil
	sc.r = nil
	return
}

// Read returns the next request on the wire. An ErrPersistEOF is returned if
// it is gracefully determined that there are no more requests (e.g. after the
// first request on an HTTP/1.0 connection, or after a Connection:close on a
// HTTP/1.1 connection).
func (sc *ServerConn) Read() (req *Request, err os.Error) {

	// Ensure ordered execution of Reads and Writes
	id := sc.pipe.Next()
	sc.pipe.StartRequest(id)
	defer func() {
		sc.pipe.EndRequest(id)
		if req == nil {
			sc.pipe.StartResponse(id)
			sc.pipe.EndResponse(id)
		} else {
			// Remember the pipeline id of this request
			sc.lk.Lock()
			sc.pipereq[req] = id
			sc.lk.Unlock()
		}
	}()

	sc.lk.Lock()
	if sc.we != nil { // no point receiving if write-side broken or closed
		defer sc.lk.Unlock()
		return nil, sc.we
	}
	if sc.re != nil {
		defer sc.lk.Unlock()
		return nil, sc.re
	}
	sc.lk.Unlock()

	// Make sure body is fully consumed, even if user does not call body.Close
	if sc.lastbody != nil {
		// body.Close is assumed to be idempotent and multiple calls to
		// it should return the error that its first invokation
		// returned.
		err = sc.lastbody.Close()
		sc.lastbody = nil
		if err != nil {
			sc.lk.Lock()
			defer sc.lk.Unlock()
			sc.re = err
			return nil, err
		}
	}

	req, err = ReadRequest(sc.r)
	if err != nil {
		sc.lk.Lock()
		defer sc.lk.Unlock()
		if err == io.ErrUnexpectedEOF {
			// A close from the opposing client is treated as a
			// graceful close, even if there was some unparse-able
			// data before the close.
			sc.re = ErrPersistEOF
			return nil, sc.re
		} else {
			sc.re = err
			return
		}
	}
	sc.lastbody = req.Body
	sc.nread++
	if req.Close {
		sc.lk.Lock()
		defer sc.lk.Unlock()
		sc.re = ErrPersistEOF
		return req, sc.re
	}
	return
}

// Pending returns the number of unanswered requests
// that have been received on the connection.
func (sc *ServerConn) Pending() int {
	sc.lk.Lock()
	defer sc.lk.Unlock()
	return sc.nread - sc.nwritten
}

// Write writes resp in response to req. To close the connection gracefully, set the
// Response.Close field to true. Write should be considered operational until
// it returns an error, regardless of any errors returned on the Read side.
func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {

	// Retrieve the pipeline ID of this request/response pair
	sc.lk.Lock()
	id, ok := sc.pipereq[req]
	sc.pipereq[req] = 0, false
	if !ok {
		sc.lk.Unlock()
		return ErrPipeline
	}
	sc.lk.Unlock()

	// Ensure pipeline order
	sc.pipe.StartResponse(id)
	defer sc.pipe.EndResponse(id)

	sc.lk.Lock()
	if sc.we != nil {
		defer sc.lk.Unlock()
		return sc.we
	}
	sc.lk.Unlock()
	if sc.nread <= sc.nwritten {
		return os.NewError("persist server pipe count")
	}

	if resp.Close {
		// After signaling a keep-alive close, any pipelined unread
		// requests will be lost. It is up to the user to drain them
		// before signaling.
		sc.lk.Lock()
		sc.re = ErrPersistEOF
		sc.lk.Unlock()
	}

	err := resp.Write(sc.c)
	if err != nil {
		sc.lk.Lock()
		defer sc.lk.Unlock()
		sc.we = err
		return err
	}
	sc.nwritten++

	return nil
}

// A ClientConn sends request and receives headers over an underlying
// connection, while respecting the HTTP keepalive logic. ClientConn is not
// responsible for closing the underlying connection. One must call Close to
// regain control of that connection and deal with it as desired.
type ClientConn struct {
	c               net.Conn
	r               *bufio.Reader
	re, we          os.Error // read/write errors
	lastbody        io.ReadCloser
	nread, nwritten int
	pipe            textproto.Pipeline
	pipereq         map[*Request]uint
	lk              sync.Mutex // protects read/write to re,we,pipereq,etc.
}

// NewClientConn returns a new ClientConn reading and writing c.  If r is not
// nil, it is the buffer to use when reading c.
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ClientConn{c: c, r: r, pipereq: make(map[*Request]uint)}
}

// Close detaches the ClientConn and returns the underlying connection as well
// as the read-side bufio which may have some left over data. Close may be
// called before the user or Read have signaled the end of the keep-alive
// logic. The user should not call Close while Read or Write is in progress.
func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) {
	cc.lk.Lock()
	c = cc.c
	r = cc.r
	cc.c = nil
	cc.r = nil
	cc.lk.Unlock()
	return
}

// Write writes a request. An ErrPersistEOF error is returned if the connection
// has been closed in an HTTP keepalive sense. If req.Close equals true, the
// keepalive connection is logically closed after this request and the opposing
// server is informed. An ErrUnexpectedEOF indicates the remote closed the
// underlying TCP connection, which is usually considered as graceful close.
func (cc *ClientConn) Write(req *Request) (err os.Error) {

	// Ensure ordered execution of Writes
	id := cc.pipe.Next()
	cc.pipe.StartRequest(id)
	defer func() {
		cc.pipe.EndRequest(id)
		if err != nil {
			cc.pipe.StartResponse(id)
			cc.pipe.EndResponse(id)
		} else {
			// Remember the pipeline id of this request
			cc.lk.Lock()
			cc.pipereq[req] = id
			cc.lk.Unlock()
		}
	}()

	cc.lk.Lock()
	if cc.re != nil { // no point sending if read-side closed or broken
		defer cc.lk.Unlock()
		return cc.re
	}
	if cc.we != nil {
		defer cc.lk.Unlock()
		return cc.we
	}
	cc.lk.Unlock()

	if req.Close {
		// We write the EOF to the write-side error, because there
		// still might be some pipelined reads
		cc.lk.Lock()
		cc.we = ErrPersistEOF
		cc.lk.Unlock()
	}

	err = req.Write(cc.c)
	if err != nil {
		cc.lk.Lock()
		defer cc.lk.Unlock()
		cc.we = err
		return err
	}
	cc.nwritten++

	return nil
}

// Pending returns the number of unanswered requests
// that have been sent on the connection.
func (cc *ClientConn) Pending() int {
	cc.lk.Lock()
	defer cc.lk.Unlock()
	return cc.nwritten - cc.nread
}

// Read reads the next response from the wire. A valid response might be
// returned together with an ErrPersistEOF, which means that the remote
// requested that this be the last request serviced. Read can be called
// concurrently with Write, but not with another Read.
func (cc *ClientConn) Read(req *Request) (resp *Response, err os.Error) {

	// Retrieve the pipeline ID of this request/response pair
	cc.lk.Lock()
	id, ok := cc.pipereq[req]
	cc.pipereq[req] = 0, false
	if !ok {
		cc.lk.Unlock()
		return nil, ErrPipeline
	}
	cc.lk.Unlock()

	// Ensure pipeline order
	cc.pipe.StartResponse(id)
	defer cc.pipe.EndResponse(id)

	cc.lk.Lock()
	if cc.re != nil {
		defer cc.lk.Unlock()
		return nil, cc.re
	}
	cc.lk.Unlock()

	// Make sure body is fully consumed, even if user does not call body.Close
	if cc.lastbody != nil {
		// body.Close is assumed to be idempotent and multiple calls to
		// it should return the error that its first invokation
		// returned.
		err = cc.lastbody.Close()
		cc.lastbody = nil
		if err != nil {
			cc.lk.Lock()
			defer cc.lk.Unlock()
			cc.re = err
			return nil, err
		}
	}

	resp, err = ReadResponse(cc.r, req.Method)
	if err != nil {
		cc.lk.Lock()
		defer cc.lk.Unlock()
		cc.re = err
		return
	}
	cc.lastbody = resp.Body

	cc.nread++

	if resp.Close {
		cc.lk.Lock()
		defer cc.lk.Unlock()
		cc.re = ErrPersistEOF // don't send any more requests
		return resp, cc.re
	}
	return
}

// Do is convenience method that writes a request and reads a response.
func (cc *ClientConn) Do(req *Request) (resp *Response, err os.Error) {
	err = cc.Write(req)
	if err != nil {
		return
	}
	return cc.Read(req)
}
<commit_msg>http: fixed race condition in persist.go<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package http

import (
	"bufio"
	"io"
	"net"
	"net/textproto"
	"os"
	"sync"
)

var (
	ErrPersistEOF = &ProtocolError{"persistent connection closed"}
	ErrPipeline   = &ProtocolError{"pipeline error"}
)

// A ServerConn reads requests and sends responses over an underlying
// connection, until the HTTP keepalive logic commands an end. ServerConn
// does not close the underlying connection. Instead, the user calls Close
// and regains control over the connection. ServerConn supports pipe-lining,
// i.e. requests can be read out of sync (but in the same order) while the
// respective responses are sent.
type ServerConn struct {
	lk              sync.Mutex // read-write protects the following fields
	c               net.Conn
	r               *bufio.Reader
	re, we          os.Error // read/write errors
	lastbody        io.ReadCloser
	nread, nwritten int
	pipereq         map[*Request]uint

	pipe textproto.Pipeline
}

// NewServerConn returns a new ServerConn reading and writing c.  If r is not
// nil, it is the buffer to use when reading c.
func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ServerConn{c: c, r: r, pipereq: make(map[*Request]uint)}
}

// Close detaches the ServerConn and returns the underlying connection as well
// as the read-side bufio which may have some left over data. Close may be
// called before Read has signaled the end of the keep-alive logic. The user
// should not call Close while Read or Write is in progress.
func (sc *ServerConn) Close() (c net.Conn, r *bufio.Reader) {
	sc.lk.Lock()
	defer sc.lk.Unlock()
	c = sc.c
	r = sc.r
	sc.c = nil
	sc.r = nil
	return
}

// Read returns the next request on the wire. An ErrPersistEOF is returned if
// it is gracefully determined that there are no more requests (e.g. after the
// first request on an HTTP/1.0 connection, or after a Connection:close on a
// HTTP/1.1 connection).
func (sc *ServerConn) Read() (req *Request, err os.Error) {

	// Ensure ordered execution of Reads and Writes
	id := sc.pipe.Next()
	sc.pipe.StartRequest(id)
	defer func() {
		sc.pipe.EndRequest(id)
		if req == nil {
			sc.pipe.StartResponse(id)
			sc.pipe.EndResponse(id)
		} else {
			// Remember the pipeline id of this request
			sc.lk.Lock()
			sc.pipereq[req] = id
			sc.lk.Unlock()
		}
	}()

	sc.lk.Lock()
	if sc.we != nil { // no point receiving if write-side broken or closed
		defer sc.lk.Unlock()
		return nil, sc.we
	}
	if sc.re != nil {
		defer sc.lk.Unlock()
		return nil, sc.re
	}
	if sc.r == nil { // connection closed by user in the meantime
		defer sc.lk.Unlock()
		return nil, os.EBADF
	}
	r := sc.r
	lastbody := sc.lastbody
	sc.lastbody = nil
	sc.lk.Unlock()

	// Make sure body is fully consumed, even if user does not call body.Close
	if lastbody != nil {
		// body.Close is assumed to be idempotent and multiple calls to
		// it should return the error that its first invokation
		// returned.
		err = lastbody.Close()
		if err != nil {
			sc.lk.Lock()
			defer sc.lk.Unlock()
			sc.re = err
			return nil, err
		}
	}

	req, err = ReadRequest(r)
	sc.lk.Lock()
	defer sc.lk.Unlock()
	if err != nil {
		if err == io.ErrUnexpectedEOF {
			// A close from the opposing client is treated as a
			// graceful close, even if there was some unparse-able
			// data before the close.
			sc.re = ErrPersistEOF
			return nil, sc.re
		} else {
			sc.re = err
			return req, err
		}
	}
	sc.lastbody = req.Body
	sc.nread++
	if req.Close {
		sc.re = ErrPersistEOF
		return req, sc.re
	}
	return req, err
}

// Pending returns the number of unanswered requests
// that have been received on the connection.
func (sc *ServerConn) Pending() int {
	sc.lk.Lock()
	defer sc.lk.Unlock()
	return sc.nread - sc.nwritten
}

// Write writes resp in response to req. To close the connection gracefully, set the
// Response.Close field to true. Write should be considered operational until
// it returns an error, regardless of any errors returned on the Read side.
func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {

	// Retrieve the pipeline ID of this request/response pair
	sc.lk.Lock()
	id, ok := sc.pipereq[req]
	sc.pipereq[req] = 0, false
	if !ok {
		sc.lk.Unlock()
		return ErrPipeline
	}
	sc.lk.Unlock()

	// Ensure pipeline order
	sc.pipe.StartResponse(id)
	defer sc.pipe.EndResponse(id)

	sc.lk.Lock()
	if sc.we != nil {
		defer sc.lk.Unlock()
		return sc.we
	}
	if sc.c == nil { // connection closed by user in the meantime
		defer sc.lk.Unlock()
		return os.EBADF
	}
	c := sc.c
	if sc.nread <= sc.nwritten {
		defer sc.lk.Unlock()
		return os.NewError("persist server pipe count")
	}
	if resp.Close {
		// After signaling a keep-alive close, any pipelined unread
		// requests will be lost. It is up to the user to drain them
		// before signaling.
		sc.re = ErrPersistEOF
	}
	sc.lk.Unlock()

	err := resp.Write(c)
	sc.lk.Lock()
	defer sc.lk.Unlock()
	if err != nil {
		sc.we = err
		return err
	}
	sc.nwritten++

	return nil
}

// A ClientConn sends request and receives headers over an underlying
// connection, while respecting the HTTP keepalive logic. ClientConn is not
// responsible for closing the underlying connection. One must call Close to
// regain control of that connection and deal with it as desired.
type ClientConn struct {
	lk              sync.Mutex // read-write protects the following fields
	c               net.Conn
	r               *bufio.Reader
	re, we          os.Error // read/write errors
	lastbody        io.ReadCloser
	nread, nwritten int
	pipereq         map[*Request]uint

	pipe textproto.Pipeline
}

// NewClientConn returns a new ClientConn reading and writing c.  If r is not
// nil, it is the buffer to use when reading c.
func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
	if r == nil {
		r = bufio.NewReader(c)
	}
	return &ClientConn{c: c, r: r, pipereq: make(map[*Request]uint)}
}

// Close detaches the ClientConn and returns the underlying connection as well
// as the read-side bufio which may have some left over data. Close may be
// called before the user or Read have signaled the end of the keep-alive
// logic. The user should not call Close while Read or Write is in progress.
func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) {
	cc.lk.Lock()
	defer cc.lk.Unlock()
	c = cc.c
	r = cc.r
	cc.c = nil
	cc.r = nil
	return
}

// Write writes a request. An ErrPersistEOF error is returned if the connection
// has been closed in an HTTP keepalive sense. If req.Close equals true, the
// keepalive connection is logically closed after this request and the opposing
// server is informed. An ErrUnexpectedEOF indicates the remote closed the
// underlying TCP connection, which is usually considered as graceful close.
func (cc *ClientConn) Write(req *Request) (err os.Error) {

	// Ensure ordered execution of Writes
	id := cc.pipe.Next()
	cc.pipe.StartRequest(id)
	defer func() {
		cc.pipe.EndRequest(id)
		if err != nil {
			cc.pipe.StartResponse(id)
			cc.pipe.EndResponse(id)
		} else {
			// Remember the pipeline id of this request
			cc.lk.Lock()
			cc.pipereq[req] = id
			cc.lk.Unlock()
		}
	}()

	cc.lk.Lock()
	if cc.re != nil { // no point sending if read-side closed or broken
		defer cc.lk.Unlock()
		return cc.re
	}
	if cc.we != nil {
		defer cc.lk.Unlock()
		return cc.we
	}
	if cc.c == nil { // connection closed by user in the meantime
		defer cc.lk.Unlock()
		return os.EBADF
	}
	c := cc.c
	if req.Close {
		// We write the EOF to the write-side error, because there
		// still might be some pipelined reads
		cc.we = ErrPersistEOF
	}
	cc.lk.Unlock()

	err = req.Write(c)
	cc.lk.Lock()
	defer cc.lk.Unlock()
	if err != nil {
		cc.we = err
		return err
	}
	cc.nwritten++

	return nil
}

// Pending returns the number of unanswered requests
// that have been sent on the connection.
func (cc *ClientConn) Pending() int {
	cc.lk.Lock()
	defer cc.lk.Unlock()
	return cc.nwritten - cc.nread
}

// Read reads the next response from the wire. A valid response might be
// returned together with an ErrPersistEOF, which means that the remote
// requested that this be the last request serviced. Read can be called
// concurrently with Write, but not with another Read.
func (cc *ClientConn) Read(req *Request) (resp *Response, err os.Error) {

	// Retrieve the pipeline ID of this request/response pair
	cc.lk.Lock()
	id, ok := cc.pipereq[req]
	cc.pipereq[req] = 0, false
	if !ok {
		cc.lk.Unlock()
		return nil, ErrPipeline
	}
	cc.lk.Unlock()

	// Ensure pipeline order
	cc.pipe.StartResponse(id)
	defer cc.pipe.EndResponse(id)

	cc.lk.Lock()
	if cc.re != nil {
		defer cc.lk.Unlock()
		return nil, cc.re
	}
	if cc.r == nil { // connection closed by user in the meantime
		defer cc.lk.Unlock()
		return nil, os.EBADF
	}
	r := cc.r
	lastbody := cc.lastbody
	cc.lastbody = nil
	cc.lk.Unlock()

	// Make sure body is fully consumed, even if user does not call body.Close
	if lastbody != nil {
		// body.Close is assumed to be idempotent and multiple calls to
		// it should return the error that its first invokation
		// returned.
		err = lastbody.Close()
		if err != nil {
			cc.lk.Lock()
			defer cc.lk.Unlock()
			cc.re = err
			return nil, err
		}
	}

	resp, err = ReadResponse(r, req.Method)
	cc.lk.Lock()
	defer cc.lk.Unlock()
	if err != nil {
		cc.re = err
		return resp, err
	}
	cc.lastbody = resp.Body

	cc.nread++

	if resp.Close {
		cc.re = ErrPersistEOF // don't send any more requests
		return resp, cc.re
	}
	return resp, err
}

// Do is convenience method that writes a request and reads a response.
func (cc *ClientConn) Do(req *Request) (resp *Response, err os.Error) {
	err = cc.Write(req)
	if err != nil {
		return
	}
	return cc.Read(req)
}
<|endoftext|>


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

package walk

import (
	"os"
	"syscall"
	"unsafe"
)

import (
	. "walk/winapi"
	. "walk/winapi/comctl32"
	. "walk/winapi/user32"
)

type ToolBar struct {
	WidgetBase
	imageList      *ImageList
	actions        *ActionList
	minButtonWidth uint16
	maxButtonWidth uint16
}

func newToolBar(parent Container, style uint) (*ToolBar, os.Error) {
	if parent == nil {
		return nil, newError("parent cannot be nil")
	}

	hWnd := CreateWindowEx(
		0, syscall.StringToUTF16Ptr("ToolbarWindow32"), nil,
		WS_CHILD|style,
		0, 0, 0, 0, parent.BaseWidget().hWnd, 0, 0, nil)
	if hWnd == 0 {
		return nil, lastError("CreateWindowEx")
	}

	tb := &ToolBar{
		WidgetBase: WidgetBase{
			hWnd:   hWnd,
			parent: parent,
		},
	}

	succeeded := false
	defer func() {
		if !succeeded {
			tb.Dispose()
		}
	}()

	tb.layoutFlags = HGrow | HShrink | VGrow | VShrink

	tb.actions = newActionList(tb)

	tb.SetFont(defaultFont)

	if err := parent.Children().Add(tb); err != nil {
		return nil, err
	}

	widgetsByHWnd[hWnd] = tb

	//	exStyle := SendMessage(hWnd, TB_GETEXTENDEDSTYLE, 0, 0)
	//	exStyle |= TBSTYLE_EX_DOUBLEBUFFER
	//	SendMessage(hWnd, TB_SETEXTENDEDSTYLE, 0, LPARAM(exStyle))

	succeeded = true

	return tb, nil
}

func NewToolBar(parent Container) (*ToolBar, os.Error) {
	return newToolBar(parent, TBSTYLE_WRAPABLE)
}

func NewVerticalToolBar(parent Container) (*ToolBar, os.Error) {
	return newToolBar(parent, CCS_VERT|CCS_NORESIZE)
}

func (tb *ToolBar) LayoutFlagsMask() LayoutFlags {
	style := GetWindowLong(tb.hWnd, GWL_STYLE)

	if style&CCS_VERT > 0 {
		return VShrink | VGrow
	}

	return HShrink | HGrow
}

func (tb *ToolBar) PreferredSize() Size {
	if tb.actions.Len() == 0 {
		return Size{}
	}

	style := GetWindowLong(tb.hWnd, GWL_STYLE)

	if style&CCS_VERT > 0 && tb.minButtonWidth > 0 {
		return Size{int(tb.minButtonWidth), 44}
	}

	// FIXME: Figure out how to do this.
	return Size{44, 44}
}

func (tb *ToolBar) ButtonWidthLimits() (min, max uint16) {
	return tb.minButtonWidth, tb.maxButtonWidth
}

func (tb *ToolBar) SetButtonWidthLimits(min, max uint16) os.Error {
	if SendMessage(tb.hWnd, TB_SETBUTTONWIDTH, 0, uintptr(MAKELONG(min, max))) == 0 {
		return newError("TB_SETBUTTONWIDTH failed")
	}

	tb.minButtonWidth = min
	tb.maxButtonWidth = max

	return nil
}

func (tb *ToolBar) Actions() *ActionList {
	return tb.actions
}

func (tb *ToolBar) ImageList() *ImageList {
	return tb.imageList
}

func (tb *ToolBar) SetImageList(value *ImageList) {
	var hIml HIMAGELIST

	if value != nil {
		hIml = value.hIml
	}

	SendMessage(tb.hWnd, TB_SETIMAGELIST, 0, uintptr(hIml))

	tb.imageList = value
}

func (tb *ToolBar) imageIndex(image *Bitmap) (imageIndex int, err os.Error) {
	imageIndex = -1
	if image != nil {
		// FIXME: Protect against duplicate insertion
		imageIndex, err = tb.imageList.AddMasked(image)
		if err != nil {
			return
		}
	}

	return
}

func (tb *ToolBar) wndProc(hwnd HWND, msg uint, wParam, lParam uintptr, origWndProcPtr uintptr) uintptr {
	switch msg {
	case WM_NOTIFY:
		nmm := (*NMMOUSE)(unsafe.Pointer(lParam))

		switch nmm.Hdr.Code {
		case NM_CLICK:
			actionId := uint16(nmm.DwItemSpec)
			action := actionsById[actionId]
			action.raiseTriggered()
		}
	}

	return tb.WidgetBase.wndProc(hwnd, msg, wParam, lParam, origWndProcPtr)
}

func (tb *ToolBar) onActionChanged(action *Action) (err os.Error) {
	imageIndex, err := tb.imageIndex(action.image)
	if err != nil {
		return
	}

	tbbi := TBBUTTONINFO{
		DwMask:  TBIF_BYINDEX | TBIF_IMAGE | TBIF_STATE | TBIF_STYLE | TBIF_TEXT,
		IImage:  imageIndex,
		FsState: TBSTATE_WRAP,
		FsStyle: BTNS_BUTTON,
		PszText: syscall.StringToUTF16Ptr(action.Text()),
	}
	tbbi.CbSize = uint(unsafe.Sizeof(tbbi))
	if action.checked {
		tbbi.FsState |= TBSTATE_CHECKED
	}
	if action.enabled {
		tbbi.FsState |= TBSTATE_ENABLED
	}
	if action.checkable {
		tbbi.FsStyle |= BTNS_CHECK
	}
	if action.exclusive {
		tbbi.FsStyle |= BTNS_GROUP
	}

	if 0 == SendMessage(tb.hWnd, TB_SETBUTTONINFO, uintptr(tb.actions.Index(action)), uintptr(unsafe.Pointer(&tbbi))) {
		err = newError("SendMessage(TB_SETBUTTONINFO) failed")
	}

	return
}

func (tb *ToolBar) onInsertingAction(index int, action *Action) (err os.Error) {
	imageIndex, err := tb.imageIndex(action.image)
	if err != nil {
		return
	}

	tbb := TBBUTTON{
		IBitmap:   imageIndex,
		IdCommand: int(action.id),
		FsState:   TBSTATE_WRAP,
		FsStyle:/*BTNS_AUTOSIZE |*/ BTNS_BUTTON,
		IString: uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(action.Text()))),
	}
	if action.checked {
		tbb.FsState |= TBSTATE_CHECKED
	}
	if action.enabled {
		tbb.FsState |= TBSTATE_ENABLED
	}
	if action.checkable {
		tbb.FsStyle |= BTNS_CHECK
	}
	if action.exclusive {
		tbb.FsStyle |= BTNS_GROUP
	}

	tb.SetVisible(true)

	SendMessage(tb.hWnd, TB_BUTTONSTRUCTSIZE, uintptr(unsafe.Sizeof(tbb)), 0)
	SendMessage(tb.hWnd, TB_ADDBUTTONS, 1, uintptr(unsafe.Pointer(&tbb)))
	SendMessage(tb.hWnd, TB_AUTOSIZE, 0, 0)

	return
}

func (tb *ToolBar) removeAt(index int) (err os.Error) {
	if 0 == SendMessage(tb.hWnd, TB_DELETEBUTTON, uintptr(index), 0) {
		err = newError("SendMessage(TB_DELETEBUTTON) failed")
	}

	return
}

func (tb *ToolBar) onRemovingAction(index int, action *Action) os.Error {
	return tb.removeAt(index)
}

func (tb *ToolBar) onClearingActions() (err os.Error) {
	for i := tb.actions.Len() - 1; i >= 0; i-- {
		err = tb.removeAt(i)
		if err != nil {
			return
		}
	}

	return
}
<commit_msg>Fix ToolBar regression<commit_after>// Copyright 2010 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package walk

import (
	"os"
	"syscall"
	"unsafe"
)

import (
	. "walk/winapi"
	. "walk/winapi/comctl32"
	. "walk/winapi/user32"
)

type ToolBar struct {
	WidgetBase
	imageList      *ImageList
	actions        *ActionList
	minButtonWidth uint16
	maxButtonWidth uint16
}

func newToolBar(parent Container, style uint) (*ToolBar, os.Error) {
	if parent == nil {
		return nil, newError("parent cannot be nil")
	}

	hWnd := CreateWindowEx(
		0, syscall.StringToUTF16Ptr("ToolbarWindow32"), nil,
		WS_CHILD|style,
		0, 0, 0, 0, parent.BaseWidget().hWnd, 0, 0, nil)
	if hWnd == 0 {
		return nil, lastError("CreateWindowEx")
	}

	tb := &ToolBar{
		WidgetBase: WidgetBase{
			hWnd:   hWnd,
			parent: parent,
		},
	}

	succeeded := false
	defer func() {
		if !succeeded {
			tb.Dispose()
		}
	}()

	tb.layoutFlags = HGrow | HShrink | VGrow | VShrink

	tb.actions = newActionList(tb)

	tb.SetFont(defaultFont)

	if err := parent.Children().Add(tb); err != nil {
		return nil, err
	}

	widgetsByHWnd[hWnd] = tb

	//	exStyle := SendMessage(hWnd, TB_GETEXTENDEDSTYLE, 0, 0)
	//	exStyle |= TBSTYLE_EX_DOUBLEBUFFER
	//	SendMessage(hWnd, TB_SETEXTENDEDSTYLE, 0, LPARAM(exStyle))

	succeeded = true

	return tb, nil
}

func NewToolBar(parent Container) (*ToolBar, os.Error) {
	return newToolBar(parent, TBSTYLE_WRAPABLE)
}

func NewVerticalToolBar(parent Container) (*ToolBar, os.Error) {
	return newToolBar(parent, CCS_VERT|CCS_NORESIZE)
}

func (tb *ToolBar) LayoutFlagsMask() LayoutFlags {
	style := GetWindowLong(tb.hWnd, GWL_STYLE)

	if style&CCS_VERT > 0 {
		return VShrink | VGrow
	}

	return HShrink | HGrow
}

func (tb *ToolBar) PreferredSize() Size {
	if tb.actions.Len() == 0 {
		return Size{}
	}

	style := GetWindowLong(tb.hWnd, GWL_STYLE)

	if style&CCS_VERT > 0 && tb.minButtonWidth > 0 {
		return Size{int(tb.minButtonWidth), 44}
	}

	// FIXME: Figure out how to do this.
	return Size{44, 44}
}

func (tb *ToolBar) ButtonWidthLimits() (min, max uint16) {
	return tb.minButtonWidth, tb.maxButtonWidth
}

func (tb *ToolBar) SetButtonWidthLimits(min, max uint16) os.Error {
	if SendMessage(tb.hWnd, TB_SETBUTTONWIDTH, 0, uintptr(MAKELONG(min, max))) == 0 {
		return newError("TB_SETBUTTONWIDTH failed")
	}

	tb.minButtonWidth = min
	tb.maxButtonWidth = max

	return nil
}

func (tb *ToolBar) Actions() *ActionList {
	return tb.actions
}

func (tb *ToolBar) ImageList() *ImageList {
	return tb.imageList
}

func (tb *ToolBar) SetImageList(value *ImageList) {
	var hIml HIMAGELIST

	if value != nil {
		hIml = value.hIml
	}

	SendMessage(tb.hWnd, TB_SETIMAGELIST, 0, uintptr(hIml))

	tb.imageList = value
}

func (tb *ToolBar) imageIndex(image *Bitmap) (imageIndex int, err os.Error) {
	imageIndex = -1
	if image != nil {
		// FIXME: Protect against duplicate insertion
		imageIndex, err = tb.imageList.AddMasked(image)
		if err != nil {
			return
		}
	}

	return
}

func (tb *ToolBar) wndProc(hwnd HWND, msg uint, wParam, lParam uintptr, origWndProcPtr uintptr) uintptr {
	switch msg {
	case WM_NOTIFY:
		nmm := (*NMMOUSE)(unsafe.Pointer(lParam))

		switch nmm.Hdr.Code {
		case NM_CLICK:
			actionId := uint16(nmm.DwItemSpec)
			if action := actionsById[actionId]; action != nil {
				action.raiseTriggered()
			}
		}
	}

	return tb.WidgetBase.wndProc(hwnd, msg, wParam, lParam, origWndProcPtr)
}

func (tb *ToolBar) onActionChanged(action *Action) (err os.Error) {
	imageIndex, err := tb.imageIndex(action.image)
	if err != nil {
		return
	}

	tbbi := TBBUTTONINFO{
		DwMask:  TBIF_BYINDEX | TBIF_IMAGE | TBIF_STATE | TBIF_STYLE | TBIF_TEXT,
		IImage:  imageIndex,
		FsState: TBSTATE_WRAP,
		FsStyle: BTNS_BUTTON,
		PszText: syscall.StringToUTF16Ptr(action.Text()),
	}
	tbbi.CbSize = uint(unsafe.Sizeof(tbbi))
	if action.checked {
		tbbi.FsState |= TBSTATE_CHECKED
	}
	if action.enabled {
		tbbi.FsState |= TBSTATE_ENABLED
	}
	if action.checkable {
		tbbi.FsStyle |= BTNS_CHECK
	}
	if action.exclusive {
		tbbi.FsStyle |= BTNS_GROUP
	}

	if 0 == SendMessage(tb.hWnd, TB_SETBUTTONINFO, uintptr(tb.actions.Index(action)), uintptr(unsafe.Pointer(&tbbi))) {
		err = newError("SendMessage(TB_SETBUTTONINFO) failed")
	}

	return
}

func (tb *ToolBar) onInsertingAction(index int, action *Action) (err os.Error) {
	imageIndex, err := tb.imageIndex(action.image)
	if err != nil {
		return
	}

	tbb := TBBUTTON{
		IBitmap:   imageIndex,
		IdCommand: int(action.id),
		FsState:   TBSTATE_WRAP,
		FsStyle:/*BTNS_AUTOSIZE |*/ BTNS_BUTTON,
		IString: uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(action.Text()))),
	}
	if action.checked {
		tbb.FsState |= TBSTATE_CHECKED
	}
	if action.enabled {
		tbb.FsState |= TBSTATE_ENABLED
	}
	if action.checkable {
		tbb.FsStyle |= BTNS_CHECK
	}
	if action.exclusive {
		tbb.FsStyle |= BTNS_GROUP
	}

	tb.SetVisible(true)

	SendMessage(tb.hWnd, TB_BUTTONSTRUCTSIZE, uintptr(unsafe.Sizeof(tbb)), 0)
	SendMessage(tb.hWnd, TB_ADDBUTTONS, 1, uintptr(unsafe.Pointer(&tbb)))
	SendMessage(tb.hWnd, TB_AUTOSIZE, 0, 0)

	return
}

func (tb *ToolBar) removeAt(index int) (err os.Error) {
	if 0 == SendMessage(tb.hWnd, TB_DELETEBUTTON, uintptr(index), 0) {
		err = newError("SendMessage(TB_DELETEBUTTON) failed")
	}

	return
}

func (tb *ToolBar) onRemovingAction(index int, action *Action) os.Error {
	return tb.removeAt(index)
}

func (tb *ToolBar) onClearingActions() (err os.Error) {
	for i := tb.actions.Len() - 1; i >= 0; i-- {
		err = tb.removeAt(i)
		if err != nil {
			return
		}
	}

	return
}
<|endoftext|>


<commit_before>// +build esv5

package backend

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strings"
	"time"

	"bosun.org/annotate"
	elastic "gopkg.in/olivere/elastic.v5"
)

type Elastic struct {
	*elastic.Client
	index             string
	urls              []string
	simpleClient      bool
	clientOptionFuncs []elastic.ClientOptionFunc
	maxResults        int
	initialized       bool
}

func NewElastic(urls []string, simpleclient bool, index string, clientoptions []elastic.ClientOptionFunc) *Elastic {
	return &Elastic{&elastic.Client{}, index, urls, simpleclient, clientoptions, 200, false}
}

func (e *Elastic) GetAnnotations(start, end *time.Time, fieldFilters ...FieldFilter) (annotate.Annotations, error) {
	if !e.initialized {
		return nil, unInitErr
	}
	annotations := annotate.Annotations{}
	filters := []elastic.Query{}
	if start != nil && end != nil {
		startQ := elastic.NewRangeQuery(annotate.EndDate).Gte(start)
		endQ := elastic.NewRangeQuery(annotate.StartDate).Lte(end)
		filters = append(filters, elastic.NewBoolQuery().Must(startQ, endQ))
	}
	for _, filter := range fieldFilters {
		switch filter.Field {
		case annotate.Source, annotate.Host, annotate.CreationUser, annotate.Owner, annotate.Category:
		default:
			return annotations, fmt.Errorf("%v is not a field that can be filtered on", filter.Field)
		}
		var q elastic.Query
		switch filter.Verb {
		case Is, "":
			q = elastic.NewTermQuery(filter.Field, filter.Value)
		case Empty:
			// Can't detect empty on a analyzed field
			if filter.Field == annotate.Message {
				return annotations, fmt.Errorf("message field does not support empty searches")
			}
			q = elastic.NewTermQuery(filter.Field, "")
		default:
			return annotations, fmt.Errorf("%v is not a valid query verb", filter.Verb)
		}
		if filter.Not {
			q = elastic.NewBoolQuery().MustNot(q)
		}
		filters = append(filters, q)
	}

	var aType annotate.Annotation
	scroll := e.Scroll(e.index).Query(elastic.NewBoolQuery().Must(filters...)).Size(e.maxResults).Pretty(true)
	for {
		res, err := scroll.Do(context.Background())
		if err == io.EOF {
			break
		}
		if err != nil {
			return annotations, err
		}
		for _, item := range res.Each(reflect.TypeOf(aType)) {
			a := item.(annotate.Annotation)
			annotations = append(annotations, a)
		}
	}
	return annotations, nil
}

func (e *Elastic) GetFieldValues(field string) ([]string, error) {
	if !e.initialized {
		return nil, unInitErr
	}
	terms := []string{}
	switch field {
	case annotate.Source, annotate.Host, annotate.CreationUser, annotate.Owner, annotate.Category:
		//continue
	default:
		return terms, fmt.Errorf("invalid field %v", field)
	}
	termsAgg := elastic.NewTermsAggregation().Field(field)
	res, err := e.Search(e.index).Aggregation(field, termsAgg).Size(e.maxResults).Do(context.Background())
	if err != nil {
		return terms, err
	}
	b, found := res.Aggregations.Terms(field)
	if !found {
		return terms, fmt.Errorf("expected aggregation %v not found in result", field)
	}
	for _, bucket := range b.Buckets {
		if v, ok := bucket.Key.(string); ok {
			terms = append(terms, v)
		}
	}
	return terms, nil
}

func (e *Elastic) InitBackend() error {
	var err error
	var ec *elastic.Client

	if e.simpleClient {
		ec, err = elastic.NewSimpleClient(elastic.SetURL(e.urls...))
	} else if len(e.urls) == 0 {
		ec, err = elastic.NewClient(e.clientOptionFuncs...)
	} else {
		ec, err = elastic.NewClient(elastic.SetURL(e.urls...))
	}
	if err != nil {
		return err
	}
	e.Client = ec
	exists, err := e.IndexExists(e.index).Do(context.Background())
	if err != nil {
		return err
	}
	if !exists {
		res, err := e.CreateIndex(e.index).Do(context.Background())
		if (res != nil && !res.Acknowledged) || err != nil {
			return fmt.Errorf("failed to create elastic mapping (ack: %v): %v", res != nil && res.Acknowledged, err)
		}
	}
	stringNA := map[string]string{
		"type":  "string",
		"index": "not_analyzed",
	}
	stringA := map[string]string{
		"type": "string",
	}
	date := map[string]string{
		"type": "date",
	}
	p := make(map[string]interface{})
	p[annotate.Message] = stringA
	p[annotate.StartDate] = date
	p[annotate.EndDate] = date
	p[annotate.Source] = stringNA
	p[annotate.Host] = stringNA
	p[annotate.CreationUser] = stringNA
	p[annotate.Owner] = stringNA
	p[annotate.Category] = stringNA
	p[annotate.Url] = stringNA
	mapping := make(map[string]interface{})
	mapping["properties"] = p
	q := e.PutMapping().Index(e.index).Type(docType).BodyJson(mapping)
	res, err := q.Do(context.Background())
	if (res != nil && !res.Acknowledged) || err != nil {
		return fmt.Errorf("failed to create elastic mapping (ack: %v): %v", res != nil && res.Acknowledged, err)
	}
	e.initialized = true
	return nil
}

func (e *Elastic) InsertAnnotation(a *annotate.Annotation) error {
	if !e.initialized {
		return unInitErr
	}
	_, err := e.Index().Index(e.index).BodyJson(a).Id(a.Id).Type(docType).Do(context.Background())
	return err
}

func (e *Elastic) GetAnnotation(id string) (*annotate.Annotation, bool, error) {
	if !e.initialized {
		return nil, false, unInitErr
	}
	a := annotate.Annotation{}
	if id == "" {
		return &a, false, fmt.Errorf("must provide id")
	}
	res, err := e.Get().Index(e.index).Type(docType).Id(id).Do(context.Background())
	// Ewwww...
	if err != nil && strings.Contains(err.Error(), "Error 404") {
		return &a, false, nil
	}
	if err != nil {
		return &a, false, err
	}
	if err := json.Unmarshal(*res.Source, &a); err != nil {
		return &a, res.Found, err
	}
	return &a, res.Found, nil
}

func (e *Elastic) DeleteAnnotation(id string) error {
	if !e.initialized {
		return unInitErr
	}
	_, err := e.Delete().Index(e.index).Type(docType).Id(id).Do(context.Background())
	if err != nil {
		return err
	}
	return nil
	//TODO? Check res.Found?
}
<commit_msg>try new mappings<commit_after>// +build esv5

package backend

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strings"
	"time"

	"bosun.org/annotate"
	elastic "gopkg.in/olivere/elastic.v5"
)

type Elastic struct {
	*elastic.Client
	index             string
	urls              []string
	simpleClient      bool
	clientOptionFuncs []elastic.ClientOptionFunc
	maxResults        int
	initialized       bool
}

func NewElastic(urls []string, simpleclient bool, index string, clientoptions []elastic.ClientOptionFunc) *Elastic {
	return &Elastic{&elastic.Client{}, index, urls, simpleclient, clientoptions, 200, false}
}

func (e *Elastic) GetAnnotations(start, end *time.Time, fieldFilters ...FieldFilter) (annotate.Annotations, error) {
	if !e.initialized {
		return nil, unInitErr
	}
	annotations := annotate.Annotations{}
	filters := []elastic.Query{}
	if start != nil && end != nil {
		startQ := elastic.NewRangeQuery(annotate.EndDate).Gte(start)
		endQ := elastic.NewRangeQuery(annotate.StartDate).Lte(end)
		filters = append(filters, elastic.NewBoolQuery().Must(startQ, endQ))
	}
	for _, filter := range fieldFilters {
		switch filter.Field {
		case annotate.Source, annotate.Host, annotate.CreationUser, annotate.Owner, annotate.Category:
		default:
			return annotations, fmt.Errorf("%v is not a field that can be filtered on", filter.Field)
		}
		var q elastic.Query
		switch filter.Verb {
		case Is, "":
			q = elastic.NewTermQuery(filter.Field, filter.Value)
		case Empty:
			// Can't detect empty on a analyzed field
			if filter.Field == annotate.Message {
				return annotations, fmt.Errorf("message field does not support empty searches")
			}
			q = elastic.NewTermQuery(filter.Field, "")
		default:
			return annotations, fmt.Errorf("%v is not a valid query verb", filter.Verb)
		}
		if filter.Not {
			q = elastic.NewBoolQuery().MustNot(q)
		}
		filters = append(filters, q)
	}

	var aType annotate.Annotation
	scroll := e.Scroll(e.index).Query(elastic.NewBoolQuery().Must(filters...)).Size(e.maxResults).Pretty(true)
	for {
		res, err := scroll.Do(context.Background())
		if err == io.EOF {
			break
		}
		if err != nil {
			return annotations, err
		}
		for _, item := range res.Each(reflect.TypeOf(aType)) {
			a := item.(annotate.Annotation)
			annotations = append(annotations, a)
		}
	}
	return annotations, nil
}

func (e *Elastic) GetFieldValues(field string) ([]string, error) {
	if !e.initialized {
		return nil, unInitErr
	}
	terms := []string{}
	switch field {
	case annotate.Source, annotate.Host, annotate.CreationUser, annotate.Owner, annotate.Category:
		//continue
	default:
		return terms, fmt.Errorf("invalid field %v", field)
	}
	termsAgg := elastic.NewTermsAggregation().Field(field)
	res, err := e.Search(e.index).Aggregation(field, termsAgg).Size(e.maxResults).Do(context.Background())
	if err != nil {
		return terms, err
	}
	b, found := res.Aggregations.Terms(field)
	if !found {
		return terms, fmt.Errorf("expected aggregation %v not found in result", field)
	}
	for _, bucket := range b.Buckets {
		if v, ok := bucket.Key.(string); ok {
			terms = append(terms, v)
		}
	}
	return terms, nil
}

func (e *Elastic) InitBackend() error {
	var err error
	var ec *elastic.Client

	if e.simpleClient {
		ec, err = elastic.NewSimpleClient(elastic.SetURL(e.urls...))
	} else if len(e.urls) == 0 {
		ec, err = elastic.NewClient(e.clientOptionFuncs...)
	} else {
		ec, err = elastic.NewClient(elastic.SetURL(e.urls...))
	}
	if err != nil {
		return err
	}
	e.Client = ec
	exists, err := e.IndexExists(e.index).Do(context.Background())
	if err != nil {
		return err
	}
	if !exists {
		res, err := e.CreateIndex(e.index).Do(context.Background())
		if (res != nil && !res.Acknowledged) || err != nil {
			return fmt.Errorf("failed to create elastic mapping (ack: %v): %v", res != nil && res.Acknowledged, err)
		}
	}
	// mappings updated according to https://www.elastic.co/blog/strings-are-dead-long-live-strings
	stringNA := map[string]interface{}{
		"type":  "keyword",
		"index": true,
	}
	stringA := map[string]string{
		"type":  "text",
		"index": true,
	}
	date := map[string]string{
		"type": "date",
	}
	p := make(map[string]interface{})
	p[annotate.Message] = stringA
	p[annotate.StartDate] = date
	p[annotate.EndDate] = date
	p[annotate.Source] = stringNA
	p[annotate.Host] = stringNA
	p[annotate.CreationUser] = stringNA
	p[annotate.Owner] = stringNA
	p[annotate.Category] = stringNA
	p[annotate.Url] = stringNA
	mapping := make(map[string]interface{})
	mapping["properties"] = p
	q := e.PutMapping().Index(e.index).Type(docType).BodyJson(mapping)
	res, err := q.Do(context.Background())
	if (res != nil && !res.Acknowledged) || err != nil {
		return fmt.Errorf("failed to create elastic mapping (ack: %v): %v", res != nil && res.Acknowledged, err)
	}
	e.initialized = true
	return nil
}

func (e *Elastic) InsertAnnotation(a *annotate.Annotation) error {
	if !e.initialized {
		return unInitErr
	}
	_, err := e.Index().Index(e.index).BodyJson(a).Id(a.Id).Type(docType).Do(context.Background())
	return err
}

func (e *Elastic) GetAnnotation(id string) (*annotate.Annotation, bool, error) {
	if !e.initialized {
		return nil, false, unInitErr
	}
	a := annotate.Annotation{}
	if id == "" {
		return &a, false, fmt.Errorf("must provide id")
	}
	res, err := e.Get().Index(e.index).Type(docType).Id(id).Do(context.Background())
	// Ewwww...
	if err != nil && strings.Contains(err.Error(), "Error 404") {
		return &a, false, nil
	}
	if err != nil {
		return &a, false, err
	}
	if err := json.Unmarshal(*res.Source, &a); err != nil {
		return &a, res.Found, err
	}
	return &a, res.Found, nil
}

func (e *Elastic) DeleteAnnotation(id string) error {
	if !e.initialized {
		return unInitErr
	}
	_, err := e.Delete().Index(e.index).Type(docType).Id(id).Do(context.Background())
	if err != nil {
		return err
	}
	return nil
	//TODO? Check res.Found?
}
<|endoftext|>