<commit_before>// Package ccm implements a CCM, Counter with CBC-MAC
// as per RFC 3610.
//
// See https://tools.ietf.org/html/rfc3610
package ccm

import (
	"crypto/cipher"
	"crypto/subtle"
	"encoding/binary"
	"errors"
	"fmt"
	"math"
)

// ccm represents a Counter with CBC-MAC with a specific key.
type ccm struct {
	b cipher.Block
	M uint8
	L uint8
}

const ccmBlockSize = 16

// CCM is a block cipher in Counter with CBC-MAC mode.
// Providing authenticated encryption with associated data via the cipher.AEAD interface.
type CCM interface {
	cipher.AEAD
	// MaxLength returns the maxium length of plaintext in calls to Seal.
	// The maximum length of ciphertext in calls to Open is MaxLength()+Overhead().
	// The maximum length is related to CCM's `L` parameter (15-noncesize) and
	// is 1<<(8*L) - 1 (but also limited by the maxium size of an int).
	MaxLength() int
}

// NewCCM returns the given 128-bit block cipher wrapped in CCM.
// The tagsize must be an even integer between 4 and 16 inclusive
// and is used as CCM's `M` parameter.
// The noncesize must be an integer between 7 and 13 inclusive,
// 15-noncesize is used as CCM's `L` parameter.
func NewCCM(b cipher.Block, tagsize, noncesize int) (CCM, error) {
	if b.BlockSize() != ccmBlockSize {
		return nil, errors.New("ccm: NewCCM requires 128-bit block cipher")
	}
	if tagsize < 4 || tagsize > 16 || tagsize&1 != 0 {
		return nil, errors.New("ccm: tagsize must be 4, 6, 8, 10, 12, 14, or 16")
	}
	lensize := 15 - noncesize
	if lensize < 2 || lensize > 8 {
		return nil, errors.New("ccm: invalid noncesize")
	}
	c := &ccm{b: b, M: uint8(tagsize), L: uint8(lensize)}
	return c, nil
}

func (c *ccm) NonceSize() int { return 15 - int(c.L) }
func (c *ccm) Overhead() int  { return int(c.M) }
func (c *ccm) MaxLength() int { return maxlen(c.L, c.Overhead()) }

func maxlen(L uint8, tagsize int) int {
	max := (uint64(1) << (8 * L)) - 1
	if m64 := uint64(math.MaxInt64) - uint64(tagsize); L > 8 || max > m64 {
		max = m64 // The maximum lentgh on a 64bit arch
	}
	if max != uint64(int(max)) {
		return math.MaxInt32 - tagsize // We have only 32bit int's
	}
	return int(max)
}

// MaxNonceLength returns the maximum nonce length for a given plaintext length.
// A return value <= 0 indicates that plaintext length is too large for
// any nonce length.
func MaxNonceLength(pdatalen int) int {
	const tagsize = 16
	for L := 2; L <= 8; L++ {
		if maxlen(uint8(L), tagsize) >= pdatalen {
			return 15 - L
		}
	}
	return 0
}

func (c *ccm) cbcRound(mac, data []byte) {
	for i := 0; i < ccmBlockSize; i++ {
		mac[i] ^= data[i]
	}
	c.b.Encrypt(mac, mac)
}

func (c *ccm) cbcData(mac, data []byte) {
	for len(data) >= ccmBlockSize {
		c.cbcRound(mac, data[:ccmBlockSize])
		data = data[ccmBlockSize:]
	}
	if len(data) > 0 {
		var block [ccmBlockSize]byte
		copy(block[:], data)
		c.cbcRound(mac, block[:])
	}
}

func (c *ccm) tag(nonce, plaintext, adata []byte) ([]byte, error) {
	var mac [ccmBlockSize]byte

	if len(adata) > 0 {
		mac[0] |= 1 << 6
	}
	mac[0] |= (c.M - 2) << 2
	mac[0] |= c.L - 1
	if len(nonce) != c.NonceSize() {
		return nil, errors.New("ccm: Invalid nonce size")
	}
	if len(plaintext) > c.MaxLength() {
		return nil, errors.New("ccm: plaintext too large")
	}
	binary.BigEndian.PutUint64(mac[ccmBlockSize-8:], uint64(len(plaintext)))
	copy(mac[1:ccmBlockSize-c.L], nonce)
	c.b.Encrypt(mac[:], mac[:])

	var block [ccmBlockSize]byte
	if n := uint64(len(adata)); n > 0 {
		// First adata block includes adata length
		i := 2
		if n <= 0xfeff {
			binary.BigEndian.PutUint16(block[:i], uint16(n))
		} else {
			block[0] = 0xfe
			block[1] = 0xff
			if n < uint64(1<<32) {
				i = 2 + 4
				binary.BigEndian.PutUint32(block[2:i], uint32(n))
			} else {
				i = 2 + 8
				binary.BigEndian.PutUint64(block[2:i], uint64(n))
			}
		}
		i = copy(block[i:], adata)
		c.cbcRound(mac[:], block[:])
		c.cbcData(mac[:], adata[i:])
	}

	if len(plaintext) > 0 {
		c.cbcData(mac[:], plaintext)
	}

	return mac[:c.M], nil
}

// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
// From crypto/cipher/gcm.go
func sliceForAppend(in []byte, n int) (head, tail []byte) {
	if total := len(in) + n; cap(in) >= total {
		head = in[:total]
	} else {
		head = make([]byte, total)
		copy(head, in)
	}
	tail = head[len(in):]
	return
}

// Seal encrypts and authenticates plaintext, authenticates the
// additional data and appends the result to dst, returning the updated
// slice. The nonce must be NonceSize() bytes long and unique for all
// time, for a given key.
// The plaintext must be no longer than MaxLength() bytes long.
//
// The plaintext and dst may alias exactly or not at all.
func (c *ccm) Seal(dst, nonce, plaintext, adata []byte) []byte {
	tag, err := c.tag(nonce, plaintext, adata)
	if err != nil {
		// The cipher.AEAD interface doesn't allow for an error return.
		panic(err)
	}

	var iv, s0 [ccmBlockSize]byte
	iv[0] = c.L - 1
	copy(iv[1:ccmBlockSize-c.L], nonce)
	c.b.Encrypt(s0[:], iv[:])
	for i := 0; i < int(c.M); i++ {
		tag[i] ^= s0[i]
	}
	iv[len(iv)-1] |= 1
	stream := cipher.NewCTR(c.b, iv[:])
	ret, out := sliceForAppend(dst, len(plaintext)+int(c.M))
	stream.XORKeyStream(out, plaintext)
	copy(out[len(plaintext):], tag)
	return ret
}

var errOpen = errors.New("ccm: message authentication failed")

func (c *ccm) Open(dst, nonce, ciphertext, adata []byte) ([]byte, error) {
	if len(ciphertext) < int(c.M) {
		return nil, errors.New("ccm: ciphertext too short")
	}
	if len(ciphertext) > c.MaxLength()+c.Overhead() {
		return nil, errors.New("ccm: ciphertext too long")
	}

	tag := ciphertext[len(ciphertext)-int(c.M):]
	ciphertext = ciphertext[:len(ciphertext)-int(c.M)]

	var iv, s0 [ccmBlockSize]byte
	iv[0] = c.L - 1
	copy(iv[1:ccmBlockSize-c.L], nonce)
	c.b.Encrypt(s0[:], iv[:])
	for i := 0; i < int(c.M); i++ {
		tag[i] ^= s0[i]
	}
	iv[len(iv)-1] |= 1
	stream := cipher.NewCTR(c.b, iv[:])

	// Cannot decrypt directly to dst since we're not supposed to
	// reveal the plaintext to the caller if authentication fails.
	plaintext := make([]byte, len(ciphertext))
	stream.XORKeyStream(plaintext, ciphertext)
	expectedTag, err := c.tag(nonce, plaintext, adata)
	if err != nil {
		return nil, err
	}

	if subtle.ConstantTimeCompare(tag, expectedTag) != 1 {
		return nil, errors.New(fmt.Sprintf("ccm: t[%X] != et[%X]", tag, expectedTag))
		//return nil, errOpen
	}
	return append(dst, plaintext...), nil
}
<commit_msg>Fix for CCM cipher modifying the original ciphertext which prevented processing after a failed decryption.<commit_after>// Package ccm implements a CCM, Counter with CBC-MAC
// as per RFC 3610.
//
// See https://tools.ietf.org/html/rfc3610
package ccm

import (
	"crypto/cipher"
	"crypto/subtle"
	"encoding/binary"
	"errors"
	"fmt"
	"math"
)

// ccm represents a Counter with CBC-MAC with a specific key.
type ccm struct {
	b cipher.Block
	M uint8
	L uint8
}

const ccmBlockSize = 16

// CCM is a block cipher in Counter with CBC-MAC mode.
// Providing authenticated encryption with associated data via the cipher.AEAD interface.
type CCM interface {
	cipher.AEAD
	// MaxLength returns the maxium length of plaintext in calls to Seal.
	// The maximum length of ciphertext in calls to Open is MaxLength()+Overhead().
	// The maximum length is related to CCM's `L` parameter (15-noncesize) and
	// is 1<<(8*L) - 1 (but also limited by the maxium size of an int).
	MaxLength() int
}

// NewCCM returns the given 128-bit block cipher wrapped in CCM.
// The tagsize must be an even integer between 4 and 16 inclusive
// and is used as CCM's `M` parameter.
// The noncesize must be an integer between 7 and 13 inclusive,
// 15-noncesize is used as CCM's `L` parameter.
func NewCCM(b cipher.Block, tagsize, noncesize int) (CCM, error) {
	if b.BlockSize() != ccmBlockSize {
		return nil, errors.New("ccm: NewCCM requires 128-bit block cipher")
	}
	if tagsize < 4 || tagsize > 16 || tagsize&1 != 0 {
		return nil, errors.New("ccm: tagsize must be 4, 6, 8, 10, 12, 14, or 16")
	}
	lensize := 15 - noncesize
	if lensize < 2 || lensize > 8 {
		return nil, errors.New("ccm: invalid noncesize")
	}
	c := &ccm{b: b, M: uint8(tagsize), L: uint8(lensize)}
	return c, nil
}

func (c *ccm) NonceSize() int { return 15 - int(c.L) }
func (c *ccm) Overhead() int  { return int(c.M) }
func (c *ccm) MaxLength() int { return maxlen(c.L, c.Overhead()) }

func maxlen(L uint8, tagsize int) int {
	max := (uint64(1) << (8 * L)) - 1
	if m64 := uint64(math.MaxInt64) - uint64(tagsize); L > 8 || max > m64 {
		max = m64 // The maximum lentgh on a 64bit arch
	}
	if max != uint64(int(max)) {
		return math.MaxInt32 - tagsize // We have only 32bit int's
	}
	return int(max)
}

// MaxNonceLength returns the maximum nonce length for a given plaintext length.
// A return value <= 0 indicates that plaintext length is too large for
// any nonce length.
func MaxNonceLength(pdatalen int) int {
	const tagsize = 16
	for L := 2; L <= 8; L++ {
		if maxlen(uint8(L), tagsize) >= pdatalen {
			return 15 - L
		}
	}
	return 0
}

func (c *ccm) cbcRound(mac, data []byte) {
	for i := 0; i < ccmBlockSize; i++ {
		mac[i] ^= data[i]
	}
	c.b.Encrypt(mac, mac)
}

func (c *ccm) cbcData(mac, data []byte) {
	for len(data) >= ccmBlockSize {
		c.cbcRound(mac, data[:ccmBlockSize])
		data = data[ccmBlockSize:]
	}
	if len(data) > 0 {
		var block [ccmBlockSize]byte
		copy(block[:], data)
		c.cbcRound(mac, block[:])
	}
}

func (c *ccm) tag(nonce, plaintext, adata []byte) ([]byte, error) {
	var mac [ccmBlockSize]byte

	if len(adata) > 0 {
		mac[0] |= 1 << 6
	}
	mac[0] |= (c.M - 2) << 2
	mac[0] |= c.L - 1
	if len(nonce) != c.NonceSize() {
		return nil, errors.New("ccm: Invalid nonce size")
	}
	if len(plaintext) > c.MaxLength() {
		return nil, errors.New("ccm: plaintext too large")
	}
	binary.BigEndian.PutUint64(mac[ccmBlockSize-8:], uint64(len(plaintext)))
	copy(mac[1:ccmBlockSize-c.L], nonce)
	c.b.Encrypt(mac[:], mac[:])

	var block [ccmBlockSize]byte
	if n := uint64(len(adata)); n > 0 {
		// First adata block includes adata length
		i := 2
		if n <= 0xfeff {
			binary.BigEndian.PutUint16(block[:i], uint16(n))
		} else {
			block[0] = 0xfe
			block[1] = 0xff
			if n < uint64(1<<32) {
				i = 2 + 4
				binary.BigEndian.PutUint32(block[2:i], uint32(n))
			} else {
				i = 2 + 8
				binary.BigEndian.PutUint64(block[2:i], uint64(n))
			}
		}
		i = copy(block[i:], adata)
		c.cbcRound(mac[:], block[:])
		c.cbcData(mac[:], adata[i:])
	}

	if len(plaintext) > 0 {
		c.cbcData(mac[:], plaintext)
	}

	return mac[:c.M], nil
}

// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
// From crypto/cipher/gcm.go
func sliceForAppend(in []byte, n int) (head, tail []byte) {
	if total := len(in) + n; cap(in) >= total {
		head = in[:total]
	} else {
		head = make([]byte, total)
		copy(head, in)
	}
	tail = head[len(in):]
	return
}

// Seal encrypts and authenticates plaintext, authenticates the
// additional data and appends the result to dst, returning the updated
// slice. The nonce must be NonceSize() bytes long and unique for all
// time, for a given key.
// The plaintext must be no longer than MaxLength() bytes long.
//
// The plaintext and dst may alias exactly or not at all.
func (c *ccm) Seal(dst, nonce, plaintext, adata []byte) []byte {
	tag, err := c.tag(nonce, plaintext, adata)
	if err != nil {
		// The cipher.AEAD interface doesn't allow for an error return.
		panic(err)
	}

	var iv, s0 [ccmBlockSize]byte
	iv[0] = c.L - 1
	copy(iv[1:ccmBlockSize-c.L], nonce)
	c.b.Encrypt(s0[:], iv[:])
	for i := 0; i < int(c.M); i++ {
		tag[i] ^= s0[i]
	}
	iv[len(iv)-1] |= 1
	stream := cipher.NewCTR(c.b, iv[:])
	ret, out := sliceForAppend(dst, len(plaintext)+int(c.M))
	stream.XORKeyStream(out, plaintext)
	copy(out[len(plaintext):], tag)
	return ret
}

var errOpen = errors.New("ccm: message authentication failed")

func (c *ccm) Open(dst, nonce, ciphertext, adata []byte) ([]byte, error) {
	if len(ciphertext) < int(c.M) {
		return nil, errors.New("ccm: ciphertext too short")
	}
	if len(ciphertext) > c.MaxLength()+c.Overhead() {
		return nil, errors.New("ccm: ciphertext too long")
	}

	var tag = make([]byte, int(c.M), int(c.M))
	copy(tag, ciphertext[len(ciphertext)-int(c.M):])
	ciphertextWithoutTag := ciphertext[:len(ciphertext)-int(c.M)]

	var iv, s0 [ccmBlockSize]byte
	iv[0] = c.L - 1
	copy(iv[1:ccmBlockSize-c.L], nonce)
	c.b.Encrypt(s0[:], iv[:])
	for i := 0; i < int(c.M); i++ {
		tag[i] ^= s0[i]
	}
	iv[len(iv)-1] |= 1
	stream := cipher.NewCTR(c.b, iv[:])

	// Cannot decrypt directly to dst since we're not supposed to
	// reveal the plaintext to the caller if authentication fails.
	plaintext := make([]byte, len(ciphertextWithoutTag))
	stream.XORKeyStream(plaintext, ciphertextWithoutTag)
	expectedTag, err := c.tag(nonce, plaintext, adata)
	if err != nil {
		return nil, err
	}

	if subtle.ConstantTimeCompare(tag, expectedTag) != 1 {
		return nil, errors.New(fmt.Sprintf("ccm: t[%X] != et[%X]", tag, expectedTag))
		//return nil, errOpen
	}
	return append(dst, plaintext...), nil
}
<|endoftext|>


<commit_before>package sync

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/svdberg/syncmysport-runkeeper/Godeps/_workspace/src/github.com/go-sql-driver/mysql"
	"log"
	"strings"
	"time"
)

//should come from config (file) somewhere...
const default_connection_string = "root:root123@/syncmysport?charset=utf8,parseTime=true"

type DbSync struct {
	ConnectionString string
}

func CreateSyncDbRepo(dbString string) *DbSync {
	if dbString != "" {
		dbString = MakeDbStringHerokuCompliant(dbString)
		appendedConnectionString := fmt.Sprintf("%s,parseTime=true", dbString)
		log.Printf("Connection string was: %s, now is %s", dbString, appendedConnectionString)
		return &DbSync{appendedConnectionString}
	} else {
		return &DbSync{default_connection_string}
	}
}

func (db DbSync) UpdateSyncTask(sync SyncTask) (int, error) {
	if sync.Uid == -1 {
		return 0, errors.New("SyncTask was never stored before, use StoreSyncTask")
	}
	dbCon, _ := sql.Open("mysql", db.ConnectionString)
	defer dbCon.Close()

	stmtOut, err := dbCon.Prepare("UPDATE sync SET rk_key=?, stv_key=?, last_succesfull_retrieve=? WHERE uid = ?")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	defer stmtOut.Close()
	res, err := stmtOut.Exec(sync.RunkeeperToken, sync.StravaToken, createStringOutOfUnixTime(sync.LastSeenTimestamp), sync.Uid)
	if err != nil {
		log.Fatal(err)
	}

	i, err := res.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	return int(i), nil
}

/*
* Returns 1) Created Id, 2) Rows changed/added, 3)synctask, 4) error
 */
func (db DbSync) StoreSyncTask(sync SyncTask) (int64, int64, SyncTask, error) {
	dbCon, _ := sql.Open("mysql", db.ConnectionString)
	defer dbCon.Close()

	stmtOut, err := dbCon.Prepare("INSERT INTO sync(rk_key, stv_key, last_succesfull_retrieve) VALUES(?,?,?)")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	defer stmtOut.Close()
	res, err := stmtOut.Exec(sync.RunkeeperToken, sync.StravaToken, createStringOutOfUnixTime(sync.LastSeenTimestamp))
	if err != nil {
		log.Fatal(err)
	}
	lastId, err := res.LastInsertId()
	if err != nil {
		log.Fatal(err)
	}
	rowCnt, err := res.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	sync.Uid = lastId
	return lastId, rowCnt, sync, nil
}

func (db DbSync) RetrieveAllSyncTasks() ([]SyncTask, error) {
	dbCon, _ := sql.Open("mysql", db.ConnectionString)
	stmtOut, err := dbCon.Prepare("SELECT * FROM sync")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	defer stmtOut.Close()

	rows, err := stmtOut.Query()
	defer rows.Close()

	result := make([]SyncTask, 0)
	for rows.Next() {
		var rkToken string
		var stvToken string
		var uid int64
		var lastSeenTime string

		rows.Scan(&uid, &rkToken, &stvToken, &lastSeenTime)
		unixTime, err := createUnixTimeOutOfString(lastSeenTime)
		if err != nil {
			panic(err.Error()) // proper error handling instead of panic in your app
		}

		sync := CreateSyncTask(rkToken, stvToken, unixTime)
		sync.Uid = uid
		result = append(result, *sync)
	}
	return result, nil
}

func (db DbSync) RetrieveSyncTaskByToken(token string) (*SyncTask, error) {
	dbCon, _ := sql.Open("mysql", db.ConnectionString)
	stmtOut, err := dbCon.Prepare("SELECT * FROM sync WHERE rk_key = ? OR stv_key = ?")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	defer stmtOut.Close()

	rows, err := stmtOut.Query(token, token)
	defer rows.Close()

	for rows.Next() {
		var uid int64
		var rkToken string
		var stvToken string
		var lastSeen string
		err = rows.Scan(&uid, &rkToken, &stvToken, &lastSeen)
		if err != nil {
			panic(err.Error()) // proper error handling instead of panic in your app
		}
		unixTime, err := createUnixTimeOutOfString(lastSeen)
		if err != nil {
			panic(err.Error()) // proper error handling instead of panic in your app
		}
		task := CreateSyncTask(rkToken, stvToken, unixTime)
		task.Uid = uid
		return task, nil
	}
	return nil, nil
}

func MakeDbStringHerokuCompliant(dbString string) string {
	dbStringWithoutProtocol := strings.Replace(dbString, "mysql://", "", 1)
	parts := strings.Split(dbStringWithoutProtocol, "@")
	userAndPassword := strings.Split(parts[0], ":")

	addr := strings.Split(parts[1], "/")[0]
	dbName := strings.Split(strings.Split(parts[1], "/")[1], "?")[0]

	//resultString := fmt.Sprintf("mysql://%s:%s@tcp(%s:3306)/%s?reconnect=true", userAndPassword[0], userAndPassword[1], addr, dbName)
	resultString := fmt.Sprintf("mysql://%s:%s@tcp(%s)/%s?reconnect=true", userAndPassword[0], userAndPassword[1], addr, dbName)
	return resultString
}

func createUnixTimeOutOfString(lastSeen string) (int, error) {
	timestamp, err := time.Parse("2006-01-02 15:04:05", lastSeen)

	if err != nil {
		return 0, err
	}
	return int(timestamp.Unix()), nil
}

func createStringOutOfUnixTime(t int) string {
	return time.Unix(int64(t), 0).Format("2006-01-02 15:04:05")
}
<commit_msg>I did not..<commit_after>package sync

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/svdberg/syncmysport-runkeeper/Godeps/_workspace/src/github.com/go-sql-driver/mysql"
	"log"
	"strings"
	"time"
)

//should come from config (file) somewhere...
const default_connection_string = "root:root123@/syncmysport?charset=utf8,parseTime=true"

type DbSync struct {
	ConnectionString string
}

func CreateSyncDbRepo(dbString string) *DbSync {
	if dbString != "" {
		dbString = MakeDbStringHerokuCompliant(dbString)
		appendedConnectionString := fmt.Sprintf("%s,parseTime=true", dbString)
		log.Printf("Connection string was: %s, now is %s", dbString, appendedConnectionString)
		return &DbSync{appendedConnectionString}
	} else {
		return &DbSync{default_connection_string}
	}
}

func (db DbSync) UpdateSyncTask(sync SyncTask) (int, error) {
	if sync.Uid == -1 {
		return 0, errors.New("SyncTask was never stored before, use StoreSyncTask")
	}
	dbCon, _ := sql.Open("mysql", db.ConnectionString)
	defer dbCon.Close()

	stmtOut, err := dbCon.Prepare("UPDATE sync SET rk_key=?, stv_key=?, last_succesfull_retrieve=? WHERE uid = ?")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	defer stmtOut.Close()
	res, err := stmtOut.Exec(sync.RunkeeperToken, sync.StravaToken, createStringOutOfUnixTime(sync.LastSeenTimestamp), sync.Uid)
	if err != nil {
		log.Fatal(err)
	}

	i, err := res.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	return int(i), nil
}

/*
* Returns 1) Created Id, 2) Rows changed/added, 3)synctask, 4) error
 */
func (db DbSync) StoreSyncTask(sync SyncTask) (int64, int64, SyncTask, error) {
	dbCon, _ := sql.Open("mysql", db.ConnectionString)
	defer dbCon.Close()

	stmtOut, err := dbCon.Prepare("INSERT INTO sync(rk_key, stv_key, last_succesfull_retrieve) VALUES(?,?,?)")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	defer stmtOut.Close()
	res, err := stmtOut.Exec(sync.RunkeeperToken, sync.StravaToken, createStringOutOfUnixTime(sync.LastSeenTimestamp))
	if err != nil {
		log.Fatal(err)
	}
	lastId, err := res.LastInsertId()
	if err != nil {
		log.Fatal(err)
	}
	rowCnt, err := res.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	sync.Uid = lastId
	return lastId, rowCnt, sync, nil
}

func (db DbSync) RetrieveAllSyncTasks() ([]SyncTask, error) {
	dbCon, _ := sql.Open("mysql", db.ConnectionString)
	stmtOut, err := dbCon.Prepare("SELECT * FROM sync")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	defer stmtOut.Close()

	rows, err := stmtOut.Query()
	defer rows.Close()

	result := make([]SyncTask, 0)
	for rows.Next() {
		var rkToken string
		var stvToken string
		var uid int64
		var lastSeenTime string

		rows.Scan(&uid, &rkToken, &stvToken, &lastSeenTime)
		unixTime, err := createUnixTimeOutOfString(lastSeenTime)
		if err != nil {
			panic(err.Error()) // proper error handling instead of panic in your app
		}

		sync := CreateSyncTask(rkToken, stvToken, unixTime)
		sync.Uid = uid
		result = append(result, *sync)
	}
	return result, nil
}

func (db DbSync) RetrieveSyncTaskByToken(token string) (*SyncTask, error) {
	dbCon, _ := sql.Open("mysql", db.ConnectionString)
	stmtOut, err := dbCon.Prepare("SELECT * FROM sync WHERE rk_key = ? OR stv_key = ?")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	defer stmtOut.Close()

	rows, err := stmtOut.Query(token, token)
	defer rows.Close()

	for rows.Next() {
		var uid int64
		var rkToken string
		var stvToken string
		var lastSeen string
		err = rows.Scan(&uid, &rkToken, &stvToken, &lastSeen)
		if err != nil {
			panic(err.Error()) // proper error handling instead of panic in your app
		}
		unixTime, err := createUnixTimeOutOfString(lastSeen)
		if err != nil {
			panic(err.Error()) // proper error handling instead of panic in your app
		}
		task := CreateSyncTask(rkToken, stvToken, unixTime)
		task.Uid = uid
		return task, nil
	}
	return nil, nil
}

func MakeDbStringHerokuCompliant(dbString string) string {
	dbStringWithoutProtocol := strings.Replace(dbString, "mysql://", "", 1)
	parts := strings.Split(dbStringWithoutProtocol, "@")
	userAndPassword := strings.Split(parts[0], ":")

	addr := strings.Split(parts[1], "/")[0]
	dbName := strings.Split(strings.Split(parts[1], "/")[1], "?")[0]

	resultString := fmt.Sprintf("mysql://%s:%s@tcp(%s:3306)/%s?reconnect=true", userAndPassword[0], userAndPassword[1], addr, dbName)
	return resultString
}

func createUnixTimeOutOfString(lastSeen string) (int, error) {
	timestamp, err := time.Parse("2006-01-02 15:04:05", lastSeen)

	if err != nil {
		return 0, err
	}
	return int(timestamp.Unix()), nil
}

func createStringOutOfUnixTime(t int) string {
	return time.Unix(int64(t), 0).Format("2006-01-02 15:04:05")
}
<|endoftext|>


<commit_before>//package syncmap is a map with sync.RWMutex.
package syncmap

import (
	"errors"
	. "github.com/yanjinzh6/flowkey/tools"
	"sync"
	"time"
)

const (
	DEFAULT_DURATION_TIME = time.Minute * 30
)

var (
	NilKeyError = errors.New("nil key error")
	NilError    = errors.New("text")
)

type syncMap struct {
	m      map[interface{}]interface{}
	rwlock sync.RWMutex
}

type SyncMap interface {
	Get(key interface{}) (val interface{}, err error)
	Put(key, value interface{}, d time.Duration) (val interface{}, err error)
	PutSimple(key, value interface{}) (val interface{}, err error)
	PutNormal(key, value interface{}) (val interface{}, err error)
	PutIfAbsent(key, value interface{}, d time.Duration) (b bool, err error)
	PutAll(child map[interface{}]interface{}, d time.Duration) (err error)
	Remove(key interface{}) (val interface{}, err error)
	RemoveEntry(key, value interface{}) (b bool, err error)
	Update(key, value interface{}) (b bool, err error)
	IsEmpty() (b bool)
	Clear() (err error)
	Size() (size int)
}

func NewSyncMap() SyncMap {
	return &syncMap{
		m: make(map[interface{}]interface{}),
	}
}

func (s *syncMap) Get(key interface{}) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.RLock()
	val = s.m[key]
	if ok, ent := chTimeEntity(val); ok {
		val, err = ent.Value()
	}
	s.rwlock.RUnlock()
	return
}

func (s *syncMap) Put(key, value interface{}, d time.Duration) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.Lock()
	val = s.m[key]
	if val == nil {
		ent := NewTimeEntity(value, d)
		s.m[key] = ent
	} else {
		if ok, ent := chTimeEntity(val); ok {
			val, err = ent.Value()
		} else {
			s.m[key] = value
		}
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) PutSimple(key, value interface{}) (val interface{}, err error) {
	val, err = s.Put(key, value, DEFAULT_DURATION_TIME)
	return
}

func (s *syncMap) PutNormal(key, value interface{}) (val interface{}, err error) {
	val, err = s.Put(key, value, 0)
	return
}

func (s *syncMap) PutIfAbsent(key, value interface{}, d time.Duration) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	if s.m[key] == nil {
		b = true
		s.m[key] = value
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) PutAll(child map[interface{}]interface{}, d time.Duration) (err error) {
	if child != nil {
		s.rwlock.Lock()
		for k, v := range child {
			s.m[k] = v
		}
		s.rwlock.Unlock()
	}
	return
}

func (s *syncMap) Remove(key interface{}) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.Lock()
	val = s.m[key]
	if val != nil {
		delete(s.m, key)
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) RemoveEntry(key, value interface{}) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	val := s.m[key]
	if val != nil && val == value {
		b = true
		delete(s.m, key)
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) Update(key, value interface{}) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	return
}

func (s *syncMap) IsEmpty() (b bool) {
	s.rwlock.RLock()
	if s.m == nil || len(s.m) == 0 {
		b = true
	} else {
		b = false
	}
	s.rwlock.RUnlock()
	return
}

func (s *syncMap) Clear() (err error) {
	s.rwlock.Lock()
	for k := range s.m {
		delete(s.m, k)
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) Size() (size int) {
	s.rwlock.RLock()
	size = len(s.m)
	s.rwlock.RUnlock()
	return
}

func chTimeEntity(val interface{}) (ok bool, ent TimeEntity) {
	if val == nil {
		return false, nil
	}
	switch value := val.(type) {
	case TimeEntity:
		return true, value
	default:
		return false, nil
	}
}

type syncMapEnt struct {
	m      map[interface{}]TimeEntity
	rwlock sync.RWMutex
}

func NewSyncMapEnt() SyncMap {
	return &syncMapEnt{
		m: make(map[interface{}]TimeEntity),
	}
}

func (s *syncMapEnt) Get(key interface{}) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	if s.m[key].IsDie() {
		s.rwlock.Lock()
		s.m[key] = nil
		delete(s.m, key)
		val = nil
		s.rwlock.Unlock()
	} else {
		s.rwlock.RLock()
		val, err = s.m[key].Value()
		s.rwlock.RUnlock()
	}
	return
}

func (s *syncMapEnt) Put(key, value interface{}, d time.Duration) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.Lock()
	oldEnt := s.m[key]
	if oldEnt == nil {
		ent := NewTimeEntity(value, d)
		s.m[key] = ent
	} else {
		if val, _ := oldEnt.Value(); val != value {
			s.m[key].Update(value)
		}
		if oldEnt.Dtime() != d {
			s.m[key].ChangeDur(d)
		}
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) PutSimple(key, value interface{}) (val interface{}, err error) {
	val, err = s.Put(key, value, DEFAULT_DURATION_TIME)
	return
}

func (s *syncMapEnt) PutNormal(key, value interface{}) (val interface{}, err error) {
	val, err = s.Put(key, value, 0)
	return
}

func (s *syncMapEnt) PutIfAbsent(key, value interface{}, d time.Duration) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	if s.m[key] == nil {
		b = true
		ent := NewTimeEntity(value, d)
		s.m[key] = ent
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) PutAll(child map[interface{}]interface{}, d time.Duration) (err error) {
	if child != nil {
		s.rwlock.Lock()
		for k, v := range child {
			if s.m[k] != nil {
				s.m[k] = nil
			}
			ent := NewTimeEntity(v, d)
			s.m[k] = ent
		}
		s.rwlock.Unlock()
	}
	return
}

func (s *syncMapEnt) Remove(key interface{}) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.Lock()
	val = s.m[key]
	if val != nil {
		s.m[key] = nil
		delete(s.m, key)
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) RemoveEntry(key, value interface{}) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	val := s.m[key]
	if val != nil {
		if v, _ := val.Value(); v == value {
			b = true
			s.m[key] = nil
			delete(s.m, key)
		}
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) Update(key, value interface{}) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	val := s.m[key]
	if val != nil {
		b = true
		val.Update(value)
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) IsEmpty() (b bool) {
	s.rwlock.RLock()
	if s.m == nil || len(s.m) == 0 {
		b = true
	} else {
		b = false
	}
	s.rwlock.RUnlock()
	return
}

func (s *syncMapEnt) Clear() (err error) {
	s.rwlock.Lock()
	for k := range s.m {
		delete(s.m, k)
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) Size() (size int) {
	s.rwlock.RLock()
	size = len(s.m)
	s.rwlock.RUnlock()
	return
}
<commit_msg>syncMap.go change put function, remove the old entity and put the new entity.<commit_after>//package syncmap is a map with sync.RWMutex.
package syncmap

import (
	"errors"
	. "github.com/yanjinzh6/flowkey/tools"
	"sync"
	"time"
)

const (
	DEFAULT_DURATION_TIME = time.Minute * 30
)

var (
	NilKeyError = errors.New("nil key error")
	NilError    = errors.New("text")
)

type syncMap struct {
	m      map[interface{}]interface{}
	rwlock sync.RWMutex
}

type SyncMap interface {
	Get(key interface{}) (val interface{}, err error)
	Put(key, value interface{}, d time.Duration) (val interface{}, err error)
	PutSimple(key, value interface{}) (val interface{}, err error)
	PutNormal(key, value interface{}) (val interface{}, err error)
	PutIfAbsent(key, value interface{}, d time.Duration) (b bool, err error)
	PutAll(child map[interface{}]interface{}, d time.Duration) (err error)
	Remove(key interface{}) (val interface{}, err error)
	RemoveEntry(key, value interface{}) (b bool, err error)
	Update(key, value interface{}) (b bool, err error)
	IsEmpty() (b bool)
	Clear() (err error)
	Size() (size int)
}

func NewSyncMap() SyncMap {
	return &syncMap{
		m: make(map[interface{}]interface{}),
	}
}

func (s *syncMap) Get(key interface{}) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.RLock()
	val = s.m[key]
	if ok, ent := chTimeEntity(val); ok {
		val, err = ent.Value()
	}
	s.rwlock.RUnlock()
	return
}

func (s *syncMap) Put(key, value interface{}, d time.Duration) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.Lock()
	val = s.m[key]
	if val == nil {
		ent := NewTimeEntity(value, d)
		s.m[key] = ent
	} else {
		if ok, ent := chTimeEntity(val); ok {
			val, err = ent.Value()
		} else {
			s.m[key] = value
		}
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) PutSimple(key, value interface{}) (val interface{}, err error) {
	val, err = s.Put(key, value, DEFAULT_DURATION_TIME)
	return
}

func (s *syncMap) PutNormal(key, value interface{}) (val interface{}, err error) {
	val, err = s.Put(key, value, 0)
	return
}

func (s *syncMap) PutIfAbsent(key, value interface{}, d time.Duration) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	if s.m[key] == nil {
		b = true
		s.m[key] = value
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) PutAll(child map[interface{}]interface{}, d time.Duration) (err error) {
	if child != nil {
		s.rwlock.Lock()
		for k, v := range child {
			s.m[k] = v
		}
		s.rwlock.Unlock()
	}
	return
}

func (s *syncMap) Remove(key interface{}) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.Lock()
	val = s.m[key]
	if val != nil {
		delete(s.m, key)
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) RemoveEntry(key, value interface{}) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	val := s.m[key]
	if val != nil && val == value {
		b = true
		delete(s.m, key)
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) Update(key, value interface{}) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	return
}

func (s *syncMap) IsEmpty() (b bool) {
	s.rwlock.RLock()
	if s.m == nil || len(s.m) == 0 {
		b = true
	} else {
		b = false
	}
	s.rwlock.RUnlock()
	return
}

func (s *syncMap) Clear() (err error) {
	s.rwlock.Lock()
	for k := range s.m {
		delete(s.m, k)
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMap) Size() (size int) {
	s.rwlock.RLock()
	size = len(s.m)
	s.rwlock.RUnlock()
	return
}

func chTimeEntity(val interface{}) (ok bool, ent TimeEntity) {
	if val == nil {
		return false, nil
	}
	switch value := val.(type) {
	case TimeEntity:
		return true, value
	default:
		return false, nil
	}
}

type syncMapEnt struct {
	m      map[interface{}]TimeEntity
	rwlock sync.RWMutex
}

func NewSyncMapEnt() SyncMap {
	return &syncMapEnt{
		m: make(map[interface{}]TimeEntity),
	}
}

func (s *syncMapEnt) Get(key interface{}) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	if s.m[key].IsDie() {
		s.rwlock.Lock()
		s.m[key] = nil
		delete(s.m, key)
		val = nil
		s.rwlock.Unlock()
	} else {
		s.rwlock.RLock()
		val, err = s.m[key].Value()
		s.rwlock.RUnlock()
	}
	return
}

func (s *syncMapEnt) Put(key, value interface{}, d time.Duration) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.Lock()
	oldEnt := s.m[key]
	if oldEnt == nil {
		ent := NewTimeEntity(value, d)
		s.m[key] = ent
	} else {
		/*if val, _ := oldEnt.Value(); val != value {
			s.m[key].Update(value)
		}
		if oldEnt.Dtime() != d {
			s.m[key].ChangeDur(d)
		}*/
		s.m[key] = nil
		ent := NewTimeEntity(value, d)
		s.m[key] = ent
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) PutSimple(key, value interface{}) (val interface{}, err error) {
	val, err = s.Put(key, value, DEFAULT_DURATION_TIME)
	return
}

func (s *syncMapEnt) PutNormal(key, value interface{}) (val interface{}, err error) {
	val, err = s.Put(key, value, 0)
	return
}

func (s *syncMapEnt) PutIfAbsent(key, value interface{}, d time.Duration) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	if s.m[key] == nil {
		b = true
		ent := NewTimeEntity(value, d)
		s.m[key] = ent
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) PutAll(child map[interface{}]interface{}, d time.Duration) (err error) {
	if child != nil {
		s.rwlock.Lock()
		for k, v := range child {
			if s.m[k] != nil {
				s.m[k] = nil
			}
			ent := NewTimeEntity(v, d)
			s.m[k] = ent
		}
		s.rwlock.Unlock()
	}
	return
}

func (s *syncMapEnt) Remove(key interface{}) (val interface{}, err error) {
	if !ChKey(key) {
		return nil, NilKeyError
	}
	s.rwlock.Lock()
	val = s.m[key]
	if val != nil {
		s.m[key] = nil
		delete(s.m, key)
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) RemoveEntry(key, value interface{}) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	val := s.m[key]
	if val != nil {
		if v, _ := val.Value(); v == value {
			b = true
			s.m[key] = nil
			delete(s.m, key)
		}
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) Update(key, value interface{}) (b bool, err error) {
	if !ChKey(key) {
		return false, NilKeyError
	}
	s.rwlock.Lock()
	val := s.m[key]
	if val != nil {
		b = true
		val.Update(value)
	} else {
		b = false
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) IsEmpty() (b bool) {
	s.rwlock.RLock()
	if s.m == nil || len(s.m) == 0 {
		b = true
	} else {
		b = false
	}
	s.rwlock.RUnlock()
	return
}

func (s *syncMapEnt) Clear() (err error) {
	s.rwlock.Lock()
	for k := range s.m {
		delete(s.m, k)
	}
	s.rwlock.Unlock()
	return
}

func (s *syncMapEnt) Size() (size int) {
	s.rwlock.RLock()
	size = len(s.m)
	s.rwlock.RUnlock()
	return
}
<|endoftext|>


<commit_before>package cmd

import (
	"archive/zip"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/gobuffalo/buffalo/generators/assets/webpack"
	pack "github.com/gobuffalo/packr/builder"
	"github.com/gobuffalo/plush"
	"github.com/spf13/cobra"
)

var outputBinName string
var zipBin bool
var extractAssets bool
var hasDB bool

type builder struct {
	cleanup      []string
	originalMain []byte
	originalApp  []byte
	workDir      string
}

func (b *builder) clean(name ...string) string {
	path := filepath.Join(name...)
	b.cleanup = append(b.cleanup, path)
	return path
}

func (b *builder) exec(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	fmt.Printf("--> running %s\n", strings.Join(cmd.Args, " "))
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

func (b *builder) execQuiet(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	return cmd.Run()
}

func (b *builder) buildWebpack() error {
	_, err := os.Stat("webpack.config.js")
	if err == nil {
		// build webpack
		return b.exec(webpack.BinPath)
	}
	return nil
}

func (b *builder) buildAPack() error {
	err := os.MkdirAll(b.clean("a"), 0766)
	if err != nil {
		return err
	}
	err = b.buildAInit()
	if err != nil {
		return err
	}
	err = b.buildDatabase()
	if err != nil {
		return err
	}
	return nil
}

func (b *builder) buildAInit() error {
	a, err := os.Create(b.clean("a", "a.go"))
	if err != nil {
		return err
	}
	a.WriteString(aGo)
	return nil
}

func (b *builder) buildDatabase() error {
	bb := &bytes.Buffer{}
	dgo, err := os.Create(b.clean("a", "database.go"))
	if err != nil {
		return err
	}
	if hasDB {
		// copy the database.yml file to the migrations folder so it's available through packr
		os.MkdirAll("./migrations", 0755)
		d, err := os.Open("database.yml")
		if err != nil {
			return err
		}
		_, err = io.Copy(bb, d)
		if err != nil {
			return err
		}
	}
	dgo.WriteString("package a\n")
	dgo.WriteString(fmt.Sprintf("var DB_CONFIG = `%s`", bb.String()))
	return nil
}

func (b *builder) buildPackrEmbedded() error {
	defer os.Chdir(b.workDir)
	p := pack.New(context.Background(), b.workDir)
	return p.Run()
}

func (b *builder) disableAssetsHandling() error {
	defer os.Chdir(b.workDir)
	fmt.Printf("--> disable self assets handling\n")

	newApp := strings.Replace(string(b.originalApp), "app.ServeFiles(\"/assets\", assetsPath())", "//app.ServeFiles(\"/assets\", assetsPath())", 1)

	appgo, err := os.Create("actions/app.go")
	if err != nil {
		return err
	}
	_, err = appgo.WriteString(newApp)
	if err != nil {
		return err
	}

	return nil
}

func (b *builder) buildAssetsArchive() error {
	defer os.Chdir(b.workDir)
	fmt.Printf("--> build assets archive\n")

	outputDir := filepath.Dir(outputBinName)
	assetsName := filepath.Base(outputBinName)
	target := outputDir + "/" + assetsName + "-assets.zip"
	source := filepath.Join(b.workDir, "public", "assets")

	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	info, err := os.Stat(source)
	if err != nil {
		return err
	}

	var baseDir string
	if info.IsDir() {
		baseDir = filepath.Base(source)
	}

	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		if baseDir != "" {
			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
		}

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := archive.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	})

	return err
}

func (b *builder) buildMain() error {
	newMain := strings.Replace(string(b.originalMain), "func main()", "func originalMain()", 1)
	maingo, err := os.Create("main.go")
	if err != nil {
		return err
	}
	_, err = maingo.WriteString(newMain)
	if err != nil {
		return err
	}

	ctx := plush.NewContext()
	ctx.Set("root", rootPath)
	ctx.Set("hasDB", hasDB)
	if hasDB {
		ctx.Set("modelsPack", packagePath(rootPath)+"/models")
	}
	_, err = os.Stat(filepath.Join(rootPath, "grifts"))
	if err == nil {
		ctx.Set("griftsPack", packagePath(rootPath)+"/grifts")
	}
	ctx.Set("aPack", packagePath(rootPath)+"/a")
	ctx.Set("name", filepath.Base(rootPath))
	s, err := plush.Render(buildMainTmpl, ctx)
	if err != nil {
		return err
	}
	f, err := os.Create(b.clean("buffalo_build_main.go"))
	if err != nil {
		return err
	}
	f.WriteString(s)

	return nil
}

func (b *builder) cleanupBuild() {
	fmt.Println("--> cleaning up build")
	for _, b := range b.cleanup {
		fmt.Printf("----> cleaning up %s\n", b)
		os.RemoveAll(b)
	}

	pack.Clean(b.workDir)

	maingo, _ := os.Create("main.go")
	maingo.Write(b.originalMain)

	appgo, _ := os.Create("actions/app.go")
	appgo.Write(b.originalApp)
}

func (b *builder) cleanupTarget() {
	fmt.Println("--> cleaning up target dir")

	// Create output directory if not exists
	outputDir := filepath.Dir(outputBinName)

	if _, err := os.Stat(outputDir); os.IsNotExist(err) {
		os.MkdirAll(outputDir, 0776)
		fmt.Printf("----> creating target dir %s\n", outputDir)
	}

	files, _ := ioutil.ReadDir(outputDir)
	for _, f := range files {
		fmt.Printf("----> cleaning up %s\n", f.Name())
		os.RemoveAll(outputDir + f.Name())
	}
}

func (b *builder) run() error {
	_, err := os.Stat("database.yml")
	if err == nil {
		hasDB = true
	}

	err = b.buildMain()
	if err != nil {
		return err
	}

	err = b.buildWebpack()
	if err != nil {
		return err
	}

	err = b.buildAPack()
	if err != nil {
		return err
	}

	err = b.buildMain()
	if err != nil {
		return err
	}

	if extractAssets {
		err = b.buildAssetsArchive()
		if err != nil {
			return err
		}
		err = b.disableAssetsHandling()
		if err != nil {
			return err
		}
		return b.buildBin()
	}

	// if zipBin {
	// 	err = b.buildBin()
	// 	if err != nil {
	// 		return err
	// 	}
	// 	return b.buildpackrZip()
	// }

	err = b.buildPackrEmbedded()
	if err != nil {
		return err
	}
	return b.buildBin()
}

func (b *builder) buildBin() error {
	buildArgs := []string{"build", "-v", "-o", outputBinName}
	_, err := exec.LookPath("git")
	buildTime := fmt.Sprintf("\"%s\"", time.Now().Format(time.RFC3339))
	version := buildTime
	if err == nil {
		cmd := exec.Command("git", "rev-parse", "--short", "HEAD")
		out := &bytes.Buffer{}
		cmd.Stdout = out
		err = cmd.Run()
		if err == nil && out.String() != "" {
			version = strings.TrimSpace(out.String())
		}
	}
	buildArgs = append(buildArgs, "-ldflags", fmt.Sprintf("-X main.version=%s -X main.buildTime=%s", version, buildTime))

	return b.exec("go", buildArgs...)
}

// buildCmd represents the build command
var buildCmd = &cobra.Command{
	Use:     "build",
	Aliases: []string{"b", "bill"},
	Short:   "Builds a Buffalo binary, including bundling of assets (packr & webpack)",
	RunE: func(cc *cobra.Command, args []string) error {
		originalMain := &bytes.Buffer{}
		maingo, err := os.Open("main.go")
		_, err = originalMain.ReadFrom(maingo)
		if err != nil {
			return err
		}
		maingo.Close()

		originalApp := &bytes.Buffer{}
		appgo, err := os.Open("actions/app.go")
		_, err = originalApp.ReadFrom(appgo)
		if err != nil {
			return err
		}
		appgo.Close()

		pwd, _ := os.Getwd()
		b := builder{
			cleanup:      []string{},
			originalMain: originalMain.Bytes(),
			originalApp:  originalApp.Bytes(),
			workDir:      pwd,
		}
		defer b.cleanupBuild()

		b.cleanupTarget()
		return b.run()
	},
}

func init() {
	RootCmd.AddCommand(buildCmd)
	pwd, _ := os.Getwd()
	output := filepath.Join("bin", filepath.Base(pwd))

	if runtime.GOOS == "windows" {
		output += ".exe"
	}

	buildCmd.Flags().StringVarP(&outputBinName, "output", "o", output, "set the name of the binary")
	buildCmd.Flags().BoolVarP(&zipBin, "zip", "z", false, "zips the assets to the binary, this requires zip installed")
	buildCmd.Flags().BoolVarP(&extractAssets, "extract-assets", "e", false, "extract the assets and put them in a distinct archive")
}

var buildMainTmpl = `package main

import (
	"fmt"
	"log"
	"os"
	"io"

	"github.com/markbates/grift/grift"
	"github.com/gobuffalo/packr"
	_ "<%= aPack %>"
	<%= if (modelsPack) { %>
	"io/ioutil"
	"path/filepath"
	"<%= modelsPack %>"
	<% } %>
	<%= if (griftsPack) { %>
	_ "<%= griftsPack %>"
	<% } %>
)

var version = "unknown"
var buildTime = "unknown"
var migrationBox packr.Box

func main() {
	args := os.Args
	if len(args) == 1 {
		originalMain()
	}
	c := args[1]
	switch c {
	<%= if (modelsPack) { %>
	case "migrate":
		migrate()
	<% } %>
	case "start", "run", "serve":
		printVersion()
		originalMain()
	case "version":
		printVersion()
	case "task", "t", "tasks":
		err := grift.Run(args[2], grift.NewContext(args[2]))
		if err != nil {
			log.Fatal(err)
		}
	default:
		log.Fatalf("Could not find a command named: %s", c)
	}
}

func printVersion() {
	fmt.Printf("<%= name %> version %s (%s)\n\n", version, buildTime)
}

<%= if (modelsPack) { %>
func migrate() {
	var err error
	migrationBox = packr.NewBox("./migrations")
	fmt.Println("--> Running migrations")
	path, err := unpackMigrations()
	if err != nil {
		log.Fatalf("Failed to unpack migrations: %s", err)
	}
	defer os.RemoveAll(path)

	models.DB.MigrateUp(path)
}

func unpackMigrations() (string, error) {
	dir, err := ioutil.TempDir("", "<%= name %>-migrations")
	if err != nil {
		log.Fatalf("Unable to create temp directory: %s", err)
	}

	migrationBox.Walk(func(path string, f packr.File) error {
		file, err := os.Create(filepath.Join(dir, path))
		if err != nil {
			log.Fatalf("Failed to write migration to disk: %s", err)
		}
		_, err = io.Copy(file, f)
		if err != nil {
			log.Fatalf("Failed to write migration to disk: %s", err)
		}
		return nil
	})

	return dir, nil
}
<% } %>
`

var aGo = `package a

import (
	"log"
	"os"
)

func init() {
	dropDatabaseYml()
}

func dropDatabaseYml() {
	if DB_CONFIG != "" {
		_, err := os.Stat("database.yml")
		if err == nil {
			// yaml already exists, don't do anything
			return
		}
		f, err := os.Create("database.yml")
		if err != nil {
			log.Fatal(err)
		}
		_, err = f.WriteString(DB_CONFIG)
		if err != nil {
			log.Fatal(err)
		}
	}
}`
<commit_msg>fixed unused io package for non-model based apps<commit_after>package cmd

import (
	"archive/zip"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/gobuffalo/buffalo/generators/assets/webpack"
	pack "github.com/gobuffalo/packr/builder"
	"github.com/gobuffalo/plush"
	"github.com/spf13/cobra"
)

var outputBinName string
var zipBin bool
var extractAssets bool
var hasDB bool

type builder struct {
	cleanup      []string
	originalMain []byte
	originalApp  []byte
	workDir      string
}

func (b *builder) clean(name ...string) string {
	path := filepath.Join(name...)
	b.cleanup = append(b.cleanup, path)
	return path
}

func (b *builder) exec(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	fmt.Printf("--> running %s\n", strings.Join(cmd.Args, " "))
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

func (b *builder) execQuiet(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	return cmd.Run()
}

func (b *builder) buildWebpack() error {
	_, err := os.Stat("webpack.config.js")
	if err == nil {
		// build webpack
		return b.exec(webpack.BinPath)
	}
	return nil
}

func (b *builder) buildAPack() error {
	err := os.MkdirAll(b.clean("a"), 0766)
	if err != nil {
		return err
	}
	err = b.buildAInit()
	if err != nil {
		return err
	}
	err = b.buildDatabase()
	if err != nil {
		return err
	}
	return nil
}

func (b *builder) buildAInit() error {
	a, err := os.Create(b.clean("a", "a.go"))
	if err != nil {
		return err
	}
	a.WriteString(aGo)
	return nil
}

func (b *builder) buildDatabase() error {
	bb := &bytes.Buffer{}
	dgo, err := os.Create(b.clean("a", "database.go"))
	if err != nil {
		return err
	}
	if hasDB {
		// copy the database.yml file to the migrations folder so it's available through packr
		os.MkdirAll("./migrations", 0755)
		d, err := os.Open("database.yml")
		if err != nil {
			return err
		}
		_, err = io.Copy(bb, d)
		if err != nil {
			return err
		}
	}
	dgo.WriteString("package a\n")
	dgo.WriteString(fmt.Sprintf("var DB_CONFIG = `%s`", bb.String()))
	return nil
}

func (b *builder) buildPackrEmbedded() error {
	defer os.Chdir(b.workDir)
	p := pack.New(context.Background(), b.workDir)
	return p.Run()
}

func (b *builder) disableAssetsHandling() error {
	defer os.Chdir(b.workDir)
	fmt.Printf("--> disable self assets handling\n")

	newApp := strings.Replace(string(b.originalApp), "app.ServeFiles(\"/assets\", assetsPath())", "//app.ServeFiles(\"/assets\", assetsPath())", 1)

	appgo, err := os.Create("actions/app.go")
	if err != nil {
		return err
	}
	_, err = appgo.WriteString(newApp)
	if err != nil {
		return err
	}

	return nil
}

func (b *builder) buildAssetsArchive() error {
	defer os.Chdir(b.workDir)
	fmt.Printf("--> build assets archive\n")

	outputDir := filepath.Dir(outputBinName)
	assetsName := filepath.Base(outputBinName)
	target := outputDir + "/" + assetsName + "-assets.zip"
	source := filepath.Join(b.workDir, "public", "assets")

	zipfile, err := os.Create(target)
	if err != nil {
		return err
	}
	defer zipfile.Close()

	archive := zip.NewWriter(zipfile)
	defer archive.Close()

	info, err := os.Stat(source)
	if err != nil {
		return err
	}

	var baseDir string
	if info.IsDir() {
		baseDir = filepath.Base(source)
	}

	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		if baseDir != "" {
			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
		}

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := archive.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)
		return err
	})

	return err
}

func (b *builder) buildMain() error {
	newMain := strings.Replace(string(b.originalMain), "func main()", "func originalMain()", 1)
	maingo, err := os.Create("main.go")
	if err != nil {
		return err
	}
	_, err = maingo.WriteString(newMain)
	if err != nil {
		return err
	}

	ctx := plush.NewContext()
	ctx.Set("root", rootPath)
	ctx.Set("hasDB", hasDB)
	if hasDB {
		ctx.Set("modelsPack", packagePath(rootPath)+"/models")
	}
	_, err = os.Stat(filepath.Join(rootPath, "grifts"))
	if err == nil {
		ctx.Set("griftsPack", packagePath(rootPath)+"/grifts")
	}
	ctx.Set("aPack", packagePath(rootPath)+"/a")
	ctx.Set("name", filepath.Base(rootPath))
	s, err := plush.Render(buildMainTmpl, ctx)
	if err != nil {
		return err
	}
	f, err := os.Create(b.clean("buffalo_build_main.go"))
	if err != nil {
		return err
	}
	f.WriteString(s)

	return nil
}

func (b *builder) cleanupBuild() {
	fmt.Println("--> cleaning up build")
	for _, b := range b.cleanup {
		fmt.Printf("----> cleaning up %s\n", b)
		os.RemoveAll(b)
	}

	pack.Clean(b.workDir)

	maingo, _ := os.Create("main.go")
	maingo.Write(b.originalMain)

	appgo, _ := os.Create("actions/app.go")
	appgo.Write(b.originalApp)
}

func (b *builder) cleanupTarget() {
	fmt.Println("--> cleaning up target dir")

	// Create output directory if not exists
	outputDir := filepath.Dir(outputBinName)

	if _, err := os.Stat(outputDir); os.IsNotExist(err) {
		os.MkdirAll(outputDir, 0776)
		fmt.Printf("----> creating target dir %s\n", outputDir)
	}

	files, _ := ioutil.ReadDir(outputDir)
	for _, f := range files {
		fmt.Printf("----> cleaning up %s\n", f.Name())
		os.RemoveAll(outputDir + f.Name())
	}
}

func (b *builder) run() error {
	_, err := os.Stat("database.yml")
	if err == nil {
		hasDB = true
	}

	err = b.buildMain()
	if err != nil {
		return err
	}

	err = b.buildWebpack()
	if err != nil {
		return err
	}

	err = b.buildAPack()
	if err != nil {
		return err
	}

	err = b.buildMain()
	if err != nil {
		return err
	}

	if extractAssets {
		err = b.buildAssetsArchive()
		if err != nil {
			return err
		}
		err = b.disableAssetsHandling()
		if err != nil {
			return err
		}
		return b.buildBin()
	}

	// if zipBin {
	// 	err = b.buildBin()
	// 	if err != nil {
	// 		return err
	// 	}
	// 	return b.buildpackrZip()
	// }

	err = b.buildPackrEmbedded()
	if err != nil {
		return err
	}
	return b.buildBin()
}

func (b *builder) buildBin() error {
	buildArgs := []string{"build", "-v", "-o", outputBinName}
	_, err := exec.LookPath("git")
	buildTime := fmt.Sprintf("\"%s\"", time.Now().Format(time.RFC3339))
	version := buildTime
	if err == nil {
		cmd := exec.Command("git", "rev-parse", "--short", "HEAD")
		out := &bytes.Buffer{}
		cmd.Stdout = out
		err = cmd.Run()
		if err == nil && out.String() != "" {
			version = strings.TrimSpace(out.String())
		}
	}
	buildArgs = append(buildArgs, "-ldflags", fmt.Sprintf("-X main.version=%s -X main.buildTime=%s", version, buildTime))

	return b.exec("go", buildArgs...)
}

// buildCmd represents the build command
var buildCmd = &cobra.Command{
	Use:     "build",
	Aliases: []string{"b", "bill"},
	Short:   "Builds a Buffalo binary, including bundling of assets (packr & webpack)",
	RunE: func(cc *cobra.Command, args []string) error {
		originalMain := &bytes.Buffer{}
		maingo, err := os.Open("main.go")
		_, err = originalMain.ReadFrom(maingo)
		if err != nil {
			return err
		}
		maingo.Close()

		originalApp := &bytes.Buffer{}
		appgo, err := os.Open("actions/app.go")
		_, err = originalApp.ReadFrom(appgo)
		if err != nil {
			return err
		}
		appgo.Close()

		pwd, _ := os.Getwd()
		b := builder{
			cleanup:      []string{},
			originalMain: originalMain.Bytes(),
			originalApp:  originalApp.Bytes(),
			workDir:      pwd,
		}
		defer b.cleanupBuild()

		b.cleanupTarget()
		return b.run()
	},
}

func init() {
	RootCmd.AddCommand(buildCmd)
	pwd, _ := os.Getwd()
	output := filepath.Join("bin", filepath.Base(pwd))

	if runtime.GOOS == "windows" {
		output += ".exe"
	}

	buildCmd.Flags().StringVarP(&outputBinName, "output", "o", output, "set the name of the binary")
	buildCmd.Flags().BoolVarP(&zipBin, "zip", "z", false, "zips the assets to the binary, this requires zip installed")
	buildCmd.Flags().BoolVarP(&extractAssets, "extract-assets", "e", false, "extract the assets and put them in a distinct archive")
}

var buildMainTmpl = `package main

import (
	"fmt"
	"log"
	"os"

	"github.com/markbates/grift/grift"
	"github.com/gobuffalo/packr"
	_ "<%= aPack %>"
	<%= if (modelsPack) { %>
	"io"
	"io/ioutil"
	"path/filepath"
	"<%= modelsPack %>"
	<% } %>
	<%= if (griftsPack) { %>
	_ "<%= griftsPack %>"
	<% } %>
)

var version = "unknown"
var buildTime = "unknown"
var migrationBox packr.Box

func main() {
	args := os.Args
	if len(args) == 1 {
		originalMain()
	}
	c := args[1]
	switch c {
	<%= if (modelsPack) { %>
	case "migrate":
		migrate()
	<% } %>
	case "start", "run", "serve":
		printVersion()
		originalMain()
	case "version":
		printVersion()
	case "task", "t", "tasks":
		err := grift.Run(args[2], grift.NewContext(args[2]))
		if err != nil {
			log.Fatal(err)
		}
	default:
		log.Fatalf("Could not find a command named: %s", c)
	}
}

func printVersion() {
	fmt.Printf("<%= name %> version %s (%s)\n\n", version, buildTime)
}

<%= if (modelsPack) { %>
func migrate() {
	var err error
	migrationBox = packr.NewBox("./migrations")
	fmt.Println("--> Running migrations")
	path, err := unpackMigrations()
	if err != nil {
		log.Fatalf("Failed to unpack migrations: %s", err)
	}
	defer os.RemoveAll(path)

	models.DB.MigrateUp(path)
}

func unpackMigrations() (string, error) {
	dir, err := ioutil.TempDir("", "<%= name %>-migrations")
	if err != nil {
		log.Fatalf("Unable to create temp directory: %s", err)
	}

	migrationBox.Walk(func(path string, f packr.File) error {
		file, err := os.Create(filepath.Join(dir, path))
		if err != nil {
			log.Fatalf("Failed to write migration to disk: %s", err)
		}
		_, err = io.Copy(file, f)
		if err != nil {
			log.Fatalf("Failed to write migration to disk: %s", err)
		}
		return nil
	})

	return dir, nil
}
<% } %>
`

var aGo = `package a

import (
	"log"
	"os"
)

func init() {
	dropDatabaseYml()
}

func dropDatabaseYml() {
	if DB_CONFIG != "" {
		_, err := os.Stat("database.yml")
		if err == nil {
			// yaml already exists, don't do anything
			return
		}
		f, err := os.Create("database.yml")
		if err != nil {
			log.Fatal(err)
		}
		_, err = f.WriteString(DB_CONFIG)
		if err != nil {
			log.Fatal(err)
		}
	}
}`
<|endoftext|>


<commit_before>package main

import (
  "encoding/json"
	"fmt"
	"net/http"
	"runtime"
)

type MessageStruct struct {
	Message string
}

func hello(w http.ResponseWriter, r *http.Request) {
	m := MessageStruct{"Hello, world"}
	enc := json.NewEncoder(w)
	enc.Encode(m)
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	http.HandleFunc("/json", hello)
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Update hello.go<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"runtime"
)

type MessageStruct struct {
	Message string
}

func hello(w http.ResponseWriter, r *http.Request) {
	m := MessageStruct{"Hello, world"}
	enc := json.NewEncoder(w)
	enc.Encode(m)
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	http.HandleFunc("/json", hello)
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package flatbuffers

const (
	// See http://golang.org/ref/spec#Numeric_types

	// SizeUint8 is the byte size of a uint8.
	SizeUint8 = 1
	// SizeUint16 is the byte size of a uint16.
	SizeUint16 = 2
	// SizeUint32 is the byte size of a uint32.
	SizeUint32 = 4
	// SizeUint64 is the byte size of a uint64.
	SizeUint64 = 8

	// SizeInt8 is the byte size of a int8.
	SizeInt8 = 1
	// SizeInt16 is the byte size of a int16.
	SizeInt16 = 2
	// SizeInt32 is the byte size of a int32.
	SizeInt32 = 4
	// SizeInt64 is the byte size of a int64.
	SizeInt64 = 8

	// SizeFloat32 is the byte size of a float32.
	SizeFloat32 = 4
	// SizeFloat64 is the byte size of a float64.
	SizeFloat64 = 8

	// SizeByte is the byte size of a byte.
	// The `byte` type is aliased (by Go definition) to uint8.
	SizeByte = 1

	// SizeBool is the byte size of a bool.
	// The `bool` type is aliased (by flatbuffers convention) to uint8.
	SizeBool = 1

	// SizeSOffsetT is the byte size of an SOffsetT.
	// The `SOffsetT` type is aliased (by flatbuffers convention) to int32.
	SizeSOffsetT = 4
	// SizeUOffsetT is the byte size of an UOffsetT.
	// The `UOffsetT` type is aliased (by flatbuffers convention) to uint32.
	SizeUOffsetT = 4
	// SizeVOffsetT is the byte size of an VOffsetT.
	// The `VOffsetT` type is aliased (by flatbuffers convention) to uint16.
	SizeVOffsetT = 2
)

// byteSliceToString converts a []byte to string without a heap allocation.
func byteSliceToString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}
<commit_msg>Restore the ''import "unsafe'' removed in 36daedf35fd0cc2ad0e5e24d187b25613c13660e. This was causing build failures with tools dependent on Flatbuffers in Go. E.g. go/src/github.com/google/flatbuffers/go/sizes.go:50: undefined: unsafe in unsafe.Pointer<commit_after>package flatbuffers

import (
        "unsafe"
)

const (
	// See http://golang.org/ref/spec#Numeric_types

	// SizeUint8 is the byte size of a uint8.
	SizeUint8 = 1
	// SizeUint16 is the byte size of a uint16.
	SizeUint16 = 2
	// SizeUint32 is the byte size of a uint32.
	SizeUint32 = 4
	// SizeUint64 is the byte size of a uint64.
	SizeUint64 = 8

	// SizeInt8 is the byte size of a int8.
	SizeInt8 = 1
	// SizeInt16 is the byte size of a int16.
	SizeInt16 = 2
	// SizeInt32 is the byte size of a int32.
	SizeInt32 = 4
	// SizeInt64 is the byte size of a int64.
	SizeInt64 = 8

	// SizeFloat32 is the byte size of a float32.
	SizeFloat32 = 4
	// SizeFloat64 is the byte size of a float64.
	SizeFloat64 = 8

	// SizeByte is the byte size of a byte.
	// The `byte` type is aliased (by Go definition) to uint8.
	SizeByte = 1

	// SizeBool is the byte size of a bool.
	// The `bool` type is aliased (by flatbuffers convention) to uint8.
	SizeBool = 1

	// SizeSOffsetT is the byte size of an SOffsetT.
	// The `SOffsetT` type is aliased (by flatbuffers convention) to int32.
	SizeSOffsetT = 4
	// SizeUOffsetT is the byte size of an UOffsetT.
	// The `UOffsetT` type is aliased (by flatbuffers convention) to uint32.
	SizeUOffsetT = 4
	// SizeVOffsetT is the byte size of an VOffsetT.
	// The `VOffsetT` type is aliased (by flatbuffers convention) to uint16.
	SizeVOffsetT = 2
)

// byteSliceToString converts a []byte to string without a heap allocation.
func byteSliceToString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}
<|endoftext|>


<commit_before>// Copyright 2016 Alex Fluter

package bot

import (
	"io"
	"net"
	"testing"
)

func matchNickRe(s string, t *testing.T) {
	var m []string
	m = nickRe.FindStringSubmatch(s)
	if m == nil {
		t.Fail()
	}
	t.Log(m)
}

func TestNickRe(t *testing.T) {
	var s string

	s = "fe!~fe@servx.ru"
	matchNickRe(s, t)

	s = "jayeshsolanki!~jayeshsol@219.91.250.106"
	matchNickRe(s, t)

	s = "j!~jayeshsol@219.91.250.106"
	matchNickRe(s, t)

	s = "de-facto_!~de-facto@unaffiliated/de-facto"
	matchNickRe(s, t)

	s = "c!~c@freenode"
	matchNickRe(s, t)
}

func newTestBot(ch chan bool) *Bot {
	config := &BotConfig{
		Trigger: '/',
		DataDir: "../data",
		DB:      "testbot",
		IRC: []*IRCConfig{
			&IRCConfig{
				Name:        "Localhost",
				Server:      "127.0.0.1",
				AutoConnect: false,
				Trigger:     '?',
				BotNick:     G,
				Channels: []*ChannelConfig{
					&ChannelConfig{
						Name:    "#candice",
						Repaste: true,
					},
				},
			},
		},
		CompileServer: "127.0.0.1:1234",
	}
	bot := NewBot("TestBot", config)
	go func() {
		bot.Start()
		ch <- true
	}()
	for bot.State != Running {
	}
	return bot
}

func delTestBot(bot *Bot, t *testing.T, ch chan bool) {
	bot.Stop()
	<-ch
	if bot.State != Stopped {
		t.Fail()
	}
}

func readLog(r io.Reader, t *testing.T) {
	buf := make([]byte, 1024)
	n, _ := r.Read(buf)
	t.Log(string(buf[:n]))
}

var (
	pc *int
	c  chan bool
)

func bashCmd(*MessageRequest, string) (string, error) {
	(*pc)++
	c <- true
	return "", nil
}

func TestIRCCommandChannel(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	var counter int
	c = make(chan bool)
	pc = &counter
	irc.interpreter.RegisterCommand("bash", bashCmd)

	irc.onCommand("PRIVMSG", "", "#candice :hello")
	// channel messages
	irc.onCommand("PRIVMSG", "", "#candice :bash")
	// call with trigger
	irc.onCommand("PRIVMSG", "", "#candice :?bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :!bash")
	irc.onCommand("PRIVMSG", "", "#candice :?bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :,bash arg1 arg2")
	// call with nick, 1st form
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti: bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti, bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti; bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti. bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti! bash")
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti: bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti, bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti; bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti. bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti! bash arg1 arg2")
	// call with nick, 2nd form
	irc.onCommand("PRIVMSG", "", "#candice :bash, Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash. Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash: Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash; Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash! Subhuti")
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2, Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2. Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2: Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2; Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2! Subhuti")

	if counter != 18 {
		t.Fail()
	}

	for irc.interpreter.total != 26 {
	}

	delTestBot(bot, t, ch)
}

func TestIRCCommandPrivate(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	var counter int
	var c chan bool = make(chan bool)
	irc.interpreter.RegisterCommand("bash", bashCmd)

	irc.onCommand("PRIVMSG", "", "foo :hello")
	// channel messages
	irc.onCommand("PRIVMSG", "", "foo :bash")
	<-c
	// call with trigger
	irc.onCommand("PRIVMSG", "", "foo :?bash")
	<-c
	irc.onCommand("PRIVMSG", "", "foo :!bash")
	irc.onCommand("PRIVMSG", "", "foo :?bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "foo :,bash arg1 arg2")

	if counter != 3 {
		t.Fail()
	}

	for irc.interpreter.total != 6 {
	}

	delTestBot(bot, t, ch)
}

func TestIRCURLParserGetTitle(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	r, w := net.Pipe()
	irc.conn = w

	irc.onCommand("PRIVMSG", "foo", "#candice :https://www.bing.com")
	readLog(r, t)

	irc.conn = nil
	delTestBot(bot, t, ch)
}

func TestIRCURLParserPaste(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	r, w := net.Pipe()
	irc.conn = w

	irc.onCommand("PRIVMSG", "foo", "#candice :http://ideone.com/FllowW")
	readLog(r, t)

	irc.onCommand("PRIVMSG", "foo", "#candice :http://sprunge.us/RWOP")
	readLog(r, t)

	// no repaste and no reply
	irc.onCommand("PRIVMSG", "foo", "#candice :http://sprunge.us/UjQf")

	irc.conn = nil
	delTestBot(bot, t, ch)
}

func TestIRCURLParserYoutube(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	r, w := net.Pipe()
	irc.conn = w

	irc.onCommand("PRIVMSG", "foo", "#candice :https://www.youtube.com/watch?v=Pd12BmxP-08")
	readLog(r, t)

	irc.onCommand("PRIVMSG", "foo", "#candice :https://youtube.com/watch?v=Pd12BmxP-08")
	readLog(r, t)

	irc.onCommand("PRIVMSG", "foo", "#candice :https://youtu.be/QEllLECo4OM")
	readLog(r, t)

	irc.conn = nil
	delTestBot(bot, t, ch)
}
<commit_msg>fix test case<commit_after>// Copyright 2016 Alex Fluter

package bot

import (
	"io"
	"net"
	"testing"
)

func matchNickRe(s string, t *testing.T) {
	var m []string
	m = nickRe.FindStringSubmatch(s)
	if m == nil {
		t.Fail()
	}
	t.Log(m)
}

func TestNickRe(t *testing.T) {
	var s string

	s = "fe!~fe@servx.ru"
	matchNickRe(s, t)

	s = "jayeshsolanki!~jayeshsol@219.91.250.106"
	matchNickRe(s, t)

	s = "j!~jayeshsol@219.91.250.106"
	matchNickRe(s, t)

	s = "de-facto_!~de-facto@unaffiliated/de-facto"
	matchNickRe(s, t)

	s = "c!~c@freenode"
	matchNickRe(s, t)
}

func newTestBot(ch chan bool) *Bot {
	config := &BotConfig{
		Trigger: '/',
		DataDir: "../data",
		DB:      "testbot",
		IRC: []*IRCConfig{
			&IRCConfig{
				Name:        "Localhost",
				Server:      "127.0.0.1",
				AutoConnect: false,
				Trigger:     '?',
				BotNick:     G,
				Channels: []*ChannelConfig{
					&ChannelConfig{
						Name:    "#candice",
						Repaste: true,
					},
				},
			},
		},
		CompileServer: "127.0.0.1:1234",
	}
	bot := NewBot("TestBot", config)
	go func() {
		bot.Start()
		ch <- true
	}()
	for bot.State != Running {
	}
	return bot
}

func delTestBot(bot *Bot, t *testing.T, ch chan bool) {
	bot.Stop()
	<-ch
	if bot.State != Stopped {
		t.Fail()
	}
}

func readLog(r io.Reader, t *testing.T) {
	buf := make([]byte, 1024)
	n, _ := r.Read(buf)
	t.Log(string(buf[:n]))
}

var (
	pc *int
	c  chan bool
)

func bashCmd(*MessageRequest, string) (string, error) {
	(*pc)++
	c <- true
	return "", nil
}

func TestIRCCommandChannel(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	var counter int
	c = make(chan bool)
	pc = &counter
	irc.interpreter.RegisterCommand("bash", bashCmd)

	irc.onCommand("PRIVMSG", "", "#candice :hello")
	// channel messages
	irc.onCommand("PRIVMSG", "", "#candice :bash")
	// call with trigger
	irc.onCommand("PRIVMSG", "", "#candice :?bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :!bash")
	irc.onCommand("PRIVMSG", "", "#candice :?bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :,bash arg1 arg2")
	// call with nick, 1st form
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti: bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti, bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti; bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti. bash")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti! bash")
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti: bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti, bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti; bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti. bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :Subhuti! bash arg1 arg2")
	// call with nick, 2nd form
	irc.onCommand("PRIVMSG", "", "#candice :bash, Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash. Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash: Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash; Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash! Subhuti")
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2, Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2. Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2: Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2; Subhuti")
	<-c
	irc.onCommand("PRIVMSG", "", "#candice :bash arg1 arg2! Subhuti")

	if counter != 18 {
		t.Fail()
	}

	for irc.interpreter.total != 26 {
	}

	delTestBot(bot, t, ch)
}

func TestIRCCommandPrivate(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	var counter int
	c = make(chan bool)
	pc = &counter
	irc.interpreter.RegisterCommand("bash", bashCmd)

	irc.onCommand("PRIVMSG", "", "foo :hello")
	// channel messages
	irc.onCommand("PRIVMSG", "", "foo :bash")
	<-c
	// call with trigger
	irc.onCommand("PRIVMSG", "", "foo :?bash")
	<-c
	irc.onCommand("PRIVMSG", "", "foo :!bash")
	irc.onCommand("PRIVMSG", "", "foo :?bash arg1 arg2")
	<-c
	irc.onCommand("PRIVMSG", "", "foo :,bash arg1 arg2")

	if counter != 3 {
		t.Fail()
	}

	for irc.interpreter.total != 6 {
	}

	delTestBot(bot, t, ch)
}

func TestIRCURLParserGetTitle(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	r, w := net.Pipe()
	irc.conn = w

	irc.onCommand("PRIVMSG", "foo", "#candice :https://www.bing.com")
	readLog(r, t)

	irc.conn = nil
	delTestBot(bot, t, ch)
}

func TestIRCURLParserPaste(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	r, w := net.Pipe()
	irc.conn = w

	irc.onCommand("PRIVMSG", "foo", "#candice :http://ideone.com/FllowW")
	readLog(r, t)

	irc.onCommand("PRIVMSG", "foo", "#candice :http://sprunge.us/RWOP")
	readLog(r, t)

	// no repaste and no reply
	irc.onCommand("PRIVMSG", "foo", "#candice :http://sprunge.us/UjQf")

	irc.conn = nil
	delTestBot(bot, t, ch)
}

func TestIRCURLParserYoutube(t *testing.T) {
	ch := make(chan bool)
	bot := newTestBot(ch)
	if bot.State != Running {
		t.Fail()
	}

	var irc *IRC
	for _, mod := range bot.modules {
		if _, ok := mod.(*IRC); ok {
			irc = mod.(*IRC)
			break
		}
	}
	if irc == nil {
		t.Fail()
	}

	r, w := net.Pipe()
	irc.conn = w

	irc.onCommand("PRIVMSG", "foo", "#candice :https://www.youtube.com/watch?v=Pd12BmxP-08")
	readLog(r, t)

	irc.onCommand("PRIVMSG", "foo", "#candice :https://youtube.com/watch?v=Pd12BmxP-08")
	readLog(r, t)

	irc.onCommand("PRIVMSG", "foo", "#candice :https://youtu.be/QEllLECo4OM")
	readLog(r, t)

	irc.conn = nil
	delTestBot(bot, t, ch)
}
<|endoftext|>


<commit_before>package detailed

import (
	"bytes"
	"fmt"
	"net/url"
	"strings"

	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/report"

	"github.com/ugorji/go/codec"
)

const (
	// Replacement variable name for the query in the metrics graph url
	urlQueryVarName = ":query"

	idReceiveBytes  = "receive_bytes"
	idTransmitBytes = "transmit_bytes"
)

var (
	// Metadata for shown queries
	shownQueries = []struct {
		ID    string
		Label string
	}{
		{
			ID:    docker.CPUTotalUsage,
			Label: "CPU",
		},
		{
			ID:    docker.MemoryUsage,
			Label: "Memory",
		},
		{
			ID:    idReceiveBytes,
			Label: "Rx/s",
		},
		{
			ID:    idTransmitBytes,
			Label: "Tx/s",
		},
	}

	// Queries on pod names of the format `name-<id>-<hash>`
	// See also:  https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#pod-template-hash-label
	podIDHashQueries = formatMetricQueries(`pod_name=~"^{{label}}-[^-]+-[^-]+$",namespace="{{namespace}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage})

	// Prometheus queries for topologies
	topologyQueries = map[string]map[string]string{
		// Containers

		report.Container:      formatMetricQueries(`name="{{containerName}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
		report.ContainerImage: formatMetricQueries(`image="{{label}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),

		// Kubernetes topologies

		report.Pod: formatMetricQueries(
			`pod_name="{{label}}",namespace="{{namespace}}"`,
			[]string{docker.MemoryUsage, docker.CPUTotalUsage},
		),
		report.DaemonSet:   formatMetricQueries(`pod_name=~"^{{label}}-[^-]+$",namespace="{{namespace}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
		report.Deployment:  podIDHashQueries,
		report.StatefulSet: podIDHashQueries,
		report.CronJob:     podIDHashQueries,
		report.Service: {
			// These recording rules must be defined in the prometheus config.
			// NB: Pods need to be labeled and selected by their respective Service name, meaning:
			// - The Service's `spec.selector` needs to select on `name`
			// - The Service's `metadata.name` needs to be the same value as `spec.selector.name`
			docker.CPUTotalUsage: `namespace_label_name:container_cpu_usage_seconds_total:sum_rate{label_name="{{label}}",namespace="{{namespace}}"}`,
			docker.MemoryUsage:   `namespace_label_name:container_memory_usage_bytes:sum{label_name="{{label}}",namespace="{{namespace}}"}`,
		},
	}
)

func formatMetricQueries(filter string, ids []string) map[string]string {
	queries := make(map[string]string)
	for _, id := range ids {
		// All  `container_*`metrics  are provided by cAdvisor in Kubelets
		switch id {
		case docker.MemoryUsage:
			queries[id] = fmt.Sprintf("sum(container_memory_usage_bytes{%s})", filter)
		case docker.CPUTotalUsage:
			queries[id] = fmt.Sprintf(
				"sum(rate(container_cpu_usage_seconds_total{%s}[1m]))/count(container_cpu_usage_seconds_total{%s})*100",
				filter,
				filter,
			)
		case idReceiveBytes:
			queries[id] = fmt.Sprintf("sum(rate(container_network_receive_bytes_total{%s}[5m]))", filter)
		case idTransmitBytes:
			queries[id] = fmt.Sprintf("sum(rate(container_network_transmit_bytes_total{%s}[5m]))", filter)
		}
	}

	return queries
}

// RenderMetricURLs sets respective URLs for metrics in a node summary. Missing metrics
// where we have a query for will be appended as an empty metric (no values or samples).
func RenderMetricURLs(summary NodeSummary, n report.Node, metricsGraphURL string) NodeSummary {
	if metricsGraphURL == "" {
		return summary
	}

	var maxprio float64
	var ms []report.MetricRow
	found := make(map[string]struct{})

	// Set URL on existing metrics
	for _, metric := range summary.Metrics {
		if metric.Priority > maxprio {
			maxprio = metric.Priority
		}

		query := metricQuery(summary, n, metric.ID)
		ms = append(ms, metric)

		if query != "" {
			ms[len(ms)-1].URL = metricURL(query, metricsGraphURL)
		}

		found[metric.ID] = struct{}{}
	}

	// Append empty metrics for unattached queries
	for _, metadata := range shownQueries {
		if _, ok := found[metadata.ID]; ok {
			continue
		}

		query := metricQuery(summary, n, metadata.ID)
		if query == "" {
			continue
		}

		maxprio++
		ms = append(ms, report.MetricRow{
			ID:         metadata.ID,
			Label:      metadata.Label,
			URL:        metricURL(query, metricsGraphURL),
			Metric:     &report.Metric{},
			Priority:   maxprio,
			ValueEmpty: true,
		})
	}

	summary.Metrics = ms

	return summary
}

// metricQuery returns the query for the given node and metric.
func metricQuery(summary NodeSummary, n report.Node, metricID string) string {
	queries := topologyQueries[n.Topology]
	if len(queries) == 0 {
		return ""
	}

	namespace, _ := n.Latest.Lookup(kubernetes.Namespace)
	name, _ := n.Latest.Lookup(docker.ContainerName)
	r := strings.NewReplacer(
		"{{label}}", summary.Label,
		"{{namespace}}", namespace,
		"{{containerName}}", name,
	)
	return r.Replace(queries[metricID])
}

// metricURL builds the URL by embedding it into the configured `metricsGraphURL`.
func metricURL(query, metricsGraphURL string) string {
	if strings.Contains(metricsGraphURL, urlQueryVarName) {
		return strings.Replace(metricsGraphURL, urlQueryVarName, queryEscape(query), -1)
	}

	params, err := queryParamsAsJSON(query)
	if err != nil {
		return ""
	}

	if metricsGraphURL[len(metricsGraphURL)-1] != '/' {
		metricsGraphURL += "/"
	}

	return metricsGraphURL + queryEscape(params)
}

// queryParamsAsJSON packs the query into a JSON of the format `{"cells":[{"queries":[$query]}]}`.
func queryParamsAsJSON(query string) (string, error) {
	type cell struct {
		Queries []string `json:"queries"`
	}
	type queryParams struct {
		Cells []cell `json:"cells"`
	}
	params := &queryParams{[]cell{{[]string{query}}}}

	buf := &bytes.Buffer{}
	encoder := codec.NewEncoder(buf, &codec.JsonHandle{})
	if err := encoder.Encode(params); err != nil {
		return "", err
	}

	return buf.String(), nil
}

// queryEscape uses `%20` instead of `+` to encode whitespaces. Both are
// valid but react-router does not decode `+` properly.
func queryEscape(query string) string {
	return url.QueryEscape(strings.Replace(query, " ", "%20", -1))
}
<commit_msg>Replace service cpu/mem link to 'Monitor'<commit_after>package detailed

import (
	"bytes"
	"fmt"
	"net/url"
	"strings"

	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/report"

	"github.com/ugorji/go/codec"
)

const (
	// Replacement variable name for the query in the metrics graph url
	urlQueryVarName = ":query"

	idReceiveBytes  = "receive_bytes"
	idTransmitBytes = "transmit_bytes"
)

var (
	// Metadata for shown queries
	shownQueries = []struct {
		ID    string
		Label string
	}{
		{
			ID:    docker.CPUTotalUsage,
			Label: "CPU",
		},
		{
			ID:    docker.MemoryUsage,
			Label: "Memory",
		},
		{
			ID:    idReceiveBytes,
			Label: "Rx/s",
		},
		{
			ID:    idTransmitBytes,
			Label: "Tx/s",
		},
	}

	// Queries on pod names of the format `name-<id>-<hash>`
	// See also:  https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#pod-template-hash-label
	podIDHashQueries = formatMetricQueries(`pod_name=~"^{{label}}-[^-]+-[^-]+$",namespace="{{namespace}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage})

	// Prometheus queries for topologies
	topologyQueries = map[string]map[string]string{
		// Containers

		report.Container:      formatMetricQueries(`name="{{containerName}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
		report.ContainerImage: formatMetricQueries(`image="{{label}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),

		// Kubernetes topologies

		report.Pod: formatMetricQueries(
			`pod_name="{{label}}",namespace="{{namespace}}"`,
			[]string{docker.MemoryUsage, docker.CPUTotalUsage},
		),
		report.DaemonSet:   formatMetricQueries(`pod_name=~"^{{label}}-[^-]+$",namespace="{{namespace}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
		report.Deployment:  podIDHashQueries,
		report.StatefulSet: podIDHashQueries,
		report.CronJob:     podIDHashQueries,
		report.Service: {
			// These recording rules must be defined in the prometheus config.
			// NB: Pods need to be labeled and selected by their respective Service name, meaning:
			// - The Service's `spec.selector` needs to select on `name`
			// - The Service's `metadata.name` needs to be the same value as `spec.selector.name`
			docker.CPUTotalUsage: `sum(rate(container_cpu_usage_seconds_total{image!="",namespace="{{namespace}}",_weave_pod_name="{{label}}",job="cadvisor",container_name!="POD"}[5m]))`,
			docker.MemoryUsage:   `sum(rate(container_memory_usage_bytes{image!="",namespace="{{namespace}}",_weave_pod_name="{{label}}",job="cadvisor",container_name!="POD"}[5m]))`,
		},
	}
)

func formatMetricQueries(filter string, ids []string) map[string]string {
	queries := make(map[string]string)
	for _, id := range ids {
		// All  `container_*`metrics  are provided by cAdvisor in Kubelets
		switch id {
		case docker.MemoryUsage:
			queries[id] = fmt.Sprintf("sum(container_memory_usage_bytes{%s})", filter)
		case docker.CPUTotalUsage:
			queries[id] = fmt.Sprintf(
				"sum(rate(container_cpu_usage_seconds_total{%s}[1m]))/count(container_cpu_usage_seconds_total{%s})*100",
				filter,
				filter,
			)
		case idReceiveBytes:
			queries[id] = fmt.Sprintf("sum(rate(container_network_receive_bytes_total{%s}[5m]))", filter)
		case idTransmitBytes:
			queries[id] = fmt.Sprintf("sum(rate(container_network_transmit_bytes_total{%s}[5m]))", filter)
		}
	}

	return queries
}

// RenderMetricURLs sets respective URLs for metrics in a node summary. Missing metrics
// where we have a query for will be appended as an empty metric (no values or samples).
func RenderMetricURLs(summary NodeSummary, n report.Node, metricsGraphURL string) NodeSummary {
	if metricsGraphURL == "" {
		return summary
	}

	var maxprio float64
	var ms []report.MetricRow
	found := make(map[string]struct{})

	// Set URL on existing metrics
	for _, metric := range summary.Metrics {
		if metric.Priority > maxprio {
			maxprio = metric.Priority
		}

		query := metricQuery(summary, n, metric.ID)
		ms = append(ms, metric)

		if query != "" {
			ms[len(ms)-1].URL = metricURL(query, metricsGraphURL)
		}

		found[metric.ID] = struct{}{}
	}

	// Append empty metrics for unattached queries
	for _, metadata := range shownQueries {
		if _, ok := found[metadata.ID]; ok {
			continue
		}

		query := metricQuery(summary, n, metadata.ID)
		if query == "" {
			continue
		}

		maxprio++
		ms = append(ms, report.MetricRow{
			ID:         metadata.ID,
			Label:      metadata.Label,
			URL:        metricURL(query, metricsGraphURL),
			Metric:     &report.Metric{},
			Priority:   maxprio,
			ValueEmpty: true,
		})
	}

	summary.Metrics = ms

	return summary
}

// metricQuery returns the query for the given node and metric.
func metricQuery(summary NodeSummary, n report.Node, metricID string) string {
	queries := topologyQueries[n.Topology]
	if len(queries) == 0 {
		return ""
	}

	namespace, _ := n.Latest.Lookup(kubernetes.Namespace)
	name, _ := n.Latest.Lookup(docker.ContainerName)
	r := strings.NewReplacer(
		"{{label}}", summary.Label,
		"{{namespace}}", namespace,
		"{{containerName}}", name,
	)
	return r.Replace(queries[metricID])
}

// metricURL builds the URL by embedding it into the configured `metricsGraphURL`.
func metricURL(query, metricsGraphURL string) string {
	if strings.Contains(metricsGraphURL, urlQueryVarName) {
		return strings.Replace(metricsGraphURL, urlQueryVarName, queryEscape(query), -1)
	}

	params, err := queryParamsAsJSON(query)
	if err != nil {
		return ""
	}

	if metricsGraphURL[len(metricsGraphURL)-1] != '/' {
		metricsGraphURL += "/"
	}

	return metricsGraphURL + queryEscape(params)
}

// queryParamsAsJSON packs the query into a JSON of the format `{"cells":[{"queries":[$query]}]}`.
func queryParamsAsJSON(query string) (string, error) {
	type cell struct {
		Queries []string `json:"queries"`
	}
	type queryParams struct {
		Cells []cell `json:"cells"`
	}
	params := &queryParams{[]cell{{[]string{query}}}}

	buf := &bytes.Buffer{}
	encoder := codec.NewEncoder(buf, &codec.JsonHandle{})
	if err := encoder.Encode(params); err != nil {
		return "", err
	}

	return buf.String(), nil
}

// queryEscape uses `%20` instead of `+` to encode whitespaces. Both are
// valid but react-router does not decode `+` properly.
func queryEscape(query string) string {
	return url.QueryEscape(strings.Replace(query, " ", "%20", -1))
}
<|endoftext|>


<commit_before>// Package ccs provides GCM CCS (Cloud Connection Server) client implementation using XMPP.
// https://developer.android.com/google/gcm/ccs.html
package ccs

import (
	"crypto/rand"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/nbusy/go-xmpp"
)

const (
	gcmMessageStanza = `<message id=""><gcm xmlns="google:mobile:data">%v</gcm></message>`
	gcmDomain        = "gcm.googleapis.com"
)

// Conn is a GCM CCS connection.
type Conn struct {
	Host, SenderID string
	Debug          bool
	xmppConn       *xmpp.Client
}

// Connect connects to GCM CCS server denoted by host (production or staging CCS endpoint URI) along with relevant credentials.
// Debug mode dumps all CSS communications to stdout.
func Connect(host, senderID, apiKey string, debug bool) (*Conn, error) {
	if !strings.Contains(senderID, gcmDomain) {
		senderID += "@" + gcmDomain
	}

	c, err := xmpp.NewClient(host, senderID, apiKey, debug)
	if debug {
		if err == nil {
			log.Printf("New CCS connection established with XMPP parameters: %+v\n", c)
		} else {
			log.Printf("New CCS connection failed to establish with XMPP parameters: %+v and with error: %v\n", c, err)
		}
	}
	if err != nil {
		return nil, err
	}

	return &Conn{
		Host:     host,
		SenderID: senderID,
		Debug:    debug,
		xmppConn: c,
	}, nil
}

// Receive retrieves the next incoming messages from the CCS connection.
func (c *Conn) Receive() (*InMsg, error) {
	event, err := c.xmppConn.Recv()
	if err != nil {
		return nil, err
	}

	switch v := event.(type) {
	case xmpp.Chat:
		isGcmMsg, message, err := c.handleMessage(v.Other[0])
		if err != nil {
			return nil, err
		}
		if isGcmMsg {
			return nil, nil
		}
		return message, nil
	case xmpp.Presence:
		return nil, fmt.Errorf("XMPP presence message from CCS which is not valid: %+v\n", v)
	default:
		return nil, fmt.Errorf("Unknown XMPP message type from CCS: %+v\n", v)
	}
}

// isGcmMsg indicates if this is a GCM control message (ack, nack, receipt, control) coming from the CCS server.
// If so, the message is automatically handled with appropriate response. Otherwise, it is sent to the
// parent app server for handling.
func (c *Conn) handleMessage(msg string) (isGcmMsg bool, message *InMsg, err error) {
	log.Printf("Incoming raw CCS message: %+v\n", msg)
	var m InMsg
	if err = json.Unmarshal([]byte(msg), &m); err != nil {
		return false, nil, errors.New("unknow message from CCS")
	}

	switch m.MessageType {
	case "ack":
		return true, nil, nil
	case "nack":
		errFormat := "From: %v, Message ID: %v, Error: %v, Error Description: %v"
		result := fmt.Sprintf(errFormat, m.From, m.ID, m.Err, m.ErrDesc)
		return true, nil, errors.New(result)
	case "receipt":
		return true, nil, nil
	case "control":
		return true, nil, nil
	default:
		// acknowledge the incoming message as per spec
		if m.From != "" {
			ack := &OutMsg{MessageType: "ack", To: m.From, ID: m.ID}
			if _, err = c.Send(ack); err != nil {
				return false, nil, fmt.Errorf("Failed to send ack message to CCS. Error was: %v", err)
			}
			return false, &m, nil
		}
	}

	return false, nil, errors.New("unknow message")
}

// Send sends a message to GCM CCS server and returns the number of bytes written and any error encountered.
func (c *Conn) Send(m *OutMsg) (n int, err error) {
	if m.ID == "" {
		if m.ID, err = getMsgID(); err != nil {
			return 0, err
		}
	}

	mb, err := json.Marshal(m)
	if err != nil {
		return 0, err
	}
	ms := string(mb)
	res := fmt.Sprintf(gcmMessageStanza, ms)
	return c.xmppConn.SendOrg(res)
}

// getID generates a unique message ID using crypto/rand in the form "m-96bitBase16"
func getMsgID() (string, error) {
	b := make([]byte, 12)
	if _, err := rand.Read(b); err != nil {
		return "", err
	}
	return fmt.Sprintf("m-%x", b), nil
}

// Close a CSS connection.
func (c *Conn) Close() error {
	return c.xmppConn.Close()
}
<commit_msg>simplify things futher<commit_after>// Package ccs provides GCM CCS (Cloud Connection Server) client implementation using XMPP.
// https://developer.android.com/google/gcm/ccs.html
package ccs

import (
	"crypto/rand"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/nbusy/go-xmpp"
)

const (
	gcmMessageStanza = `<message id=""><gcm xmlns="google:mobile:data">%v</gcm></message>`
	gcmDomain        = "gcm.googleapis.com"
)

// Conn is a GCM CCS connection.
type Conn struct {
	Host, SenderID string
	Debug          bool
	xmppConn       *xmpp.Client
}

// Connect connects to GCM CCS server denoted by host (production or staging CCS endpoint URI) along with relevant credentials.
// Debug mode dumps all CSS communications to stdout.
func Connect(host, senderID, apiKey string, debug bool) (*Conn, error) {
	if !strings.Contains(senderID, gcmDomain) {
		senderID += "@" + gcmDomain
	}

	c, err := xmpp.NewClient(host, senderID, apiKey, debug)
	if debug {
		if err == nil {
			log.Printf("New CCS connection established with XMPP parameters: %+v\n", c)
		} else {
			log.Printf("New CCS connection failed to establish with XMPP parameters: %+v and with error: %v\n", c, err)
		}
	}
	if err != nil {
		return nil, err
	}

	return &Conn{
		Host:     host,
		SenderID: senderID,
		Debug:    debug,
		xmppConn: c,
	}, nil
}

// Receive retrieves the next incoming messages from the CCS connection.
func (c *Conn) Receive() (*InMsg, error) {
	event, err := c.xmppConn.Recv()
	if err != nil {
		return nil, err
	}

	chat, ok := event.(xmpp.Chat)
	if !ok {
		return nil, nil
	}

	log.Printf("Incoming raw CCS message: %+v\n", chat)

	var m InMsg
	if err = json.Unmarshal([]byte(chat.Other[0]), &m); err != nil { // todo: handle other fields of chat (remote/type/text/other[1,2,..])
		return nil, errors.New("unknow message from CCS")
	}

	switch m.MessageType {
	case "ack":
		return nil, nil
	case "nack":
		errFormat := "From: %v, Message ID: %v, Error: %v, Error Description: %v"
		result := fmt.Sprintf(errFormat, m.From, m.ID, m.Err, m.ErrDesc)
		return nil, errors.New(result)
	case "receipt":
		return nil, nil
	case "control":
		return nil, nil
	case "":
		// acknowledge the incoming message as per specs
		if m.From != "" { // todo: what if From is empty? review specs
			ack := &OutMsg{MessageType: "ack", To: m.From, ID: m.ID}
			if _, err = c.Send(ack); err != nil {
				return nil, fmt.Errorf("Failed to send ack message to CCS. Error was: %v", err)
			}
			return &m, nil
		}
	default:
		// unknown message types are ignored as adviced by the specs
	}
	return &m, nil
}

// Send sends a message to GCM CCS server and returns the number of bytes written and any error encountered.
func (c *Conn) Send(m *OutMsg) (n int, err error) {
	if m.ID == "" {
		if m.ID, err = getMsgID(); err != nil {
			return 0, err
		}
	}

	mb, err := json.Marshal(m)
	if err != nil {
		return 0, err
	}
	ms := string(mb)
	res := fmt.Sprintf(gcmMessageStanza, ms)
	return c.xmppConn.SendOrg(res)
}

// getID generates a unique message ID using crypto/rand in the form "m-96bitBase16"
func getMsgID() (string, error) {
	b := make([]byte, 12)
	if _, err := rand.Read(b); err != nil {
		return "", err
	}
	return fmt.Sprintf("m-%x", b), nil
}

// Close a CSS connection.
func (c *Conn) Close() error {
	return c.xmppConn.Close()
}
<|endoftext|>