<commit_before>package epub

import (
	"archive/zip"
	"bytes"
	"encoding/xml"
	"errors"
	"io"
	"path"
	"strings"

	"golang.org/x/net/html"
)

const ContainerPath = "META-INF/container.xml"

var (
	ErrNoRootfile  = errors.New("epub: no rootfile found in container")
	ErrBadRootfile = errors.New("epub: container references non-existent rootfile")
	ErrNoItemref   = errors.New("epub: no itemrefs found in spine")
	ErrBadItemref  = errors.New("epub: itemref references non-existent item")
)

type Reader struct {
	Container
	files map[string]*zip.File
}

type ReadCloser struct {
	Reader
	z *zip.ReadCloser
}

// Rootfile contains the location of a content.opf package file.
type Rootfile struct {
	FullPath string `xml:"full-path,attr"`
	Package
}

// Container serves as a directory of Rootfiles.
type Container struct {
	Rootfiles []*Rootfile `xml:"rootfiles>rootfile"`
}

// Package represents an epub content.opf file.
type Package struct {
	Metadata
	Manifest
	Spine
}

// Metadata contains publishing information about the epub.
type Metadata struct {
	Title       string `xml:"metadata>title"`
	Language    string `xml:"metadata>language"`
	Identifier  string `xml:"metadata>idenifier"`
	Creator     string `xml:"metadata>creator"`
	Contributor string `xml:"metadata>contributor"`
	Publisher   string `xml:"metadata>publisher"`
	Subject     string `xml:"metadata>subject"`
	Description string `xml:"metadata>description"`
	Event       []struct {
		Name string `xml:"event,attr"`
		Date string `xml:",innerxml"`
	} `xml:"metadata>date"`
	Type     string `xml:"metadata>type"`
	Format   string `xml:"metadata>format"`
	Source   string `xml:"metadata>source"`
	Relation string `xml:"metadata>relation"`
	Coverage string `xml:"metadata>coverage"`
	Rights   string `xml:"metadata>rights"`
}

// Manifest lists every file that is part of the epub.
type Manifest struct {
	Items []Item `xml:"manifest>item"`
}

// Item represents a file stored in the epub.
type Item struct {
	ID        string `xml:"id,attr"`
	HREF      string `xml:"href,attr"`
	MediaType string `xml:"media-type,attr"`
	f         *zip.File
}

// Spine defines the reading order of the epub documents.
type Spine struct {
	Itemrefs []Itemref `xml:"spine>itemref"`
}

// Itemref points to an Item.
type Itemref struct {
	IDREF string `xml:"idref,attr"`
	Item  *Item
}

// OpenReader will open the epub file specified by name and return a
// ReadCloser.
func OpenReader(name string) (*ReadCloser, error) {
	z, err := zip.OpenReader(name)
	if err != nil {
		return nil, err
	}

	rc := new(ReadCloser)
	rc.z = z
	if err = rc.init(&z.Reader); err != nil {
		return nil, err
	}
	return rc, nil
}

// NewReader returns a new Reader reading from r, which is assumed to have the
// given size in bytes.
func NewReader(ra io.ReaderAt, size int64) (*Reader, error) {
	z, err := zip.NewReader(ra, size)
	if err != nil {
		return nil, err
	}

	r := new(Reader)
	if err = r.init(z); err != nil {
		return nil, err
	}
	return r, nil
}

func (r *Reader) init(z *zip.Reader) error {
	// Create a file lookup table
	r.files = make(map[string]*zip.File)
	for _, f := range z.File {
		r.files[f.Name] = f
	}

	err := r.setContainer()
	if err != nil {
		return err
	}
	err = r.setPackages()
	if err != nil {
		return err
	}
	err = r.setItems()
	if err != nil {
		return err
	}

	return nil
}

// setContainer unmarshals the epub's container.xml file.
func (r *Reader) setContainer() error {
	f, err := r.files[ContainerPath].Open()
	if err != nil {
		return err
	}

	var b bytes.Buffer
	_, err = io.Copy(&b, f)
	if err != nil {
		return err
	}

	err = xml.Unmarshal(b.Bytes(), &r.Container)
	if err != nil {
		return err
	}

	if len(r.Container.Rootfiles) < 1 {
		return ErrNoRootfile
	}

	return nil
}

// setPackages unmarshal's each of the epub's content.opf files.
func (r *Reader) setPackages() error {
	for _, rf := range r.Container.Rootfiles {
		if r.files[rf.FullPath] == nil {
			return ErrBadRootfile
		}

		f, err := r.files[rf.FullPath].Open()
		if err != nil {
			return err
		}

		var b bytes.Buffer
		_, err = io.Copy(&b, f)
		if err != nil {
			return err
		}

		err = xml.Unmarshal(b.Bytes(), &rf.Package)
		if err != nil {
			return err
		}
	}

	return nil
}

// setItems associates Itemrefs with their respective Item and Items with
// their zip.File.
func (r *Reader) setItems() error {
	itemrefCount := 0
	for _, rf := range r.Container.Rootfiles {
		itemMap := make(map[string]*Item)
		for i := range rf.Manifest.Items {
			item := &rf.Manifest.Items[i]
			itemMap[item.ID] = item

			abs := path.Join(path.Dir(rf.FullPath), item.HREF)
			item.f = r.files[abs]
		}

		for i := range rf.Spine.Itemrefs {
			itemref := &rf.Spine.Itemrefs[i]
			itemref.Item = itemMap[itemref.IDREF]
			if itemref.Item == nil {
				return ErrBadItemref
			}
		}
		itemrefCount += len(rf.Spine.Itemrefs)
	}

	if itemrefCount < 1 {
		return ErrNoItemref
	}

	return nil
}

// Text returns a bytes.Buffer representing the plain text contents of an item.
// For non-xml/html items or items whose file contents are missing, the buffer
// will contain no text.
func (item *Item) Text() (buf bytes.Buffer, err error) {
	if !(strings.Contains(item.MediaType, "xml") ||
		strings.Contains(item.MediaType, "html") ||
		item.f == nil) {
		_, err = buf.WriteString("")
		return
	}

	rc, err := item.f.Open()
	if err != nil {
		return
	}
	defer rc.Close()

	t := html.NewTokenizer(rc)
	for {
		switch t.Next() {
		case html.ErrorToken:
			if err = t.Err(); err != io.EOF {
				return
			}
			return buf, nil
		case html.TextToken:
			_, err = buf.Write(t.Text())
			if err != nil {
				return
			}
		}
	}
}

// Close closes the epub file, rendering it unusable for I/O.
func (rc *ReadCloser) Close() {
	rc.z.Close()
}
<commit_msg>Display alt text in place of images; skip style tags<commit_after>package epub

import (
	"archive/zip"
	"bytes"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"path"
	"strings"

	"golang.org/x/net/html"
)

const ContainerPath = "META-INF/container.xml"

var (
	ErrNoRootfile  = errors.New("epub: no rootfile found in container")
	ErrBadRootfile = errors.New("epub: container references non-existent rootfile")
	ErrNoItemref   = errors.New("epub: no itemrefs found in spine")
	ErrBadItemref  = errors.New("epub: itemref references non-existent item")
)

type Reader struct {
	Container
	files map[string]*zip.File
}

type ReadCloser struct {
	Reader
	z *zip.ReadCloser
}

// Rootfile contains the location of a content.opf package file.
type Rootfile struct {
	FullPath string `xml:"full-path,attr"`
	Package
}

// Container serves as a directory of Rootfiles.
type Container struct {
	Rootfiles []*Rootfile `xml:"rootfiles>rootfile"`
}

// Package represents an epub content.opf file.
type Package struct {
	Metadata
	Manifest
	Spine
}

// Metadata contains publishing information about the epub.
type Metadata struct {
	Title       string `xml:"metadata>title"`
	Language    string `xml:"metadata>language"`
	Identifier  string `xml:"metadata>idenifier"`
	Creator     string `xml:"metadata>creator"`
	Contributor string `xml:"metadata>contributor"`
	Publisher   string `xml:"metadata>publisher"`
	Subject     string `xml:"metadata>subject"`
	Description string `xml:"metadata>description"`
	Event       []struct {
		Name string `xml:"event,attr"`
		Date string `xml:",innerxml"`
	} `xml:"metadata>date"`
	Type     string `xml:"metadata>type"`
	Format   string `xml:"metadata>format"`
	Source   string `xml:"metadata>source"`
	Relation string `xml:"metadata>relation"`
	Coverage string `xml:"metadata>coverage"`
	Rights   string `xml:"metadata>rights"`
}

// Manifest lists every file that is part of the epub.
type Manifest struct {
	Items []Item `xml:"manifest>item"`
}

// Item represents a file stored in the epub.
type Item struct {
	ID        string `xml:"id,attr"`
	HREF      string `xml:"href,attr"`
	MediaType string `xml:"media-type,attr"`
	f         *zip.File
}

// Spine defines the reading order of the epub documents.
type Spine struct {
	Itemrefs []Itemref `xml:"spine>itemref"`
}

// Itemref points to an Item.
type Itemref struct {
	IDREF string `xml:"idref,attr"`
	*Item
}

// OpenReader will open the epub file specified by name and return a
// ReadCloser.
func OpenReader(name string) (*ReadCloser, error) {
	z, err := zip.OpenReader(name)
	if err != nil {
		return nil, err
	}

	rc := new(ReadCloser)
	rc.z = z
	if err = rc.init(&z.Reader); err != nil {
		return nil, err
	}
	return rc, nil
}

// NewReader returns a new Reader reading from r, which is assumed to have the
// given size in bytes.
func NewReader(ra io.ReaderAt, size int64) (*Reader, error) {
	z, err := zip.NewReader(ra, size)
	if err != nil {
		return nil, err
	}

	r := new(Reader)
	if err = r.init(z); err != nil {
		return nil, err
	}
	return r, nil
}

func (r *Reader) init(z *zip.Reader) error {
	// Create a file lookup table
	r.files = make(map[string]*zip.File)
	for _, f := range z.File {
		r.files[f.Name] = f
	}

	err := r.setContainer()
	if err != nil {
		return err
	}
	err = r.setPackages()
	if err != nil {
		return err
	}
	err = r.setItems()
	if err != nil {
		return err
	}

	return nil
}

// setContainer unmarshals the epub's container.xml file.
func (r *Reader) setContainer() error {
	f, err := r.files[ContainerPath].Open()
	if err != nil {
		return err
	}

	var b bytes.Buffer
	_, err = io.Copy(&b, f)
	if err != nil {
		return err
	}

	err = xml.Unmarshal(b.Bytes(), &r.Container)
	if err != nil {
		return err
	}

	if len(r.Container.Rootfiles) < 1 {
		return ErrNoRootfile
	}

	return nil
}

// setPackages unmarshal's each of the epub's content.opf files.
func (r *Reader) setPackages() error {
	for _, rf := range r.Container.Rootfiles {
		if r.files[rf.FullPath] == nil {
			return ErrBadRootfile
		}

		f, err := r.files[rf.FullPath].Open()
		if err != nil {
			return err
		}

		var b bytes.Buffer
		_, err = io.Copy(&b, f)
		if err != nil {
			return err
		}

		err = xml.Unmarshal(b.Bytes(), &rf.Package)
		if err != nil {
			return err
		}
	}

	return nil
}

// setItems associates Itemrefs with their respective Item and Items with
// their zip.File.
func (r *Reader) setItems() error {
	itemrefCount := 0
	for _, rf := range r.Container.Rootfiles {
		itemMap := make(map[string]*Item)
		for i := range rf.Manifest.Items {
			item := &rf.Manifest.Items[i]
			itemMap[item.ID] = item

			abs := path.Join(path.Dir(rf.FullPath), item.HREF)
			item.f = r.files[abs]
		}

		for i := range rf.Spine.Itemrefs {
			itemref := &rf.Spine.Itemrefs[i]
			itemref.Item = itemMap[itemref.IDREF]
			if itemref.Item == nil {
				return ErrBadItemref
			}
		}
		itemrefCount += len(rf.Spine.Itemrefs)
	}

	if itemrefCount < 1 {
		return ErrNoItemref
	}

	return nil
}

// Text returns a bytes.Buffer representing the plain text contents of an item.
// For non-xml/html items or items whose file contents are missing, the buffer
// will contain no text. Alt text will be used in place of images when
// available.
func (item *Item) Text() (buf bytes.Buffer, err error) {
	isText := strings.Contains(item.MediaType, "xml") || strings.Contains(item.MediaType, "html")
	if !isText || item.f == nil {
		_, err = buf.WriteString("")
		return
	}

	rc, err := item.f.Open()
	if err != nil {
		return
	}
	defer rc.Close()

	var elStack []string
	t := html.NewTokenizer(rc)
	for {
		switch t.Next() {
		case html.ErrorToken:
			if err = t.Err(); err != io.EOF {
				return
			}
			return buf, nil
		case html.StartTagToken:
			elStack = append(elStack, t.Token().Data) // push element
			fallthrough
		case html.SelfClosingTagToken:
			// Display alt text in place of image
			token := t.Token()
			if token.Data == "img" {
				for _, a := range token.Attr {
					if a.Key == "alt" {
						_, err := buf.Write([]byte(fmt.Sprintf("\nImage alt text: %s\n", a.Val)))
						if err != nil {
							return buf, err
						}
					}
				}
			}
		case html.TextToken:
			// Skip style tags
			if len(elStack) > 0 && elStack[len(elStack)-1] == "style" {
				break
			}
			_, err = buf.Write(t.Text())
			if err != nil {
				return
			}
		case html.EndTagToken:
			elStack = elStack[:len(elStack)-1] // pop element
		}
	}
}

// Close closes the epub file, rendering it unusable for I/O.
func (rc *ReadCloser) Close() {
	rc.z.Close()
}
<|endoftext|>


<commit_before>// Package packet provides structures to marshal binary data to and from binary data.
// The specification is located at http://gearman.org/protocol/.
package packet

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"math"
)

type packetCode []byte

var (
	// Req is the code for a Request packet
	Req = packetCode([]byte{0, byte('R'), byte('E'), byte('Q')})
	// Res is the code for a Response packet
	Res = packetCode([]byte{0, byte('R'), byte('E'), byte('S')})
)

// Packet contains a Gearman packet. See http://gearman.org/protocol/
type Packet struct {
	// The Code for the packet: either \0REQ or \0RES
	Code packetCode
	// The Type of the packet, e.g. WorkStatus
	Type Type
	// The Arguments of the packet
	Arguments [][]byte
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (packet *Packet) UnmarshalBinary(data []byte) error {
	// ensure packet is of minimum length
	if len(data) < 12 {
		return errors.New("All gearman packets must be at least 12 bytes or more.")
	}

	// determine the packet magic code
	if bytes.Compare(data[0:4], Req) == 0 {
		packet.Code = Req
	} else if bytes.Compare(data[0:4], Res) == 0 {
		packet.Code = Res
	} else {
		return fmt.Errorf("Unrecognized magic packet code %#v", data[0:4])
	}

	// determine the kind of packet
	kind := int32(0)
	if err := binary.Read(bytes.NewBuffer(data[4:8]), binary.BigEndian, &kind); err != nil {
		return fmt.Errorf("Error while reading packet type: %s", err)
	}
	packet.Type = Type(kind)

	// parse the length of the packet
	length := int32(0)
	if err := binary.Read(bytes.NewBuffer(data[8:12]), binary.BigEndian, &length); err != nil {
		return fmt.Errorf("Error while reading packet length: %s", err)
	}

	// parse the arguments into a byte array
	packet.Arguments = [][]byte{}
	if length > 0 {
		packet.Arguments = bytes.Split(data[12:len(data)], []byte{0})
	}

	return nil
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (packet *Packet) MarshalBinary() ([]byte, error) {
	// form a buffer with the packet's magic code
	buf := bytes.NewBuffer(packet.Code)

	// write the request header
	if err := binary.Write(buf, binary.BigEndian, int32(packet.Type)); err != nil {
		return nil, fmt.Errorf("Error while writing packet type: %s", err)
	}

	// write the size of the packet
	size := len(packet.Arguments) - 1 // One for each null-byte separator
	for _, argument := range packet.Arguments {
		size += len(argument)
	}
	size = int(math.Max(0, float64(size)))

	// write the size of the packet
	if err := binary.Write(buf, binary.BigEndian, int32(size)); err != nil {
		return nil, fmt.Errorf("Error while writing packet length: %s", err)
	}

	// write all arguments provided
	for i := 0; i < len(packet.Arguments); i++ {
		if _, err := buf.Write(packet.Arguments[i]); err != nil {
			return nil, fmt.Errorf("Error while writing packet argument: %s", err)
		}

		// null deliminate every argument but the last
		if i == len(packet.Arguments)-1 {
			break // last argument
		} else if err := buf.WriteByte(0); err != nil {
			return nil, fmt.Errorf("Error while deliminating packet argument: %s", err)
		}
	}
	return buf.Bytes(), nil
}
<commit_msg>bytes.Buffer is super safe apparently<commit_after>// Package packet provides structures to marshal binary data to and from binary data.
// The specification is located at http://gearman.org/protocol/.
package packet

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"math"
)

type packetCode []byte

var (
	// Req is the code for a Request packet
	Req = packetCode([]byte{0, byte('R'), byte('E'), byte('Q')})
	// Res is the code for a Response packet
	Res = packetCode([]byte{0, byte('R'), byte('E'), byte('S')})
)

// Packet contains a Gearman packet. See http://gearman.org/protocol/
type Packet struct {
	// The Code for the packet: either \0REQ or \0RES
	Code packetCode
	// The Type of the packet, e.g. WorkStatus
	Type Type
	// The Arguments of the packet
	Arguments [][]byte
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (packet *Packet) UnmarshalBinary(data []byte) error {
	// ensure packet is of minimum length
	if len(data) < 12 {
		return errors.New("All gearman packets must be at least 12 bytes or more.")
	}

	// determine the packet magic code
	if bytes.Compare(data[0:4], Req) == 0 {
		packet.Code = Req
	} else if bytes.Compare(data[0:4], Res) == 0 {
		packet.Code = Res
	} else {
		return fmt.Errorf("Unrecognized magic packet code %#v", data[0:4])
	}

	// determine the kind of packet
	kind := int32(0)
	if err := binary.Read(bytes.NewBuffer(data[4:8]), binary.BigEndian, &kind); err != nil {
		return fmt.Errorf("Error while reading packet type: %s", err)
	}
	packet.Type = Type(kind)

	// parse the length of the packet
	length := int32(0)
	if err := binary.Read(bytes.NewBuffer(data[8:12]), binary.BigEndian, &length); err != nil {
		return fmt.Errorf("Error while reading packet length: %s", err)
	}

	// parse the arguments into a byte array
	packet.Arguments = [][]byte{}
	if length > 0 {
		packet.Arguments = bytes.Split(data[12:len(data)], []byte{0})
	}

	return nil
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (packet *Packet) MarshalBinary() ([]byte, error) {
	// form a buffer with the packet's magic code
	buf := bytes.NewBuffer(packet.Code)

	// write the packet type
	if err := binary.Write(buf, binary.BigEndian, int32(packet.Type)); err != nil {
		return nil, fmt.Errorf("Error while writing packet type: %s", err)
	}

	// finish the header with the size of the packet
	size := len(packet.Arguments) - 1 // One for each null-byte separator
	for _, argument := range packet.Arguments {
		size += len(argument)
	}
	size = int(math.Max(0, float64(size)))

	// write the size of the packet
	if err := binary.Write(buf, binary.BigEndian, int32(size)); err != nil {
		return nil, fmt.Errorf("Error while writing packet length: %s", err)
	}

	// write all arguments provided
	for i, arg := range packet.Arguments {
		buf.Write(arg)

		// null deliminate every argument but the last
		if i != len(packet.Arguments)-1 {
			buf.WriteByte(0)
		}
	}
	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before>package manta

import (
	"github.com/dotabuff/manta/dota"
)

// Represents the state of an entity
type packetEntity struct {
	index      int32
	classId    int32
	className  string
	sendTable  *sendTable
	properties map[string]interface{}
}

// Internal callback for CSVCMsg_PacketEntities.
func (p *Parser) onCSVCMsg_PacketEntities(m *dota.CSVCMsg_PacketEntities) error {
	// XXX: Remove once we've gotten readProperties working.
	return nil

	defer func() {
		if err := recover(); err != nil {
			_debugf("recovered: %s", err)
		}
	}()

	_debugf("pTick=%d isDelta=%v deltaFrom=%d updatedEntries=%d maxEntries=%d baseline=%d updateBaseline=%v", p.Tick, m.GetIsDelta(), m.GetDeltaFrom(), m.GetUpdatedEntries(), m.GetMaxEntries(), m.GetBaseline(), m.GetUpdateBaseline())

	r := newReader(m.GetEntityData())
	index := int32(-1)
	ok := false

	// Iterate over all entries
	for i := 0; i < int(m.GetUpdatedEntries()); i++ {
		// Read the index delta from the buffer. This is an implementation
		// from Alice. An alternate implementation from Yasha has the same result.
		delta := r.readBits(6)
		switch delta & 0x30 {
		case 16:
			delta = (delta & 15) | (r.readBits(4) << 4)
		case 32:
			delta = (delta & 15) | (r.readBits(8) << 4)
		case 48:
			delta = (delta & 15) | (r.readBits(28) << 4)
		}
		index += int32(delta) + 1
		_debugf("index delta is %d to %d", delta, index)

		// Read the type of update based on two booleans.
		// This appears to be backwards from source 1:
		// true+true used to be "create", now appears to be false+true?
		// This seems suspcious.
		updateType := " "
		if r.readBoolean() {
			if r.readBoolean() {
				updateType = "D"
			} else {
				updateType = "?"
			}
		} else {
			if r.readBoolean() {
				updateType = "C"
			} else {
				updateType = "U"
			}
		}
		_debugf("update type is %s", updateType)

		// Proceed based on the update type
		switch updateType {
		case "C":
			// Create a new packetEntity.
			pe := &packetEntity{
				index:      index,
				classId:    int32(r.readBits(p.classIdSize)),
				properties: make(map[string]interface{}),
			}

			// Skip the 10 serial bits for now.
			r.seekBits(10)

			// Get the associated class.
			if pe.className, ok = p.classInfo[pe.classId]; !ok {
				_panicf("unable to find class %d", pe.classId)
			}

			// Get the associated send table.
			if pe.sendTable, ok = p.sendTables.getTableByName(pe.className); !ok {
				_panicf("unable to find sendtable for class %s", pe.className)
			}

			// Register the packetEntity with the parser.
			p.packetEntities[index] = pe

			_debugf("created a pe: %+v", pe)

			// Read properties and set them in the packetEntity
			pe.properties = readProperties(r, pe.sendTable)

		case "U":
			// Find the existing packetEntity
			pe, ok := p.packetEntities[index]
			if !ok {
				_panicf("unable to find packet entity %d for update", index)
			}

			// Read properties and update the packetEntity
			for k, v := range readProperties(r, pe.sendTable) {
				pe.properties[k] = v
			}

		case "D":
			if _, ok := p.packetEntities[index]; !ok {
				_panicf("unable to find packet entity %d for delete", index)
			} else {
				delete(p.packetEntities, index)
			}
		}
	}

	return nil
}
<commit_msg>Reuse readUBitVar for packet entity index<commit_after>package manta

import (
	"github.com/dotabuff/manta/dota"
)

// Represents the state of an entity
type packetEntity struct {
	index      int32
	classId    int32
	className  string
	sendTable  *sendTable
	properties map[string]interface{}
}

// Internal callback for CSVCMsg_PacketEntities.
func (p *Parser) onCSVCMsg_PacketEntities(m *dota.CSVCMsg_PacketEntities) error {
	// XXX: Remove once we've gotten readProperties working.
	return nil

	defer func() {
		if err := recover(); err != nil {
			_debugf("recovered: %s", err)
		}
	}()

	_debugf("pTick=%d isDelta=%v deltaFrom=%d updatedEntries=%d maxEntries=%d baseline=%d updateBaseline=%v", p.Tick, m.GetIsDelta(), m.GetDeltaFrom(), m.GetUpdatedEntries(), m.GetMaxEntries(), m.GetBaseline(), m.GetUpdateBaseline())

	r := newReader(m.GetEntityData())
	index := int32(-1)
	ok := false

	// Iterate over all entries
	for i := 0; i < int(m.GetUpdatedEntries()); i++ {
		// Read the index delta from the buffer. This is an implementation
		// from Alice. An alternate implementation from Yasha has the same result.
		delta := r.readUBitVar()
		index += int32(delta) + 1
		_debugf("index delta is %d to %d", delta, index)

		// Read the type of update based on two booleans.
		// This appears to be backwards from source 1:
		// true+true used to be "create", now appears to be false+true?
		// This seems suspcious.
		updateType := " "
		if r.readBoolean() {
			if r.readBoolean() {
				updateType = "D"
			} else {
				updateType = "?"
			}
		} else {
			if r.readBoolean() {
				updateType = "C"
			} else {
				updateType = "U"
			}
		}
		_debugf("update type is %s", updateType)

		// Proceed based on the update type
		switch updateType {
		case "C":
			// Create a new packetEntity.
			pe := &packetEntity{
				index:      index,
				classId:    int32(r.readBits(p.classIdSize)),
				properties: make(map[string]interface{}),
			}

			// Skip the 10 serial bits for now.
			r.seekBits(10)

			// Get the associated class.
			if pe.className, ok = p.classInfo[pe.classId]; !ok {
				_panicf("unable to find class %d", pe.classId)
			}

			// Get the associated send table.
			if pe.sendTable, ok = p.sendTables.getTableByName(pe.className); !ok {
				_panicf("unable to find sendtable for class %s", pe.className)
			}

			// Register the packetEntity with the parser.
			p.packetEntities[index] = pe

			_debugf("created a pe: %+v", pe)

			// Read properties and set them in the packetEntity
			pe.properties = readProperties(r, pe.sendTable)

		case "U":
			// Find the existing packetEntity
			pe, ok := p.packetEntities[index]
			if !ok {
				_panicf("unable to find packet entity %d for update", index)
			}

			// Read properties and update the packetEntity
			for k, v := range readProperties(r, pe.sendTable) {
				pe.properties[k] = v
			}

		case "D":
			if _, ok := p.packetEntities[index]; !ok {
				_panicf("unable to find packet entity %d for delete", index)
			} else {
				delete(p.packetEntities, index)
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2013 CoreOS Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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 etcd

import (
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	goetcd "github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
	golog "github.com/coreos/etcd/third_party/github.com/coreos/go-log/log"
	"github.com/coreos/etcd/third_party/github.com/goraft/raft"

	"github.com/coreos/etcd/config"
	ehttp "github.com/coreos/etcd/http"
	"github.com/coreos/etcd/log"
	"github.com/coreos/etcd/metrics"
	"github.com/coreos/etcd/server"
	"github.com/coreos/etcd/store"
)

type Etcd struct {
	Config       *config.Config     // etcd config
	Store        store.Store        // data store
	Registry     *server.Registry   // stores URL information for nodes
	Server       *server.Server     // http server, runs on 4001 by default
	PeerServer   *server.PeerServer // peer server, runs on 7001 by default
	listener     net.Listener       // Listener for Server
	peerListener net.Listener       // Listener for PeerServer
	readyC       chan bool          // To signal when server is ready to accept connections
}

// New returns a new Etcd instance.
func New(c *config.Config) *Etcd {
	if c == nil {
		c = config.New()
	}
	return &Etcd{
		Config: c,
		readyC: make(chan bool),
	}
}

// Run the etcd instance.
func (e *Etcd) Run() {
	// Enable options.
	if e.Config.VeryVeryVerbose {
		log.Verbose = true
		raft.SetLogLevel(raft.Trace)
		goetcd.SetLogger(
			golog.New(
				"go-etcd",
				false,
				golog.CombinedSink(
					os.Stdout,
					"[%s] %s %-9s | %s\n",
					[]string{"prefix", "time", "priority", "message"},
				),
			),
		)
	} else if e.Config.VeryVerbose {
		log.Verbose = true
		raft.SetLogLevel(raft.Debug)
	} else if e.Config.Verbose {
		log.Verbose = true
	}
	if e.Config.CPUProfileFile != "" {
		profile(e.Config.CPUProfileFile)
	}

	if e.Config.DataDir == "" {
		log.Fatal("The data dir was not set and could not be guessed from machine name")
	}

	// Create data directory if it doesn't already exist.
	if err := os.MkdirAll(e.Config.DataDir, 0744); err != nil {
		log.Fatalf("Unable to create path: %s", err)
	}

	// Warn people if they have an info file
	info := filepath.Join(e.Config.DataDir, "info")
	if _, err := os.Stat(info); err == nil {
		log.Warnf("All cached configuration is now ignored. The file %s can be removed.", info)
	}

	var mbName string
	if e.Config.Trace() {
		mbName = e.Config.MetricsBucketName()
		runtime.SetBlockProfileRate(1)
	}

	mb := metrics.NewBucket(mbName)

	if e.Config.GraphiteHost != "" {
		err := mb.Publish(e.Config.GraphiteHost)
		if err != nil {
			panic(err)
		}
	}

	// Retrieve CORS configuration
	corsInfo, err := ehttp.NewCORSInfo(e.Config.CorsOrigins)
	if err != nil {
		log.Fatal("CORS:", err)
	}

	// Create etcd key-value store and registry.
	e.Store = store.New()
	e.Registry = server.NewRegistry(e.Store)

	// Create stats objects
	followersStats := server.NewRaftFollowersStats(e.Config.Name)
	serverStats := server.NewRaftServerStats(e.Config.Name)

	// Calculate all of our timeouts
	heartbeatInterval := time.Duration(e.Config.Peer.HeartbeatInterval) * time.Millisecond
	electionTimeout := time.Duration(e.Config.Peer.ElectionTimeout) * time.Millisecond
	dialTimeout := (3 * heartbeatInterval) + electionTimeout
	responseHeaderTimeout := (3 * heartbeatInterval) + electionTimeout

	// Create peer server
	psConfig := server.PeerServerConfig{
		Name:          e.Config.Name,
		Scheme:        e.Config.PeerTLSInfo().Scheme(),
		URL:           e.Config.Peer.Addr,
		SnapshotCount: e.Config.SnapshotCount,
		RetryTimes:    e.Config.MaxRetryAttempts,
		RetryInterval: e.Config.RetryInterval,
	}
	e.PeerServer = server.NewPeerServer(psConfig, e.Registry, e.Store, &mb, followersStats, serverStats)

	// Create raft transporter and server
	raftTransporter := server.NewTransporter(followersStats, serverStats, e.Registry, heartbeatInterval, dialTimeout, responseHeaderTimeout)
	if psConfig.Scheme == "https" {
		raftClientTLSConfig, err := e.Config.PeerTLSInfo().ClientConfig()
		if err != nil {
			log.Fatal("raft client TLS error: ", err)
		}
		raftTransporter.SetTLSConfig(*raftClientTLSConfig)
	}
	raftServer, err := raft.NewServer(e.Config.Name, e.Config.DataDir, raftTransporter, e.Store, e.PeerServer, "")
	if err != nil {
		log.Fatal(err)
	}
	raftServer.SetElectionTimeout(electionTimeout)
	raftServer.SetHeartbeatInterval(heartbeatInterval)
	e.PeerServer.SetRaftServer(raftServer)

	// Create etcd server
	e.Server = server.New(e.Config.Name, e.Config.Addr, e.PeerServer, e.Registry, e.Store, &mb)

	if e.Config.Trace() {
		e.Server.EnableTracing()
	}

	e.PeerServer.SetServer(e.Server)

	// Generating config could be slow.
	// Put it here to make listen happen immediately after peer-server starting.
	peerTLSConfig := server.TLSServerConfig(e.Config.PeerTLSInfo())
	etcdTLSConfig := server.TLSServerConfig(e.Config.EtcdTLSInfo())

	log.Infof("peer server [name %s, listen on %s, advertised url %s]", e.PeerServer.Config.Name, e.Config.Peer.BindAddr, e.PeerServer.Config.URL)
	e.peerListener = server.NewListener(psConfig.Scheme, e.Config.Peer.BindAddr, peerTLSConfig)

	log.Infof("etcd server [name %s, listen on %s, advertised url %s]", e.Server.Name, e.Config.BindAddr, e.Server.URL())
	e.listener = server.NewListener(e.Config.EtcdTLSInfo().Scheme(), e.Config.BindAddr, etcdTLSConfig)

	close(e.readyC) // etcd server is ready to accept connections, notify waiters.

	// An error string equivalent to net.errClosing for using with
	// http.Serve() during server shutdown. Need to re-declare
	// here because it is not exported by "net" package.
	const errClosing = "use of closed network connection"

	peerServerClosed := make(chan bool)
	go func() {
		// Starting peer server should be followed close by listening on its port
		// If not, it may leave many requests unaccepted, or cannot receive heartbeat from the cluster.
		// One severe problem caused if failing receiving heartbeats is when the second node joins one-node cluster,
		// the cluster could be out of work as long as the two nodes cannot transfer messages.
		e.PeerServer.Start(e.Config.Snapshot, e.Config.Discovery, e.Config.Peers)
		log.Infof("peer server [name %s, listen on %s, advertised url %s]", e.PeerServer.Config.Name, e.Config.Peer.BindAddr, e.PeerServer.Config.URL)
		e.peerListener = server.NewListener(psConfig.Scheme, e.Config.Peer.BindAddr, peerTLSConfig)

		sHTTP := &ehttp.CORSHandler{e.PeerServer.HTTPHandler(), corsInfo}
		if err = http.Serve(e.peerListener, sHTTP); err != nil {
			if !strings.Contains(err.Error(), errClosing) {
				log.Fatal(err)
			}
		}
		close(peerServerClosed)
	}()

	sHTTP := &ehttp.CORSHandler{e.Server.HTTPHandler(), corsInfo}
	if err = http.Serve(e.listener, sHTTP); err != nil {
		if !strings.Contains(err.Error(), errClosing) {
			log.Fatal(err)
		}
	}

	<-peerServerClosed
	log.Infof("etcd instance is stopped [name %s]", e.Config.Name)
}

// Stop the etcd instance.
//
// TODO Shutdown gracefully.
func (e *Etcd) Stop() {
	e.PeerServer.Stop()
	e.peerListener.Close()
	e.listener.Close()
}

// ReadyNotify returns a channel that is going to be closed
// when the etcd instance is ready to accept connections.
func (e *Etcd) ReadyNotify() chan bool {
	return e.readyC
}
<commit_msg>chore(main): add a space line between the two if statements<commit_after>/*
Copyright 2013 CoreOS Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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 etcd

import (
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	goetcd "github.com/coreos/etcd/third_party/github.com/coreos/go-etcd/etcd"
	golog "github.com/coreos/etcd/third_party/github.com/coreos/go-log/log"
	"github.com/coreos/etcd/third_party/github.com/goraft/raft"

	"github.com/coreos/etcd/config"
	ehttp "github.com/coreos/etcd/http"
	"github.com/coreos/etcd/log"
	"github.com/coreos/etcd/metrics"
	"github.com/coreos/etcd/server"
	"github.com/coreos/etcd/store"
)

type Etcd struct {
	Config       *config.Config     // etcd config
	Store        store.Store        // data store
	Registry     *server.Registry   // stores URL information for nodes
	Server       *server.Server     // http server, runs on 4001 by default
	PeerServer   *server.PeerServer // peer server, runs on 7001 by default
	listener     net.Listener       // Listener for Server
	peerListener net.Listener       // Listener for PeerServer
	readyC       chan bool          // To signal when server is ready to accept connections
}

// New returns a new Etcd instance.
func New(c *config.Config) *Etcd {
	if c == nil {
		c = config.New()
	}
	return &Etcd{
		Config: c,
		readyC: make(chan bool),
	}
}

// Run the etcd instance.
func (e *Etcd) Run() {
	// Enable options.
	if e.Config.VeryVeryVerbose {
		log.Verbose = true
		raft.SetLogLevel(raft.Trace)
		goetcd.SetLogger(
			golog.New(
				"go-etcd",
				false,
				golog.CombinedSink(
					os.Stdout,
					"[%s] %s %-9s | %s\n",
					[]string{"prefix", "time", "priority", "message"},
				),
			),
		)
	} else if e.Config.VeryVerbose {
		log.Verbose = true
		raft.SetLogLevel(raft.Debug)
	} else if e.Config.Verbose {
		log.Verbose = true
	}

	if e.Config.CPUProfileFile != "" {
		profile(e.Config.CPUProfileFile)
	}

	if e.Config.DataDir == "" {
		log.Fatal("The data dir was not set and could not be guessed from machine name")
	}

	// Create data directory if it doesn't already exist.
	if err := os.MkdirAll(e.Config.DataDir, 0744); err != nil {
		log.Fatalf("Unable to create path: %s", err)
	}

	// Warn people if they have an info file
	info := filepath.Join(e.Config.DataDir, "info")
	if _, err := os.Stat(info); err == nil {
		log.Warnf("All cached configuration is now ignored. The file %s can be removed.", info)
	}

	var mbName string
	if e.Config.Trace() {
		mbName = e.Config.MetricsBucketName()
		runtime.SetBlockProfileRate(1)
	}

	mb := metrics.NewBucket(mbName)

	if e.Config.GraphiteHost != "" {
		err := mb.Publish(e.Config.GraphiteHost)
		if err != nil {
			panic(err)
		}
	}

	// Retrieve CORS configuration
	corsInfo, err := ehttp.NewCORSInfo(e.Config.CorsOrigins)
	if err != nil {
		log.Fatal("CORS:", err)
	}

	// Create etcd key-value store and registry.
	e.Store = store.New()
	e.Registry = server.NewRegistry(e.Store)

	// Create stats objects
	followersStats := server.NewRaftFollowersStats(e.Config.Name)
	serverStats := server.NewRaftServerStats(e.Config.Name)

	// Calculate all of our timeouts
	heartbeatInterval := time.Duration(e.Config.Peer.HeartbeatInterval) * time.Millisecond
	electionTimeout := time.Duration(e.Config.Peer.ElectionTimeout) * time.Millisecond
	dialTimeout := (3 * heartbeatInterval) + electionTimeout
	responseHeaderTimeout := (3 * heartbeatInterval) + electionTimeout

	// Create peer server
	psConfig := server.PeerServerConfig{
		Name:          e.Config.Name,
		Scheme:        e.Config.PeerTLSInfo().Scheme(),
		URL:           e.Config.Peer.Addr,
		SnapshotCount: e.Config.SnapshotCount,
		RetryTimes:    e.Config.MaxRetryAttempts,
		RetryInterval: e.Config.RetryInterval,
	}
	e.PeerServer = server.NewPeerServer(psConfig, e.Registry, e.Store, &mb, followersStats, serverStats)

	// Create raft transporter and server
	raftTransporter := server.NewTransporter(followersStats, serverStats, e.Registry, heartbeatInterval, dialTimeout, responseHeaderTimeout)
	if psConfig.Scheme == "https" {
		raftClientTLSConfig, err := e.Config.PeerTLSInfo().ClientConfig()
		if err != nil {
			log.Fatal("raft client TLS error: ", err)
		}
		raftTransporter.SetTLSConfig(*raftClientTLSConfig)
	}
	raftServer, err := raft.NewServer(e.Config.Name, e.Config.DataDir, raftTransporter, e.Store, e.PeerServer, "")
	if err != nil {
		log.Fatal(err)
	}
	raftServer.SetElectionTimeout(electionTimeout)
	raftServer.SetHeartbeatInterval(heartbeatInterval)
	e.PeerServer.SetRaftServer(raftServer)

	// Create etcd server
	e.Server = server.New(e.Config.Name, e.Config.Addr, e.PeerServer, e.Registry, e.Store, &mb)

	if e.Config.Trace() {
		e.Server.EnableTracing()
	}

	e.PeerServer.SetServer(e.Server)

	// Generating config could be slow.
	// Put it here to make listen happen immediately after peer-server starting.
	peerTLSConfig := server.TLSServerConfig(e.Config.PeerTLSInfo())
	etcdTLSConfig := server.TLSServerConfig(e.Config.EtcdTLSInfo())

	log.Infof("peer server [name %s, listen on %s, advertised url %s]", e.PeerServer.Config.Name, e.Config.Peer.BindAddr, e.PeerServer.Config.URL)
	e.peerListener = server.NewListener(psConfig.Scheme, e.Config.Peer.BindAddr, peerTLSConfig)

	log.Infof("etcd server [name %s, listen on %s, advertised url %s]", e.Server.Name, e.Config.BindAddr, e.Server.URL())
	e.listener = server.NewListener(e.Config.EtcdTLSInfo().Scheme(), e.Config.BindAddr, etcdTLSConfig)

	close(e.readyC) // etcd server is ready to accept connections, notify waiters.

	// An error string equivalent to net.errClosing for using with
	// http.Serve() during server shutdown. Need to re-declare
	// here because it is not exported by "net" package.
	const errClosing = "use of closed network connection"

	peerServerClosed := make(chan bool)
	go func() {
		// Starting peer server should be followed close by listening on its port
		// If not, it may leave many requests unaccepted, or cannot receive heartbeat from the cluster.
		// One severe problem caused if failing receiving heartbeats is when the second node joins one-node cluster,
		// the cluster could be out of work as long as the two nodes cannot transfer messages.
		e.PeerServer.Start(e.Config.Snapshot, e.Config.Discovery, e.Config.Peers)
		log.Infof("peer server [name %s, listen on %s, advertised url %s]", e.PeerServer.Config.Name, e.Config.Peer.BindAddr, e.PeerServer.Config.URL)
		e.peerListener = server.NewListener(psConfig.Scheme, e.Config.Peer.BindAddr, peerTLSConfig)

		sHTTP := &ehttp.CORSHandler{e.PeerServer.HTTPHandler(), corsInfo}
		if err = http.Serve(e.peerListener, sHTTP); err != nil {
			if !strings.Contains(err.Error(), errClosing) {
				log.Fatal(err)
			}
		}
		close(peerServerClosed)
	}()

	sHTTP := &ehttp.CORSHandler{e.Server.HTTPHandler(), corsInfo}
	if err = http.Serve(e.listener, sHTTP); err != nil {
		if !strings.Contains(err.Error(), errClosing) {
			log.Fatal(err)
		}
	}

	<-peerServerClosed
	log.Infof("etcd instance is stopped [name %s]", e.Config.Name)
}

// Stop the etcd instance.
//
// TODO Shutdown gracefully.
func (e *Etcd) Stop() {
	e.PeerServer.Stop()
	e.peerListener.Close()
	e.listener.Close()
}

// ReadyNotify returns a channel that is going to be closed
// when the etcd instance is ready to accept connections.
func (e *Etcd) ReadyNotify() chan bool {
	return e.readyC
}
<|endoftext|>


<commit_before>package pinger

import (
	"fmt"
	"net"
	"sync"
	"time"

	"golang.org/x/net/icmp"
)

// An EchoRequest is a single ICMP echo request packet that will be sent.
// When the echoResponse is recieved, the "Received" field will be set and
// the Done() will be called on the WaitGroup.
//
type EchoRequest struct {
	icmp.Message

	Destination net.IP
	Sent        time.Time
	Received    time.Time
	ID          string
	WaitGroup   *sync.WaitGroup
}

// create a new EchoRequest instance.
func NewEchoRequest(msg icmp.Message, dest net.IP, wg *sync.WaitGroup) *EchoRequest {
	return &EchoRequest{
		Message:     msg,
		Destination: dest,
		WaitGroup:   wg,
		ID:          packetKey(dest.String(), msg.Body.(*icmp.Echo).ID, msg.Body.(*icmp.Echo).Seq),
	}

}

func packetKey(addr string, id, seq int) string {
	return fmt.Sprintf("%s-%d-%d", addr, id, seq)
}

func (p *Pinger) Send(req *EchoRequest) error {
	b, err := req.Marshal(nil)
	if err != nil {
		return err
	}
	if req.Destination.To4() == nil {
		_, err = p.v6Conn.WriteTo(b, &net.IPAddr{IP: req.Destination})
		if err != nil {
			return err
		}
	} else {
		_, err = p.v4Conn.WriteTo(b, &net.IPAddr{IP: req.Destination})
		if err != nil {
			return err
		}
	}
	req.Sent = time.Now()
	return nil
}
<commit_msg>Avoid negative latency<commit_after>package pinger

import (
	"fmt"
	"net"
	"sync"
	"time"

	"golang.org/x/net/icmp"
)

// An EchoRequest is a single ICMP echo request packet that will be sent.
// When the echoResponse is recieved, the "Received" field will be set and
// the Done() will be called on the WaitGroup.
//
type EchoRequest struct {
	icmp.Message

	Destination net.IP
	Sent        time.Time
	Received    time.Time
	ID          string
	WaitGroup   *sync.WaitGroup
}

// create a new EchoRequest instance.
func NewEchoRequest(msg icmp.Message, dest net.IP, wg *sync.WaitGroup) *EchoRequest {
	return &EchoRequest{
		Message:     msg,
		Destination: dest,
		WaitGroup:   wg,
		ID:          packetKey(dest.String(), msg.Body.(*icmp.Echo).ID, msg.Body.(*icmp.Echo).Seq),
	}

}

func packetKey(addr string, id, seq int) string {
	return fmt.Sprintf("%s-%d-%d", addr, id, seq)
}

func (p *Pinger) Send(req *EchoRequest) error {
	b, err := req.Marshal(nil)
	if err != nil {
		return err
	}
	req.Sent = time.Now()
	if req.Destination.To4() == nil {
		_, err = p.v6Conn.WriteTo(b, &net.IPAddr{IP: req.Destination})
		if err != nil {
			return err
		}
	} else {
		_, err = p.v4Conn.WriteTo(b, &net.IPAddr{IP: req.Destination})
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package locker

import "github.com/coreos/go-etcd/etcd"

// EtcdStore is a backing store for Locker which uses Etcd for storage.
type EtcdStore struct {
	// Etcd client used for storing locks.
	Etcd *etcd.Client

	// Directory in Etcd to store locks. Default: locker.
	Directory string

	// TTL is the time-to-live for the lock. Default: 5s.
	TTL int
}

// Get returns the value of a lock. LockNotFound will be returned if a
// lock with the name isn't held.
func (s EtcdStore) Get(name string) (string, error) {
	res, err := s.Etcd.Get(s.lockPath(name), false, false)
	if err == nil {
		return res.Node.Value, nil
	}

	if etcderr, ok := err.(etcd.EtcdError); ok && etcderr.ErrorCode == 100 {
		return "", LockNotFound{name}
	}

	return "", err
}

// AcquireOrFreshenLock will aquires a named lock if it isn't already
// held, or updates its TTL if it is.
func (s EtcdStore) AcquireOrFreshenLock(name, value string) error {
	if err := s.ensureLockDirectoryCreated(); err != nil {
		return err
	}

	key := s.lockPath(name)
	_, err := s.Etcd.CompareAndSwap(key, value, s.lockTTL(), value, 0)
	if err == nil {
		// success!
		return nil
	}

	if etcderr, ok := err.(etcd.EtcdError); ok {
		switch etcderr.ErrorCode {
		case 100:
			// key doesn't exist, set it. This seems to be odd behaviour for
			// CompareAndSwap. Surely, if it doesn't exist we should just set
			// it as part of CompareAndSwap. Potential for a race condition here,
			// where another client is able to do a CompareAndSwap and then we
			// stomp on it with our dumb Set.
			if _, err := s.Etcd.Set(key, value, 1); err != nil {
				// wasn't able to force-set the key, no idea what happened
				return err
			}

			// Retry after stomping
			return s.AcquireOrFreshenLock(name, value)
		case 101:
			// couldn't set the key, the prevValue we gave it differs from the
			// one in the server. Someone else has this key.
			return LockDenied{name}
		}
	}

	return err
}

// directory will return the provided Directory or locker if nil.
func (s EtcdStore) directory() string {
	if s.Directory == "" {
		return "locker"
	}

	return s.Directory
}

// ensureLockDirectoryCreated tries to create the root locker directory in
// etcd. This is to compensate for etcd sometimes getting upset when all
// the nodes expire.
func (s EtcdStore) ensureLockDirectoryCreated() error {
	_, err := s.Etcd.CreateDir(s.directory(), 0)

	if eerr, ok := err.(*etcd.EtcdError); ok {
		if eerr.ErrorCode == 105 {
			return nil // key already exists, cool
		}
	}

	// not an etcderr, or a etcderror we want to propagate, or there was no error
	return err
}

// lockPath gets the path to a lock in Etcd. Defaults to /locker/name
func (s EtcdStore) lockPath(name string) string {
	return s.directory() + "/" + name
}

// lockTTL gets the TTL of the locks being stored in Etcd. Defaults to
// 5 seconds.
func (s EtcdStore) lockTTL() uint64 {
	if s.TTL <= 0 {
		return 5
	}

	return uint64(s.TTL)
}
<commit_msg>Add logger into EtcdStore.<commit_after>package locker

import (
	"github.com/coreos/go-etcd/etcd"
	"github.com/coreos/go-log/log"
)

// EtcdStore is a backing store for Locker which uses Etcd for storage.
type EtcdStore struct {
	// Etcd client used for storing locks.
	Etcd *etcd.Client

	// Directory in Etcd to store locks. Default: locker.
	Directory string

	// TTL is the time-to-live for the lock. Default: 5s.
	TTL int
}

// Get returns the value of a lock. LockNotFound will be returned if a
// lock with the name isn't held.
func (s EtcdStore) Get(name string) (string, error) {
	log.Infof("GET %s", name)
	res, err := s.Etcd.Get(s.lockPath(name), false, false)
	if err == nil {
		return res.Node.Value, nil
	}

	if etcderr, ok := err.(etcd.EtcdError); ok && etcderr.ErrorCode == 100 {
		log.Errorf("GET %s failed: Lock not found", name)
		return "", LockNotFound{name}
	}

	log.Errorf("GET %s failed: %s", name, err)
	return "", err
}

// AcquireOrFreshenLock will aquires a named lock if it isn't already
// held, or updates its TTL if it is.
func (s EtcdStore) AcquireOrFreshenLock(name, value string) error {
	log.Infof("ACQUIRE %s", name)
	if err := s.ensureLockDirectoryCreated(); err != nil {
		log.Errorf("ACQUIRE %s failed ensuring lock directory exists: %s", name, err)
		return err
	}

	key := s.lockPath(name)

	log.Debugf("ACQUIRE %s CompareAndSwap on %s", name, key)
	_, err := s.Etcd.CompareAndSwap(key, value, s.lockTTL(), value, 0)
	if err == nil {
		// success!
		return nil
	}

	log.Debugf("ACQUIRE %s CompareAndSwap on %s failed (%s) trying to recover", name, key, err)
	if etcderr, ok := err.(etcd.EtcdError); ok {
		switch etcderr.ErrorCode {
		case 100:
			log.Debugf("ACQUIRE %s CompareAndSwap on %s key didn't exist, trying to force set it", name, key)
			// key doesn't exist, set it. This seems to be odd behaviour for
			// CompareAndSwap. Surely, if it doesn't exist we should just set
			// it as part of CompareAndSwap. Potential for a race condition here,
			// where another client is able to do a CompareAndSwap and then we
			// stomp on it with our dumb Set.
			if _, err := s.Etcd.Set(key, value, 1); err != nil {
				// wasn't able to force-set the key, no idea what happened
				log.Errorf("ACQUIRE %s Set on %s key failed", name, key, err)
				return err
			}

			// Retry after stomping
			log.Debugf("ACQUIRE %s retrying", name)
			return s.AcquireOrFreshenLock(name, value)
		case 101:
			// couldn't set the key, the prevValue we gave it differs from the
			// one in the server. Someone else has this key.
			log.Errorf("ACQUIRE %s CompareAndSwap on %s key failed, lock denied", name, key)
			return LockDenied{name}
		}
	}

	return err
}

// directory will return the provided Directory or locker if nil.
func (s EtcdStore) directory() string {
	if s.Directory == "" {
		return "locker"
	}

	return s.Directory
}

// ensureLockDirectoryCreated tries to create the root locker directory in
// etcd. This is to compensate for etcd sometimes getting upset when all
// the nodes expire.
func (s EtcdStore) ensureLockDirectoryCreated() error {
	_, err := s.Etcd.CreateDir(s.directory(), 0)

	if eerr, ok := err.(*etcd.EtcdError); ok {
		if eerr.ErrorCode == 105 {
			return nil // key already exists, cool
		}
	}

	// not an etcderr, or a etcderror we want to propagate, or there was no error
	return err
}

// lockPath gets the path to a lock in Etcd. Defaults to /locker/name
func (s EtcdStore) lockPath(name string) string {
	return s.directory() + "/" + name
}

// lockTTL gets the TTL of the locks being stored in Etcd. Defaults to
// 5 seconds.
func (s EtcdStore) lockTTL() uint64 {
	if s.TTL <= 0 {
		return 5
	}

	return uint64(s.TTL)
}
<|endoftext|>


<commit_before>// Package EventBus is the little and lightweight eventbus for GoLang.
package EventBus

import "reflect"

// EventBus - box for handlers and callbacks.
type EventBus struct {
	handlers map[string]reflect.Value
	flagOnce map[string]bool
}

// New returns new EventBus with empty handlers.
func New() *EventBus {
	return &EventBus{
		make(map[string]reflect.Value),
		make(map[string]bool),
	}
}

// Subscribe - subscribe to a channel.
func (bus *EventBus) Subscribe(channel string, fn interface{}) {
	if !(reflect.TypeOf(fn).Kind() == reflect.Func) {
		return;
	}
	v := reflect.ValueOf(fn)
	bus.handlers[channel] = v;
	bus.flagOnce[channel] = false;
}

// SubscribeOnce - subscribe to a channel once. Handler will be removed after executing.
func (bus *EventBus) SubscribeOnce(channel string, fn interface{}) {
	if !(reflect.TypeOf(fn).Kind() == reflect.Func) {
		return;
	}
	v := reflect.ValueOf(fn)
	bus.handlers[channel] = v;
	bus.flagOnce[channel] = true;
}

// Unsubscribe - remove callback defined for a channel.
func (bus *EventBus) Unsubscribe(channel string) {
	if _, ok := bus.handlers[channel]; ok {
		delete(bus.handlers, channel);
	}
}

// Publish - execute callback defined for a channel. Any addional argument will be tranfered to the callback.
func (bus *EventBus) Publish(channel string, args ...interface{}) {
	if handler, ok := bus.handlers[channel]; ok {
		removeAfterExec, _ := bus.flagOnce[channel];
		args_ := make([]reflect.Value, 0);
		for _, arg := range args {
			args_ = append(args_, reflect.ValueOf(arg));
		}
		handler.Call(args_)
		if removeAfterExec {
			delete(bus.handlers, channel);
			bus.flagOnce[channel] = false;
		}
	}
}
<commit_msg>sync.Mutex applied<commit_after>// Package EventBus is the little and lightweight eventbus for GoLang.
package EventBus

import (
	"reflect"
	"sync"
)

// EventBus - box for handlers and callbacks.
type EventBus struct {
	handlers map[string]reflect.Value
	flagOnce map[string]bool
	lock sync.Mutex
}

// New returns new EventBus with empty handlers.
func New() *EventBus {
	return &EventBus{
		make(map[string]reflect.Value),
		make(map[string]bool),
		sync.Mutex{},
	}
}

// Subscribe - subscribe to a channel.
func (bus *EventBus) Subscribe(channel string, fn interface{}) {
	bus.lock.Lock();
	if !(reflect.TypeOf(fn).Kind() == reflect.Func) {
		bus.lock.Unlock();
		return;
	}
	v := reflect.ValueOf(fn)
	bus.handlers[channel] = v;
	bus.flagOnce[channel] = false;
	bus.lock.Unlock();
}

// SubscribeOnce - subscribe to a channel once. Handler will be removed after executing.
func (bus *EventBus) SubscribeOnce(channel string, fn interface{}) {
	bus.lock.Lock();
	if !(reflect.TypeOf(fn).Kind() == reflect.Func) {
		bus.lock.Unlock();
		return;
	}
	v := reflect.ValueOf(fn)
	bus.handlers[channel] = v;
	bus.flagOnce[channel] = true;
	bus.lock.Unlock();
}

// Unsubscribe - remove callback defined for a channel.
func (bus *EventBus) Unsubscribe(channel string) {
	bus.lock.Lock();
	if _, ok := bus.handlers[channel]; ok {
		delete(bus.handlers, channel);
	}
	bus.lock.Unlock();
}

// Publish - execute callback defined for a channel. Any addional argument will be tranfered to the callback.
func (bus *EventBus) Publish(channel string, args ...interface{}) {
	bus.lock.Lock()
	if handler, ok := bus.handlers[channel]; ok {
		removeAfterExec, _ := bus.flagOnce[channel];
		args_ := make([]reflect.Value, 0);
		for _, arg := range args {
			args_ = append(args_, reflect.ValueOf(arg));
		}
		handler.Call(args_)
		if removeAfterExec {
			delete(bus.handlers, channel);
			bus.flagOnce[channel] = false;
		}
	}
	bus.lock.Unlock()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/dimfeld/gocache"
	"os"
	"path"
	"sort"
	"strings"
	"time"
	//"io/ioutil"
	//"html/template"
)

type PageGenerator func(*GlobalData, map[string]string) (PostList, error)

type PageSpec struct {
	globalData *GlobalData
	customPage bool
	generator  PageGenerator
	params     map[string]string
}

type ArchiveSpec time.Time
type ArchiveSpecList []ArchiveSpec

type TemplateData struct {
	// Set Posts to make a list of posts. A custom page should set Page.
	Posts    []*Post
	Page     *Post
	Tags     []string
	Archives ArchiveSpecList
}

func (ps PageSpec) Fill(cacheObj gocache.Cache, path string) (gocache.Object, error) {
	posts, err := ps.generator(ps.globalData, ps.params)
	if err != nil {
		return gocache.Object{}, err
	}

	if len(posts) == 0 {
		// No error, but an empty post list means that no matching file was found.
		return gocache.Object{}, os.ErrNotExist
	}

	// TODO Actually do templating here.
	output := posts[0].Content

	uncompressed, compressed, err := gocache.CompressAndSet(cacheObj, path, output, time.Now())
	if strings.HasSuffix(path, ".gz") {
		return compressed, err
	} else {
		return uncompressed, err
	}
}

func generatePostPage(globalData *GlobalData, params map[string]string) (PostList, error) {
	postPath := path.Join(globalData.postsDir, params["year"], params["month"], params["post"])
	post, err := NewPost(postPath, true)
	if err != nil {
		return nil, err
	}
	postList := PostList{post}

	// Do templating

	return postList, nil
}

func generateArchivePage(globalData *GlobalData, params map[string]string) (PostList, error) {
	archivePath := path.Join(globalData.postsDir, params["year"], params["month"])
	posts, err := LoadPostsFromPath(archivePath, true)
	if err != nil {
		return nil, err
	}
	sort.Sort(posts)

	return posts, nil
}

func generateTagsPage(globalData *GlobalData, params map[string]string) (PostList, error) {
	return nil, nil
}

func generateIndexPage(globalData *GlobalData, params map[string]string) (PostList, error) {
	if globalData.archive == nil {
		archive, err := NewArchiveSpecList(globalData.postsDir)
		if err != nil {
			return nil, err
		}

		globalData.archive = archive
	}

	postList := make(PostList, 0, globalData.indexPosts)

	for _, current := range globalData.archive {
		postPath := PostPath(globalData.postsDir, current.Year(), current.Month())
		monthPosts, err := LoadPostsFromPath(postPath, true)
		if err != nil {
			return nil, err
		}

		postList = append(postList, monthPosts...)

		// We have enough posts.
		if len(postList) >= globalData.indexPosts {
			break
		}
	}

	sort.Sort(sort.Reverse(postList))

	if len(postList) > globalData.indexPosts {
		postList = postList[0:globalData.indexPosts]
	}

	return nil, nil
}

func generateCustomPage(globalData *GlobalData, params map[string]string) (PostList, error) {
	pagePath := path.Join(globalData.postsDir, "page", params["page"])
	post, err := NewPost(pagePath, true)
	if err != nil {
		return nil, err
	}

	return PostList{post}, nil
}

func (l ArchiveSpecList) Less(i, j int) bool {
	// Reverse sort so the most recent is first.
	return time.Time(l[i]).After(time.Time(l[j]))
}

func (l ArchiveSpecList) Len(i, j int) int {
	return len(l)
}

func (l ArchiveSpecList) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

func (a ArchiveSpec) Href() string {
	return fmt.Sprintf("/%04d/%02d", a.Year(), a.Month())
}

func (a ArchiveSpec) Text() string {
	return time.Time(a).Format("Jan 2006")
}

func (a ArchiveSpec) Month() time.Month {
	return time.Time(a).Month()
}

func (a ArchiveSpec) Year() int {
	return time.Time(a).Year()
}
<commit_msg>More templating code. Other minor changes<commit_after>package main

import (
	"fmt"
	"github.com/dimfeld/gocache"
	"os"
	"path"
	"sort"
	"strings"
	"time"
	//"io/ioutil"
	//"html/template"
)

type PageGenerator func(*GlobalData, map[string]string) (PostList, error)

type PageSpec struct {
	globalData *GlobalData
	customPage bool
	generator  PageGenerator
	params     map[string]string
}

type ArchiveSpec time.Time
type ArchiveSpecList []ArchiveSpec

type TemplateData struct {
	// Set Posts to make a list of posts. A custom page should set Page.
	Posts    []*Post
	Page     *Post
	Tags     TagPopularity
	Archives ArchiveSpecList
}

func (ps PageSpec) Fill(cacheObj gocache.Cache, path string) (gocache.Object, error) {
	posts, err := ps.generator(ps.globalData, ps.params)
	if err != nil {
		return gocache.Object{}, err
	}

	if len(posts) == 0 {
		// No error, but an empty post list means that no matching file was found.
		return gocache.Object{}, os.ErrNotExist
	}

	templateData := TemplateData{}
	if ps.customPage {
		templateData.Page = posts[0]
	} else {
		templateData.Posts = posts
	}
	templateData.Archives = ps.globalData.archive
	tags := NewTags(ps.globalData.tagsPath, ps.globalData.postsDir)
	templateData.Tags = tags.TagsByPopularity()
	output := posts[0].Content

	uncompressed, compressed, err := gocache.CompressAndSet(cacheObj, path, output, time.Now())
	if strings.HasSuffix(path, ".gz") {
		return compressed, err
	} else {
		return uncompressed, err
	}
}

func generatePostPage(globalData *GlobalData, params map[string]string) (PostList, error) {
	postPath := path.Join(globalData.postsDir, params["year"], params["month"], params["post"])
	post, err := NewPost(postPath, true)
	if err != nil {
		return nil, err
	}
	postList := PostList{post}

	return postList, nil
}

func generateArchivePage(globalData *GlobalData, params map[string]string) (PostList, error) {
	archivePath := path.Join(globalData.postsDir, params["year"], params["month"])
	posts, err := LoadPostsFromPath(archivePath, true)
	if err != nil {
		return nil, err
	}
	sort.Sort(posts)

	return posts, nil
}

func generateTagsPage(globalData *GlobalData, params map[string]string) (PostList, error) {
	return nil, nil
}

func generateIndexPage(globalData *GlobalData, params map[string]string) (PostList, error) {
	if globalData.archive == nil {
		archive, err := NewArchiveSpecList(globalData.postsDir)
		if err != nil {
			return nil, err
		}

		globalData.archive = archive
	}

	postList := make(PostList, 0, globalData.indexPosts)

	for _, current := range globalData.archive {
		postPath := PostPath(globalData.postsDir, current.Year(), current.Month())
		monthPosts, err := LoadPostsFromPath(postPath, true)
		if err != nil {
			return nil, err
		}

		postList = append(postList, monthPosts...)

		// We have enough posts.
		if len(postList) >= globalData.indexPosts {
			break
		}
	}

	// Sort posts, starting with the most recent.
	sort.Sort(sort.Reverse(postList))

	if len(postList) > globalData.indexPosts {
		postList = postList[0:globalData.indexPosts]
	}

	return nil, nil
}

func generateCustomPage(globalData *GlobalData, params map[string]string) (PostList, error) {
	pagePath := path.Join(globalData.postsDir, "page", params["page"])
	post, err := NewPost(pagePath, true)
	if err != nil {
		return nil, err
	}

	return PostList{post}, nil
}

func (l ArchiveSpecList) Less(i, j int) bool {
	// Reverse sort so the most recent is first.
	return time.Time(l[i]).After(time.Time(l[j]))
}

func (l ArchiveSpecList) Len() int {
	return len(l)
}

func (l ArchiveSpecList) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

func (a ArchiveSpec) Href() string {
	return fmt.Sprintf("/%04d/%02d", a.Year(), a.Month())
}

func (a ArchiveSpec) String() string {
	return time.Time(a).Format("Jan 2006")
}

func (a ArchiveSpec) Month() time.Month {
	return time.Time(a).Month()
}

func (a ArchiveSpec) Year() int {
	return time.Time(a).Year()
}
<|endoftext|>


<commit_before>package mysql

import (
	"fmt"
	"github.com/jinzhu/gorm"
	"github.com/tolexo/aero/conf"
	"math/rand"
	"net/url"
)

var engines map[string]gorm.DB
var ormInit []func(*gorm.DB)
var connMySqlWrite string
var connMySqlRead []string

func initMaster() {
	lookup := "database.master"
	if conf.Exists(lookup) {
		connMySqlWrite = getMySqlConnString(lookup)
	}
}
func initSlaves() {
	lookup := "database.slaves"
	if conf.Exists(lookup) {
		slaves := conf.StringSlice(lookup, []string{})
		connMySqlRead = make([]string, len(slaves))
		for i, container := range slaves {
			connMySqlRead[i] = getMySqlConnString(container)
		}
	}
}
func getMySqlConnString(container string) string {
	if !conf.Exists(container) {
		panic("Container for mysql configuration not found")
	}

	username := conf.String(container+".username", "")
	password := conf.String(container+".password", "")
	host := conf.String(container+".host", "")
	port := conf.String(container+".port", "")
	db := conf.String(container+".db", "")
	timezone := conf.String(container+".timezone", "")

	return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true&loc=%s",
		username, password,
		host, port, db,
		url.QueryEscape(timezone),
	)
}

func getOrm(connStr string) (ormObj gorm.DB, err error) {
	var ok bool

	if ormObj, ok = engines[connStr]; ok {
		return
	}
	// http://go-database-sql.org/accessing.html
	// the sql.DB object is designed to be long-lived
	if ormObj, err = gorm.Open("mysql", connStr); err == nil {
		if ormInit != nil {
			for _, fn := range ormInit {
				fn(&ormObj)
			}
		}
		engines[connStr] = ormObj
		return

	} else {
		return
	}
}

func DoOrmInit(fn func(*gorm.DB)) {
	// TODO: use mutex
	if ormInit == nil {
		ormInit = make([]func(*gorm.DB), 0)
	}
	ormInit = append(ormInit, fn)
}

func getDefaultConn(write bool) string {
	if write {
		initMaster()
		return connMySqlWrite
	} else {
		initSlaves()
		if connMySqlRead == nil || len(connMySqlRead) == 0 {
			initMaster()
			return connMySqlWrite
		}
		return connMySqlRead[rand.Intn(len(connMySqlRead))]
	}
}

//Get MySql connection
func GetMySqlConn(writable bool) (gorm.DB, error) {
	engines = make(map[string]gorm.DB)
	connStr := getDefaultConn(writable)
	return getOrm(connStr)
}
<commit_msg>CLA-137A mysql DoOrmInit function removed<commit_after>package mysql

import (
	"fmt"
	"github.com/jinzhu/gorm"
	"github.com/tolexo/aero/conf"
	"math/rand"
	"net/url"
)

var connMySqlWrite string
var connMySqlRead []string

func initMaster() {
	lookup := "database.master"
	if conf.Exists(lookup) {
		connMySqlWrite = getMySqlConnString(lookup)
	}
}
func initSlaves() {
	lookup := "database.slaves"
	if conf.Exists(lookup) {
		slaves := conf.StringSlice(lookup, []string{})
		connMySqlRead = make([]string, len(slaves))
		for i, container := range slaves {
			connMySqlRead[i] = getMySqlConnString(container)
		}
	}
}
func getMySqlConnString(container string) string {
	if !conf.Exists(container) {
		panic("Container for mysql configuration not found")
	}

	username := conf.String(container+".username", "")
	password := conf.String(container+".password", "")
	host := conf.String(container+".host", "")
	port := conf.String(container+".port", "")
	db := conf.String(container+".db", "")
	timezone := conf.String(container+".timezone", "")

	return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true&loc=%s",
		username, password,
		host, port, db,
		url.QueryEscape(timezone),
	)
}

func getDefaultConn(write bool) string {
	if write {
		initMaster()
		return connMySqlWrite
	} else {
		initSlaves()
		if connMySqlRead == nil || len(connMySqlRead) == 0 {
			initMaster()
			return connMySqlWrite
		}
		return connMySqlRead[rand.Intn(len(connMySqlRead))]
	}
}

//Get MySql connection
func GetMySqlConn(writable bool) (dbConn gorm.DB, err error) {
	connStr := getDefaultConn(writable)
	if dbConn, err = gorm.Open("mysql", connStr); err != nil {
		return
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2014 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 parser parses Go code and keeps track of all the types defined
// and provides access to all the constants defined for an int type.
package parser

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"log"
	"path/filepath"
	"strings"

	"go/constant"
	_ "go/importer"
	"go/types"
)

// A Package contains all the information related to a parsed package.
type Package struct {
	Name  string
	files []*ast.File

	defs map[*ast.Ident]types.Object
}

// ParsePackage parses the package in the given directory and returns it.
func ParsePackage(directory, skipPrefix, skipSuffix string) (*Package, error) {
	pkgDir, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		return nil, fmt.Errorf("cannot process directory %s: %s", directory, err)
	}

	var files []*ast.File
	fs := token.NewFileSet()
	for _, name := range pkgDir.GoFiles {
		if !strings.HasSuffix(name, ".go") ||
			(skipSuffix != "" && strings.HasPrefix(name, skipPrefix) &&
				strings.HasSuffix(name, skipSuffix)) {
			continue
		}
		if directory != "." {
			name = filepath.Join(directory, name)
		}
		f, err := parser.ParseFile(fs, name, nil, 0)
		if err != nil {
			return nil, fmt.Errorf("parsing file %v: %v", name, err)
		}
		files = append(files, f)
	}
	if len(files) == 0 {
		return nil, fmt.Errorf("%s: no buildable Go files", directory)
	}

	// type-check the package
	defs := make(map[*ast.Ident]types.Object)
	config := types.Config{FakeImportC: true, Importer: importer.Default()}
	info := &types.Info{Defs: defs}
	if _, err := config.Check(directory, fs, files, info); err != nil {
		return nil, fmt.Errorf("type-checking package: %v", err)
	}

	return &Package{
		Name:  files[0].Name.Name,
		files: files,
		defs:  defs,
	}, nil
}

// generate produces the String method for the named type.
func (pkg *Package) ValuesOfType(typeName string) ([]string, error) {
	var values, inspectErrs []string
	for _, file := range pkg.files {
		ast.Inspect(file, func(node ast.Node) bool {
			decl, ok := node.(*ast.GenDecl)
			if !ok || decl.Tok != token.CONST {
				// We only care about const declarations.
				return true
			}

			if vs, err := pkg.valuesOfTypeIn(typeName, decl); err != nil {
				inspectErrs = append(inspectErrs, err.Error())
			} else {
				values = append(values, vs...)
			}
			return false
		})
	}
	if len(inspectErrs) > 0 {
		return nil, fmt.Errorf("inspecting code:\n\t%v", strings.Join(inspectErrs, "\n\t"))
	}
	if len(values) == 0 {
		return nil, fmt.Errorf("no values defined for type %s", typeName)
	}
	return values, nil
}

func (pkg *Package) valuesOfTypeIn(typeName string, decl *ast.GenDecl) ([]string, error) {
	var values []string

	// The name of the type of the constants we are declaring.
	// Can change if this is a multi-element declaration.
	typ := ""
	// Loop over the elements of the declaration. Each element is a ValueSpec:
	// a list of names possibly followed by a type, possibly followed by values.
	// If the type and value are both missing, we carry down the type (and value,
	// but the "go/types" package takes care of that).
	for _, spec := range decl.Specs {
		vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST.
		if vspec.Type == nil && len(vspec.Values) > 0 {
			// "X = 1". With no type but a value, the constant is untyped.
			// Skip this vspec and reset the remembered type.
			typ = ""
			continue
		}
		if vspec.Type != nil {
			// "X T". We have a type. Remember it.
			ident, ok := vspec.Type.(*ast.Ident)
			if !ok {
				continue
			}
			typ = ident.Name
		}
		if typ != typeName {
			// This is not the type we're looking for.
			continue
		}

		// We now have a list of names (from one line of source code) all being
		// declared with the desired type.
		// Grab their names and actual values and store them in f.values.
		for _, name := range vspec.Names {
			if name.Name == "_" {
				continue
			}
			// This dance lets the type checker find the values for us. It's a
			// bit tricky: look up the object declared by the name, find its
			// types.Const, and extract its value.
			obj, ok := pkg.defs[name]
			if !ok {
				return nil, fmt.Errorf("no value for constant %s", name)
			}
			info := obj.Type().Underlying().(*types.Basic).Info()
			if info&types.IsInteger == 0 {
				return nil, fmt.Errorf("can't handle non-integer constant type %s", typ)
			}
			value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST.
			if value.Kind() != constant.Int {
				log.Fatalf("can't happen: constant is not an integer %s", name)
			}
			values = append(values, name.Name)
		}
	}
	return values, nil
}
<commit_msg>Need to pass an explicit importer<commit_after>// Copyright 2014 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 parser parses Go code and keeps track of all the types defined
// and provides access to all the constants defined for an int type.
package parser

import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"log"
	"path/filepath"
	"strings"

	"go/constant"
	"go/importer"
	"go/types"
)

// A Package contains all the information related to a parsed package.
type Package struct {
	Name  string
	files []*ast.File

	defs map[*ast.Ident]types.Object
}

// ParsePackage parses the package in the given directory and returns it.
func ParsePackage(directory, skipPrefix, skipSuffix string) (*Package, error) {
	pkgDir, err := build.Default.ImportDir(directory, 0)
	if err != nil {
		return nil, fmt.Errorf("cannot process directory %s: %s", directory, err)
	}

	var files []*ast.File
	fs := token.NewFileSet()
	for _, name := range pkgDir.GoFiles {
		if !strings.HasSuffix(name, ".go") ||
			(skipSuffix != "" && strings.HasPrefix(name, skipPrefix) &&
				strings.HasSuffix(name, skipSuffix)) {
			continue
		}
		if directory != "." {
			name = filepath.Join(directory, name)
		}
		f, err := parser.ParseFile(fs, name, nil, 0)
		if err != nil {
			return nil, fmt.Errorf("parsing file %v: %v", name, err)
		}
		files = append(files, f)
	}
	if len(files) == 0 {
		return nil, fmt.Errorf("%s: no buildable Go files", directory)
	}

	// type-check the package
	defs := make(map[*ast.Ident]types.Object)
	config := types.Config{FakeImportC: true, Importer: importer.Default()}
	info := &types.Info{Defs: defs}
	if _, err := config.Check(directory, fs, files, info); err != nil {
		return nil, fmt.Errorf("type-checking package: %v", err)
	}

	return &Package{
		Name:  files[0].Name.Name,
		files: files,
		defs:  defs,
	}, nil
}

// generate produces the String method for the named type.
func (pkg *Package) ValuesOfType(typeName string) ([]string, error) {
	var values, inspectErrs []string
	for _, file := range pkg.files {
		ast.Inspect(file, func(node ast.Node) bool {
			decl, ok := node.(*ast.GenDecl)
			if !ok || decl.Tok != token.CONST {
				// We only care about const declarations.
				return true
			}

			if vs, err := pkg.valuesOfTypeIn(typeName, decl); err != nil {
				inspectErrs = append(inspectErrs, err.Error())
			} else {
				values = append(values, vs...)
			}
			return false
		})
	}
	if len(inspectErrs) > 0 {
		return nil, fmt.Errorf("inspecting code:\n\t%v", strings.Join(inspectErrs, "\n\t"))
	}
	if len(values) == 0 {
		return nil, fmt.Errorf("no values defined for type %s", typeName)
	}
	return values, nil
}

func (pkg *Package) valuesOfTypeIn(typeName string, decl *ast.GenDecl) ([]string, error) {
	var values []string

	// The name of the type of the constants we are declaring.
	// Can change if this is a multi-element declaration.
	typ := ""
	// Loop over the elements of the declaration. Each element is a ValueSpec:
	// a list of names possibly followed by a type, possibly followed by values.
	// If the type and value are both missing, we carry down the type (and value,
	// but the "go/types" package takes care of that).
	for _, spec := range decl.Specs {
		vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST.
		if vspec.Type == nil && len(vspec.Values) > 0 {
			// "X = 1". With no type but a value, the constant is untyped.
			// Skip this vspec and reset the remembered type.
			typ = ""
			continue
		}
		if vspec.Type != nil {
			// "X T". We have a type. Remember it.
			ident, ok := vspec.Type.(*ast.Ident)
			if !ok {
				continue
			}
			typ = ident.Name
		}
		if typ != typeName {
			// This is not the type we're looking for.
			continue
		}

		// We now have a list of names (from one line of source code) all being
		// declared with the desired type.
		// Grab their names and actual values and store them in f.values.
		for _, name := range vspec.Names {
			if name.Name == "_" {
				continue
			}
			// This dance lets the type checker find the values for us. It's a
			// bit tricky: look up the object declared by the name, find its
			// types.Const, and extract its value.
			obj, ok := pkg.defs[name]
			if !ok {
				return nil, fmt.Errorf("no value for constant %s", name)
			}
			info := obj.Type().Underlying().(*types.Basic).Info()
			if info&types.IsInteger == 0 {
				return nil, fmt.Errorf("can't handle non-integer constant type %s", typ)
			}
			value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST.
			if value.Kind() != constant.Int {
				log.Fatalf("can't happen: constant is not an integer %s", name)
			}
			values = append(values, name.Name)
		}
	}
	return values, nil
}
<|endoftext|>


<commit_before>package parser

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"math"
)

const maxPacketSize = 1<<24 - 1

// ReuseBufferMaxSize represent maximum size of buffer to reuse.  When size of
// buffer is bigger than this, buffer will be destory and create agein to free
// a big bunch of memory.
var ReuseBufferMaxSize = 8 * 1024 * 1024

type dir int

const (
	fromServer dir = iota
	fromClient
)

func (v dir) String() string {
	switch v {
	case fromServer:
		return "server"
	case fromClient:
		return "client"
	default:
		return "(dir:unknown)"
	}
}

type Parser struct {
	currR io.Reader
	raw   *CountReader

	dir dir
	ctx *Context

	decompressing bool

	header [4]byte
	pktLen int
	body   *bytes.Buffer

	PktLens []int
	SeqNums []uint8
	Body    []byte

	Detail interface{}
}

// NewFromServer creates a parser to parse packet from server.
func NewFromServer(r io.Reader) *Parser {
	cr := &CountReader{R: bufio.NewReader(r)}
	return &Parser{
		currR: cr,
		raw:   cr,
		dir:   fromServer,
		ctx:   newContext(),
	}
}

// NewFromServer creates a parser to parse packet from client.
func NewFromClient(r io.Reader) *Parser {
	cr := &CountReader{R: bufio.NewReader(r)}
	return &Parser{
		currR: cr,
		raw:   cr,
		dir:   fromClient,
		ctx:   newContext(),
	}
}

func (pa *Parser) resetBuffer() {
	if pa.body == nil {
		pa.body = new(bytes.Buffer)
		return
	}
	if ReuseBufferMaxSize > 0 && pa.body.Cap() > ReuseBufferMaxSize {
		pa.body = new(bytes.Buffer)
		return
	}
	pa.body.Reset()
}

func (pa *Parser) initParse() {
	pa.resetBuffer()
	if pa.PktLens == nil {
		pa.PktLens = make([]int, 0, 10)
	}
	pa.PktLens = pa.PktLens[:0]
	if pa.SeqNums == nil {
		pa.SeqNums = make([]uint8, 0, 10)
	}
	pa.SeqNums = pa.SeqNums[:0]
	pa.Body = nil

	if pa.shouldStartDecompress() {
		pa.switchDecompress(pa.raw)
	}

	// reset read bytes count.
	pa.raw.N = 0
}

func (pa *Parser) shouldStartDecompress() bool {
	return !pa.decompressing && pa.ctx.Compressing
}

func (pa *Parser) switchDecompress(r io.Reader) {
	pa.currR = newDecompressor(r)
	pa.decompressing = true
}

func (pa *Parser) toReader(b []byte) io.Reader {
	b2 := make([]byte, len(b))
	copy(b2, b)
	return bytes.NewBuffer(b)
}

func (pa *Parser) Parse() error {
	pa.initParse()
	for {
		err := readN(pa.currR, pa.header[:])
		if err != nil {
			return err
		}
		// re-parse stream with decompressing.
		if pa.shouldStartDecompress() {
			pa.switchDecompress(io.MultiReader(pa.toReader(pa.header[:]), pa.raw))
			continue
		}
		pa.pktLen = packetLen(pa.header[:])
		pa.PktLens = append(pa.PktLens, pa.pktLen)
		pa.SeqNums = append(pa.SeqNums, pa.header[3])
		if pa.pktLen == 0 {
			break
		}
		_, err = io.CopyN(pa.body, pa.currR, int64(pa.pktLen))
		if err != nil {
			return err
		}
		if pa.pktLen != maxPacketSize {
			break
		}
	}
	pa.Body = pa.body.Bytes()
	pa.Detail = nil
	switch pa.dir {
	case fromServer:
		return pa.parseServerPacket()
	case fromClient:
		return pa.parseClientPacket()
	default:
		return fmt.Errorf("unknown direction: %s", pa.dir)
	}
}

func (pa *Parser) parseServerPacket() error {
	if len(pa.Body) < 1 {
		return errors.New("less body as packet from server")
	}
	if pa.ctx.State == None {
		pkt, err := NewServerHandshakePacket(pa.Body)
		if err != nil {
			return err
		}
		pa.ctx.State = Handshake
		pa.Detail = pkt
		return nil
	}
	switch pa.Body[0] {
	case 0x00:
		if pa.ctx.State == Auth {
			// logged in successfully.
			pkt, err := NewOKPacket(pa.Body)
			if err != nil {
				return err
			}
			pa.Detail = pkt
			pa.ctx.State = Connected
			pa.ctx.Compressing = pa.ctx.WillCompress
			break
		}
		switch pa.ctx.LastCommand {

		case Prepare:
			pkt, err := NewPrepareResultPacket(pa.Body)
			if err != nil {
				return err
			}
			pa.Detail = pkt
			if pkt.ParameterCount > 0 {
				if pkt.FieldCount > 0 {
					pa.ctx.ResultState = PrepareParamsAndColumns
				} else {
					pa.ctx.ResultState = PrepareParams
				}
			} else {
				if pkt.FieldCount > 0 {
					pa.ctx.ResultState = PrepareColumns
				} else {
					pa.ctx.ResultState = 0
				}
			}
			pa.ctx.addStmt(Stmt{
				ID:         pkt.StatementID,
				NumParams:  pkt.ParameterCount,
				NumColumns: pkt.FieldCount,
			})
			return nil

		case Query, Execute, Reset:
			err := pa.parseServerResultPacket()
			if err != nil {
				return err
			}
			return nil

		default:
			// TODO: parse other server commands
			pa.Detail = nil
			return nil
		}

	case 0xfe:
		pkt, err := NewEOFPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.Detail = pkt
		switch pa.ctx.ResultState {
		case PrepareParamsAndColumns:
			pa.ctx.ResultState = PrepareColumns
			return nil
		case PrepareParams, PrepareColumns:
			pa.ctx.ResultState = 0
			return nil
		}
		if !pa.ctx.IsClientDeprecateEOF() && pa.ctx.ResultState == Fields {
			pa.ctx.ResultState = Records
			return nil
		}
		pa.ctx.ResultState = 0

	case 0xff:
		pkt, err := NewErrorPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.Detail = pkt
	default:
		// FIXME: any specific procedure?
		err := pa.parseServerResultPacket()
		if err != nil {
			return err
		}
		return nil
	}
	return nil
}

func (pa *Parser) parseServerResultPacket() error {
	switch pa.ctx.ResultState {
	case 0:
		buf := &decbuf{buf: pa.Body}
		p, err := buf.ReadUintV()
		if err != nil {
			return err
		}
		if p == nil {
			return nil
		}
		n := *p
		if n == 0 {
			pkt, err := NewResultNonePacket(buf.buf)
			if err != nil {
				return err
			}
			pa.Detail = pkt
			pa.ctx.ResultState = 0
			return nil
		}
		pa.Detail = &ResultFieldNumPacket{Num: uint64(n)}
		pa.ctx.ResultState = Fields
		pa.ctx.FieldNCurr = 0
		pa.ctx.FieldNMax = uint64(n)
		return nil

	case Fields, PrepareParamsAndColumns, PrepareParams, PrepareColumns:
		pkt, err := NewResultFieldPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.Detail = pkt
		pa.ctx.FieldNCurr++
		if pa.ctx.IsClientDeprecateEOF() && pa.ctx.FieldNCurr >= pa.ctx.FieldNMax {
			pa.ctx.ResultState = Records
		}
		return nil

	case Records:
		var nfields int
		if pa.ctx.FieldNMax <= math.MaxInt32 {
			nfields = int(pa.ctx.FieldNMax)
		} else {
			nfields = math.MaxInt32
		}
		pkt, err := NewResultRecordPacket(pa.Body, nfields)
		if err != nil {
			return err
		}
		pa.Detail = pkt
		return nil

	default:
		return fmt.Errorf("unexpected query result mode: %d",
			pa.ctx.ResultState)
	}
}

func (pa *Parser) parseClientPacket() error {
	switch pa.ctx.State {
	case Handshake:
		pkt, err := NewClientHandshakePacket(pa.Body)
		if err != nil {
			return err
		}
		pa.ctx.ClientFlags = pkt.ClientFlags
		pa.ctx.WillCompress = pa.ctx.ClientFlags&ClientCompress != 0
		pa.ctx.State = Auth
		pa.Detail = pkt
	case AuthResend:
		pkt, err := NewClientAuthResendPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.ctx.State = Auth
		pa.Detail = pkt
	case AwaitingReply:
		pkt, err := NewAwaitingReplyPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.Detail = pkt
	default:
		pkt, err := NewCOMPacket(pa.Body, pa.ctx)
		if err != nil {
			return err
		}
		pa.Detail = pkt
		if c, ok := pkt.(Command); ok {
			pa.ctx.LastCommand = c.CommandType()
		} else {
			pa.ctx.LastCommand = -1
		}
	}
	return nil
}

func (pa *Parser) ShareContext(other *Parser) {
	if pa == other {
		return
	}
	pa.ctx = other.ctx
}

func (pa *Parser) Context() Context {
	return *pa.ctx
}

func (pa *Parser) String() string {
	if pa.Detail == nil {
		var fb byte
		if len(pa.Body) > 0 {
			fb = pa.Body[0]
		}
		return fmt.Sprintf("PktLens=%+v SeqNums=%+v First=%02x",
			pa.PktLens, pa.SeqNums, fb)
	}
	return fmt.Sprintf("Detail=%#v PktLens=%+v SeqNums=%+v",
		pa.Detail, pa.PktLens, pa.SeqNums)
}

func (pa *Parser) ContextData() interface{} {
	return pa.ctx.Data
}

func (pa *Parser) SetContextData(d interface{}) {
	pa.ctx.Data = d
}

func (pa *Parser) PacketRawLen() uint64 {
	return pa.raw.N
}
<commit_msg>reduce maximum reuse<commit_after>package parser

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"math"
)

const maxPacketSize = 1<<24 - 1

// ReuseBufferMaxSize represent maximum size of buffer to reuse.  When size of
// buffer is bigger than this, buffer will be destory and create agein to free
// a big bunch of memory.
var ReuseBufferMaxSize = 1024 * 1024

type dir int

const (
	fromServer dir = iota
	fromClient
)

func (v dir) String() string {
	switch v {
	case fromServer:
		return "server"
	case fromClient:
		return "client"
	default:
		return "(dir:unknown)"
	}
}

type Parser struct {
	currR io.Reader
	raw   *CountReader

	dir dir
	ctx *Context

	decompressing bool

	header [4]byte
	pktLen int
	body   *bytes.Buffer

	PktLens []int
	SeqNums []uint8
	Body    []byte

	Detail interface{}
}

// NewFromServer creates a parser to parse packet from server.
func NewFromServer(r io.Reader) *Parser {
	cr := &CountReader{R: bufio.NewReader(r)}
	return &Parser{
		currR: cr,
		raw:   cr,
		dir:   fromServer,
		ctx:   newContext(),
	}
}

// NewFromServer creates a parser to parse packet from client.
func NewFromClient(r io.Reader) *Parser {
	cr := &CountReader{R: bufio.NewReader(r)}
	return &Parser{
		currR: cr,
		raw:   cr,
		dir:   fromClient,
		ctx:   newContext(),
	}
}

func (pa *Parser) resetBuffer() {
	if pa.body == nil {
		pa.body = new(bytes.Buffer)
		return
	}
	if ReuseBufferMaxSize > 0 && pa.body.Cap() > ReuseBufferMaxSize {
		pa.body = new(bytes.Buffer)
		return
	}
	pa.body.Reset()
}

func (pa *Parser) initParse() {
	pa.resetBuffer()
	if pa.PktLens == nil {
		pa.PktLens = make([]int, 0, 10)
	}
	pa.PktLens = pa.PktLens[:0]
	if pa.SeqNums == nil {
		pa.SeqNums = make([]uint8, 0, 10)
	}
	pa.SeqNums = pa.SeqNums[:0]
	pa.Body = nil

	if pa.shouldStartDecompress() {
		pa.switchDecompress(pa.raw)
	}

	// reset read bytes count.
	pa.raw.N = 0
}

func (pa *Parser) shouldStartDecompress() bool {
	return !pa.decompressing && pa.ctx.Compressing
}

func (pa *Parser) switchDecompress(r io.Reader) {
	pa.currR = newDecompressor(r)
	pa.decompressing = true
}

func (pa *Parser) toReader(b []byte) io.Reader {
	b2 := make([]byte, len(b))
	copy(b2, b)
	return bytes.NewBuffer(b)
}

func (pa *Parser) Parse() error {
	pa.initParse()
	for {
		err := readN(pa.currR, pa.header[:])
		if err != nil {
			return err
		}
		// re-parse stream with decompressing.
		if pa.shouldStartDecompress() {
			pa.switchDecompress(io.MultiReader(pa.toReader(pa.header[:]), pa.raw))
			continue
		}
		pa.pktLen = packetLen(pa.header[:])
		pa.PktLens = append(pa.PktLens, pa.pktLen)
		pa.SeqNums = append(pa.SeqNums, pa.header[3])
		if pa.pktLen == 0 {
			break
		}
		_, err = io.CopyN(pa.body, pa.currR, int64(pa.pktLen))
		if err != nil {
			return err
		}
		if pa.pktLen != maxPacketSize {
			break
		}
	}
	pa.Body = pa.body.Bytes()
	pa.Detail = nil
	switch pa.dir {
	case fromServer:
		return pa.parseServerPacket()
	case fromClient:
		return pa.parseClientPacket()
	default:
		return fmt.Errorf("unknown direction: %s", pa.dir)
	}
}

func (pa *Parser) parseServerPacket() error {
	if len(pa.Body) < 1 {
		return errors.New("less body as packet from server")
	}
	if pa.ctx.State == None {
		pkt, err := NewServerHandshakePacket(pa.Body)
		if err != nil {
			return err
		}
		pa.ctx.State = Handshake
		pa.Detail = pkt
		return nil
	}
	switch pa.Body[0] {
	case 0x00:
		if pa.ctx.State == Auth {
			// logged in successfully.
			pkt, err := NewOKPacket(pa.Body)
			if err != nil {
				return err
			}
			pa.Detail = pkt
			pa.ctx.State = Connected
			pa.ctx.Compressing = pa.ctx.WillCompress
			break
		}
		switch pa.ctx.LastCommand {

		case Prepare:
			pkt, err := NewPrepareResultPacket(pa.Body)
			if err != nil {
				return err
			}
			pa.Detail = pkt
			if pkt.ParameterCount > 0 {
				if pkt.FieldCount > 0 {
					pa.ctx.ResultState = PrepareParamsAndColumns
				} else {
					pa.ctx.ResultState = PrepareParams
				}
			} else {
				if pkt.FieldCount > 0 {
					pa.ctx.ResultState = PrepareColumns
				} else {
					pa.ctx.ResultState = 0
				}
			}
			pa.ctx.addStmt(Stmt{
				ID:         pkt.StatementID,
				NumParams:  pkt.ParameterCount,
				NumColumns: pkt.FieldCount,
			})
			return nil

		case Query, Execute, Reset:
			err := pa.parseServerResultPacket()
			if err != nil {
				return err
			}
			return nil

		default:
			// TODO: parse other server commands
			pa.Detail = nil
			return nil
		}

	case 0xfe:
		pkt, err := NewEOFPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.Detail = pkt
		switch pa.ctx.ResultState {
		case PrepareParamsAndColumns:
			pa.ctx.ResultState = PrepareColumns
			return nil
		case PrepareParams, PrepareColumns:
			pa.ctx.ResultState = 0
			return nil
		}
		if !pa.ctx.IsClientDeprecateEOF() && pa.ctx.ResultState == Fields {
			pa.ctx.ResultState = Records
			return nil
		}
		pa.ctx.ResultState = 0

	case 0xff:
		pkt, err := NewErrorPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.Detail = pkt
	default:
		// FIXME: any specific procedure?
		err := pa.parseServerResultPacket()
		if err != nil {
			return err
		}
		return nil
	}
	return nil
}

func (pa *Parser) parseServerResultPacket() error {
	switch pa.ctx.ResultState {
	case 0:
		buf := &decbuf{buf: pa.Body}
		p, err := buf.ReadUintV()
		if err != nil {
			return err
		}
		if p == nil {
			return nil
		}
		n := *p
		if n == 0 {
			pkt, err := NewResultNonePacket(buf.buf)
			if err != nil {
				return err
			}
			pa.Detail = pkt
			pa.ctx.ResultState = 0
			return nil
		}
		pa.Detail = &ResultFieldNumPacket{Num: uint64(n)}
		pa.ctx.ResultState = Fields
		pa.ctx.FieldNCurr = 0
		pa.ctx.FieldNMax = uint64(n)
		return nil

	case Fields, PrepareParamsAndColumns, PrepareParams, PrepareColumns:
		pkt, err := NewResultFieldPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.Detail = pkt
		pa.ctx.FieldNCurr++
		if pa.ctx.IsClientDeprecateEOF() && pa.ctx.FieldNCurr >= pa.ctx.FieldNMax {
			pa.ctx.ResultState = Records
		}
		return nil

	case Records:
		var nfields int
		if pa.ctx.FieldNMax <= math.MaxInt32 {
			nfields = int(pa.ctx.FieldNMax)
		} else {
			nfields = math.MaxInt32
		}
		pkt, err := NewResultRecordPacket(pa.Body, nfields)
		if err != nil {
			return err
		}
		pa.Detail = pkt
		return nil

	default:
		return fmt.Errorf("unexpected query result mode: %d",
			pa.ctx.ResultState)
	}
}

func (pa *Parser) parseClientPacket() error {
	switch pa.ctx.State {
	case Handshake:
		pkt, err := NewClientHandshakePacket(pa.Body)
		if err != nil {
			return err
		}
		pa.ctx.ClientFlags = pkt.ClientFlags
		pa.ctx.WillCompress = pa.ctx.ClientFlags&ClientCompress != 0
		pa.ctx.State = Auth
		pa.Detail = pkt
	case AuthResend:
		pkt, err := NewClientAuthResendPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.ctx.State = Auth
		pa.Detail = pkt
	case AwaitingReply:
		pkt, err := NewAwaitingReplyPacket(pa.Body)
		if err != nil {
			return err
		}
		pa.Detail = pkt
	default:
		pkt, err := NewCOMPacket(pa.Body, pa.ctx)
		if err != nil {
			return err
		}
		pa.Detail = pkt
		if c, ok := pkt.(Command); ok {
			pa.ctx.LastCommand = c.CommandType()
		} else {
			pa.ctx.LastCommand = -1
		}
	}
	return nil
}

func (pa *Parser) ShareContext(other *Parser) {
	if pa == other {
		return
	}
	pa.ctx = other.ctx
}

func (pa *Parser) Context() Context {
	return *pa.ctx
}

func (pa *Parser) String() string {
	if pa.Detail == nil {
		var fb byte
		if len(pa.Body) > 0 {
			fb = pa.Body[0]
		}
		return fmt.Sprintf("PktLens=%+v SeqNums=%+v First=%02x",
			pa.PktLens, pa.SeqNums, fb)
	}
	return fmt.Sprintf("Detail=%#v PktLens=%+v SeqNums=%+v",
		pa.Detail, pa.PktLens, pa.SeqNums)
}

func (pa *Parser) ContextData() interface{} {
	return pa.ctx.Data
}

func (pa *Parser) SetContextData(d interface{}) {
	pa.ctx.Data = d
}

func (pa *Parser) PacketRawLen() uint64 {
	return pa.raw.N
}
<|endoftext|>


<commit_before>package pop

import (
	"fmt"

	. "github.com/markbates/pop/columns"
	"github.com/markbates/validate"
	uuid "github.com/satori/go.uuid"
)

func (c *Connection) Reload(model interface{}) error {
	sm := Model{Value: model}
	return c.Find(model, sm.ID())
}

func (q *Query) Exec() error {
	return q.Connection.timeFunc("Exec", func() error {
		sql, args := q.ToSQL(nil)
		Log(sql, args...)
		_, err := q.Connection.Store.Exec(sql, args...)
		return err
	})
}

func (q *Query) ExecWithCount() (int, error) {
	count, err := q.ExecWithCount64()
	return int(count), err
}

func (q *Query) ExecWithCount64() (int64, error) {
	count := int64(0)
	return count, q.Connection.timeFunc("Exec", func() error {
		sql, args := q.ToSQL(nil)
		Log(sql, args...)
		result, err := q.Connection.Store.Exec(sql, args...)
		if err != nil {
			return err
		}

		count, err = result.RowsAffected()
		return err
	})
}

func (c *Connection) ValidateAndSave(model interface{}, excludeColumns ...string) (*validate.Errors, error) {
	sm := &Model{Value: model}
	verrs, err := sm.validateSave(c)
	if err != nil {
		return verrs, err
	}
	if verrs.HasAny() {
		return verrs, nil
	}
	return verrs, c.Save(model, excludeColumns...)
}

var emptyUUID = uuid.Nil.String()

func (c *Connection) Save(model interface{}, excludeColumns ...string) error {
	sm := &Model{Value: model}
	id := sm.ID()

	if fmt.Sprint(id) == "0" || fmt.Sprint(id) == emptyUUID {
		return c.Create(model, excludeColumns...)
	}
	return c.Update(model, excludeColumns...)
}

func (c *Connection) ValidateAndCreate(model interface{}, excludeColumns ...string) (*validate.Errors, error) {
	sm := &Model{Value: model}
	verrs, err := sm.validateCreate(c)
	if err != nil {
		return verrs, err
	}
	if verrs.HasAny() {
		return verrs, nil
	}
	return verrs, c.Create(model, excludeColumns...)
}

func (c *Connection) Create(model interface{}, excludeColumns ...string) error {
	return c.timeFunc("Create", func() error {
		var err error
		sm := &Model{Value: model}

		if err = sm.beforeSave(c); err != nil {
			return err
		}

		if err = sm.beforeCreate(c); err != nil {
			return err
		}

		cols := ColumnsForStructWithAlias(model, sm.TableName(), sm.As)
		cols.Remove(excludeColumns...)

		sm.touchCreatedAt()
		sm.touchUpdatedAt()

		if err = c.Dialect.Create(c.Store, sm, cols); err != nil {
			return err
		}

		if err = sm.afterCreate(c); err != nil {
			return err
		}

		return sm.afterSave(c)
	})
}

func (c *Connection) ValidateAndUpdate(model interface{}, excludeColumns ...string) (*validate.Errors, error) {
	sm := &Model{Value: model}
	verrs, err := sm.validateUpdate(c)
	if err != nil {
		return verrs, err
	}
	if verrs.HasAny() {
		return verrs, nil
	}
	return verrs, c.Update(model, excludeColumns...)
}

func (c *Connection) Update(model interface{}, excludeColumns ...string) error {
	return c.timeFunc("Update", func() error {
		var err error
		sm := &Model{Value: model}

		if err = sm.beforeSave(c); err != nil {
			return err
		}
		if err = sm.beforeUpdate(c); err != nil {
			return err
		}

		cols := ColumnsForStructWithAlias(model, sm.TableName(), sm.As)
		cols.Remove("id", "created_at")
		cols.Remove(excludeColumns...)

		sm.touchUpdatedAt()

		if err = c.Dialect.Update(c.Store, sm, cols); err != nil {
			return err
		}
		if err = sm.afterUpdate(c); err != nil {
			return err
		}

		return sm.afterSave(c)
	})
}

func (c *Connection) Destroy(model interface{}) error {
	return c.timeFunc("Destroy", func() error {
		var err error
		sm := &Model{Value: model}

		if err = sm.beforeDestroy(c); err != nil {
			return err
		}
		if err = c.Dialect.Destroy(c.Store, sm); err != nil {
			return err
		}

		return sm.afterDestroy(c)
	})
}
<commit_msg>int only execwithcount<commit_after>package pop

import (
	"fmt"

	. "github.com/markbates/pop/columns"
	"github.com/markbates/validate"
	uuid "github.com/satori/go.uuid"
)

func (c *Connection) Reload(model interface{}) error {
	sm := Model{Value: model}
	return c.Find(model, sm.ID())
}

func (q *Query) Exec() error {
	return q.Connection.timeFunc("Exec", func() error {
		sql, args := q.ToSQL(nil)
		Log(sql, args...)
		_, err := q.Connection.Store.Exec(sql, args...)
		return err
	})
}

func (q *Query) ExecWithCount() (int, error) {
	count := int64(0)
	return int(count), q.Connection.timeFunc("Exec", func() error {
		sql, args := q.ToSQL(nil)
		Log(sql, args...)
		result, err := q.Connection.Store.Exec(sql, args...)
		if err != nil {
			return err
		}

		count, err = result.RowsAffected()
		return err
	})
}

func (c *Connection) ValidateAndSave(model interface{}, excludeColumns ...string) (*validate.Errors, error) {
	sm := &Model{Value: model}
	verrs, err := sm.validateSave(c)
	if err != nil {
		return verrs, err
	}
	if verrs.HasAny() {
		return verrs, nil
	}
	return verrs, c.Save(model, excludeColumns...)
}

var emptyUUID = uuid.Nil.String()

func (c *Connection) Save(model interface{}, excludeColumns ...string) error {
	sm := &Model{Value: model}
	id := sm.ID()

	if fmt.Sprint(id) == "0" || fmt.Sprint(id) == emptyUUID {
		return c.Create(model, excludeColumns...)
	}
	return c.Update(model, excludeColumns...)
}

func (c *Connection) ValidateAndCreate(model interface{}, excludeColumns ...string) (*validate.Errors, error) {
	sm := &Model{Value: model}
	verrs, err := sm.validateCreate(c)
	if err != nil {
		return verrs, err
	}
	if verrs.HasAny() {
		return verrs, nil
	}
	return verrs, c.Create(model, excludeColumns...)
}

func (c *Connection) Create(model interface{}, excludeColumns ...string) error {
	return c.timeFunc("Create", func() error {
		var err error
		sm := &Model{Value: model}

		if err = sm.beforeSave(c); err != nil {
			return err
		}

		if err = sm.beforeCreate(c); err != nil {
			return err
		}

		cols := ColumnsForStructWithAlias(model, sm.TableName(), sm.As)
		cols.Remove(excludeColumns...)

		sm.touchCreatedAt()
		sm.touchUpdatedAt()

		if err = c.Dialect.Create(c.Store, sm, cols); err != nil {
			return err
		}

		if err = sm.afterCreate(c); err != nil {
			return err
		}

		return sm.afterSave(c)
	})
}

func (c *Connection) ValidateAndUpdate(model interface{}, excludeColumns ...string) (*validate.Errors, error) {
	sm := &Model{Value: model}
	verrs, err := sm.validateUpdate(c)
	if err != nil {
		return verrs, err
	}
	if verrs.HasAny() {
		return verrs, nil
	}
	return verrs, c.Update(model, excludeColumns...)
}

func (c *Connection) Update(model interface{}, excludeColumns ...string) error {
	return c.timeFunc("Update", func() error {
		var err error
		sm := &Model{Value: model}

		if err = sm.beforeSave(c); err != nil {
			return err
		}
		if err = sm.beforeUpdate(c); err != nil {
			return err
		}

		cols := ColumnsForStructWithAlias(model, sm.TableName(), sm.As)
		cols.Remove("id", "created_at")
		cols.Remove(excludeColumns...)

		sm.touchUpdatedAt()

		if err = c.Dialect.Update(c.Store, sm, cols); err != nil {
			return err
		}
		if err = sm.afterUpdate(c); err != nil {
			return err
		}

		return sm.afterSave(c)
	})
}

func (c *Connection) Destroy(model interface{}) error {
	return c.timeFunc("Destroy", func() error {
		var err error
		sm := &Model{Value: model}

		if err = sm.beforeDestroy(c); err != nil {
			return err
		}
		if err = c.Dialect.Destroy(c.Store, sm); err != nil {
			return err
		}

		return sm.afterDestroy(c)
	})
}
<|endoftext|>


<commit_before>// +build darwin freebsd linux netbsd openbsd
package main

import (
	"io"
	"syscall"
	"unsafe"
)

// readPassword is borrowed from the crypto/ssh/terminal sub repo to accept a password from stdin without local echo.
// http://godoc.org/code.google.com/p/go.crypto/ssh/terminal#Terminal.ReadPassword
func readPassword() ([]byte, error) {
	fd := 0
	var oldState syscall.Termios
	if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 {
		return nil, err
	}

	newState := oldState
	newState.Lflag &^= syscall.ECHO
	newState.Lflag |= syscall.ICANON | syscall.ISIG
	newState.Iflag |= syscall.ICRNL
	if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCSETS, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
		return nil, err
	}

	defer func() {
		syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCSETS, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0)
	}()

	var buf [16]byte
	var ret []byte
	for {
		n, err := syscall.Read(fd, buf[:])
		if err != nil {
			return nil, err
		}

		if n == 0 {
			if len(ret) == 0 {
				return nil, io.EOF
			}
			break
		}

		if buf[n-1] == '\n' {
			n--
		}

		ret = append(ret, buf[:n]...)
		if n < len(buf) {
			break
		}
	}

	return ret, nil
}
<commit_msg>should have used git rename<commit_after><|endoftext|>