<commit_before>package sarama

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"time"

	"github.com/eapache/go-xerial-snappy"
)

// CompressionCodec represents the various compression codecs recognized by Kafka in messages.
type CompressionCodec int8

// only the last two bits are really used
const compressionCodecMask int8 = 0x03

const (
	CompressionNone   CompressionCodec = 0
	CompressionGZIP   CompressionCodec = 1
	CompressionSnappy CompressionCodec = 2
)

type Message struct {
	Codec     CompressionCodec // codec used to compress the message contents
	Key       []byte           // the message key, may be nil
	Value     []byte           // the message contents
	Set       *MessageSet      // the message set a message might wrap
	Version   int8             // v1 requires Kafka 0.10
	Timestamp time.Time        // the timestamp of the message (version 1+ only)

	compressedCache []byte
}

func (m *Message) encode(pe packetEncoder) error {
	pe.push(&crc32Field{})

	pe.putInt8(m.Version)

	attributes := int8(m.Codec) & compressionCodecMask
	pe.putInt8(attributes)

	if m.Version >= 1 {
		pe.putInt64(m.Timestamp.UnixNano() / int64(time.Millisecond))
	}

	err := pe.putBytes(m.Key)
	if err != nil {
		return err
	}

	var payload []byte

	if m.compressedCache != nil {
		payload = m.compressedCache
		m.compressedCache = nil
	} else if m.Value != nil {
		switch m.Codec {
		case CompressionNone:
			payload = m.Value
		case CompressionGZIP:
			var buf bytes.Buffer
			writer := gzip.NewWriter(&buf)
			if _, err = writer.Write(m.Value); err != nil {
				return err
			}
			if err = writer.Close(); err != nil {
				return err
			}
			m.compressedCache = buf.Bytes()
			payload = m.compressedCache
		case CompressionSnappy:
			tmp := snappy.Encode(m.Value)
			m.compressedCache = tmp
			payload = m.compressedCache
		default:
			return PacketEncodingError{fmt.Sprintf("unsupported compression codec (%d)", m.Codec)}
		}
	}

	if err = pe.putBytes(payload); err != nil {
		return err
	}

	return pe.pop()
}

func (m *Message) decode(pd packetDecoder) (err error) {
	err = pd.push(&crc32Field{})
	if err != nil {
		return err
	}

	m.Version, err = pd.getInt8()
	if err != nil {
		return err
	}

	attribute, err := pd.getInt8()
	if err != nil {
		return err
	}
	m.Codec = CompressionCodec(attribute & compressionCodecMask)

	if m.Version >= 1 {
		millis, err := pd.getInt64()
		if err != nil {
			return err
		}
		m.Timestamp = time.Unix(millis/1000, (millis%1000)*int64(time.Millisecond))
	}

	m.Key, err = pd.getBytes()
	if err != nil {
		return err
	}

	m.Value, err = pd.getBytes()
	if err != nil {
		return err
	}

	switch m.Codec {
	case CompressionNone:
		// nothing to do
	case CompressionGZIP:
		if m.Value == nil {
			break
		}
		reader, err := gzip.NewReader(bytes.NewReader(m.Value))
		if err != nil {
			return err
		}
		if m.Value, err = ioutil.ReadAll(reader); err != nil {
			return err
		}
		if err := m.decodeSet(); err != nil {
			return err
		}
	case CompressionSnappy:
		if m.Value == nil {
			break
		}
		if m.Value, err = snappy.Decode(m.Value); err != nil {
			return err
		}
		if err := m.decodeSet(); err != nil {
			return err
		}
	default:
		return PacketDecodingError{fmt.Sprintf("invalid compression specified (%d)", m.Codec)}
	}

	return pd.pop()
}

// decodes a message set from a previousy encoded bulk-message
func (m *Message) decodeSet() (err error) {
	pd := realDecoder{raw: m.Value}
	m.Set = &MessageSet{}
	return m.Set.decode(&pd)
}
<commit_msg>Add lz4 compression<commit_after>package sarama

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io/ioutil"
	"time"

	"github.com/eapache/go-xerial-snappy"
	"github.com/pierrec/lz4"
)

// CompressionCodec represents the various compression codecs recognized by Kafka in messages.
type CompressionCodec int8

// only the last two bits are really used
const compressionCodecMask int8 = 0x03

const (
	CompressionNone   CompressionCodec = 0
	CompressionGZIP   CompressionCodec = 1
	CompressionSnappy CompressionCodec = 2
	CompressionLZ4    CompressionCodec = 3
)

type Message struct {
	Codec     CompressionCodec // codec used to compress the message contents
	Key       []byte           // the message key, may be nil
	Value     []byte           // the message contents
	Set       *MessageSet      // the message set a message might wrap
	Version   int8             // v1 requires Kafka 0.10
	Timestamp time.Time        // the timestamp of the message (version 1+ only)

	compressedCache []byte
}

func (m *Message) encode(pe packetEncoder) error {
	pe.push(&crc32Field{})

	pe.putInt8(m.Version)

	attributes := int8(m.Codec) & compressionCodecMask
	pe.putInt8(attributes)

	if m.Version >= 1 {
		pe.putInt64(m.Timestamp.UnixNano() / int64(time.Millisecond))
	}

	err := pe.putBytes(m.Key)
	if err != nil {
		return err
	}

	var payload []byte

	if m.compressedCache != nil {
		payload = m.compressedCache
		m.compressedCache = nil
	} else if m.Value != nil {
		switch m.Codec {
		case CompressionNone:
			payload = m.Value
		case CompressionGZIP:
			var buf bytes.Buffer
			writer := gzip.NewWriter(&buf)
			if _, err = writer.Write(m.Value); err != nil {
				return err
			}
			if err = writer.Close(); err != nil {
				return err
			}
			m.compressedCache = buf.Bytes()
			payload = m.compressedCache
		case CompressionSnappy:
			tmp := snappy.Encode(m.Value)
			m.compressedCache = tmp
			payload = m.compressedCache
		case CompressionLZ4:
			var buf bytes.Buffer
			writer := lz4.NewWriter(&buf)
			if _, err = writer.Write(m.Value); err != nil {
				return err
			}
			if err = writer.Close(); err != nil {
				return err
			}
			m.compressedCache = buf.Bytes()
			payload = m.compressedCache

		default:
			return PacketEncodingError{fmt.Sprintf("unsupported compression codec (%d)", m.Codec)}
		}
	}

	if err = pe.putBytes(payload); err != nil {
		return err
	}

	return pe.pop()
}

func (m *Message) decode(pd packetDecoder) (err error) {
	err = pd.push(&crc32Field{})
	if err != nil {
		return err
	}

	m.Version, err = pd.getInt8()
	if err != nil {
		return err
	}

	attribute, err := pd.getInt8()
	if err != nil {
		return err
	}
	m.Codec = CompressionCodec(attribute & compressionCodecMask)

	if m.Version >= 1 {
		millis, err := pd.getInt64()
		if err != nil {
			return err
		}
		m.Timestamp = time.Unix(millis/1000, (millis%1000)*int64(time.Millisecond))
	}

	m.Key, err = pd.getBytes()
	if err != nil {
		return err
	}

	m.Value, err = pd.getBytes()
	if err != nil {
		return err
	}

	switch m.Codec {
	case CompressionNone:
		// nothing to do
	case CompressionGZIP:
		if m.Value == nil {
			break
		}
		reader, err := gzip.NewReader(bytes.NewReader(m.Value))
		if err != nil {
			return err
		}
		if m.Value, err = ioutil.ReadAll(reader); err != nil {
			return err
		}
		if err := m.decodeSet(); err != nil {
			return err
		}
	case CompressionSnappy:
		if m.Value == nil {
			break
		}
		if m.Value, err = snappy.Decode(m.Value); err != nil {
			return err
		}
		if err := m.decodeSet(); err != nil {
			return err
		}
	case CompressionLZ4:
		if m.Value == nil {
			break
		}
		reader := lz4.NewReader(bytes.NewReader(m.Value))
		if m.Value, err = ioutil.ReadAll(reader); err != nil {
			return err
		}
		if err := m.decodeSet(); err != nil {
			return err
		}

	default:
		return PacketDecodingError{fmt.Sprintf("invalid compression specified (%d)", m.Codec)}
	}

	return pd.pop()
}

// decodes a message set from a previousy encoded bulk-message
func (m *Message) decodeSet() (err error) {
	pd := realDecoder{raw: m.Value}
	m.Set = &MessageSet{}
	return m.Set.decode(&pd)
}
<|endoftext|>


<commit_before>package main

// Message represents an individual message for processing by the server or
// returning to the client.
//
// See http://jmap.io/spec.html#the-structure-of-an-exchange
type Message struct {
	// Name specifies the method to be called on the server or the type of
	// response being sent to the client.
	Name string

	// Arguments is an object containing named arguments for the method or
	// response.
	Arguments interface{}

	// ClientID is an arbitary string to be echoed back with the responses
	// emitted bythe method call.
	ClientID string
}
<commit_msg>message: implement json marshaling and unmarshaling<commit_after>package main

import "encoding/json"

// Message represents an individual message for processing by the server or
// returning to the client.
//
// See http://jmap.io/spec.html#the-structure-of-an-exchange
type Message struct {
	// Name specifies the method to be called on the server or the type of
	// response being sent to the client.
	Name string

	// Arguments is an object containing named arguments for the method or
	// response.
	Arguments interface{}

	// ClientID is an arbitary string to be echoed back with the responses
	// emitted bythe method call.
	ClientID string
}

func (m *Message) MarshalJSON() ([]byte, error) {
	arr := make([]interface{}, 3)
	arr[0] = m.Name
	arr[1] = m.Arguments
	arr[2] = m.ClientID

	return json.Marshal(arr)
}

func (m *Message) UnmarshalJSON(j []byte) error {
	arr := []interface{}{}
	if err := json.Unmarshal(j, &arr); err != nil {
		return err
	}

	m.Name = arr[0].(string)
	m.Arguments = arr[1]
	m.ClientID = arr[2].(string)

	return nil
}
<|endoftext|>


<commit_before>package smtpd

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"mime"
	"mime/multipart"
	"mime/quotedprintable"
	"net/mail"
	"net/textproto"
	"strings"
	"sync"
	"time"
)

const idEntropy = 64
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

// Message is a nicely packaged representation of the
// recieved message
type Message struct {
	To      []*mail.Address
	From    *mail.Address
	Header  mail.Header
	Subject string
	RawBody []byte
	Source  []byte

	messageID    string
	genMessageID sync.Once
	rcpt         []*mail.Address

	// meta info
	Logger *log.Logger
}

// Part represents a single part of the message
type Part struct {
	Header   textproto.MIMEHeader
	part     *multipart.Part
	Body     []byte
	Children []*Part
}

// ID returns an identifier for this message, or generates one if none available using the masked string
// algorithm from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang
func (m *Message) ID() string {
	m.genMessageID.Do(func() {
		if m.messageID = m.Header.Get("Message-ID"); m.messageID != "" {
			return
		}
		var src = rand.NewSource(time.Now().UnixNano())

		b := make([]byte, idEntropy)
		// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
		for i, cache, remain := idEntropy-1, src.Int63(), letterIdxMax; i >= 0; {
			if remain == 0 {
				cache, remain = src.Int63(), letterIdxMax
			}
			if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
				b[i] = letterBytes[idx]
				i--
			}
			cache >>= letterIdxBits
			remain--
		}

		m.messageID = string(b)
	})
	return m.messageID
}

// BCC returns a list of addresses this message should be
func (m *Message) BCC() []*mail.Address {

	var inHeaders = make(map[string]struct{})
	for _, to := range m.To {
		inHeaders[to.Address] = struct{}{}
	}

	var bcc []*mail.Address
	for _, recipient := range m.rcpt {
		if _, ok := inHeaders[recipient.Address]; !ok {
			bcc = append(bcc, recipient)
		}
	}

	return bcc
}

// Plain returns the text/plain content of the message, if any
func (m *Message) Plain() ([]byte, error) {
	return m.FindBody("text/plain")
}

// HTML returns the text/html content of the message, if any
func (m *Message) HTML() ([]byte, error) {
	return m.FindBody("text/html")
}

func findTypeInParts(contentType string, parts []*Part) *Part {
	for _, p := range parts {
		mediaType, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
		if err == nil && mediaType == contentType {
			return p
		}
	}
	return nil
}

// Attachments returns the list of attachments on this message
// XXX: this assumes that the only mimetype supporting attachments is multipart/mixed
// need to review https://en.wikipedia.org/wiki/MIME#Multipart_messages to ensure that is the case
func (m *Message) Attachments() ([]*Part, error) {
	mediaType, _, err := mime.ParseMediaType(m.Header.Get("Content-Type"))
	if err != nil {
		return nil, err
	}

	parts, err := m.Parts()
	if err != nil {
		return nil, err
	}

	var attachments []*Part
	if mediaType == "multipart/mixed" {
		for _, part := range parts {
			mediaType, _, err := mime.ParseMediaType(part.Header.Get("Content-Type"))
			if err != nil {
				return nil, err
			}
			if strings.HasPrefix(mediaType, "multipart/") {
				// XXX: any cases where this would still be an attachment?
				continue
			}
			attachments = append(attachments, part)
		}
	}
	return attachments, nil
}

// FindBody finds the first part of the message with the specified Content-Type
func (m *Message) FindBody(contentType string) ([]byte, error) {

	mediaType, _, err := mime.ParseMediaType(m.Header.Get("Content-Type"))
	if err != nil {
		return nil, err
	}

	parts, err := m.Parts()
	if err != nil {
		return nil, err
	}

	var alternatives []*Part
	switch mediaType {
	case contentType:
		if len(parts) > 0 {
			return parts[0].Body, nil
		}
		return nil, fmt.Errorf("%v found, but no data in body", contentType)
	case "multipart/alternative":
		alternatives = parts
	default:
		if alt := findTypeInParts("multipart/alternative", parts); alt != nil {
			alternatives = alt.Children
		}
	}

	if len(alternatives) == 0 {
		return nil, fmt.Errorf("No multipart/alternative section found, can't find %v", contentType)
	}

	part := findTypeInParts(contentType, alternatives)
	if part == nil {
		return nil, fmt.Errorf("No %v content found in multipart/alternative section", contentType)
	}

	return part.Body, nil
}

func readToPart(header textproto.MIMEHeader, content io.Reader) (*Part, error) {
	cte := strings.ToLower(header.Get("Content-Transfer-Encoding"))

	if cte == "quoted-printable" {
		content = quotedprintable.NewReader(content)
	}

	slurp, err := ioutil.ReadAll(content)
	if err != nil {
		return nil, err
	}

	if cte == "base64" {
		dst := make([]byte, base64.StdEncoding.DecodedLen(len(slurp)))
		decodedLen, err := base64.StdEncoding.Decode(dst, slurp)
		if err != nil {
			return nil, err
		}

		slurp = dst[:decodedLen]
	}
	return &Part{
		Header: header,
		Body:   slurp,
	}, nil
}

func parseContent(header textproto.MIMEHeader, content io.Reader) ([]*Part, error) {

	mediaType, params, err := mime.ParseMediaType(header.Get("Content-Type"))
	if err != nil && err.Error() == "mime: no media type" {
		mediaType = "application/octet-stream"
	} else if err != nil {
		return nil, fmt.Errorf("Media Type error: %v", err)
	}

	var parts []*Part

	if strings.HasPrefix(mediaType, "multipart/") {

		mr := multipart.NewReader(content, params["boundary"])
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			} else if err != nil {
				return nil, fmt.Errorf("MIME error: %v", err)
			}

			part, err := readToPart(p.Header, p)

			// XXX: maybe want to implement a less strict mode that gets what it can out of the message
			// instead of erroring out on individual sections?
			partType, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
			if err != nil {
				return nil, err
			}
			if strings.HasPrefix(partType, "multipart/") {
				subParts, err := parseContent(p.Header, bytes.NewBuffer(part.Body))
				if err != nil {
					return nil, err
				}
				part.Children = subParts
			}
			parts = append(parts, part)
		}
	} else {
		part, err := readToPart(header, content)
		if err != nil {
			return nil, err
		}
		parts = append(parts, part)
	}

	return parts, nil
}

// Parts breaks a message body into its mime parts
func (m *Message) Parts() ([]*Part, error) {
	parts, err := parseContent(textproto.MIMEHeader(m.Header), bytes.NewBuffer(m.RawBody))
	if err != nil {
		return nil, err
	}

	return parts, nil
}

// NewMessage creates a Message from a data blob and a recipients list
func NewMessage(data []byte, rcpt []*mail.Address, logger *log.Logger) (*Message, error) {
	m, err := mail.ReadMessage(bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}

	// TODO: This isn't accurate, the To field should be all the values from RCPT TO:
	to, err := m.Header.AddressList("To")
	if err != nil {
		return nil, err
	}

	from, err := m.Header.AddressList("From")
	if err != nil {
		return nil, err
	}

	header := make(map[string]string)

	for k, v := range m.Header {
		if len(v) == 1 {
			header[k] = v[0]
		}
	}

	raw, err := ioutil.ReadAll(m.Body)
	if err != nil && err != io.EOF {
		return nil, err
	}

	return &Message{
		rcpt:    rcpt,
		To:      to,
		From:    from[0],
		Header:  m.Header,
		Subject: m.Header.Get("subject"),
		RawBody: raw,
		Source:  data,
		Logger:  logger,
	}, nil

}
<commit_msg>Don't require the To header<commit_after>package smtpd

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"mime"
	"mime/multipart"
	"mime/quotedprintable"
	"net/mail"
	"net/textproto"
	"strings"
	"sync"
	"time"
)

const idEntropy = 64
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

// Message is a nicely packaged representation of the
// recieved message
type Message struct {
	To      []*mail.Address
	From    *mail.Address
	Header  mail.Header
	Subject string
	RawBody []byte
	Source  []byte

	messageID    string
	genMessageID sync.Once
	rcpt         []*mail.Address

	// meta info
	Logger *log.Logger
}

// Part represents a single part of the message
type Part struct {
	Header   textproto.MIMEHeader
	part     *multipart.Part
	Body     []byte
	Children []*Part
}

// ID returns an identifier for this message, or generates one if none available using the masked string
// algorithm from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang
func (m *Message) ID() string {
	m.genMessageID.Do(func() {
		if m.messageID = m.Header.Get("Message-ID"); m.messageID != "" {
			return
		}
		var src = rand.NewSource(time.Now().UnixNano())

		b := make([]byte, idEntropy)
		// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
		for i, cache, remain := idEntropy-1, src.Int63(), letterIdxMax; i >= 0; {
			if remain == 0 {
				cache, remain = src.Int63(), letterIdxMax
			}
			if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
				b[i] = letterBytes[idx]
				i--
			}
			cache >>= letterIdxBits
			remain--
		}

		m.messageID = string(b)
	})
	return m.messageID
}

// BCC returns a list of addresses this message should be
func (m *Message) BCC() []*mail.Address {

	var inHeaders = make(map[string]struct{})
	for _, to := range m.To {
		inHeaders[to.Address] = struct{}{}
	}

	var bcc []*mail.Address
	for _, recipient := range m.rcpt {
		if _, ok := inHeaders[recipient.Address]; !ok {
			bcc = append(bcc, recipient)
		}
	}

	return bcc
}

// Plain returns the text/plain content of the message, if any
func (m *Message) Plain() ([]byte, error) {
	return m.FindBody("text/plain")
}

// HTML returns the text/html content of the message, if any
func (m *Message) HTML() ([]byte, error) {
	return m.FindBody("text/html")
}

func findTypeInParts(contentType string, parts []*Part) *Part {
	for _, p := range parts {
		mediaType, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
		if err == nil && mediaType == contentType {
			return p
		}
	}
	return nil
}

// Attachments returns the list of attachments on this message
// XXX: this assumes that the only mimetype supporting attachments is multipart/mixed
// need to review https://en.wikipedia.org/wiki/MIME#Multipart_messages to ensure that is the case
func (m *Message) Attachments() ([]*Part, error) {
	mediaType, _, err := mime.ParseMediaType(m.Header.Get("Content-Type"))
	if err != nil {
		return nil, err
	}

	parts, err := m.Parts()
	if err != nil {
		return nil, err
	}

	var attachments []*Part
	if mediaType == "multipart/mixed" {
		for _, part := range parts {
			mediaType, _, err := mime.ParseMediaType(part.Header.Get("Content-Type"))
			if err != nil {
				return nil, err
			}
			if strings.HasPrefix(mediaType, "multipart/") {
				// XXX: any cases where this would still be an attachment?
				continue
			}
			attachments = append(attachments, part)
		}
	}
	return attachments, nil
}

// FindBody finds the first part of the message with the specified Content-Type
func (m *Message) FindBody(contentType string) ([]byte, error) {

	mediaType, _, err := mime.ParseMediaType(m.Header.Get("Content-Type"))
	if err != nil {
		return nil, err
	}

	parts, err := m.Parts()
	if err != nil {
		return nil, err
	}

	var alternatives []*Part
	switch mediaType {
	case contentType:
		if len(parts) > 0 {
			return parts[0].Body, nil
		}
		return nil, fmt.Errorf("%v found, but no data in body", contentType)
	case "multipart/alternative":
		alternatives = parts
	default:
		if alt := findTypeInParts("multipart/alternative", parts); alt != nil {
			alternatives = alt.Children
		}
	}

	if len(alternatives) == 0 {
		return nil, fmt.Errorf("No multipart/alternative section found, can't find %v", contentType)
	}

	part := findTypeInParts(contentType, alternatives)
	if part == nil {
		return nil, fmt.Errorf("No %v content found in multipart/alternative section", contentType)
	}

	return part.Body, nil
}

func readToPart(header textproto.MIMEHeader, content io.Reader) (*Part, error) {
	cte := strings.ToLower(header.Get("Content-Transfer-Encoding"))

	if cte == "quoted-printable" {
		content = quotedprintable.NewReader(content)
	}

	slurp, err := ioutil.ReadAll(content)
	if err != nil {
		return nil, err
	}

	if cte == "base64" {
		dst := make([]byte, base64.StdEncoding.DecodedLen(len(slurp)))
		decodedLen, err := base64.StdEncoding.Decode(dst, slurp)
		if err != nil {
			return nil, err
		}

		slurp = dst[:decodedLen]
	}
	return &Part{
		Header: header,
		Body:   slurp,
	}, nil
}

func parseContent(header textproto.MIMEHeader, content io.Reader) ([]*Part, error) {

	mediaType, params, err := mime.ParseMediaType(header.Get("Content-Type"))
	if err != nil && err.Error() == "mime: no media type" {
		mediaType = "application/octet-stream"
	} else if err != nil {
		return nil, fmt.Errorf("Media Type error: %v", err)
	}

	var parts []*Part

	if strings.HasPrefix(mediaType, "multipart/") {

		mr := multipart.NewReader(content, params["boundary"])
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			} else if err != nil {
				return nil, fmt.Errorf("MIME error: %v", err)
			}

			part, err := readToPart(p.Header, p)

			// XXX: maybe want to implement a less strict mode that gets what it can out of the message
			// instead of erroring out on individual sections?
			partType, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
			if err != nil {
				return nil, err
			}
			if strings.HasPrefix(partType, "multipart/") {
				subParts, err := parseContent(p.Header, bytes.NewBuffer(part.Body))
				if err != nil {
					return nil, err
				}
				part.Children = subParts
			}
			parts = append(parts, part)
		}
	} else {
		part, err := readToPart(header, content)
		if err != nil {
			return nil, err
		}
		parts = append(parts, part)
	}

	return parts, nil
}

// Parts breaks a message body into its mime parts
func (m *Message) Parts() ([]*Part, error) {
	parts, err := parseContent(textproto.MIMEHeader(m.Header), bytes.NewBuffer(m.RawBody))
	if err != nil {
		return nil, err
	}

	return parts, nil
}

// NewMessage creates a Message from a data blob and a recipients list
func NewMessage(data []byte, rcpt []*mail.Address, logger *log.Logger) (*Message, error) {
	m, err := mail.ReadMessage(bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}

	// this is only used to differentiate normal To: recipients from BCC:
	// recipients in tests. The To: header explicitly not required by RFC 2822
	// 3.6.
	to, err := m.Header.AddressList("To")
	if err != nil && err != mail.ErrHeaderNotPresent {
		return nil, err
	}

	from, err := m.Header.AddressList("From")
	if err != nil {
		return nil, err
	}

	header := make(map[string]string)

	for k, v := range m.Header {
		if len(v) == 1 {
			header[k] = v[0]
		}
	}

	raw, err := ioutil.ReadAll(m.Body)
	if err != nil && err != io.EOF {
		return nil, err
	}

	return &Message{
		rcpt:    rcpt,
		To:      to,
		From:    from[0],
		Header:  m.Header,
		Subject: m.Header.Get("subject"),
		RawBody: raw,
		Source:  data,
		Logger:  logger,
	}, nil

}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to the Message struct

package discordgo

import (
	"io"
	"regexp"
	"strings"
)

// MessageType is the type of Message
type MessageType int

// Block contains the valid known MessageType values
const (
	MessageTypeDefault MessageType = iota
	MessageTypeRecipientAdd
	MessageTypeRecipientRemove
	MessageTypeCall
	MessageTypeChannelNameChange
	MessageTypeChannelIconChange
	MessageTypeChannelPinnedMessage
	MessageTypeGuildMemberJoin
	MessageTypeUserPremiumGuildSubscription
	MessageTypeUserPremiumGuildSubscriptionTierOne
	MessageTypeUserPremiumGuildSubscriptionTierTwo
	MessageTypeUserPremiumGuildSubscriptionTierThree
	MessageTypeChannelFollowAdd
)

// A Message stores all data related to a specific Discord message.
type Message struct {
	// The ID of the message.
	ID string `json:"id"`

	// The ID of the channel in which the message was sent.
	ChannelID string `json:"channel_id"`

	// The ID of the guild in which the message was sent.
	GuildID string `json:"guild_id,omitempty"`

	// The content of the message.
	Content string `json:"content"`

	// The time at which the messsage was sent.
	// CAUTION: this field may be removed in a
	// future API version; it is safer to calculate
	// the creation time via the ID.
	Timestamp Timestamp `json:"timestamp"`

	// The time at which the last edit of the message
	// occurred, if it has been edited.
	EditedTimestamp Timestamp `json:"edited_timestamp"`

	// The roles mentioned in the message.
	MentionRoles []string `json:"mention_roles"`

	// Whether the message is text-to-speech.
	Tts bool `json:"tts"`

	// Whether the message mentions everyone.
	MentionEveryone bool `json:"mention_everyone"`

	// The author of the message. This is not guaranteed to be a
	// valid user (webhook-sent messages do not possess a full author).
	Author *User `json:"author"`

	// A list of attachments present in the message.
	Attachments []*MessageAttachment `json:"attachments"`

	// A list of embeds present in the message. Multiple
	// embeds can currently only be sent by webhooks.
	Embeds []*MessageEmbed `json:"embeds"`

	// A list of users mentioned in the message.
	Mentions []*User `json:"mentions"`

	// A list of reactions to the message.
	Reactions []*MessageReactions `json:"reactions"`

	// Whether the message is pinned or not.
	Pinned bool `json:"pinned"`

	// The type of the message.
	Type MessageType `json:"type"`

	// The webhook ID of the message, if it was generated by a webhook
	WebhookID string `json:"webhook_id"`

	// Member properties for this message's author,
	// contains only partial information
	Member *Member `json:"member"`

	// Channels specifically mentioned in this message
	// Not all channel mentions in a message will appear in mention_channels.
	// Only textual channels that are visible to everyone in a lurkable guild will ever be included.
	// Only crossposted messages (via Channel Following) currently include mention_channels at all.
	// If no mentions in the message meet these requirements, this field will not be sent.
	MentionChannels []*Channel `json:"mention_channels"`

	// Is sent with Rich Presence-related chat embeds
	Activity *MessageActivity `json:"activity"`

	// Is sent with Rich Presence-related chat embeds
	Application *MessageApplication `json:"application"`

	// MessageReference contains reference data sent with crossposted messages
	MessageReference *MessageReference `json:"message_reference"`

	// The flags of the message, which describe extra features of a message.
	// This is a combination of bit masks; the presence of a certain permission can
	// be checked by performing a bitwise AND between this int and the flag.
	Flags int `json:"flags"`
}

// File stores info about files you e.g. send in messages.
type File struct {
	Name        string
	ContentType string
	Reader      io.Reader
}

// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
type MessageSend struct {
	Content string        `json:"content,omitempty"`
	Embed   *MessageEmbed `json:"embed,omitempty"`
	Tts     bool          `json:"tts"`
	Files   []*File       `json:"-"`

	// TODO: Remove this when compatibility is not required.
	File *File `json:"-"`
}

// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
// is also where you should get the instance from.
type MessageEdit struct {
	Content *string       `json:"content,omitempty"`
	Embed   *MessageEmbed `json:"embed,omitempty"`

	ID      string
	Channel string
}

// NewMessageEdit returns a MessageEdit struct, initialized
// with the Channel and ID.
func NewMessageEdit(channelID string, messageID string) *MessageEdit {
	return &MessageEdit{
		Channel: channelID,
		ID:      messageID,
	}
}

// SetContent is the same as setting the variable Content,
// except it doesn't take a pointer.
func (m *MessageEdit) SetContent(str string) *MessageEdit {
	m.Content = &str
	return m
}

// SetEmbed is a convenience function for setting the embed,
// so you can chain commands.
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
	m.Embed = embed
	return m
}

// A MessageAttachment stores data for message attachments.
type MessageAttachment struct {
	ID       string `json:"id"`
	URL      string `json:"url"`
	ProxyURL string `json:"proxy_url"`
	Filename string `json:"filename"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	Size     int    `json:"size"`
}

// MessageEmbedFooter is a part of a MessageEmbed struct.
type MessageEmbedFooter struct {
	Text         string `json:"text,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedImage is a part of a MessageEmbed struct.
type MessageEmbedImage struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedThumbnail is a part of a MessageEmbed struct.
type MessageEmbedThumbnail struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedVideo is a part of a MessageEmbed struct.
type MessageEmbedVideo struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedProvider is a part of a MessageEmbed struct.
type MessageEmbedProvider struct {
	URL  string `json:"url,omitempty"`
	Name string `json:"name,omitempty"`
}

// MessageEmbedAuthor is a part of a MessageEmbed struct.
type MessageEmbedAuthor struct {
	URL          string `json:"url,omitempty"`
	Name         string `json:"name,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedField is a part of a MessageEmbed struct.
type MessageEmbedField struct {
	Name   string `json:"name,omitempty"`
	Value  string `json:"value,omitempty"`
	Inline bool   `json:"inline,omitempty"`
}

// An MessageEmbed stores data for message embeds.
type MessageEmbed struct {
	URL         string                 `json:"url,omitempty"`
	Type        string                 `json:"type,omitempty"`
	Title       string                 `json:"title,omitempty"`
	Description string                 `json:"description,omitempty"`
	Timestamp   string                 `json:"timestamp,omitempty"`
	Color       int                    `json:"color,omitempty"`
	Footer      *MessageEmbedFooter    `json:"footer,omitempty"`
	Image       *MessageEmbedImage     `json:"image,omitempty"`
	Thumbnail   *MessageEmbedThumbnail `json:"thumbnail,omitempty"`
	Video       *MessageEmbedVideo     `json:"video,omitempty"`
	Provider    *MessageEmbedProvider  `json:"provider,omitempty"`
	Author      *MessageEmbedAuthor    `json:"author,omitempty"`
	Fields      []*MessageEmbedField   `json:"fields,omitempty"`
}

// MessageReactions holds a reactions object for a message.
type MessageReactions struct {
	Count int    `json:"count"`
	Me    bool   `json:"me"`
	Emoji *Emoji `json:"emoji"`
}

// MessageActivity is sent with Rich Presence-related chat embeds
type MessageActivity struct {
	Type    MessageActivityType `json:"type"`
	PartyID string              `json:"party_id"`
}

// MessageActivityType is the type of message activity
type MessageActivityType int

const (
	MessageActivityTypeJoin = iota + 1
	MessageActivityTypeSpectate
	MessageActivityTypeListen
	MessageActivityTypeJoinRequest
)

// MessageFlag describes an extra feature of the message
type MessageFlag int

// Constants for the different bit offsets of Message Flags
const (
	// This message has been published to subscribed channels (via Channel Following)
	MessageFlagCrossposted = 1 << iota
	// This message originated from a message in another channel (via Channel Following)
	MessageFlagIsCrosspost
	// Do not include any embeds when serializing this message
	MessageFlagSuppressEmbeds
)

// MessageApplication is sent with Rich Presence-related chat embeds
type MessageApplication struct {
	ID          string `json:"id"`
	CoverImage  string `json:"cover_image"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
	Name        string `json:"name"`
}

// MessageReference contains reference data sent with crossposted messages
type MessageReference struct {
	MessageID string `json:"message_id"`
	ChannelID string `json:"channel_id"`
	GuildID   string `json:"guild_id"`
}

// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() (content string) {
	content = m.Content

	for _, user := range m.Mentions {
		content = strings.NewReplacer(
			"<@"+user.ID+">", "@"+user.Username,
			"<@!"+user.ID+">", "@"+user.Username,
		).Replace(content)
	}
	return
}

var patternChannels = regexp.MustCompile("<#[^>]*>")

// ContentWithMoreMentionsReplaced will replace all @<id> mentions with the
// username of the mention, but also role IDs and more.
func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) {
	content = m.Content

	if !s.StateEnabled {
		content = m.ContentWithMentionsReplaced()
		return
	}

	channel, err := s.State.Channel(m.ChannelID)
	if err != nil {
		content = m.ContentWithMentionsReplaced()
		return
	}

	for _, user := range m.Mentions {
		nick := user.Username

		member, err := s.State.Member(channel.GuildID, user.ID)
		if err == nil && member.Nick != "" {
			nick = member.Nick
		}

		content = strings.NewReplacer(
			"<@"+user.ID+">", "@"+user.Username,
			"<@!"+user.ID+">", "@"+nick,
		).Replace(content)
	}
	for _, roleID := range m.MentionRoles {
		role, err := s.State.Role(channel.GuildID, roleID)
		if err != nil || !role.Mentionable {
			continue
		}

		content = strings.Replace(content, "<@&"+role.ID+">", "@"+role.Name, -1)
	}

	content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string {
		channel, err := s.State.Channel(mention[2 : len(mention)-1])
		if err != nil || channel.Type == ChannelTypeGuildVoice {
			return mention
		}

		return "#" + channel.Name
	})
	return
}
<commit_msg>fixes lint<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to the Message struct

package discordgo

import (
	"io"
	"regexp"
	"strings"
)

// MessageType is the type of Message
type MessageType int

// Block contains the valid known MessageType values
const (
	MessageTypeDefault MessageType = iota
	MessageTypeRecipientAdd
	MessageTypeRecipientRemove
	MessageTypeCall
	MessageTypeChannelNameChange
	MessageTypeChannelIconChange
	MessageTypeChannelPinnedMessage
	MessageTypeGuildMemberJoin
	MessageTypeUserPremiumGuildSubscription
	MessageTypeUserPremiumGuildSubscriptionTierOne
	MessageTypeUserPremiumGuildSubscriptionTierTwo
	MessageTypeUserPremiumGuildSubscriptionTierThree
	MessageTypeChannelFollowAdd
)

// A Message stores all data related to a specific Discord message.
type Message struct {
	// The ID of the message.
	ID string `json:"id"`

	// The ID of the channel in which the message was sent.
	ChannelID string `json:"channel_id"`

	// The ID of the guild in which the message was sent.
	GuildID string `json:"guild_id,omitempty"`

	// The content of the message.
	Content string `json:"content"`

	// The time at which the messsage was sent.
	// CAUTION: this field may be removed in a
	// future API version; it is safer to calculate
	// the creation time via the ID.
	Timestamp Timestamp `json:"timestamp"`

	// The time at which the last edit of the message
	// occurred, if it has been edited.
	EditedTimestamp Timestamp `json:"edited_timestamp"`

	// The roles mentioned in the message.
	MentionRoles []string `json:"mention_roles"`

	// Whether the message is text-to-speech.
	Tts bool `json:"tts"`

	// Whether the message mentions everyone.
	MentionEveryone bool `json:"mention_everyone"`

	// The author of the message. This is not guaranteed to be a
	// valid user (webhook-sent messages do not possess a full author).
	Author *User `json:"author"`

	// A list of attachments present in the message.
	Attachments []*MessageAttachment `json:"attachments"`

	// A list of embeds present in the message. Multiple
	// embeds can currently only be sent by webhooks.
	Embeds []*MessageEmbed `json:"embeds"`

	// A list of users mentioned in the message.
	Mentions []*User `json:"mentions"`

	// A list of reactions to the message.
	Reactions []*MessageReactions `json:"reactions"`

	// Whether the message is pinned or not.
	Pinned bool `json:"pinned"`

	// The type of the message.
	Type MessageType `json:"type"`

	// The webhook ID of the message, if it was generated by a webhook
	WebhookID string `json:"webhook_id"`

	// Member properties for this message's author,
	// contains only partial information
	Member *Member `json:"member"`

	// Channels specifically mentioned in this message
	// Not all channel mentions in a message will appear in mention_channels.
	// Only textual channels that are visible to everyone in a lurkable guild will ever be included.
	// Only crossposted messages (via Channel Following) currently include mention_channels at all.
	// If no mentions in the message meet these requirements, this field will not be sent.
	MentionChannels []*Channel `json:"mention_channels"`

	// Is sent with Rich Presence-related chat embeds
	Activity *MessageActivity `json:"activity"`

	// Is sent with Rich Presence-related chat embeds
	Application *MessageApplication `json:"application"`

	// MessageReference contains reference data sent with crossposted messages
	MessageReference *MessageReference `json:"message_reference"`

	// The flags of the message, which describe extra features of a message.
	// This is a combination of bit masks; the presence of a certain permission can
	// be checked by performing a bitwise AND between this int and the flag.
	Flags int `json:"flags"`
}

// File stores info about files you e.g. send in messages.
type File struct {
	Name        string
	ContentType string
	Reader      io.Reader
}

// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
type MessageSend struct {
	Content string        `json:"content,omitempty"`
	Embed   *MessageEmbed `json:"embed,omitempty"`
	Tts     bool          `json:"tts"`
	Files   []*File       `json:"-"`

	// TODO: Remove this when compatibility is not required.
	File *File `json:"-"`
}

// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
// is also where you should get the instance from.
type MessageEdit struct {
	Content *string       `json:"content,omitempty"`
	Embed   *MessageEmbed `json:"embed,omitempty"`

	ID      string
	Channel string
}

// NewMessageEdit returns a MessageEdit struct, initialized
// with the Channel and ID.
func NewMessageEdit(channelID string, messageID string) *MessageEdit {
	return &MessageEdit{
		Channel: channelID,
		ID:      messageID,
	}
}

// SetContent is the same as setting the variable Content,
// except it doesn't take a pointer.
func (m *MessageEdit) SetContent(str string) *MessageEdit {
	m.Content = &str
	return m
}

// SetEmbed is a convenience function for setting the embed,
// so you can chain commands.
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
	m.Embed = embed
	return m
}

// A MessageAttachment stores data for message attachments.
type MessageAttachment struct {
	ID       string `json:"id"`
	URL      string `json:"url"`
	ProxyURL string `json:"proxy_url"`
	Filename string `json:"filename"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	Size     int    `json:"size"`
}

// MessageEmbedFooter is a part of a MessageEmbed struct.
type MessageEmbedFooter struct {
	Text         string `json:"text,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedImage is a part of a MessageEmbed struct.
type MessageEmbedImage struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedThumbnail is a part of a MessageEmbed struct.
type MessageEmbedThumbnail struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedVideo is a part of a MessageEmbed struct.
type MessageEmbedVideo struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedProvider is a part of a MessageEmbed struct.
type MessageEmbedProvider struct {
	URL  string `json:"url,omitempty"`
	Name string `json:"name,omitempty"`
}

// MessageEmbedAuthor is a part of a MessageEmbed struct.
type MessageEmbedAuthor struct {
	URL          string `json:"url,omitempty"`
	Name         string `json:"name,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedField is a part of a MessageEmbed struct.
type MessageEmbedField struct {
	Name   string `json:"name,omitempty"`
	Value  string `json:"value,omitempty"`
	Inline bool   `json:"inline,omitempty"`
}

// An MessageEmbed stores data for message embeds.
type MessageEmbed struct {
	URL         string                 `json:"url,omitempty"`
	Type        string                 `json:"type,omitempty"`
	Title       string                 `json:"title,omitempty"`
	Description string                 `json:"description,omitempty"`
	Timestamp   string                 `json:"timestamp,omitempty"`
	Color       int                    `json:"color,omitempty"`
	Footer      *MessageEmbedFooter    `json:"footer,omitempty"`
	Image       *MessageEmbedImage     `json:"image,omitempty"`
	Thumbnail   *MessageEmbedThumbnail `json:"thumbnail,omitempty"`
	Video       *MessageEmbedVideo     `json:"video,omitempty"`
	Provider    *MessageEmbedProvider  `json:"provider,omitempty"`
	Author      *MessageEmbedAuthor    `json:"author,omitempty"`
	Fields      []*MessageEmbedField   `json:"fields,omitempty"`
}

// MessageReactions holds a reactions object for a message.
type MessageReactions struct {
	Count int    `json:"count"`
	Me    bool   `json:"me"`
	Emoji *Emoji `json:"emoji"`
}

// MessageActivity is sent with Rich Presence-related chat embeds
type MessageActivity struct {
	Type    MessageActivityType `json:"type"`
	PartyID string              `json:"party_id"`
}

// MessageActivityType is the type of message activity
type MessageActivityType int

// Constants for the different types of Message Activity
const (
	MessageActivityTypeJoin = iota + 1
	MessageActivityTypeSpectate
	MessageActivityTypeListen
	MessageActivityTypeJoinRequest
)

// MessageFlag describes an extra feature of the message
type MessageFlag int

// Constants for the different bit offsets of Message Flags
const (
	// This message has been published to subscribed channels (via Channel Following)
	MessageFlagCrossposted = 1 << iota
	// This message originated from a message in another channel (via Channel Following)
	MessageFlagIsCrosspost
	// Do not include any embeds when serializing this message
	MessageFlagSuppressEmbeds
)

// MessageApplication is sent with Rich Presence-related chat embeds
type MessageApplication struct {
	ID          string `json:"id"`
	CoverImage  string `json:"cover_image"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
	Name        string `json:"name"`
}

// MessageReference contains reference data sent with crossposted messages
type MessageReference struct {
	MessageID string `json:"message_id"`
	ChannelID string `json:"channel_id"`
	GuildID   string `json:"guild_id"`
}

// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() (content string) {
	content = m.Content

	for _, user := range m.Mentions {
		content = strings.NewReplacer(
			"<@"+user.ID+">", "@"+user.Username,
			"<@!"+user.ID+">", "@"+user.Username,
		).Replace(content)
	}
	return
}

var patternChannels = regexp.MustCompile("<#[^>]*>")

// ContentWithMoreMentionsReplaced will replace all @<id> mentions with the
// username of the mention, but also role IDs and more.
func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) {
	content = m.Content

	if !s.StateEnabled {
		content = m.ContentWithMentionsReplaced()
		return
	}

	channel, err := s.State.Channel(m.ChannelID)
	if err != nil {
		content = m.ContentWithMentionsReplaced()
		return
	}

	for _, user := range m.Mentions {
		nick := user.Username

		member, err := s.State.Member(channel.GuildID, user.ID)
		if err == nil && member.Nick != "" {
			nick = member.Nick
		}

		content = strings.NewReplacer(
			"<@"+user.ID+">", "@"+user.Username,
			"<@!"+user.ID+">", "@"+nick,
		).Replace(content)
	}
	for _, roleID := range m.MentionRoles {
		role, err := s.State.Role(channel.GuildID, roleID)
		if err != nil || !role.Mentionable {
			continue
		}

		content = strings.Replace(content, "<@&"+role.ID+">", "@"+role.Name, -1)
	}

	content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string {
		channel, err := s.State.Channel(mention[2 : len(mention)-1])
		if err != nil || channel.Type == ChannelTypeGuildVoice {
			return mention
		}

		return "#" + channel.Name
	})
	return
}
<|endoftext|>


<commit_before>package modules

import (
	"fmt"

	"bitbucket.org/cihangirsavas/gene/generators/folders"
	"bitbucket.org/cihangirsavas/gene/generators/handlers"
	"bitbucket.org/cihangirsavas/gene/schema"

	"bitbucket.org/cihangirsavas/gene/stringext"
)

type Module struct {
	schema *schema.Schema
}

func NewModule(s *schema.Schema) *Module {
	return &Module{schema: s}
}

func (m *Module) Create() error {
	rootPath := "./"

	// first ensure that we have the correct folder structure for our system
	if err := folders.EnsureFolders(
		rootPath, // root folder
		folders.FolderStucture,
	); err != nil {
		return err
	}

	// create the module folder structure
	if err := folders.EnsureFolders(
		rootPath, // root folder
		createModuleStructure(stringext.ToLowerFirst(
			m.schema.Title,
		)),
	); err != nil {
		return err
	}

	if err := handlers.Generate(rootPath, m.schema.Title); err != nil {
		return err
	}

	if err := m.GenerateMainFile(rootPath); err != nil {
		return err
	}

	return nil
}

var moduleFolderStucture = []string{
	"gene/modules/%[1]s",
	"gene/modules/%[1]s/api",
	"gene/modules/%[1]s/%[1]s",
	"gene/modules/%[1]s/cmd",
	"gene/modules/%[1]s/cmd/%[1]s",
	"gene/modules/%[1]s/tests",
	"gene/modules/%[1]s/errors",
	"gene/modules/%[1]s/handlers",
}

func createModuleStructure(name string) []string {
	modified := make([]string, len(moduleFolderStucture))
	for i, str := range moduleFolderStucture {
		modified[i] = fmt.Sprintf(str, name)
	}

	return modified
}
<commit_msg>Module: added model creation into  module creator<commit_after>package modules

import (
	"fmt"

	"bitbucket.org/cihangirsavas/gene/generators/folders"
	"bitbucket.org/cihangirsavas/gene/generators/handlers"
	"bitbucket.org/cihangirsavas/gene/generators/models"
	"bitbucket.org/cihangirsavas/gene/schema"

	"bitbucket.org/cihangirsavas/gene/stringext"
)

type Module struct {
	schema *schema.Schema
}

func NewModule(s *schema.Schema) *Module {
	return &Module{schema: s}
}

func (m *Module) Create() error {
	rootPath := "./"

	// first ensure that we have the correct folder structure for our system
	if err := folders.EnsureFolders(
		rootPath, // root folder
		folders.FolderStucture,
	); err != nil {
		return err
	}

	// create the module folder structure
	if err := folders.EnsureFolders(
		rootPath, // root folder
		createModuleStructure(stringext.ToLowerFirst(
			m.schema.Title,
		)),
	); err != nil {
		return err
	}

	if err := models.Generate(rootPath, m.schema); err != nil {
		return err
	}

	if err := handlers.Generate(rootPath, m.schema.Title); err != nil {
		return err
	}

	if err := m.GenerateMainFile(rootPath); err != nil {
		return err
	}

	return nil
}

var moduleFolderStucture = []string{
	"gene/modules/%[1]s",
	"gene/modules/%[1]s/api",
	"gene/modules/%[1]s/%[1]s",
	"gene/modules/%[1]s/cmd",
	"gene/modules/%[1]s/cmd/%[1]s",
	"gene/modules/%[1]s/tests",
	"gene/modules/%[1]s/errors",
	"gene/modules/%[1]s/handlers",
}

func createModuleStructure(name string) []string {
	modified := make([]string, len(moduleFolderStucture))
	for i, str := range moduleFolderStucture {
		modified[i] = fmt.Sprintf(str, name)
	}

	return modified
}
<|endoftext|>


<commit_before>package pcp

import (
	"errors"
	"hash/fnv"
)

// MetricType is an enumerated type representing all valid types for a metric
type MetricType int32

// Possible values for a MetricType
const (
	NoSupportType       MetricType = iota
	Int32Type           MetricType = iota
	Uint32Type          MetricType = iota
	Int64Type           MetricType = iota
	Uint64Type          MetricType = iota
	FloatType           MetricType = iota
	DoubleType          MetricType = iota
	StringType          MetricType = iota
	AggregateType       MetricType = iota
	AggregateStaticType MetricType = iota
	EventType           MetricType = iota
	HighresEventType    MetricType = iota
	UnknownType         MetricType = iota
)

func (mt MetricType) String() string {
	switch mt {
	case NoSupportType:
		return "Type: No Support"
	case Int32Type:
		return "Type: Int32"
	case Int64Type:
		return "Type: Int64"
	case Uint32Type:
		return "Type: Uint32"
	case Uint64Type:
		return "Type: Uint64"
	case FloatType:
		return "Type: Float"
	case DoubleType:
		return "Type: Double"
	case StringType:
		return "Type: String"
	case AggregateType:
		return "Type: Aggregate"
	case AggregateStaticType:
		return "Type: Aggregate Static"
	case EventType:
		return "Type: Event"
	case HighresEventType:
		return "Type: Highres Event"
	case UnknownType:
		return "Type: Unknown"
	default:
		return "Type: Invalid"
	}
}

// MetricUnit is an enumerated type representing all possible values for a valid PCP unit
type MetricUnit int32

// SpaceUnit is an enumerated type representing all units for space
type SpaceUnit MetricUnit

// Possible values for SpaceUnit
const (
	ByteUnit     SpaceUnit = iota
	KilobyteUnit SpaceUnit = iota
	MegabyteUnit SpaceUnit = iota
	GigabyteUnit SpaceUnit = iota
	TerabyteUnit SpaceUnit = iota
	PetabyteUnit SpaceUnit = iota
	ExabyteUnit  SpaceUnit = iota
)

func (su SpaceUnit) String() string {
	switch su {
	case ByteUnit:
		return "Unit: Byte"
	case KilobyteUnit:
		return "Unit: Kilobyte"
	case MegabyteUnit:
		return "Unit: Megabyte"
	case GigabyteUnit:
		return "Unit: Gigabyte"
	case TerabyteUnit:
		return "Unit: Terabyte"
	case PetabyteUnit:
		return "Unit: Petabyte"
	case ExabyteUnit:
		return "Unit: Exabyte"
	default:
		return "Unit: Invalid SpaceUnit"
	}
}

// TimeUnit is an enumerated type representing all possible units for representing time
type TimeUnit MetricUnit

// Possible Values for TimeUnit
const (
	NanosecondUnit  TimeUnit = iota
	MicrosecondUnit TimeUnit = iota
	MillisecondUnit TimeUnit = iota
	SecondUnit      TimeUnit = iota
	MinuteUnit      TimeUnit = iota
	HourUnit        TimeUnit = iota
)

func (tu TimeUnit) String() string {
	switch tu {
	case NanosecondUnit:
		return "Unit: Nanosecond"
	case MicrosecondUnit:
		return "Unit: Microsecond"
	case MillisecondUnit:
		return "Unit: Millisecond"
	case SecondUnit:
		return "Unit: Second"
	case MinuteUnit:
		return "Unit: Minute"
	case HourUnit:
		return "Unit: Hour"
	default:
		return "Unit: Invalid TimeUnit"
	}
}

// CountUnit is a type representing a counted quantity
type CountUnit MetricUnit

// OneUnit represents the only CountUnit
const OneUnit CountUnit = iota

func (cu CountUnit) String() string {
	switch cu {
	case OneUnit:
		return "Unit: One"
	default:
		return "Unit: Invalid CounterUnit"
	}
}

// MetricSemantics represents an enumerated type representing the possible
// values for the semantics of a metric
type MetricSemantics int32

// Possible values for MetricSemantics
const (
	NoSemantics       MetricSemantics = iota
	CounterSemantics  MetricSemantics = iota
	InstantSemantics  MetricSemantics = iota
	DiscreteSemantics MetricSemantics = iota
)

func (ms MetricSemantics) String() string {
	switch ms {
	case NoSemantics:
		return "Semantics: None"
	case CounterSemantics:
		return "Semantics: Counter"
	case InstantSemantics:
		return "Semantics: Instant"
	case DiscreteSemantics:
		return "Semantics: Discrete"
	default:
		return "Semantics: Invalid"
	}
}

// Metric defines the general interface a type needs to implement to qualify
// as a valid PCP metric
type Metric interface {
	Val() interface{}           // gets the value of the metric
	Set(interface{}) error      // sets the value of the metric to a value, optionally returns an error on failure
	Type() MetricType           // gets the type of a metric
	Unit() MetricUnit           // gets the unit of a metric
	Semantics() MetricSemantics // gets the semantics for a metric
	Description() string        // gets the description of a metric
}

// generate a unique uint32 hash for a string
// NOTE: make sure this is as fast as possible
func getHash(s string) uint32 {
	h := fnv.New32a()
	h.Write([]byte(s))
	return h.Sum32()
}

// Instance wraps a PCP compatible Instance
type Instance struct {
	name  string
	id    uint32
	indom *InstanceDomain
}

// NewInstance generates a new Instance type based on the passed parameters
// the id is passed explicitly as it is assumed that this will be constructed
// after initializing the InstanceDomain
// this is not a part of the public API as this is not supposed to be used directly,
// but instead added using the AddInstance method of InstanceDomain
func newInstance(id uint32, name string, indom *InstanceDomain) *Instance {
	return &Instance{
		name, id, indom,
	}
}

// InstanceDomain wraps a PCP compatible instance domain
type InstanceDomain struct {
	id                          uint32
	name                        string
	instanceCache               map[uint32]*Instance // the instances for this InstanceDomain stored as a map
	shortHelpText, longHelpText string
}

// NOTE: this declaration alone doesn't make this usable
// it needs to be 'made' at the beginning of monitoring
var instanceDomainCache map[uint32]*InstanceDomain

// NOTE: this is different from parfait's idea of generating ids for InstanceDomains
// We simply generate a unique 32 bit hash for an instance domain name, and if it has not
// already been created, we create it, otherwise we return the already created version
func NewInstanceDomain(name string) *InstanceDomain {
	h := getHash(name)

	v, present := instanceDomainCache[h]
	if present {
		return v
	}

	instanceDomainCache[h] = &InstanceDomain{
		id:   h,
		name: name,
	}

	return instanceDomainCache[h]
}

// AddInstance adds a new instance to the current InstanceDomain
func (indom *InstanceDomain) AddInstance(name string) error {
	h := getHash(name)

	_, present := indom.instanceCache[h]
	if present {
		return errors.New("Instance with same name already created for the InstanceDomain")
	}

	ins := newInstance(h, name, indom)
	indom.instanceCache[h] = ins

	return nil
}
<commit_msg>InstanceDomain: fix construction<commit_after>package pcp

import (
	"errors"
	"hash/fnv"
)

// MetricType is an enumerated type representing all valid types for a metric
type MetricType int32

// Possible values for a MetricType
const (
	NoSupportType       MetricType = iota
	Int32Type           MetricType = iota
	Uint32Type          MetricType = iota
	Int64Type           MetricType = iota
	Uint64Type          MetricType = iota
	FloatType           MetricType = iota
	DoubleType          MetricType = iota
	StringType          MetricType = iota
	AggregateType       MetricType = iota
	AggregateStaticType MetricType = iota
	EventType           MetricType = iota
	HighresEventType    MetricType = iota
	UnknownType         MetricType = iota
)

func (mt MetricType) String() string {
	switch mt {
	case NoSupportType:
		return "Type: No Support"
	case Int32Type:
		return "Type: Int32"
	case Int64Type:
		return "Type: Int64"
	case Uint32Type:
		return "Type: Uint32"
	case Uint64Type:
		return "Type: Uint64"
	case FloatType:
		return "Type: Float"
	case DoubleType:
		return "Type: Double"
	case StringType:
		return "Type: String"
	case AggregateType:
		return "Type: Aggregate"
	case AggregateStaticType:
		return "Type: Aggregate Static"
	case EventType:
		return "Type: Event"
	case HighresEventType:
		return "Type: Highres Event"
	case UnknownType:
		return "Type: Unknown"
	default:
		return "Type: Invalid"
	}
}

// MetricUnit is an enumerated type representing all possible values for a valid PCP unit
type MetricUnit int32

// SpaceUnit is an enumerated type representing all units for space
type SpaceUnit MetricUnit

// Possible values for SpaceUnit
const (
	ByteUnit     SpaceUnit = iota
	KilobyteUnit SpaceUnit = iota
	MegabyteUnit SpaceUnit = iota
	GigabyteUnit SpaceUnit = iota
	TerabyteUnit SpaceUnit = iota
	PetabyteUnit SpaceUnit = iota
	ExabyteUnit  SpaceUnit = iota
)

func (su SpaceUnit) String() string {
	switch su {
	case ByteUnit:
		return "Unit: Byte"
	case KilobyteUnit:
		return "Unit: Kilobyte"
	case MegabyteUnit:
		return "Unit: Megabyte"
	case GigabyteUnit:
		return "Unit: Gigabyte"
	case TerabyteUnit:
		return "Unit: Terabyte"
	case PetabyteUnit:
		return "Unit: Petabyte"
	case ExabyteUnit:
		return "Unit: Exabyte"
	default:
		return "Unit: Invalid SpaceUnit"
	}
}

// TimeUnit is an enumerated type representing all possible units for representing time
type TimeUnit MetricUnit

// Possible Values for TimeUnit
const (
	NanosecondUnit  TimeUnit = iota
	MicrosecondUnit TimeUnit = iota
	MillisecondUnit TimeUnit = iota
	SecondUnit      TimeUnit = iota
	MinuteUnit      TimeUnit = iota
	HourUnit        TimeUnit = iota
)

func (tu TimeUnit) String() string {
	switch tu {
	case NanosecondUnit:
		return "Unit: Nanosecond"
	case MicrosecondUnit:
		return "Unit: Microsecond"
	case MillisecondUnit:
		return "Unit: Millisecond"
	case SecondUnit:
		return "Unit: Second"
	case MinuteUnit:
		return "Unit: Minute"
	case HourUnit:
		return "Unit: Hour"
	default:
		return "Unit: Invalid TimeUnit"
	}
}

// CountUnit is a type representing a counted quantity
type CountUnit MetricUnit

// OneUnit represents the only CountUnit
const OneUnit CountUnit = iota

func (cu CountUnit) String() string {
	switch cu {
	case OneUnit:
		return "Unit: One"
	default:
		return "Unit: Invalid CounterUnit"
	}
}

// MetricSemantics represents an enumerated type representing the possible
// values for the semantics of a metric
type MetricSemantics int32

// Possible values for MetricSemantics
const (
	NoSemantics       MetricSemantics = iota
	CounterSemantics  MetricSemantics = iota
	InstantSemantics  MetricSemantics = iota
	DiscreteSemantics MetricSemantics = iota
)

func (ms MetricSemantics) String() string {
	switch ms {
	case NoSemantics:
		return "Semantics: None"
	case CounterSemantics:
		return "Semantics: Counter"
	case InstantSemantics:
		return "Semantics: Instant"
	case DiscreteSemantics:
		return "Semantics: Discrete"
	default:
		return "Semantics: Invalid"
	}
}

// Metric defines the general interface a type needs to implement to qualify
// as a valid PCP metric
type Metric interface {
	Val() interface{}           // gets the value of the metric
	Set(interface{}) error      // sets the value of the metric to a value, optionally returns an error on failure
	Type() MetricType           // gets the type of a metric
	Unit() MetricUnit           // gets the unit of a metric
	Semantics() MetricSemantics // gets the semantics for a metric
	Description() string        // gets the description of a metric
}

// generate a unique uint32 hash for a string
// NOTE: make sure this is as fast as possible
func getHash(s string) uint32 {
	h := fnv.New32a()
	h.Write([]byte(s))
	return h.Sum32()
}

// Instance wraps a PCP compatible Instance
type Instance struct {
	name  string
	id    uint32
	indom *InstanceDomain
}

// NewInstance generates a new Instance type based on the passed parameters
// the id is passed explicitly as it is assumed that this will be constructed
// after initializing the InstanceDomain
// this is not a part of the public API as this is not supposed to be used directly,
// but instead added using the AddInstance method of InstanceDomain
func newInstance(id uint32, name string, indom *InstanceDomain) *Instance {
	return &Instance{
		name, id, indom,
	}
}

// InstanceDomain wraps a PCP compatible instance domain
type InstanceDomain struct {
	id                          uint32
	name                        string
	instanceCache               map[uint32]*Instance // the instances for this InstanceDomain stored as a map
	shortHelpText, longHelpText string
}

// NOTE: this declaration alone doesn't make this usable
// it needs to be 'made' at the beginning of monitoring
var instanceDomainCache map[uint32]*InstanceDomain

// NewInstanceDomain creates a new instance domain or returns an already created one for the passed name
// NOTE: this is different from parfait's idea of generating ids for InstanceDomains
// We simply generate a unique 32 bit hash for an instance domain name, and if it has not
// already been created, we create it, otherwise we return the already created version
func NewInstanceDomain(name, shortDescription, longDescription string) *InstanceDomain {
	h := getHash(name)

	v, present := instanceDomainCache[h]
	if present {
		return v
	}

	cache := make(map[uint32]*Instance)
	instanceDomainCache[h] = &InstanceDomain{
		id:            h,
		name:          name,
		instanceCache: cache,
		shortHelpText: shortDescription,
		longHelpText:  longDescription,
	}

	return instanceDomainCache[h]
}

// AddInstance adds a new instance to the current InstanceDomain
func (indom *InstanceDomain) AddInstance(name string) error {
	h := getHash(name)

	_, present := indom.instanceCache[h]
	if present {
		return errors.New("Instance with same name already created for the InstanceDomain")
	}

	ins := newInstance(h, name, indom)
	indom.instanceCache[h] = ins

	return nil
}
<|endoftext|>


<commit_before>// Package gitlab provides authentication strategies using Gitlab.
package gitlab

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"

	"github.com/coreos/dex/connector"
	"github.com/sirupsen/logrus"
	"golang.org/x/oauth2"
)

const (
	scopeEmail = "user:email"
	scopeOrgs  = "read:org"
)

// Config holds configuration options for gilab logins.
type Config struct {
	BaseURL      string `json:"baseURL"`
	ClientID     string `json:"clientID"`
	ClientSecret string `json:"clientSecret"`
	RedirectURI  string `json:"redirectURI"`
}

type gitlabUser struct {
	ID       int
	Name     string
	Username string
	State    string
	Email    string
	IsAdmin  bool
}

type gitlabGroup struct {
	ID   int
	Name string
	Path string
}

// Open returns a strategy for logging in through GitLab.
func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
	if c.BaseURL == "" {
		c.BaseURL = "https://www.gitlab.com"
	}
	return &gitlabConnector{
		baseURL:      c.BaseURL,
		redirectURI:  c.RedirectURI,
		clientID:     c.ClientID,
		clientSecret: c.ClientSecret,
		logger:       logger,
	}, nil
}

type connectorData struct {
	// GitLab's OAuth2 tokens never expire. We don't need a refresh token.
	AccessToken string `json:"accessToken"`
}

var (
	_ connector.CallbackConnector = (*gitlabConnector)(nil)
	_ connector.RefreshConnector  = (*gitlabConnector)(nil)
)

type gitlabConnector struct {
	baseURL      string
	redirectURI  string
	org          string
	clientID     string
	clientSecret string
	logger       logrus.FieldLogger
}

func (c *gitlabConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
	gitlabScopes := []string{"api"}
	gitlabEndpoint := oauth2.Endpoint{AuthURL: c.baseURL + "/oauth/authorize", TokenURL: c.baseURL + "/oauth/token"}
	return &oauth2.Config{
		ClientID:     c.clientID,
		ClientSecret: c.clientSecret,
		Endpoint:     gitlabEndpoint,
		Scopes:       gitlabScopes,
		RedirectURL:  c.redirectURI,
	}
}

func (c *gitlabConnector) LoginURL(scopes connector.Scopes, callbackURL, state string) (string, error) {
	if c.redirectURI != callbackURL {
		return "", fmt.Errorf("expected callback URL %q did not match the URL in the config %q", c.redirectURI, callbackURL)
	}
	return c.oauth2Config(scopes).AuthCodeURL(state), nil
}

type oauth2Error struct {
	error            string
	errorDescription string
}

func (e *oauth2Error) Error() string {
	if e.errorDescription == "" {
		return e.error
	}
	return e.error + ": " + e.errorDescription
}

func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
	q := r.URL.Query()
	if errType := q.Get("error"); errType != "" {
		return identity, &oauth2Error{errType, q.Get("error_description")}
	}

	oauth2Config := c.oauth2Config(s)
	ctx := r.Context()

	token, err := oauth2Config.Exchange(ctx, q.Get("code"))
	if err != nil {
		return identity, fmt.Errorf("gitlab: failed to get token: %v", err)
	}

	client := oauth2Config.Client(ctx, token)

	user, err := c.user(ctx, client)
	if err != nil {
		return identity, fmt.Errorf("gitlab: get user: %v", err)
	}

	username := user.Name
	if username == "" {
		username = user.Email
	}
	identity = connector.Identity{
		UserID:        strconv.Itoa(user.ID),
		Username:      username,
		Email:         user.Email,
		EmailVerified: true,
	}

	if s.Groups {
		groups, err := c.groups(ctx, client)
		if err != nil {
			return identity, fmt.Errorf("gitlab: get groups: %v", err)
		}
		identity.Groups = groups
	}

	if s.OfflineAccess {
		data := connectorData{AccessToken: token.AccessToken}
		connData, err := json.Marshal(data)
		if err != nil {
			return identity, fmt.Errorf("marshal connector data: %v", err)
		}
		identity.ConnectorData = connData
	}

	return identity, nil
}

func (c *gitlabConnector) Refresh(ctx context.Context, s connector.Scopes, ident connector.Identity) (connector.Identity, error) {
	if len(ident.ConnectorData) == 0 {
		return ident, errors.New("no upstream access token found")
	}

	var data connectorData
	if err := json.Unmarshal(ident.ConnectorData, &data); err != nil {
		return ident, fmt.Errorf("gitlab: unmarshal access token: %v", err)
	}

	client := c.oauth2Config(s).Client(ctx, &oauth2.Token{AccessToken: data.AccessToken})
	user, err := c.user(ctx, client)
	if err != nil {
		return ident, fmt.Errorf("gitlab: get user: %v", err)
	}

	username := user.Name
	if username == "" {
		username = user.Email
	}
	ident.Username = username
	ident.Email = user.Email

	if s.Groups {
		groups, err := c.groups(ctx, client)
		if err != nil {
			return ident, fmt.Errorf("gitlab: get groups: %v", err)
		}
		ident.Groups = groups
	}
	return ident, nil
}

// user queries the GitLab API for profile information using the provided client. The HTTP
// client is expected to be constructed by the golang.org/x/oauth2 package, which inserts
// a bearer token as part of the request.
func (c *gitlabConnector) user(ctx context.Context, client *http.Client) (gitlabUser, error) {
	var u gitlabUser
	req, err := http.NewRequest("GET", c.baseURL+"/api/v3/user", nil)
	if err != nil {
		return u, fmt.Errorf("gitlab: new req: %v", err)
	}
	req = req.WithContext(ctx)
	resp, err := client.Do(req)
	if err != nil {
		return u, fmt.Errorf("gitlab: get URL %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return u, fmt.Errorf("gitlab: read body: %v", err)
		}
		return u, fmt.Errorf("%s: %s", resp.Status, body)
	}

	if err := json.NewDecoder(resp.Body).Decode(&u); err != nil {
		return u, fmt.Errorf("failed to decode response: %v", err)
	}
	return u, nil
}

// groups queries the GitLab API for group membership.
//
// The HTTP passed client is expected to be constructed by the golang.org/x/oauth2 package,
// which inserts a bearer token as part of the request.
func (c *gitlabConnector) groups(ctx context.Context, client *http.Client) ([]string, error) {

	apiURL := c.baseURL + "/api/v3/groups"

	reNext := regexp.MustCompile("<(.*)>; rel=\"next\"")
	reLast := regexp.MustCompile("<(.*)>; rel=\"last\"")

	groups := []string{}
	var gitlabGroups []gitlabGroup
	for {
		// 100 is the maximum number for per_page that allowed by gitlab
		req, err := http.NewRequest("GET", apiURL, nil)
		if err != nil {
			return nil, fmt.Errorf("gitlab: new req: %v", err)
		}
		req = req.WithContext(ctx)
		resp, err := client.Do(req)
		if err != nil {
			return nil, fmt.Errorf("gitlab: get groups: %v", err)
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			body, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return nil, fmt.Errorf("gitlab: read body: %v", err)
			}
			return nil, fmt.Errorf("%s: %s", resp.Status, body)
		}

		if err := json.NewDecoder(resp.Body).Decode(&gitlabGroups); err != nil {
			return nil, fmt.Errorf("gitlab: unmarshal groups: %v", err)
		}

		for _, group := range gitlabGroups {
			groups = append(groups, group.Name)
		}

		link := resp.Header.Get("Link")

		if len(reLast.FindStringSubmatch(link)) > 1 {
			lastPageURL := reLast.FindStringSubmatch(link)[1]

			if apiURL == lastPageURL {
				break
			}
		} else {
			break
		}

		if len(reNext.FindStringSubmatch(link)) > 1 {
			apiURL = reNext.FindStringSubmatch(link)[1]
		} else {
			break
		}

	}
	return groups, nil
}
<commit_msg>connector/gitlab: correct scope strings, better default<commit_after>// Package gitlab provides authentication strategies using Gitlab.
package gitlab

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"

	"github.com/coreos/dex/connector"
	"github.com/sirupsen/logrus"
	"golang.org/x/oauth2"
)

const (
	// https://docs.gitlab.com/ee/integration/oauth_provider.html#authorized-applications
	scopeUser = "read_user"
	scopeAPI  = "api"
)

// Config holds configuration options for gilab logins.
type Config struct {
	BaseURL      string `json:"baseURL"`
	ClientID     string `json:"clientID"`
	ClientSecret string `json:"clientSecret"`
	RedirectURI  string `json:"redirectURI"`
}

type gitlabUser struct {
	ID       int
	Name     string
	Username string
	State    string
	Email    string
	IsAdmin  bool
}

type gitlabGroup struct {
	ID   int
	Name string
	Path string
}

// Open returns a strategy for logging in through GitLab.
func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
	if c.BaseURL == "" {
		c.BaseURL = "https://www.gitlab.com"
	}
	return &gitlabConnector{
		baseURL:      c.BaseURL,
		redirectURI:  c.RedirectURI,
		clientID:     c.ClientID,
		clientSecret: c.ClientSecret,
		logger:       logger,
	}, nil
}

type connectorData struct {
	// GitLab's OAuth2 tokens never expire. We don't need a refresh token.
	AccessToken string `json:"accessToken"`
}

var (
	_ connector.CallbackConnector = (*gitlabConnector)(nil)
	_ connector.RefreshConnector  = (*gitlabConnector)(nil)
)

type gitlabConnector struct {
	baseURL      string
	redirectURI  string
	org          string
	clientID     string
	clientSecret string
	logger       logrus.FieldLogger
}

func (c *gitlabConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
	gitlabScopes := []string{scopeUser}
	if scopes.Groups {
		gitlabScopes = []string{scopeAPI}
	}

	gitlabEndpoint := oauth2.Endpoint{AuthURL: c.baseURL + "/oauth/authorize", TokenURL: c.baseURL + "/oauth/token"}
	return &oauth2.Config{
		ClientID:     c.clientID,
		ClientSecret: c.clientSecret,
		Endpoint:     gitlabEndpoint,
		Scopes:       gitlabScopes,
		RedirectURL:  c.redirectURI,
	}
}

func (c *gitlabConnector) LoginURL(scopes connector.Scopes, callbackURL, state string) (string, error) {
	if c.redirectURI != callbackURL {
		return "", fmt.Errorf("expected callback URL %q did not match the URL in the config %q", c.redirectURI, callbackURL)
	}
	return c.oauth2Config(scopes).AuthCodeURL(state), nil
}

type oauth2Error struct {
	error            string
	errorDescription string
}

func (e *oauth2Error) Error() string {
	if e.errorDescription == "" {
		return e.error
	}
	return e.error + ": " + e.errorDescription
}

func (c *gitlabConnector) HandleCallback(s connector.Scopes, r *http.Request) (identity connector.Identity, err error) {
	q := r.URL.Query()
	if errType := q.Get("error"); errType != "" {
		return identity, &oauth2Error{errType, q.Get("error_description")}
	}

	oauth2Config := c.oauth2Config(s)
	ctx := r.Context()

	token, err := oauth2Config.Exchange(ctx, q.Get("code"))
	if err != nil {
		return identity, fmt.Errorf("gitlab: failed to get token: %v", err)
	}

	client := oauth2Config.Client(ctx, token)

	user, err := c.user(ctx, client)
	if err != nil {
		return identity, fmt.Errorf("gitlab: get user: %v", err)
	}

	username := user.Name
	if username == "" {
		username = user.Email
	}
	identity = connector.Identity{
		UserID:        strconv.Itoa(user.ID),
		Username:      username,
		Email:         user.Email,
		EmailVerified: true,
	}

	if s.Groups {
		groups, err := c.groups(ctx, client)
		if err != nil {
			return identity, fmt.Errorf("gitlab: get groups: %v", err)
		}
		identity.Groups = groups
	}

	if s.OfflineAccess {
		data := connectorData{AccessToken: token.AccessToken}
		connData, err := json.Marshal(data)
		if err != nil {
			return identity, fmt.Errorf("marshal connector data: %v", err)
		}
		identity.ConnectorData = connData
	}

	return identity, nil
}

func (c *gitlabConnector) Refresh(ctx context.Context, s connector.Scopes, ident connector.Identity) (connector.Identity, error) {
	if len(ident.ConnectorData) == 0 {
		return ident, errors.New("no upstream access token found")
	}

	var data connectorData
	if err := json.Unmarshal(ident.ConnectorData, &data); err != nil {
		return ident, fmt.Errorf("gitlab: unmarshal access token: %v", err)
	}

	client := c.oauth2Config(s).Client(ctx, &oauth2.Token{AccessToken: data.AccessToken})
	user, err := c.user(ctx, client)
	if err != nil {
		return ident, fmt.Errorf("gitlab: get user: %v", err)
	}

	username := user.Name
	if username == "" {
		username = user.Email
	}
	ident.Username = username
	ident.Email = user.Email

	if s.Groups {
		groups, err := c.groups(ctx, client)
		if err != nil {
			return ident, fmt.Errorf("gitlab: get groups: %v", err)
		}
		ident.Groups = groups
	}
	return ident, nil
}

// user queries the GitLab API for profile information using the provided client. The HTTP
// client is expected to be constructed by the golang.org/x/oauth2 package, which inserts
// a bearer token as part of the request.
func (c *gitlabConnector) user(ctx context.Context, client *http.Client) (gitlabUser, error) {
	var u gitlabUser
	req, err := http.NewRequest("GET", c.baseURL+"/api/v4/user", nil)
	if err != nil {
		return u, fmt.Errorf("gitlab: new req: %v", err)
	}
	req = req.WithContext(ctx)
	resp, err := client.Do(req)
	if err != nil {
		return u, fmt.Errorf("gitlab: get URL %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return u, fmt.Errorf("gitlab: read body: %v", err)
		}
		return u, fmt.Errorf("%s: %s", resp.Status, body)
	}

	if err := json.NewDecoder(resp.Body).Decode(&u); err != nil {
		return u, fmt.Errorf("failed to decode response: %v", err)
	}
	return u, nil
}

// groups queries the GitLab API for group membership.
//
// The HTTP passed client is expected to be constructed by the golang.org/x/oauth2 package,
// which inserts a bearer token as part of the request.
func (c *gitlabConnector) groups(ctx context.Context, client *http.Client) ([]string, error) {

	apiURL := c.baseURL + "/api/v4/groups"

	reNext := regexp.MustCompile("<(.*)>; rel=\"next\"")
	reLast := regexp.MustCompile("<(.*)>; rel=\"last\"")

	groups := []string{}
	var gitlabGroups []gitlabGroup
	for {
		// 100 is the maximum number for per_page that allowed by gitlab
		req, err := http.NewRequest("GET", apiURL, nil)
		if err != nil {
			return nil, fmt.Errorf("gitlab: new req: %v", err)
		}
		req = req.WithContext(ctx)
		resp, err := client.Do(req)
		if err != nil {
			return nil, fmt.Errorf("gitlab: get groups: %v", err)
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			body, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return nil, fmt.Errorf("gitlab: read body: %v", err)
			}
			return nil, fmt.Errorf("%s: %s", resp.Status, body)
		}

		if err := json.NewDecoder(resp.Body).Decode(&gitlabGroups); err != nil {
			return nil, fmt.Errorf("gitlab: unmarshal groups: %v", err)
		}

		for _, group := range gitlabGroups {
			groups = append(groups, group.Name)
		}

		link := resp.Header.Get("Link")

		if len(reLast.FindStringSubmatch(link)) > 1 {
			lastPageURL := reLast.FindStringSubmatch(link)[1]

			if apiURL == lastPageURL {
				break
			}
		} else {
			break
		}

		if len(reNext.FindStringSubmatch(link)) > 1 {
			apiURL = reNext.FindStringSubmatch(link)[1]
		} else {
			break
		}

	}
	return groups, nil
}
<|endoftext|>


<commit_before>// Package metrics is a go library for sampling, counting and timing go code
// to be output in the l2met format.
package metrics

import (
	"log"
	"os"
)

// Logger is the logger to use when printing metrics. By default, metrics are printed
// to Stdout.
var Logger = log.New(os.Stdout, "", 0)

func Count(metric string, v interface{}) {
	printMetric(MetricCount, metric, v, "")
}

func Sample(metric string, v interface{}, units string) {
	printMetric(MetricSample, metric, v, units)
}

func Measure(metric string, v interface{}, units string) {
	printMetric(MetricMeasure, metric, v, units)
}

func printMetric(t MetricType, metric string, v interface{}, units string) {
	m := &Metric{Name: metric, Type: t, Value: v, Units: units}
	m.Print()
}
<commit_msg>Namespace.<commit_after>// Package metrics is a go library for sampling, counting and timing go code
// to be output in the l2met format.
package metrics

import (
	"fmt"
	"log"
	"os"
)

type Namespace string

// Logger is the logger to use when printing metrics. By default, metrics are printed
// to Stdout.
var Logger = log.New(os.Stdout, "", 0)

// The root namespace.
var root Namespace = ""

func (n Namespace) Count(metric string, v interface{}) {
	n.print(MetricCount, metric, v, "")
}

func (n Namespace) Sample(metric string, v interface{}, units string) {
	n.print(MetricSample, metric, v, units)
}

func (n Namespace) Measure(metric string, v interface{}, units string) {
	n.print(MetricMeasure, metric, v, units)
}

func (n Namespace) print(t MetricType, metric string, v interface{}, units string) {
	if n != "" {
		metric = fmt.Sprintf("%s.%s", n, metric)
	}
	m := &Metric{Name: metric, Type: t, Value: v, Units: units}
	m.Print()
}

func Count(metric string, v interface{}) {
	root.Count(metric, v)
}

func Sample(metric string, v interface{}, units string) {
	root.Sample(metric, v, units)
}

func Measure(metric string, v interface{}, units string) {
	root.Measure(metric, v, units)
}
<|endoftext|>


<commit_before>package handlers

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"code.cloudfoundry.org/lager"
	"github.com/cloudfoundry/hm9000/store"
	"code.cloudfoundry.org/clock"
)

type bulkHandler struct {
	logger lager.Logger
	store  store.Store
	clock  clock.Clock
}

type AppStateRequest struct {
	AppGuid    string `json:"droplet"`
	AppVersion string `json:"version"`
}

func NewBulkAppStateHandler(logger lager.Logger, store store.Store, clock clock.Clock) http.Handler {
	return &bulkHandler{
		logger: logger,
		store:  store,
		clock:  clock,
	}
}

func (handler *bulkHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	startTime := time.Now()
	requests := make([]AppStateRequest, 0)

	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		handler.logger.Error("Failed to handle bulk_app_state request", err)
		w.Write([]byte("{}"))
	}

	err = json.Unmarshal(bodyBytes, &requests)
	if err != nil {
		handler.logger.Error("Failed to handle bulk_app_state request", err, lager.Data{
			"payload":      string(bodyBytes),
			"elapsed time": fmt.Sprintf("%s", time.Since(startTime)),
		})
		w.Write([]byte("{}"))
		return
	}

	err = handler.store.VerifyFreshness(handler.clock.Now())
	if err != nil {
		handler.logger.Error("Failed to handle bulk_app_state request", err, lager.Data{
			"payload":      string(bodyBytes),
			"elapsed time": fmt.Sprintf("%s", time.Since(startTime)),
		})
		w.Write([]byte("{}"))
		return
	}

	var apps = make(map[string]interface{})
	for _, request := range requests {
		app, err := handler.store.GetApp(request.AppGuid, request.AppVersion)
		if err == nil {
			apps[app.AppGuid] = app
		}
	}

	appsJson, err := json.Marshal(apps)
	if err != nil {
		handler.logger.Error("Failed to handle bulk_app_state request", err, lager.Data{
			"payload":      string(bodyBytes),
			"elapsed time": fmt.Sprintf("%s", time.Since(startTime)),
		})
	}

	w.Write([]byte(appsJson))
}
<commit_msg>Make error messages for bulk app state handling more meaningful<commit_after>package handlers

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"code.cloudfoundry.org/lager"
	"github.com/cloudfoundry/hm9000/store"
	"code.cloudfoundry.org/clock"
)

type bulkHandler struct {
	logger lager.Logger
	store  store.Store
	clock  clock.Clock
}

type AppStateRequest struct {
	AppGuid    string `json:"droplet"`
	AppVersion string `json:"version"`
}

func NewBulkAppStateHandler(logger lager.Logger, store store.Store, clock clock.Clock) http.Handler {
	return &bulkHandler{
		logger: logger,
		store:  store,
		clock:  clock,
	}
}

func (handler *bulkHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	startTime := time.Now()
	requests := make([]AppStateRequest, 0)

	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		handler.logger.Error("Failed to handle bulk_app_state request", err)
		w.Write([]byte("{}"))
	}

	err = json.Unmarshal(bodyBytes, &requests)
	if err != nil {
		handler.logger.Error("Failed to unmarshal bulk app state request", err, lager.Data{
			"payload":      string(bodyBytes),
			"elapsed time": fmt.Sprintf("%s", time.Since(startTime)),
		})
		w.Write([]byte("{}"))
		return
	}

	err = handler.store.VerifyFreshness(handler.clock.Now())
	if err != nil {
		handler.logger.Error("Failed to verify freshness while handling bulk app state request", err, lager.Data{
			"payload":      string(bodyBytes),
			"elapsed time": fmt.Sprintf("%s", time.Since(startTime)),
		})
		w.Write([]byte("{}"))
		return
	}

	var apps = make(map[string]interface{})
	for _, request := range requests {
		app, err := handler.store.GetApp(request.AppGuid, request.AppVersion)
		if err == nil {
			apps[app.AppGuid] = app
		}
	}

	appsJson, err := json.Marshal(apps)
	if err != nil {
		handler.logger.Error("Failed to marshal app states while handling bulk app state request", err, lager.Data{
			"payload":      string(bodyBytes),
			"elapsed time": fmt.Sprintf("%s", time.Since(startTime)),
		})
	}

	w.Write([]byte(appsJson))
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/codegangsta/cli"
	_ "github.com/go-sql-driver/mysql"
	"github.com/karamani/iostreams"
)

var (
	debugMode           bool
	queryArg            string
	execArg             string
	connectionStringArg string
	formatArg           string
	fakeMode            bool
	isExec              bool
)

func main() {
	app := cli.NewApp()
	app.Name = "massquery"
	app.Usage = "massquery"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "debug mode",
			EnvVar:      "MASSQUERY_DEBUG",
			Destination: &debugMode,
		},
		cli.StringFlag{
			Name:        "query",
			Usage:       "sql-query",
			Destination: &queryArg,
		},
		cli.StringFlag{
			Name:        "exec",
			Usage:       "exec-string (insert, update or delete)",
			Destination: &execArg,
		},
		cli.StringFlag{
			Name:        "cnn",
			Usage:       "db connection string",
			EnvVar:      "MASSQUERY_CNN",
			Destination: &connectionStringArg,
		},
		cli.StringFlag{
			Name:        "format",
			Usage:       "output format",
			Destination: &formatArg,
		},
	}

	app.Action = func(c *cli.Context) {

		if len(connectionStringArg) == 0 {
			log.Println("[ERROR] 'cnn' arg is required")
			return
		}

		if len(queryArg) == 0 && len(execArg) == 0 {
			log.Println("[ERROR] It should be one of the arguments: 'query' or 'exec'")
			return
		}

		query := queryArg
		isExec = len(query) == 0
		if isExec {
			query = execArg
		}

		if !iostreams.StdinReady() {
			processOneQuery(connectionStringArg, query, isExec, "")
			return
		}

		// this func's called for each stdin's row
		process := func(row []byte) error {

			debug(string(row))

			params := strings.Split(string(row), "\t")
			rowQuery := parameterizedString(query, "{%d}", params)
			rowCnn := parameterizedString(connectionStringArg, "{%d}", params)

			debug("connection:" + rowCnn)
			debug("query:" + rowQuery)

			processOneQuery(rowCnn, rowQuery, isExec, string(row))

			return nil
		}

		if err := iostreams.ProcessStdin(process); err != nil {
			log.Panicln(err.Error())
		}
	}

	app.Run(os.Args)
}

func processOneQuery(cnn, query string, isExec bool, input string) {
	res, err := runQuery(cnn, query, isExec)
	if err != nil {
		log.Println(err.Error())
		printRes(formatRes(formatArg, input, cnn, "error", nil))
	} else {
		for _, resrow := range res {
			printRes(formatRes(formatArg, input, cnn, "success", resrow))
		}
	}
}

func parameterizedString(s, tpl string, params []string) string {
	res := s
	for i, param := range params {
		t := fmt.Sprintf(tpl, i)
		res = strings.Replace(res, t, param, -1)
	}
	return res
}

func formatRes(format, input, cnn, status string, values []string) string {

	res := strings.Join(values, "\t")

	if len(format) > 0 {
		s := format

		// remove unnecessary quotes from command line
		s = strings.Replace(s, "\\t", "\t", -1)
		s = strings.Replace(s, "\\n", "\n", -1)

		s = strings.Replace(s, "{input}", input, -1)
		s = strings.Replace(s, "{res}", res, -1)
		s = strings.Replace(s, "{cnn}", cnn, -1)
		s = strings.Replace(s, "{status}", status, -1)
		s = parameterizedString(s, "{res%d}", values)

		res = s
	}

	return res
}

func printRes(s string) {
	if len(s) > 0 {
		fmt.Println(s)
	}
}

func runQuery(connectionString, query string, isExec bool) (res [][]string, resErr error) {

	res, resErr = nil, nil

	db, resErr := sql.Open("mysql", connectionString)
	if resErr != nil {
		return
	}
	defer db.Close()

	resErr = db.Ping()
	if resErr != nil {
		return
	}

	if isExec {

		resErr = func() error {
			execRes, err := db.Exec(query)
			if err != nil {
				return err
			}
			affected, err := execRes.RowsAffected()
			if err != nil {
				return err
			}
			lastInsertID, err := execRes.LastInsertId()
			if err != nil {
				return err
			}
			res = append(res, []string{
				strconv.FormatInt(affected, 10),
				strconv.FormatInt(lastInsertID, 10),
			})
			return nil
		}()

	} else {

		resErr = func() error {

			rows, err := db.Query(query)
			if err != nil {
				return err
			}
			defer rows.Close()

			cols, err := rows.Columns()
			if err != nil {
				return err
			}

			container := newScanContainer(len(cols))
			for rows.Next() {
				if err := rows.Scan(container.Pointers...); err != nil {
					return err
				}
				res = append(res, container.AsStrings())
			}

			if err := rows.Err(); err != nil {
				res = nil
				return err
			}
			return nil
		}()
	}

	return
}

func debug(format string, args ...interface{}) {
	if debugMode {
		log.Printf("[DEBUG] "+format+"\n", args...)
	}
}
<commit_msg>Small refactoring in func processOneQuery<commit_after>package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/codegangsta/cli"
	_ "github.com/go-sql-driver/mysql"
	"github.com/karamani/iostreams"
)

var (
	debugMode           bool
	queryArg            string
	execArg             string
	connectionStringArg string
	formatArg           string
	fakeMode            bool
	isExec              bool
)

func main() {
	app := cli.NewApp()
	app.Name = "massquery"
	app.Usage = "massquery"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "debug mode",
			EnvVar:      "MASSQUERY_DEBUG",
			Destination: &debugMode,
		},
		cli.StringFlag{
			Name:        "query",
			Usage:       "sql-query",
			Destination: &queryArg,
		},
		cli.StringFlag{
			Name:        "exec",
			Usage:       "exec-string (insert, update or delete)",
			Destination: &execArg,
		},
		cli.StringFlag{
			Name:        "cnn",
			Usage:       "db connection string",
			EnvVar:      "MASSQUERY_CNN",
			Destination: &connectionStringArg,
		},
		cli.StringFlag{
			Name:        "format",
			Usage:       "output format",
			Destination: &formatArg,
		},
	}

	app.Action = func(c *cli.Context) {

		if len(connectionStringArg) == 0 {
			log.Println("[ERROR] 'cnn' arg is required")
			return
		}

		if len(queryArg) == 0 && len(execArg) == 0 {
			log.Println("[ERROR] It should be one of the arguments: 'query' or 'exec'")
			return
		}

		query := queryArg
		isExec = len(query) == 0
		if isExec {
			query = execArg
		}

		if !iostreams.StdinReady() {
			processOneQuery(connectionStringArg, query, isExec, "")
			return
		}

		// this func's called for each stdin's row
		process := func(row []byte) error {

			debug(string(row))

			params := strings.Split(string(row), "\t")
			rowQuery := parameterizedString(query, "{%d}", params)
			rowCnn := parameterizedString(connectionStringArg, "{%d}", params)

			debug("connection:" + rowCnn)
			debug("query:" + rowQuery)

			processOneQuery(rowCnn, rowQuery, isExec, string(row))

			return nil
		}

		if err := iostreams.ProcessStdin(process); err != nil {
			log.Panicln(err.Error())
		}
	}

	app.Run(os.Args)
}

func processOneQuery(cnn, query string, isExec bool, input string) {
	res, err := runQuery(cnn, query, isExec)
	if err != nil {
		log.Println(err.Error())
		printRes(formatRes(formatArg, input, cnn, "error", nil))
		return
	}

	for _, resrow := range res {
		printRes(formatRes(formatArg, input, cnn, "success", resrow))
	}
}

func parameterizedString(s, tpl string, params []string) string {
	res := s
	for i, param := range params {
		t := fmt.Sprintf(tpl, i)
		res = strings.Replace(res, t, param, -1)
	}
	return res
}

func formatRes(format, input, cnn, status string, values []string) string {

	res := strings.Join(values, "\t")

	if len(format) > 0 {
		s := format

		// remove unnecessary quotes from command line
		s = strings.Replace(s, "\\t", "\t", -1)
		s = strings.Replace(s, "\\n", "\n", -1)

		s = strings.Replace(s, "{input}", input, -1)
		s = strings.Replace(s, "{res}", res, -1)
		s = strings.Replace(s, "{cnn}", cnn, -1)
		s = strings.Replace(s, "{status}", status, -1)
		s = parameterizedString(s, "{res%d}", values)

		res = s
	}

	return res
}

func printRes(s string) {
	if len(s) > 0 {
		fmt.Println(s)
	}
}

func runQuery(connectionString, query string, isExec bool) (res [][]string, resErr error) {

	res, resErr = nil, nil

	db, resErr := sql.Open("mysql", connectionString)
	if resErr != nil {
		return
	}
	defer db.Close()

	resErr = db.Ping()
	if resErr != nil {
		return
	}

	if isExec {

		resErr = func() error {
			execRes, err := db.Exec(query)
			if err != nil {
				return err
			}
			affected, err := execRes.RowsAffected()
			if err != nil {
				return err
			}
			lastInsertID, err := execRes.LastInsertId()
			if err != nil {
				return err
			}
			res = append(res, []string{
				strconv.FormatInt(affected, 10),
				strconv.FormatInt(lastInsertID, 10),
			})
			return nil
		}()

	} else {

		resErr = func() error {

			rows, err := db.Query(query)
			if err != nil {
				return err
			}
			defer rows.Close()

			cols, err := rows.Columns()
			if err != nil {
				return err
			}

			container := newScanContainer(len(cols))
			for rows.Next() {
				if err := rows.Scan(container.Pointers...); err != nil {
					return err
				}
				res = append(res, container.AsStrings())
			}

			if err := rows.Err(); err != nil {
				res = nil
				return err
			}
			return nil
		}()
	}

	return
}

func debug(format string, args ...interface{}) {
	if debugMode {
		log.Printf("[DEBUG] "+format+"\n", args...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go-tour/tree"
	"fmt"
	"sort"
)

func Walk(t *tree.Tree, ch chan int) {
	ch <- t.Value
	if t.Left != nil {
		go Walk(t.Left, ch)
	}
	if t.Right != nil {
		go Walk(t.Right, ch)
	}
}

func Same(t1, t2 *tree.Tree) bool {
	ch := make(chan int)
	t1vals := make([]int, 10)
	t2vals := make([]int, 10)

	go Walk(t1, ch)
	for i := 0; i < 10; i++ {
		t1vals[i] = <-ch
	}
	go Walk(t2, ch)
	for i := 0; i < 10; i++ {
		t2vals[i] = <-ch
	}
	fmt.Println(t1vals)
	fmt.Println(t2vals)
	sort.Ints(t1vals)
	sort.Ints(t2vals)
	strt1 := fmt.Sprintf("%v", t1vals)
	strt2 := fmt.Sprintf("%v", t2vals)
	if strt1 == strt2 {
		return true
	} else {
		return false
	}
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))
}
<commit_msg>Update binarytree.go<commit_after>package main

import (
	"code.google.com/p/go-tour/tree"
	"fmt"
	"sort"
)

func Walk(t *tree.Tree, ch chan int) {
	ch <- t.Value
	if t.Left != nil {
		go Walk(t.Left, ch)
	}
	if t.Right != nil {
		go Walk(t.Right, ch)
	}
}

func Same(t1, t2 *tree.Tree) bool {
	ch := make(chan int)
	t1vals := make([]int, 10)
	t2vals := make([]int, 10)

	go Walk(t1, ch)
	for i := 0; i < 10; i++ {
		t1vals[i] = <-ch
	}
	go Walk(t2, ch)
	for i := 0; i < 10; i++ {
		t2vals[i] = <-ch
	}
	// the next few lines should be made a bit cleaner, you can't compare slices so I should use arrays instead
	fmt.Println(t1vals)
	fmt.Println(t2vals)
	sort.Ints(t1vals)
	sort.Ints(t2vals)
	strt1 := fmt.Sprintf("%v", t1vals)
	strt2 := fmt.Sprintf("%v", t2vals)
	if strt1 == strt2 {
		return true
	} else {
		return false
	}
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))
}
<|endoftext|>