<commit_before>// Copyright 2015 FactomProject Authors. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.

package process

import (
	"errors"
	"github.com/FactomProject/FactomCode/common"
	"github.com/FactomProject/FactomCode/database"
	"github.com/FactomProject/btcd/wire"
	"github.com/davecgh/go-spew/spew"
	"strconv"
	"time"
)

// processDirBlock validates dir block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processDirBlock(msg *wire.MsgDirBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	blk, _ := db.FetchDBlockByHeight(msg.DBlk.Header.DBHeight)
	if blk != nil {
		procLog.Info("DBlock already existing for height:" + string(msg.DBlk.Header.DBHeight))
		return nil
	}

	msg.DBlk.IsSealed = true
	dchain.AddDBlockToDChain(msg.DBlk)

	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, strconv.Itoa(int(msg.DBlk.Header.DBHeight))) // store in mempool with the height as the key

	procLog.Debug("SyncUp: MsgDirBlock DBHeight=", msg.DBlk.Header.DBHeight)

	return nil
}

// processFBlock validates admin block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processFBlock(msg *wire.MsgFBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	key, _ := msg.SC.GetHash().MarshalText()
	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, string(key)) // stored in mem pool with the MR as the key

	procLog.Debug("SyncUp: MsgFBlock DBHeight=", msg.SC.GetDBHeight())

	return nil

}

// processABlock validates admin block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processABlock(msg *wire.MsgABlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	//Add it to mem pool before saving it in db
	msg.ABlk.BuildABHash()
	fMemPool.addBlockMsg(msg, msg.ABlk.ABHash.String()) // store in mem pool with ABHash as key

	procLog.Debug("SyncUp: MsgABlock DBHeight=", msg.ABlk.Header.DBHeight)

	return nil
}

// procesFBlock validates entry credit block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func procesECBlock(msg *wire.MsgECBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, msg.ECBlock.Header.Hash().String())

	// for debugging??
	procLog.Debug("SyncUp: MsgCBlock DBHeight=", msg.ECBlock.Header.DBHeight)

	return nil
}

// processEBlock validates entry block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processEBlock(msg *wire.MsgEBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}
	/*
		if msg.EBlk.Header.DBHeight >= dchain.NextBlockHeight || msg.EBlk.Header.DBHeight < 0 {
			return errors.New("MsgEBlock has an invalid DBHeight:" + strconv.Itoa(int(msg.EBlk.Header.DBHeight)))
		}
	*/
	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, msg.EBlk.KeyMR().String()) // store it in mem pool with MR as the key

	// for debugging??
	procLog.Debug("SyncUp: MsgEBlock DBHeight=", msg.EBlk.Header.DBHeight)

	return nil
}

// processEntry validates entry and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processEntry(msg *wire.MsgEntry) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	// store the entry in mem pool
	h := msg.Entry.Hash()
	fMemPool.addBlockMsg(msg, h.String()) // store it in mem pool with hash as the key

	procLog.Debug("SyncUp: MsgEntry hash=", msg.Entry.Hash())

	return nil
}

// Validate the new blocks in mem pool and store them in db
func validateAndStoreBlocks(fMemPool *ftmMemPool, db database.Db, dchain *common.DChain, outCtlMsgQ chan wire.FtmInternalMsg) {
	var myDBHeight int64
	var sleeptime int
	var dblk *common.DirectoryBlock

	for true {
		dblk = nil
		_, myDBHeight, _ = db.FetchBlockHeightCache()

		adj := (len(dchain.Blocks) - int(myDBHeight))
		if adj <= 0 {
			adj = 1
		}
		// in milliseconds
		sleeptime = 100 + 1000/adj

		if len(dchain.Blocks) > int(myDBHeight+1) {
			dblk = dchain.Blocks[myDBHeight+1]
		}
		if dblk != nil {
			if validateBlocksFromMemPool(dblk, fMemPool, db) {
				err := storeBlocksFromMemPool(dblk, fMemPool, db)
				if err == nil {
					deleteBlocksFromMemPool(dblk, fMemPool)
				} else {
					panic("error in deleteBlocksFromMemPool.")
				}
			} else {
				time.Sleep(time.Duration(sleeptime * 1000000)) // Nanoseconds for duration
			}
		} else {
			time.Sleep(time.Duration(sleeptime * 1000000)) // Nanoseconds for duration

			//send an internal msg to sync up with peers
			// ??
		}

	}

}

// Validate the new blocks in mem pool and store them in db
func validateBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) bool {

	// Validate the genesis block
	if b.Header.DBHeight == 0 {
		h, _ := common.CreateHash(b)
		if h.String() != common.GENESIS_DIR_BLOCK_HASH {
			// panic for milestone 1
			panic("Genesis dir block is not as expected: " + h.String())
		}
	}

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			}
		case achain.ChainID.String():
			if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			} else {
				// validate signature of the previous dir block
				aBlkMsg, _ := msg.(*wire.MsgABlock)
				if !validateDBSignature(aBlkMsg.ABlk, dchain) {
					return false
				}
			}
		case fchain.ChainID.String():
			if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			}
		default:
			if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			} else {
				eBlkMsg, _ := msg.(*wire.MsgEBlock)
				// validate every entry in EBlock
				for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
					if _, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; !foundInMemPool {
						// continue if the entry arleady exists in db
						entry, _ := db.FetchEntryByHash(ebEntry)
						if entry == nil {
							return false
						}
					}
				}
			}
		}
	}

	return true
}

// Validate the new blocks in mem pool and store them in db
// Need to make a batch insert in db in milestone 2
func storeBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) error {

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			ecBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgECBlock)
			err := db.ProcessECBlockBatch(ecBlkMsg.ECBlock)
			if err != nil {
				return err
			}
			// needs to be improved??
			initializeECreditMap(ecBlkMsg.ECBlock)
			// for debugging
			exportECBlock(ecBlkMsg.ECBlock)
		case achain.ChainID.String():
			aBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgABlock)
			err := db.ProcessABlockBatch(aBlkMsg.ABlk)
			if err != nil {
				return err
			}
			// for debugging
			exportABlock(aBlkMsg.ABlk)
		case fchain.ChainID.String():
			fBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgFBlock)
			err := db.ProcessFBlockBatch(fBlkMsg.SC)
			if err != nil {
				return err
			}
			// Initialize the Factoid State
			err = common.FactoidState.AddTransactionBlock(fBlkMsg.SC)
			FactoshisPerCredit = fBlkMsg.SC.GetExchRate()
			if err != nil {
				return err
			}

			// for debugging
			exportFctBlock(fBlkMsg.SC)
		default:
			// handle Entry Block
			eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock)
			// store entry in db first
			for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
				if msg, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; foundInMemPool {
					err := db.InsertEntry(msg.(*wire.MsgEntry).Entry)
					if err != nil {
						return err
					}
				}
			}
			// Store Entry Block in db
			err := db.ProcessEBlockBatch(eBlkMsg.EBlk)
			if err != nil {
				return err
			}

			// create a chain in db if it's not existing
			chain := chainIDMap[eBlkMsg.EBlk.Header.ChainID.String()]
			if chain == nil {
				chain = new(common.EChain)
				chain.ChainID = eBlkMsg.EBlk.Header.ChainID
				if eBlkMsg.EBlk.Header.EBSequence == 0 {
					chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0])
				}
				db.InsertChain(chain)
				chainIDMap[chain.ChainID.String()] = chain
			} else if chain.FirstEntry == nil && eBlkMsg.EBlk.Header.EBSequence == 0 {
				chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0])
				db.InsertChain(chain)
			}

			// for debugging
			exportEBlock(eBlkMsg.EBlk)
		}
	}

	// Store the dir block
	err := db.ProcessDBlockBatch(b)
	if err != nil {
		return err
	}

	// Update dir block height cache in db
	commonHash, _ := common.CreateHash(b)
	db.UpdateBlockHeightCache(b.Header.DBHeight, commonHash)

	// for debugging
	exportDBlock(b)

	return nil
}

// Validate the new blocks in mem pool and store them in db
func deleteBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool) error {

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			delete(fMemPool.blockpool, dbEntry.KeyMR.String())
		case achain.ChainID.String():
			delete(fMemPool.blockpool, dbEntry.KeyMR.String())
		case fchain.ChainID.String():
			delete(fMemPool.blockpool, dbEntry.KeyMR.String())
		default:
			eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock)
			for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
				delete(fMemPool.blockpool, ebEntry.String())
			}
			delete(fMemPool.blockpool, dbEntry.KeyMR.String())
		}
	}
	delete(fMemPool.blockpool, strconv.Itoa(int(b.Header.DBHeight)))

	return nil
}

func validateDBSignature(aBlock *common.AdminBlock, dchain *common.DChain) bool {

	dbSigEntry := aBlock.GetDBSignature()
	if dbSigEntry == nil {
		if aBlock.Header.DBHeight == 0 {
			return true
		} else {
			return false
		}
	} else {
		dbSig := dbSigEntry.(*common.DBSignatureEntry)
		if serverPubKey.String() != dbSig.PubKey.String() {
			return false
		} else {
			// obtain the previous directory block
			dblk := dchain.Blocks[aBlock.Header.DBHeight-1]
			if dblk == nil {
				return false
			} else {
				// validatet the signature
				bHeader, _ := dblk.Header.MarshalBinary()
				if !serverPubKey.Verify(bHeader, dbSig.PrevDBSig) {
					procLog.Infof("No valid signature found in Admin Block = %s\n", spew.Sdump(aBlock))
					return false
				}
			}
		}
	}

	return true
}
<commit_msg>Deactivate genesis block hash panic check<commit_after>// Copyright 2015 FactomProject Authors. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.

package process

import (
	"errors"
	"github.com/FactomProject/FactomCode/common"
	"github.com/FactomProject/FactomCode/database"
	"github.com/FactomProject/btcd/wire"
	"github.com/davecgh/go-spew/spew"
	"strconv"
	"time"
)

// processDirBlock validates dir block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processDirBlock(msg *wire.MsgDirBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	blk, _ := db.FetchDBlockByHeight(msg.DBlk.Header.DBHeight)
	if blk != nil {
		procLog.Info("DBlock already existing for height:" + string(msg.DBlk.Header.DBHeight))
		return nil
	}

	msg.DBlk.IsSealed = true
	dchain.AddDBlockToDChain(msg.DBlk)

	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, strconv.Itoa(int(msg.DBlk.Header.DBHeight))) // store in mempool with the height as the key

	procLog.Debug("SyncUp: MsgDirBlock DBHeight=", msg.DBlk.Header.DBHeight)

	return nil
}

// processFBlock validates admin block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processFBlock(msg *wire.MsgFBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	key, _ := msg.SC.GetHash().MarshalText()
	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, string(key)) // stored in mem pool with the MR as the key

	procLog.Debug("SyncUp: MsgFBlock DBHeight=", msg.SC.GetDBHeight())

	return nil

}

// processABlock validates admin block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processABlock(msg *wire.MsgABlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	//Add it to mem pool before saving it in db
	msg.ABlk.BuildABHash()
	fMemPool.addBlockMsg(msg, msg.ABlk.ABHash.String()) // store in mem pool with ABHash as key

	procLog.Debug("SyncUp: MsgABlock DBHeight=", msg.ABlk.Header.DBHeight)

	return nil
}

// procesFBlock validates entry credit block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func procesECBlock(msg *wire.MsgECBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, msg.ECBlock.Header.Hash().String())

	// for debugging??
	procLog.Debug("SyncUp: MsgCBlock DBHeight=", msg.ECBlock.Header.DBHeight)

	return nil
}

// processEBlock validates entry block and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processEBlock(msg *wire.MsgEBlock) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}
	/*
		if msg.EBlk.Header.DBHeight >= dchain.NextBlockHeight || msg.EBlk.Header.DBHeight < 0 {
			return errors.New("MsgEBlock has an invalid DBHeight:" + strconv.Itoa(int(msg.EBlk.Header.DBHeight)))
		}
	*/
	//Add it to mem pool before saving it in db
	fMemPool.addBlockMsg(msg, msg.EBlk.KeyMR().String()) // store it in mem pool with MR as the key

	// for debugging??
	procLog.Debug("SyncUp: MsgEBlock DBHeight=", msg.EBlk.Header.DBHeight)

	return nil
}

// processEntry validates entry and save it to factom db.
// similar to blockChain.BC_ProcessBlock
func processEntry(msg *wire.MsgEntry) error {

	// Error condiftion for Milestone 1
	if nodeMode == common.SERVER_NODE {
		return errors.New("Server received msg:" + msg.Command())
	}

	// store the entry in mem pool
	h := msg.Entry.Hash()
	fMemPool.addBlockMsg(msg, h.String()) // store it in mem pool with hash as the key

	procLog.Debug("SyncUp: MsgEntry hash=", msg.Entry.Hash())

	return nil
}

// Validate the new blocks in mem pool and store them in db
func validateAndStoreBlocks(fMemPool *ftmMemPool, db database.Db, dchain *common.DChain, outCtlMsgQ chan wire.FtmInternalMsg) {
	var myDBHeight int64
	var sleeptime int
	var dblk *common.DirectoryBlock

	for true {
		dblk = nil
		_, myDBHeight, _ = db.FetchBlockHeightCache()

		adj := (len(dchain.Blocks) - int(myDBHeight))
		if adj <= 0 {
			adj = 1
		}
		// in milliseconds
		sleeptime = 100 + 1000/adj

		if len(dchain.Blocks) > int(myDBHeight+1) {
			dblk = dchain.Blocks[myDBHeight+1]
		}
		if dblk != nil {
			if validateBlocksFromMemPool(dblk, fMemPool, db) {
				err := storeBlocksFromMemPool(dblk, fMemPool, db)
				if err == nil {
					deleteBlocksFromMemPool(dblk, fMemPool)
				} else {
					panic("error in deleteBlocksFromMemPool.")
				}
			} else {
				time.Sleep(time.Duration(sleeptime * 1000000)) // Nanoseconds for duration
			}
		} else {
			time.Sleep(time.Duration(sleeptime * 1000000)) // Nanoseconds for duration

			//send an internal msg to sync up with peers
			// ??
		}

	}

}

// Validate the new blocks in mem pool and store them in db
func validateBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) bool {

	// Validate the genesis block
	if b.Header.DBHeight == 0 {
		h, _ := common.CreateHash(b)
		if h.String() != common.GENESIS_DIR_BLOCK_HASH {
			// panic for milestone 1
			//panic("Genesis dir block is not as expected: " + h.String())
			procLog.Errorf("Genesis dir block is not as expected: " + h.String())
		}
	}

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			}
		case achain.ChainID.String():
			if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			} else {
				// validate signature of the previous dir block
				aBlkMsg, _ := msg.(*wire.MsgABlock)
				if !validateDBSignature(aBlkMsg.ABlk, dchain) {
					return false
				}
			}
		case fchain.ChainID.String():
			if _, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			}
		default:
			if msg, ok := fMemPool.blockpool[dbEntry.KeyMR.String()]; !ok {
				return false
			} else {
				eBlkMsg, _ := msg.(*wire.MsgEBlock)
				// validate every entry in EBlock
				for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
					if _, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; !foundInMemPool {
						// continue if the entry arleady exists in db
						entry, _ := db.FetchEntryByHash(ebEntry)
						if entry == nil {
							return false
						}
					}
				}
			}
		}
	}

	return true
}

// Validate the new blocks in mem pool and store them in db
// Need to make a batch insert in db in milestone 2
func storeBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool, db database.Db) error {

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			ecBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgECBlock)
			err := db.ProcessECBlockBatch(ecBlkMsg.ECBlock)
			if err != nil {
				return err
			}
			// needs to be improved??
			initializeECreditMap(ecBlkMsg.ECBlock)
			// for debugging
			exportECBlock(ecBlkMsg.ECBlock)
		case achain.ChainID.String():
			aBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgABlock)
			err := db.ProcessABlockBatch(aBlkMsg.ABlk)
			if err != nil {
				return err
			}
			// for debugging
			exportABlock(aBlkMsg.ABlk)
		case fchain.ChainID.String():
			fBlkMsg := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgFBlock)
			err := db.ProcessFBlockBatch(fBlkMsg.SC)
			if err != nil {
				return err
			}
			// Initialize the Factoid State
			err = common.FactoidState.AddTransactionBlock(fBlkMsg.SC)
			FactoshisPerCredit = fBlkMsg.SC.GetExchRate()
			if err != nil {
				return err
			}

			// for debugging
			exportFctBlock(fBlkMsg.SC)
		default:
			// handle Entry Block
			eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock)
			// store entry in db first
			for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
				if msg, foundInMemPool := fMemPool.blockpool[ebEntry.String()]; foundInMemPool {
					err := db.InsertEntry(msg.(*wire.MsgEntry).Entry)
					if err != nil {
						return err
					}
				}
			}
			// Store Entry Block in db
			err := db.ProcessEBlockBatch(eBlkMsg.EBlk)
			if err != nil {
				return err
			}

			// create a chain in db if it's not existing
			chain := chainIDMap[eBlkMsg.EBlk.Header.ChainID.String()]
			if chain == nil {
				chain = new(common.EChain)
				chain.ChainID = eBlkMsg.EBlk.Header.ChainID
				if eBlkMsg.EBlk.Header.EBSequence == 0 {
					chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0])
				}
				db.InsertChain(chain)
				chainIDMap[chain.ChainID.String()] = chain
			} else if chain.FirstEntry == nil && eBlkMsg.EBlk.Header.EBSequence == 0 {
				chain.FirstEntry, _ = db.FetchEntryByHash(eBlkMsg.EBlk.Body.EBEntries[0])
				db.InsertChain(chain)
			}

			// for debugging
			exportEBlock(eBlkMsg.EBlk)
		}
	}

	// Store the dir block
	err := db.ProcessDBlockBatch(b)
	if err != nil {
		return err
	}

	// Update dir block height cache in db
	commonHash, _ := common.CreateHash(b)
	db.UpdateBlockHeightCache(b.Header.DBHeight, commonHash)

	// for debugging
	exportDBlock(b)

	return nil
}

// Validate the new blocks in mem pool and store them in db
func deleteBlocksFromMemPool(b *common.DirectoryBlock, fMemPool *ftmMemPool) error {

	for _, dbEntry := range b.DBEntries {
		switch dbEntry.ChainID.String() {
		case ecchain.ChainID.String():
			delete(fMemPool.blockpool, dbEntry.KeyMR.String())
		case achain.ChainID.String():
			delete(fMemPool.blockpool, dbEntry.KeyMR.String())
		case fchain.ChainID.String():
			delete(fMemPool.blockpool, dbEntry.KeyMR.String())
		default:
			eBlkMsg, _ := fMemPool.blockpool[dbEntry.KeyMR.String()].(*wire.MsgEBlock)
			for _, ebEntry := range eBlkMsg.EBlk.Body.EBEntries {
				delete(fMemPool.blockpool, ebEntry.String())
			}
			delete(fMemPool.blockpool, dbEntry.KeyMR.String())
		}
	}
	delete(fMemPool.blockpool, strconv.Itoa(int(b.Header.DBHeight)))

	return nil
}

func validateDBSignature(aBlock *common.AdminBlock, dchain *common.DChain) bool {

	dbSigEntry := aBlock.GetDBSignature()
	if dbSigEntry == nil {
		if aBlock.Header.DBHeight == 0 {
			return true
		} else {
			return false
		}
	} else {
		dbSig := dbSigEntry.(*common.DBSignatureEntry)
		if serverPubKey.String() != dbSig.PubKey.String() {
			return false
		} else {
			// obtain the previous directory block
			dblk := dchain.Blocks[aBlock.Header.DBHeight-1]
			if dblk == nil {
				return false
			} else {
				// validatet the signature
				bHeader, _ := dblk.Header.MarshalBinary()
				if !serverPubKey.Verify(bHeader, dbSig.PrevDBSig) {
					procLog.Infof("No valid signature found in Admin Block = %s\n", spew.Sdump(aBlock))
					return false
				}
			}
		}
	}

	return true
}
<|endoftext|>


<commit_before>package packed

import (
	"github.com/balzaczyy/golucene/core/util"
	"reflect"
)

// util/packed/PackedLongValues.java

const DEFAULT_PAGE_SIZE = 1024
const MIN_PAGE_SIZE = 64
const MAX_PAGE_SIZE = 1 << 20

type PackedLongValues interface {
	Size() int64
	Iterator() func() (interface{}, bool)
}

type PackedLongValuesBuilder interface {
	util.Accountable
	Build() PackedLongValues
	Size() int64
	Add(int64) PackedLongValuesBuilder
}

func DeltaPackedBuilder(acceptableOverheadRatio float32) PackedLongValuesBuilder {
	return NewDeltaPackedLongValuesBuilder(DEFAULT_PAGE_SIZE, acceptableOverheadRatio)
}

type PackedLongValuesImpl struct {
}

func (p *PackedLongValuesImpl) Size() int64 {
	panic("niy")
}

func (p *PackedLongValuesImpl) Iterator() func() (interface{}, bool) {
	panic("niy")
}

const INITIAL_PAGE_COUNT = 16

type PackedLongValuesBuilderImpl struct {
	pageShift, pageMask     int
	acceptableOverheadRatio float32
	pending                 []int64
	size                    int64

	values       []PackedIntsReader
	ramBytesUsed int64
	valuesOff    int
	pendingOff   int
}

func newPackedLongValuesBuilder(pageSize int,
	acceptableOverheadRatio float32) *PackedLongValuesBuilderImpl {

	ans := &PackedLongValuesBuilderImpl{
		pageShift:               checkBlockSize(pageSize, MIN_PAGE_SIZE, MAX_PAGE_SIZE),
		pageMask:                pageSize - 1,
		acceptableOverheadRatio: acceptableOverheadRatio,
		values:                  make([]PackedIntsReader, INITIAL_PAGE_COUNT),
		pending:                 make([]int64, pageSize),
	}
	ans.ramBytesUsed = util.ShallowSizeOfInstance(reflect.TypeOf(&PackedLongValuesBuilderImpl{})) +
		util.SizeOf(ans.pending) + util.ShallowSizeOf(ans.values)
	return ans
}

/*
Build a PackedLongValues instance that contains values that have been
added to this builder. This operation is destructive.
*/
func (b *PackedLongValuesBuilderImpl) Build() PackedLongValues {
	panic("niy")
}

func (b *PackedLongValuesBuilderImpl) RamBytesUsed() int64 {
	panic("niy")
}

/* Return the number of elements that have been added to this builder */
func (b *PackedLongValuesBuilderImpl) Size() int64 {
	panic("niy")
}

/* Add a new element to this builder. */
func (b *PackedLongValuesBuilderImpl) Add(l int64) PackedLongValuesBuilder {
	panic("niy")
}

// util/packed/DeltaPackedLongValues.java

type DeltaPackedLongValuesBuilderImpl struct {
	*PackedLongValuesBuilderImpl
	mins []int64
}

func NewDeltaPackedLongValuesBuilder(pageSize int,
	acceptableOverheadRatio float32) *DeltaPackedLongValuesBuilderImpl {

	super := newPackedLongValuesBuilder(pageSize, acceptableOverheadRatio)
	ans := &DeltaPackedLongValuesBuilderImpl{
		PackedLongValuesBuilderImpl: super,
		mins: make([]int64, len(super.values)),
	}
	ans.ramBytesUsed += util.ShallowSizeOfInstance(reflect.TypeOf(&DeltaPackedLongValuesBuilderImpl{})) +
		util.SizeOf(ans.mins)
	return ans
}
<commit_msg>implement PackedLongValuesBuilder.add()<commit_after>package packed

import (
	"github.com/balzaczyy/golucene/core/util"
	"reflect"
)

// util/packed/PackedLongValues.java

const DEFAULT_PAGE_SIZE = 1024
const MIN_PAGE_SIZE = 64
const MAX_PAGE_SIZE = 1 << 20

type PackedLongValues interface {
	Size() int64
	Iterator() func() (interface{}, bool)
}

type PackedLongValuesBuilder interface {
	util.Accountable
	Build() PackedLongValues
	Size() int64
	Add(int64) PackedLongValuesBuilder
}

func DeltaPackedBuilder(acceptableOverheadRatio float32) PackedLongValuesBuilder {
	return NewDeltaPackedLongValuesBuilder(DEFAULT_PAGE_SIZE, acceptableOverheadRatio)
}

type PackedLongValuesImpl struct {
}

func (p *PackedLongValuesImpl) Size() int64 {
	panic("niy")
}

func (p *PackedLongValuesImpl) Iterator() func() (interface{}, bool) {
	panic("niy")
}

const INITIAL_PAGE_COUNT = 16

type PackedLongValuesBuilderImpl struct {
	pageShift, pageMask     int
	acceptableOverheadRatio float32
	pending                 []int64
	size                    int64

	values       []PackedIntsReader
	ramBytesUsed int64
	valuesOff    int
	pendingOff   int
}

func newPackedLongValuesBuilder(pageSize int,
	acceptableOverheadRatio float32) *PackedLongValuesBuilderImpl {

	ans := &PackedLongValuesBuilderImpl{
		pageShift:               checkBlockSize(pageSize, MIN_PAGE_SIZE, MAX_PAGE_SIZE),
		pageMask:                pageSize - 1,
		acceptableOverheadRatio: acceptableOverheadRatio,
		values:                  make([]PackedIntsReader, INITIAL_PAGE_COUNT),
		pending:                 make([]int64, pageSize),
	}
	ans.ramBytesUsed = util.ShallowSizeOfInstance(reflect.TypeOf(&PackedLongValuesBuilderImpl{})) +
		util.SizeOf(ans.pending) + util.ShallowSizeOf(ans.values)
	return ans
}

/*
Build a PackedLongValues instance that contains values that have been
added to this builder. This operation is destructive.
*/
func (b *PackedLongValuesBuilderImpl) Build() PackedLongValues {
	panic("niy")
}

func (b *PackedLongValuesBuilderImpl) RamBytesUsed() int64 {
	return b.ramBytesUsed
}

/* Return the number of elements that have been added to this builder */
func (b *PackedLongValuesBuilderImpl) Size() int64 {
	return b.size
}

/* Add a new element to this builder. */
func (b *PackedLongValuesBuilderImpl) Add(l int64) PackedLongValuesBuilder {
	assert2(b.pending != nil, "Cannot be reused after build()")
	if b.pendingOff == len(b.pending) { // check size
		if b.valuesOff == len(b.values) {
			newLength := util.Oversize(b.valuesOff+1, 8)
			b.grow(newLength)
		}
		b.pack()
	}
	b.pending[b.pendingOff] = l
	b.pendingOff++
	b.size++
	return b
}

func (b *PackedLongValuesBuilderImpl) finish() {
	panic("niy")
}

func (b *PackedLongValuesBuilderImpl) pack() {
	panic("niy")
}

func (b *PackedLongValuesBuilderImpl) grow(newBlockCount int) {
	panic("niy")
}

// util/packed/DeltaPackedLongValues.java

type DeltaPackedLongValuesBuilderImpl struct {
	*PackedLongValuesBuilderImpl
	mins []int64
}

func NewDeltaPackedLongValuesBuilder(pageSize int,
	acceptableOverheadRatio float32) *DeltaPackedLongValuesBuilderImpl {

	super := newPackedLongValuesBuilder(pageSize, acceptableOverheadRatio)
	ans := &DeltaPackedLongValuesBuilderImpl{
		PackedLongValuesBuilderImpl: super,
		mins: make([]int64, len(super.values)),
	}
	ans.ramBytesUsed += util.ShallowSizeOfInstance(reflect.TypeOf(&DeltaPackedLongValuesBuilderImpl{})) +
		util.SizeOf(ans.mins)
	return ans
}
<|endoftext|>


<commit_before>package registry

import (
	"bytes"
	"io/ioutil"
	"net/http"

	manifest "github.com/docker/distribution/manifest/schema1"
)

func (registry *Registry) Manifest(repository, reference string) (*manifest.SignedManifest, error) {
	url := registry.url("/v2/%s/manifests/%s", repository, reference)
	registry.Logf("registry.manifest.get url=%s repository=%s reference=%s", url, repository, reference)

	resp, err := registry.Client.Get(url)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	signedManifest := &manifest.SignedManifest{}
	err = signedManifest.UnmarshalJSON(body)
	if err != nil {
		return nil, err
	}

	return signedManifest, nil
}

func (registry *Registry) ManifestDigest(repository, reference string) (string, error) {
	url := registry.url("/v2/%s/manifests/%s", repository, reference)
	registry.Logf("registry.manifest.head url=%s repository=%s reference=%s", url, repository, reference)

	resp, err := registry.Client.Head(url)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return "", err
	}
	return resp.Header.Get("Docker-Content-Digest"), nil
}

func (registry *Registry) DeleteManifest(repository, reference string) error {
	digest, err := registry.ManifestDigest(repository, reference)
	if err != nil {
		return err
	}

	url := registry.url("/v2/%s/manifests/%s", repository, digest)
	registry.Logf("registry.manifest.delete url=%s repository=%s reference=%s", url, repository, digest)

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}
	resp, err := registry.Client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return err
	}
	return nil
}

func (registry *Registry) PutManifest(repository, reference string, signedManifest *manifest.SignedManifest) error {
	url := registry.url("/v2/%s/manifests/%s", repository, reference)
	registry.Logf("registry.manifest.put url=%s repository=%s reference=%s", url, repository, reference)

	body, err := signedManifest.MarshalJSON()
	if err != nil {
		return err
	}

	buffer := bytes.NewBuffer(body)
	req, err := http.NewRequest("PUT", url, buffer)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", manifest.MediaTypeManifest)
	resp, err := registry.Client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}
	return err
}
<commit_msg>Switched to type digest.Digest<commit_after>package registry

import (
	"bytes"
	"io/ioutil"
	"net/http"

	"github.com/docker/distribution/digest"
	manifest "github.com/docker/distribution/manifest/schema1"
)

func (registry *Registry) Manifest(repository, reference string) (*manifest.SignedManifest, error) {
	url := registry.url("/v2/%s/manifests/%s", repository, reference)
	registry.Logf("registry.manifest.get url=%s repository=%s reference=%s", url, repository, reference)

	resp, err := registry.Client.Get(url)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	signedManifest := &manifest.SignedManifest{}
	err = signedManifest.UnmarshalJSON(body)
	if err != nil {
		return nil, err
	}

	return signedManifest, nil
}

func (registry *Registry) ManifestDigest(repository, reference string) (digest.Digest, error) {
	url := registry.url("/v2/%s/manifests/%s", repository, reference)
	registry.Logf("registry.manifest.head url=%s repository=%s reference=%s", url, repository, reference)

	resp, err := registry.Client.Head(url)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return "", err
	}
	return digest.ParseDigest(resp.Header.Get("Docker-Content-Digest"))
}

func (registry *Registry) DeleteManifest(repository, reference string) error {
	digest, err := registry.ManifestDigest(repository, reference)
	if err != nil {
		return err
	}

	url := registry.url("/v2/%s/manifests/%s", repository, digest)
	registry.Logf("registry.manifest.delete url=%s repository=%s reference=%s", url, repository, digest)

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return err
	}
	resp, err := registry.Client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return err
	}
	return nil
}

func (registry *Registry) PutManifest(repository, reference string, signedManifest *manifest.SignedManifest) error {
	url := registry.url("/v2/%s/manifests/%s", repository, reference)
	registry.Logf("registry.manifest.put url=%s repository=%s reference=%s", url, repository, reference)

	body, err := signedManifest.MarshalJSON()
	if err != nil {
		return err
	}

	buffer := bytes.NewBuffer(body)
	req, err := http.NewRequest("PUT", url, buffer)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", manifest.MediaTypeManifest)
	resp, err := registry.Client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}
	return err
}
<|endoftext|>


<commit_before>// Package registry contains client primitives to interact with a remote Docker registry.
package registry

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/distribution/registry/api/errcode"
	"github.com/docker/distribution/registry/api/v2"
	"github.com/docker/distribution/registry/client"
	"github.com/docker/distribution/registry/client/transport"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/parsers/kernel"
	"github.com/docker/docker/pkg/tlsconfig"
	"github.com/docker/docker/pkg/useragent"
)

var (
	// ErrAlreadyExists is an error returned if an image being pushed
	// already exists on the remote side
	ErrAlreadyExists = errors.New("Image already exists")
	errLoginRequired = errors.New("Authentication is required.")
)

// dockerUserAgent is the User-Agent the Docker client uses to identify itself.
// It is populated on init(), comprising version information of different components.
var dockerUserAgent string

func init() {
	httpVersion := make([]useragent.VersionInfo, 0, 6)
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "docker", Version: dockerversion.Version})
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "go", Version: runtime.Version()})
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "git-commit", Version: dockerversion.GitCommit})
	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "kernel", Version: kernelVersion.String()})
	}
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "os", Version: runtime.GOOS})
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "arch", Version: runtime.GOARCH})

	dockerUserAgent = useragent.AppendVersions("", httpVersion...)

	if runtime.GOOS != "linux" {
		V2Only = true
	}
}

func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) {
	// PreferredServerCipherSuites should have no effect
	tlsConfig := tlsconfig.ServerDefault

	tlsConfig.InsecureSkipVerify = !isSecure

	if isSecure {
		hostDir := filepath.Join(CertsDir, cleanPath(hostname))
		logrus.Debugf("hostDir: %s", hostDir)
		if err := ReadCertsDirectory(&tlsConfig, hostDir); err != nil {
			return nil, err
		}
	}

	return &tlsConfig, nil
}

func hasFile(files []os.FileInfo, name string) bool {
	for _, f := range files {
		if f.Name() == name {
			return true
		}
	}
	return false
}

// ReadCertsDirectory reads the directory for TLS certificates
// including roots and certificate pairs and updates the
// provided TLS configuration.
func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
	fs, err := ioutil.ReadDir(directory)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	for _, f := range fs {
		if strings.HasSuffix(f.Name(), ".crt") {
			if tlsConfig.RootCAs == nil {
				// TODO(dmcgowan): Copy system pool
				tlsConfig.RootCAs = x509.NewCertPool()
			}
			logrus.Debugf("crt: %s", filepath.Join(directory, f.Name()))
			data, err := ioutil.ReadFile(filepath.Join(directory, f.Name()))
			if err != nil {
				return err
			}
			tlsConfig.RootCAs.AppendCertsFromPEM(data)
		}
		if strings.HasSuffix(f.Name(), ".cert") {
			certName := f.Name()
			keyName := certName[:len(certName)-5] + ".key"
			logrus.Debugf("cert: %s", filepath.Join(directory, f.Name()))
			if !hasFile(fs, keyName) {
				return fmt.Errorf("Missing key %s for certificate %s", keyName, certName)
			}
			cert, err := tls.LoadX509KeyPair(filepath.Join(directory, certName), filepath.Join(directory, keyName))
			if err != nil {
				return err
			}
			tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
		}
		if strings.HasSuffix(f.Name(), ".key") {
			keyName := f.Name()
			certName := keyName[:len(keyName)-4] + ".cert"
			logrus.Debugf("key: %s", filepath.Join(directory, f.Name()))
			if !hasFile(fs, certName) {
				return fmt.Errorf("Missing certificate %s for key %s", certName, keyName)
			}
		}
	}

	return nil
}

// DockerHeaders returns request modifiers that ensure requests have
// the User-Agent header set to dockerUserAgent and that metaHeaders
// are added.
func DockerHeaders(metaHeaders http.Header) []transport.RequestModifier {
	modifiers := []transport.RequestModifier{
		transport.NewHeaderRequestModifier(http.Header{"User-Agent": []string{dockerUserAgent}}),
	}
	if metaHeaders != nil {
		modifiers = append(modifiers, transport.NewHeaderRequestModifier(metaHeaders))
	}
	return modifiers
}

// HTTPClient returns a HTTP client structure which uses the given transport
// and contains the necessary headers for redirected requests
func HTTPClient(transport http.RoundTripper) *http.Client {
	return &http.Client{
		Transport:     transport,
		CheckRedirect: addRequiredHeadersToRedirectedRequests,
	}
}

func trustedLocation(req *http.Request) bool {
	var (
		trusteds = []string{"docker.com", "docker.io"}
		hostname = strings.SplitN(req.Host, ":", 2)[0]
	)
	if req.URL.Scheme != "https" {
		return false
	}

	for _, trusted := range trusteds {
		if hostname == trusted || strings.HasSuffix(hostname, "."+trusted) {
			return true
		}
	}
	return false
}

// addRequiredHeadersToRedirectedRequests adds the necessary redirection headers
// for redirected requests
func addRequiredHeadersToRedirectedRequests(req *http.Request, via []*http.Request) error {
	if via != nil && via[0] != nil {
		if trustedLocation(req) && trustedLocation(via[0]) {
			req.Header = via[0].Header
			return nil
		}
		for k, v := range via[0].Header {
			if k != "Authorization" {
				for _, vv := range v {
					req.Header.Add(k, vv)
				}
			}
		}
	}
	return nil
}

func shouldV2Fallback(err errcode.Error) bool {
	logrus.Debugf("v2 error: %T %v", err, err)
	switch err.Code {
	case errcode.ErrorCodeUnauthorized, v2.ErrorCodeManifestUnknown:
		return true
	}
	return false
}

// ErrNoSupport is an error type used for errors indicating that an operation
// is not supported. It encapsulates a more specific error.
type ErrNoSupport struct{ Err error }

func (e ErrNoSupport) Error() string {
	if e.Err == nil {
		return "not supported"
	}
	return e.Err.Error()
}

// ContinueOnError returns true if we should fallback to the next endpoint
// as a result of this error.
func ContinueOnError(err error) bool {
	switch v := err.(type) {
	case errcode.Errors:
		return ContinueOnError(v[0])
	case ErrNoSupport:
		return ContinueOnError(v.Err)
	case errcode.Error:
		return shouldV2Fallback(v)
	case *client.UnexpectedHTTPResponseError:
		return true
	case error:
		if val := strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())); val {
			return false
		}
	}
	// let's be nice and fallback if the error is a completely
	// unexpected one.
	// If new errors have to be handled in some way, please
	// add them to the switch above.
	return true
}

// NewTransport returns a new HTTP transport. If tlsConfig is nil, it uses the
// default TLS configuration.
func NewTransport(tlsConfig *tls.Config) *http.Transport {
	if tlsConfig == nil {
		var cfg = tlsconfig.ServerDefault
		tlsConfig = &cfg
	}
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     tlsConfig,
		// TODO(dmcgowan): Call close idle connections when complete and use keep alive
		DisableKeepAlives: true,
	}
}
<commit_msg>registry/registry.go: simplify logical expression<commit_after>// Package registry contains client primitives to interact with a remote Docker registry.
package registry

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/distribution/registry/api/errcode"
	"github.com/docker/distribution/registry/api/v2"
	"github.com/docker/distribution/registry/client"
	"github.com/docker/distribution/registry/client/transport"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/parsers/kernel"
	"github.com/docker/docker/pkg/tlsconfig"
	"github.com/docker/docker/pkg/useragent"
)

var (
	// ErrAlreadyExists is an error returned if an image being pushed
	// already exists on the remote side
	ErrAlreadyExists = errors.New("Image already exists")
	errLoginRequired = errors.New("Authentication is required.")
)

// dockerUserAgent is the User-Agent the Docker client uses to identify itself.
// It is populated on init(), comprising version information of different components.
var dockerUserAgent string

func init() {
	httpVersion := make([]useragent.VersionInfo, 0, 6)
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "docker", Version: dockerversion.Version})
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "go", Version: runtime.Version()})
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "git-commit", Version: dockerversion.GitCommit})
	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "kernel", Version: kernelVersion.String()})
	}
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "os", Version: runtime.GOOS})
	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "arch", Version: runtime.GOARCH})

	dockerUserAgent = useragent.AppendVersions("", httpVersion...)

	if runtime.GOOS != "linux" {
		V2Only = true
	}
}

func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) {
	// PreferredServerCipherSuites should have no effect
	tlsConfig := tlsconfig.ServerDefault

	tlsConfig.InsecureSkipVerify = !isSecure

	if isSecure {
		hostDir := filepath.Join(CertsDir, cleanPath(hostname))
		logrus.Debugf("hostDir: %s", hostDir)
		if err := ReadCertsDirectory(&tlsConfig, hostDir); err != nil {
			return nil, err
		}
	}

	return &tlsConfig, nil
}

func hasFile(files []os.FileInfo, name string) bool {
	for _, f := range files {
		if f.Name() == name {
			return true
		}
	}
	return false
}

// ReadCertsDirectory reads the directory for TLS certificates
// including roots and certificate pairs and updates the
// provided TLS configuration.
func ReadCertsDirectory(tlsConfig *tls.Config, directory string) error {
	fs, err := ioutil.ReadDir(directory)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	for _, f := range fs {
		if strings.HasSuffix(f.Name(), ".crt") {
			if tlsConfig.RootCAs == nil {
				// TODO(dmcgowan): Copy system pool
				tlsConfig.RootCAs = x509.NewCertPool()
			}
			logrus.Debugf("crt: %s", filepath.Join(directory, f.Name()))
			data, err := ioutil.ReadFile(filepath.Join(directory, f.Name()))
			if err != nil {
				return err
			}
			tlsConfig.RootCAs.AppendCertsFromPEM(data)
		}
		if strings.HasSuffix(f.Name(), ".cert") {
			certName := f.Name()
			keyName := certName[:len(certName)-5] + ".key"
			logrus.Debugf("cert: %s", filepath.Join(directory, f.Name()))
			if !hasFile(fs, keyName) {
				return fmt.Errorf("Missing key %s for certificate %s", keyName, certName)
			}
			cert, err := tls.LoadX509KeyPair(filepath.Join(directory, certName), filepath.Join(directory, keyName))
			if err != nil {
				return err
			}
			tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
		}
		if strings.HasSuffix(f.Name(), ".key") {
			keyName := f.Name()
			certName := keyName[:len(keyName)-4] + ".cert"
			logrus.Debugf("key: %s", filepath.Join(directory, f.Name()))
			if !hasFile(fs, certName) {
				return fmt.Errorf("Missing certificate %s for key %s", certName, keyName)
			}
		}
	}

	return nil
}

// DockerHeaders returns request modifiers that ensure requests have
// the User-Agent header set to dockerUserAgent and that metaHeaders
// are added.
func DockerHeaders(metaHeaders http.Header) []transport.RequestModifier {
	modifiers := []transport.RequestModifier{
		transport.NewHeaderRequestModifier(http.Header{"User-Agent": []string{dockerUserAgent}}),
	}
	if metaHeaders != nil {
		modifiers = append(modifiers, transport.NewHeaderRequestModifier(metaHeaders))
	}
	return modifiers
}

// HTTPClient returns a HTTP client structure which uses the given transport
// and contains the necessary headers for redirected requests
func HTTPClient(transport http.RoundTripper) *http.Client {
	return &http.Client{
		Transport:     transport,
		CheckRedirect: addRequiredHeadersToRedirectedRequests,
	}
}

func trustedLocation(req *http.Request) bool {
	var (
		trusteds = []string{"docker.com", "docker.io"}
		hostname = strings.SplitN(req.Host, ":", 2)[0]
	)
	if req.URL.Scheme != "https" {
		return false
	}

	for _, trusted := range trusteds {
		if hostname == trusted || strings.HasSuffix(hostname, "."+trusted) {
			return true
		}
	}
	return false
}

// addRequiredHeadersToRedirectedRequests adds the necessary redirection headers
// for redirected requests
func addRequiredHeadersToRedirectedRequests(req *http.Request, via []*http.Request) error {
	if via != nil && via[0] != nil {
		if trustedLocation(req) && trustedLocation(via[0]) {
			req.Header = via[0].Header
			return nil
		}
		for k, v := range via[0].Header {
			if k != "Authorization" {
				for _, vv := range v {
					req.Header.Add(k, vv)
				}
			}
		}
	}
	return nil
}

func shouldV2Fallback(err errcode.Error) bool {
	logrus.Debugf("v2 error: %T %v", err, err)
	switch err.Code {
	case errcode.ErrorCodeUnauthorized, v2.ErrorCodeManifestUnknown:
		return true
	}
	return false
}

// ErrNoSupport is an error type used for errors indicating that an operation
// is not supported. It encapsulates a more specific error.
type ErrNoSupport struct{ Err error }

func (e ErrNoSupport) Error() string {
	if e.Err == nil {
		return "not supported"
	}
	return e.Err.Error()
}

// ContinueOnError returns true if we should fallback to the next endpoint
// as a result of this error.
func ContinueOnError(err error) bool {
	switch v := err.(type) {
	case errcode.Errors:
		return ContinueOnError(v[0])
	case ErrNoSupport:
		return ContinueOnError(v.Err)
	case errcode.Error:
		return shouldV2Fallback(v)
	case *client.UnexpectedHTTPResponseError:
		return true
	case error:
		return !strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error()))
	}
	// let's be nice and fallback if the error is a completely
	// unexpected one.
	// If new errors have to be handled in some way, please
	// add them to the switch above.
	return true
}

// NewTransport returns a new HTTP transport. If tlsConfig is nil, it uses the
// default TLS configuration.
func NewTransport(tlsConfig *tls.Config) *http.Transport {
	if tlsConfig == nil {
		var cfg = tlsconfig.ServerDefault
		tlsConfig = &cfg
	}
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     tlsConfig,
		// TODO(dmcgowan): Call close idle connections when complete and use keep alive
		DisableKeepAlives: true,
	}
}
<|endoftext|>


<commit_before>package main

import (
	// "encoding/base64"
	// "encoding/json"
	"testing"

	"github.com/stretchr/testify/assert"

	pubsub "google.golang.org/api/pubsub/v1"
)

const (
	bucket = "bucket1"
	path1 = "path/to/file1"
	url1 = "gs://" + bucket + "/" + path1
	local1 = downloads_dir + "/" + bucket + "/" + path1
)

var (
	BaseNotificationAttrs = map[string]string {
		"objectId" : "path/to/file1",
		"payloadFormat": "JSON_API_V1",
		"resource": "projects/_/buckets/bucket1/objects/path/to/file1#1495443037537696",
		"bucketId": "bucket1",
		"eventType": "OBJECT_FINALIZE",
		"notificationConfig": "projects/_/buckets/bucket1/notificationConfigs/3",
		"objectGeneration": "1495443037537696",
	}

	BaseNotificationData = `{
  "kind": "storage#object",
  "id": "bucket1/path/to/file1/1495443037537696",
  "selfLink": "https://www.googleapis.com/storage/v1/b/bucket1/o/files%2Fnode-v4.5.0-linux-x64.tar.xz",
  "name": "path/to/file1",
  "bucket": "bucket1",
  "generation": "1495443037537696",
  "metageneration": "1",
  "contentType": "binary/octet-stream",
  "timeCreated": "2017-05-22T08:50:37.518Z",
  "updated": "2017-05-22T08:50:37.518Z",
  "storageClass": "REGIONAL",
  "timeStorageClassUpdated": "2017-05-22T08:50:37.518Z",
  "size": "8320540",
  "md5Hash": "bXiRq/+p9S1mnM6EcdDGKQ==",
  "mediaLink": "https://www.googleapis.com/download/storage/v1/b/bucket1/o/files%2Fnode-v4.5.0-linux-x64.tar.xz?generation=1495443037537696&alt=media",
  "crc32c": "J8Knpg==",
  "etag": "CKCLo7iPg9QCEAE="
}`
)

func TestJobSetupWithPubSubNotification1(t *testing.T) {
	job := &Job{
		config: &CommandConfig{
			Template: []string{"cmd1", "%{download_files}", "%{uploads_dir}"},
		},
		message: &JobMessage{
			raw: &pubsub.ReceivedMessage{
				AckId: "test-ack1",
				Message: &pubsub.PubsubMessage{
					Data: BaseNotificationData,
					Attributes: BaseNotificationAttrs,
					MessageId: "test-message1",
				},
			},
		},
		workspace:     workspace,
		downloads_dir: downloads_dir,
		uploads_dir:   uploads_dir,
	}

	job.remoteDownloadFiles = job.message.DownloadFiles()
	err := job.setupDownloadFiles()
	assert.NoError(t, err)

	assert.Equal(t, map[string]string{
		url1: local1,
	}, job.downloadFileMap)

	assert.Equal(t, []interface{}{url1}, job.remoteDownloadFiles)
	assert.Equal(t, []interface{}{local1}, job.localDownloadFiles)

	err = job.build()
	assert.NoError(t, err)

	assert.Equal(t, "cmd1", job.cmd.Path)
	assert.Equal(t, []string{"cmd1", local1, uploads_dir}, job.cmd.Args)
}
<commit_msg>:shirt: go fmt<commit_after>package main

import (
	// "encoding/base64"
	// "encoding/json"
	"testing"

	"github.com/stretchr/testify/assert"

	pubsub "google.golang.org/api/pubsub/v1"
)

const (
	bucket = "bucket1"
	path1  = "path/to/file1"
	url1   = "gs://" + bucket + "/" + path1
	local1 = downloads_dir + "/" + bucket + "/" + path1
)

var (
	BaseNotificationAttrs = map[string]string{
		"objectId":           "path/to/file1",
		"payloadFormat":      "JSON_API_V1",
		"resource":           "projects/_/buckets/bucket1/objects/path/to/file1#1495443037537696",
		"bucketId":           "bucket1",
		"eventType":          "OBJECT_FINALIZE",
		"notificationConfig": "projects/_/buckets/bucket1/notificationConfigs/3",
		"objectGeneration":   "1495443037537696",
	}

	BaseNotificationData = `{
  "kind": "storage#object",
  "id": "bucket1/path/to/file1/1495443037537696",
  "selfLink": "https://www.googleapis.com/storage/v1/b/bucket1/o/files%2Fnode-v4.5.0-linux-x64.tar.xz",
  "name": "path/to/file1",
  "bucket": "bucket1",
  "generation": "1495443037537696",
  "metageneration": "1",
  "contentType": "binary/octet-stream",
  "timeCreated": "2017-05-22T08:50:37.518Z",
  "updated": "2017-05-22T08:50:37.518Z",
  "storageClass": "REGIONAL",
  "timeStorageClassUpdated": "2017-05-22T08:50:37.518Z",
  "size": "8320540",
  "md5Hash": "bXiRq/+p9S1mnM6EcdDGKQ==",
  "mediaLink": "https://www.googleapis.com/download/storage/v1/b/bucket1/o/files%2Fnode-v4.5.0-linux-x64.tar.xz?generation=1495443037537696&alt=media",
  "crc32c": "J8Knpg==",
  "etag": "CKCLo7iPg9QCEAE="
}`
)

func TestJobSetupWithPubSubNotification1(t *testing.T) {
	job := &Job{
		config: &CommandConfig{
			Template: []string{"cmd1", "%{download_files}", "%{uploads_dir}"},
		},
		message: &JobMessage{
			raw: &pubsub.ReceivedMessage{
				AckId: "test-ack1",
				Message: &pubsub.PubsubMessage{
					Data:       BaseNotificationData,
					Attributes: BaseNotificationAttrs,
					MessageId:  "test-message1",
				},
			},
		},
		workspace:     workspace,
		downloads_dir: downloads_dir,
		uploads_dir:   uploads_dir,
	}

	job.remoteDownloadFiles = job.message.DownloadFiles()
	err := job.setupDownloadFiles()
	assert.NoError(t, err)

	assert.Equal(t, map[string]string{
		url1: local1,
	}, job.downloadFileMap)

	assert.Equal(t, []interface{}{url1}, job.remoteDownloadFiles)
	assert.Equal(t, []interface{}{local1}, job.localDownloadFiles)

	err = job.build()
	assert.NoError(t, err)

	assert.Equal(t, "cmd1", job.cmd.Path)
	assert.Equal(t, []string{"cmd1", local1, uploads_dir}, job.cmd.Args)
}
<|endoftext|>


<commit_before>// Copyright 2016 Qiang Xue. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package validation

import (
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
)

type (
	// Errors represents the validation errors for a struct object. The keys are the struct field names.
	Errors map[string]error
	// SliceErrors represents the validation errors for a slice. The keys are the indices of the slice elements having errors.
	SliceErrors map[int]error
)

// Error returns the error string of SliceErrors.
func (es SliceErrors) Error() string {
	if len(es) == 0 {
		return ""
	}

	keys := []int{}
	for key := range es {
		keys = append(keys, key)
	}
	sort.Ints(keys)

	s := ""
	for i, key := range keys {
		if i > 0 {
			s += "; "
		}
		s += formatError(key, es[key])
	}
	return s + "."
}

// MarshalJSON converts the SliceErrors
// into a valid JSON.
func (es SliceErrors) MarshalJSON() ([]byte, error) {
	errs := map[string]string{}
	for key := range es {
		errs[strconv.Itoa(key)] = es[key].Error()
	}
	return json.Marshal(errs)
}

// Error returns the error string of Errors.
func (es Errors) Error() string {
	if len(es) == 0 {
		return ""
	}

	keys := []string{}
	for key := range es {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	s := ""
	for i, key := range keys {
		if i > 0 {
			s += "; "
		}
		s += formatError(key, es[key])
	}
	return s + "."
}

// MarshalJSON converts the SliceErrors
// into a valid JSON.
func (es Errors) MarshalJSON() ([]byte, error) {
	errs := map[string]string{}
	for key := range es {
		errs[key] = es[key].Error()
	}
	return json.Marshal(errs)
}

func formatError(key interface{}, err error) string {
	switch err.(type) {
	case SliceErrors, Errors:
		return fmt.Sprintf("%v: (%v)", key, err.Error())
	default:
		return fmt.Sprintf("%v: %v", key, err.Error())
	}
}
<commit_msg>Fix comments wording.<commit_after>// Copyright 2016 Qiang Xue. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package validation

import (
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
)

type (
	// Errors represents the validation errors for a struct object. The keys are the struct field names.
	Errors map[string]error
	// SliceErrors represents the validation errors for a slice. The keys are the indices of the slice elements having errors.
	SliceErrors map[int]error
)

// Error returns the error string of SliceErrors.
func (es SliceErrors) Error() string {
	if len(es) == 0 {
		return ""
	}

	keys := []int{}
	for key := range es {
		keys = append(keys, key)
	}
	sort.Ints(keys)

	s := ""
	for i, key := range keys {
		if i > 0 {
			s += "; "
		}
		s += formatError(key, es[key])
	}
	return s + "."
}

// MarshalJSON converts SliceErrors
// into a valid JSON.
func (es SliceErrors) MarshalJSON() ([]byte, error) {
	errs := map[string]string{}
	for key := range es {
		errs[strconv.Itoa(key)] = es[key].Error()
	}
	return json.Marshal(errs)
}

// Error returns the error string of Errors.
func (es Errors) Error() string {
	if len(es) == 0 {
		return ""
	}

	keys := []string{}
	for key := range es {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	s := ""
	for i, key := range keys {
		if i > 0 {
			s += "; "
		}
		s += formatError(key, es[key])
	}
	return s + "."
}

// MarshalJSON converts the Errors
// into a valid JSON.
func (es Errors) MarshalJSON() ([]byte, error) {
	errs := map[string]string{}
	for key := range es {
		errs[key] = es[key].Error()
	}
	return json.Marshal(errs)
}

func formatError(key interface{}, err error) string {
	switch err.(type) {
	case SliceErrors, Errors:
		return fmt.Sprintf("%v: (%v)", key, err.Error())
	default:
		return fmt.Sprintf("%v: %v", key, err.Error())
	}
}
<|endoftext|>


<commit_before>package glfw3

//#include "glfw/include/GLFW/glfw3.h"
//void glfwSetErrorCallbackCB();
import "C"

import (
	"fmt"
)

// ErrorCode corresponds to an error code.
type ErrorCode int

// Error codes.
const (
	NotInitialized     ErrorCode = C.GLFW_NOT_INITIALIZED     // GLFW has not been initialized.
	NoCurrentContext   ErrorCode = C.GLFW_NO_CURRENT_CONTEXT  // No context is current.
	InvalidEnum        ErrorCode = C.GLFW_INVALID_ENUM        // One of the enum parameters for the function was given an invalid enum.
	InvalidValue       ErrorCode = C.GLFW_INVALID_VALUE       // One of the parameters for the function was given an invalid value.
	OutOfMemory        ErrorCode = C.GLFW_OUT_OF_MEMORY       // A memory allocation failed.
	APIUnavailable     ErrorCode = C.GLFW_API_UNAVAILABLE     // GLFW could not find support for the requested client API on the system.
	VersionUnavailable ErrorCode = C.GLFW_VERSION_UNAVAILABLE // The requested client API version is not available.
	PlatformError      ErrorCode = C.GLFW_PLATFORM_ERROR      // A platform-specific error occurred that does not match any of the more specific categories.
	FormatUnavailable  ErrorCode = C.GLFW_FORMAT_UNAVAILABLE  // The clipboard did not contain data in the requested format.
)

// GlfwError holds error code and description.
type GLFWError struct {
	Code ErrorCode
	Desc string
}

// Note: There are many cryptic caveats to proper error handling here.
// See: https://github.com/go-gl/glfw3/pull/86

// Holds the value of the last error
var lastError = make(chan *GLFWError, 1)

//export goErrorCB
func goErrorCB(code C.int, desc *C.char) {
	err := &GLFWError{ErrorCode(code), C.GoString(desc)}
	select {
	case lastError <- err:
	default:
		fmt.Printf("GLFW: Uncaught error: %d -> %s\n", err.Code, err.Desc)
	}
}

// Error prints the error code and description in a readable format.
func (e *GLFWError) Error() string {
	return fmt.Sprintf("Error %d: %s", e.Code, e.Desc)
}

// Set the glfw callback internally
func init() {
	C.glfwSetErrorCallbackCB()
}

// flushErrors is called by Terminate before it actually calls C.glfwTerminate,
// this ensures that any uncaught errors buffered in lastError are printed
// before the program exits.
func flushErrors() {
	select {
	case err := <-lastError:
		fmt.Printf("GLFW: Uncaught error: %d -> %s\n", err.Code, err.Desc)
	default:
	}
}
<commit_msg>Flush errors upon entering the error callback.<commit_after>package glfw3

//#include "glfw/include/GLFW/glfw3.h"
//void glfwSetErrorCallbackCB();
import "C"

import (
	"fmt"
)

// ErrorCode corresponds to an error code.
type ErrorCode int

// Error codes.
const (
	NotInitialized     ErrorCode = C.GLFW_NOT_INITIALIZED     // GLFW has not been initialized.
	NoCurrentContext   ErrorCode = C.GLFW_NO_CURRENT_CONTEXT  // No context is current.
	InvalidEnum        ErrorCode = C.GLFW_INVALID_ENUM        // One of the enum parameters for the function was given an invalid enum.
	InvalidValue       ErrorCode = C.GLFW_INVALID_VALUE       // One of the parameters for the function was given an invalid value.
	OutOfMemory        ErrorCode = C.GLFW_OUT_OF_MEMORY       // A memory allocation failed.
	APIUnavailable     ErrorCode = C.GLFW_API_UNAVAILABLE     // GLFW could not find support for the requested client API on the system.
	VersionUnavailable ErrorCode = C.GLFW_VERSION_UNAVAILABLE // The requested client API version is not available.
	PlatformError      ErrorCode = C.GLFW_PLATFORM_ERROR      // A platform-specific error occurred that does not match any of the more specific categories.
	FormatUnavailable  ErrorCode = C.GLFW_FORMAT_UNAVAILABLE  // The clipboard did not contain data in the requested format.
)

// GlfwError holds error code and description.
type GLFWError struct {
	Code ErrorCode
	Desc string
}

// Note: There are many cryptic caveats to proper error handling here.
// See: https://github.com/go-gl/glfw3/pull/86

// Holds the value of the last error
var lastError = make(chan *GLFWError, 1)

//export goErrorCB
func goErrorCB(code C.int, desc *C.char) {
	flushErrors()
	err := &GLFWError{ErrorCode(code), C.GoString(desc)}
	select {
	case lastError <- err:
	default:
		fmt.Printf("GLFW: Uncaught error: %d -> %s\n", err.Code, err.Desc)
	}
}

// Error prints the error code and description in a readable format.
func (e *GLFWError) Error() string {
	return fmt.Sprintf("Error %d: %s", e.Code, e.Desc)
}

// Set the glfw callback internally
func init() {
	C.glfwSetErrorCallbackCB()
}

// flushErrors is called by Terminate before it actually calls C.glfwTerminate,
// this ensures that any uncaught errors buffered in lastError are printed
// before the program exits.
func flushErrors() {
	select {
	case err := <-lastError:
		fmt.Printf("GLFW: Uncaught error: %d -> %s\n", err.Code, err.Desc)
	default:
	}
}
<|endoftext|>


<commit_before>package gotracer

import (
	"log"
	"runtime"
	"time"
)

const layout = "Jan 2, 2006 at 3:04pm (MST)"

type Tracer struct {
	Dummy         bool
	EmailHost     string
	EmailPort     string
	EmailUsername string
	EmailPassword string
	EmailSender   string
	EmailFrom     string
	ErrorTo       string
}

func (self Tracer) Notify(extra ...func() string) {
	err := recover()
	if err != nil {
		const size = 4096
		var exc_message string

		buf := make([]byte, size)
		buf = buf[:runtime.Stack(buf, false)]
		buffer := string(buf)

		switch err.(type) {
		case string:
			_err, ok := err.(string)
			if ok == true {
				exc_message = _err
			}
		case interface{}:
			_err, ok := err.(error)
			if ok == true {
				exc_message = _err.Error()
			}
		}

		extras := ""

		for i := range extra {
			extras += extra[i]()
			extras += " "
		}

		self.sendException(&ErrorStack{
			Subject:   exc_message,
			Traceback: buffer,
			Extra:     extras,
			Timestamp: time.Now().Format(layout),
		})
	}
}

func (self Tracer) sendException(stack *ErrorStack) {
	if self.Dummy {
		log.Println(stack.Subject)
		log.Println(stack.Traceback)
	} else {
		log.Println("Sending Exception: " + stack.Subject)
		connection := MakeConn(&self)
		connection.SenderName += " Exception"

		connection.SendEmail(Message{
			self.EmailFrom,
			[]string{self.ErrorTo},
			stack.Subject,
			ErrorTemplate(stack),
		})
	}
}

type ErrorStack struct {
	Subject   string
	Extra     string
	Traceback string
	Timestamp string
}
<commit_msg>Extras receive an extra reason<commit_after>package gotracer

import (
	"log"
	"runtime"
	"time"
)

const layout = "Jan 2, 2006 at 3:04pm (MST)"

type Tracer struct {
	Dummy         bool
	EmailHost     string
	EmailPort     string
	EmailUsername string
	EmailPassword string
	EmailSender   string
	EmailFrom     string
	ErrorTo       string
}

func (self Tracer) Notify(extra ...func(reason string) string) {
	err := recover()
	if err != nil {
		const size = 4096
		var exc_message string

		buf := make([]byte, size)
		buf = buf[:runtime.Stack(buf, false)]
		buffer := string(buf)

		switch err.(type) {
		case string:
			_err, ok := err.(string)
			if ok == true {
				exc_message = _err
			}
		case interface{}:
			_err, ok := err.(error)
			if ok == true {
				exc_message = _err.Error()
			}
		}

		extras := ""

		for i := range extra {
			extras += extra[i](exc_message)
			extras += " "
		}

		self.sendException(&ErrorStack{
			Subject:   exc_message,
			Traceback: buffer,
			Extra:     extras,
			Timestamp: time.Now().Format(layout),
		})
	}
}

func (self Tracer) sendException(stack *ErrorStack) {
	if self.Dummy {
		log.Println(stack.Subject)
		log.Println(stack.Traceback)
	} else {
		log.Println("Sending Exception: " + stack.Subject)
		connection := MakeConn(&self)
		connection.SenderName += " Exception"

		connection.SendEmail(Message{
			self.EmailFrom,
			[]string{self.ErrorTo},
			stack.Subject,
			ErrorTemplate(stack),
		})
	}
}

type ErrorStack struct {
	Subject   string
	Extra     string
	Traceback string
	Timestamp string
}
<|endoftext|>


<commit_before>package validate

import (
	"errors"
	"fmt"
	"github.com/graniticio/granitic/ioc"
	"github.com/graniticio/granitic/logging"
	"github.com/graniticio/granitic/types"
	"regexp"
	"strconv"
	"strings"
)

type ValidationRuleType uint

type parseAndBuild func(string, []string) (Validator, error)

const (
	UnknownRuleType = iota
	StringRule
	ObjectRule
	IntRule
	BoolRule
	FloatRule
	SliceRule
)

const commandSep = ":"
const escapedCommandSep = "::"
const escapedCommandReplace = "||ESC||"
const RuleRefCode = "RULE"

const commonOpRequired = "REQ"
const commonOpStopAll = "STOPALL"
const commonOpIn = "IN"
const commonOpBreak = "BREAK"
const commonOpExt = "EXT"
const commonOpMex = "MEX"
const commonOpLen = "LEN"

const lengthPattern = "^(\\d*)-(\\d*)$"

type SubjectContext struct {
	Subject interface{}
}

type ValidationContext struct {
	Subject        interface{}
	KnownSetFields types.StringSet
	OverrideField  string
	DirectSubject  bool
}

type ValidationResult struct {
	ErrorCodes map[string][]string
	Unset      bool
}

func (vr *ValidationResult) AddForField(field string, codes []string) {

	if codes == nil || len(codes) == 0 {
		return
	}

	existing := vr.ErrorCodes[field]

	if existing == nil {
		vr.ErrorCodes[field] = codes
	} else {
		vr.ErrorCodes[field] = append(existing, codes...)
	}
}

func (vr *ValidationResult) ErrorCount() int {
	c := 0

	for _, v := range vr.ErrorCodes {

		c += len(v)

	}

	return c
}

func NewValidationResult() *ValidationResult {
	vr := new(ValidationResult)
	vr.ErrorCodes = make(map[string][]string)

	return vr
}

func NewPopulatedValidationResult(field string, codes []string) *ValidationResult {
	vr := NewValidationResult()
	vr.AddForField(field, codes)

	return vr
}

type Validator interface {
	Validate(vc *ValidationContext) (result *ValidationResult, unexpected error)
	StopAllOnFail() bool
	CodesInUse() types.StringSet
	DependsOnFields() types.StringSet
	IsSet(string, interface{}) (bool, error)
}

type validatorLink struct {
	validator Validator
	field     string
}

type UnparsedRuleManager struct {
	Rules map[string][]string
}

func (rm *UnparsedRuleManager) Exists(ref string) bool {
	return rm.Rules[ref] != nil
}

func (rm *UnparsedRuleManager) Rule(ref string) []string {
	return rm.Rules[ref]
}

type FieldErrors struct {
	Field      string
	ErrorCodes []string
}

type RuleValidator struct {
	jsonConfig             interface{}
	RuleManager            *UnparsedRuleManager
	stringBuilder          *StringValidatorBuilder
	objectValidatorBuilder *ObjectValidatorBuilder
	boolValidatorBuilder   *BoolValidatorBuilder
	intValidatorBuilder    *IntValidatorBuilder
	floatValidatorBuilder  *FloatValidatorBuilder
	sliceValidatorBuilder  *SliceValidatorBuilder
	DefaultErrorCode       string
	Rules                  [][]string
	ComponentFinder        ioc.ComponentByNameFinder
	validatorChain         []*validatorLink
	componentName          string
	codesInUse             types.StringSet
	Log                    logging.Logger
}

func (ov *RuleValidator) Container(container *ioc.ComponentContainer) {
	ov.ComponentFinder = container
}

func (ov *RuleValidator) ComponentName() string {
	return ov.componentName
}

func (ov *RuleValidator) SetComponentName(name string) {
	ov.componentName = name
}

func (ov *RuleValidator) ErrorCodesInUse() (codes types.StringSet, sourceName string) {
	return ov.codesInUse, ov.componentName
}

func (ov *RuleValidator) Validate(subject *SubjectContext) ([]*FieldErrors, error) {

	log := ov.Log

	fieldErrors := make([]*FieldErrors, 0)
	fieldsWithProblems := types.NewOrderedStringSet([]string{})
	unsetFields := types.NewOrderedStringSet([]string{})
	setFields := types.NewOrderedStringSet([]string{})

	for _, vl := range ov.validatorChain {
		f := vl.field
		v := vl.validator
		log.LogDebugf("Checking field %s set", f)

		if !ov.parentsOkay(v, fieldsWithProblems, unsetFields) {
			log.LogDebugf("Skipping set check on field %s as one or more parent objects invalid", f)
			continue
		}

		set, err := v.IsSet(f, subject.Subject)

		if err != nil {
			return nil, err
		}

		if set {
			setFields.Add(f)
		} else {
			unsetFields.Add(f)
		}

	}

	for _, vl := range ov.validatorChain {

		f := vl.field

		log.LogDebugf("Validating field %s", f)

		vc := new(ValidationContext)
		vc.Subject = subject.Subject
		vc.KnownSetFields = setFields

		v := vl.validator

		if !ov.parentsOkay(v, fieldsWithProblems, unsetFields) {
			log.LogDebugf("Skipping field %s as one or more parent objects invalid", f)
			continue
		}

		r, err := vl.validator.Validate(vc)

		if err != nil {
			return nil, err
		}

		ec := r.ErrorCodes

		if r.Unset {
			log.LogDebugf("%s is unset", f)
			unsetFields.Add(f)
		}

		l := r.ErrorCount()

		if ec != nil && l > 0 {

			for k, v := range ec {

				fieldsWithProblems.Add(k)
				log.LogDebugf("%s has %d errors", k, l)

				fe := new(FieldErrors)
				fe.Field = k
				fe.ErrorCodes = v

				fieldErrors = append(fieldErrors, fe)

				if vl.validator.StopAllOnFail() {
					break
				}
			}

		}

	}

	return fieldErrors, nil

}

func (ov *RuleValidator) parentsOkay(v Validator, fieldsWithProblems types.StringSet, unsetFields types.StringSet) bool {

	log := ov.Log

	d := v.DependsOnFields()

	if d == nil || d.Size() == 0 {
		return true
	}

	for _, f := range d.Contents() {

		log.LogTracef("Depends on %s", f)

		if fieldsWithProblems.Contains(f) || unsetFields.Contains(f) {

			log.LogTracef("%s is not okay", f)
			return false
		}

	}

	return true
}

func (ov *RuleValidator) StartComponent() error {

	if ov.Rules == nil {
		return errors.New("No Rules specified for validator.")
	}

	ov.codesInUse = types.NewUnorderedStringSet([]string{})

	if ov.DefaultErrorCode != "" {
		ov.codesInUse.Add(ov.DefaultErrorCode)
	}

	ov.stringBuilder = NewStringValidatorBuilder(ov.DefaultErrorCode)
	ov.stringBuilder.componentFinder = ov.ComponentFinder

	ov.objectValidatorBuilder = NewObjectValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder)
	ov.boolValidatorBuilder = NewBoolValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder)
	ov.validatorChain = make([]*validatorLink, 0)

	ov.intValidatorBuilder = NewIntValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder)
	ov.floatValidatorBuilder = NewFloatValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder)

	ov.sliceValidatorBuilder = NewSliceValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder, ov)

	return ov.parseRules()

}

func (ov *RuleValidator) parseRules() error {

	var err error

	for _, rule := range ov.Rules {

		var ruleToParse []string

		if len(rule) < 2 {
			m := fmt.Sprintf("Rule is invalid (must have at least an identifier and a type). Supplied rule is: %q", rule)
			return errors.New(m)
		}

		field := rule[0]
		ruleType := rule[1]

		if ov.isRuleRef(ruleType) {
			ruleToParse, err = ov.findRule(field, ruleType)

			if err != nil {
				break
			}

		} else {
			ruleToParse = rule[1:]
		}

		v, err := ov.parseRule(field, ruleToParse)

		if err == nil {
			ov.addValidator(field, v)
		}

		if err != nil {
			break
		}

	}

	return err
}

func (ov *RuleValidator) addValidator(field string, v Validator) {

	vl := new(validatorLink)
	vl.field = field
	vl.validator = v

	ov.validatorChain = append(ov.validatorChain, vl)

	c := v.CodesInUse()

	if c != nil {
		ov.codesInUse.AddAll(c)
	}

}

func (ov *RuleValidator) isRuleRef(op string) bool {

	s := strings.SplitN(op, commandSep, -1)

	return len(s) == 2 && s[0] == RuleRefCode

}

func (ov *RuleValidator) findRule(field, op string) ([]string, error) {

	ref := strings.SplitN(op, commandSep, -1)[1]

	rf := ov.RuleManager

	if rf == nil {
		m := fmt.Sprintf("Field %s has its rule specified as a reference to an external rule %s, but RuleManager is not set.\n", field, ref)
		return nil, errors.New(m)

	}

	if !rf.Exists(ref) {
		m := fmt.Sprintf("Field %s has its rule specified as a reference to an external rule %s, but no rule with that reference exists.\n", field, ref)
		return nil, errors.New(m)
	}

	return rf.Rule(ref), nil
}

func (ov *RuleValidator) parseRule(field string, rule []string) (Validator, error) {

	rt, err := ov.extractType(field, rule)

	if err != nil {
		return nil, err
	}

	var v Validator

	switch rt {
	case StringRule:
		v, err = ov.parse(field, rule, ov.stringBuilder.parseRule)
	case ObjectRule:
		v, err = ov.parse(field, rule, ov.objectValidatorBuilder.parseRule)
	case BoolRule:
		v, err = ov.parse(field, rule, ov.boolValidatorBuilder.parseRule)
	case IntRule:
		v, err = ov.parse(field, rule, ov.intValidatorBuilder.parseRule)
	case FloatRule:
		v, err = ov.parse(field, rule, ov.floatValidatorBuilder.parseRule)
	case SliceRule:
		v, err = ov.parse(field, rule, ov.floatValidatorBuilder.parseRule)

	default:
		m := fmt.Sprintf("Unsupported rule type for field %s\n", field)
		return nil, errors.New(m)
	}

	return v, err

}

func (ov *RuleValidator) parse(field string, rule []string, pf parseAndBuild) (Validator, error) {
	v, err := pf(field, rule)

	if err != nil {
		return nil, err
	} else {
		return v, nil
	}
}

func (ov *RuleValidator) extractType(field string, rule []string) (ValidationRuleType, error) {

	for _, v := range rule {

		f := DecomposeOperation(v)

		switch f[0] {
		case StringRuleCode:
			return StringRule, nil
		case ObjectRuleCode:
			return ObjectRule, nil
		case BoolRuleCode:
			return BoolRule, nil
		case IntRuleCode:
			return IntRule, nil
		case FloatRuleCode:
			return FloatRule, nil
		case SliceRuleCode:
			return SliceRule, nil
		}
	}

	m := fmt.Sprintf("Unable to determine the type of rule from the rule definition for field %s: %v/n", field, rule)

	return UnknownRuleType, errors.New(m)
}

func IsTypeIndicator(vType, op string) bool {

	return DecomposeOperation(op)[0] == vType

}

func DetermineDefaultErrorCode(vt string, rule []string, defaultCode string) string {
	for _, v := range rule {

		f := DecomposeOperation(v)

		if f[0] == vt {
			if len(f) > 1 {
				//Error code must be second component of type
				return f[1]
			}
		}

	}

	return defaultCode
}

func DecomposeOperation(r string) []string {

	removeEscaped := strings.Replace(r, escapedCommandSep, escapedCommandReplace, -1)
	split := strings.SplitN(removeEscaped, commandSep, -1)

	decomposed := make([]string, len(split))

	for i, v := range split {
		decomposed[i] = strings.Replace(v, escapedCommandReplace, commandSep, -1)
	}

	return decomposed

}

func determinePathFields(path string) types.StringSet {

	set := types.NewOrderedStringSet([]string{})

	split := strings.SplitN(path, ".", -1)

	l := len(split)

	if l > 1 {

		for i := 1; i < l; i++ {

			set.Add(strings.Join(split[0:i], "."))
		}

	}

	return set
}

func validateExternalOperation(cf ioc.ComponentByNameFinder, field string, ops []string) (int, *ioc.Component, error) {

	if cf == nil {
		m := fmt.Sprintf("Field %s relies on an external component to validate, but no ioc.ComponentByNameFinder is available.", field)
		return 0, nil, errors.New(m)
	}

	pCount, err := paramCount(ops, "External", field, 2, 3)

	if err != nil {
		return pCount, nil, err
	}

	ref := ops[1]
	component := cf.ComponentByName(ref)

	if component == nil {
		m := fmt.Sprintf("No external component named %s available to validate field %s", ref, field)
		return 0, nil, errors.New(m)
	}

	return pCount, component, nil
}

func checkMExFields(mf types.StringSet, vc *ValidationContext, ec types.StringSet, code string) {

	if vc.KnownSetFields == nil || vc.KnownSetFields.Size() == 0 {
		return
	}

	for _, s := range mf.Contents() {

		if vc.KnownSetFields.Contains(s) {
			ec.Add(code)
			break
		}
	}

}

func extractVargs(ops []string, l int) []string {

	if len(ops) == l {
		return []string{ops[l-1]}
	} else {
		return []string{}
	}

}

func extractLengthParams(field string, vals string, pattern *regexp.Regexp) (min, max int, err error) {

	min = NoLimit
	max = NoLimit

	if !pattern.MatchString(vals) {
		m := fmt.Sprintf("Length parameters for field %s are invalid. Values provided: %s", field, vals)
		return min, max, errors.New(m)
	}

	groups := pattern.FindStringSubmatch(vals)

	if groups[1] != "" {
		min, _ = strconv.Atoi(groups[1])
	}

	if groups[2] != "" {
		max, _ = strconv.Atoi(groups[2])
	}

	return min, max, nil
}
<commit_msg>Slice element validation<commit_after>package validate

import (
	"errors"
	"fmt"
	"github.com/graniticio/granitic/ioc"
	"github.com/graniticio/granitic/logging"
	"github.com/graniticio/granitic/types"
	"regexp"
	"strconv"
	"strings"
)

type ValidationRuleType uint

type parseAndBuild func(string, []string) (Validator, error)

const (
	UnknownRuleType = iota
	StringRule
	ObjectRule
	IntRule
	BoolRule
	FloatRule
	SliceRule
)

const commandSep = ":"
const escapedCommandSep = "::"
const escapedCommandReplace = "||ESC||"
const RuleRefCode = "RULE"

const commonOpRequired = "REQ"
const commonOpStopAll = "STOPALL"
const commonOpIn = "IN"
const commonOpBreak = "BREAK"
const commonOpExt = "EXT"
const commonOpMex = "MEX"
const commonOpLen = "LEN"

const lengthPattern = "^(\\d*)-(\\d*)$"

type SubjectContext struct {
	Subject interface{}
}

type ValidationContext struct {
	Subject        interface{}
	KnownSetFields types.StringSet
	OverrideField  string
	DirectSubject  bool
}

type ValidationResult struct {
	ErrorCodes map[string][]string
	Unset      bool
}

func (vr *ValidationResult) AddForField(field string, codes []string) {

	if codes == nil || len(codes) == 0 {
		return
	}

	existing := vr.ErrorCodes[field]

	if existing == nil {
		vr.ErrorCodes[field] = codes
	} else {
		vr.ErrorCodes[field] = append(existing, codes...)
	}
}

func (vr *ValidationResult) ErrorCount() int {
	c := 0

	for _, v := range vr.ErrorCodes {

		c += len(v)

	}

	return c
}

func NewValidationResult() *ValidationResult {
	vr := new(ValidationResult)
	vr.ErrorCodes = make(map[string][]string)

	return vr
}

func NewPopulatedValidationResult(field string, codes []string) *ValidationResult {
	vr := NewValidationResult()
	vr.AddForField(field, codes)

	return vr
}

type Validator interface {
	Validate(vc *ValidationContext) (result *ValidationResult, unexpected error)
	StopAllOnFail() bool
	CodesInUse() types.StringSet
	DependsOnFields() types.StringSet
	IsSet(string, interface{}) (bool, error)
}

type validatorLink struct {
	validator Validator
	field     string
}

type UnparsedRuleManager struct {
	Rules map[string][]string
}

func (rm *UnparsedRuleManager) Exists(ref string) bool {
	return rm.Rules[ref] != nil
}

func (rm *UnparsedRuleManager) Rule(ref string) []string {
	return rm.Rules[ref]
}

type FieldErrors struct {
	Field      string
	ErrorCodes []string
}

type RuleValidator struct {
	jsonConfig             interface{}
	RuleManager            *UnparsedRuleManager
	stringBuilder          *StringValidatorBuilder
	objectValidatorBuilder *ObjectValidatorBuilder
	boolValidatorBuilder   *BoolValidatorBuilder
	intValidatorBuilder    *IntValidatorBuilder
	floatValidatorBuilder  *FloatValidatorBuilder
	sliceValidatorBuilder  *SliceValidatorBuilder
	DefaultErrorCode       string
	Rules                  [][]string
	ComponentFinder        ioc.ComponentByNameFinder
	validatorChain         []*validatorLink
	componentName          string
	codesInUse             types.StringSet
	Log                    logging.Logger
}

func (ov *RuleValidator) Container(container *ioc.ComponentContainer) {
	ov.ComponentFinder = container
}

func (ov *RuleValidator) ComponentName() string {
	return ov.componentName
}

func (ov *RuleValidator) SetComponentName(name string) {
	ov.componentName = name
}

func (ov *RuleValidator) ErrorCodesInUse() (codes types.StringSet, sourceName string) {
	return ov.codesInUse, ov.componentName
}

func (ov *RuleValidator) Validate(subject *SubjectContext) ([]*FieldErrors, error) {

	log := ov.Log

	fieldErrors := make([]*FieldErrors, 0)
	fieldsWithProblems := types.NewOrderedStringSet([]string{})
	unsetFields := types.NewOrderedStringSet([]string{})
	setFields := types.NewOrderedStringSet([]string{})

	for _, vl := range ov.validatorChain {
		f := vl.field
		v := vl.validator
		log.LogDebugf("Checking field %s set", f)

		if !ov.parentsOkay(v, fieldsWithProblems, unsetFields) {
			log.LogDebugf("Skipping set check on field %s as one or more parent objects invalid", f)
			continue
		}

		set, err := v.IsSet(f, subject.Subject)

		if err != nil {
			return nil, err
		}

		if set {
			setFields.Add(f)
		} else {
			unsetFields.Add(f)
		}

	}

	for _, vl := range ov.validatorChain {

		f := vl.field

		log.LogDebugf("Validating field %s", f)

		vc := new(ValidationContext)
		vc.Subject = subject.Subject
		vc.KnownSetFields = setFields

		v := vl.validator

		if !ov.parentsOkay(v, fieldsWithProblems, unsetFields) {
			log.LogDebugf("Skipping field %s as one or more parent objects invalid", f)
			continue
		}

		r, err := vl.validator.Validate(vc)

		if err != nil {
			return nil, err
		}

		ec := r.ErrorCodes

		if r.Unset {
			log.LogDebugf("%s is unset", f)
			unsetFields.Add(f)
		}

		l := r.ErrorCount()

		if ec != nil && l > 0 {

			for k, v := range ec {

				fieldsWithProblems.Add(k)
				log.LogDebugf("%s has %d errors", k, l)

				fe := new(FieldErrors)
				fe.Field = k
				fe.ErrorCodes = v

				fieldErrors = append(fieldErrors, fe)

				if vl.validator.StopAllOnFail() {
					log.LogDebugf("Sopping all after problem found with %s", f)
					break
				}
			}

		}

	}

	return fieldErrors, nil

}

func (ov *RuleValidator) parentsOkay(v Validator, fieldsWithProblems types.StringSet, unsetFields types.StringSet) bool {

	log := ov.Log

	d := v.DependsOnFields()

	if d == nil || d.Size() == 0 {
		return true
	}

	for _, f := range d.Contents() {

		log.LogTracef("Depends on %s", f)

		if fieldsWithProblems.Contains(f) || unsetFields.Contains(f) {

			log.LogTracef("%s is not okay", f)
			return false
		}

	}

	return true
}

func (ov *RuleValidator) StartComponent() error {

	if ov.Rules == nil {
		return errors.New("No Rules specified for validator.")
	}

	ov.codesInUse = types.NewUnorderedStringSet([]string{})

	if ov.DefaultErrorCode != "" {
		ov.codesInUse.Add(ov.DefaultErrorCode)
	}

	ov.stringBuilder = NewStringValidatorBuilder(ov.DefaultErrorCode)
	ov.stringBuilder.componentFinder = ov.ComponentFinder

	ov.objectValidatorBuilder = NewObjectValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder)
	ov.boolValidatorBuilder = NewBoolValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder)
	ov.validatorChain = make([]*validatorLink, 0)

	ov.intValidatorBuilder = NewIntValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder)
	ov.floatValidatorBuilder = NewFloatValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder)

	ov.sliceValidatorBuilder = NewSliceValidatorBuilder(ov.DefaultErrorCode, ov.ComponentFinder, ov)

	return ov.parseRules()

}

func (ov *RuleValidator) parseRules() error {

	var err error

	for _, rule := range ov.Rules {

		var ruleToParse []string

		if len(rule) < 2 {
			m := fmt.Sprintf("Rule is invalid (must have at least an identifier and a type). Supplied rule is: %q", rule)
			return errors.New(m)
		}

		field := rule[0]
		ruleType := rule[1]

		if ov.isRuleRef(ruleType) {
			ruleToParse, err = ov.findRule(field, ruleType)

			if err != nil {
				break
			}

		} else {
			ruleToParse = rule[1:]
		}

		v, err := ov.parseRule(field, ruleToParse)

		if err == nil {
			ov.addValidator(field, v)
		}

		if err != nil {
			return err
		}

	}

	return err
}

func (ov *RuleValidator) addValidator(field string, v Validator) {

	vl := new(validatorLink)
	vl.field = field
	vl.validator = v

	ov.validatorChain = append(ov.validatorChain, vl)

	c := v.CodesInUse()

	if c != nil {
		ov.codesInUse.AddAll(c)
	}

}

func (ov *RuleValidator) isRuleRef(op string) bool {

	s := strings.SplitN(op, commandSep, -1)

	return len(s) == 2 && s[0] == RuleRefCode

}

func (ov *RuleValidator) findRule(field, op string) ([]string, error) {

	ref := strings.SplitN(op, commandSep, -1)[1]

	rf := ov.RuleManager

	if rf == nil {
		m := fmt.Sprintf("Field %s has its rule specified as a reference to an external rule %s, but RuleManager is not set.", field, ref)
		return nil, errors.New(m)

	}

	if !rf.Exists(ref) {
		m := fmt.Sprintf("Field %s has its rule specified as a reference to an external rule %s, but no rule with that reference exists.", field, ref)
		return nil, errors.New(m)
	}

	return rf.Rule(ref), nil
}

func (ov *RuleValidator) parseRule(field string, rule []string) (Validator, error) {

	rt, err := ov.extractType(field, rule)

	if err != nil {
		return nil, err
	}

	var v Validator

	switch rt {
	case StringRule:
		v, err = ov.parse(field, rule, ov.stringBuilder.parseRule)
	case ObjectRule:
		v, err = ov.parse(field, rule, ov.objectValidatorBuilder.parseRule)
	case BoolRule:
		v, err = ov.parse(field, rule, ov.boolValidatorBuilder.parseRule)
	case IntRule:
		v, err = ov.parse(field, rule, ov.intValidatorBuilder.parseRule)
	case FloatRule:
		v, err = ov.parse(field, rule, ov.floatValidatorBuilder.parseRule)
	case SliceRule:
		v, err = ov.parse(field, rule, ov.sliceValidatorBuilder.parseRule)

	default:
		m := fmt.Sprintf("Unsupported rule type for field %s\n", field)
		return nil, errors.New(m)
	}

	return v, err

}

func (ov *RuleValidator) parse(field string, rule []string, pf parseAndBuild) (Validator, error) {
	v, err := pf(field, rule)

	if err != nil {
		return nil, err
	} else {
		return v, nil
	}
}

func (ov *RuleValidator) extractType(field string, rule []string) (ValidationRuleType, error) {

	for _, v := range rule {

		f := DecomposeOperation(v)

		switch f[0] {
		case StringRuleCode:
			return StringRule, nil
		case ObjectRuleCode:
			return ObjectRule, nil
		case BoolRuleCode:
			return BoolRule, nil
		case IntRuleCode:
			return IntRule, nil
		case FloatRuleCode:
			return FloatRule, nil
		case SliceRuleCode:
			return SliceRule, nil
		}
	}

	m := fmt.Sprintf("Unable to determine the type of rule from the rule definition for field %s: %v", field, rule)

	return UnknownRuleType, errors.New(m)
}

func IsTypeIndicator(vType, op string) bool {

	return DecomposeOperation(op)[0] == vType

}

func DetermineDefaultErrorCode(vt string, rule []string, defaultCode string) string {
	for _, v := range rule {

		f := DecomposeOperation(v)

		if f[0] == vt {
			if len(f) > 1 {
				//Error code must be second component of type
				return f[1]
			}
		}

	}

	return defaultCode
}

func DecomposeOperation(r string) []string {

	removeEscaped := strings.Replace(r, escapedCommandSep, escapedCommandReplace, -1)
	split := strings.SplitN(removeEscaped, commandSep, -1)

	decomposed := make([]string, len(split))

	for i, v := range split {
		decomposed[i] = strings.Replace(v, escapedCommandReplace, commandSep, -1)
	}

	return decomposed

}

func determinePathFields(path string) types.StringSet {

	set := types.NewOrderedStringSet([]string{})

	split := strings.SplitN(path, ".", -1)

	l := len(split)

	if l > 1 {

		for i := 1; i < l; i++ {

			set.Add(strings.Join(split[0:i], "."))
		}

	}

	return set
}

func validateExternalOperation(cf ioc.ComponentByNameFinder, field string, ops []string) (int, *ioc.Component, error) {

	if cf == nil {
		m := fmt.Sprintf("Field %s relies on an external component to validate, but no ioc.ComponentByNameFinder is available.", field)
		return 0, nil, errors.New(m)
	}

	pCount, err := paramCount(ops, "External", field, 2, 3)

	if err != nil {
		return pCount, nil, err
	}

	ref := ops[1]
	component := cf.ComponentByName(ref)

	if component == nil {
		m := fmt.Sprintf("No external component named %s available to validate field %s", ref, field)
		return 0, nil, errors.New(m)
	}

	return pCount, component, nil
}

func checkMExFields(mf types.StringSet, vc *ValidationContext, ec types.StringSet, code string) {

	if vc.KnownSetFields == nil || vc.KnownSetFields.Size() == 0 {
		return
	}

	for _, s := range mf.Contents() {

		if vc.KnownSetFields.Contains(s) {
			ec.Add(code)
			break
		}
	}

}

func extractVargs(ops []string, l int) []string {

	if len(ops) == l {
		return []string{ops[l-1]}
	} else {
		return []string{}
	}

}

func extractLengthParams(field string, vals string, pattern *regexp.Regexp) (min, max int, err error) {

	min = NoLimit
	max = NoLimit

	if !pattern.MatchString(vals) {
		m := fmt.Sprintf("Length parameters for field %s are invalid. Values provided: %s", field, vals)
		return min, max, errors.New(m)
	}

	groups := pattern.FindStringSubmatch(vals)

	if groups[1] != "" {
		min, _ = strconv.Atoi(groups[1])
	}

	if groups[2] != "" {
		max, _ = strconv.Atoi(groups[2])
	}

	return min, max, nil
}
<|endoftext|>