<commit_before>// Copyright (c) 2014-2019 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package account

import (
	"bytes"

	"golang.org/x/crypto/ed25519"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/sha3"

	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/util"
)

// PrivateKey - base type for PrivateKey
type PrivateKey struct {
	PrivateKeyInterface
}

// PrivateKeyInterface - interface type for private key methods
type PrivateKeyInterface interface {
	Account() *Account
	KeyType() int
	PrivateKeyBytes() []byte
	Bytes() []byte
	String() string
	IsTesting() bool
	MarshalText() ([]byte, error)
}

// ED25519PrivateKey - structure for ed25519 keys
type ED25519PrivateKey struct {
	Test       bool
	PrivateKey []byte
}

// NothingPrivateKey - just for debugging
type NothingPrivateKey struct {
	Test       bool
	PrivateKey []byte
}

// seed parameters
var (
	seedHeader   = []byte{0x5a, 0xfe}
	seedHeaderV1 = append(seedHeader, []byte{0x01}...)
	seedHeaderV2 = append(seedHeader, []byte{0x02}...)
)

// for seed v1 only
var (
	seedNonce = [24]byte{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}
	authSeedIndex = [16]byte{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe7,
	}
)

const (
	seedHeaderLength   = 3
	seedPrefixLength   = 1
	secretKeyV1Length  = 32
	secretKeyV2Length  = 17
	seedChecksumLength = 4

	base58EncodedSeedV1Length = 40
	base58EncodedSeedV2Length = 24
)

// PrivateKeyFromBase58Seed - this converts a Base58 encoded seed string and returns a private key
//
// one of the specific private key types are returned using the base "PrivateKeyInterface"
// interface type to allow individual methods to be called.
func PrivateKeyFromBase58Seed(seedBase58Encoded string) (*PrivateKey, error) {

	// verify length
	seed := util.FromBase58(seedBase58Encoded)
	seedLength := len(seed)
	if base58EncodedSeedV1Length != seedLength && base58EncodedSeedV2Length != seedLength {
		return nil, fault.ErrInvalidSeedLength
	}

	// verify checksum
	digest := sha3.Sum256(seed[:seedLength-checksumLength])
	checksumStart := seedLength - seedChecksumLength
	expectedChecksum := digest[:seedChecksumLength]
	actualChecksum := seed[checksumStart:]
	if !bytes.Equal(expectedChecksum, actualChecksum) {
		return nil, fault.ErrChecksumMismatch
	}

	header := seed[:seedHeaderLength]
	var encryptedSk []byte // encrypted seed for generate key pair
	var isTest bool        // denote the network is test net

	switch {
	case bytes.Equal(seedHeaderV1, header):
		// copy the secret key from seed
		var sk [secretKeyV1Length]byte
		secretStart := seedHeaderLength + seedPrefixLength
		copy(sk[:], seed[secretStart:])

		prefix := seed[seedHeaderLength:secretStart]
		// first byte of prefix is test/live indication
		isTest = prefix[0] == 0x01

		encryptedSk = secretbox.Seal([]byte{}, authSeedIndex[:], &seedNonce, &sk)

	case bytes.Equal(seedHeaderV2, header):
		sk := seed[seedHeaderLength:checksumStart]

		// verify valid secret key
		if secretKeyV2Length != len(sk) || 0 != sk[16]&0x0f {
			return nil, fault.ErrInvalidSeedLength
		}

		// parse network
		mode := sk[0]&0x80 | sk[1]&0x40 | sk[2]&0x20 | sk[3]&0x10
		isTest = mode == sk[15]&0xf0^0xf0

		// add the seed 4 times to hash value
		hash := sha3.NewShake256()
		for i := 0; i < 4; i++ {
			n, err := hash.Write(sk)
			if err != nil {
				return nil, err
			}
			if secretKeyV2Length != n {
				return nil, fault.InvalidError("secret key is not written successfully")
			}
		}

		const encryptedLength = 32
		encryptedSk = make([]byte, encryptedLength)
		n, err := hash.Read(encryptedSk)
		if nil != err {
			return nil, err
		}
		if encryptedLength != n {
			return nil, fault.InvalidError("encrypted secret is not read successfully")
		}

	default:
		return nil, fault.ErrInvalidSeedHeader
	}

	// generate key pair from encrypted secret key
	_, priv, err := ed25519.GenerateKey(bytes.NewBuffer(encryptedSk))
	if nil != err {
		return nil, err
	}

	privateKey := &PrivateKey{
		PrivateKeyInterface: &ED25519PrivateKey{
			Test:       isTest,
			PrivateKey: priv,
		},
	}
	return privateKey, nil
}

// PrivateKeyFromBase58 - this converts a Base58 encoded string and returns an private key
//
// one of the specific private key types are returned using the base "PrivateKeyInterface"
// interface type to allow individual methods to be called.
func PrivateKeyFromBase58(privateKeyBase58Encoded string) (*PrivateKey, error) {
	// Decode the privateKey
	privateKeyDecoded := util.FromBase58(privateKeyBase58Encoded)
	if 0 == len(privateKeyDecoded) {
		return nil, fault.ErrCannotDecodePrivateKey
	}

	// Parse the key variant
	keyVariant, keyVariantLength := util.FromVarint64(privateKeyDecoded)

	// Check key type
	if 0 == keyVariantLength || keyVariant&publicKeyCode == publicKeyCode {
		return nil, fault.ErrNotPrivateKey
	}

	// compute algorithm
	keyAlgorithm := keyVariant >> algorithmShift
	if keyAlgorithm >= algorithmLimit {
		return nil, fault.ErrInvalidKeyType
	}

	// network selection
	isTest := 0 != keyVariant&testKeyCode

	// Compute key length
	keyLength := len(privateKeyDecoded) - keyVariantLength - checksumLength
	if keyLength <= 0 {
		return nil, fault.ErrInvalidKeyLength
	}

	// Checksum
	checksumStart := len(privateKeyDecoded) - checksumLength
	checksum := sha3.Sum256(privateKeyDecoded[:checksumStart])
	if !bytes.Equal(checksum[:checksumLength], privateKeyDecoded[checksumStart:]) {
		return nil, fault.ErrChecksumMismatch
	}

	// return a pointer to the specific private key type
	switch keyAlgorithm {
	case ED25519:
		if keyLength != ed25519.PrivateKeySize {
			return nil, fault.ErrInvalidKeyLength
		}
		priv := privateKeyDecoded[keyVariantLength:checksumStart]
		privateKey := &PrivateKey{
			PrivateKeyInterface: &ED25519PrivateKey{
				Test:       isTest,
				PrivateKey: priv,
			},
		}
		return privateKey, nil
	case Nothing:
		if 2 != keyLength {
			return nil, fault.ErrInvalidKeyLength
		}
		priv := privateKeyDecoded[keyVariantLength:checksumStart]
		privateKey := &PrivateKey{
			PrivateKeyInterface: &NothingPrivateKey{
				Test:       isTest,
				PrivateKey: priv,
			},
		}
		return privateKey, nil
	default:
		return nil, fault.ErrInvalidKeyType
	}
}

// PrivateKeyFromBytes - this converts a byte encoded buffer and returns an private key
//
// one of the specific private key types are returned using the base "PrivateKeyInterface"
// interface type to allow individual methods to be called.
func PrivateKeyFromBytes(privateKeyBytes []byte) (*PrivateKey, error) {

	// Parse the key variant
	keyVariant, keyVariantLength := util.FromVarint64(privateKeyBytes)

	// Check key type
	if 0 == keyVariantLength || keyVariant&publicKeyCode == publicKeyCode {
		return nil, fault.ErrNotPrivateKey
	}

	// compute algorithm
	keyAlgorithm := keyVariant >> algorithmShift
	if keyAlgorithm < 0 || keyAlgorithm >= algorithmLimit {
		return nil, fault.ErrInvalidKeyType
	}

	// network selection
	isTest := 0 != keyVariant&testKeyCode

	// Compute key length
	keyLength := len(privateKeyBytes) - keyVariantLength
	if keyLength <= 0 {
		return nil, fault.ErrInvalidKeyLength
	}

	// return a pointer to the specific private key type
	switch keyAlgorithm {
	case ED25519:
		if keyLength != ed25519.PrivateKeySize {
			return nil, fault.ErrInvalidKeyLength
		}
		priv := privateKeyBytes[keyVariantLength:]
		privateKey := &PrivateKey{
			PrivateKeyInterface: &ED25519PrivateKey{
				Test:       isTest,
				PrivateKey: priv,
			},
		}
		return privateKey, nil
	case Nothing:
		if 2 != keyLength {
			return nil, fault.ErrInvalidKeyLength
		}
		priv := privateKeyBytes[keyVariantLength:]
		privateKey := &PrivateKey{
			PrivateKeyInterface: &NothingPrivateKey{
				Test:       isTest,
				PrivateKey: priv,
			},
		}
		return privateKey, nil
	default:
		return nil, fault.ErrInvalidKeyType
	}
}

// UnmarshalText - convert string to private key structure
func (privateKey *PrivateKey) UnmarshalText(s []byte) error {
	a, err := PrivateKeyFromBase58(string(s))
	if nil != err {
		return err
	}
	privateKey.PrivateKeyInterface = a.PrivateKeyInterface
	return nil
}

// ED25519
// -------

// IsTesting - return whether the private key is in test mode or not
func (privateKey *ED25519PrivateKey) IsTesting() bool {
	return privateKey.Test
}

// KeyType - key type code (see enumeration in account.go)
func (privateKey *ED25519PrivateKey) KeyType() int {
	return ED25519
}

// Account - return the corresponding account
func (privateKey *ED25519PrivateKey) Account() *Account {
	return &Account{
		AccountInterface: &ED25519Account{
			Test:      privateKey.Test,
			PublicKey: privateKey.PrivateKey[ed25519.PrivateKeySize-ed25519.PublicKeySize:],
		},
	}
}

// PrivateKeyBytes - fetch the private key as byte slice
func (privateKey *ED25519PrivateKey) PrivateKeyBytes() []byte {
	return privateKey.PrivateKey[:]
}

// Bytes - byte slice for encoded key
func (privateKey *ED25519PrivateKey) Bytes() []byte {
	keyVariant := byte(ED25519 << algorithmShift)
	if privateKey.Test {
		keyVariant |= testKeyCode
	}
	return append([]byte{keyVariant}, privateKey.PrivateKey[:]...)
}

// String - base58 encoding of encoded key
func (privateKey *ED25519PrivateKey) String() string {
	buffer := privateKey.Bytes()
	checksum := sha3.Sum256(buffer)
	buffer = append(buffer, checksum[:checksumLength]...)
	return util.ToBase58(buffer)
}

// MarshalText - convert an privateKey to its Base58 JSON form
func (privateKey ED25519PrivateKey) MarshalText() ([]byte, error) {
	return []byte(privateKey.String()), nil
}

// Nothing
// -------

// IsTesting - return whether the private key is in test mode or not
func (privateKey *NothingPrivateKey) IsTesting() bool {
	return privateKey.Test
}

// KeyType - key type code (see enumeration in account.go)
func (privateKey *NothingPrivateKey) KeyType() int {
	return Nothing
}

// Account - return the corresponding account
func (privateKey *NothingPrivateKey) Account() *Account {
	return nil
}

// PrivateKeyBytes - fetch the private key as byte slice
func (privateKey *NothingPrivateKey) PrivateKeyBytes() []byte {
	return privateKey.PrivateKey[:]
}

// Bytes - byte slice for encoded key
func (privateKey *NothingPrivateKey) Bytes() []byte {
	keyVariant := byte(Nothing << algorithmShift)
	if privateKey.Test {
		keyVariant |= testKeyCode
	}
	return append([]byte{keyVariant}, privateKey.PrivateKey[:]...)
}

// String - base58 encoding of encoded key
func (privateKey *NothingPrivateKey) String() string {
	buffer := privateKey.Bytes()
	checksum := sha3.Sum256(buffer)
	buffer = append(buffer, checksum[:checksumLength]...)
	return util.ToBase58(buffer)
}

// MarshalText - convert an privateKey to its Base58 JSON form
func (privateKey NothingPrivateKey) MarshalText() ([]byte, error) {
	return []byte(privateKey.String()), nil
}
<commit_msg>[account] - Fixes no value of type uint64 is less than 0 (SA4003)<commit_after>// Copyright (c) 2014-2019 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package account

import (
	"bytes"

	"golang.org/x/crypto/ed25519"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/sha3"

	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/util"
)

// PrivateKey - base type for PrivateKey
type PrivateKey struct {
	PrivateKeyInterface
}

// PrivateKeyInterface - interface type for private key methods
type PrivateKeyInterface interface {
	Account() *Account
	KeyType() int
	PrivateKeyBytes() []byte
	Bytes() []byte
	String() string
	IsTesting() bool
	MarshalText() ([]byte, error)
}

// ED25519PrivateKey - structure for ed25519 keys
type ED25519PrivateKey struct {
	Test       bool
	PrivateKey []byte
}

// NothingPrivateKey - just for debugging
type NothingPrivateKey struct {
	Test       bool
	PrivateKey []byte
}

// seed parameters
var (
	seedHeader   = []byte{0x5a, 0xfe}
	seedHeaderV1 = append(seedHeader, []byte{0x01}...)
	seedHeaderV2 = append(seedHeader, []byte{0x02}...)
)

// for seed v1 only
var (
	seedNonce = [24]byte{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}
	authSeedIndex = [16]byte{
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe7,
	}
)

const (
	seedHeaderLength   = 3
	seedPrefixLength   = 1
	secretKeyV1Length  = 32
	secretKeyV2Length  = 17
	seedChecksumLength = 4

	base58EncodedSeedV1Length = 40
	base58EncodedSeedV2Length = 24
)

// PrivateKeyFromBase58Seed - this converts a Base58 encoded seed string and returns a private key
//
// one of the specific private key types are returned using the base "PrivateKeyInterface"
// interface type to allow individual methods to be called.
func PrivateKeyFromBase58Seed(seedBase58Encoded string) (*PrivateKey, error) {

	// verify length
	seed := util.FromBase58(seedBase58Encoded)
	seedLength := len(seed)
	if base58EncodedSeedV1Length != seedLength && base58EncodedSeedV2Length != seedLength {
		return nil, fault.ErrInvalidSeedLength
	}

	// verify checksum
	digest := sha3.Sum256(seed[:seedLength-checksumLength])
	checksumStart := seedLength - seedChecksumLength
	expectedChecksum := digest[:seedChecksumLength]
	actualChecksum := seed[checksumStart:]
	if !bytes.Equal(expectedChecksum, actualChecksum) {
		return nil, fault.ErrChecksumMismatch
	}

	header := seed[:seedHeaderLength]
	var encryptedSk []byte // encrypted seed for generate key pair
	var isTest bool        // denote the network is test net

	switch {
	case bytes.Equal(seedHeaderV1, header):
		// copy the secret key from seed
		var sk [secretKeyV1Length]byte
		secretStart := seedHeaderLength + seedPrefixLength
		copy(sk[:], seed[secretStart:])

		prefix := seed[seedHeaderLength:secretStart]
		// first byte of prefix is test/live indication
		isTest = prefix[0] == 0x01

		encryptedSk = secretbox.Seal([]byte{}, authSeedIndex[:], &seedNonce, &sk)

	case bytes.Equal(seedHeaderV2, header):
		sk := seed[seedHeaderLength:checksumStart]

		// verify valid secret key
		if secretKeyV2Length != len(sk) || 0 != sk[16]&0x0f {
			return nil, fault.ErrInvalidSeedLength
		}

		// parse network
		mode := sk[0]&0x80 | sk[1]&0x40 | sk[2]&0x20 | sk[3]&0x10
		isTest = mode == sk[15]&0xf0^0xf0

		// add the seed 4 times to hash value
		hash := sha3.NewShake256()
		for i := 0; i < 4; i++ {
			n, err := hash.Write(sk)
			if err != nil {
				return nil, err
			}
			if secretKeyV2Length != n {
				return nil, fault.InvalidError("secret key is not written successfully")
			}
		}

		const encryptedLength = 32
		encryptedSk = make([]byte, encryptedLength)
		n, err := hash.Read(encryptedSk)
		if nil != err {
			return nil, err
		}
		if encryptedLength != n {
			return nil, fault.InvalidError("encrypted secret is not read successfully")
		}

	default:
		return nil, fault.ErrInvalidSeedHeader
	}

	// generate key pair from encrypted secret key
	_, priv, err := ed25519.GenerateKey(bytes.NewBuffer(encryptedSk))
	if nil != err {
		return nil, err
	}

	privateKey := &PrivateKey{
		PrivateKeyInterface: &ED25519PrivateKey{
			Test:       isTest,
			PrivateKey: priv,
		},
	}
	return privateKey, nil
}

// PrivateKeyFromBase58 - this converts a Base58 encoded string and returns an private key
//
// one of the specific private key types are returned using the base "PrivateKeyInterface"
// interface type to allow individual methods to be called.
func PrivateKeyFromBase58(privateKeyBase58Encoded string) (*PrivateKey, error) {
	// Decode the privateKey
	privateKeyDecoded := util.FromBase58(privateKeyBase58Encoded)
	if 0 == len(privateKeyDecoded) {
		return nil, fault.ErrCannotDecodePrivateKey
	}

	// Parse the key variant
	keyVariant, keyVariantLength := util.FromVarint64(privateKeyDecoded)

	// Check key type
	if 0 == keyVariantLength || keyVariant&publicKeyCode == publicKeyCode {
		return nil, fault.ErrNotPrivateKey
	}

	// compute algorithm
	keyAlgorithm := keyVariant >> algorithmShift
	if keyAlgorithm >= algorithmLimit {
		return nil, fault.ErrInvalidKeyType
	}

	// network selection
	isTest := 0 != keyVariant&testKeyCode

	// Compute key length
	keyLength := len(privateKeyDecoded) - keyVariantLength - checksumLength
	if keyLength <= 0 {
		return nil, fault.ErrInvalidKeyLength
	}

	// Checksum
	checksumStart := len(privateKeyDecoded) - checksumLength
	checksum := sha3.Sum256(privateKeyDecoded[:checksumStart])
	if !bytes.Equal(checksum[:checksumLength], privateKeyDecoded[checksumStart:]) {
		return nil, fault.ErrChecksumMismatch
	}

	// return a pointer to the specific private key type
	switch keyAlgorithm {
	case ED25519:
		if keyLength != ed25519.PrivateKeySize {
			return nil, fault.ErrInvalidKeyLength
		}
		priv := privateKeyDecoded[keyVariantLength:checksumStart]
		privateKey := &PrivateKey{
			PrivateKeyInterface: &ED25519PrivateKey{
				Test:       isTest,
				PrivateKey: priv,
			},
		}
		return privateKey, nil
	case Nothing:
		if 2 != keyLength {
			return nil, fault.ErrInvalidKeyLength
		}
		priv := privateKeyDecoded[keyVariantLength:checksumStart]
		privateKey := &PrivateKey{
			PrivateKeyInterface: &NothingPrivateKey{
				Test:       isTest,
				PrivateKey: priv,
			},
		}
		return privateKey, nil
	default:
		return nil, fault.ErrInvalidKeyType
	}
}

// PrivateKeyFromBytes - this converts a byte encoded buffer and returns an private key
//
// one of the specific private key types are returned using the base "PrivateKeyInterface"
// interface type to allow individual methods to be called.
func PrivateKeyFromBytes(privateKeyBytes []byte) (*PrivateKey, error) {

	// Parse the key variant
	keyVariant, keyVariantLength := util.FromVarint64(privateKeyBytes)

	// Check key type
	if 0 == keyVariantLength || keyVariant&publicKeyCode == publicKeyCode {
		return nil, fault.ErrNotPrivateKey
	}

	// compute algorithm
	keyAlgorithm := keyVariant >> algorithmShift
	if keyAlgorithm >= algorithmLimit {
		return nil, fault.ErrInvalidKeyType
	}

	// network selection
	isTest := 0 != keyVariant&testKeyCode

	// Compute key length
	keyLength := len(privateKeyBytes) - keyVariantLength
	if keyLength <= 0 {
		return nil, fault.ErrInvalidKeyLength
	}

	// return a pointer to the specific private key type
	switch keyAlgorithm {
	case ED25519:
		if keyLength != ed25519.PrivateKeySize {
			return nil, fault.ErrInvalidKeyLength
		}
		priv := privateKeyBytes[keyVariantLength:]
		privateKey := &PrivateKey{
			PrivateKeyInterface: &ED25519PrivateKey{
				Test:       isTest,
				PrivateKey: priv,
			},
		}
		return privateKey, nil
	case Nothing:
		if 2 != keyLength {
			return nil, fault.ErrInvalidKeyLength
		}
		priv := privateKeyBytes[keyVariantLength:]
		privateKey := &PrivateKey{
			PrivateKeyInterface: &NothingPrivateKey{
				Test:       isTest,
				PrivateKey: priv,
			},
		}
		return privateKey, nil
	default:
		return nil, fault.ErrInvalidKeyType
	}
}

// UnmarshalText - convert string to private key structure
func (privateKey *PrivateKey) UnmarshalText(s []byte) error {
	a, err := PrivateKeyFromBase58(string(s))
	if nil != err {
		return err
	}
	privateKey.PrivateKeyInterface = a.PrivateKeyInterface
	return nil
}

// ED25519
// -------

// IsTesting - return whether the private key is in test mode or not
func (privateKey *ED25519PrivateKey) IsTesting() bool {
	return privateKey.Test
}

// KeyType - key type code (see enumeration in account.go)
func (privateKey *ED25519PrivateKey) KeyType() int {
	return ED25519
}

// Account - return the corresponding account
func (privateKey *ED25519PrivateKey) Account() *Account {
	return &Account{
		AccountInterface: &ED25519Account{
			Test:      privateKey.Test,
			PublicKey: privateKey.PrivateKey[ed25519.PrivateKeySize-ed25519.PublicKeySize:],
		},
	}
}

// PrivateKeyBytes - fetch the private key as byte slice
func (privateKey *ED25519PrivateKey) PrivateKeyBytes() []byte {
	return privateKey.PrivateKey[:]
}

// Bytes - byte slice for encoded key
func (privateKey *ED25519PrivateKey) Bytes() []byte {
	keyVariant := byte(ED25519 << algorithmShift)
	if privateKey.Test {
		keyVariant |= testKeyCode
	}
	return append([]byte{keyVariant}, privateKey.PrivateKey[:]...)
}

// String - base58 encoding of encoded key
func (privateKey *ED25519PrivateKey) String() string {
	buffer := privateKey.Bytes()
	checksum := sha3.Sum256(buffer)
	buffer = append(buffer, checksum[:checksumLength]...)
	return util.ToBase58(buffer)
}

// MarshalText - convert an privateKey to its Base58 JSON form
func (privateKey ED25519PrivateKey) MarshalText() ([]byte, error) {
	return []byte(privateKey.String()), nil
}

// Nothing
// -------

// IsTesting - return whether the private key is in test mode or not
func (privateKey *NothingPrivateKey) IsTesting() bool {
	return privateKey.Test
}

// KeyType - key type code (see enumeration in account.go)
func (privateKey *NothingPrivateKey) KeyType() int {
	return Nothing
}

// Account - return the corresponding account
func (privateKey *NothingPrivateKey) Account() *Account {
	return nil
}

// PrivateKeyBytes - fetch the private key as byte slice
func (privateKey *NothingPrivateKey) PrivateKeyBytes() []byte {
	return privateKey.PrivateKey[:]
}

// Bytes - byte slice for encoded key
func (privateKey *NothingPrivateKey) Bytes() []byte {
	keyVariant := byte(Nothing << algorithmShift)
	if privateKey.Test {
		keyVariant |= testKeyCode
	}
	return append([]byte{keyVariant}, privateKey.PrivateKey[:]...)
}

// String - base58 encoding of encoded key
func (privateKey *NothingPrivateKey) String() string {
	buffer := privateKey.Bytes()
	checksum := sha3.Sum256(buffer)
	buffer = append(buffer, checksum[:checksumLength]...)
	return util.ToBase58(buffer)
}

// MarshalText - convert an privateKey to its Base58 JSON form
func (privateKey NothingPrivateKey) MarshalText() ([]byte, error) {
	return []byte(privateKey.String()), nil
}
<|endoftext|>


<commit_before>package acl

import (
	"reflect"
	"testing"
)

func TestParse(t *testing.T) {
	inp := `
key "" {
	policy = "read"
}
key "foo/" {
	policy = "write"
}
key "foo/bar/" {
	policy = "read"
}
key "foo/bar/baz" {
	policy = "deny"
}
service "" {
	policy = "write"
}
service "foo" {
	policy = "read"
}
event "" {
	policy = "read"
}
event "foo" {
	policy = "write"
}
event "bar" {
	policy = "deny"
}
keyring = "deny"
	`
	exp := &Policy{
		Keys: []*KeyPolicy{
			&KeyPolicy{
				Prefix: "",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/",
				Policy: KeyPolicyWrite,
			},
			&KeyPolicy{
				Prefix: "foo/bar/",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/bar/baz",
				Policy: KeyPolicyDeny,
			},
		},
		Services: []*ServicePolicy{
			&ServicePolicy{
				Name:   "",
				Policy: ServicePolicyWrite,
			},
			&ServicePolicy{
				Name:   "foo",
				Policy: ServicePolicyRead,
			},
		},
		Events: []*EventPolicy{
			&EventPolicy{
				Event:  "",
				Policy: EventPolicyRead,
			},
			&EventPolicy{
				Event:  "foo",
				Policy: EventPolicyWrite,
			},
			&EventPolicy{
				Event:  "bar",
				Policy: EventPolicyDeny,
			},
		},
		Keyring: KeyringPolicyDeny,
	}

	out, err := Parse(inp)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !reflect.DeepEqual(out, exp) {
		t.Fatalf("bad: %#v %#v", out, exp)
	}
}

func TestParse_JSON(t *testing.T) {
	inp := `{
	"key": {
		"": {
			"policy": "read"
		},
		"foo/": {
			"policy": "write"
		},
		"foo/bar/": {
			"policy": "read"
		},
		"foo/bar/baz": {
			"policy": "deny"
		}
	},
	"service": {
		"": {
			"policy": "write"
		},
		"foo": {
			"policy": "read"
		}
	},
	"event": {
		"": {
			"policy": "read"
		},
		"foo": {
			"policy": "write"
		},
		"bar": {
			"policy": "deny"
		}
	},
	"keyring": "deny"
}`
	exp := &Policy{
		Keys: []*KeyPolicy{
			&KeyPolicy{
				Prefix: "",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/",
				Policy: KeyPolicyWrite,
			},
			&KeyPolicy{
				Prefix: "foo/bar/",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/bar/baz",
				Policy: KeyPolicyDeny,
			},
		},
		Services: []*ServicePolicy{
			&ServicePolicy{
				Name:   "",
				Policy: ServicePolicyWrite,
			},
			&ServicePolicy{
				Name:   "foo",
				Policy: ServicePolicyRead,
			},
		},
		Events: []*EventPolicy{
			&EventPolicy{
				Event:  "",
				Policy: EventPolicyRead,
			},
			&EventPolicy{
				Event:  "foo",
				Policy: EventPolicyWrite,
			},
			&EventPolicy{
				Event:  "bar",
				Policy: EventPolicyDeny,
			},
		},
		Keyring: KeyringPolicyDeny,
	}

	out, err := Parse(inp)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !reflect.DeepEqual(out, exp) {
		t.Fatalf("bad: %#v %#v", out, exp)
	}
}
<commit_msg>acl: adding negative tests for bad policy<commit_after>package acl

import (
	"reflect"
	"strings"
	"testing"
)

func TestParse(t *testing.T) {
	inp := `
key "" {
	policy = "read"
}
key "foo/" {
	policy = "write"
}
key "foo/bar/" {
	policy = "read"
}
key "foo/bar/baz" {
	policy = "deny"
}
service "" {
	policy = "write"
}
service "foo" {
	policy = "read"
}
event "" {
	policy = "read"
}
event "foo" {
	policy = "write"
}
event "bar" {
	policy = "deny"
}
keyring = "deny"
	`
	exp := &Policy{
		Keys: []*KeyPolicy{
			&KeyPolicy{
				Prefix: "",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/",
				Policy: KeyPolicyWrite,
			},
			&KeyPolicy{
				Prefix: "foo/bar/",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/bar/baz",
				Policy: KeyPolicyDeny,
			},
		},
		Services: []*ServicePolicy{
			&ServicePolicy{
				Name:   "",
				Policy: ServicePolicyWrite,
			},
			&ServicePolicy{
				Name:   "foo",
				Policy: ServicePolicyRead,
			},
		},
		Events: []*EventPolicy{
			&EventPolicy{
				Event:  "",
				Policy: EventPolicyRead,
			},
			&EventPolicy{
				Event:  "foo",
				Policy: EventPolicyWrite,
			},
			&EventPolicy{
				Event:  "bar",
				Policy: EventPolicyDeny,
			},
		},
		Keyring: KeyringPolicyDeny,
	}

	out, err := Parse(inp)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !reflect.DeepEqual(out, exp) {
		t.Fatalf("bad: %#v %#v", out, exp)
	}
}

func TestParse_JSON(t *testing.T) {
	inp := `{
	"key": {
		"": {
			"policy": "read"
		},
		"foo/": {
			"policy": "write"
		},
		"foo/bar/": {
			"policy": "read"
		},
		"foo/bar/baz": {
			"policy": "deny"
		}
	},
	"service": {
		"": {
			"policy": "write"
		},
		"foo": {
			"policy": "read"
		}
	},
	"event": {
		"": {
			"policy": "read"
		},
		"foo": {
			"policy": "write"
		},
		"bar": {
			"policy": "deny"
		}
	},
	"keyring": "deny"
}`
	exp := &Policy{
		Keys: []*KeyPolicy{
			&KeyPolicy{
				Prefix: "",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/",
				Policy: KeyPolicyWrite,
			},
			&KeyPolicy{
				Prefix: "foo/bar/",
				Policy: KeyPolicyRead,
			},
			&KeyPolicy{
				Prefix: "foo/bar/baz",
				Policy: KeyPolicyDeny,
			},
		},
		Services: []*ServicePolicy{
			&ServicePolicy{
				Name:   "",
				Policy: ServicePolicyWrite,
			},
			&ServicePolicy{
				Name:   "foo",
				Policy: ServicePolicyRead,
			},
		},
		Events: []*EventPolicy{
			&EventPolicy{
				Event:  "",
				Policy: EventPolicyRead,
			},
			&EventPolicy{
				Event:  "foo",
				Policy: EventPolicyWrite,
			},
			&EventPolicy{
				Event:  "bar",
				Policy: EventPolicyDeny,
			},
		},
		Keyring: KeyringPolicyDeny,
	}

	out, err := Parse(inp)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if !reflect.DeepEqual(out, exp) {
		t.Fatalf("bad: %#v %#v", out, exp)
	}
}

func TestACLPolicy_badPolicy(t *testing.T) {
	cases := []string{
		`key "" { policy = "nope" }`,
		`service "" { policy = "nope" }`,
		`event "" { policy = "nope" }`,
		`keyring = "nope"`,
	}
	for _, c := range cases {
		_, err := Parse(c)
		if err == nil || !strings.Contains(err.Error(), "Invalid") {
			t.Fatalf("expected policy error, got: %#v", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/github/hub/github"
	"github.com/mitchellh/go-homedir"
	"github.com/octokit/go-octokit/octokit"
)

const (
	exitOK = iota
	exitError
)

const version = "0.0.0"

func main() {
	os.Exit(run(os.Args[1:]))
}

func run(argv []string) int {
	remotes, err := github.Remotes()
	if err != nil || len(remotes) < 1 {
		log.Printf("can't detect remote repository: %#v\n", err)
		return exitError
	}
	proj, err := remotes[0].Project()
	if err != nil {
		log.Printf("failed to retrieve project: %#v\n", err)
		return exitError
	}
	fs := flag.NewFlagSet("mackerel-github-release", flag.ContinueOnError)
	var (
		dryRun  = fs.Bool("dry-run", false, "dry-run mode")
		staging = fs.Bool("staging", false, "staging release")
	)
	err = fs.Parse(argv)
	if err != nil {
		if err == flag.ErrHelp {
			return exitOK

		}
		return exitError
	}

	out, err := exec.Command("gobump", "show").Output()
	if err != nil {
		log.Printf("failed to `gobump show`: %#v\n", err)
		return exitError
	}

	var v struct {
		Version string `json:"version"`
	}
	err = json.Unmarshal(out, &v)
	if err != nil {
		log.Printf("failed to unmarshal `gobump show`'s output: %#v\n", err)
		return exitError
	}
	err = uploadToGithubRelease(proj, v.Version, *staging, *dryRun)
	if err != nil {
		log.Printf("error occured while uploading artifacts to github: %#v\n", err)
		return exitError
	}
	return exitOK
}

var errAlreadyReleased = fmt.Errorf("the release of this version has already existed at GitHub Relase, so skip the process")

func uploadToGithubRelease(proj *github.Project, releaseVer string, staging, dryRun bool) error {
	tag := "staging"
	if !staging {
		tag = "v" + releaseVer
	}
	repo, owner := proj.Name, proj.Owner
	octoCli := getOctoCli()

	pr, err := getReleasePullRequest(octoCli, owner, repo, releaseVer)
	if err != nil {
		return err
	}

	err = handleOldRelease(octoCli, owner, repo, tag, staging, dryRun)
	if err != nil {
		if err == errAlreadyReleased {
			log.Println(err.Error())
			return nil
		}
		return err
	}

	body := pr.Body
	assets, err := collectAssets()
	if err != nil {
		return fmt.Errorf("error occured while collecting releasing assets: %#v", err)
	}

	host, err := github.CurrentConfig().PromptForHost(proj.Host)
	if err != nil {
		return fmt.Errorf("failed to detect github config: %#v", err)
	}
	gh := github.NewClientWithHost(host)

	if !dryRun {
		params := &github.Release{
			TagName:    tag,
			Name:       tag,
			Body:       body,
			Prerelease: true,
		}
		release, err := gh.CreateRelease(proj, params)
		if err != nil {
			return fmt.Errorf("failed to create release: %#v", err)
		}

		err = uploadAssets(gh, release, assets)
		if err != nil {
			return err
		}
		if !staging {
			release, err = gh.EditRelease(release, map[string]interface{}{
				"prerelease": false,
			})
		}
	}
	return nil
}

func getOctoCli() *octokit.Client {
	var auth octokit.AuthMethod
	token := os.Getenv("GITHUB_TOKEN")
	if token != "" {
		auth = octokit.TokenAuth{AccessToken: token}
	}
	return octokit.NewClient(auth)
}

func getReleasePullRequest(octoCli *octokit.Client, owner, repo, releaseVer string) (*octokit.PullRequest, error) {
	releaseBranch := "bump-version-" + releaseVer
	u, err := octokit.PullRequestsURL.Expand(octokit.M{"owner": owner, "repo": repo})
	if err != nil {
		return nil, fmt.Errorf("something went wrong while expanding pullrequest url")
	}
	q := u.Query()
	q.Set("state", "closed")
	q.Set("head", fmt.Sprintf("%s:%s", owner, releaseBranch))
	u.RawQuery = q.Encode()
	prs, r := octoCli.PullRequests(u).All()
	if r.HasError() || len(prs) != 1 {
		return nil, fmt.Errorf("failed to detect release pull request: %#v", r.Err)
	}
	return &prs[0], nil
}

func handleOldRelease(octoCli *octokit.Client, owner, repo, tag string, staging, dryRun bool) error {
	releaseByTagURL := octokit.Hyperlink("repos/{owner}/{repo}/releases/tags/{tag}")
	u, err := releaseByTagURL.Expand(octokit.M{"owner": owner, "repo": repo, "tag": tag})
	if err != nil {
		return fmt.Errorf("failed to build GitHub URL: %#v", err)
	}
	release, r := octoCli.Releases(u).Latest()
	if r.Err != nil {
		rerr, ok := r.Err.(*octokit.ResponseError)
		if !ok {
			return fmt.Errorf("failed to fetch release: %#v", r.Err)
		}
		if rerr.Response == nil || rerr.Response.StatusCode != http.StatusNotFound {
			return fmt.Errorf("failed to fetch release: %#v", r.Err)
		}
	}
	if release != nil {
		if !staging {
			return errAlreadyReleased
		}
		if !dryRun {
			req, err := octoCli.NewRequest(release.URL)
			if err != nil {
				return fmt.Errorf("something went wrong: %#v", err)
			}
			sawyerResp := req.Request.Delete()
			if sawyerResp.IsError() {
				return fmt.Errorf("release deletion unsuccesful, %#v", sawyerResp.ResponseError)
			}
			defer sawyerResp.Body.Close()

			if sawyerResp.StatusCode != http.StatusNoContent {
				return fmt.Errorf("could not delete the release corresponding to tag %s", tag)
			}
		}
	}
	return nil
}

func collectAssets() (assets []string, err error) {
	home, err := homedir.Dir()
	if err != nil {
		return nil, err
	}
	for _, glob := range [...]string{
		home + "/rpmbuild/RPMS/*/*.rpm",
		"rpmbuild/RPMS/*/*.rpm",
		"packaging/*.deb",
		"snapshot/*.zip",
		"snapshot/*.tar.gz",
		"build/*.tar.gz",
	} {
		files, err := filepath.Glob(glob)
		if err != nil {
			return nil, err
		}
		assets = append(assets, files...)
	}
	return assets, nil
}

func uploadAssets(gh *github.Client, release *github.Release, assets []string) error {
	for _, asset := range assets {
		_, err := gh.UploadReleaseAsset(release, asset, "")
		if err != nil {
			return fmt.Errorf("failed to upload asset: %s, error: %#v", asset, err)
		}
	}
	return nil
}
<commit_msg>Retry at most twice, when failed to upload asset to GitHub Releases<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/Songmu/retry"
	"github.com/github/hub/github"
	"github.com/mitchellh/go-homedir"
	"github.com/octokit/go-octokit/octokit"
)

const (
	exitOK = iota
	exitError
)

const version = "0.0.0"

func main() {
	os.Exit(run(os.Args[1:]))
}

func run(argv []string) int {
	remotes, err := github.Remotes()
	if err != nil || len(remotes) < 1 {
		log.Printf("can't detect remote repository: %#v\n", err)
		return exitError
	}
	proj, err := remotes[0].Project()
	if err != nil {
		log.Printf("failed to retrieve project: %#v\n", err)
		return exitError
	}
	fs := flag.NewFlagSet("mackerel-github-release", flag.ContinueOnError)
	var (
		dryRun  = fs.Bool("dry-run", false, "dry-run mode")
		staging = fs.Bool("staging", false, "staging release")
	)
	err = fs.Parse(argv)
	if err != nil {
		if err == flag.ErrHelp {
			return exitOK

		}
		return exitError
	}

	out, err := exec.Command("gobump", "show").Output()
	if err != nil {
		log.Printf("failed to `gobump show`: %#v\n", err)
		return exitError
	}

	var v struct {
		Version string `json:"version"`
	}
	err = json.Unmarshal(out, &v)
	if err != nil {
		log.Printf("failed to unmarshal `gobump show`'s output: %#v\n", err)
		return exitError
	}
	err = uploadToGithubRelease(proj, v.Version, *staging, *dryRun)
	if err != nil {
		log.Printf("error occured while uploading artifacts to github: %#v\n", err)
		return exitError
	}
	return exitOK
}

var errAlreadyReleased = fmt.Errorf("the release of this version has already existed at GitHub Relase, so skip the process")

func uploadToGithubRelease(proj *github.Project, releaseVer string, staging, dryRun bool) error {
	tag := "staging"
	if !staging {
		tag = "v" + releaseVer
	}
	repo, owner := proj.Name, proj.Owner
	octoCli := getOctoCli()

	pr, err := getReleasePullRequest(octoCli, owner, repo, releaseVer)
	if err != nil {
		return err
	}

	err = handleOldRelease(octoCli, owner, repo, tag, staging, dryRun)
	if err != nil {
		if err == errAlreadyReleased {
			log.Println(err.Error())
			return nil
		}
		return err
	}

	body := pr.Body
	assets, err := collectAssets()
	if err != nil {
		return fmt.Errorf("error occured while collecting releasing assets: %#v", err)
	}

	host, err := github.CurrentConfig().PromptForHost(proj.Host)
	if err != nil {
		return fmt.Errorf("failed to detect github config: %#v", err)
	}
	gh := github.NewClientWithHost(host)

	if !dryRun {
		params := &github.Release{
			TagName:    tag,
			Name:       tag,
			Body:       body,
			Prerelease: true,
		}
		release, err := gh.CreateRelease(proj, params)
		if err != nil {
			return fmt.Errorf("failed to create release: %#v", err)
		}

		err = uploadAssets(gh, release, assets)
		if err != nil {
			return err
		}
		if !staging {
			release, err = gh.EditRelease(release, map[string]interface{}{
				"prerelease": false,
			})
		}
	}
	return nil
}

func getOctoCli() *octokit.Client {
	var auth octokit.AuthMethod
	token := os.Getenv("GITHUB_TOKEN")
	if token != "" {
		auth = octokit.TokenAuth{AccessToken: token}
	}
	return octokit.NewClient(auth)
}

func getReleasePullRequest(octoCli *octokit.Client, owner, repo, releaseVer string) (*octokit.PullRequest, error) {
	releaseBranch := "bump-version-" + releaseVer
	u, err := octokit.PullRequestsURL.Expand(octokit.M{"owner": owner, "repo": repo})
	if err != nil {
		return nil, fmt.Errorf("something went wrong while expanding pullrequest url")
	}
	q := u.Query()
	q.Set("state", "closed")
	q.Set("head", fmt.Sprintf("%s:%s", owner, releaseBranch))
	u.RawQuery = q.Encode()
	prs, r := octoCli.PullRequests(u).All()
	if r.HasError() || len(prs) != 1 {
		return nil, fmt.Errorf("failed to detect release pull request: %#v", r.Err)
	}
	return &prs[0], nil
}

func handleOldRelease(octoCli *octokit.Client, owner, repo, tag string, staging, dryRun bool) error {
	releaseByTagURL := octokit.Hyperlink("repos/{owner}/{repo}/releases/tags/{tag}")
	u, err := releaseByTagURL.Expand(octokit.M{"owner": owner, "repo": repo, "tag": tag})
	if err != nil {
		return fmt.Errorf("failed to build GitHub URL: %#v", err)
	}
	release, r := octoCli.Releases(u).Latest()
	if r.Err != nil {
		rerr, ok := r.Err.(*octokit.ResponseError)
		if !ok {
			return fmt.Errorf("failed to fetch release: %#v", r.Err)
		}
		if rerr.Response == nil || rerr.Response.StatusCode != http.StatusNotFound {
			return fmt.Errorf("failed to fetch release: %#v", r.Err)
		}
	}
	if release != nil {
		if !staging {
			return errAlreadyReleased
		}
		if !dryRun {
			req, err := octoCli.NewRequest(release.URL)
			if err != nil {
				return fmt.Errorf("something went wrong: %#v", err)
			}
			sawyerResp := req.Request.Delete()
			if sawyerResp.IsError() {
				return fmt.Errorf("release deletion unsuccesful, %#v", sawyerResp.ResponseError)
			}
			defer sawyerResp.Body.Close()

			if sawyerResp.StatusCode != http.StatusNoContent {
				return fmt.Errorf("could not delete the release corresponding to tag %s", tag)
			}
		}
	}
	return nil
}

func collectAssets() (assets []string, err error) {
	home, err := homedir.Dir()
	if err != nil {
		return nil, err
	}
	for _, glob := range [...]string{
		home + "/rpmbuild/RPMS/*/*.rpm",
		"rpmbuild/RPMS/*/*.rpm",
		"packaging/*.deb",
		"snapshot/*.zip",
		"snapshot/*.tar.gz",
		"build/*.tar.gz",
	} {
		files, err := filepath.Glob(glob)
		if err != nil {
			return nil, err
		}
		assets = append(assets, files...)
	}
	return assets, nil
}

func uploadAssets(gh *github.Client, release *github.Release, assets []string) error {
	for _, asset := range assets {
		err := retry.Retry(3, 3*time.Second, func() error {
			_, err := gh.UploadReleaseAsset(release, asset, "")
			if err != nil {
				log.Printf("failed to upload asset: %s, error: %#v", asset, err)
			}
			return err
		})
		if err != nil {
			return fmt.Errorf("failed to upload asset and gave up: %s, error: %#v", asset, err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Package rollinghash/adler32 implements a rolling version of hash/adler32

package adler32

import (
	vanilla "hash/adler32"

	"github.com/chmduquesne/rollinghash"
)

const (
	mod = 65521
)

const Size = 4

type digest struct {
	a, b uint32

	// window is treated like a circular buffer, where the oldest element
	// is indicated by d.oldest
	window []byte
	oldest int
	n      uint32
}

// Reset resets the Hash to its initial state.
func (d *digest) Reset() {
	d.a = 1
	d.b = 0
	d.window = nil
	d.oldest = 0
}

// New returns a new rollinghash.Hash32 computing the rolling Adler-32
// checksum. The window is copied from the last Write(). This window is
// only used to determine which is the oldest element (leaving the
// window). The calls to Roll() do not recompute the whole checksum.
func New() rollinghash.Hash32 {
	return &digest{a: 1, b: 0, window: nil, oldest: 0}
}

// Size returns the number of bytes Sum will return.
func (d *digest) Size() int { return Size }

// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all
// writes are a multiple of the block size.
func (d *digest) BlockSize() int { return 1 }

// Write (via the embedded io.Writer interface) adds more data to the
// running hash. It never returns an error.
func (d *digest) Write(p []byte) (int, error) {
	// Copy the window
	d.window = make([]byte, len(p))
	copy(d.window, p)

	// Piggy-back on the core implementation
	h := vanilla.New()
	h.Write(p)
	s := h.Sum32()
	d.a, d.b = s&0xffff, s>>16
	d.n = uint32(len(p)) % mod
	return len(d.window), nil
}

func (d *digest) Sum32() uint32 {
	return d.b<<16 | d.a
}

func (d *digest) Sum(b []byte) []byte {
	v := d.Sum32()
	return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}

// Roll updates the checksum of the window from the leaving byte and the
// entering byte. See
// http://stackoverflow.com/questions/40985080/why-does-my-rolling-adler32-checksum-not-work-in-go-modulo-arithmetic
func (d *digest) Roll(b byte) {
	if len(d.window) == 0 {
		d.window = make([]byte, 1)
		d.window[0] = b
	}
	// extract the entering/leaving bytes and update the circular buffer.
	enter := uint32(b)
	leave := uint32(d.window[d.oldest])
	d.window[d.oldest] = b
	d.oldest += 1
	if d.oldest >= len(d.window) {
		d.oldest = 0
	}

	// compute
	d.a = (d.a + mod + enter - leave) % mod
	d.b = (d.b + (d.n*leave/mod+1)*mod + d.a - (d.n * leave) - 1) % mod
}
<commit_msg>Speed up adler32.Write<commit_after>// Package rollinghash/adler32 implements a rolling version of hash/adler32

package adler32

import (
	"hash"
	vanilla "hash/adler32"

	"github.com/chmduquesne/rollinghash"
)

const (
	mod = 65521
)

const Size = 4

type digest struct {
	a, b uint32

	// window is treated like a circular buffer, where the oldest element
	// is indicated by d.oldest
	window []byte
	oldest int
	n      uint32

	vanilla hash.Hash32
}

// Reset resets the Hash to its initial state.
func (d *digest) Reset() {
	d.a = 1
	d.b = 0
	d.window = nil
	d.oldest = 0
}

// New returns a new rollinghash.Hash32 computing the rolling Adler-32
// checksum. The window is copied from the last Write(). This window is
// only used to determine which is the oldest element (leaving the
// window). The calls to Roll() do not recompute the whole checksum.
func New() rollinghash.Hash32 {
	return &digest{a: 1, b: 0, window: nil, oldest: 0, vanilla: vanilla.New()}
}

// Size returns the number of bytes Sum will return.
func (d *digest) Size() int { return Size }

// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all
// writes are a multiple of the block size.
func (d *digest) BlockSize() int { return 1 }

// Write (via the embedded io.Writer interface) adds more data to the
// running hash. It never returns an error.
func (d *digest) Write(p []byte) (int, error) {
	// Copy the window
	if len(d.window) != len(p) {
		d.window = make([]byte, len(p))
	}
	copy(d.window, p)

	// Piggy-back on the core implementation
	d.vanilla.Reset()
	d.vanilla.Write(p)
	s := d.vanilla.Sum32()
	d.a, d.b = s&0xffff, s>>16
	d.n = uint32(len(p)) % mod
	return len(d.window), nil
}

func (d *digest) Sum32() uint32 {
	return d.b<<16 | d.a
}

func (d *digest) Sum(b []byte) []byte {
	v := d.Sum32()
	return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}

// Roll updates the checksum of the window from the leaving byte and the
// entering byte. See
// http://stackoverflow.com/questions/40985080/why-does-my-rolling-adler32-checksum-not-work-in-go-modulo-arithmetic
func (d *digest) Roll(b byte) {
	if len(d.window) == 0 {
		d.window = make([]byte, 1)
		d.window[0] = b
	}
	// extract the entering/leaving bytes and update the circular buffer.
	enter := uint32(b)
	leave := uint32(d.window[d.oldest])
	d.window[d.oldest] = b
	d.oldest += 1
	if d.oldest >= len(d.window) {
		d.oldest = 0
	}

	// compute
	d.a = (d.a + mod + enter - leave) % mod
	d.b = (d.b + (d.n*leave/mod+1)*mod + d.a - (d.n * leave) - 1) % mod
}
<|endoftext|>


<commit_before>package dtest

import (
	"godownloader/http"
	"godownloader/iotools"
	"godownloader/monitor"
	"testing"
	"time"
)

func TestMultiPartDownloadPool(t *testing.T) {
	partcount := 10
	pc := int64(partcount)
	url := "http://mirror.yandex.ru/ubuntu-releases/15.04/ubuntu-15.04-snappy-amd64%2bgeneric.img.xz"
	c, _ := httpclient.GetSize(url)
	f, _ := iotools.CreateSafeFile("ubuntu-15.04-snappy-amd64+generic.img.xz ")
	defer f.Close()
	f.Truncate(c)
	ps := c / pc
	wp := monitor.WorkerPool{}
	for i := int64(0); i < pc-1; i++ {
		//log.Println(ps*i, ps*i+ps)
		d := httpclient.CreatePartialDownloader(url, f, ps*i, ps*i, ps*i+ps)
		mv := monitor.MonitoredWorker{Itw: d}
		wp.AppendWork(&mv)
	}
	lastseg := c - (ps * (pc - 1))
	dow := httpclient.CreatePartialDownloader(url, f, lastseg,lastseg, c)
	mv := monitor.MonitoredWorker{Itw: dow}
	wp.AppendWork(&mv)
	wp.StartAll()
	time.Sleep(time.Second * 10000)

}
<commit_msg>fix sleep time<commit_after>package dtest

import (
	"godownloader/http"
	"godownloader/iotools"
	"godownloader/monitor"
	"testing"
	"time"
)

func TestMultiPartDownloadPool(t *testing.T) {
	partcount := 10
	pc := int64(partcount)
	url := "http://pinegrow.s3.amazonaws.com/PinegrowLinux64.2.2.zip"
	c, _ := httpclient.GetSize(url)
	f, _ := iotools.CreateSafeFile("ubuntu-15.04-snappy-amd64+generic.img.xz ")
	defer f.Close()
	f.Truncate(c)
	ps := c / pc
	wp := monitor.WorkerPool{}
	for i := int64(0); i < pc-1; i++ {
		//log.Println(ps*i, ps*i+ps)
		d := httpclient.CreatePartialDownloader(url, f, ps*i, ps*i, ps*i+ps)
		mv := monitor.MonitoredWorker{Itw: d}
		wp.AppendWork(&mv)
	}
	lastseg := c - (ps * (pc - 1))
	dow := httpclient.CreatePartialDownloader(url, f, lastseg,lastseg, c)
	mv := monitor.MonitoredWorker{Itw: dow}
	wp.AppendWork(&mv)
	wp.StartAll()
	time.Sleep(time.Second * 30)

}
<|endoftext|>


<commit_before>// or the fan-out pattern
package main

import (
	"fmt"
	"time"
	"sync"
)

func worker(name int, jobs <-chan int, wg *sync.WaitGroup) {
	defer wg.Done()
	for j := range jobs {
		fmt.Printf("Worker %d processing job %d\n", name, j)
		time.Sleep(100 * time.Millisecond)
	}
	fmt.Printf("Worker %d finished\n", name)
}

func pool(numJobs, numWorkers int, wg *sync.WaitGroup) {
	var out = make(chan int)
	go func() {
		for i := 0; i < numJobs; i += 1 {
			out<- i
		}
		close(out)
	}()

	for i := 1; i <= numWorkers; i += 1 {
		go worker(i, out, wg)
	}
}

func main() {
	numWorkers := 100
	numJobs := 1000
	wg := &sync.WaitGroup{}
	wg.Add(numWorkers)
	go pool(numJobs, numWorkers, wg)
	wg.Wait()
}
<commit_msg>more work on the concurrency patterns<commit_after>// or the fan-out pattern
package main

import (
	"fmt"
	"time"
	"sync"
)

func worker(name int, jobs <-chan int, wg *sync.WaitGroup) {
	defer wg.Done()
	for j := range jobs {
		fmt.Printf("Worker %d processing job %d\n", name, j)
		time.Sleep(100 * time.Millisecond)
	}
	fmt.Printf("Worker %d finished\n", name)
}

func masterWorker(name, numSubworkers int, jobs <-chan int, wg *sync.WaitGroup) {
	fmt.Printf("Master worker %d started\n", name)
	for i := 1; i <= numSubworkers; i += 1 {
		workerName := name * 10 + i
		go worker(workerName, jobs, wg)
	}
}

func pool(numJobs, numWorkers int, wg *sync.WaitGroup) {
	var out = make(chan int)
	go func() {
		for i := 0; i < numJobs; i += 1 {
			out<- i
		}
		close(out)
	}()

	numMasterWorkers := int(numWorkers / 10)
	for i := 1; i <= numMasterWorkers; i += 1 {
		go masterWorker(i, 10, out, wg)
	}
}

func main() {
	numWorkers := 100
	numJobs := 1000
	wg := &sync.WaitGroup{}
	wg.Add(numWorkers)
	go pool(numJobs, numWorkers, wg)
	wg.Wait()
}
<|endoftext|>


<commit_before>package auth

/*
 * Implements auth middleware for cention applications.
 * Expects to be running in Gin framework
 */

import (
	wf "c3/osm/webframework"
	"c3/osm/workflow"
	"c3/syncmap"
	"c3/web/controllers"

	"github.com/gin-gonic/gin"
)

const (
	HTTP_UNAUTHORIZE_ACCESS = 401
	HTTP_FORBIDDEN_ACCESS   = 403
)

var ssid2idCache = syncmap.New()

var getFromMemcache = func(ssid string) int {
	if id, exist := ssid2idCache.Get(ssid); exist {
		return id.(int)
	}
	return -1
}

var saveInMemcache = func(ssid string, id int) {
	ssid2idCache.Put(ssid, id)
}

var userIdFromHash = func(ssid string) int {
	wfUser, err := wf.QueryUser_byHashLogin(ssid)
	if err == nil && wfUser != nil {
		if wfUser.Active {
			saveInMemcache(ssid, wfUser.Id)
			return wfUser.Id
		}
	}
	return -1
}

var fetchUser = func(ssid string) *workflow.User {
	var id int = -1

	id = getFromMemcache(ssid)

	if id == -1 {
		id = userIdFromHash(ssid)
	}

	if id != -1 {
		return controllers.FetchUserObject(id)
	}
	return nil
}

func User(ctx *gin.Context) *workflow.User {
	return ctx.Keys["loggedInUser"].(*workflow.User)
}

func Middleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var ssid string = ""

		cookie, err := ctx.Request.Cookie("cention-suiteSSID")
		if err == nil {
			ssid = cookie.Value
		}

		currUser := fetchUser(ssid)

		if currUser == nil {
			ctx.AbortWithStatus(HTTP_UNAUTHORIZE_ACCESS)
		}

		ctx.Keys = make(map[string]interface{})
		ctx.Keys["loggedInUser"] = currUser
		ctx.Next()
	}
}
<commit_msg>auth.go: Rename {getFrom,saveIn}Memcache to {getFrom,SaveTo}Cache<commit_after>package auth

/*
 * Implements auth middleware for cention applications.
 * Expects to be running in Gin framework
 */

import (
	wf "c3/osm/webframework"
	"c3/osm/workflow"
	"c3/syncmap"
	"c3/web/controllers"

	"github.com/gin-gonic/gin"
)

const (
	HTTP_UNAUTHORIZE_ACCESS = 401
	HTTP_FORBIDDEN_ACCESS   = 403
)

var ssid2idCache = syncmap.New()

var getFromCache = func(ssid string) int {
	if id, exist := ssid2idCache.Get(ssid); exist {
		return id.(int)
	}
	return -1
}

var saveToCache = func(ssid string, id int) {
	ssid2idCache.Put(ssid, id)
}

var userIdFromHash = func(ssid string) int {
	wfUser, err := wf.QueryUser_byHashLogin(ssid)
	if err == nil && wfUser != nil {
		if wfUser.Active {
			saveToCache(ssid, wfUser.Id)
			return wfUser.Id
		}
	}
	return -1
}

var fetchUser = func(ssid string) *workflow.User {
	var id int = -1

	id = getFromCache(ssid)

	if id == -1 {
		id = userIdFromHash(ssid)
	}

	if id != -1 {
		return controllers.FetchUserObject(id)
	}
	return nil
}

func User(ctx *gin.Context) *workflow.User {
	return ctx.Keys["loggedInUser"].(*workflow.User)
}

func Middleware() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var ssid string = ""

		cookie, err := ctx.Request.Cookie("cention-suiteSSID")
		if err == nil {
			ssid = cookie.Value
		}

		currUser := fetchUser(ssid)

		if currUser == nil {
			ctx.AbortWithStatus(HTTP_UNAUTHORIZE_ACCESS)
		}

		ctx.Keys = make(map[string]interface{})
		ctx.Keys["loggedInUser"] = currUser
		ctx.Next()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/spf13/cobra"
	"os"
	"path/filepath"
)

// Plugins
var goPlugin GoPlugin
var lessPlugin LessPlugin
var typescriptPlugin TypeScriptPlugin

var workdir string // Our working directory

// Commands

var rootCmd = &cobra.Command{
	Use:   "noodles",
	Short: "noodles is an opinionated manager for web apps.",
	Long: `noodles is an opinionated manager for web applications, enabling various functionality such as:
	- basic dependency management for built-in plugin support
	- compilation of project(s) in a configurable, ordered manner
	- configurable packing of project assets for distribution`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		if conf, readErr := ReadConfig(filepath.Join(workdir, "noodles.toml")); readErr == nil { // Read the config
			noodles = conf
		} else {
			fmt.Printf("noodles.toml appears to have the following issue(s):\n%s\n", readErr.Error())
			os.Exit(1)
		}
	},
	DisableAutoGenTag: true,
}

// Main

func init() {
	var getWdErr error
	workdir, getWdErr = os.Getwd() // Get the current working directory

	if getWdErr != nil { // If we failed to get the current working directory
		fmt.Printf("Failed to get the current working directory: %s", getWdErr.Error())
		os.Exit(1)
	}

	rootCmd.AddCommand(buildCmd)
	rootCmd.AddCommand(checkCmd)
	rootCmd.AddCommand(genDocs)
	rootCmd.AddCommand(lintCmd)
	rootCmd.AddCommand(newCmd)
	rootCmd.AddCommand(packCmd)
	rootCmd.AddCommand(setupCmd)
	rootCmd.AddCommand(scriptCmd)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>Fix noodles.toml checking occurring during new command<commit_after>package main

import (
	"fmt"
	"github.com/spf13/cobra"
	"os"
	"path/filepath"
)

// Plugins
var goPlugin GoPlugin
var lessPlugin LessPlugin
var typescriptPlugin TypeScriptPlugin

var workdir string // Our working directory

// Commands

var rootCmd = &cobra.Command{
	Use:   "noodles",
	Short: "noodles is an opinionated manager for web apps.",
	Long: `noodles is an opinionated manager for web applications, enabling various functionality such as:
	- basic dependency management for built-in plugin support
	- compilation of project(s) in a configurable, ordered manner
	- configurable packing of project assets for distribution`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		if cmd.Use != "new" { // If we're not potentially creating a new Noodles workspace
			if conf, readErr := ReadConfig(filepath.Join(workdir, "noodles.toml")); readErr == nil { // Read the config
				noodles = conf
			} else {
				fmt.Printf("noodles.toml appears to have the following issue(s):\n%s\n", readErr.Error())
				os.Exit(1)
			}
		}
	},
	DisableAutoGenTag: true,
}

// Main

func init() {
	var getWdErr error
	workdir, getWdErr = os.Getwd() // Get the current working directory

	if getWdErr != nil { // If we failed to get the current working directory
		fmt.Printf("Failed to get the current working directory: %s", getWdErr.Error())
		os.Exit(1)
	}

	rootCmd.AddCommand(buildCmd)
	rootCmd.AddCommand(checkCmd)
	rootCmd.AddCommand(genDocs)
	rootCmd.AddCommand(lintCmd)
	rootCmd.AddCommand(newCmd)
	rootCmd.AddCommand(packCmd)
	rootCmd.AddCommand(setupCmd)
	rootCmd.AddCommand(scriptCmd)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package gofetcher

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"time"

	"github.com/cocaine/cocaine-framework-go/cocaine"
	"github.com/ugorji/go/codec"
)

const (
	DefaultTimeout         = 5000
	DefaultFollowRedirects = true
	KeepAliveTimeout       = 30
)

// took from httputil/reverseproxy.go
// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
	"Connection",
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te", // canonicalized version of "TE"
	"Trailers",
	"Transfer-Encoding",
	"Upgrade",
}

type WarnError struct {
	err error
}

func (s *WarnError) Error() string { return s.err.Error() }

func NewWarn(err error) *WarnError {
	return &WarnError{err: err}
}

type Gofetcher struct {
	Logger    *cocaine.Logger
	Transport http.RoundTripper

	UserAgent string
}

type Cookies map[string]string

type Request struct {
	method          string
	url             string
	body            io.Reader
	timeout         int64
	cookies         Cookies
	headers         http.Header
	followRedirects bool
}

type responseAndError struct {
	res *http.Response
	err error
}

type Response struct {
	httpResponse *http.Response
	body         []byte
	header       http.Header
	runtime      time.Duration
}

func NewGofetcher() *Gofetcher {
	logger, err := cocaine.NewLogger()
	if err != nil {
		fmt.Printf("Could not initialize logger due to error: %v", err)
		return nil
	}
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: KeepAliveTimeout * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
	}
	gofetcher := Gofetcher{logger, transport, ""}
	return &gofetcher
}

func (gofetcher *Gofetcher) SetUserAgent(userAgent string) {
	gofetcher.UserAgent = userAgent
}

func noRedirect(_ *http.Request, via []*http.Request) error {
	if len(via) > 0 {
		return errors.New("stopped after first redirect")
	}
	return nil
}

func (gofetcher *Gofetcher) performRequest(request *Request, attempt int) (*Response, error) {
	var (
		err            error
		httpRequest    *http.Request
		httpResponse   *http.Response
		requestTimeout time.Duration = time.Duration(request.timeout) * time.Millisecond
	)
	gofetcher.Logger.Infof("Requested url: %s, method: %s, timeout: %d, headers: %v, attempt: %d",
		request.url, request.method, request.timeout, request.headers, attempt)
	httpClient := &http.Client{
		Transport: gofetcher.Transport,
		Timeout:   requestTimeout,
	}
	if request.followRedirects == false {
		httpClient.CheckRedirect = noRedirect
	}
	httpRequest, err = http.NewRequest(request.method, request.url, request.body)
	if err != nil {
		return nil, err
	}
	for name, value := range request.cookies {
		httpRequest.AddCookie(&http.Cookie{Name: name, Value: value})
	}
	httpRequest.Header = request.headers

	// Remove hop-by-hop headers to the backend.  Especially
	// important is "Connection" because we want a persistent
	// connection, regardless of what the client sent to us.  This
	// is modifying the same underlying map from req (shallow
	// copied above) so we only copy it if necessary.
	for _, h := range hopHeaders {
		httpRequest.Header.Del(h)
	}
	httpRequest.Header.Add("Connection", "keep-alive")
	httpRequest.Header.Add("Keep-Alive", fmt.Sprintf("%d", KeepAliveTimeout))

	if gofetcher.UserAgent != "" {
		httpRequest.Header.Set("User-Agent", gofetcher.UserAgent)
	}

	resultChan := make(chan responseAndError)
	started := time.Now()
	go func() {
		res, err := httpClient.Do(httpRequest)
		resultChan <- responseAndError{res, err}
	}()
	// http connection stay active after timeout exceeded in go <1.3, cause we can't close it using current client api.
	// Read more about timeouts: https://code.google.com/p/go/issues/detail?id=3362
	//
	select {
	case result := <-resultChan:
		httpResponse, err = result.res, result.err
	case <-time.After(requestTimeout):
		err = errors.New(fmt.Sprintf("Request timeout[%s] exceeded", requestTimeout.String()))
		go func() {
			// close httpResponse when it ready
			result := <-resultChan
			if result.res != nil {
				result.res.Body.Close()
			}
		}()
	}
	body := []byte{}
	if err != nil {
		// special case for redirect failure (returns both response and error)
		// read more https://code.google.com/p/go/issues/detail?id=3795
		if httpResponse == nil {
			if urlError, ok := err.(*url.Error); ok {
				// golang bug: golang.org/issue/3514
				if urlError.Err == io.EOF {
					gofetcher.Logger.Infof("Got EOF error while loading %s, attempt(%d)", request.url, attempt)
					if attempt == 1 {
						return gofetcher.performRequest(request, attempt+1)
					}
				}
			}
			return nil, NewWarn(err)
		}
	} else {
		defer httpResponse.Body.Close()
		body, err = ioutil.ReadAll(httpResponse.Body)
		if err != nil {
			return nil, NewWarn(err)
		}
	}
	runtime := time.Since(started)
	for _, h := range hopHeaders {
		httpResponse.Header.Del(h)
	}
	response := &Response{httpResponse: httpResponse, body: body, header: httpResponse.Header, runtime: runtime}
	return response, nil

}

// Normal methods

func parseHeaders(rawHeaders map[string]interface{}) http.Header {
	headers := make(http.Header)
	for name, values := range rawHeaders {
		for _, value := range values.([]interface{}) {
			headers.Add(name, string(value.([]uint8))) // to transform in canonical form
		}
	}
	return headers
}

func parseCookies(rawCookie map[string]interface{}) Cookies {
	cookies := Cookies{}
	for key, value := range rawCookie {
		cookies[key] = string(value.([]uint8))
	}
	return cookies
}

func parseTimeout(rawTimeout interface{}) (timeout int64) {
	// is it possible to got timeout in int64 instead of uint64?
	switch rawTimeout.(type) {
	case uint64:
		timeout = int64(rawTimeout.(uint64))
	case int64:
		timeout = rawTimeout.(int64)
	}
	return timeout
}

func (gofetcher *Gofetcher) parseRequest(method string, requestBody []byte) (request *Request) {
	var (
		mh              codec.MsgpackHandle
		h                     = &mh
		timeout         int64 = DefaultTimeout
		cookies         Cookies
		headers              = make(http.Header)
		followRedirects bool = DefaultFollowRedirects
		body            *bytes.Buffer
	)
	mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
	var res []interface{}
	codec.NewDecoderBytes(requestBody, h).Decode(&res)
	url := string(res[0].([]uint8))
	switch {
	case method == "GET" || method == "HEAD" || method == "DELETE":
		if len(res) > 1 {
			timeout = parseTimeout(res[1])
		}
		if len(res) > 2 {
			cookies = parseCookies(res[2].(map[string]interface{}))
		}
		if len(res) > 3 {
			headers = parseHeaders(res[3].(map[string]interface{}))
		}
		if len(res) > 4 {
			followRedirects = res[4].(bool)
		}
	case method == "POST" || method == "PUT" || method == "PATCH":
		if len(res) > 1 {
			body = bytes.NewBuffer(res[1].([]byte))
		}
		if len(res) > 2 {
			timeout = parseTimeout(res[2])
		}
		if len(res) > 3 {
			cookies = parseCookies(res[3].(map[string]interface{}))
		}
		if len(res) > 4 {
			headers = parseHeaders(res[4].(map[string]interface{}))
		}
		if len(res) > 5 {
			followRedirects = res[5].(bool)
		}
	}

	request = &Request{method: method, url: url, timeout: timeout,
		followRedirects: followRedirects,
		cookies:         cookies, headers: headers}
	if body != nil {
		request.body = body
	}
	return request
}

func (gofetcher *Gofetcher) writeResponse(response *cocaine.Response, request *Request, resp *Response, err error) {
	if err != nil {
		if _, casted := err.(*WarnError); casted {
			gofetcher.Logger.Warnf("Error occured: %v, while downloading %s",
				err.Error(), request.url)
		} else {
			gofetcher.Logger.Errf("Error occured: %v, while downloading %s",
				err.Error(), request.url)
		}
		response.Write([]interface{}{false, err.Error(), 0, http.Header{}})
	} else {
		response.Write([]interface{}{true, resp.body, resp.httpResponse.StatusCode, resp.header})
		gofetcher.Logger.Info(fmt.Sprintf("Response code: %d, url: %s, runtime: %v",
			resp.httpResponse.StatusCode, request.url, resp.runtime))
	}
}

func (gofetcher *Gofetcher) handler(method string, request *cocaine.Request, response *cocaine.Response) {
	defer response.Close()
	requestBody := <-request.Read()
	httpRequest := gofetcher.parseRequest(method, requestBody)
	resp, err := gofetcher.performRequest(httpRequest, 1)
	gofetcher.writeResponse(response, httpRequest, resp, err)
}

func (gofetcher *Gofetcher) GetHandler(method string) func(request *cocaine.Request, response *cocaine.Response) {
	return func(request *cocaine.Request, response *cocaine.Response) {
		gofetcher.handler(method, request, response)
	}
}

// Http methods

func (gofetcher *Gofetcher) HttpProxy(res http.ResponseWriter, req *http.Request) {
	var (
		timeout int64 = DefaultTimeout
	)
	url := req.FormValue("url")
	timeoutArg := req.FormValue("timeout")
	if timeoutArg != "" {
		tout, _ := strconv.Atoi(timeoutArg)
		timeout = int64(tout)
	}
	httpRequest := Request{method: req.Method, url: url, timeout: timeout,
		followRedirects: DefaultFollowRedirects, headers: req.Header, body: req.Body}
	resp, err := gofetcher.performRequest(&httpRequest, 1)
	if err != nil {
		res.Header().Set("Content-Type", "text/html")
		res.WriteHeader(500)
		res.Write([]byte(err.Error()))
		if _, casted := err.(*WarnError); casted {
			gofetcher.Logger.Warnf("Gofetcher error: %v", err)
		} else {
			gofetcher.Logger.Errf("Gofetcher error: %v", err)
		}

	} else {
		for key, values := range resp.header {
			for _, value := range values {
				res.Header().Add(key, value)
			}
		}
		res.WriteHeader(200)
		if _, err := res.Write(resp.body); err != nil {
			gofetcher.Logger.Errf("Error: %v", err)
		}
	}
}

func (gofetcher *Gofetcher) HttpEcho(res http.ResponseWriter, req *http.Request) {
	gofetcher.Logger.Info("Http echo handler requested")
	text := req.FormValue("text")
	res.Header().Set("Content-Type", "text/html")
	res.WriteHeader(200)
	res.Write([]byte(text))
}
<commit_msg>do not overwrite user-specified User-Agent if set<commit_after>package gofetcher

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"time"

	"github.com/cocaine/cocaine-framework-go/cocaine"
	"github.com/ugorji/go/codec"
)

const (
	DefaultTimeout         = 5000
	DefaultFollowRedirects = true
	KeepAliveTimeout       = 30
)

// took from httputil/reverseproxy.go
// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
	"Connection",
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te", // canonicalized version of "TE"
	"Trailers",
	"Transfer-Encoding",
	"Upgrade",
}

type WarnError struct {
	err error
}

func (s *WarnError) Error() string { return s.err.Error() }

func NewWarn(err error) *WarnError {
	return &WarnError{err: err}
}

type Gofetcher struct {
	Logger    *cocaine.Logger
	Transport http.RoundTripper

	UserAgent string
}

type Cookies map[string]string

type Request struct {
	method          string
	url             string
	body            io.Reader
	timeout         int64
	cookies         Cookies
	headers         http.Header
	followRedirects bool
}

type responseAndError struct {
	res *http.Response
	err error
}

type Response struct {
	httpResponse *http.Response
	body         []byte
	header       http.Header
	runtime      time.Duration
}

func NewGofetcher() *Gofetcher {
	logger, err := cocaine.NewLogger()
	if err != nil {
		fmt.Printf("Could not initialize logger due to error: %v", err)
		return nil
	}
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: KeepAliveTimeout * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
	}
	gofetcher := Gofetcher{logger, transport, ""}
	return &gofetcher
}

func (gofetcher *Gofetcher) SetUserAgent(userAgent string) {
	gofetcher.UserAgent = userAgent
}

func noRedirect(_ *http.Request, via []*http.Request) error {
	if len(via) > 0 {
		return errors.New("stopped after first redirect")
	}
	return nil
}

func (gofetcher *Gofetcher) performRequest(request *Request, attempt int) (*Response, error) {
	var (
		err            error
		httpRequest    *http.Request
		httpResponse   *http.Response
		requestTimeout time.Duration = time.Duration(request.timeout) * time.Millisecond
	)
	gofetcher.Logger.Infof("Requested url: %s, method: %s, timeout: %d, headers: %v, attempt: %d",
		request.url, request.method, request.timeout, request.headers, attempt)
	httpClient := &http.Client{
		Transport: gofetcher.Transport,
		Timeout:   requestTimeout,
	}
	if request.followRedirects == false {
		httpClient.CheckRedirect = noRedirect
	}
	httpRequest, err = http.NewRequest(request.method, request.url, request.body)
	if err != nil {
		return nil, err
	}
	for name, value := range request.cookies {
		httpRequest.AddCookie(&http.Cookie{Name: name, Value: value})
	}
	httpRequest.Header = request.headers

	// Remove hop-by-hop headers to the backend.  Especially
	// important is "Connection" because we want a persistent
	// connection, regardless of what the client sent to us.  This
	// is modifying the same underlying map from req (shallow
	// copied above) so we only copy it if necessary.
	for _, h := range hopHeaders {
		httpRequest.Header.Del(h)
	}
	httpRequest.Header.Add("Connection", "keep-alive")
	httpRequest.Header.Add("Keep-Alive", fmt.Sprintf("%d", KeepAliveTimeout))

	if gofetcher.UserAgent != "" && len(httpRequest["User-Agent"]) == 0 {
		httpRequest.Header.Set("User-Agent", gofetcher.UserAgent)
	}

	resultChan := make(chan responseAndError)
	started := time.Now()
	go func() {
		res, err := httpClient.Do(httpRequest)
		resultChan <- responseAndError{res, err}
	}()
	// http connection stay active after timeout exceeded in go <1.3, cause we can't close it using current client api.
	// Read more about timeouts: https://code.google.com/p/go/issues/detail?id=3362
	//
	select {
	case result := <-resultChan:
		httpResponse, err = result.res, result.err
	case <-time.After(requestTimeout):
		err = errors.New(fmt.Sprintf("Request timeout[%s] exceeded", requestTimeout.String()))
		go func() {
			// close httpResponse when it ready
			result := <-resultChan
			if result.res != nil {
				result.res.Body.Close()
			}
		}()
	}
	body := []byte{}
	if err != nil {
		// special case for redirect failure (returns both response and error)
		// read more https://code.google.com/p/go/issues/detail?id=3795
		if httpResponse == nil {
			if urlError, ok := err.(*url.Error); ok {
				// golang bug: golang.org/issue/3514
				if urlError.Err == io.EOF {
					gofetcher.Logger.Infof("Got EOF error while loading %s, attempt(%d)", request.url, attempt)
					if attempt == 1 {
						return gofetcher.performRequest(request, attempt+1)
					}
				}
			}
			return nil, NewWarn(err)
		}
	} else {
		defer httpResponse.Body.Close()
		body, err = ioutil.ReadAll(httpResponse.Body)
		if err != nil {
			return nil, NewWarn(err)
		}
	}
	runtime := time.Since(started)
	for _, h := range hopHeaders {
		httpResponse.Header.Del(h)
	}
	response := &Response{httpResponse: httpResponse, body: body, header: httpResponse.Header, runtime: runtime}
	return response, nil

}

// Normal methods

func parseHeaders(rawHeaders map[string]interface{}) http.Header {
	headers := make(http.Header)
	for name, values := range rawHeaders {
		for _, value := range values.([]interface{}) {
			headers.Add(name, string(value.([]uint8))) // to transform in canonical form
		}
	}
	return headers
}

func parseCookies(rawCookie map[string]interface{}) Cookies {
	cookies := Cookies{}
	for key, value := range rawCookie {
		cookies[key] = string(value.([]uint8))
	}
	return cookies
}

func parseTimeout(rawTimeout interface{}) (timeout int64) {
	// is it possible to got timeout in int64 instead of uint64?
	switch rawTimeout.(type) {
	case uint64:
		timeout = int64(rawTimeout.(uint64))
	case int64:
		timeout = rawTimeout.(int64)
	}
	return timeout
}

func (gofetcher *Gofetcher) parseRequest(method string, requestBody []byte) (request *Request) {
	var (
		mh              codec.MsgpackHandle
		h                     = &mh
		timeout         int64 = DefaultTimeout
		cookies         Cookies
		headers              = make(http.Header)
		followRedirects bool = DefaultFollowRedirects
		body            *bytes.Buffer
	)
	mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
	var res []interface{}
	codec.NewDecoderBytes(requestBody, h).Decode(&res)
	url := string(res[0].([]uint8))
	switch {
	case method == "GET" || method == "HEAD" || method == "DELETE":
		if len(res) > 1 {
			timeout = parseTimeout(res[1])
		}
		if len(res) > 2 {
			cookies = parseCookies(res[2].(map[string]interface{}))
		}
		if len(res) > 3 {
			headers = parseHeaders(res[3].(map[string]interface{}))
		}
		if len(res) > 4 {
			followRedirects = res[4].(bool)
		}
	case method == "POST" || method == "PUT" || method == "PATCH":
		if len(res) > 1 {
			body = bytes.NewBuffer(res[1].([]byte))
		}
		if len(res) > 2 {
			timeout = parseTimeout(res[2])
		}
		if len(res) > 3 {
			cookies = parseCookies(res[3].(map[string]interface{}))
		}
		if len(res) > 4 {
			headers = parseHeaders(res[4].(map[string]interface{}))
		}
		if len(res) > 5 {
			followRedirects = res[5].(bool)
		}
	}

	request = &Request{method: method, url: url, timeout: timeout,
		followRedirects: followRedirects,
		cookies:         cookies, headers: headers}
	if body != nil {
		request.body = body
	}
	return request
}

func (gofetcher *Gofetcher) writeResponse(response *cocaine.Response, request *Request, resp *Response, err error) {
	if err != nil {
		if _, casted := err.(*WarnError); casted {
			gofetcher.Logger.Warnf("Error occured: %v, while downloading %s",
				err.Error(), request.url)
		} else {
			gofetcher.Logger.Errf("Error occured: %v, while downloading %s",
				err.Error(), request.url)
		}
		response.Write([]interface{}{false, err.Error(), 0, http.Header{}})
	} else {
		response.Write([]interface{}{true, resp.body, resp.httpResponse.StatusCode, resp.header})
		gofetcher.Logger.Info(fmt.Sprintf("Response code: %d, url: %s, runtime: %v",
			resp.httpResponse.StatusCode, request.url, resp.runtime))
	}
}

func (gofetcher *Gofetcher) handler(method string, request *cocaine.Request, response *cocaine.Response) {
	defer response.Close()
	requestBody := <-request.Read()
	httpRequest := gofetcher.parseRequest(method, requestBody)
	resp, err := gofetcher.performRequest(httpRequest, 1)
	gofetcher.writeResponse(response, httpRequest, resp, err)
}

func (gofetcher *Gofetcher) GetHandler(method string) func(request *cocaine.Request, response *cocaine.Response) {
	return func(request *cocaine.Request, response *cocaine.Response) {
		gofetcher.handler(method, request, response)
	}
}

// Http methods

func (gofetcher *Gofetcher) HttpProxy(res http.ResponseWriter, req *http.Request) {
	var (
		timeout int64 = DefaultTimeout
	)
	url := req.FormValue("url")
	timeoutArg := req.FormValue("timeout")
	if timeoutArg != "" {
		tout, _ := strconv.Atoi(timeoutArg)
		timeout = int64(tout)
	}
	httpRequest := Request{method: req.Method, url: url, timeout: timeout,
		followRedirects: DefaultFollowRedirects, headers: req.Header, body: req.Body}
	resp, err := gofetcher.performRequest(&httpRequest, 1)
	if err != nil {
		res.Header().Set("Content-Type", "text/html")
		res.WriteHeader(500)
		res.Write([]byte(err.Error()))
		if _, casted := err.(*WarnError); casted {
			gofetcher.Logger.Warnf("Gofetcher error: %v", err)
		} else {
			gofetcher.Logger.Errf("Gofetcher error: %v", err)
		}

	} else {
		for key, values := range resp.header {
			for _, value := range values {
				res.Header().Add(key, value)
			}
		}
		res.WriteHeader(200)
		if _, err := res.Write(resp.body); err != nil {
			gofetcher.Logger.Errf("Error: %v", err)
		}
	}
}

func (gofetcher *Gofetcher) HttpEcho(res http.ResponseWriter, req *http.Request) {
	gofetcher.Logger.Info("Http echo handler requested")
	text := req.FormValue("text")
	res.Header().Set("Content-Type", "text/html")
	res.WriteHeader(200)
	res.Write([]byte(text))
}
<|endoftext|>


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

package gommap

import (
	"errors"
	"os"
	"sync"
	"syscall"
)

// mmap on Windows is a two-step process.
// First, we call CreateFileMapping to get a handle.
// Then, we call MapviewToFile to get an actual pointer into memory.
// Because we want to emulate a POSIX-style mmap, we don't want to expose
// the handle -- only the pointer. We also want to return only a byte slice,
// not a struct, so it's convenient to manipulate.

// We keep this map so that we can get back the original handle from the memory address.
var handleLock sync.Mutex
var handleMap = map[uintptr]syscall.Handle{}

// Windows mmap always mapes the entire file regardless of the specified length.
func mmap(length int, prot, hfile uintptr) ([]byte, error) {
	flProtect := uint32(syscall.PAGE_READONLY)
	dwDesiredAccess := uint32(syscall.FILE_MAP_READ)
	flProtect = syscall.PAGE_READWRITE
	dwDesiredAccess = syscall.FILE_MAP_WRITE

	h, errno := syscall.CreateFileMapping(syscall.Handle(hfile), nil, flProtect, 0, 0, nil)
	if h == 0 {
		return nil, os.NewSyscallError("CreateFileMapping", errno)
	}

	addr, errno := syscall.MapViewOfFile(h, dwDesiredAccess, 0, 0, 0)
	if addr == 0 {
		return nil, os.NewSyscallError("MapViewOfFile", errno)
	}
	handleLock.Lock()
	handleMap[addr] = h
	handleLock.Unlock()

	m := MMap{}
	dh := m.header()
	dh.Data = addr
	dh.Len = length
	dh.Cap = length

	return m, nil
}

func flush(addr, len uintptr) error {
	errno := syscall.FlushViewOfFile(addr, len)
	return os.NewSyscallError("FlushViewOfFile", errno)
}

func unmap(addr, len uintptr) error {
	flush(addr, len)
	err := syscall.UnmapViewOfFile(addr)
	if err != nil {
		return err
	}

	handleLock.Lock()
	defer handleLock.Unlock()
	handle, ok := handleMap[addr]
	if !ok {
		// should be impossible; we would've errored above
		return errors.New("unknown base address")
	}
	delete(handleMap, addr)

	e := syscall.CloseHandle(syscall.Handle(handle))
	return os.NewSyscallError("CloseHandle", e)
}
<commit_msg>fix build error under windows<commit_after>// Copyright 2011 Evan Shaw. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gommap

import (
	"errors"
	"os"
	"sync"
	"syscall"
)

// mmap on Windows is a two-step process.
// First, we call CreateFileMapping to get a handle.
// Then, we call MapviewToFile to get an actual pointer into memory.
// Because we want to emulate a POSIX-style mmap, we don't want to expose
// the handle -- only the pointer. We also want to return only a byte slice,
// not a struct, so it's convenient to manipulate.

// We keep this map so that we can get back the original handle from the memory address.
var handleLock sync.Mutex
var handleMap = map[uintptr]syscall.Handle{}

// Windows mmap always mapes the entire file regardless of the specified length.
func mmap(length int, hfile uintptr) ([]byte, error) {
	flProtect := uint32(syscall.PAGE_READONLY)
	dwDesiredAccess := uint32(syscall.FILE_MAP_READ)
	flProtect = syscall.PAGE_READWRITE
	dwDesiredAccess = syscall.FILE_MAP_WRITE

	h, errno := syscall.CreateFileMapping(syscall.Handle(hfile), nil, flProtect, 0, 0, nil)
	if h == 0 {
		return nil, os.NewSyscallError("CreateFileMapping", errno)
	}

	addr, errno := syscall.MapViewOfFile(h, dwDesiredAccess, 0, 0, 0)
	if addr == 0 {
		return nil, os.NewSyscallError("MapViewOfFile", errno)
	}
	handleLock.Lock()
	handleMap[addr] = h
	handleLock.Unlock()

	m := MMap{}
	dh := m.header()
	dh.Data = addr
	dh.Len = length
	dh.Cap = length

	return m, nil
}

func flush(addr, len uintptr) error {
	errno := syscall.FlushViewOfFile(addr, len)
	return os.NewSyscallError("FlushViewOfFile", errno)
}

func unmap(addr, len uintptr) error {
	flush(addr, len)
	err := syscall.UnmapViewOfFile(addr)
	if err != nil {
		return err
	}

	handleLock.Lock()
	defer handleLock.Unlock()
	handle, ok := handleMap[addr]
	if !ok {
		// should be impossible; we would've errored above
		return errors.New("unknown base address")
	}
	delete(handleMap, addr)

	e := syscall.CloseHandle(syscall.Handle(handle))
	return os.NewSyscallError("CloseHandle", e)
}
<|endoftext|>


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

// Package spinner is a simple package to add a spinner / progress indicator to any terminal application.
package spinner

import (
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"strconv"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/fatih/color"
)

// errInvalidColor is returned when attempting to set an invalid color
var errInvalidColor = errors.New("invalid color")

// validColors holds an array of the only colors allowed
var validColors = map[string]bool{
	// default colors for backwards compatibility
	"black":   true,
	"red":     true,
	"green":   true,
	"yellow":  true,
	"blue":    true,
	"magenta": true,
	"cyan":    true,
	"white":   true,

	// attributes
	"reset":        true,
	"bold":         true,
	"faint":        true,
	"italic":       true,
	"underline":    true,
	"blinkslow":    true,
	"blinkrapid":   true,
	"reversevideo": true,
	"concealed":    true,
	"crossedout":   true,

	// foreground text
	"fgBlack":   true,
	"fgRed":     true,
	"fgGreen":   true,
	"fgYellow":  true,
	"fgBlue":    true,
	"fgMagenta": true,
	"fgCyan":    true,
	"fgWhite":   true,

	// foreground Hi-Intensity text
	"fgHiBlack":   true,
	"fgHiRed":     true,
	"fgHiGreen":   true,
	"fgHiYellow":  true,
	"fgHiBlue":    true,
	"fgHiMagenta": true,
	"fgHiCyan":    true,
	"fgHiWhite":   true,

	// background text
	"bgBlack":   true,
	"bgRed":     true,
	"bgGreen":   true,
	"bgYellow":  true,
	"bgBlue":    true,
	"bgMagenta": true,
	"bgCyan":    true,
	"bgWhite":   true,

	// background Hi-Intensity text
	"bgHiBlack":   true,
	"bgHiRed":     true,
	"bgHiGreen":   true,
	"bgHiYellow":  true,
	"bgHiBlue":    true,
	"bgHiMagenta": true,
	"bgHiCyan":    true,
	"bgHiWhite":   true,
}

// returns a valid color's foreground text color attribute
var colorAttributeMap = map[string]color.Attribute{
	// default colors for backwards compatibility
	"black":   color.FgBlack,
	"red":     color.FgRed,
	"green":   color.FgGreen,
	"yellow":  color.FgYellow,
	"blue":    color.FgBlue,
	"magenta": color.FgMagenta,
	"cyan":    color.FgCyan,
	"white":   color.FgWhite,

	// attributes
	"reset":        color.Reset,
	"bold":         color.Bold,
	"faint":        color.Faint,
	"italic":       color.Italic,
	"underline":    color.Underline,
	"blinkslow":    color.BlinkSlow,
	"blinkrapid":   color.BlinkRapid,
	"reversevideo": color.ReverseVideo,
	"concealed":    color.Concealed,
	"crossedout":   color.CrossedOut,

	// foreground text colors
	"fgBlack":   color.FgBlack,
	"fgRed":     color.FgRed,
	"fgGreen":   color.FgGreen,
	"fgYellow":  color.FgYellow,
	"fgBlue":    color.FgBlue,
	"fgMagenta": color.FgMagenta,
	"fgCyan":    color.FgCyan,
	"fgWhite":   color.FgWhite,

	// foreground Hi-Intensity text colors
	"fgHiBlack":   color.FgHiBlack,
	"fgHiRed":     color.FgHiRed,
	"fgHiGreen":   color.FgHiGreen,
	"fgHiYellow":  color.FgHiYellow,
	"fgHiBlue":    color.FgHiBlue,
	"fgHiMagenta": color.FgHiMagenta,
	"fgHiCyan":    color.FgHiCyan,
	"fgHiWhite":   color.FgHiWhite,

	// background text colors
	"bgBlack":   color.BgBlack,
	"bgRed":     color.BgRed,
	"bgGreen":   color.BgGreen,
	"bgYellow":  color.BgYellow,
	"bgBlue":    color.BgBlue,
	"bgMagenta": color.BgMagenta,
	"bgCyan":    color.BgCyan,
	"bgWhite":   color.BgWhite,

	// background Hi-Intensity text colors
	"bgHiBlack":   color.BgHiBlack,
	"bgHiRed":     color.BgHiRed,
	"bgHiGreen":   color.BgHiGreen,
	"bgHiYellow":  color.BgHiYellow,
	"bgHiBlue":    color.BgHiBlue,
	"bgHiMagenta": color.BgHiMagenta,
	"bgHiCyan":    color.BgHiCyan,
	"bgHiWhite":   color.BgHiWhite,
}

// validColor will make sure the given color is actually allowed
func validColor(c string) bool {
	valid := false
	if validColors[c] {
		valid = true
	}
	return valid
}

// Spinner struct to hold the provided options
type Spinner struct {
	Delay      time.Duration                 // Delay is the speed of the indicator
	chars      []string                      // chars holds the chosen character set
	Prefix     string                        // Prefix is the text preppended to the indicator
	Suffix     string                        // Suffix is the text appended to the indicator
	FinalMSG   string                        // string displayed after Stop() is called
	lastOutput string                        // last character(set) written
	color      func(a ...interface{}) string // default color is white
	lock       *sync.RWMutex                 //
	Writer     io.Writer                     // to make testing better, exported so users have access
	active     bool                          // active holds the state of the spinner
	stopChan   chan struct{}                 // stopChan is a channel used to stop the indicator
}

// New provides a pointer to an instance of Spinner with the supplied options
func New(cs []string, d time.Duration) *Spinner {
	return &Spinner{
		Delay:    d,
		chars:    cs,
		color:    color.New(color.FgWhite).SprintFunc(),
		lock:     &sync.RWMutex{},
		Writer:   color.Output,
		active:   false,
		stopChan: make(chan struct{}, 1),
	}
}

// Active will return whether or not the spinner is currently active
func (s *Spinner) Active() bool {
	return s.active
}

// Start will start the indicator
func (s *Spinner) Start() {
	if s.active {
		return
	}
	s.active = true

	go func() {
		for {
			for i := 0; i < len(s.chars); i++ {
				select {
				case <-s.stopChan:
					return
				default:
					s.lock.Lock()
					s.erase()
					outColor := fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
					outPlain := fmt.Sprintf("%s%s%s ", s.Prefix, s.chars[i], s.Suffix)
					fmt.Fprint(s.Writer, outColor)
					s.lastOutput = outPlain
					delay := s.Delay
					s.lock.Unlock()

					time.Sleep(delay)
				}
			}
		}
	}()
}

// Stop stops the indicator
func (s *Spinner) Stop() {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.active {
		s.active = false
		s.erase()
		if s.FinalMSG != "" {
			fmt.Fprintf(s.Writer, s.FinalMSG)
		}
		s.stopChan <- struct{}{}
	}
}

// Restart will stop and start the indicator
func (s *Spinner) Restart() {
	s.Stop()
	s.Start()
}

// Reverse will reverse the order of the slice assigned to the indicator
func (s *Spinner) Reverse() {
	s.lock.Lock()
	defer s.lock.Unlock()
	for i, j := 0, len(s.chars)-1; i < j; i, j = i+1, j-1 {
		s.chars[i], s.chars[j] = s.chars[j], s.chars[i]
	}
}

// Color will set the struct field for the given color to be used
func (s *Spinner) Color(colors ...string) error {

	colorAttributes := make([]color.Attribute, len(colors))

	// Verify colours are valid and place the appropriate attribute in the array
	for index, c := range colors {
		if !validColor(c) {
			return errInvalidColor
		}

		colorAttributes[index] = colorAttributeMap[c]
	}

	s.color = color.New(colorAttributes...).SprintFunc()
	s.Restart()
	return nil
}

// UpdateSpeed will set the indicator delay to the given value
func (s *Spinner) UpdateSpeed(d time.Duration) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.Delay = d
}

// UpdateCharSet will change the current character set to the given one
func (s *Spinner) UpdateCharSet(cs []string) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.chars = cs
}

// erase deletes written characters
//
// Caller must already hold s.lock.
func (s *Spinner) erase() {
	n := utf8.RuneCountInString(s.lastOutput)
	del, _ := hex.DecodeString("7f")
	for _, c := range []string{
		"\b",
		string(del),
		"\b",
		"\033[K", // for macOS Terminal
	} {
		for i := 0; i < n; i++ {
			fmt.Fprintf(s.Writer, c)
		}
	}
	s.lastOutput = ""
}

// GenerateNumberSequence will generate a slice of integers at the
// provided length and convert them each to a string
func GenerateNumberSequence(length int) []string {
	numSeq := make([]string, length)
	for i := 0; i < length; i++ {
		numSeq[i] = strconv.Itoa(i)
	}
	return numSeq
}
<commit_msg>fix for windows, for when using os.Stderr<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package spinner is a simple package to add a spinner / progress indicator to any terminal application.
package spinner

import (
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"os"
	"runtime"
	"strconv"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/fatih/color"
)

// errInvalidColor is returned when attempting to set an invalid color
var errInvalidColor = errors.New("invalid color")

// validColors holds an array of the only colors allowed
var validColors = map[string]bool{
	// default colors for backwards compatibility
	"black":   true,
	"red":     true,
	"green":   true,
	"yellow":  true,
	"blue":    true,
	"magenta": true,
	"cyan":    true,
	"white":   true,

	// attributes
	"reset":        true,
	"bold":         true,
	"faint":        true,
	"italic":       true,
	"underline":    true,
	"blinkslow":    true,
	"blinkrapid":   true,
	"reversevideo": true,
	"concealed":    true,
	"crossedout":   true,

	// foreground text
	"fgBlack":   true,
	"fgRed":     true,
	"fgGreen":   true,
	"fgYellow":  true,
	"fgBlue":    true,
	"fgMagenta": true,
	"fgCyan":    true,
	"fgWhite":   true,

	// foreground Hi-Intensity text
	"fgHiBlack":   true,
	"fgHiRed":     true,
	"fgHiGreen":   true,
	"fgHiYellow":  true,
	"fgHiBlue":    true,
	"fgHiMagenta": true,
	"fgHiCyan":    true,
	"fgHiWhite":   true,

	// background text
	"bgBlack":   true,
	"bgRed":     true,
	"bgGreen":   true,
	"bgYellow":  true,
	"bgBlue":    true,
	"bgMagenta": true,
	"bgCyan":    true,
	"bgWhite":   true,

	// background Hi-Intensity text
	"bgHiBlack":   true,
	"bgHiRed":     true,
	"bgHiGreen":   true,
	"bgHiYellow":  true,
	"bgHiBlue":    true,
	"bgHiMagenta": true,
	"bgHiCyan":    true,
	"bgHiWhite":   true,
}

// returns a valid color's foreground text color attribute
var colorAttributeMap = map[string]color.Attribute{
	// default colors for backwards compatibility
	"black":   color.FgBlack,
	"red":     color.FgRed,
	"green":   color.FgGreen,
	"yellow":  color.FgYellow,
	"blue":    color.FgBlue,
	"magenta": color.FgMagenta,
	"cyan":    color.FgCyan,
	"white":   color.FgWhite,

	// attributes
	"reset":        color.Reset,
	"bold":         color.Bold,
	"faint":        color.Faint,
	"italic":       color.Italic,
	"underline":    color.Underline,
	"blinkslow":    color.BlinkSlow,
	"blinkrapid":   color.BlinkRapid,
	"reversevideo": color.ReverseVideo,
	"concealed":    color.Concealed,
	"crossedout":   color.CrossedOut,

	// foreground text colors
	"fgBlack":   color.FgBlack,
	"fgRed":     color.FgRed,
	"fgGreen":   color.FgGreen,
	"fgYellow":  color.FgYellow,
	"fgBlue":    color.FgBlue,
	"fgMagenta": color.FgMagenta,
	"fgCyan":    color.FgCyan,
	"fgWhite":   color.FgWhite,

	// foreground Hi-Intensity text colors
	"fgHiBlack":   color.FgHiBlack,
	"fgHiRed":     color.FgHiRed,
	"fgHiGreen":   color.FgHiGreen,
	"fgHiYellow":  color.FgHiYellow,
	"fgHiBlue":    color.FgHiBlue,
	"fgHiMagenta": color.FgHiMagenta,
	"fgHiCyan":    color.FgHiCyan,
	"fgHiWhite":   color.FgHiWhite,

	// background text colors
	"bgBlack":   color.BgBlack,
	"bgRed":     color.BgRed,
	"bgGreen":   color.BgGreen,
	"bgYellow":  color.BgYellow,
	"bgBlue":    color.BgBlue,
	"bgMagenta": color.BgMagenta,
	"bgCyan":    color.BgCyan,
	"bgWhite":   color.BgWhite,

	// background Hi-Intensity text colors
	"bgHiBlack":   color.BgHiBlack,
	"bgHiRed":     color.BgHiRed,
	"bgHiGreen":   color.BgHiGreen,
	"bgHiYellow":  color.BgHiYellow,
	"bgHiBlue":    color.BgHiBlue,
	"bgHiMagenta": color.BgHiMagenta,
	"bgHiCyan":    color.BgHiCyan,
	"bgHiWhite":   color.BgHiWhite,
}

// validColor will make sure the given color is actually allowed
func validColor(c string) bool {
	valid := false
	if validColors[c] {
		valid = true
	}
	return valid
}

// Spinner struct to hold the provided options
type Spinner struct {
	Delay      time.Duration                 // Delay is the speed of the indicator
	chars      []string                      // chars holds the chosen character set
	Prefix     string                        // Prefix is the text preppended to the indicator
	Suffix     string                        // Suffix is the text appended to the indicator
	FinalMSG   string                        // string displayed after Stop() is called
	lastOutput string                        // last character(set) written
	color      func(a ...interface{}) string // default color is white
	lock       *sync.RWMutex                 //
	Writer     io.Writer                     // to make testing better, exported so users have access
	active     bool                          // active holds the state of the spinner
	stopChan   chan struct{}                 // stopChan is a channel used to stop the indicator
}

// New provides a pointer to an instance of Spinner with the supplied options
func New(cs []string, d time.Duration) *Spinner {
	return &Spinner{
		Delay:    d,
		chars:    cs,
		color:    color.New(color.FgWhite).SprintFunc(),
		lock:     &sync.RWMutex{},
		Writer:   color.Output,
		active:   false,
		stopChan: make(chan struct{}, 1),
	}
}

// Active will return whether or not the spinner is currently active
func (s *Spinner) Active() bool {
	return s.active
}

// Start will start the indicator
func (s *Spinner) Start() {
	if s.active {
		return
	}
	s.active = true

	go func() {
		for {
			for i := 0; i < len(s.chars); i++ {
				select {
				case <-s.stopChan:
					return
				default:
					s.lock.Lock()
					// s.erase()
					var outColor string
					if runtime.GOOS == "windows" {
						if s.Writer == os.Stderr {
							outColor = fmt.Sprintf("\r%s%s%s ", s.Prefix, s.chars[i], s.Suffix)
						} else {
							outColor = fmt.Sprintf("\r%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
						}
					} else {
						outColor = fmt.Sprintf("%s%s%s ", s.Prefix, s.color(s.chars[i]), s.Suffix)
					}
					outPlain := fmt.Sprintf("%s%s%s ", s.Prefix, s.chars[i], s.Suffix)
					fmt.Fprint(s.Writer, outColor)
					s.lastOutput = outPlain
					delay := s.Delay
					s.lock.Unlock()

					time.Sleep(delay)
				}
			}
		}
	}()
}

// Stop stops the indicator
func (s *Spinner) Stop() {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.active {
		s.active = false
		s.erase()
		if s.FinalMSG != "" {
			fmt.Fprintf(s.Writer, s.FinalMSG)
		}
		s.stopChan <- struct{}{}
	}
}

// Restart will stop and start the indicator
func (s *Spinner) Restart() {
	s.Stop()
	s.Start()
}

// Reverse will reverse the order of the slice assigned to the indicator
func (s *Spinner) Reverse() {
	s.lock.Lock()
	defer s.lock.Unlock()
	for i, j := 0, len(s.chars)-1; i < j; i, j = i+1, j-1 {
		s.chars[i], s.chars[j] = s.chars[j], s.chars[i]
	}
}

// Color will set the struct field for the given color to be used
func (s *Spinner) Color(colors ...string) error {

	colorAttributes := make([]color.Attribute, len(colors))

	// Verify colours are valid and place the appropriate attribute in the array
	for index, c := range colors {
		if !validColor(c) {
			return errInvalidColor
		}

		colorAttributes[index] = colorAttributeMap[c]
	}

	s.color = color.New(colorAttributes...).SprintFunc()
	s.Restart()
	return nil
}

// UpdateSpeed will set the indicator delay to the given value
func (s *Spinner) UpdateSpeed(d time.Duration) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.Delay = d
}

// UpdateCharSet will change the current character set to the given one
func (s *Spinner) UpdateCharSet(cs []string) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.chars = cs
}

// erase deletes written characters
//
// Caller must already hold s.lock.
func (s *Spinner) erase() {
	n := utf8.RuneCountInString(s.lastOutput)
	del, _ := hex.DecodeString("7f")
	for _, c := range []string{
		"\b",
		string(del),
		"\b",
		"\033[K", // for macOS Terminal
	} {
		for i := 0; i < n; i++ {
			fmt.Fprintf(s.Writer, c)
		}
	}
	s.lastOutput = ""
}

// GenerateNumberSequence will generate a slice of integers at the
// provided length and convert them each to a string
func GenerateNumberSequence(length int) []string {
	numSeq := make([]string, length)
	for i := 0; i < length; i++ {
		numSeq[i] = strconv.Itoa(i)
	}
	return numSeq
}
<|endoftext|>


<commit_before>/*
 * Funkensturm, a versatile DNS proxy
 * Miek Gieben <miek@miek.nl> (c) 2011
 * GPLv2
 */

package main

import (
	"dns"
	"flag"
	"log"
	"os"
)

func serve(w dns.ResponseWriter, req *dns.Msg) {

}

func listenAndServe(add, net string) {
	if err := dns.ListenAndServe(add, net, nil); err != nil {
		log.Printf("fks-shield: failed to setup:", net, add)
	}
}

func main() {
	listen := flag.String("listen", "127.0.0.1:8053", "set the listener address")
	//server := flag.String("server", "127.0.0.1:53", "remote server address(es), seperate with commas")
	//verbose := flag.Bool("verbose", false, "Print packet as it flows through")
	flag.Usage = func() {
		flag.PrintDefaults()
	}
	flag.Parse()

	dns.HandleFunc(".", serve)
	go listenAndServe(*listen, "tcp")
	go listenAndServe(*listen, "udp")

	sig := make(chan os.Signal)
forever:
	for {
		select {
		case <-sig:
			log.Printf("fks-shield: signal received, stopping")
			break forever
		}
	}
}
<commit_msg>Skeleton cache ready<commit_after>/*
 * Funkensturm, a versatile DNS proxy
 * Miek Gieben <miek@miek.nl> (c) 2011
 * GPLv2
 */

package main

import (
	"dns"
	"flag"
	"log"
	"os"
)

var (
	listen  = flag.String("listen", "127.0.0.1:8053", "set the listener address")
	server  = flag.String("server", "127.0.0.1:53", "remote server address(es), seperate with commas")
	verbose = flag.Bool("verbose", false, "Print packet as it flows through")
)

func serve(w dns.ResponseWriter, r *dns.Msg, c *Cache) {
	if p := c.Find(r); p != nil {
		w.Write(p)
		return
	}
	// Cache miss
	client := new(dns.Client)
	if p, e := client.Exchange(r, *server); e == nil {
		w.Write(p)
		c.Insert(p)
		return
	} else {
		// w.Write(SERFVAIL)
	}
}

func listenAndServe(add, net string) {
	if err := dns.ListenAndServe(add, net, nil); err != nil {
		log.Printf("fks-shield: failed to setup:", net, add)
	}
}

func main() {
	flag.Usage = func() {
		flag.PrintDefaults()
	}
	flag.Parse()

	cache := NewCache()

	dns.HandleFunc(".", func(w dns.ResponseWriter, r *dns.Msg) { serve(w, r, cache) })

	go listenAndServe(*listen, "tcp")
	go listenAndServe(*listen, "udp")

	sig := make(chan os.Signal)
forever:
	for {
		select {
		case <-sig:
			log.Printf("fks-shield: signal received, stopping")
			break forever
		}
	}
}
<|endoftext|>