<commit_before>package eth

import (
	"fmt"
	"math/big"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/errs"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/rlp"
)

const (
	ProtocolVersion    = 58
	NetworkId          = 0
	ProtocolLength     = uint64(8)
	ProtocolMaxMsgSize = 10 * 1024 * 1024
	maxHashes          = 256
	maxBlocks          = 64
)

// eth protocol message codes
const (
	StatusMsg = iota
	GetTxMsg  // unused
	TxMsg
	GetBlockHashesMsg
	BlockHashesMsg
	GetBlocksMsg
	BlocksMsg
	NewBlockMsg
)

const (
	ErrMsgTooLarge = iota
	ErrDecode
	ErrInvalidMsgCode
	ErrProtocolVersionMismatch
	ErrNetworkIdMismatch
	ErrGenesisBlockMismatch
	ErrNoStatusMsg
	ErrExtraStatusMsg
	ErrSuspendedPeer
)

var errorToString = map[int]string{
	ErrMsgTooLarge:             "Message too long",
	ErrDecode:                  "Invalid message",
	ErrInvalidMsgCode:          "Invalid message code",
	ErrProtocolVersionMismatch: "Protocol version mismatch",
	ErrNetworkIdMismatch:       "NetworkId mismatch",
	ErrGenesisBlockMismatch:    "Genesis block mismatch",
	ErrNoStatusMsg:             "No status message",
	ErrExtraStatusMsg:          "Extra status message",
	ErrSuspendedPeer:           "Suspended peer",
}

// ethProtocol represents the ethereum wire protocol
// instance is running on each peer
type ethProtocol struct {
	txPool          txPool
	chainManager    chainManager
	blockPool       blockPool
	peer            *p2p.Peer
	id              string
	rw              p2p.MsgReadWriter
	errors          *errs.Errors
	protocolVersion int
	networkId       int
}

// backend is the interface the ethereum protocol backend should implement
// used as an argument to EthProtocol
type txPool interface {
	AddTransactions([]*types.Transaction)
	GetTransactions() types.Transactions
}

type chainManager interface {
	GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash)
	GetBlock(hash common.Hash) (block *types.Block)
	Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash)
}

type blockPool interface {
	AddBlockHashes(next func() (common.Hash, bool), peerId string)
	AddBlock(block *types.Block, peerId string)
	AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool)
	RemovePeer(peerId string)
}

// message structs used for RLP serialization
type newBlockMsgData struct {
	Block *types.Block
	TD    *big.Int
}

type getBlockHashesMsgData struct {
	Hash   common.Hash
	Amount uint64
}

type statusMsgData struct {
	ProtocolVersion uint32
	NetworkId       uint32
	TD              *big.Int
	CurrentBlock    common.Hash
	GenesisBlock    common.Hash
}

// main entrypoint, wrappers starting a server running the eth protocol
// use this constructor to attach the protocol ("class") to server caps
// the Dev p2p layer then runs the protocol instance on each peer
func EthProtocol(protocolVersion, networkId int, txPool txPool, chainManager chainManager, blockPool blockPool) p2p.Protocol {
	return p2p.Protocol{
		Name:    "eth",
		Version: uint(protocolVersion),
		Length:  ProtocolLength,
		Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
			return runEthProtocol(protocolVersion, networkId, txPool, chainManager, blockPool, peer, rw)
		},
	}
}

// the main loop that handles incoming messages
// note RemovePeer in the post-disconnect hook
func runEthProtocol(protocolVersion, networkId int, txPool txPool, chainManager chainManager, blockPool blockPool, peer *p2p.Peer, rw p2p.MsgReadWriter) (err error) {
	id := peer.ID()
	self := &ethProtocol{
		txPool:          txPool,
		chainManager:    chainManager,
		blockPool:       blockPool,
		rw:              rw,
		peer:            peer,
		protocolVersion: protocolVersion,
		networkId:       networkId,
		errors: &errs.Errors{
			Package: "ETH",
			Errors:  errorToString,
		},
		id: fmt.Sprintf("%x", id[:8]),
	}

	// handshake.
	if err := self.handleStatus(); err != nil {
		return err
	}
	defer self.blockPool.RemovePeer(self.id)

	// propagate existing transactions. new transactions appearing
	// after this will be sent via broadcasts.
	if err := p2p.Send(rw, TxMsg, txPool.GetTransactions()); err != nil {
		return err
	}

	// main loop. handle incoming messages.
	for {
		if err := self.handle(); err != nil {
			return err
		}
	}
}

func (self *ethProtocol) handle() error {
	msg, err := self.rw.ReadMsg()
	if err != nil {
		return err
	}
	if msg.Size > ProtocolMaxMsgSize {
		return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
	}
	// make sure that the payload has been fully consumed
	defer msg.Discard()

	switch msg.Code {
	case GetTxMsg: // ignore
	case StatusMsg:
		return self.protoError(ErrExtraStatusMsg, "")

	case TxMsg:
		// TODO: rework using lazy RLP stream
		var txs []*types.Transaction
		if err := msg.Decode(&txs); err != nil {
			return self.protoError(ErrDecode, "msg %v: %v", msg, err)
		}
		for _, tx := range txs {
			jsonlogger.LogJson(&logger.EthTxReceived{
				TxHash:   tx.Hash().Hex(),
				RemoteId: self.peer.ID().String(),
			})
		}
		self.txPool.AddTransactions(txs)

	case GetBlockHashesMsg:
		var request getBlockHashesMsgData
		if err := msg.Decode(&request); err != nil {
			return self.protoError(ErrDecode, "->msg %v: %v", msg, err)
		}

		if request.Amount > maxHashes {
			request.Amount = maxHashes
		}
		hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount)
		return p2p.Send(self.rw, BlockHashesMsg, hashes)

	case BlockHashesMsg:
		msgStream := rlp.NewStream(msg.Payload)
		if _, err := msgStream.List(); err != nil {
			return err
		}

		var i int
		iter := func() (hash common.Hash, ok bool) {
			var h common.Hash
			err := msgStream.Decode(&h)
			if err == rlp.EOL {
				return common.Hash{}, false
			} else if err != nil {
				self.protoError(ErrDecode, "msg %v: after %v hashes : %v", msg, i, err)
				return common.Hash{}, false
			}

			i++
			return hash, true
		}
		self.blockPool.AddBlockHashes(iter, self.id)

	case GetBlocksMsg:
		msgStream := rlp.NewStream(msg.Payload)
		if _, err := msgStream.List(); err != nil {
			return err
		}

		var blocks []*types.Block
		var i int
		for {
			i++
			var hash common.Hash
			err := msgStream.Decode(&hash)
			if err == rlp.EOL {
				break
			} else if err != nil {
				return self.protoError(ErrDecode, "msg %v: %v", msg, err)
			}

			block := self.chainManager.GetBlock(hash)
			if block != nil {
				blocks = append(blocks, block)
			}
			if i == maxBlocks {
				break
			}
		}
		return p2p.Send(self.rw, BlocksMsg, blocks)

	case BlocksMsg:
		msgStream := rlp.NewStream(msg.Payload)
		if _, err := msgStream.List(); err != nil {
			return err
		}
		for {
			var block types.Block
			if err := msgStream.Decode(&block); err != nil {
				if err == rlp.EOL {
					break
				} else {
					return self.protoError(ErrDecode, "msg %v: %v", msg, err)
				}
			}
			self.blockPool.AddBlock(&block, self.id)
		}

	case NewBlockMsg:
		var request newBlockMsgData
		if err := msg.Decode(&request); err != nil {
			return self.protoError(ErrDecode, "%v: %v", msg, err)
		}
		hash := request.Block.Hash()
		_, chainHead, _ := self.chainManager.Status()

		jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{
			BlockHash:     hash.Hex(),
			BlockNumber:   request.Block.Number(), // this surely must be zero
			ChainHeadHash: chainHead.Hex(),
			BlockPrevHash: request.Block.ParentHash().Hex(),
			RemoteId:      self.peer.ID().String(),
		})
		// to simplify backend interface adding a new block
		// uses AddPeer followed by AddBlock only if peer is the best peer
		// (or selected as new best peer)
		if best, _ := self.blockPool.AddPeer(request.TD, hash, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect); best {
			self.blockPool.AddBlock(request.Block, self.id)
		}

	default:
		return self.protoError(ErrInvalidMsgCode, "%v", msg.Code)
	}
	return nil
}

func (self *ethProtocol) handleStatus() error {
	if err := self.sendStatus(); err != nil {
		return err
	}

	// read and handle remote status
	msg, err := self.rw.ReadMsg()
	if err != nil {
		return err
	}
	if msg.Code != StatusMsg {
		return self.protoError(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg)
	}
	if msg.Size > ProtocolMaxMsgSize {
		return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
	}

	var status statusMsgData
	if err := msg.Decode(&status); err != nil {
		return self.protoError(ErrDecode, "msg %v: %v", msg, err)
	}

	_, _, genesisBlock := self.chainManager.Status()

	if status.GenesisBlock != genesisBlock {
		return self.protoError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock)
	}

	if int(status.NetworkId) != self.networkId {
		return self.protoError(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, self.networkId)
	}

	if int(status.ProtocolVersion) != self.protocolVersion {
		return self.protoError(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, self.protocolVersion)
	}

	_, suspended := self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect)
	if suspended {
		return self.protoError(ErrSuspendedPeer, "")
	}

	self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4])

	return nil
}

func (self *ethProtocol) requestBlockHashes(from common.Hash) error {
	self.peer.Debugf("fetching hashes (%d) %x...\n", maxHashes, from[0:4])
	return p2p.Send(self.rw, GetBlockHashesMsg, getBlockHashesMsgData{from, maxHashes})
}

func (self *ethProtocol) requestBlocks(hashes []common.Hash) error {
	self.peer.Debugf("fetching %v blocks", len(hashes))
	return p2p.Send(self.rw, GetBlocksMsg, hashes)
}

func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *errs.Error) {
	err = self.errors.New(code, format, params...)
	err.Log(self.peer.Logger)
	return
}

func (self *ethProtocol) sendStatus() error {
	td, currentBlock, genesisBlock := self.chainManager.Status()
	return p2p.Send(self.rw, StatusMsg, &statusMsgData{
		ProtocolVersion: uint32(self.protocolVersion),
		NetworkId:       uint32(self.networkId),
		TD:              td,
		CurrentBlock:    currentBlock,
		GenesisBlock:    genesisBlock,
	})
}

func (self *ethProtocol) protoErrorDisconnect(err *errs.Error) {
	err.Log(self.peer.Logger)
	if err.Fatal() {
		self.peer.Disconnect(p2p.DiscSubprotocolError)
	}
}
<commit_msg>iterator returned wrong value<commit_after>package eth

import (
	"fmt"
	"math/big"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/errs"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/rlp"
)

const (
	ProtocolVersion    = 58
	NetworkId          = 0
	ProtocolLength     = uint64(8)
	ProtocolMaxMsgSize = 10 * 1024 * 1024
	maxHashes          = 256
	maxBlocks          = 64
)

// eth protocol message codes
const (
	StatusMsg = iota
	GetTxMsg  // unused
	TxMsg
	GetBlockHashesMsg
	BlockHashesMsg
	GetBlocksMsg
	BlocksMsg
	NewBlockMsg
)

const (
	ErrMsgTooLarge = iota
	ErrDecode
	ErrInvalidMsgCode
	ErrProtocolVersionMismatch
	ErrNetworkIdMismatch
	ErrGenesisBlockMismatch
	ErrNoStatusMsg
	ErrExtraStatusMsg
	ErrSuspendedPeer
)

var errorToString = map[int]string{
	ErrMsgTooLarge:             "Message too long",
	ErrDecode:                  "Invalid message",
	ErrInvalidMsgCode:          "Invalid message code",
	ErrProtocolVersionMismatch: "Protocol version mismatch",
	ErrNetworkIdMismatch:       "NetworkId mismatch",
	ErrGenesisBlockMismatch:    "Genesis block mismatch",
	ErrNoStatusMsg:             "No status message",
	ErrExtraStatusMsg:          "Extra status message",
	ErrSuspendedPeer:           "Suspended peer",
}

// ethProtocol represents the ethereum wire protocol
// instance is running on each peer
type ethProtocol struct {
	txPool          txPool
	chainManager    chainManager
	blockPool       blockPool
	peer            *p2p.Peer
	id              string
	rw              p2p.MsgReadWriter
	errors          *errs.Errors
	protocolVersion int
	networkId       int
}

// backend is the interface the ethereum protocol backend should implement
// used as an argument to EthProtocol
type txPool interface {
	AddTransactions([]*types.Transaction)
	GetTransactions() types.Transactions
}

type chainManager interface {
	GetBlockHashesFromHash(hash common.Hash, amount uint64) (hashes []common.Hash)
	GetBlock(hash common.Hash) (block *types.Block)
	Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash)
}

type blockPool interface {
	AddBlockHashes(next func() (common.Hash, bool), peerId string)
	AddBlock(block *types.Block, peerId string)
	AddPeer(td *big.Int, currentBlock common.Hash, peerId string, requestHashes func(common.Hash) error, requestBlocks func([]common.Hash) error, peerError func(*errs.Error)) (best bool, suspended bool)
	RemovePeer(peerId string)
}

// message structs used for RLP serialization
type newBlockMsgData struct {
	Block *types.Block
	TD    *big.Int
}

type getBlockHashesMsgData struct {
	Hash   common.Hash
	Amount uint64
}

type statusMsgData struct {
	ProtocolVersion uint32
	NetworkId       uint32
	TD              *big.Int
	CurrentBlock    common.Hash
	GenesisBlock    common.Hash
}

// main entrypoint, wrappers starting a server running the eth protocol
// use this constructor to attach the protocol ("class") to server caps
// the Dev p2p layer then runs the protocol instance on each peer
func EthProtocol(protocolVersion, networkId int, txPool txPool, chainManager chainManager, blockPool blockPool) p2p.Protocol {
	return p2p.Protocol{
		Name:    "eth",
		Version: uint(protocolVersion),
		Length:  ProtocolLength,
		Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
			return runEthProtocol(protocolVersion, networkId, txPool, chainManager, blockPool, peer, rw)
		},
	}
}

// the main loop that handles incoming messages
// note RemovePeer in the post-disconnect hook
func runEthProtocol(protocolVersion, networkId int, txPool txPool, chainManager chainManager, blockPool blockPool, peer *p2p.Peer, rw p2p.MsgReadWriter) (err error) {
	id := peer.ID()
	self := &ethProtocol{
		txPool:          txPool,
		chainManager:    chainManager,
		blockPool:       blockPool,
		rw:              rw,
		peer:            peer,
		protocolVersion: protocolVersion,
		networkId:       networkId,
		errors: &errs.Errors{
			Package: "ETH",
			Errors:  errorToString,
		},
		id: fmt.Sprintf("%x", id[:8]),
	}

	// handshake.
	if err := self.handleStatus(); err != nil {
		return err
	}
	defer self.blockPool.RemovePeer(self.id)

	// propagate existing transactions. new transactions appearing
	// after this will be sent via broadcasts.
	if err := p2p.Send(rw, TxMsg, txPool.GetTransactions()); err != nil {
		return err
	}

	// main loop. handle incoming messages.
	for {
		if err := self.handle(); err != nil {
			return err
		}
	}
}

func (self *ethProtocol) handle() error {
	msg, err := self.rw.ReadMsg()
	if err != nil {
		return err
	}
	if msg.Size > ProtocolMaxMsgSize {
		return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
	}
	// make sure that the payload has been fully consumed
	defer msg.Discard()

	switch msg.Code {
	case GetTxMsg: // ignore
	case StatusMsg:
		return self.protoError(ErrExtraStatusMsg, "")

	case TxMsg:
		// TODO: rework using lazy RLP stream
		var txs []*types.Transaction
		if err := msg.Decode(&txs); err != nil {
			return self.protoError(ErrDecode, "msg %v: %v", msg, err)
		}
		for _, tx := range txs {
			jsonlogger.LogJson(&logger.EthTxReceived{
				TxHash:   tx.Hash().Hex(),
				RemoteId: self.peer.ID().String(),
			})
		}
		self.txPool.AddTransactions(txs)

	case GetBlockHashesMsg:
		var request getBlockHashesMsgData
		if err := msg.Decode(&request); err != nil {
			return self.protoError(ErrDecode, "->msg %v: %v", msg, err)
		}

		if request.Amount > maxHashes {
			request.Amount = maxHashes
		}
		hashes := self.chainManager.GetBlockHashesFromHash(request.Hash, request.Amount)
		return p2p.Send(self.rw, BlockHashesMsg, hashes)

	case BlockHashesMsg:
		msgStream := rlp.NewStream(msg.Payload)
		if _, err := msgStream.List(); err != nil {
			return err
		}

		var i int
		iter := func() (hash common.Hash, ok bool) {
			err := msgStream.Decode(&hash)
			if err == rlp.EOL {
				return common.Hash{}, false
			} else if err != nil {
				self.protoError(ErrDecode, "msg %v: after %v hashes : %v", msg, i, err)
				return common.Hash{}, false
			}

			i++
			return hash, true
		}
		self.blockPool.AddBlockHashes(iter, self.id)

	case GetBlocksMsg:
		msgStream := rlp.NewStream(msg.Payload)
		if _, err := msgStream.List(); err != nil {
			return err
		}

		var blocks []*types.Block
		var i int
		for {
			i++
			var hash common.Hash
			err := msgStream.Decode(&hash)
			if err == rlp.EOL {
				break
			} else if err != nil {
				return self.protoError(ErrDecode, "msg %v: %v", msg, err)
			}

			block := self.chainManager.GetBlock(hash)
			if block != nil {
				blocks = append(blocks, block)
			}
			if i == maxBlocks {
				break
			}
		}
		return p2p.Send(self.rw, BlocksMsg, blocks)

	case BlocksMsg:
		msgStream := rlp.NewStream(msg.Payload)
		if _, err := msgStream.List(); err != nil {
			return err
		}
		for {
			var block types.Block
			if err := msgStream.Decode(&block); err != nil {
				if err == rlp.EOL {
					break
				} else {
					return self.protoError(ErrDecode, "msg %v: %v", msg, err)
				}
			}
			self.blockPool.AddBlock(&block, self.id)
		}

	case NewBlockMsg:
		var request newBlockMsgData
		if err := msg.Decode(&request); err != nil {
			return self.protoError(ErrDecode, "%v: %v", msg, err)
		}
		hash := request.Block.Hash()
		_, chainHead, _ := self.chainManager.Status()

		jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{
			BlockHash:     hash.Hex(),
			BlockNumber:   request.Block.Number(), // this surely must be zero
			ChainHeadHash: chainHead.Hex(),
			BlockPrevHash: request.Block.ParentHash().Hex(),
			RemoteId:      self.peer.ID().String(),
		})
		// to simplify backend interface adding a new block
		// uses AddPeer followed by AddBlock only if peer is the best peer
		// (or selected as new best peer)
		if best, _ := self.blockPool.AddPeer(request.TD, hash, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect); best {
			self.blockPool.AddBlock(request.Block, self.id)
		}

	default:
		return self.protoError(ErrInvalidMsgCode, "%v", msg.Code)
	}
	return nil
}

func (self *ethProtocol) handleStatus() error {
	if err := self.sendStatus(); err != nil {
		return err
	}

	// read and handle remote status
	msg, err := self.rw.ReadMsg()
	if err != nil {
		return err
	}
	if msg.Code != StatusMsg {
		return self.protoError(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg)
	}
	if msg.Size > ProtocolMaxMsgSize {
		return self.protoError(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
	}

	var status statusMsgData
	if err := msg.Decode(&status); err != nil {
		return self.protoError(ErrDecode, "msg %v: %v", msg, err)
	}

	_, _, genesisBlock := self.chainManager.Status()

	if status.GenesisBlock != genesisBlock {
		return self.protoError(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock, genesisBlock)
	}

	if int(status.NetworkId) != self.networkId {
		return self.protoError(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, self.networkId)
	}

	if int(status.ProtocolVersion) != self.protocolVersion {
		return self.protoError(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, self.protocolVersion)
	}

	_, suspended := self.blockPool.AddPeer(status.TD, status.CurrentBlock, self.id, self.requestBlockHashes, self.requestBlocks, self.protoErrorDisconnect)
	if suspended {
		return self.protoError(ErrSuspendedPeer, "")
	}

	self.peer.Infof("Peer is [eth] capable (%d/%d). TD=%v H=%x\n", status.ProtocolVersion, status.NetworkId, status.TD, status.CurrentBlock[:4])

	return nil
}

func (self *ethProtocol) requestBlockHashes(from common.Hash) error {
	self.peer.Debugf("fetching hashes (%d) %x...\n", maxHashes, from[0:4])
	return p2p.Send(self.rw, GetBlockHashesMsg, getBlockHashesMsgData{from, maxHashes})
}

func (self *ethProtocol) requestBlocks(hashes []common.Hash) error {
	self.peer.Debugf("fetching %v blocks", len(hashes))
	return p2p.Send(self.rw, GetBlocksMsg, hashes)
}

func (self *ethProtocol) protoError(code int, format string, params ...interface{}) (err *errs.Error) {
	err = self.errors.New(code, format, params...)
	err.Log(self.peer.Logger)
	return
}

func (self *ethProtocol) sendStatus() error {
	td, currentBlock, genesisBlock := self.chainManager.Status()
	return p2p.Send(self.rw, StatusMsg, &statusMsgData{
		ProtocolVersion: uint32(self.protocolVersion),
		NetworkId:       uint32(self.networkId),
		TD:              td,
		CurrentBlock:    currentBlock,
		GenesisBlock:    genesisBlock,
	})
}

func (self *ethProtocol) protoErrorDisconnect(err *errs.Error) {
	err.Log(self.peer.Logger)
	if err.Fatal() {
		self.peer.Disconnect(p2p.DiscSubprotocolError)
	}
}
<|endoftext|>


<commit_before>package eval

import (
	"os"
	"fmt"
	"strings"
	"syscall"
	"../parse"
	"../util"
)

const (
	// A special impossible fd value. Used for "close fd" in
	// syscall.ProcAttr.Files.
	FD_NIL uintptr = ^uintptr(0)
)

// Represents an IO for commands. At most one of f and ch is non-nil. When
// both are nil, the IO is closed.
type io struct {
	f *os.File
	ch chan Value
}

type IOType byte

const (
	fileIO IOType = iota // Default IO type. Corresponds to io.f.
	chanIO // Corresponds to io.ch.
	unusedIO
)

func (i *io) compatible(typ IOType) bool {
	if i == nil {
		return false
	}
	if typ == unusedIO {
		return true
	}
	switch {
	case i.f != nil:
		return typ == fileIO
	case i.ch != nil:
		return typ == chanIO
	default:
		return true
	}
}

// The "head" of a command is either a function, the path of an external
// command or a closure.
type CommandHead struct {
	Func BuiltinFunc // A builtin function, if the command is builtin.
	Path string // Command full path, if the command is external.
	Closure *Closure // The closure value, if the command is a closure.
}

// command packs runtime states of a fully constructured command.
type command struct {
	name string // Command name, used in error messages.
	args []Value // Argument list, minus command name.
	ios [3]*io // IOs for in, out and err.
	CommandHead
}

type StateUpdate struct {
	Terminated bool
	Msg string
}

func isExecutable(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return false
	}
	fm := fi.Mode()
	return !fm.IsDir() && (fm & 0111 != 0)
}

// Search for executable `exe`.
func (ev *Evaluator) search(exe string) (string, error) {
	for _, p := range []string{"/", "./", "../"} {
		if strings.HasPrefix(exe, p) {
			if isExecutable(exe) {
				return exe, nil
			}
			return "", fmt.Errorf("external command not executable")
		}
	}
	for _, p := range ev.searchPaths {
		full := p + "/" + exe
		if isExecutable(full) {
			return full, nil
		}
	}
	return "", fmt.Errorf("external command not found")
}

func (ev *Evaluator) evalRedir(r parse.Redir, ios []*io, ioTypes []IOType) {
	ev.push(r)
	defer ev.pop()

	fd := r.Fd()
	if fd > 2 {
		ev.errorf("redir on fd > 2 not yet supported")
	}

	switch r := r.(type) {
	case *parse.CloseRedir:
		ios[fd] = &io{}
	case *parse.FdRedir:
		if ioTypes[fd] == chanIO {
			ev.errorf("fd redir on channel IO")
		}
		if r.OldFd > 2 {
			ev.errorf("fd redir from fd > 2 not yet supported")
		}
		ios[fd] = ios[r.OldFd]
	case *parse.FilenameRedir:
		if ioTypes[fd] == chanIO {
			ev.errorf("filename redir on channel IO")
		}
		fname := ev.evalTermSingleScalar(r.Filename, "filename").str
		// TODO haz hardcoded permbits now
		f, e := os.OpenFile(fname, r.Flag, 0644)
		if e != nil {
			ev.errorf("failed to open file %q: %s", fname[0], e)
		}
		ios[fd] = &io{f: f}
		// XXX Files opened in redirections of builtins shouldn't be
		// closed.
		ev.filesToClose = append(ev.filesToClose, f)
	}
}

func (ev *Evaluator) ResolveCommand(name string) (head CommandHead, ioTypes [3]IOType, err error) {
	defer util.Recover(&err)
	head, ioTypes = ev.resolveCommand(name, nil)
	return head, ioTypes, nil
}

func (ev *Evaluator) resolveCommand(name string, n parse.Node) (head CommandHead, ioTypes [3]IOType) {
	if n != nil {
		ev.push(n)
		defer ev.pop()
	}

	// Try function
	if v, err := ev.ResolveVar("fn-" + name); err == nil {
		if fn, ok := v.(*Closure); ok {
			head.Closure = fn
			// XXX Use zero value (fileIO) for ioTypes now
			return
		}
	}

	// Try builtin
	if bi, ok := builtins[name]; ok {
		head.Func = bi.fn
		ioTypes = bi.ioTypes
		return
	}

	// Try external command
	path, e := ev.search(name)
	if e != nil {
		ev.errorf("%s", e)
	}
	head.Path = path
	// Use zero value (fileIO) for ioTypes
	return
}

func (ev *Evaluator) preevalCommand(n *parse.CommandNode) (cmd *command, ioTypes [3]IOType) {
	// Evaluate name.
	nameValues := ev.evalTerm(n.Name)
	if len(nameValues) != 1 {
		ev.errorfNode(n.Name, "command name must be a single value")
	}
	name := nameValues[0]

	// Start building command.
	nameStr := name.String(ev)
	cmd = &command{name: nameStr}

	// Resolve command. Assign one of cmd.{fn path closure} and ioTypes.
	switch name := name.(type) {
	case *Scalar:
		cmd.CommandHead, ioTypes = ev.resolveCommand(nameStr, n.Name)
	case *Closure:
		cmd.CommandHead.Closure = name
		// XXX Use zero value (fileIO) for ioTypes now
	default:
		ev.errorfNode(n.Name, "Command name must be either scalar or closure")
	}

	// IO list.
	defaultErrIO := &io{f: os.Stderr}
	// XXX Should we allow chan IO stderr at all?
	if defaultErrIO.compatible(ioTypes[2]) {
		cmd.ios[2] = defaultErrIO
	}

	// Evaluate IO redirections.
	for _, r := range n.Redirs {
		ev.evalRedir(r, cmd.ios[:], ioTypes[:])
	}

	// Evaluate arguments after everything else.
	cmd.args = ev.evalTermList(n.Args)
	return
}

// ExecPipeline executes a pipeline.
//
// XXX Outdated comments below
//
// As many things as possible are done before any command actually gets
// executed, to avoid leaving the pipeline broken - resolving command names,
// opening files, and in future, evaluating shell constructs. If any error is
// encountered, pids is nil and err contains the error.
//
// However, if error is encountered when executing individual commands, the
// rest of the pipeline will still be executed. In that case, the
// corresponding elements in pids is -1 and err is typed *CommandErrors. For
// each pids[i] == -1, err.(*CommandErrors)Errors[i] contains the
// corresponding error.
func (ev *Evaluator) evalPipeline(pl *parse.ListNode) []<-chan *StateUpdate {
	ev.push(pl)
	defer ev.pop()

	defer func() {
		for _, f := range ev.filesToClose {
			f.Close()
		}
		ev.filesToClose = ev.filesToClose[0:]
	}()

	ncmds := len(pl.Nodes)
	if ncmds == 0 {
		return []<-chan *StateUpdate{}
	}

	cmds := make([]*command, 0, ncmds)

	var nextIn *io
	for i, n := range pl.Nodes {
		cmd, ioTypes := ev.preevalCommand(n.(*parse.CommandNode))

		// Create and connect pipes.
		if i == 0 {
			// First command. Only connect input when no input redirection is
			// present.
			if cmd.ios[0] == nil {
				if ioTypes[0] == chanIO {
					// TODO locate command
					ev.errorf("channel input from user not yet supported")
				}
				cmd.ios[0] = &io{f: os.Stdin}
			}
		} else {
			if cmd.ios[0] != nil {
				ev.errorf("command #%d has both pipe input and input redirection")
			} else if !nextIn.compatible(ioTypes[0]) {
				ev.errorf("command #%d has incompatible input pipe")
			}
			cmd.ios[0] = nextIn
		}
		if i == ncmds - 1 {
			if cmd.ios[1] == nil {
				if ioTypes[1] == chanIO {
					ev.errorf("channel output to user not yet supported")
				}
				cmd.ios[1] = &io{f: os.Stdout}
			}
		} else {
			if cmd.ios[1] != nil {
				ev.errorf("command #%d has both pipe output and output redirection", i)
			}
			switch ioTypes[1] {
			case unusedIO:
				ev.errorf("command #%d has unused output connected in pipeline", i)
			case fileIO:
				// os.Pipe sets O_CLOEXEC, which is what we want.
				reader, writer, e := os.Pipe()
				if e != nil {
					ev.errorf("failed to create pipe: %s", e)
				}
				// XXX The pipe end for builtins shouldn't be closed.
				ev.filesToClose = append(ev.filesToClose, reader, writer)
				nextIn = &io{f: reader}
				cmd.ios[1] = &io{f: writer}
			case chanIO:
				// TODO Buffered channel?
				// XXX Builtins are relied on to close channels.
				ch := make(chan Value)
				nextIn = &io{ch: ch}
				cmd.ios[1] = &io{ch: ch}
			default:
				panic("unreachable")
			}
		}

		cmds = append(cmds, cmd)
	}

	updates := make([]<-chan *StateUpdate, ncmds)
	for i, cmd := range cmds {
		updates[i] = ev.execCommand(cmd)
	}
	return updates
}

// execCommand executes a command.
func (ev *Evaluator) execCommand(cmd *command) <-chan *StateUpdate {
	switch {
	case cmd.Func != nil:
		return ev.execBuiltin(cmd)
	case cmd.Path != "":
		return ev.execExternal(cmd)
	case cmd.Closure != nil:
		return ev.execClosure(cmd)
	default:
		panic("Bad eval.command struct")
	}
}

func (ev *Evaluator) execClosure(cmd *command) <-chan *StateUpdate {
	update := make(chan *StateUpdate, 1)

	locals := make(map[string]Value)
	// TODO Support optional/rest argument
	if len(cmd.args) != len(cmd.Closure.ArgNames) {
		// TODO Check arity before exec'ing
		update <- &StateUpdate{Terminated: true, Msg: "arity mismatch"}
		close(update)
		return update
	}
	// Pass argument by populating locals.
	for i, name := range cmd.Closure.ArgNames {
		locals[name] = cmd.args[i]
	}

	// Make a subevaluator.
	// TODO Guard against concurrent writes to globals.
	newEv := Evaluator{
		globals: ev.globals,
		locals: locals,
		env: ev.env,
		searchPaths: ev.searchPaths,
	}
	go func() {
		// TODO Support calling closure originated in another source.
		newEv.Eval(ev.name, ev.text, cmd.Closure.Chunk)
		// TODO Support returning value.
		update <- &StateUpdate{Terminated: true}
		close(update)
	}()
	return update
}

// execBuiltin executes a builtin command.
func (ev *Evaluator) execBuiltin(cmd *command) <-chan *StateUpdate {
	update := make(chan *StateUpdate)
	go func() {
		msg := cmd.Func(ev, cmd.args, cmd.ios)
		update <- &StateUpdate{Terminated: true, Msg: msg}
		close(update)
	}()
	return update
}

func waitStateUpdate(pid int, update chan<- *StateUpdate) {
	for {
		var ws syscall.WaitStatus
		_, err := syscall.Wait4(pid, &ws, 0, nil)

		if err != nil {
			if err != syscall.ECHILD {
				update <- &StateUpdate{Msg: err.Error()}
			}
			break
		}
		update <- &StateUpdate{
			Terminated: ws.Exited(), Msg: fmt.Sprintf("%v", ws)}
	}
	close(update)
}

// execExternal executes an external command.
func (ev *Evaluator) execExternal(cmd *command) <-chan *StateUpdate {
	files := make([]uintptr, len(cmd.ios))
	for i, io := range cmd.ios {
		if io == nil || io.f == nil {
			files[i] = FD_NIL
		} else {
			files[i] = io.f.Fd()
		}
	}

	args := make([]string, len(cmd.args) + 1)
	args[0] = cmd.Path
	for i, a := range cmd.args {
		// NOTE Maybe we should enfore scalar arguments instead of coercing all
		// args into string
		args[i+1] = a.String(ev)
	}

	sys := syscall.SysProcAttr{}
	attr := syscall.ProcAttr{Env: ev.env.Export(), Files: files[:], Sys: &sys}
	pid, err := syscall.ForkExec(cmd.Path, args, &attr)

	update := make(chan *StateUpdate)
	if err != nil {
		update <- &StateUpdate{Terminated: true, Msg: err.Error()}
		close(update)
	} else {
		go waitStateUpdate(pid, update)
	}

	return update
}
<commit_msg>Update comments<commit_after>package eval

import (
	"os"
	"fmt"
	"strings"
	"syscall"
	"../parse"
	"../util"
)

const (
	// A special impossible fd value. Used for "close fd" in
	// syscall.ProcAttr.Files.
	FD_NIL uintptr = ^uintptr(0)
)

// Represents an IO for commands. At most one of f and ch is non-nil. When
// both are nil, the IO is closed.
type io struct {
	f *os.File
	ch chan Value
}

type IOType byte

const (
	fileIO IOType = iota // Default IO type. Corresponds to io.f.
	chanIO // Corresponds to io.ch.
	unusedIO
)

func (i *io) compatible(typ IOType) bool {
	if i == nil {
		return false
	}
	if typ == unusedIO {
		return true
	}
	switch {
	case i.f != nil:
		return typ == fileIO
	case i.ch != nil:
		return typ == chanIO
	default:
		return true
	}
}

// The "head" of a command is either a function, the path of an external
// command or a closure.
type CommandHead struct {
	Func BuiltinFunc // A builtin function, if the command is builtin.
	Path string // Command full path, if the command is external.
	Closure *Closure // The closure value, if the command is a closure.
}

// command packs runtime states of a fully constructured command.
type command struct {
	name string // Command name, used in error messages.
	args []Value // Argument list, minus command name.
	ios [3]*io // IOs for in, out and err.
	CommandHead
}

type StateUpdate struct {
	Terminated bool
	Msg string
}

func isExecutable(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return false
	}
	fm := fi.Mode()
	return !fm.IsDir() && (fm & 0111 != 0)
}

// Search for executable `exe`.
func (ev *Evaluator) search(exe string) (string, error) {
	for _, p := range []string{"/", "./", "../"} {
		if strings.HasPrefix(exe, p) {
			if isExecutable(exe) {
				return exe, nil
			}
			return "", fmt.Errorf("external command not executable")
		}
	}
	for _, p := range ev.searchPaths {
		full := p + "/" + exe
		if isExecutable(full) {
			return full, nil
		}
	}
	return "", fmt.Errorf("external command not found")
}

func (ev *Evaluator) evalRedir(r parse.Redir, ios []*io, ioTypes []IOType) {
	ev.push(r)
	defer ev.pop()

	fd := r.Fd()
	if fd > 2 {
		ev.errorf("redir on fd > 2 not yet supported")
	}

	switch r := r.(type) {
	case *parse.CloseRedir:
		ios[fd] = &io{}
	case *parse.FdRedir:
		if ioTypes[fd] == chanIO {
			ev.errorf("fd redir on channel IO")
		}
		if r.OldFd > 2 {
			ev.errorf("fd redir from fd > 2 not yet supported")
		}
		ios[fd] = ios[r.OldFd]
	case *parse.FilenameRedir:
		if ioTypes[fd] == chanIO {
			ev.errorf("filename redir on channel IO")
		}
		fname := ev.evalTermSingleScalar(r.Filename, "filename").str
		// TODO haz hardcoded permbits now
		f, e := os.OpenFile(fname, r.Flag, 0644)
		if e != nil {
			ev.errorf("failed to open file %q: %s", fname[0], e)
		}
		ios[fd] = &io{f: f}
		// XXX Files opened in redirections of builtins shouldn't be
		// closed.
		ev.filesToClose = append(ev.filesToClose, f)
	}
}

func (ev *Evaluator) ResolveCommand(name string) (head CommandHead, ioTypes [3]IOType, err error) {
	defer util.Recover(&err)
	head, ioTypes = ev.resolveCommand(name, nil)
	return head, ioTypes, nil
}

func (ev *Evaluator) resolveCommand(name string, n parse.Node) (head CommandHead, ioTypes [3]IOType) {
	if n != nil {
		ev.push(n)
		defer ev.pop()
	}

	// Try function
	if v, err := ev.ResolveVar("fn-" + name); err == nil {
		if fn, ok := v.(*Closure); ok {
			head.Closure = fn
			// XXX Use zero value (fileIO) for ioTypes now
			return
		}
	}

	// Try builtin
	if bi, ok := builtins[name]; ok {
		head.Func = bi.fn
		ioTypes = bi.ioTypes
		return
	}

	// Try external command
	path, e := ev.search(name)
	if e != nil {
		ev.errorf("%s", e)
	}
	head.Path = path
	// Use zero value (fileIO) for ioTypes
	return
}

func (ev *Evaluator) preevalCommand(n *parse.CommandNode) (cmd *command, ioTypes [3]IOType) {
	// Evaluate name.
	nameValues := ev.evalTerm(n.Name)
	if len(nameValues) != 1 {
		ev.errorfNode(n.Name, "command name must be a single value")
	}
	name := nameValues[0]

	// Start building command.
	nameStr := name.String(ev)
	cmd = &command{name: nameStr}

	// Resolve command. Assign one of cmd.{fn path closure} and ioTypes.
	switch name := name.(type) {
	case *Scalar:
		cmd.CommandHead, ioTypes = ev.resolveCommand(nameStr, n.Name)
	case *Closure:
		cmd.CommandHead.Closure = name
		// XXX Use zero value (fileIO) for ioTypes now
	default:
		ev.errorfNode(n.Name, "Command name must be either scalar or closure")
	}

	// IO list.
	defaultErrIO := &io{f: os.Stderr}
	// XXX Should we allow chan IO stderr at all?
	if defaultErrIO.compatible(ioTypes[2]) {
		cmd.ios[2] = defaultErrIO
	}

	// Evaluate IO redirections.
	for _, r := range n.Redirs {
		ev.evalRedir(r, cmd.ios[:], ioTypes[:])
	}

	// Evaluate arguments after everything else.
	cmd.args = ev.evalTermList(n.Args)
	return
}

// ExecPipeline executes a pipeline.
//
// As many things as possible are done before any command actually gets
// executed, to avoid leaving the pipeline broken - resolving command names,
// opening files, and in future, evaluating shell constructs. Such errors are
// signalled with Evaluator.errorf and will abort the whole script that is
// being evaluated. They are akin to "compile-time" errors.
//
// Another class of errors - nonzero return value from external command, etc.
// can only be detected after trying to execute the command. They are akin to
// "run-time" errors and do not affect the whole script. Instead, the errors
// signaled are merely recorded and returned.
//
// TODO Should return a slice of exit statuses.
// XXX Unresolvable external command should always be regarded as run-time
// error.
func (ev *Evaluator) evalPipeline(pl *parse.ListNode) []<-chan *StateUpdate {
	ev.push(pl)
	defer ev.pop()

	defer func() {
		for _, f := range ev.filesToClose {
			f.Close()
		}
		ev.filesToClose = ev.filesToClose[0:]
	}()

	ncmds := len(pl.Nodes)
	if ncmds == 0 {
		return []<-chan *StateUpdate{}
	}

	cmds := make([]*command, 0, ncmds)

	var nextIn *io
	for i, n := range pl.Nodes {
		cmd, ioTypes := ev.preevalCommand(n.(*parse.CommandNode))

		// Create and connect pipes.
		if i == 0 {
			// First command. Only connect input when no input redirection is
			// present.
			if cmd.ios[0] == nil {
				if ioTypes[0] == chanIO {
					// TODO locate command
					ev.errorf("channel input from user not yet supported")
				}
				cmd.ios[0] = &io{f: os.Stdin}
			}
		} else {
			if cmd.ios[0] != nil {
				ev.errorf("command #%d has both pipe input and input redirection")
			} else if !nextIn.compatible(ioTypes[0]) {
				ev.errorf("command #%d has incompatible input pipe")
			}
			cmd.ios[0] = nextIn
		}
		if i == ncmds - 1 {
			if cmd.ios[1] == nil {
				if ioTypes[1] == chanIO {
					ev.errorf("channel output to user not yet supported")
				}
				cmd.ios[1] = &io{f: os.Stdout}
			}
		} else {
			if cmd.ios[1] != nil {
				ev.errorf("command #%d has both pipe output and output redirection", i)
			}
			switch ioTypes[1] {
			case unusedIO:
				ev.errorf("command #%d has unused output connected in pipeline", i)
			case fileIO:
				// os.Pipe sets O_CLOEXEC, which is what we want.
				reader, writer, e := os.Pipe()
				if e != nil {
					ev.errorf("failed to create pipe: %s", e)
				}
				// XXX The pipe end for builtins shouldn't be closed.
				ev.filesToClose = append(ev.filesToClose, reader, writer)
				nextIn = &io{f: reader}
				cmd.ios[1] = &io{f: writer}
			case chanIO:
				// TODO Buffered channel?
				// XXX Builtins are relied on to close channels.
				ch := make(chan Value)
				nextIn = &io{ch: ch}
				cmd.ios[1] = &io{ch: ch}
			default:
				panic("unreachable")
			}
		}

		cmds = append(cmds, cmd)
	}

	updates := make([]<-chan *StateUpdate, ncmds)
	for i, cmd := range cmds {
		updates[i] = ev.execCommand(cmd)
	}
	return updates
}

// execCommand executes a command.
func (ev *Evaluator) execCommand(cmd *command) <-chan *StateUpdate {
	switch {
	case cmd.Func != nil:
		return ev.execBuiltin(cmd)
	case cmd.Path != "":
		return ev.execExternal(cmd)
	case cmd.Closure != nil:
		return ev.execClosure(cmd)
	default:
		panic("Bad eval.command struct")
	}
}

func (ev *Evaluator) execClosure(cmd *command) <-chan *StateUpdate {
	update := make(chan *StateUpdate, 1)

	locals := make(map[string]Value)
	// TODO Support optional/rest argument
	if len(cmd.args) != len(cmd.Closure.ArgNames) {
		// TODO Check arity before exec'ing
		update <- &StateUpdate{Terminated: true, Msg: "arity mismatch"}
		close(update)
		return update
	}
	// Pass argument by populating locals.
	for i, name := range cmd.Closure.ArgNames {
		locals[name] = cmd.args[i]
	}

	// Make a subevaluator.
	// TODO Guard against concurrent writes to globals.
	newEv := Evaluator{
		globals: ev.globals,
		locals: locals,
		env: ev.env,
		searchPaths: ev.searchPaths,
	}
	go func() {
		// TODO Support calling closure originated in another source.
		newEv.Eval(ev.name, ev.text, cmd.Closure.Chunk)
		// TODO Support returning value.
		update <- &StateUpdate{Terminated: true}
		close(update)
	}()
	return update
}

// execBuiltin executes a builtin command.
func (ev *Evaluator) execBuiltin(cmd *command) <-chan *StateUpdate {
	update := make(chan *StateUpdate)
	go func() {
		msg := cmd.Func(ev, cmd.args, cmd.ios)
		update <- &StateUpdate{Terminated: true, Msg: msg}
		close(update)
	}()
	return update
}

func waitStateUpdate(pid int, update chan<- *StateUpdate) {
	for {
		var ws syscall.WaitStatus
		_, err := syscall.Wait4(pid, &ws, 0, nil)

		if err != nil {
			if err != syscall.ECHILD {
				update <- &StateUpdate{Msg: err.Error()}
			}
			break
		}
		update <- &StateUpdate{
			Terminated: ws.Exited(), Msg: fmt.Sprintf("%v", ws)}
	}
	close(update)
}

// execExternal executes an external command.
func (ev *Evaluator) execExternal(cmd *command) <-chan *StateUpdate {
	files := make([]uintptr, len(cmd.ios))
	for i, io := range cmd.ios {
		if io == nil || io.f == nil {
			files[i] = FD_NIL
		} else {
			files[i] = io.f.Fd()
		}
	}

	args := make([]string, len(cmd.args) + 1)
	args[0] = cmd.Path
	for i, a := range cmd.args {
		// NOTE Maybe we should enfore scalar arguments instead of coercing all
		// args into string
		args[i+1] = a.String(ev)
	}

	sys := syscall.SysProcAttr{}
	attr := syscall.ProcAttr{Env: ev.env.Export(), Files: files[:], Sys: &sys}
	pid, err := syscall.ForkExec(cmd.Path, args, &attr)

	update := make(chan *StateUpdate)
	if err != nil {
		update <- &StateUpdate{Terminated: true, Msg: err.Error()}
		close(update)
	} else {
		go waitStateUpdate(pid, update)
	}

	return update
}
<|endoftext|>


<commit_before>// Copyright 2017 Corey Scott http://www.sage42.org/
//
// 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 internal

import (
	"bytes"
	"net/http"
)

// NewCustomResponseWriter returns a CustomResponseWriter from the supplied http.ResponseWriter
func NewCustomResponseWriter(resp http.ResponseWriter, catchBody bool) *CustomResponseWriter {
	return &CustomResponseWriter{
		ResponseWriter: resp,
		catchBody:      catchBody,
	}
}

// CustomResponseWriter implements http.ResponseWriter and extends the default implementation by allowing us
// access to the http response code
type CustomResponseWriter struct {
	http.ResponseWriter
	status      int
	wroteHeader bool

	catchBody bool
	body      bytes.Buffer
}

// Write implements http.ResponseWriter
func (resp *CustomResponseWriter) Write(in []byte) (int, error) {
	if resp.catchBody {
		_, err := resp.body.Write(in)
		if err != nil {
			return 0, err
		}
	}

	return resp.ResponseWriter.Write(in)
}

// WriteHeader implements http.ResponseWriter
func (resp *CustomResponseWriter) WriteHeader(code int) {
	// check after in case there's error handling in the wrapped http.ResponseWriter
	if resp.wroteHeader {
		return
	}

	resp.ResponseWriter.WriteHeader(code)

	resp.status = code
	resp.wroteHeader = true
}

// Status returns the HTTP status code (or 0 if not set)
func (resp *CustomResponseWriter) Status() int {
	return resp.status
}

// Body returns the HTTP body (if `catchBody == true` in the constructor)
func (resp *CustomResponseWriter) Body() []byte {
	return resp.body.Bytes()
}
<commit_msg>Remove incorrect "automatic" header writing<commit_after>// Copyright 2017 Corey Scott http://www.sage42.org/
//
// 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 internal

import (
	"bytes"
	"net/http"
)

// NewCustomResponseWriter returns a CustomResponseWriter from the supplied http.ResponseWriter
func NewCustomResponseWriter(resp http.ResponseWriter, catchBody bool) *CustomResponseWriter {
	return &CustomResponseWriter{
		ResponseWriter: resp,
		catchBody:      catchBody,
	}
}

// CustomResponseWriter implements http.ResponseWriter and extends the default implementation by allowing us
// access to the http response code
type CustomResponseWriter struct {
	http.ResponseWriter
	status      int
	wroteHeader bool

	catchBody bool
	body      bytes.Buffer
}

// Write implements http.ResponseWriter
func (resp *CustomResponseWriter) Write(in []byte) (int, error) {
	if !resp.wroteHeader {
		resp.WriteHeader(http.StatusOK)
	}

	if resp.catchBody {
		_, err := resp.body.Write(in)
		if err != nil {
			return 0, err
		}
	}

	return resp.ResponseWriter.Write(in)
}

// WriteHeader implements http.ResponseWriter
func (resp *CustomResponseWriter) WriteHeader(code int) {
	// check after in case there's error handling in the wrapped http.ResponseWriter
	if resp.wroteHeader {
		return
	}

	resp.ResponseWriter.WriteHeader(code)

	resp.status = code
	resp.wroteHeader = true
}

// Status returns the HTTP status code (or 0 if not set)
func (resp *CustomResponseWriter) Status() int {
	return resp.status
}

// Body returns the HTTP body (if `catchBody == true` in the constructor)
func (resp *CustomResponseWriter) Body() []byte {
	return resp.body.Bytes()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	skiplist "../../go-skiplist"
)

func main() {
	//New a skiplist
	sl := skiplist.NewSkipList()

	//Insert search key 50, value "5", value could be anything.
	sl.Insert(50, "5")
	sl.Insert(40, "4")
	sl.Insert(70, "7")
	sl.Insert(100, "10")

	//Search key, which time complexity O(log n)
	ret, err := sl.Search(50)
	if err == nil {
		fmt.Println("key 50: val->", ret)
	} else {
		fmt.Println("Not found, ", err)
	}

	//Delete by search key
	err = sl.Delete(70)
	if err != nil {
		fmt.Println("Delete not found")
	}

	//Display all skip list content.
	sl.DisplayAll()
}
<commit_msg>Update example<commit_after>package main

import (
	"fmt"

	skiplist "github.com/kkdai/skiplist"
)

func main() {
	//New a skiplist
	sl := skiplist.NewSkipList()

	//Insert search key 50, value "5", value could be anything.
	sl.Insert(50, "5")
	sl.Insert(40, "4")
	sl.Insert(70, "7")
	sl.Insert(100, "10")

	//Search key, which time complexity O(log n)
	ret, err := sl.Search(50)
	if err == nil {
		fmt.Println("key 50: val->", ret)
	} else {
		fmt.Println("Not found, ", err)
	}

	//Delete by search key
	err = sl.Delete(70)
	if err != nil {
		fmt.Println("Delete not found")
	}

	//Display all skip list content.
	sl.DisplayAll()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	_ "github.com/cookieo9/go-sqlite3"
	"os"
)

func main() {
	os.Remove("./foo.db")

	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer db.Close()

	sqls := []string{
		"create table foo (id integer not null primary key, name text)",
		"delete from foo",
	}
	for _, sql := range sqls {
		_, err = db.Exec(sql)
		if err != nil {
			fmt.Printf("%q: %s\n", err, sql)
			return
		}
	}

	tx, err := db.Begin()
	if err != nil {
		fmt.Println(err)
		return
	}
	stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer stmt.Close()
	for i := 0; i < 100; i++ {
		_, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i))
		if err != nil {
			fmt.Println(err)
			return
		}
	}
	tx.Commit()

	rows, err := db.Query("select id, name from foo")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer rows.Close()
	for rows.Next() {
		var id int
		var name string
		rows.Scan(&id, &name)
		println(id, name)
	}
	rows.Close()

	stmt, err = db.Prepare("select name from foo where id = ?")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer stmt.Close()
	var name string
	err = stmt.QueryRow("3").Scan(&name)
	if err != nil {
		fmt.Println(err)
		return
	}
	println(name)
}
<commit_msg>Switched example back to mattn's repo.<commit_after>package main

import (
	"database/sql"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"os"
)

func main() {
	os.Remove("./foo.db")

	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer db.Close()

	sqls := []string{
		"create table foo (id integer not null primary key, name text)",
		"delete from foo",
	}
	for _, sql := range sqls {
		_, err = db.Exec(sql)
		if err != nil {
			fmt.Printf("%q: %s\n", err, sql)
			return
		}
	}

	tx, err := db.Begin()
	if err != nil {
		fmt.Println(err)
		return
	}
	stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer stmt.Close()
	for i := 0; i < 100; i++ {
		_, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i))
		if err != nil {
			fmt.Println(err)
			return
		}
	}
	tx.Commit()

	rows, err := db.Query("select id, name from foo")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer rows.Close()
	for rows.Next() {
		var id int
		var name string
		rows.Scan(&id, &name)
		println(id, name)
	}
	rows.Close()

	stmt, err = db.Prepare("select name from foo where id = ?")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer stmt.Close()
	var name string
	err = stmt.QueryRow("3").Scan(&name)
	if err != nil {
		fmt.Println(err)
		return
	}
	println(name)
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package main

import (
	"fmt"

	"github.com/go-vgo/robotgo"
	// "go-vgo/robotgo"
)

func main() {
	////////////////////////////////////////////////////////////////////////////////
	// Control the keyboard
	////////////////////////////////////////////////////////////////////////////////
	robotgo.TypeString("Hello World") //importing "Hello World"
	robotgo.KeyTap("enter")           //Press "enter"
	robotgo.KeyTap("a", "control")
	robotgo.KeyTap("h", "command") //Hide window

	//Press "i", "alt", "command" Key combination
	robotgo.KeyTap("i", "alt", "command")
	arr := []string{"alt", "command"}
	robotgo.KeyTap("i", arr)

	robotgo.KeyTap("w", "command") //close window
	robotgo.KeyTap("m", "command") //minimize window
	robotgo.KeyTap("f1", "control")
	robotgo.KeyTap("a", "control")
	robotgo.KeyToggle("a", "down")
	robotgo.KeyToggle("a", "down", "alt")
	robotgo.KeyToggle("a", "down", "alt", "command")
	robotgo.KeyToggle("enter", "down")
	robotgo.TypeString("en")

	////////////////////////////////////////////////////////////////////////////////
	// Control the mouse
	////////////////////////////////////////////////////////////////////////////////
	robotgo.MoveMouse(100, 200)          //Move the mouse to 100, 200
	robotgo.MouseClick()                 //Click the left mouse button
	robotgo.MouseClick("right", false)   //Click the right mouse button
	robotgo.MouseClick("left", true)     //double click the left mouse button
	robotgo.ScrollMouse(10, "up")        //Scrolls the mouse either up
	robotgo.MouseToggle("down", "right") //Toggles right mouse button
	robotgo.MoveMouseSmooth(100, 200)    //Smooth move the mouse to 100, 200
	robotgo.MoveMouseSmooth(100, 200, 1.0, 100.0)
	x, y := robotgo.GetMousePos() //Gets the mouse coordinates
	fmt.Println("pos:", x, y)
	if x == 456 && y == 586 {
		fmt.Println("mouse...", "586")
	}

	robotgo.MouseToggle("up")
	robotgo.MoveMouse(x, y)
	robotgo.MoveMouse(100, 200)

	for i := 0; i < 1080; i += 1000 {
		fmt.Println(i)
		robotgo.MoveMouse(800, i)
	}

	////////////////////////////////////////////////////////////////////////////////
	// Read the screen
	////////////////////////////////////////////////////////////////////////////////
	gbitMap := robotgo.BCaptureScreen()
	fmt.Println("BCaptureScreen...", gbitMap.Width)
	// fmt.Println("...", gbitmap.Width, gbitmap.BytesPerPixel)

	//Gets the screen width and height
	sx, sy := robotgo.GetScreenSize()
	fmt.Println("...", sx, sy)

	//Gets the pixel color at 100, 200.
	color := robotgo.GetPixelColor(100, 200)
	fmt.Println("color----", color, "-----------------")

	//Gets the pixel color at 10, 20.
	color2 := robotgo.GetPixelColor(10, 20)
	fmt.Println("color---", color2)

	////////////////////////////////////////////////////////////////////////////////
	// Bitmap
	////////////////////////////////////////////////////////////////////////////////
	//Gets all of the screen
	abitMap := robotgo.CaptureScreen()
	fmt.Println("abitMap...", abitMap)

	//Gets part of the screen
	bitmap := robotgo.CaptureScreen(100, 200, 30, 40)
	fmt.Println("CaptureScreen...", bitmap)

	//Searches for needle in bitmap
	fx, fy := robotgo.FindBitmap(bitmap)
	fmt.Println("FindBitmap------", fx, fy)

	//Returns new bitmap object created from a portion of another
	bitpos := robotgo.GetPortion(bitmap, 10, 10, 11, 10)
	fmt.Println(bitpos)

	//Creates bitmap from string by bitmap
	bitstr := robotgo.TostringBitmap(bitmap)
	fmt.Println("bitstr...", bitstr)

	// sbitmap := robotgo.BitmapFromstring(bitstr, 2)
	// fmt.Println("...", sbitmap)

	//Saves image to absolute filepath in the given format
	robotgo.SaveBitmap(bitmap, "test.png")
	robotgo.SaveBitmap(bitmap, "test31.tif", 1)
	robotgo.Convert("test.png", "test.tif") //Convert image

	openbit := robotgo.OpenBitmap("test.tif") // open image bitmap
	fmt.Println("openBitmap...", openbit)

	////////////////////////////////////////////////////////////////////////////////
	// Global event listener
	////////////////////////////////////////////////////////////////////////////////
	fmt.Println("---please press v---")
	eve := robotgo.AddEvent("v")

	if eve == 0 {
		fmt.Println("---you press v---", "v")
	}

	fmt.Println("---please press k---")
	keve := robotgo.AddEvent("k")
	if keve == 0 {
		fmt.Println("---you press k---", "k")
	}

	fmt.Println("---please press f1---")
	feve := robotgo.AddEvent("f1")
	if feve == 0 {
		fmt.Println("you press...", "f1")
	}

	fmt.Println("---please press left mouse button---")
	mleft := robotgo.AddEvent("mleft")
	if mleft == 0 {
		fmt.Println("---you press left mouse button---", "mleft")
	}

	mright := robotgo.AddEvent("mright")
	if mright == 0 {
		fmt.Println("---you press right mouse button---", "mright")
	}

	//Stop AddEvent
	// robotgo.StopEvent()

	////////////////////////////////////////////////////////////////////////////////
	// Window Handle
	////////////////////////////////////////////////////////////////////////////////
	abool := robotgo.ShowAlert("hello", "robotgo") //Show Alert Window
	if abool == 0 {
		fmt.Println("ok@@@", "ok")
	}
	robotgo.ShowAlert("hello", "robotgo", "Ok", "Cancel")
	pid := robotgo.GetPID() //Get the current process id
	fmt.Println("pid----", pid)
	mdata := robotgo.GetActive() //Get current Window Active
	hwnd := robotgo.GetHandle()  //Get current Window Handle
	fmt.Println("hwnd---", hwnd)
	bhwnd := robotgo.GetBHandle() //Get current Window Handle
	fmt.Println("bhwnd---", bhwnd)
	title := robotgo.GetTitle() //Get current Window title
	fmt.Println("title-----", title)
	robotgo.CloseWindow()    //close current Window
	robotgo.SetActive(mdata) //set Window Active
}
<commit_msg>Update example<commit_after>// Copyright 2016-2017 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-vgo/robotgo/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package main

import (
	"fmt"

	"github.com/go-vgo/robotgo"
	// "go-vgo/robotgo"
)

func main() {
	////////////////////////////////////////////////////////////////////////////////
	// Control the keyboard
	////////////////////////////////////////////////////////////////////////////////
	robotgo.TypeString("Hello World") // importing "Hello World"
	robotgo.KeyTap("enter")           // Press "enter"
	robotgo.KeyTap("a", "control")
	robotgo.KeyTap("h", "command") // Hide window

	// Press "i", "alt", "command" Key combination
	robotgo.KeyTap("i", "alt", "command")
	arr := []string{"alt", "command"}
	robotgo.KeyTap("i", arr)

	robotgo.KeyTap("w", "command") // close window
	robotgo.KeyTap("m", "command") // minimize window
	robotgo.KeyTap("f1", "control")
	robotgo.KeyTap("a", "control")
	robotgo.KeyToggle("a", "down")
	robotgo.KeyToggle("a", "down", "alt")
	robotgo.KeyToggle("a", "down", "alt", "command")
	robotgo.KeyToggle("enter", "down")
	robotgo.TypeString("en")

	////////////////////////////////////////////////////////////////////////////////
	// Control the mouse
	////////////////////////////////////////////////////////////////////////////////
	robotgo.MoveMouse(100, 200)          // Move the mouse to 100, 200
	robotgo.MouseClick()                 // Click the left mouse button
	robotgo.MouseClick("right", false)   // Click the right mouse button
	robotgo.MouseClick("left", true)     // double click the left mouse button
	robotgo.ScrollMouse(10, "up")        // Scrolls the mouse either up
	robotgo.MouseToggle("down", "right") // Toggles right mouse button
	robotgo.MoveMouseSmooth(100, 200)    // Smooth move the mouse to 100, 200
	robotgo.MoveMouseSmooth(100, 200, 1.0, 100.0)
	x, y := robotgo.GetMousePos() // Gets the mouse coordinates
	fmt.Println("pos:", x, y)
	if x == 456 && y == 586 {
		fmt.Println("mouse...", "586")
	}

	robotgo.MouseToggle("up")
	robotgo.MoveMouse(x, y)
	robotgo.MoveMouse(100, 200)

	for i := 0; i < 1080; i += 1000 {
		fmt.Println(i)
		robotgo.MoveMouse(800, i)
	}

	////////////////////////////////////////////////////////////////////////////////
	// Read the screen
	////////////////////////////////////////////////////////////////////////////////
	gbitMap := robotgo.BCaptureScreen()
	fmt.Println("BCaptureScreen...", gbitMap.Width)
	// fmt.Println("...", gbitmap.Width, gbitmap.BytesPerPixel)

	// Gets the screen width and height
	sx, sy := robotgo.GetScreenSize()
	fmt.Println("...", sx, sy)

	// Gets the pixel color at 100, 200.
	color := robotgo.GetPixelColor(100, 200)
	fmt.Println("color----", color, "-----------------")

	// Gets the pixel color at 10, 20.
	color2 := robotgo.GetPixelColor(10, 20)
	fmt.Println("color---", color2)

	////////////////////////////////////////////////////////////////////////////////
	// Bitmap
	////////////////////////////////////////////////////////////////////////////////
	// Gets all of the screen
	abitMap := robotgo.CaptureScreen()
	fmt.Println("abitMap...", abitMap)

	// Gets part of the screen
	bitmap := robotgo.CaptureScreen(100, 200, 30, 40)
	fmt.Println("CaptureScreen...", bitmap)

	// Searches for needle in bitmap
	fx, fy := robotgo.FindBitmap(bitmap)
	fmt.Println("FindBitmap------", fx, fy)

	// Returns new bitmap object created from a portion of another
	bitpos := robotgo.GetPortion(bitmap, 10, 10, 11, 10)
	fmt.Println(bitpos)

	// Creates bitmap from string by bitmap
	bitstr := robotgo.TostringBitmap(bitmap)
	fmt.Println("bitstr...", bitstr)

	// sbitmap := robotgo.BitmapFromstring(bitstr, 2)
	// fmt.Println("...", sbitmap)

	// Saves image to absolute filepath in the given format
	robotgo.SaveBitmap(bitmap, "test.png")
	robotgo.SaveBitmap(bitmap, "test31.tif", 1)
	robotgo.Convert("test.png", "test.tif") // Convert image

	openbit := robotgo.OpenBitmap("test.tif") // open image bitmap
	fmt.Println("openBitmap...", openbit)

	////////////////////////////////////////////////////////////////////////////////
	// Global event listener
	////////////////////////////////////////////////////////////////////////////////
	fmt.Println("---please press v---")
	eve := robotgo.AddEvent("v")

	if eve == 0 {
		fmt.Println("---you press v---", "v")
	}

	fmt.Println("---please press k---")
	keve := robotgo.AddEvent("k")
	if keve == 0 {
		fmt.Println("---you press k---", "k")
	}

	fmt.Println("---please press f1---")
	feve := robotgo.AddEvent("f1")
	if feve == 0 {
		fmt.Println("you press...", "f1")
	}

	fmt.Println("---please press left mouse button---")
	mleft := robotgo.AddEvent("mleft")
	if mleft == 0 {
		fmt.Println("---you press left mouse button---", "mleft")
	}

	mright := robotgo.AddEvent("mright")
	if mright == 0 {
		fmt.Println("---you press right mouse button---", "mright")
	}

	// Stop AddEvent
	// robotgo.StopEvent()

	////////////////////////////////////////////////////////////////////////////////
	// Window Handle
	////////////////////////////////////////////////////////////////////////////////
	abool := robotgo.ShowAlert("hello", "robotgo") // Show Alert Window
	if abool == 0 {
		fmt.Println("ok@@@", "ok")
	}
	robotgo.ShowAlert("hello", "robotgo", "Ok", "Cancel")
	pid := robotgo.GetPID() // Get the current process id
	fmt.Println("pid----", pid)
	mdata := robotgo.GetActive() // Get current Window Active
	hwnd := robotgo.GetHandle()  // Get current Window Handle
	fmt.Println("hwnd---", hwnd)
	bhwnd := robotgo.GetBHandle() // Get current Window Handle
	fmt.Println("bhwnd---", bhwnd)
	title := robotgo.GetTitle() // Get current Window title
	fmt.Println("title-----", title)
	robotgo.CloseWindow()    // close current Window
	robotgo.SetActive(mdata) // set Window Active
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"proksi"
	"time"
	"path/filepath"
	"os"
)

func main() {

    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

	proxychan := make(chan proksi.Proxy)
	lines := 0
	amountOf := 0
	alive := 0
	te := time.Now()
	var timeout = time.Second * 3
	var buffer bytes.Buffer

	proxies, err := proksi.ReadFile(dir+"/proxies.txt")
	if err != nil {
		fmt.Println(err)
	}

	for _, proxy := range proxies {
		lines++
		amountOf++
		go proksi.ResolveAndWrite(proxychan, proxy, timeout, "http://google.com/")
	}

	for proxy := range proxychan {

		lines--

		if proxy.Alive {
			alive++
			buffer.WriteString(proxy.Address + "\n")
		}

		if lines == 0 {
			err := proksi.WriteFile("checked-proxies.txt", buffer)
			if err != nil {
				fmt.Println(err)
			}
			fmt.Println("Checked", amountOf, "proxies in", time.Now().Sub(te), "and of which", alive, "responded.")
		}
	}
}
<commit_msg>syntax: go fmt<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"proksi"
	"time"
)

func main() {

	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	proxychan := make(chan proksi.Proxy)
	lines := 0
	amountOf := 0
	alive := 0
	te := time.Now()
	var timeout = time.Second * 3
	var buffer bytes.Buffer

	proxies, err := proksi.ReadFile(dir + "/proxies.txt")
	if err != nil {
		fmt.Println(err)
	}

	for _, proxy := range proxies {
		lines++
		amountOf++
		go proksi.ResolveAndWrite(proxychan, proxy, timeout, "http://google.com/")
	}

	for proxy := range proxychan {

		lines--

		if proxy.Alive {
			alive++
			buffer.WriteString(proxy.Address + "\n")
		}

		if lines == 0 {
			err := proksi.WriteFile("checked-proxies.txt", buffer)
			if err != nil {
				fmt.Println(err)
			}
			fmt.Println("Checked", amountOf, "proxies in", time.Now().Sub(te), "and of which", alive, "responded.")
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Datacratic. All rights reserved.

package set_test

import (
	"github.com/datacratic/goset"

	"fmt"
)

func Example_Basics() {

	x := set.NewString("a", "b", "c")

	fmt.Println("len(x):", len(x))
	fmt.Println("x.Test(a):", x.Test("a"))
	fmt.Println("x.Test(d):", x.Test("d"))

	y := x.Copy()
	y.Del("b")
	fmt.Println("y:", y)

	z := set.NewString()
	for v := range y {
		z.Put(v)
	}

	fmt.Println("z:", z.Array())

	// Output:
	// len(x): 3
	// x.Test(a): true
	// x.Test(d): false
	// y: { a c }
	// z: [a c]
}

func Example_Operands() {

	x := set.NewString("a", "b", "c")
	y := set.NewString("b", "c", "d")

	fmt.Println("x.Union(y):", x.Union(y))
	fmt.Println("x.Intersect(y):", x.Intersect(y))
	fmt.Println("x.Difference(y):", x.Difference(y))

	// Output:
	// x.Union(y): { a b c d }
	// x.Intersect(y): { b c }
	// x.Difference(y): { a }
}
<commit_msg>Added examples for ints.<commit_after>// Copyright (c) 2014 Datacratic. All rights reserved.

package set_test

import (
	"github.com/datacratic/goset"

	"fmt"
)

func Example_Basics() {

	x := set.NewString("a", "b", "c")

	fmt.Println("len(x):", len(x))
	fmt.Println("x.Test(a):", x.Test("a"))
	fmt.Println("x.Test(d):", x.Test("d"))

	y := x.Copy()
	y.Del("b")
	fmt.Println("y:", y)

	z := set.NewString()
	for v := range y {
		z.Put(v)
	}

	fmt.Println("z:", z.Array())

	// Output:
	// len(x): 3
	// x.Test(a): true
	// x.Test(d): false
	// y: { a c }
	// z: [a c]
}

func Example_Operands() {

	x := set.NewString("a", "b", "c")
	y := set.NewString("b", "c", "d")

	fmt.Println("x.Union(y):", x.Union(y))
	fmt.Println("x.Intersect(y):", x.Intersect(y))
	fmt.Println("x.Difference(y):", x.Difference(y))

	// Output:
	// x.Union(y): { a b c d }
	// x.Intersect(y): { b c }
	// x.Difference(y): { a }
}

func Example_Types() {

	unsigned := set.NewUint(uint64(1), uint64(2), uint64(3))
	fmt.Println("unsigned:", unsigned)

	signed := set.NewInt(int64(-1), int64(-2), int64(-3))
	fmt.Println("signed:", signed)

	// Output:
	// unsigned: { 1 2 3 }
	// signed: { -3 -2 -1 }
}
<|endoftext|>


<commit_before>package appcast

import (
	"fmt"

	"gopkg.in/jarcoal/httpmock.v1"
)

// ExampleSparkleRSSFeed demonstrates the loading and parsing of the "Sparkle
// RSS Feed" appcast.
func Example_sparkleRSSFeed() {
	// mock the request
	content := string(getTestdata("example_sparkle.xml"))
	httpmock.ActivateNonDefault(DefaultClient.HTTPClient)
	httpmock.RegisterResponder("GET", "https://www.adium.im/sparkle/appcast-release.xml", httpmock.NewStringResponder(200, content))
	defer httpmock.DeactivateAndReset()

	// example
	a := New()
	a.LoadFromURL("https://www.adium.im/sparkle/appcast-release.xml")
	a.GenerateChecksum(SHA256)
	a.ExtractReleases()
	a.SortReleasesByVersions(DESC)

	fmt.Println("Checksum:", a.GetChecksum())
	fmt.Println("Provider:", a.Provider)

	for i, release := range a.Releases {
		fmt.Println(fmt.Sprintf("Release #%d:", i+1), release)
	}

	// Output:
	// Checksum: 6ec7c5abcaa78457cc4bf3c2196584446cca1461c65505cbaf0382a2f62128db
	// Provider: Sparkle RSS Feed
	// Release #1: {1.5.10.4 1.5.10.4 Adium 1.5.10.4  [{https://adiumx.cachefly.net/Adium_1.5.10.4.dmg application/octet-stream 21140435}] 2017-05-14 12:04:01 +0000 UTC false}
	// Release #2: {1.5.10 1.5.10 Adium 1.5.10  [{https://adiumx.cachefly.net/Adium_1.5.10.dmg application/octet-stream 24595712}] 2014-05-19 21:25:14 +0000 UTC false}
	// Release #3: {1.4.5 1.4.5 Adium 1.4.5  [{https://adiumx.cachefly.net/Adium_1.4.5.dmg application/octet-stream 23065688}] 2012-03-20 20:30:00 +0000 UTC false}
	// Release #4: {1.3.10 1.3.10 Adium 1.3.10  [{https://adiumx.cachefly.net/Adium_1.3.10.dmg application/octet-stream 22369877}] 2010-01-12 23:30:00 +0000 UTC false}
	// Release #5: {1.0.6 1.0.6 Adium 1.0.6  [{https://adiumx.cachefly.net/Adium_1.0.6.dmg application/octet-stream 13795246}] 2007-08-13 22:12:45 +0000 UTC false}
}

// ExampleSourceForgeRSSFeed demonstrates the loading and parsing of the
// "SourceForge RSS Feed" appcast.
func Example_sourceForgeRSSFeed() {
	// mock the request
	content := string(getTestdata("example_sourceforge.xml"))
	httpmock.ActivateNonDefault(DefaultClient.HTTPClient)
	httpmock.RegisterResponder("GET", "https://sourceforge.net/projects/filezilla/rss", httpmock.NewStringResponder(200, content))
	defer httpmock.DeactivateAndReset()

	// example
	a := New()
	a.LoadFromURL("https://sourceforge.net/projects/filezilla/rss")
	a.GenerateChecksum(SHA256)
	a.ExtractReleases()

	// apply some filters
	a.FilterReleasesByMediaType("application/x-bzip2")
	a.FilterReleasesByTitle("FileZilla_Client_Unstable", true)
	a.FilterReleasesByURL("macosx")
	defer a.ResetFilters() // reset

	fmt.Println("Checksum:", a.GetChecksum())
	fmt.Println("Provider:", a.Provider)

	for i, release := range a.Releases {
		fmt.Println(fmt.Sprintf("Release #%d:", i+1), release)
	}

	// Output:
	// Checksum: 69886b91a041ce9d742218a77317cd99f87a14199c3f8ba094042dd9d430f7fd
	// Provider: SourceForge RSS Feed
	// Release #1: {3.25.2  /FileZilla_Client/3.25.2/FileZilla_3.25.2_macosx-x86.app.tar.bz2 /FileZilla_Client/3.25.2/FileZilla_3.25.2_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.25.2/FileZilla_3.25.2_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8453714}] 2017-04-30 12:07:25 +0000 UTC false}
	// Release #2: {3.25.1  /FileZilla_Client/3.25.1/FileZilla_3.25.1_macosx-x86.app.tar.bz2 /FileZilla_Client/3.25.1/FileZilla_3.25.1_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.25.1/FileZilla_3.25.1_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8460741}] 2017-03-20 17:11:09 +0000 UTC false}
	// Release #3: {3.25.0  /FileZilla_Client/3.25.0/FileZilla_3.25.0_macosx-x86.app.tar.bz2 /FileZilla_Client/3.25.0/FileZilla_3.25.0_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.25.0/FileZilla_3.25.0_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8461936}] 2017-03-13 14:36:41 +0000 UTC false}
	// Release #4: {3.24.1  /FileZilla_Client/3.24.1/FileZilla_3.24.1_macosx-x86.app.tar.bz2 /FileZilla_Client/3.24.1/FileZilla_3.24.1_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.24.1/FileZilla_3.24.1_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8764178}] 2017-02-21 22:00:38 +0000 UTC false}
	// Release #5: {3.24.0  /FileZilla_Client/3.24.0/FileZilla_3.24.0_macosx-x86.app.tar.bz2 /FileZilla_Client/3.24.0/FileZilla_3.24.0_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.24.0/FileZilla_3.24.0_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8765941}] 2017-01-13 20:20:31 +0000 UTC false}
}

// ExampleGitHubAtomFeed demonstrates the loading and parsing of the
// "Github Atom Feed" appcast.
func Example_gitHubAtomFeed() {
	// mock the request
	content := string(getTestdata("example_github.xml"))
	httpmock.ActivateNonDefault(DefaultClient.HTTPClient)
	httpmock.RegisterResponder("GET", "https://github.com/atom/atom/releases.atom", httpmock.NewStringResponder(200, content))
	defer httpmock.DeactivateAndReset()

	// example
	a := New()
	a.LoadFromURL("https://github.com/atom/atom/releases.atom")
	a.GenerateChecksum(SHA256)
	a.ExtractReleases()

	fmt.Println("Checksum:", a.GetChecksum())
	fmt.Println("Provider:", a.Provider)

	for i, release := range a.Releases {
		fmt.Println(fmt.Sprintf("Release #%d:", i+1), release.Version, release.Title, release.PublishedDateTime, release.IsPrerelease)
	}

	fmt.Println("Release #1 description:", a.Releases[0].Description)

	// Output:
	// Checksum: 14dd5fa8a4f880ae7c441e2fc940516e9d50b23fa110277d7696a35380cdb102
	// Provider: GitHub Atom Feed
	// Release #1: 1.18.0-beta2 1.18.0-beta2 2017-05-25 20:39:10 +0000 UTC true
	// Release #2: 1.17.2 1.17.2 2017-05-25 20:38:59 +0000 UTC false
	// Release #3: 1.18.0-beta1 1.18.0-beta1 2017-05-24 22:32:31 +0000 UTC true
	// Release #4: 1.17.1 1.17.1 2017-05-24 22:40:15 +0000 UTC false
	// Release #5: 1.18.0-beta0 1.18.0-beta0 2017-05-16 16:41:06 +0000 UTC true
	// Release #6: 1.17.0 1.17.0 2017-05-16 16:41:24 +0000 UTC false
	// Release #7: 1.17.0-beta5 1.17.0-beta5 2017-05-05 15:53:16 +0000 UTC true
	// Release #8: 1.17.0-beta4 1.17.0-beta4 2017-04-26 20:51:47 +0000 UTC true
	// Release #9: 1.17.0-beta3 1.17.0-beta3 2017-04-18 20:20:32 +0000 UTC true
	// Release #10: 1.17.0-beta2 1.17.0-beta2 2017-04-14 16:28:23 +0000 UTC true
	// Release #1 description:
Fixes Find in current buffer' returns no results - atom/find-and-replace#901

}
<commit_msg>Use GetProvider() in examples<commit_after>package appcast

import (
	"fmt"

	"gopkg.in/jarcoal/httpmock.v1"
)

// ExampleSparkleRSSFeed demonstrates the loading and parsing of the "Sparkle
// RSS Feed" appcast.
func Example_sparkleRSSFeed() {
	// mock the request
	content := string(getTestdata("example_sparkle.xml"))
	httpmock.ActivateNonDefault(DefaultClient.HTTPClient)
	httpmock.RegisterResponder("GET", "https://www.adium.im/sparkle/appcast-release.xml", httpmock.NewStringResponder(200, content))
	defer httpmock.DeactivateAndReset()

	// example
	a := New()
	a.LoadFromURL("https://www.adium.im/sparkle/appcast-release.xml")
	a.GenerateChecksum(SHA256)
	a.ExtractReleases()
	a.SortReleasesByVersions(DESC)

	fmt.Println("Checksum:", a.GetChecksum())
	fmt.Println("Provider:", a.GetProvider())

	for i, release := range a.Releases {
		fmt.Println(fmt.Sprintf("Release #%d:", i+1), release)
	}

	// Output:
	// Checksum: 6ec7c5abcaa78457cc4bf3c2196584446cca1461c65505cbaf0382a2f62128db
	// Provider: Sparkle RSS Feed
	// Release #1: {1.5.10.4 1.5.10.4 Adium 1.5.10.4  [{https://adiumx.cachefly.net/Adium_1.5.10.4.dmg application/octet-stream 21140435}] 2017-05-14 12:04:01 +0000 UTC false}
	// Release #2: {1.5.10 1.5.10 Adium 1.5.10  [{https://adiumx.cachefly.net/Adium_1.5.10.dmg application/octet-stream 24595712}] 2014-05-19 21:25:14 +0000 UTC false}
	// Release #3: {1.4.5 1.4.5 Adium 1.4.5  [{https://adiumx.cachefly.net/Adium_1.4.5.dmg application/octet-stream 23065688}] 2012-03-20 20:30:00 +0000 UTC false}
	// Release #4: {1.3.10 1.3.10 Adium 1.3.10  [{https://adiumx.cachefly.net/Adium_1.3.10.dmg application/octet-stream 22369877}] 2010-01-12 23:30:00 +0000 UTC false}
	// Release #5: {1.0.6 1.0.6 Adium 1.0.6  [{https://adiumx.cachefly.net/Adium_1.0.6.dmg application/octet-stream 13795246}] 2007-08-13 22:12:45 +0000 UTC false}
}

// ExampleSourceForgeRSSFeed demonstrates the loading and parsing of the
// "SourceForge RSS Feed" appcast.
func Example_sourceForgeRSSFeed() {
	// mock the request
	content := string(getTestdata("example_sourceforge.xml"))
	httpmock.ActivateNonDefault(DefaultClient.HTTPClient)
	httpmock.RegisterResponder("GET", "https://sourceforge.net/projects/filezilla/rss", httpmock.NewStringResponder(200, content))
	defer httpmock.DeactivateAndReset()

	// example
	a := New()
	a.LoadFromURL("https://sourceforge.net/projects/filezilla/rss")
	a.GenerateChecksum(SHA256)
	a.ExtractReleases()

	// apply some filters
	a.FilterReleasesByMediaType("application/x-bzip2")
	a.FilterReleasesByTitle("FileZilla_Client_Unstable", true)
	a.FilterReleasesByURL("macosx")
	defer a.ResetFilters() // reset

	fmt.Println("Checksum:", a.GetChecksum())
	fmt.Println("Provider:", a.GetProvider())

	for i, release := range a.Releases {
		fmt.Println(fmt.Sprintf("Release #%d:", i+1), release)
	}

	// Output:
	// Checksum: 69886b91a041ce9d742218a77317cd99f87a14199c3f8ba094042dd9d430f7fd
	// Provider: SourceForge RSS Feed
	// Release #1: {3.25.2  /FileZilla_Client/3.25.2/FileZilla_3.25.2_macosx-x86.app.tar.bz2 /FileZilla_Client/3.25.2/FileZilla_3.25.2_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.25.2/FileZilla_3.25.2_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8453714}] 2017-04-30 12:07:25 +0000 UTC false}
	// Release #2: {3.25.1  /FileZilla_Client/3.25.1/FileZilla_3.25.1_macosx-x86.app.tar.bz2 /FileZilla_Client/3.25.1/FileZilla_3.25.1_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.25.1/FileZilla_3.25.1_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8460741}] 2017-03-20 17:11:09 +0000 UTC false}
	// Release #3: {3.25.0  /FileZilla_Client/3.25.0/FileZilla_3.25.0_macosx-x86.app.tar.bz2 /FileZilla_Client/3.25.0/FileZilla_3.25.0_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.25.0/FileZilla_3.25.0_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8461936}] 2017-03-13 14:36:41 +0000 UTC false}
	// Release #4: {3.24.1  /FileZilla_Client/3.24.1/FileZilla_3.24.1_macosx-x86.app.tar.bz2 /FileZilla_Client/3.24.1/FileZilla_3.24.1_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.24.1/FileZilla_3.24.1_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8764178}] 2017-02-21 22:00:38 +0000 UTC false}
	// Release #5: {3.24.0  /FileZilla_Client/3.24.0/FileZilla_3.24.0_macosx-x86.app.tar.bz2 /FileZilla_Client/3.24.0/FileZilla_3.24.0_macosx-x86.app.tar.bz2 [{https://sourceforge.net/projects/filezilla/files/FileZilla_Client/3.24.0/FileZilla_3.24.0_macosx-x86.app.tar.bz2/download application/x-bzip2; charset=binary 8765941}] 2017-01-13 20:20:31 +0000 UTC false}
}

// ExampleGitHubAtomFeed demonstrates the loading and parsing of the
// "Github Atom Feed" appcast.
func Example_gitHubAtomFeed() {
	// mock the request
	content := string(getTestdata("example_github.xml"))
	httpmock.ActivateNonDefault(DefaultClient.HTTPClient)
	httpmock.RegisterResponder("GET", "https://github.com/atom/atom/releases.atom", httpmock.NewStringResponder(200, content))
	defer httpmock.DeactivateAndReset()

	// example
	a := New()
	a.LoadFromURL("https://github.com/atom/atom/releases.atom")
	a.GenerateChecksum(SHA256)
	a.ExtractReleases()

	fmt.Println("Checksum:", a.GetChecksum())
	fmt.Println("Provider:", a.GetProvider())

	for i, release := range a.Releases {
		fmt.Println(fmt.Sprintf("Release #%d:", i+1), release.Version, release.Title, release.PublishedDateTime, release.IsPrerelease)
	}

	fmt.Println("Release #1 description:", a.Releases[0].Description)

	// Output:
	// Checksum: 14dd5fa8a4f880ae7c441e2fc940516e9d50b23fa110277d7696a35380cdb102
	// Provider: GitHub Atom Feed
	// Release #1: 1.18.0-beta2 1.18.0-beta2 2017-05-25 20:39:10 +0000 UTC true
	// Release #2: 1.17.2 1.17.2 2017-05-25 20:38:59 +0000 UTC false
	// Release #3: 1.18.0-beta1 1.18.0-beta1 2017-05-24 22:32:31 +0000 UTC true
	// Release #4: 1.17.1 1.17.1 2017-05-24 22:40:15 +0000 UTC false
	// Release #5: 1.18.0-beta0 1.18.0-beta0 2017-05-16 16:41:06 +0000 UTC true
	// Release #6: 1.17.0 1.17.0 2017-05-16 16:41:24 +0000 UTC false
	// Release #7: 1.17.0-beta5 1.17.0-beta5 2017-05-05 15:53:16 +0000 UTC true
	// Release #8: 1.17.0-beta4 1.17.0-beta4 2017-04-26 20:51:47 +0000 UTC true
	// Release #9: 1.17.0-beta3 1.17.0-beta3 2017-04-18 20:20:32 +0000 UTC true
	// Release #10: 1.17.0-beta2 1.17.0-beta2 2017-04-14 16:28:23 +0000 UTC true
	// Release #1 description:
Fixes Find in current buffer' returns no results - atom/find-and-replace#901

}
<|endoftext|>


<commit_before>package rest_layer

import (
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/rs/cors"
	"github.com/rs/rest-layer-mem"
	"github.com/rs/rest-layer/resource"
	"github.com/rs/rest-layer/rest"
	"github.com/rs/rest-layer/schema"
	"github.com/rs/xaccess"
	"github.com/rs/xhandler"
	"github.com/rs/xlog"
)

func Example() {
	var (
		// Define a user resource schema
		user = schema.Schema{
			"id": schema.Field{
				Required: true,
				// When a field is read-only, on default values or hooks can
				// set their value. The client can't change it.
				ReadOnly: true,
				// This is a field hook called when a new user is created.
				// The schema.NewID hook is a provided hook to generate a
				// unique id when no value is provided.
				OnInit: &schema.NewID,
				// The Filterable and Sortable allows usage of filter and sort
				// on this field in requests.
				Filterable: true,
				Sortable:   true,
				Validator: &schema.String{
					Regexp: "^[0-9a-f]{32}$",
				},
			},
			"created": schema.Field{
				Required:   true,
				ReadOnly:   true,
				Filterable: true,
				Sortable:   true,
				OnInit:     &schema.Now,
				Validator:  &schema.Time{},
			},
			"updated": schema.Field{
				Required:   true,
				ReadOnly:   true,
				Filterable: true,
				Sortable:   true,
				OnInit:     &schema.Now,
				// The OnUpdate hook is called when the item is edited. Here we use
				// provided Now hook which just return the current time.
				OnUpdate:  &schema.Now,
				Validator: &schema.Time{},
			},
			// Define a name field as required with a string validator
			"name": schema.Field{
				Required:   true,
				Filterable: true,
				Validator: &schema.String{
					MaxLen: 150,
				},
			},
		}

		// Define a post resource schema
		post = schema.Schema{
			// schema.*Field are shortcuts for common fields (identical to users' same fields)
			"id":      schema.IDField,
			"created": schema.CreatedField,
			"updated": schema.UpdatedField,
			// Define a user field which references the user owning the post.
			// See bellow, the content of this field is enforced by the fact
			// that posts is a sub-resource of users.
			"user": schema.Field{
				Required:   true,
				Filterable: true,
				Validator: &schema.Reference{
					Path: "users",
				},
			},
			"public": schema.Field{
				Filterable: true,
				Validator:  &schema.Bool{},
			},
			// Sub-documents are handled via a sub-schema
			"meta": schema.Field{
				Schema: &schema.Schema{
					"title": schema.Field{
						Required: true,
						Validator: &schema.String{
							MaxLen: 150,
						},
					},
					"body": schema.Field{
						Validator: &schema.String{
							MaxLen: 100000,
						},
					},
				},
			},
		}
	)

	// Create a REST API root resource
	index := resource.NewIndex()

	// Add a resource on /users[/:user_id]
	users := index.Bind("users", resource.New(user, mem.NewHandler(), resource.Conf{
		// We allow all REST methods
		// (rest.ReadWrite is a shortcut for []rest.Mode{Create, Read, Update, Delete, List})
		AllowedModes: resource.ReadWrite,
	}))

	// Bind a sub resource on /users/:user_id/posts[/:post_id]
	// and reference the user on each post using the "user" field of the posts resource.
	posts := users.Bind("posts", "user", resource.New(post, mem.NewHandler(), resource.Conf{
		// Posts can only be read, created and deleted, not updated
		AllowedModes: []resource.Mode{resource.Read, resource.List, resource.Create, resource.Delete},
	}))

	// Add a friendly alias to public posts
	// (equivalent to /users/:user_id/posts?filter={"public":true})
	posts.Alias("public", url.Values{"filter": []string{"{\"public\"=true}"}})

	// Create API HTTP handler for the resource graph
	api, err := rest.NewHandler(index)
	if err != nil {
		log.Fatalf("Invalid API configuration: %s", err)
	}

	// Init a xhandler chain (see https://github.com/rs/xhandler)
	c := xhandler.Chain{}

	// Add close notifier handler so context is cancelled when the client closes
	// the connection
	c.UseC(xhandler.CloseHandler)

	// Add timeout handler
	c.UseC(xhandler.TimeoutHandler(2 * time.Second))

	// Install a logger (see https://github.com/rs/xlog)
	c.UseC(xlog.NewHandler(xlog.Config{}))

	// Log API access
	c.UseC(xaccess.NewHandler())

	// Add CORS support with passthrough option on so rest-layer can still
	// handle OPTIONS method
	c.UseC(cors.New(cors.Options{OptionsPassthrough: true}).HandlerC)

	// Bind the API under /api/ path
	http.Handle("/api/", http.StripPrefix("/api/", c.Handler(api)))

	// Serve it
	log.Print("Serving API on http://localhost:8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Fix package name<commit_after>package restlayer

import (
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/rs/cors"
	"github.com/rs/rest-layer-mem"
	"github.com/rs/rest-layer/resource"
	"github.com/rs/rest-layer/rest"
	"github.com/rs/rest-layer/schema"
	"github.com/rs/xaccess"
	"github.com/rs/xhandler"
	"github.com/rs/xlog"
)

func Example() {
	var (
		// Define a user resource schema
		user = schema.Schema{
			"id": schema.Field{
				Required: true,
				// When a field is read-only, on default values or hooks can
				// set their value. The client can't change it.
				ReadOnly: true,
				// This is a field hook called when a new user is created.
				// The schema.NewID hook is a provided hook to generate a
				// unique id when no value is provided.
				OnInit: &schema.NewID,
				// The Filterable and Sortable allows usage of filter and sort
				// on this field in requests.
				Filterable: true,
				Sortable:   true,
				Validator: &schema.String{
					Regexp: "^[0-9a-f]{32}$",
				},
			},
			"created": schema.Field{
				Required:   true,
				ReadOnly:   true,
				Filterable: true,
				Sortable:   true,
				OnInit:     &schema.Now,
				Validator:  &schema.Time{},
			},
			"updated": schema.Field{
				Required:   true,
				ReadOnly:   true,
				Filterable: true,
				Sortable:   true,
				OnInit:     &schema.Now,
				// The OnUpdate hook is called when the item is edited. Here we use
				// provided Now hook which just return the current time.
				OnUpdate:  &schema.Now,
				Validator: &schema.Time{},
			},
			// Define a name field as required with a string validator
			"name": schema.Field{
				Required:   true,
				Filterable: true,
				Validator: &schema.String{
					MaxLen: 150,
				},
			},
		}

		// Define a post resource schema
		post = schema.Schema{
			// schema.*Field are shortcuts for common fields (identical to users' same fields)
			"id":      schema.IDField,
			"created": schema.CreatedField,
			"updated": schema.UpdatedField,
			// Define a user field which references the user owning the post.
			// See bellow, the content of this field is enforced by the fact
			// that posts is a sub-resource of users.
			"user": schema.Field{
				Required:   true,
				Filterable: true,
				Validator: &schema.Reference{
					Path: "users",
				},
			},
			"public": schema.Field{
				Filterable: true,
				Validator:  &schema.Bool{},
			},
			// Sub-documents are handled via a sub-schema
			"meta": schema.Field{
				Schema: &schema.Schema{
					"title": schema.Field{
						Required: true,
						Validator: &schema.String{
							MaxLen: 150,
						},
					},
					"body": schema.Field{
						Validator: &schema.String{
							MaxLen: 100000,
						},
					},
				},
			},
		}
	)

	// Create a REST API root resource
	index := resource.NewIndex()

	// Add a resource on /users[/:user_id]
	users := index.Bind("users", resource.New(user, mem.NewHandler(), resource.Conf{
		// We allow all REST methods
		// (rest.ReadWrite is a shortcut for []rest.Mode{Create, Read, Update, Delete, List})
		AllowedModes: resource.ReadWrite,
	}))

	// Bind a sub resource on /users/:user_id/posts[/:post_id]
	// and reference the user on each post using the "user" field of the posts resource.
	posts := users.Bind("posts", "user", resource.New(post, mem.NewHandler(), resource.Conf{
		// Posts can only be read, created and deleted, not updated
		AllowedModes: []resource.Mode{resource.Read, resource.List, resource.Create, resource.Delete},
	}))

	// Add a friendly alias to public posts
	// (equivalent to /users/:user_id/posts?filter={"public":true})
	posts.Alias("public", url.Values{"filter": []string{"{\"public\"=true}"}})

	// Create API HTTP handler for the resource graph
	api, err := rest.NewHandler(index)
	if err != nil {
		log.Fatalf("Invalid API configuration: %s", err)
	}

	// Init a xhandler chain (see https://github.com/rs/xhandler)
	c := xhandler.Chain{}

	// Add close notifier handler so context is cancelled when the client closes
	// the connection
	c.UseC(xhandler.CloseHandler)

	// Add timeout handler
	c.UseC(xhandler.TimeoutHandler(2 * time.Second))

	// Install a logger (see https://github.com/rs/xlog)
	c.UseC(xlog.NewHandler(xlog.Config{}))

	// Log API access
	c.UseC(xaccess.NewHandler())

	// Add CORS support with passthrough option on so rest-layer can still
	// handle OPTIONS method
	c.UseC(cors.New(cors.Options{OptionsPassthrough: true}).HandlerC)

	// Bind the API under /api/ path
	http.Handle("/api/", http.StripPrefix("/api/", c.Handler(api)))

	// Serve it
	log.Print("Serving API on http://localhost:8080")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Matthew Collins
//
// 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 render

import (
	"github.com/thinkofdeath/steven/platform/gl"
	"github.com/thinkofdeath/steven/type/direction"
)

var (
	buffers       = make(map[position]*ChunkBuffer)
	bufferColumns = make(map[positionC]int)
)

// ChunkBuffer is a renderable chunk section
type ChunkBuffer struct {
	position

	array    gl.VertexArray
	buffer   gl.Buffer
	count    int
	arrayT   gl.VertexArray
	bufferT  gl.Buffer
	countT   int
	cullBits uint64

	renderedOn uint
}

func (cb *ChunkBuffer) IsVisible(from, to direction.Type) bool {
	return (cb.cullBits & (1 << (from*6 + to))) != 0
}

// AllocateChunkBuffer allocates a chunk buffer and adds it to the
// render list.
func AllocateChunkBuffer(x, y, z int) *ChunkBuffer {
	c := &ChunkBuffer{
		position: position{X: x, Y: y, Z: z},
		array:    gl.CreateVertexArray(),
		buffer:   gl.CreateBuffer(),
		arrayT:   gl.CreateVertexArray(),
		bufferT:  gl.CreateBuffer(),
	}
	buffers[c.position] = c
	bufferColumns[positionC{x, z}]++
	return c
}

// Upload uploads the passed vertex data to the buffer.
func (cb *ChunkBuffer) Upload(data []byte, count int, cullBits uint64) {
	chunkProgram.Use()
	cb.cullBits = cullBits
	cb.array.Bind()
	cb.buffer.Bind(gl.ArrayBuffer)
	cb.buffer.Data(data, gl.DynamicDraw)
	shaderChunk.Position.Enable()
	shaderChunk.TextureInfo.Enable()
	shaderChunk.TextureOffset.Enable()
	shaderChunk.Color.Enable()
	shaderChunk.Lighting.Enable()

	cb.buffer.Bind(gl.ArrayBuffer)
	shaderChunk.Position.PointerInt(3, gl.Short, 23, 0)
	shaderChunk.TextureInfo.Pointer(4, gl.UnsignedShort, false, 23, 6)
	shaderChunk.TextureOffset.Pointer(2, gl.Short, false, 23, 14)
	shaderChunk.Color.Pointer(3, gl.UnsignedByte, true, 23, 18)
	shaderChunk.Lighting.Pointer(2, gl.UnsignedByte, false, 23, 21)

	cb.count = count
}

// UploadTrans uploads the passed vertex data to the translucent buffer.
func (cb *ChunkBuffer) UploadTrans(data []byte, count int) {
	chunkProgramT.Use()
	cb.arrayT.Bind()
	cb.bufferT.Bind(gl.ArrayBuffer)
	cb.bufferT.Data(data, gl.DynamicDraw)
	shaderChunk.Position.Enable()
	shaderChunk.TextureInfo.Enable()
	shaderChunk.TextureOffset.Enable()
	shaderChunk.Color.Enable()
	shaderChunk.Lighting.Enable()

	cb.bufferT.Bind(gl.ArrayBuffer)
	shaderChunkT.Position.PointerInt(3, gl.Short, 23, 0)
	shaderChunkT.TextureInfo.Pointer(4, gl.UnsignedShort, false, 23, 6)
	shaderChunkT.TextureOffset.Pointer(2, gl.Short, false, 23, 14)
	shaderChunkT.Color.Pointer(3, gl.UnsignedByte, true, 23, 18)
	shaderChunkT.Lighting.Pointer(2, gl.UnsignedByte, false, 23, 21)

	cb.countT = count
}

// Free removes the buffer and frees related resources.
func (cb *ChunkBuffer) Free() {
	delete(buffers, cb.position)
	cpos := positionC{cb.position.X, cb.position.Z}
	val := bufferColumns[cpos]
	val--
	if val <= 0 {
		delete(bufferColumns, cpos)
	} else {
		bufferColumns[cpos] = val
	}

	cb.buffer.Delete()
	cb.array.Delete()
}
<commit_msg>render: fix a buffer leak<commit_after>// Copyright 2015 Matthew Collins
//
// 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 render

import (
	"github.com/thinkofdeath/steven/platform/gl"
	"github.com/thinkofdeath/steven/type/direction"
)

var (
	buffers       = make(map[position]*ChunkBuffer)
	bufferColumns = make(map[positionC]int)
)

// ChunkBuffer is a renderable chunk section
type ChunkBuffer struct {
	position

	array    gl.VertexArray
	buffer   gl.Buffer
	count    int
	arrayT   gl.VertexArray
	bufferT  gl.Buffer
	countT   int
	cullBits uint64

	renderedOn uint
}

func (cb *ChunkBuffer) IsVisible(from, to direction.Type) bool {
	return (cb.cullBits & (1 << (from*6 + to))) != 0
}

// AllocateChunkBuffer allocates a chunk buffer and adds it to the
// render list.
func AllocateChunkBuffer(x, y, z int) *ChunkBuffer {
	c := &ChunkBuffer{
		position: position{X: x, Y: y, Z: z},
		array:    gl.CreateVertexArray(),
		buffer:   gl.CreateBuffer(),
		arrayT:   gl.CreateVertexArray(),
		bufferT:  gl.CreateBuffer(),
	}
	buffers[c.position] = c
	bufferColumns[positionC{x, z}]++
	return c
}

// Upload uploads the passed vertex data to the buffer.
func (cb *ChunkBuffer) Upload(data []byte, count int, cullBits uint64) {
	chunkProgram.Use()
	cb.cullBits = cullBits
	cb.array.Bind()
	shaderChunk.Position.Enable()
	shaderChunk.TextureInfo.Enable()
	shaderChunk.TextureOffset.Enable()
	shaderChunk.Color.Enable()
	shaderChunk.Lighting.Enable()

	cb.buffer.Bind(gl.ArrayBuffer)
	cb.buffer.Data(data, gl.DynamicDraw)
	shaderChunk.Position.PointerInt(3, gl.Short, 23, 0)
	shaderChunk.TextureInfo.Pointer(4, gl.UnsignedShort, false, 23, 6)
	shaderChunk.TextureOffset.Pointer(2, gl.Short, false, 23, 14)
	shaderChunk.Color.Pointer(3, gl.UnsignedByte, true, 23, 18)
	shaderChunk.Lighting.Pointer(2, gl.UnsignedByte, false, 23, 21)

	cb.count = count
}

// UploadTrans uploads the passed vertex data to the translucent buffer.
func (cb *ChunkBuffer) UploadTrans(data []byte, count int) {
	chunkProgramT.Use()
	cb.arrayT.Bind()
	shaderChunk.Position.Enable()
	shaderChunk.TextureInfo.Enable()
	shaderChunk.TextureOffset.Enable()
	shaderChunk.Color.Enable()
	shaderChunk.Lighting.Enable()

	cb.bufferT.Bind(gl.ArrayBuffer)
	cb.bufferT.Data(data, gl.DynamicDraw)
	shaderChunkT.Position.PointerInt(3, gl.Short, 23, 0)
	shaderChunkT.TextureInfo.Pointer(4, gl.UnsignedShort, false, 23, 6)
	shaderChunkT.TextureOffset.Pointer(2, gl.Short, false, 23, 14)
	shaderChunkT.Color.Pointer(3, gl.UnsignedByte, true, 23, 18)
	shaderChunkT.Lighting.Pointer(2, gl.UnsignedByte, false, 23, 21)

	cb.countT = count
}

// Free removes the buffer and frees related resources.
func (cb *ChunkBuffer) Free() {
	delete(buffers, cb.position)
	cpos := positionC{cb.position.X, cb.position.Z}
	val := bufferColumns[cpos]
	val--
	if val <= 0 {
		delete(bufferColumns, cpos)
	} else {
		bufferColumns[cpos] = val
	}

	cb.buffer.Delete()
	cb.array.Delete()
	cb.bufferT.Delete()
	cb.arrayT.Delete()
}
<|endoftext|>