<commit_before>/*
Client connection.

Allow to make simultaneous requests through the one TCP connection.
Reconnects to the server on network failures.

Author: Aleksey Morarash <aleksey.morarash@gmail.com>
Since: 4 Sep 2016
Copyright: 2016, Aleksey Morarash <aleksey.morarash@gmail.com>
*/

package tcpcall

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"sync"
	"sync/atomic"
	"tcpcall/pools"
	"tcpcall/proto"
	"time"
)

// Client counter indices.
// See Client.counters field and Client.Counters()
// method description for details.
const (
	// How many times Req*() methods were called
	CC_REQUESTS = iota
	// How many times requests failed due to connection
	// concurrency overrun
	CC_OVERLOADS
	// How many times requests were not sent due to network errors
	CC_REQUEST_SEND_FAILS
	// How many valid replies were received for
	// sent requests.
	CC_REPLIES
	// How many times requests were timeouted waiting
	// for reply
	CC_TIMEOUTS
	// How many times Cast*() methods were called
	CC_CASTS
	// How many times casts were not sent due to network errors
	CC_CAST_SEND_FAILS
	// How many times client was connected to the server
	CC_CONNECTS
	// How many times client was disconnected from the server
	CC_DISCONNECTS
	// Count of invalid packets received
	CC_BAD_PACKETS
	// Count of reply packets received
	CC_REPLY_PACKETS
	// Count of reply packets with error reason received
	CC_ERROR_PACKETS
	// Count of suspend packets received
	CC_SUSPEND_PACKETS
	// Count of resume packets received
	CC_RESUME_PACKETS
	// Count of uplink cast packets received
	CC_UCAST_PACKETS
	CC_COUNT // special value - count of all counters
)

type RRegistry map[uint32]*RREntry

type RREntry struct {
	Deadline time.Time
	Chan     chan RRReply
}

type RRReply struct {
	Reply [][]byte
	Error [][]byte
}

// Connection state.
type Client struct {
	// address of the remote server to connect to
	peer string
	// client configuration
	config ClientConf
	// list of issued pending requests
	registry   RRegistry
	registryMu sync.Mutex
	// message oriented network socket
	socket *MsgConn
	// channel for disconnection events
	closeChan chan bool
	// set to truth on client termination
	closed bool
	// Counters array
	counters []*int64
}

// Connection configuration.
type ClientConf struct {
	// Maximum parallel requests for the connection.
	Concurrency int
	// Sleep duration before reconnect after connection failure.
	ReconnectPeriod time.Duration
	// Max reply packet size, in bytes. 0 means no limit.
	MaxReplySize int
	// Minimum flush period for socket writer
	MinFlushPeriod time.Duration
	// Socket write buffer size
	WriteBufferSize int
	// Channel to send state events (connected/disconnected).
	StateListener chan StateEvent
	// Channel to send 'suspend' events.
	SuspendListener chan SuspendEvent
	// Channel to send 'resume' events.
	ResumeListener chan ResumeEvent
	// Channel to send Uplink Cast data.
	UplinkCastListener chan UplinkCastEvent
	// If true, Dial() function will attempt to connect to the
	// server before returning. Default is true.
	SyncConnect bool
	// Enable default logging or not.
	Trace bool
}

// Client instance information returned by Info() method.
// Added mostly for debugging.
type ClientInfo struct {
	// Configuration used to create Client instance
	Config ClientConf
	// Remote side address and port number
	Peer string
	// Truth if client is currently connected to the server
	Connected bool
	// Counters array
	Counters []int
}

// Connection state event.
type StateEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// If true - client just have been connected to the server.
	// If false - disconnected.
	Online bool
}

// Sent when 'suspend' signal from server received.
type SuspendEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// Requested suspend duration
	Duration time.Duration
}

// Sent when 'resume' signal from server received.
type ResumeEvent struct {
	// Pointer to the client connection state.
	Sender *Client
}

// Sent when uplink cast data received from server.
type UplinkCastEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	Data   []byte
}

var (
	replyPool = sync.Pool{New: func() interface{} {
		return make(chan RRReply, 1)
	}}
)

// Connect to server side.
// Return non nil error only when ClientConf.SyncConnect
// option is set to truth and initial connection failed.
// Regardless error value, returned Client instance is valid
// for further operation. It will connect to the server
// eventually (of course, if server will became available with time).
// If you dont want to use created Client instance in case
// when error != nil, you must call Close() method.
func Dial(dst string, conf ClientConf) (*Client, error) {
	c := &Client{
		peer:      dst,
		config:    conf,
		registry:  RRegistry{},
		closeChan: make(chan bool, 50),
		counters:  make([]*int64, CC_COUNT),
	}
	for i := 0; i < CC_COUNT; i++ {
		var v int64
		c.counters[i] = &v
	}
	var err error
	if conf.SyncConnect {
		err = c.connect()
	}
	go c.connectLoop()
	return c, err
}

// Create default client configuration
func NewClientConf() ClientConf {
	return ClientConf{
		Concurrency:     defConcurrency,
		ReconnectPeriod: time.Millisecond * 100,
		MinFlushPeriod:  defMinFlush,
		WriteBufferSize: defWBufSize,
		SyncConnect:     true,
		Trace:           traceClient,
	}
}

// Make synchronous request to the server.
func (c *Client) Req(payload []byte, timeout time.Duration) ([]byte, error) {
	var bts [][]byte
	select {
	case bts = <-bChan:
		bts[0] = payload
	default:
		bts = [][]byte{payload}
	}
	return c.ReqChunks(bts[:1], timeout)
}

// Make synchronous request to the server.
func (c *Client) ReqChunks(payload [][]byte, timeout time.Duration) ([]byte, error) {
	c.hit(CC_REQUESTS)
	entry := &RREntry{
		Deadline: time.Now().Add(timeout),
		Chan:     replyPool.Get().(chan RRReply),
	}
	if len(entry.Chan) > 0 {
		<-entry.Chan
	}
	req := proto.NewRequest(payload, entry.Deadline)
	encoded := req.Encode()

	for i := range payload {
		payload[i] = nil
	}
	select {
	case bChan <- payload:
	default:
	}

	// queue
	c.registryMu.Lock()
	if c.config.Concurrency <= len(c.registry) {
		c.registryMu.Unlock()
		c.hit(CC_OVERLOADS)
		return nil, OverloadError
	}
	// as far as seqnum is uint32, we'll do no checks
	// for seqnum collision here. It's unlikely someone
	// will use concurrency greater than 2^32 to make
	// such collisions possible.
	c.registry[req.SeqNum] = entry
	c.registryMu.Unlock()
	defer c.popRegistry(req.SeqNum)
	// send through the network
	if err := c.socket.Send(encoded); err != nil {
		c.hit(CC_REQUEST_SEND_FAILS)
		pools.AppendToBuffer(encoded[0])
		if err == MsgConnNotConnectedError {
			return nil, NotConnectedError
		}
		return nil, DisconnectedError
	}
	c.log("req sent")
	pools.AppendToBuffer(encoded[0])
	// wait for the response
	after := pools.GetFreeTimer(entry.Deadline.Sub(time.Now()))
	select {
	case reply := <-entry.Chan:
		c.hit(CC_REPLIES)
		replyPool.Put(entry.Chan)
		if reply.Error == nil {
			pools.AppendToTimer(after)
			return bytes.Join(reply.Reply, []byte{}), nil
		}
		pools.AppendToTimer(after)
		return nil, RemoteCrashedError
	case <-after.C:
		c.hit(CC_TIMEOUTS)
		replyPool.Put(entry.Chan)
		return nil, TimeoutError
	}
}

// Make asynchronous request to the server.
func (c *Client) Cast(data []byte) error {
	return c.CastChunks([][]byte{data})
}

// Make asynchronous request to the server.
func (c *Client) CastChunks(data [][]byte) error {
	c.hit(CC_CASTS)
	encoded := proto.NewCast(data).Encode()
	if err := c.socket.Send(encoded); err != nil {
		c.hit(CC_CAST_SEND_FAILS)
		pools.AppendToBuffer(encoded[0])
		return err
	}
	c.log("cast sent")
	pools.AppendToBuffer(encoded[0])
	return nil
}

// GetQueuedRequests function return total count of requests being
// processed right now.
func (c *Client) GetQueuedRequests() int {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	return len(c.registry)
}

// Return client's info and stats.
func (c *Client) Info() ClientInfo {
	return ClientInfo{
		Config:    c.config,
		Peer:      c.peer,
		Connected: c.socket != nil && !c.socket.Closed(),
		Counters:  c.Counters(),
	}
}

// Return a snapshot of all internal counters.
func (c *Client) Counters() []int {
	res := make([]int, CC_COUNT)
	for i, v := range c.counters {
		res[i] = int(atomic.LoadInt64(v))
	}
	return res
}

// Thread safe counter increment.
func (c *Client) hit(counter int) {
	atomic.AddInt64(c.counters[counter], 1)
}

// Connect (or reconnect) to the server.
func (c *Client) connect() error {
	c.disconnect()
	conn, err := net.Dial("tcp", c.peer)
	if err == nil {
		atomic.AddInt64(c.counters[CC_CONNECTS], 1)
		c.log("connected")
		msgConn, err := NewMsgConn(conn, c.config.MinFlushPeriod,
			c.config.WriteBufferSize,
			c.handlePacket, c.notifyClose)
		if err != nil {
			return err
		}
		msgConn.MaxPacketLen = c.config.MaxReplySize
		c.socket = msgConn
		c.notifyPool(true)
	} else {
		c.log("failed to connect: %s", err)
	}
	return err
}

// Terminate the client.
func (c *Client) Close() {
	c.log("closing...")
	c.closed = true
	c.disconnect()
	c.log("closed")
}

// Close connection to server.
func (c *Client) disconnect() {
	if c.socket == nil || c.socket.Closed() {
		return
	}
	c.socket.Close()
	c.notifyClose()
	// discard all pending requests
	c.registryMu.Lock()
	for _, entry := range c.registry {
		select {
		case entry.Chan <- RRReply{nil, [][]byte{[]byte("disconnected")}}:
		default:
		}
	}
	c.registry = RRegistry{}
	c.registryMu.Unlock()
	c.log("disconnected")
	c.hit(CC_DISCONNECTS)
}

// Goroutine.
// Reconnects on network errors.
func (c *Client) connectLoop() {
	c.log("daemon started")
	defer c.log("daemon terminated")
	for !c.closed {
		if c.socket == nil || c.socket.Closed() {
			if err := c.connect(); err != nil {
				time.Sleep(c.config.ReconnectPeriod)
				continue
			}
		}
		<-c.closeChan
	}
}

// Send 'connection closed' notification to the client daemon.
func (c *Client) notifyClose() {
	c.notifyPool(false)
	c.closeChan <- true
}

// Send connection state change notification to Client owner
func (c *Client) notifyPool(connected bool) {
	if c.config.StateListener != nil && !c.closed {
		after := pools.GetFreeTimer(time.Second / 5)
		select {
		case c.config.StateListener <- StateEvent{c, connected}:
		case <-after.C:
		}
		pools.AppendToTimer(after)
	}
}

// Callback for message-oriented socket.
// Handle message received from the remote peer.
func (c *Client) handlePacket(packet []byte) {
	ptype, payload, err := proto.Decode(packet)
	c.log("decoded packet_type=%d; data=%v; err=%s", ptype, payload, err)
	if err != nil {
		// close connection on bad packet receive
		c.log("decode failed: %s", err)
		c.hit(CC_BAD_PACKETS)
		c.disconnect()
		return
	}
	switch ptype {
	case proto.REPLY:
		c.hit(CC_REPLY_PACKETS)
		p := payload.(*proto.PacketReply)
		if entry, ok := c.popRegistry(p.SeqNum); ok {
			entry.Chan <- RRReply{p.Reply, nil}
		}
		proto.AppendToReply(p)
	case proto.ERROR:
		c.hit(CC_ERROR_PACKETS)
		p := payload.(*proto.PacketError)
		if entry, ok := c.popRegistry(p.SeqNum); ok {
			entry.Chan <- RRReply{nil, p.Reason}
		}
	case proto.FLOW_CONTROL_SUSPEND:
		c.hit(CC_SUSPEND_PACKETS)
		if c.config.SuspendListener != nil {
			p := payload.(*proto.PacketFlowControlSuspend)
			c.config.SuspendListener <- SuspendEvent{c, p.Duration}
		}
	case proto.FLOW_CONTROL_RESUME:
		c.hit(CC_RESUME_PACKETS)
		if c.config.ResumeListener != nil {
			c.config.ResumeListener <- ResumeEvent{c}
		}
	case proto.UPLINK_CAST:
		c.hit(CC_UCAST_PACKETS)
		if c.config.UplinkCastListener != nil {
			p := payload.(*proto.PacketUplinkCast)
			flat := bytes.Join(p.Data, []byte{})
			c.config.UplinkCastListener <- UplinkCastEvent{c, flat}
		}
	}
}

// Lookup request in the registry and remove it.
func (c *Client) popRegistry(seqnum uint32) (e *RREntry, ok bool) {
	c.registryMu.Lock()
	res, ok := c.registry[seqnum]
	if ok {
		delete(c.registry, seqnum)
	}
	c.registryMu.Unlock()
	return res, ok
}

// Print message to the stdout if verbose mode is enabled.
func (c *Client) log(format string, args ...interface{}) {
	if c.config.Trace {
		prefix := fmt.Sprintf("tcpcall conn %s> ", c.peer)
		log.Printf(prefix+format, args...)
	}
}
<commit_msg>Use return values<commit_after>/*
Client connection.

Allow to make simultaneous requests through the one TCP connection.
Reconnects to the server on network failures.

Author: Aleksey Morarash <aleksey.morarash@gmail.com>
Since: 4 Sep 2016
Copyright: 2016, Aleksey Morarash <aleksey.morarash@gmail.com>
*/

package tcpcall

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"sync"
	"sync/atomic"
	"tcpcall/pools"
	"tcpcall/proto"
	"time"
)

// Client counter indices.
// See Client.counters field and Client.Counters()
// method description for details.
const (
	// How many times Req*() methods were called
	CC_REQUESTS = iota
	// How many times requests failed due to connection
	// concurrency overrun
	CC_OVERLOADS
	// How many times requests were not sent due to network errors
	CC_REQUEST_SEND_FAILS
	// How many valid replies were received for
	// sent requests.
	CC_REPLIES
	// How many times requests were timeouted waiting
	// for reply
	CC_TIMEOUTS
	// How many times Cast*() methods were called
	CC_CASTS
	// How many times casts were not sent due to network errors
	CC_CAST_SEND_FAILS
	// How many times client was connected to the server
	CC_CONNECTS
	// How many times client was disconnected from the server
	CC_DISCONNECTS
	// Count of invalid packets received
	CC_BAD_PACKETS
	// Count of reply packets received
	CC_REPLY_PACKETS
	// Count of reply packets with error reason received
	CC_ERROR_PACKETS
	// Count of suspend packets received
	CC_SUSPEND_PACKETS
	// Count of resume packets received
	CC_RESUME_PACKETS
	// Count of uplink cast packets received
	CC_UCAST_PACKETS
	CC_COUNT // special value - count of all counters
)

type RRegistry map[uint32]*RREntry

type RREntry struct {
	Deadline time.Time
	Chan     chan RRReply
}

type RRReply struct {
	Reply [][]byte
	Error [][]byte
}

// Connection state.
type Client struct {
	// address of the remote server to connect to
	peer string
	// client configuration
	config ClientConf
	// list of issued pending requests
	registry   RRegistry
	registryMu sync.Mutex
	// message oriented network socket
	socket *MsgConn
	// channel for disconnection events
	closeChan chan bool
	// set to truth on client termination
	closed bool
	// Counters array
	counters []*int64
}

// Connection configuration.
type ClientConf struct {
	// Maximum parallel requests for the connection.
	Concurrency int
	// Sleep duration before reconnect after connection failure.
	ReconnectPeriod time.Duration
	// Max reply packet size, in bytes. 0 means no limit.
	MaxReplySize int
	// Minimum flush period for socket writer
	MinFlushPeriod time.Duration
	// Socket write buffer size
	WriteBufferSize int
	// Channel to send state events (connected/disconnected).
	StateListener chan StateEvent
	// Channel to send 'suspend' events.
	SuspendListener chan SuspendEvent
	// Channel to send 'resume' events.
	ResumeListener chan ResumeEvent
	// Channel to send Uplink Cast data.
	UplinkCastListener chan UplinkCastEvent
	// If true, Dial() function will attempt to connect to the
	// server before returning. Default is true.
	SyncConnect bool
	// Enable default logging or not.
	Trace bool
}

// Client instance information returned by Info() method.
// Added mostly for debugging.
type ClientInfo struct {
	// Configuration used to create Client instance
	Config ClientConf
	// Remote side address and port number
	Peer string
	// Truth if client is currently connected to the server
	Connected bool
	// Counters array
	Counters []int
}

// Connection state event.
type StateEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// If true - client just have been connected to the server.
	// If false - disconnected.
	Online bool
}

// Sent when 'suspend' signal from server received.
type SuspendEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// Requested suspend duration
	Duration time.Duration
}

// Sent when 'resume' signal from server received.
type ResumeEvent struct {
	// Pointer to the client connection state.
	Sender *Client
}

// Sent when uplink cast data received from server.
type UplinkCastEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	Data   []byte
}

var (
	replyPool = sync.Pool{New: func() interface{} {
		return make(chan RRReply, 1)
	}}
)

// Connect to server side.
// Return non nil error only when ClientConf.SyncConnect
// option is set to truth and initial connection failed.
// Regardless error value, returned Client instance is valid
// for further operation. It will connect to the server
// eventually (of course, if server will became available with time).
// If you dont want to use created Client instance in case
// when error != nil, you must call Close() method.
func Dial(dst string, conf ClientConf) (*Client, error) {
	c := &Client{
		peer:      dst,
		config:    conf,
		registry:  RRegistry{},
		closeChan: make(chan bool, 50),
		counters:  make([]*int64, CC_COUNT),
	}
	for i := 0; i < CC_COUNT; i++ {
		var v int64
		c.counters[i] = &v
	}
	var err error
	if conf.SyncConnect {
		err = c.connect()
	}
	go c.connectLoop()
	return c, err
}

// Create default client configuration
func NewClientConf() ClientConf {
	return ClientConf{
		Concurrency:     defConcurrency,
		ReconnectPeriod: time.Millisecond * 100,
		MinFlushPeriod:  defMinFlush,
		WriteBufferSize: defWBufSize,
		SyncConnect:     true,
		Trace:           traceClient,
	}
}

// Make synchronous request to the server.
func (c *Client) Req(payload []byte, timeout time.Duration) ([]byte, error) {
	var bts [][]byte
	select {
	case bts = <-bChan:
		bts[0] = payload
	default:
		bts = [][]byte{payload}
	}
	return c.ReqChunks(bts[:1], timeout)
}

// Make synchronous request to the server.
func (c *Client) ReqChunks(payload [][]byte, timeout time.Duration) ([]byte, error) {
	c.hit(CC_REQUESTS)
	entry := &RREntry{
		Deadline: time.Now().Add(timeout),
		Chan:     replyPool.Get().(chan RRReply),
	}
	if len(entry.Chan) > 0 {
		<-entry.Chan
	}
	req := proto.NewRequest(payload, entry.Deadline)
	encoded := req.Encode()

	for i := range payload {
		payload[i] = nil
	}
	select {
	case bChan <- payload:
	default:
	}

	// queue
	c.registryMu.Lock()
	if c.config.Concurrency <= len(c.registry) {
		c.registryMu.Unlock()
		c.hit(CC_OVERLOADS)
		return nil, OverloadError
	}
	// as far as seqnum is uint32, we'll do no checks
	// for seqnum collision here. It's unlikely someone
	// will use concurrency greater than 2^32 to make
	// such collisions possible.
	c.registry[req.SeqNum] = entry
	c.registryMu.Unlock()
	defer c.popRegistry(req.SeqNum)
	// send through the network
	if err := c.socket.Send(encoded); err != nil {
		c.hit(CC_REQUEST_SEND_FAILS)
		pools.AppendToBuffer(encoded[0])
		if err == MsgConnNotConnectedError {
			return nil, NotConnectedError
		}
		return nil, DisconnectedError
	}
	c.log("req sent")
	pools.AppendToBuffer(encoded[0])
	// wait for the response
	after := pools.GetFreeTimer(entry.Deadline.Sub(time.Now()))
	select {
	case reply := <-entry.Chan:
		c.hit(CC_REPLIES)
		replyPool.Put(entry.Chan)
		if reply.Error == nil {
			pools.AppendToTimer(after)
			return bytes.Join(reply.Reply, []byte{}), nil
		}
		pools.AppendToTimer(after)
		return nil, RemoteCrashedError
	case <-after.C:
		c.hit(CC_TIMEOUTS)
		replyPool.Put(entry.Chan)
		return nil, TimeoutError
	}
}

// Make asynchronous request to the server.
func (c *Client) Cast(data []byte) error {
	return c.CastChunks([][]byte{data})
}

// Make asynchronous request to the server.
func (c *Client) CastChunks(data [][]byte) error {
	c.hit(CC_CASTS)
	encoded := proto.NewCast(data).Encode()
	if err := c.socket.Send(encoded); err != nil {
		c.hit(CC_CAST_SEND_FAILS)
		pools.AppendToBuffer(encoded[0])
		return err
	}
	c.log("cast sent")
	pools.AppendToBuffer(encoded[0])
	return nil
}

// GetQueuedRequests function return total count of requests being
// processed right now.
func (c *Client) GetQueuedRequests() int {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	return len(c.registry)
}

// Return client's info and stats.
func (c *Client) Info() ClientInfo {
	return ClientInfo{
		Config:    c.config,
		Peer:      c.peer,
		Connected: c.socket != nil && !c.socket.Closed(),
		Counters:  c.Counters(),
	}
}

// Return a snapshot of all internal counters.
func (c *Client) Counters() []int {
	res := make([]int, CC_COUNT)
	for i, v := range c.counters {
		res[i] = int(atomic.LoadInt64(v))
	}
	return res
}

// Thread safe counter increment.
func (c *Client) hit(counter int) {
	atomic.AddInt64(c.counters[counter], 1)
}

// Connect (or reconnect) to the server.
func (c *Client) connect() error {
	c.disconnect()
	conn, err := net.Dial("tcp", c.peer)
	if err == nil {
		atomic.AddInt64(c.counters[CC_CONNECTS], 1)
		c.log("connected")
		msgConn, err := NewMsgConn(conn, c.config.MinFlushPeriod,
			c.config.WriteBufferSize,
			c.handlePacket, c.notifyClose)
		if err != nil {
			return err
		}
		msgConn.MaxPacketLen = c.config.MaxReplySize
		c.socket = msgConn
		c.notifyPool(true)
	} else {
		c.log("failed to connect: %s", err)
	}
	return err
}

// Terminate the client.
func (c *Client) Close() {
	c.log("closing...")
	c.closed = true
	c.disconnect()
	c.log("closed")
}

// Close connection to server.
func (c *Client) disconnect() {
	if c.socket == nil || c.socket.Closed() {
		return
	}
	c.socket.Close()
	c.notifyClose()
	// discard all pending requests
	c.registryMu.Lock()
	for _, entry := range c.registry {
		select {
		case entry.Chan <- RRReply{nil, [][]byte{[]byte("disconnected")}}:
		default:
		}
	}
	c.registry = RRegistry{}
	c.registryMu.Unlock()
	c.log("disconnected")
	c.hit(CC_DISCONNECTS)
}

// Goroutine.
// Reconnects on network errors.
func (c *Client) connectLoop() {
	c.log("daemon started")
	defer c.log("daemon terminated")
	for !c.closed {
		if c.socket == nil || c.socket.Closed() {
			if err := c.connect(); err != nil {
				time.Sleep(c.config.ReconnectPeriod)
				continue
			}
		}
		<-c.closeChan
	}
}

// Send 'connection closed' notification to the client daemon.
func (c *Client) notifyClose() {
	c.notifyPool(false)
	c.closeChan <- true
}

// Send connection state change notification to Client owner
func (c *Client) notifyPool(connected bool) {
	if c.config.StateListener != nil && !c.closed {
		after := pools.GetFreeTimer(time.Second / 5)
		select {
		case c.config.StateListener <- StateEvent{c, connected}:
		case <-after.C:
		}
		pools.AppendToTimer(after)
	}
}

// Callback for message-oriented socket.
// Handle message received from the remote peer.
func (c *Client) handlePacket(packet []byte) {
	ptype, payload, err := proto.Decode(packet)
	c.log("decoded packet_type=%d; data=%v; err=%s", ptype, payload, err)
	if err != nil {
		// close connection on bad packet receive
		c.log("decode failed: %s", err)
		c.hit(CC_BAD_PACKETS)
		c.disconnect()
		return
	}
	switch ptype {
	case proto.REPLY:
		c.hit(CC_REPLY_PACKETS)
		p := payload.(*proto.PacketReply)
		if entry, ok := c.popRegistry(p.SeqNum); ok {
			entry.Chan <- RRReply{p.Reply, nil}
		}
		proto.AppendToReply(p)
	case proto.ERROR:
		c.hit(CC_ERROR_PACKETS)
		p := payload.(*proto.PacketError)
		if entry, ok := c.popRegistry(p.SeqNum); ok {
			entry.Chan <- RRReply{nil, p.Reason}
		}
	case proto.FLOW_CONTROL_SUSPEND:
		c.hit(CC_SUSPEND_PACKETS)
		if c.config.SuspendListener != nil {
			p := payload.(*proto.PacketFlowControlSuspend)
			c.config.SuspendListener <- SuspendEvent{c, p.Duration}
		}
	case proto.FLOW_CONTROL_RESUME:
		c.hit(CC_RESUME_PACKETS)
		if c.config.ResumeListener != nil {
			c.config.ResumeListener <- ResumeEvent{c}
		}
	case proto.UPLINK_CAST:
		c.hit(CC_UCAST_PACKETS)
		if c.config.UplinkCastListener != nil {
			p := payload.(*proto.PacketUplinkCast)
			flat := bytes.Join(p.Data, []byte{})
			c.config.UplinkCastListener <- UplinkCastEvent{c, flat}
		}
	}
}

// Lookup request in the registry and remove it.
func (c *Client) popRegistry(seqnum uint32) (e *RREntry, ok bool) {
	c.registryMu.Lock()
	e, ok = c.registry[seqnum]
	if ok {
		delete(c.registry, seqnum)
	}
	c.registryMu.Unlock()
	return
}

// Print message to the stdout if verbose mode is enabled.
func (c *Client) log(format string, args ...interface{}) {
	if c.config.Trace {
		prefix := fmt.Sprintf("tcpcall conn %s> ", c.peer)
		log.Printf(prefix+format, args...)
	}
}
<|endoftext|>


<commit_before>// Dynamic weighted round robin load balancer
package roundrobin

import (
	"fmt"
	log "github.com/mailgun/gotools-log"
	timetools "github.com/mailgun/gotools-time"
	. "github.com/mailgun/vulcan/endpoint"
	. "github.com/mailgun/vulcan/metrics"
	"github.com/mailgun/vulcan/netutils"
	. "github.com/mailgun/vulcan/request"
	"net/http"
	"net/url"
	"sync"
	"time"
)

// Dynamic weighted round robin load balancer.
type RoundRobin struct {
	mutex *sync.Mutex
	// Current index (starts from -1)
	index         int
	endpoints     []*WeightedEndpoint
	currentWeight int
	options       Options
}

type Options struct {
	// Control time in tests
	TimeProvider timetools.TimeProvider
	// Algorithm that reacts on the failures and can adjust weights
	FailureHandler FailureHandler
}

// Set additional parameters for the endpoint can be supplied when adding endpoint
type EndpointOptions struct {
	// Relative weight for the enpoint to other enpoints in the load balancer
	Weight int
	// Meter that will be used to detect failures
	Meter FailRateMeter
}

func NewRoundRobin() (*RoundRobin, error) {
	return NewRoundRobinWithOptions(Options{})
}

func NewRoundRobinWithOptions(o Options) (*RoundRobin, error) {
	o, err := validateOptions(o)
	if err != nil {
		return nil, err
	}
	rr := &RoundRobin{
		options:   o,
		index:     -1,
		mutex:     &sync.Mutex{},
		endpoints: []*WeightedEndpoint{},
	}
	return rr, nil
}

func (r *RoundRobin) NextEndpoint(req Request) (Endpoint, error) {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	e, err := r.nextEndpoint(req)
	if err != nil {
		return nil, err
	}
	lastAttempt := req.GetLastAttempt()
	// This is the first try, so just return the selected endpoint
	if lastAttempt == nil {
		return e, err
	}
	// Try to prevent failover to the same endpoint that we've seen before,
	// that reduces the probability of the scenario when failover hits same endpoint
	// on the next attempt and fails, so users will see a failed request.
	var endpoint Endpoint
	for _, _ = range r.endpoints {
		endpoint, err = r.nextEndpoint(req)
		if err != nil {
			return nil, err
		}
		if !hasAttempted(req, endpoint) {
			return endpoint, nil
		}
	}
	return endpoint, err
}

func (r *RoundRobin) nextEndpoint(req Request) (Endpoint, error) {
	if len(r.endpoints) == 0 {
		return nil, fmt.Errorf("No endpoints")
	}

	// Adjust weights based on endpoints failure rates
	r.adjustWeights()

	// The algo below may look messy, but is actually very simple
	// it calculates the GCD  and subtracts it on every iteration, what interleaves endpoints
	// and allows us not to build an iterator every time we readjust weights

	// GCD across all enabled endpoints
	gcd := r.weightGcd()
	// Maximum weight across all enabled endpoints
	max := r.maxWeight()

	for {
		r.index = (r.index + 1) % len(r.endpoints)
		if r.index == 0 {
			r.currentWeight = r.currentWeight - gcd
			if r.currentWeight <= 0 {
				r.currentWeight = max
				if r.currentWeight == 0 {
					return nil, fmt.Errorf("All endpoints have 0 weight")
				}
			}
		}
		e := r.endpoints[r.index]
		if e.effectiveWeight >= r.currentWeight {
			return e.endpoint, nil
		}
	}

	// We did full circle and found no available endpoints
	return nil, fmt.Errorf("No available endpoints!")
}

func (r *RoundRobin) adjustWeights() {
	if r.options.FailureHandler == nil {
		return
	}
	weights, err := r.options.FailureHandler.AdjustWeights()
	if err != nil {
		log.Errorf("%s returned error: %s", r.options.FailureHandler, err)
		return
	}
	changed := false
	for _, w := range weights {
		if w.GetEndpoint().GetEffectiveWeight() != w.GetWeight() {
			w.GetEndpoint().setEffectiveWeight(w.GetWeight())
			changed = true
		}
	}
	if changed {
		r.resetIterator()
	}
}

func (r *RoundRobin) GetEndpoints() []*WeightedEndpoint {
	return r.endpoints
}

func (rr *RoundRobin) AddEndpoint(endpoint Endpoint) error {
	return rr.AddEndpointWithOptions(endpoint, EndpointOptions{})
}

// In case if endpoint is already present in the load balancer, returns error
func (r *RoundRobin) AddEndpointWithOptions(endpoint Endpoint, options EndpointOptions) error {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	if endpoint == nil {
		return fmt.Errorf("Endpoint can't be nil")
	}

	if e, _ := r.findEndpointByUrl(endpoint.GetUrl()); e != nil {
		return fmt.Errorf("Endpoint already exists")
	}

	we, err := r.newWeightedEndpoint(endpoint, options)
	if err != nil {
		return err
	}

	r.endpoints = append(r.endpoints, we)
	r.resetState()
	return nil
}

func (r *RoundRobin) resetIterator() {
	r.index = -1
	r.currentWeight = 0
}

func (r *RoundRobin) resetState() {
	r.resetIterator()
	if r.options.FailureHandler != nil {
		r.options.FailureHandler.Init(r.endpoints)
	}
}

func (r *RoundRobin) findEndpointByUrl(iu *url.URL) (*WeightedEndpoint, int) {
	if len(r.endpoints) == 0 {
		return nil, -1
	}
	for i, e := range r.endpoints {
		u := e.GetUrl()
		if u.Path == iu.Path && u.Host == iu.Host && u.Scheme == iu.Scheme {
			return e, i
		}
	}
	return nil, -1
}

func (r *RoundRobin) FindEndpointByUrl(url string) *WeightedEndpoint {
	out, err := netutils.ParseUrl(url)
	if err != nil {
		return nil
	}
	found, _ := r.findEndpointByUrl(out)
	return found
}

func (r *RoundRobin) FindEndpointById(id string) *WeightedEndpoint {
	if len(r.endpoints) == 0 {
		return nil
	}
	for _, e := range r.endpoints {
		if e.GetId() == id {
			return e
		}
	}
	return nil
}

func (rr *RoundRobin) newWeightedEndpoint(endpoint Endpoint, options EndpointOptions) (*WeightedEndpoint, error) {
	// Treat weight 0 as a default value passed by customer
	if options.Weight == 0 {
		options.Weight = 1
	}
	if options.Weight < 0 {
		return nil, fmt.Errorf("Weight should be >=0")
	}

	if options.Meter == nil {
		meter, err := NewRollingMeter(
			endpoint, 10, time.Second, rr.options.TimeProvider, IsNetworkError)
		if err != nil {
			return nil, err
		}
		options.Meter = meter
	}

	return &WeightedEndpoint{
		meter:           options.Meter,
		endpoint:        endpoint,
		weight:          options.Weight,
		effectiveWeight: options.Weight,
		rr:              rr,
	}, nil
}

func (r *RoundRobin) RemoveEndpoint(endpoint Endpoint) error {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	e, index := r.findEndpointByUrl(endpoint.GetUrl())
	if e == nil {
		return fmt.Errorf("Endpoint not found")
	}
	r.endpoints = append(r.endpoints[:index], r.endpoints[index+1:]...)
	r.resetState()
	return nil
}

func (rr *RoundRobin) ProcessRequest(Request) (*http.Response, error) {
	return nil, nil
}

func (rr *RoundRobin) ProcessResponse(req Request, a Attempt) {
}

func (rr *RoundRobin) ObserveRequest(Request) {
}

func (rr *RoundRobin) ObserveResponse(req Request, a Attempt) {
	rr.mutex.Lock()
	defer rr.mutex.Unlock()

	if a == nil || a.GetEndpoint() == nil {
		return
	}
	we, _ := rr.findEndpointByUrl(a.GetEndpoint().GetUrl())
	if we == nil {
		return
	}
	// Update stats for the endpoint after the request was done
	we.meter.ObserveResponse(req, a)
}

func (rr *RoundRobin) maxWeight() int {
	max := -1
	for _, e := range rr.endpoints {
		if e.effectiveWeight > max {
			max = e.effectiveWeight
		}
	}
	return max
}

func (rr *RoundRobin) weightGcd() int {
	divisor := -1
	for _, e := range rr.endpoints {
		if divisor == -1 {
			divisor = e.effectiveWeight
		} else {
			divisor = gcd(divisor, e.effectiveWeight)
		}
	}
	return divisor
}

func gcd(a, b int) int {
	for b != 0 {
		a, b = b, a%b
	}
	return a
}

func validateOptions(o Options) (Options, error) {
	if o.TimeProvider == nil {
		o.TimeProvider = &timetools.RealTime{}
	}

	if o.FailureHandler == nil {
		failureHandler, err := NewFSMHandler()
		if err != nil {
			return o, err
		}
		o.FailureHandler = failureHandler
	}
	return o, nil
}

func hasAttempted(req Request, endpoint Endpoint) bool {
	for _, a := range req.GetAttempts() {
		if a.GetEndpoint().GetId() == endpoint.GetId() {
			return true
		}
	}
	return false
}
<commit_msg>clarify non-error return statements<commit_after>// Dynamic weighted round robin load balancer
package roundrobin

import (
	"fmt"
	log "github.com/mailgun/gotools-log"
	timetools "github.com/mailgun/gotools-time"
	. "github.com/mailgun/vulcan/endpoint"
	. "github.com/mailgun/vulcan/metrics"
	"github.com/mailgun/vulcan/netutils"
	. "github.com/mailgun/vulcan/request"
	"net/http"
	"net/url"
	"sync"
	"time"
)

// Dynamic weighted round robin load balancer.
type RoundRobin struct {
	mutex *sync.Mutex
	// Current index (starts from -1)
	index         int
	endpoints     []*WeightedEndpoint
	currentWeight int
	options       Options
}

type Options struct {
	// Control time in tests
	TimeProvider timetools.TimeProvider
	// Algorithm that reacts on the failures and can adjust weights
	FailureHandler FailureHandler
}

// Set additional parameters for the endpoint can be supplied when adding endpoint
type EndpointOptions struct {
	// Relative weight for the enpoint to other enpoints in the load balancer
	Weight int
	// Meter that will be used to detect failures
	Meter FailRateMeter
}

func NewRoundRobin() (*RoundRobin, error) {
	return NewRoundRobinWithOptions(Options{})
}

func NewRoundRobinWithOptions(o Options) (*RoundRobin, error) {
	o, err := validateOptions(o)
	if err != nil {
		return nil, err
	}
	rr := &RoundRobin{
		options:   o,
		index:     -1,
		mutex:     &sync.Mutex{},
		endpoints: []*WeightedEndpoint{},
	}
	return rr, nil
}

func (r *RoundRobin) NextEndpoint(req Request) (Endpoint, error) {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	e, err := r.nextEndpoint(req)
	if err != nil {
		return nil, err
	}
	lastAttempt := req.GetLastAttempt()
	// This is the first try, so just return the selected endpoint
	if lastAttempt == nil {
		return e, nil
	}
	// Try to prevent failover to the same endpoint that we've seen before,
	// that reduces the probability of the scenario when failover hits same endpoint
	// on the next attempt and fails, so users will see a failed request.
	var endpoint Endpoint
	for _, _ = range r.endpoints {
		endpoint, err = r.nextEndpoint(req)
		if err != nil {
			return nil, err
		}
		if !hasAttempted(req, endpoint) {
			return endpoint, nil
		}
	}
	return endpoint, nil
}

func (r *RoundRobin) nextEndpoint(req Request) (Endpoint, error) {
	if len(r.endpoints) == 0 {
		return nil, fmt.Errorf("No endpoints")
	}

	// Adjust weights based on endpoints failure rates
	r.adjustWeights()

	// The algo below may look messy, but is actually very simple
	// it calculates the GCD  and subtracts it on every iteration, what interleaves endpoints
	// and allows us not to build an iterator every time we readjust weights

	// GCD across all enabled endpoints
	gcd := r.weightGcd()
	// Maximum weight across all enabled endpoints
	max := r.maxWeight()

	for {
		r.index = (r.index + 1) % len(r.endpoints)
		if r.index == 0 {
			r.currentWeight = r.currentWeight - gcd
			if r.currentWeight <= 0 {
				r.currentWeight = max
				if r.currentWeight == 0 {
					return nil, fmt.Errorf("All endpoints have 0 weight")
				}
			}
		}
		e := r.endpoints[r.index]
		if e.effectiveWeight >= r.currentWeight {
			return e.endpoint, nil
		}
	}

	// We did full circle and found no available endpoints
	return nil, fmt.Errorf("No available endpoints!")
}

func (r *RoundRobin) adjustWeights() {
	if r.options.FailureHandler == nil {
		return
	}
	weights, err := r.options.FailureHandler.AdjustWeights()
	if err != nil {
		log.Errorf("%s returned error: %s", r.options.FailureHandler, err)
		return
	}
	changed := false
	for _, w := range weights {
		if w.GetEndpoint().GetEffectiveWeight() != w.GetWeight() {
			w.GetEndpoint().setEffectiveWeight(w.GetWeight())
			changed = true
		}
	}
	if changed {
		r.resetIterator()
	}
}

func (r *RoundRobin) GetEndpoints() []*WeightedEndpoint {
	return r.endpoints
}

func (rr *RoundRobin) AddEndpoint(endpoint Endpoint) error {
	return rr.AddEndpointWithOptions(endpoint, EndpointOptions{})
}

// In case if endpoint is already present in the load balancer, returns error
func (r *RoundRobin) AddEndpointWithOptions(endpoint Endpoint, options EndpointOptions) error {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	if endpoint == nil {
		return fmt.Errorf("Endpoint can't be nil")
	}

	if e, _ := r.findEndpointByUrl(endpoint.GetUrl()); e != nil {
		return fmt.Errorf("Endpoint already exists")
	}

	we, err := r.newWeightedEndpoint(endpoint, options)
	if err != nil {
		return err
	}

	r.endpoints = append(r.endpoints, we)
	r.resetState()
	return nil
}

func (r *RoundRobin) resetIterator() {
	r.index = -1
	r.currentWeight = 0
}

func (r *RoundRobin) resetState() {
	r.resetIterator()
	if r.options.FailureHandler != nil {
		r.options.FailureHandler.Init(r.endpoints)
	}
}

func (r *RoundRobin) findEndpointByUrl(iu *url.URL) (*WeightedEndpoint, int) {
	if len(r.endpoints) == 0 {
		return nil, -1
	}
	for i, e := range r.endpoints {
		u := e.GetUrl()
		if u.Path == iu.Path && u.Host == iu.Host && u.Scheme == iu.Scheme {
			return e, i
		}
	}
	return nil, -1
}

func (r *RoundRobin) FindEndpointByUrl(url string) *WeightedEndpoint {
	out, err := netutils.ParseUrl(url)
	if err != nil {
		return nil
	}
	found, _ := r.findEndpointByUrl(out)
	return found
}

func (r *RoundRobin) FindEndpointById(id string) *WeightedEndpoint {
	if len(r.endpoints) == 0 {
		return nil
	}
	for _, e := range r.endpoints {
		if e.GetId() == id {
			return e
		}
	}
	return nil
}

func (rr *RoundRobin) newWeightedEndpoint(endpoint Endpoint, options EndpointOptions) (*WeightedEndpoint, error) {
	// Treat weight 0 as a default value passed by customer
	if options.Weight == 0 {
		options.Weight = 1
	}
	if options.Weight < 0 {
		return nil, fmt.Errorf("Weight should be >=0")
	}

	if options.Meter == nil {
		meter, err := NewRollingMeter(
			endpoint, 10, time.Second, rr.options.TimeProvider, IsNetworkError)
		if err != nil {
			return nil, err
		}
		options.Meter = meter
	}

	return &WeightedEndpoint{
		meter:           options.Meter,
		endpoint:        endpoint,
		weight:          options.Weight,
		effectiveWeight: options.Weight,
		rr:              rr,
	}, nil
}

func (r *RoundRobin) RemoveEndpoint(endpoint Endpoint) error {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	e, index := r.findEndpointByUrl(endpoint.GetUrl())
	if e == nil {
		return fmt.Errorf("Endpoint not found")
	}
	r.endpoints = append(r.endpoints[:index], r.endpoints[index+1:]...)
	r.resetState()
	return nil
}

func (rr *RoundRobin) ProcessRequest(Request) (*http.Response, error) {
	return nil, nil
}

func (rr *RoundRobin) ProcessResponse(req Request, a Attempt) {
}

func (rr *RoundRobin) ObserveRequest(Request) {
}

func (rr *RoundRobin) ObserveResponse(req Request, a Attempt) {
	rr.mutex.Lock()
	defer rr.mutex.Unlock()

	if a == nil || a.GetEndpoint() == nil {
		return
	}
	we, _ := rr.findEndpointByUrl(a.GetEndpoint().GetUrl())
	if we == nil {
		return
	}
	// Update stats for the endpoint after the request was done
	we.meter.ObserveResponse(req, a)
}

func (rr *RoundRobin) maxWeight() int {
	max := -1
	for _, e := range rr.endpoints {
		if e.effectiveWeight > max {
			max = e.effectiveWeight
		}
	}
	return max
}

func (rr *RoundRobin) weightGcd() int {
	divisor := -1
	for _, e := range rr.endpoints {
		if divisor == -1 {
			divisor = e.effectiveWeight
		} else {
			divisor = gcd(divisor, e.effectiveWeight)
		}
	}
	return divisor
}

func gcd(a, b int) int {
	for b != 0 {
		a, b = b, a%b
	}
	return a
}

func validateOptions(o Options) (Options, error) {
	if o.TimeProvider == nil {
		o.TimeProvider = &timetools.RealTime{}
	}

	if o.FailureHandler == nil {
		failureHandler, err := NewFSMHandler()
		if err != nil {
			return o, err
		}
		o.FailureHandler = failureHandler
	}
	return o, nil
}

func hasAttempted(req Request, endpoint Endpoint) bool {
	for _, a := range req.GetAttempts() {
		if a.GetEndpoint().GetId() == endpoint.GetId() {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package ethui

import (
	"fmt"
	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/go-qml/qml"
	"math/big"
	"strings"
)

type DebuggerWindow struct {
	win    *qml.Window
	engine *qml.Engine
	lib    *UiLib
	Db     *Debugger
}

func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
	engine := qml.NewEngine()
	component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
	if err != nil {
		fmt.Println(err)

		return nil
	}

	win := component.CreateWindow(nil)
	db := &Debugger{win, make(chan bool), make(chan bool), true}

	return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
}

func (self *DebuggerWindow) Show() {
	context := self.engine.Context()
	context.SetVar("dbg", self)

	go func() {
		self.win.Show()
		self.win.Wait()
	}()
}

func (self *DebuggerWindow) SetCode(code string) {
	self.win.Set("codeText", code)
}

func (self *DebuggerWindow) SetData(data string) {
	self.win.Set("dataText", data)
}
func (self *DebuggerWindow) SetAsm(data string) {
	dis := ethchain.Disassemble(ethutil.FromHex(data))
	for _, str := range dis {
		self.win.Root().Call("setAsm", str)
	}
}

func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
	if !self.Db.done {
		self.Db.Q <- true
	}

	data := ethutil.StringToByteFunc(dataStr, func(s string) (ret []byte) {
		slice := strings.Split(dataStr, "\n")
		for _, dataItem := range slice {
			d := ethutil.FormatData(dataItem)
			ret = append(ret, d...)
		}
		return
	})

	var err error
	script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
		ret, err = ethutil.Compile(s)
		fmt.Printf("%x\n", ret)
		return
	})

	if err != nil {
		self.Logln(err)

		return
	}

	dis := ethchain.Disassemble(script)
	self.win.Root().Call("clearAsm")
	self.win.Root().Call("clearLog")

	for _, str := range dis {
		self.win.Root().Call("setAsm", str)
	}

	gas := ethutil.Big(gasStr)
	gasPrice := ethutil.Big(gasPriceStr)
	// Contract addr as test address
	keyPair := ethutil.GetKeyRing().Get(0)
	callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), gas, gasPrice, script)
	callerTx.Sign(keyPair.PrivateKey)

	state := self.lib.eth.BlockChain().CurrentBlock.State()
	account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
	contract := ethchain.MakeContract(callerTx, state)
	callerClosure := ethchain.NewClosure(account, contract, script, state, gas, gasPrice)

	block := self.lib.eth.BlockChain().CurrentBlock
	vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
		Origin:      account.Address(),
		BlockNumber: block.BlockInfo().Number,
		PrevHash:    block.PrevHash,
		Coinbase:    block.Coinbase,
		Time:        block.Time,
		Diff:        block.Difficulty,
		Value:       ethutil.Big(valueStr),
	})

	self.Db.done = false
	self.Logf("callsize %d", len(script))
	go func() {
		ret, g, err := callerClosure.Call(vm, data, self.Db.halting)
		self.Logln("gas usage", g, "total price =", new(big.Int).Mul(g, gasPrice))
		if err != nil {
			self.Logln("exited with errors:", err)
		} else {
			if len(ret) > 0 {
				self.Logf("exited: % x", ret)
			} else {
				self.Logf("exited: nil")
			}
		}

		state.Reset()

		self.Db.done = true
	}()
}

func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
	self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}

func (self *DebuggerWindow) Logln(v ...interface{}) {
	str := fmt.Sprintln(v...)
	self.Logf("%s", str[:len(str)-1])
}

func (self *DebuggerWindow) Next() {
	self.Db.Next()
}

type Debugger struct {
	win  *qml.Window
	N    chan bool
	Q    chan bool
	done bool
}

type storeVal struct {
	Key, Value string
}

func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, stack *ethchain.Stack, stateObject *ethchain.StateObject) bool {
	d.win.Root().Call("setInstruction", pc)
	d.win.Root().Call("clearMem")
	d.win.Root().Call("clearStack")
	d.win.Root().Call("clearStorage")

	addr := 0
	for i := 0; i+32 <= mem.Len(); i += 32 {
		d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
		addr++
	}

	for _, val := range stack.Data() {
		d.win.Root().Call("setStack", val.String())
	}

	stateObject.State().EachStorage(func(key string, node *ethutil.Value) {
		d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
	})

out:
	for {
		select {
		case <-d.N:
			break out
		case <-d.Q:
			d.done = true

			return false
		}
	}

	return true
}

func (d *Debugger) Next() {
	if !d.done {
		d.N <- true
	}
}
<commit_msg>debugger output<commit_after>package ethui

import (
	"fmt"
	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/go-qml/qml"
	"math/big"
	"strings"
)

type DebuggerWindow struct {
	win    *qml.Window
	engine *qml.Engine
	lib    *UiLib
	Db     *Debugger
}

func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
	engine := qml.NewEngine()
	component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
	if err != nil {
		fmt.Println(err)

		return nil
	}

	win := component.CreateWindow(nil)
	db := &Debugger{win, make(chan bool), make(chan bool), true}

	return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
}

func (self *DebuggerWindow) Show() {
	context := self.engine.Context()
	context.SetVar("dbg", self)

	go func() {
		self.win.Show()
		self.win.Wait()
	}()
}

func (self *DebuggerWindow) SetCode(code string) {
	self.win.Set("codeText", code)
}

func (self *DebuggerWindow) SetData(data string) {
	self.win.Set("dataText", data)
}
func (self *DebuggerWindow) SetAsm(data string) {
	dis := ethchain.Disassemble(ethutil.FromHex(data))
	for _, str := range dis {
		self.win.Root().Call("setAsm", str)
	}
}

func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
	if !self.Db.done {
		self.Db.Q <- true
	}

	data := ethutil.StringToByteFunc(dataStr, func(s string) (ret []byte) {
		slice := strings.Split(dataStr, "\n")
		for _, dataItem := range slice {
			d := ethutil.FormatData(dataItem)
			ret = append(ret, d...)
		}
		return
	})

	var err error
	script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
		ret, err = ethutil.Compile(s)
		fmt.Printf("%x\n", ret)
		return
	})

	if err != nil {
		self.Logln(err)

		return
	}

	dis := ethchain.Disassemble(script)
	self.win.Root().Call("clearAsm")
	self.win.Root().Call("clearLog")

	for _, str := range dis {
		self.win.Root().Call("setAsm", str)
	}

	gas := ethutil.Big(gasStr)
	gasPrice := ethutil.Big(gasPriceStr)
	// Contract addr as test address
	keyPair := ethutil.GetKeyRing().Get(0)
	callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), gas, gasPrice, script)
	callerTx.Sign(keyPair.PrivateKey)

	state := self.lib.eth.BlockChain().CurrentBlock.State()
	account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
	contract := ethchain.MakeContract(callerTx, state)
	callerClosure := ethchain.NewClosure(account, contract, script, state, gas, gasPrice)

	block := self.lib.eth.BlockChain().CurrentBlock
	vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
		Origin:      account.Address(),
		BlockNumber: block.BlockInfo().Number,
		PrevHash:    block.PrevHash,
		Coinbase:    block.Coinbase,
		Time:        block.Time,
		Diff:        block.Difficulty,
		Value:       ethutil.Big(valueStr),
	})

	self.Db.done = false
	self.Logf("callsize %d", len(script))
	go func() {
		ret, g, err := callerClosure.Call(vm, data, self.Db.halting)
		tot := new(big.Int).Mul(g, gasPrice)
		self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot))
		if err != nil {
			self.Logln("exited with errors:", err)
		} else {
			if len(ret) > 0 {
				self.Logf("exited: % x", ret)
			} else {
				self.Logf("exited: nil")
			}
		}

		state.Reset()

		self.Db.done = true
	}()
}

func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
	self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}

func (self *DebuggerWindow) Logln(v ...interface{}) {
	str := fmt.Sprintln(v...)
	self.Logf("%s", str[:len(str)-1])
}

func (self *DebuggerWindow) Next() {
	self.Db.Next()
}

type Debugger struct {
	win  *qml.Window
	N    chan bool
	Q    chan bool
	done bool
}

type storeVal struct {
	Key, Value string
}

func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, stack *ethchain.Stack, stateObject *ethchain.StateObject) bool {
	d.win.Root().Call("setInstruction", pc)
	d.win.Root().Call("clearMem")
	d.win.Root().Call("clearStack")
	d.win.Root().Call("clearStorage")

	addr := 0
	for i := 0; i+32 <= mem.Len(); i += 32 {
		d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
		addr++
	}

	for _, val := range stack.Data() {
		d.win.Root().Call("setStack", val.String())
	}

	stateObject.State().EachStorage(func(key string, node *ethutil.Value) {
		d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
	})

out:
	for {
		select {
		case <-d.N:
			break out
		case <-d.Q:
			d.done = true

			return false
		}
	}

	return true
}

func (d *Debugger) Next() {
	if !d.done {
		d.N <- true
	}
}
<|endoftext|>


<commit_before>package db

import (
	"errors"
	"log"

	"github.com/quilt/quilt/blueprint"
)

// A Blueprint that Quilt is attempting to implement.
type Blueprint struct {
	ID int

	blueprint.Blueprint
}

// InsertBlueprint creates a new Blueprint and interts it into 'db'.
func (db Database) InsertBlueprint() Blueprint {
	result := Blueprint{ID: db.nextID()}
	db.insert(result)
	return result
}

// SelectFromBlueprint gets all blueprints in the database that satisfy 'check'.
func (db Database) SelectFromBlueprint(check func(Blueprint) bool) []Blueprint {
	var result []Blueprint
	for _, row := range db.selectRows(BlueprintTable) {
		if check == nil || check(row.(Blueprint)) {
			result = append(result, row.(Blueprint))
		}
	}
	return result
}

// SelectFromBlueprint gets all blueprints in the database that satisfy 'check'.
func (conn Conn) SelectFromBlueprint(check func(Blueprint) bool) []Blueprint {
	var blueprints []Blueprint
	conn.Txn(BlueprintTable).Run(func(view Database) error {
		blueprints = view.SelectFromBlueprint(check)
		return nil
	})
	return blueprints
}

// GetBlueprint gets the blueprint from the database. There should only ever be a single
// blueprint.
func (db Database) GetBlueprint() (Blueprint, error) {
	blueprints := db.SelectFromBlueprint(nil)
	numBlueprints := len(blueprints)
	if numBlueprints == 1 {
		return blueprints[0], nil
	} else if numBlueprints > 1 {
		log.Panicf("Found %d blueprints, there should be 1", numBlueprints)
	}
	return Blueprint{}, errors.New("no blueprints found")
}

// GetBlueprintNamespace returns the namespace of the single blueprint object in the
// blueprint table.  Otherwise it returns an error.
func (db Database) GetBlueprintNamespace() (string, error) {
	clst, err := db.GetBlueprint()
	if err != nil {
		return "", err
	}
	return clst.Namespace, nil
}

// GetBlueprintNamespace returns the namespace of the single blueprint object in the
// blueprint table.  Otherwise it returns an error.
func (conn Conn) GetBlueprintNamespace() (namespace string, err error) {
	conn.Txn(BlueprintTable).Run(func(db Database) error {
		namespace, err = db.GetBlueprintNamespace()
		return nil
	})
	return
}

func (b Blueprint) getID() int {
	return b.ID
}

func (b Blueprint) tt() TableType {
	return BlueprintTable
}

func (b Blueprint) String() string {
	return defaultString(b)
}

func (b Blueprint) less(r row) bool {
	return b.ID < r.(Blueprint).ID
}
<commit_msg>db: Don't print deployment object in daemon output<commit_after>package db

import (
	"errors"
	"log"

	"github.com/quilt/quilt/blueprint"
)

// A Blueprint that Quilt is attempting to implement.
type Blueprint struct {
	ID int

	blueprint.Blueprint `rowStringer:"omit"`
}

// InsertBlueprint creates a new Blueprint and interts it into 'db'.
func (db Database) InsertBlueprint() Blueprint {
	result := Blueprint{ID: db.nextID()}
	db.insert(result)
	return result
}

// SelectFromBlueprint gets all blueprints in the database that satisfy 'check'.
func (db Database) SelectFromBlueprint(check func(Blueprint) bool) []Blueprint {
	var result []Blueprint
	for _, row := range db.selectRows(BlueprintTable) {
		if check == nil || check(row.(Blueprint)) {
			result = append(result, row.(Blueprint))
		}
	}
	return result
}

// SelectFromBlueprint gets all blueprints in the database that satisfy 'check'.
func (conn Conn) SelectFromBlueprint(check func(Blueprint) bool) []Blueprint {
	var blueprints []Blueprint
	conn.Txn(BlueprintTable).Run(func(view Database) error {
		blueprints = view.SelectFromBlueprint(check)
		return nil
	})
	return blueprints
}

// GetBlueprint gets the blueprint from the database. There should only ever be a single
// blueprint.
func (db Database) GetBlueprint() (Blueprint, error) {
	blueprints := db.SelectFromBlueprint(nil)
	numBlueprints := len(blueprints)
	if numBlueprints == 1 {
		return blueprints[0], nil
	} else if numBlueprints > 1 {
		log.Panicf("Found %d blueprints, there should be 1", numBlueprints)
	}
	return Blueprint{}, errors.New("no blueprints found")
}

// GetBlueprintNamespace returns the namespace of the single blueprint object in the
// blueprint table.  Otherwise it returns an error.
func (db Database) GetBlueprintNamespace() (string, error) {
	clst, err := db.GetBlueprint()
	if err != nil {
		return "", err
	}
	return clst.Namespace, nil
}

// GetBlueprintNamespace returns the namespace of the single blueprint object in the
// blueprint table.  Otherwise it returns an error.
func (conn Conn) GetBlueprintNamespace() (namespace string, err error) {
	conn.Txn(BlueprintTable).Run(func(db Database) error {
		namespace, err = db.GetBlueprintNamespace()
		return nil
	})
	return
}

func (b Blueprint) getID() int {
	return b.ID
}

func (b Blueprint) tt() TableType {
	return BlueprintTable
}

func (b Blueprint) String() string {
	return defaultString(b)
}

func (b Blueprint) less(r row) bool {
	return b.ID < r.(Blueprint).ID
}
<|endoftext|>


<commit_before>// Inferno utils/5l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package arm

import (
	"cmd/internal/obj"
	"cmd/internal/sys"
	"cmd/link/internal/ld"
	"fmt"
)

func Init() {
	ld.SysArch = sys.ArchARM

	ld.Thearch.Funcalign = funcAlign
	ld.Thearch.Maxalign = maxAlign
	ld.Thearch.Minalign = minAlign
	ld.Thearch.Dwarfregsp = dwarfRegSP
	ld.Thearch.Dwarfreglr = dwarfRegLR

	ld.Thearch.Adddynrel = adddynrel
	ld.Thearch.Archinit = archinit
	ld.Thearch.Archreloc = archreloc
	ld.Thearch.Archrelocvariant = archrelocvariant
	ld.Thearch.Trampoline = trampoline
	ld.Thearch.Asmb = asmb
	ld.Thearch.Elfreloc1 = elfreloc1
	ld.Thearch.Elfsetupplt = elfsetupplt
	ld.Thearch.Gentext = gentext
	ld.Thearch.Machoreloc1 = machoreloc1
	ld.Thearch.Lput = ld.Lputl
	ld.Thearch.Wput = ld.Wputl
	ld.Thearch.Vput = ld.Vputl
	ld.Thearch.Append16 = ld.Append16l
	ld.Thearch.Append32 = ld.Append32l
	ld.Thearch.Append64 = ld.Append64l

	ld.Thearch.Linuxdynld = "/lib/ld-linux.so.3" // 2 for OABI, 3 for EABI
	ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
	ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
	ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
	ld.Thearch.Dragonflydynld = "XXX"
	ld.Thearch.Solarisdynld = "XXX"
}

func archinit(ctxt *ld.Link) {
	switch ld.Headtype {
	default:
		ld.Exitf("unknown -H option: %v", ld.Headtype)

	case obj.Hplan9: /* plan 9 */
		ld.HEADR = 32

		if *ld.FlagTextAddr == -1 {
			*ld.FlagTextAddr = 4128
		}
		if *ld.FlagDataAddr == -1 {
			*ld.FlagDataAddr = 0
		}
		if *ld.FlagRound == -1 {
			*ld.FlagRound = 4096
		}

	case obj.Hlinux, /* arm elf */
		obj.Hfreebsd,
		obj.Hnetbsd,
		obj.Hopenbsd:
		*ld.FlagD = false
		// with dynamic linking
		ld.Elfinit(ctxt)
		ld.HEADR = ld.ELFRESERVE
		if *ld.FlagTextAddr == -1 {
			*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
		}
		if *ld.FlagDataAddr == -1 {
			*ld.FlagDataAddr = 0
		}
		if *ld.FlagRound == -1 {
			*ld.FlagRound = 4096
		}

	case obj.Hnacl:
		ld.Elfinit(ctxt)
		ld.HEADR = 0x10000
		ld.Funcalign = 16
		if *ld.FlagTextAddr == -1 {
			*ld.FlagTextAddr = 0x20000
		}
		if *ld.FlagDataAddr == -1 {
			*ld.FlagDataAddr = 0
		}
		if *ld.FlagRound == -1 {
			*ld.FlagRound = 0x10000
		}

	case obj.Hdarwin: /* apple MACH */
		*ld.FlagW = true // disable DWARF generation
		ld.Machoinit()
		ld.HEADR = ld.INITIAL_MACHO_HEADR
		if *ld.FlagTextAddr == -1 {
			*ld.FlagTextAddr = 4096 + int64(ld.HEADR)
		}
		if *ld.FlagDataAddr == -1 {
			*ld.FlagDataAddr = 0
		}
		if *ld.FlagRound == -1 {
			*ld.FlagRound = 4096
		}
	}

	if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
		fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
	}
}
<commit_msg>cmd/link: use 64k segment alignment on linux/arm<commit_after>// Inferno utils/5l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package arm

import (
	"cmd/internal/obj"
	"cmd/internal/sys"
	"cmd/link/internal/ld"
	"fmt"
)

func Init() {
	ld.SysArch = sys.ArchARM

	ld.Thearch.Funcalign = funcAlign
	ld.Thearch.Maxalign = maxAlign
	ld.Thearch.Minalign = minAlign
	ld.Thearch.Dwarfregsp = dwarfRegSP
	ld.Thearch.Dwarfreglr = dwarfRegLR

	ld.Thearch.Adddynrel = adddynrel
	ld.Thearch.Archinit = archinit
	ld.Thearch.Archreloc = archreloc
	ld.Thearch.Archrelocvariant = archrelocvariant
	ld.Thearch.Trampoline = trampoline
	ld.Thearch.Asmb = asmb
	ld.Thearch.Elfreloc1 = elfreloc1
	ld.Thearch.Elfsetupplt = elfsetupplt
	ld.Thearch.Gentext = gentext
	ld.Thearch.Machoreloc1 = machoreloc1
	ld.Thearch.Lput = ld.Lputl
	ld.Thearch.Wput = ld.Wputl
	ld.Thearch.Vput = ld.Vputl
	ld.Thearch.Append16 = ld.Append16l
	ld.Thearch.Append32 = ld.Append32l
	ld.Thearch.Append64 = ld.Append64l

	ld.Thearch.Linuxdynld = "/lib/ld-linux.so.3" // 2 for OABI, 3 for EABI
	ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
	ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
	ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
	ld.Thearch.Dragonflydynld = "XXX"
	ld.Thearch.Solarisdynld = "XXX"
}

func archinit(ctxt *ld.Link) {
	switch ld.Headtype {
	default:
		ld.Exitf("unknown -H option: %v", ld.Headtype)

	case obj.Hplan9: /* plan 9 */
		ld.HEADR = 32

		if *ld.FlagTextAddr == -1 {
			*ld.FlagTextAddr = 4128
		}
		if *ld.FlagDataAddr == -1 {
			*ld.FlagDataAddr = 0
		}
		if *ld.FlagRound == -1 {
			*ld.FlagRound = 4096
		}

	case obj.Hlinux, /* arm elf */
		obj.Hfreebsd,
		obj.Hnetbsd,
		obj.Hopenbsd:
		*ld.FlagD = false
		// with dynamic linking
		ld.Elfinit(ctxt)
		ld.HEADR = ld.ELFRESERVE
		if *ld.FlagTextAddr == -1 {
			*ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
		}
		if *ld.FlagDataAddr == -1 {
			*ld.FlagDataAddr = 0
		}
		if *ld.FlagRound == -1 {
			*ld.FlagRound = 0x10000
		}

	case obj.Hnacl:
		ld.Elfinit(ctxt)
		ld.HEADR = 0x10000
		ld.Funcalign = 16
		if *ld.FlagTextAddr == -1 {
			*ld.FlagTextAddr = 0x20000
		}
		if *ld.FlagDataAddr == -1 {
			*ld.FlagDataAddr = 0
		}
		if *ld.FlagRound == -1 {
			*ld.FlagRound = 0x10000
		}

	case obj.Hdarwin: /* apple MACH */
		*ld.FlagW = true // disable DWARF generation
		ld.Machoinit()
		ld.HEADR = ld.INITIAL_MACHO_HEADR
		if *ld.FlagTextAddr == -1 {
			*ld.FlagTextAddr = 4096 + int64(ld.HEADR)
		}
		if *ld.FlagDataAddr == -1 {
			*ld.FlagDataAddr = 0
		}
		if *ld.FlagRound == -1 {
			*ld.FlagRound = 4096
		}
	}

	if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
		fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
	}
}
<|endoftext|>


<commit_before>package api100

import (
	"encoding/json"
	"net/http"
	"strconv"

	"github.com/carbocation/interpose"
	"github.com/chaosvermittlung/funkloch-server/db/v100"
	"github.com/gorilla/mux"
)

func getStoreItemRouter(prefix string) *interpose.Middleware {
	r, m := GetNewSubrouter(prefix)
	r.HandleFunc("/", postStoreItemHandler).Methods("POST")
	r.HandleFunc("/list", listStoreItemsHandler).Methods("GET")
	r.HandleFunc("/{ID}", getStoreItemHandler).Methods("GET")
	r.HandleFunc("/{ID}", patchStoreItemHandler).Methods("PATCH")
	r.HandleFunc("/{ID}", deleteStoreItemHandler).Methods("DELETE")
	return m
}

func postStoreItemHandler(w http.ResponseWriter, r *http.Request) {
	err := userhasrRight(r, db100.USERRIGHT_MEMBER)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusUnauthorized, ERROR_USERNOTAUTHORIZED)
		return
	}
	decoder := json.NewDecoder(r.Body)
	var s db100.StoreItem
	err = decoder.Decode(&s)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusBadRequest, ERROR_JSONERROR)
		return
	}
	err = s.Insert()
	if err != nil {
		apierror(w, r, "Error Inserting Storeitem: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	j, err := json.Marshal(&s)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusInternalServerError, ERROR_JSONERROR)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
}

func listStoreItemsHandler(w http.ResponseWriter, r *http.Request) {
	ss, err := db100.GetStoreItems()
	if err != nil {
		apierror(w, r, "Error fetching StoreItems: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	var res []storeItemResponse
	for _, s := range ss {
		var sir storeItemResponse
		sir.StoreItem = s
		sir.Equipment.EquipmentID = s.EquipmentID
		err = sir.Equipment.GetDetails()
		if err != nil {
			apierror(w, r, "Error fetching StoreItem Equipment: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
			return
		}
		sir.Store.StoreID = s.StoreID
		err = sir.Store.GetDetails()
		if err != nil {
			apierror(w, r, "Error fetching StoreItem Store: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
			return
		}
		res = append(res, sir)
	}
	j, err := json.Marshal(&res)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusInternalServerError, ERROR_JSONERROR)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
}

func getStoreItemHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	i := vars["ID"]
	id, err := strconv.Atoi(i)
	if err != nil {
		apierror(w, r, "Error converting ID: "+err.Error(), http.StatusBadRequest, ERROR_INVALIDPARAMETER)
		return
	}
	s := db100.StoreItem{StoreItemID: id}
	err = s.GetDetails()
	if err != nil {
		apierror(w, r, "Error fetching StoreItem: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}

	j, err := json.Marshal(&s)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusInternalServerError, ERROR_JSONERROR)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
}

func patchStoreItemHandler(w http.ResponseWriter, r *http.Request) {
	err := userhasrRight(r, db100.USERRIGHT_MEMBER)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusUnauthorized, ERROR_USERNOTAUTHORIZED)
		return
	}
	vars := mux.Vars(r)
	i := vars["ID"]
	id, err := strconv.Atoi(i)
	if err != nil {
		apierror(w, r, "Error converting ID: "+err.Error(), http.StatusBadRequest, ERROR_INVALIDPARAMETER)
		return
	}
	decoder := json.NewDecoder(r.Body)
	var si db100.StoreItem
	err = decoder.Decode(&si)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusBadRequest, ERROR_JSONERROR)
		return
	}
	si.StoreItemID = id
	err = si.Update()
	if err != nil {
		apierror(w, r, "Error updating Equipment: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	j, err := json.Marshal(&si)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusInternalServerError, ERROR_JSONERROR)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
}

func deleteStoreItemHandler(w http.ResponseWriter, r *http.Request) {
	err := userhasrRight(r, db100.USERRIGHT_MEMBER)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusUnauthorized, ERROR_USERNOTAUTHORIZED)
		return
	}
	vars := mux.Vars(r)
	i := vars["ID"]
	id, err := strconv.Atoi(i)
	if err != nil {
		apierror(w, r, "Error converting ID: "+err.Error(), http.StatusBadRequest, ERROR_INVALIDPARAMETER)
		return
	}
	s := db100.StoreItem{StoreItemID: id}
	err = s.Delete()
	if err != nil {
		apierror(w, r, "Error deleting StoreItem: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
}
<commit_msg>New Response time also for single items<commit_after>package api100

import (
	"encoding/json"
	"net/http"
	"strconv"

	"github.com/carbocation/interpose"
	"github.com/chaosvermittlung/funkloch-server/db/v100"
	"github.com/gorilla/mux"
)

func getStoreItemRouter(prefix string) *interpose.Middleware {
	r, m := GetNewSubrouter(prefix)
	r.HandleFunc("/", postStoreItemHandler).Methods("POST")
	r.HandleFunc("/list", listStoreItemsHandler).Methods("GET")
	r.HandleFunc("/{ID}", getStoreItemHandler).Methods("GET")
	r.HandleFunc("/{ID}", patchStoreItemHandler).Methods("PATCH")
	r.HandleFunc("/{ID}", deleteStoreItemHandler).Methods("DELETE")
	return m
}

func postStoreItemHandler(w http.ResponseWriter, r *http.Request) {
	err := userhasrRight(r, db100.USERRIGHT_MEMBER)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusUnauthorized, ERROR_USERNOTAUTHORIZED)
		return
	}
	decoder := json.NewDecoder(r.Body)
	var s db100.StoreItem
	err = decoder.Decode(&s)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusBadRequest, ERROR_JSONERROR)
		return
	}
	err = s.Insert()
	if err != nil {
		apierror(w, r, "Error Inserting Storeitem: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	j, err := json.Marshal(&s)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusInternalServerError, ERROR_JSONERROR)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
}

func listStoreItemsHandler(w http.ResponseWriter, r *http.Request) {
	ss, err := db100.GetStoreItems()
	if err != nil {
		apierror(w, r, "Error fetching StoreItems: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	var res []storeItemResponse
	for _, s := range ss {
		var sir storeItemResponse
		sir.StoreItem = s
		sir.Equipment.EquipmentID = s.EquipmentID
		err = sir.Equipment.GetDetails()
		if err != nil {
			apierror(w, r, "Error fetching StoreItem Equipment: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
			return
		}
		sir.Store.StoreID = s.StoreID
		err = sir.Store.GetDetails()
		if err != nil {
			apierror(w, r, "Error fetching StoreItem Store: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
			return
		}
		res = append(res, sir)
	}
	j, err := json.Marshal(&res)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusInternalServerError, ERROR_JSONERROR)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
}

func getStoreItemHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	i := vars["ID"]
	id, err := strconv.Atoi(i)
	if err != nil {
		apierror(w, r, "Error converting ID: "+err.Error(), http.StatusBadRequest, ERROR_INVALIDPARAMETER)
		return
	}
	var sir storeItemResponse
	sir.StoreItem.StoreItemID = id
	err = sir.StoreItem.GetDetails()
	if err != nil {
		apierror(w, r, "Error fetching StoreItem: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	sir.Store.StoreID = sir.StoreItem.StoreID
	err = sir.Store.GetDetails()
	if err != nil {
		apierror(w, r, "Error fetching StoreItem Store: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	sir.Equipment.EquipmentID = sir.StoreItem.EquipmentID
	err = sir.Equipment.GetDetails()
	if err != nil {
		apierror(w, r, "Error fetching StoreItem Equipment: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	j, err := json.Marshal(&sir)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusInternalServerError, ERROR_JSONERROR)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
}

func patchStoreItemHandler(w http.ResponseWriter, r *http.Request) {
	err := userhasrRight(r, db100.USERRIGHT_MEMBER)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusUnauthorized, ERROR_USERNOTAUTHORIZED)
		return
	}
	vars := mux.Vars(r)
	i := vars["ID"]
	id, err := strconv.Atoi(i)
	if err != nil {
		apierror(w, r, "Error converting ID: "+err.Error(), http.StatusBadRequest, ERROR_INVALIDPARAMETER)
		return
	}
	decoder := json.NewDecoder(r.Body)
	var si db100.StoreItem
	err = decoder.Decode(&si)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusBadRequest, ERROR_JSONERROR)
		return
	}
	si.StoreItemID = id
	err = si.Update()
	if err != nil {
		apierror(w, r, "Error updating Equipment: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
	j, err := json.Marshal(&si)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusInternalServerError, ERROR_JSONERROR)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(j)
}

func deleteStoreItemHandler(w http.ResponseWriter, r *http.Request) {
	err := userhasrRight(r, db100.USERRIGHT_MEMBER)
	if err != nil {
		apierror(w, r, err.Error(), http.StatusUnauthorized, ERROR_USERNOTAUTHORIZED)
		return
	}
	vars := mux.Vars(r)
	i := vars["ID"]
	id, err := strconv.Atoi(i)
	if err != nil {
		apierror(w, r, "Error converting ID: "+err.Error(), http.StatusBadRequest, ERROR_INVALIDPARAMETER)
		return
	}
	s := db100.StoreItem{StoreItemID: id}
	err = s.Delete()
	if err != nil {
		apierror(w, r, "Error deleting StoreItem: "+err.Error(), http.StatusInternalServerError, ERROR_DBQUERYFAILED)
		return
	}
}
<|endoftext|>


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

// Package exec runs external commands. It wraps os.StartProcess to make it
// easier to remap stdin and stdout, connect I/O with pipes, and do other
// adjustments.
package exec

import (
	"bytes"
	"io"
	"os"
	"strconv"
	"syscall"
)

// Error records the name of a binary that failed to be be executed
// and the reason it failed.
type Error struct {
	Name  string
	Error os.Error
}

func (e *Error) String() string {
	return "exec: " + strconv.Quote(e.Name) + ": " + e.Error.String()
}

// Cmd represents an external command being prepared or run.
type Cmd struct {
	// Path is the path of the command to run.
	//
	// This is the only field that must be set to a non-zero
	// value.
	Path string

	// Args holds command line arguments, including the command as Args[0].
	// If the Args field is empty or nil, Run uses {Path}.
	//
	// In typical use, both Path and Args are set by calling Command.
	Args []string

	// Env specifies the environment of the process.
	// If Env is nil, Run uses the current process's environment.
	Env []string

	// Dir specifies the working directory of the command.
	// If Dir is the empty string, Run runs the command in the
	// calling process's current directory.
	Dir string

	// Stdin specifies the process's standard input.
	// If Stdin is nil, the process reads from DevNull.
	Stdin io.Reader

	// Stdout and Stderr specify the process's standard output and error.
	//
	// If either is nil, Run connects the
	// corresponding file descriptor to /dev/null.
	//
	// If Stdout and Stderr are are the same writer, at most one
	// goroutine at a time will call Write.
	Stdout io.Writer
	Stderr io.Writer

	// SysProcAttr holds optional, operating system-specific attributes.
	// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
	SysProcAttr *syscall.SysProcAttr

	// Process is the underlying process, once started.
	Process *os.Process

	err             os.Error // last error (from LookPath, stdin, stdout, stderr)
	finished        bool     // when Wait was called
	childFiles      []*os.File
	closeAfterStart []io.Closer
	closeAfterWait  []io.Closer
	goroutine       []func() os.Error
	errch           chan os.Error // one send per goroutine
}

// Command returns the Cmd struct to execute the named program with
// the given arguments.
//
// It sets Path and Args in the returned structure and zeroes the
// other fields.
//
// If name contains no path separators, Command uses LookPath to
// resolve the path to a complete name if possible. Otherwise it uses
// name directly.
//
// The returned Cmd's Args field is constructed from the command name
// followed by the elements of arg, so arg should not include the
// command name itself. For example, Command("echo", "hello")
func Command(name string, arg ...string) *Cmd {
	aname, err := LookPath(name)
	if err != nil {
		aname = name
	}
	return &Cmd{
		Path: aname,
		Args: append([]string{name}, arg...),
		err:  err,
	}
}

// interfaceEqual protects against panics from doing equality tests on
// two interfaces with non-comparable underlying types
func interfaceEqual(a, b interface{}) bool {
	defer func() {
		recover()
	}()
	return a == b
}

func (c *Cmd) envv() []string {
	if c.Env != nil {
		return c.Env
	}
	return os.Environ()
}

func (c *Cmd) argv() []string {
	if len(c.Args) > 0 {
		return c.Args
	}
	return []string{c.Path}
}

func (c *Cmd) stdin() (f *os.File, err os.Error) {
	if c.Stdin == nil {
		f, err = os.Open(os.DevNull)
		c.closeAfterStart = append(c.closeAfterStart, f)
		return
	}

	if f, ok := c.Stdin.(*os.File); ok {
		return f, nil
	}

	pr, pw, err := os.Pipe()
	if err != nil {
		return
	}

	c.closeAfterStart = append(c.closeAfterStart, pr)
	c.closeAfterWait = append(c.closeAfterWait, pw)
	c.goroutine = append(c.goroutine, func() os.Error {
		_, err := io.Copy(pw, c.Stdin)
		if err1 := pw.Close(); err == nil {
			err = err1
		}
		return err
	})
	return pr, nil
}

func (c *Cmd) stdout() (f *os.File, err os.Error) {
	return c.writerDescriptor(c.Stdout)
}

func (c *Cmd) stderr() (f *os.File, err os.Error) {
	if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
		return c.childFiles[1], nil
	}
	return c.writerDescriptor(c.Stderr)
}

func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
	if w == nil {
		f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
		c.closeAfterStart = append(c.closeAfterStart, f)
		return
	}

	if f, ok := w.(*os.File); ok {
		return f, nil
	}

	pr, pw, err := os.Pipe()
	if err != nil {
		return
	}

	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	c.goroutine = append(c.goroutine, func() os.Error {
		_, err := io.Copy(w, pr)
		return err
	})
	return pw, nil
}

// Run starts the specified command and waits for it to complete.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command fails to run or doesn't complete successfully, the
// error is of type *os.Waitmsg. Other error types may be
// returned for I/O problems.
func (c *Cmd) Run() os.Error {
	if err := c.Start(); err != nil {
		return err
	}
	return c.Wait()
}

// Start starts the specified command but does not wait for it to complete.
func (c *Cmd) Start() os.Error {
	if c.err != nil {
		return c.err
	}
	if c.Process != nil {
		return os.NewError("exec: already started")
	}

	type F func(*Cmd) (*os.File, os.Error)
	for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
		fd, err := setupFd(c)
		if err != nil {
			return err
		}
		c.childFiles = append(c.childFiles, fd)
	}

	var err os.Error
	c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
		Dir:   c.Dir,
		Files: c.childFiles,
		Env:   c.envv(),
		Sys:   c.SysProcAttr,
	})
	if err != nil {
		return err
	}

	for _, fd := range c.closeAfterStart {
		fd.Close()
	}

	c.errch = make(chan os.Error, len(c.goroutine))
	for _, fn := range c.goroutine {
		go func(fn func() os.Error) {
			c.errch <- fn()
		}(fn)
	}

	return nil
}

// Wait waits for the command to exit.
// It must have been started by Start.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command fails to run or doesn't complete successfully, the
// error is of type *os.Waitmsg. Other error types may be
// returned for I/O problems.
func (c *Cmd) Wait() os.Error {
	if c.Process == nil {
		return os.NewError("exec: not started")
	}
	if c.finished {
		return os.NewError("exec: Wait was already called")
	}
	c.finished = true
	msg, err := c.Process.Wait(0)

	var copyError os.Error
	for _ = range c.goroutine {
		if err := <-c.errch; err != nil && copyError == nil {
			copyError = err
		}
	}

	for _, fd := range c.closeAfterWait {
		fd.Close()
	}

	if err != nil {
		return err
	} else if !msg.Exited() || msg.ExitStatus() != 0 {
		return msg
	}

	return copyError
}

// Output runs the command and returns its standard output.
func (c *Cmd) Output() ([]byte, os.Error) {
	if c.Stdout != nil {
		return nil, os.NewError("exec: Stdout already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	err := c.Run()
	return b.Bytes(), err
}

// CombinedOutput runs the command and returns its combined standard
// output and standard error.
func (c *Cmd) CombinedOutput() ([]byte, os.Error) {
	if c.Stdout != nil {
		return nil, os.NewError("exec: Stdout already set")
	}
	if c.Stderr != nil {
		return nil, os.NewError("exec: Stderr already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	err := c.Run()
	return b.Bytes(), err
}

// StdinPipe returns a pipe that will be connected to the command's
// standard input when the command starts.
func (c *Cmd) StdinPipe() (io.WriteCloser, os.Error) {
	if c.Stdin != nil {
		return nil, os.NewError("exec: Stdin already set")
	}
	if c.Process != nil {
		return nil, os.NewError("exec: StdinPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stdin = pr
	c.closeAfterStart = append(c.closeAfterStart, pr)
	c.closeAfterWait = append(c.closeAfterStart, pw)
	return pw, nil
}

// StdoutPipe returns a pipe that will be connected to the command's
// standard output when the command starts.
func (c *Cmd) StdoutPipe() (io.Reader, os.Error) {
	if c.Stdout != nil {
		return nil, os.NewError("exec: Stdout already set")
	}
	if c.Process != nil {
		return nil, os.NewError("exec: StdoutPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stdout = pw
	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterStart, pr)
	return pr, nil
}

// StderrPipe returns a pipe that will be connected to the command's
// standard error when the command starts.
func (c *Cmd) StderrPipe() (io.Reader, os.Error) {
	if c.Stderr != nil {
		return nil, os.NewError("exec: Stderr already set")
	}
	if c.Process != nil {
		return nil, os.NewError("exec: StderrPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stderr = pw
	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterStart, pr)
	return pr, nil
}
<commit_msg>exec: closeAfterWait append bug<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package exec runs external commands. It wraps os.StartProcess to make it
// easier to remap stdin and stdout, connect I/O with pipes, and do other
// adjustments.
package exec

import (
	"bytes"
	"io"
	"os"
	"strconv"
	"syscall"
)

// Error records the name of a binary that failed to be be executed
// and the reason it failed.
type Error struct {
	Name  string
	Error os.Error
}

func (e *Error) String() string {
	return "exec: " + strconv.Quote(e.Name) + ": " + e.Error.String()
}

// Cmd represents an external command being prepared or run.
type Cmd struct {
	// Path is the path of the command to run.
	//
	// This is the only field that must be set to a non-zero
	// value.
	Path string

	// Args holds command line arguments, including the command as Args[0].
	// If the Args field is empty or nil, Run uses {Path}.
	//
	// In typical use, both Path and Args are set by calling Command.
	Args []string

	// Env specifies the environment of the process.
	// If Env is nil, Run uses the current process's environment.
	Env []string

	// Dir specifies the working directory of the command.
	// If Dir is the empty string, Run runs the command in the
	// calling process's current directory.
	Dir string

	// Stdin specifies the process's standard input.
	// If Stdin is nil, the process reads from DevNull.
	Stdin io.Reader

	// Stdout and Stderr specify the process's standard output and error.
	//
	// If either is nil, Run connects the
	// corresponding file descriptor to /dev/null.
	//
	// If Stdout and Stderr are are the same writer, at most one
	// goroutine at a time will call Write.
	Stdout io.Writer
	Stderr io.Writer

	// SysProcAttr holds optional, operating system-specific attributes.
	// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
	SysProcAttr *syscall.SysProcAttr

	// Process is the underlying process, once started.
	Process *os.Process

	err             os.Error // last error (from LookPath, stdin, stdout, stderr)
	finished        bool     // when Wait was called
	childFiles      []*os.File
	closeAfterStart []io.Closer
	closeAfterWait  []io.Closer
	goroutine       []func() os.Error
	errch           chan os.Error // one send per goroutine
}

// Command returns the Cmd struct to execute the named program with
// the given arguments.
//
// It sets Path and Args in the returned structure and zeroes the
// other fields.
//
// If name contains no path separators, Command uses LookPath to
// resolve the path to a complete name if possible. Otherwise it uses
// name directly.
//
// The returned Cmd's Args field is constructed from the command name
// followed by the elements of arg, so arg should not include the
// command name itself. For example, Command("echo", "hello")
func Command(name string, arg ...string) *Cmd {
	aname, err := LookPath(name)
	if err != nil {
		aname = name
	}
	return &Cmd{
		Path: aname,
		Args: append([]string{name}, arg...),
		err:  err,
	}
}

// interfaceEqual protects against panics from doing equality tests on
// two interfaces with non-comparable underlying types
func interfaceEqual(a, b interface{}) bool {
	defer func() {
		recover()
	}()
	return a == b
}

func (c *Cmd) envv() []string {
	if c.Env != nil {
		return c.Env
	}
	return os.Environ()
}

func (c *Cmd) argv() []string {
	if len(c.Args) > 0 {
		return c.Args
	}
	return []string{c.Path}
}

func (c *Cmd) stdin() (f *os.File, err os.Error) {
	if c.Stdin == nil {
		f, err = os.Open(os.DevNull)
		c.closeAfterStart = append(c.closeAfterStart, f)
		return
	}

	if f, ok := c.Stdin.(*os.File); ok {
		return f, nil
	}

	pr, pw, err := os.Pipe()
	if err != nil {
		return
	}

	c.closeAfterStart = append(c.closeAfterStart, pr)
	c.closeAfterWait = append(c.closeAfterWait, pw)
	c.goroutine = append(c.goroutine, func() os.Error {
		_, err := io.Copy(pw, c.Stdin)
		if err1 := pw.Close(); err == nil {
			err = err1
		}
		return err
	})
	return pr, nil
}

func (c *Cmd) stdout() (f *os.File, err os.Error) {
	return c.writerDescriptor(c.Stdout)
}

func (c *Cmd) stderr() (f *os.File, err os.Error) {
	if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
		return c.childFiles[1], nil
	}
	return c.writerDescriptor(c.Stderr)
}

func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
	if w == nil {
		f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
		c.closeAfterStart = append(c.closeAfterStart, f)
		return
	}

	if f, ok := w.(*os.File); ok {
		return f, nil
	}

	pr, pw, err := os.Pipe()
	if err != nil {
		return
	}

	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	c.goroutine = append(c.goroutine, func() os.Error {
		_, err := io.Copy(w, pr)
		return err
	})
	return pw, nil
}

// Run starts the specified command and waits for it to complete.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command fails to run or doesn't complete successfully, the
// error is of type *os.Waitmsg. Other error types may be
// returned for I/O problems.
func (c *Cmd) Run() os.Error {
	if err := c.Start(); err != nil {
		return err
	}
	return c.Wait()
}

// Start starts the specified command but does not wait for it to complete.
func (c *Cmd) Start() os.Error {
	if c.err != nil {
		return c.err
	}
	if c.Process != nil {
		return os.NewError("exec: already started")
	}

	type F func(*Cmd) (*os.File, os.Error)
	for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
		fd, err := setupFd(c)
		if err != nil {
			return err
		}
		c.childFiles = append(c.childFiles, fd)
	}

	var err os.Error
	c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
		Dir:   c.Dir,
		Files: c.childFiles,
		Env:   c.envv(),
		Sys:   c.SysProcAttr,
	})
	if err != nil {
		return err
	}

	for _, fd := range c.closeAfterStart {
		fd.Close()
	}

	c.errch = make(chan os.Error, len(c.goroutine))
	for _, fn := range c.goroutine {
		go func(fn func() os.Error) {
			c.errch <- fn()
		}(fn)
	}

	return nil
}

// Wait waits for the command to exit.
// It must have been started by Start.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command fails to run or doesn't complete successfully, the
// error is of type *os.Waitmsg. Other error types may be
// returned for I/O problems.
func (c *Cmd) Wait() os.Error {
	if c.Process == nil {
		return os.NewError("exec: not started")
	}
	if c.finished {
		return os.NewError("exec: Wait was already called")
	}
	c.finished = true
	msg, err := c.Process.Wait(0)

	var copyError os.Error
	for _ = range c.goroutine {
		if err := <-c.errch; err != nil && copyError == nil {
			copyError = err
		}
	}

	for _, fd := range c.closeAfterWait {
		fd.Close()
	}

	if err != nil {
		return err
	} else if !msg.Exited() || msg.ExitStatus() != 0 {
		return msg
	}

	return copyError
}

// Output runs the command and returns its standard output.
func (c *Cmd) Output() ([]byte, os.Error) {
	if c.Stdout != nil {
		return nil, os.NewError("exec: Stdout already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	err := c.Run()
	return b.Bytes(), err
}

// CombinedOutput runs the command and returns its combined standard
// output and standard error.
func (c *Cmd) CombinedOutput() ([]byte, os.Error) {
	if c.Stdout != nil {
		return nil, os.NewError("exec: Stdout already set")
	}
	if c.Stderr != nil {
		return nil, os.NewError("exec: Stderr already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	err := c.Run()
	return b.Bytes(), err
}

// StdinPipe returns a pipe that will be connected to the command's
// standard input when the command starts.
func (c *Cmd) StdinPipe() (io.WriteCloser, os.Error) {
	if c.Stdin != nil {
		return nil, os.NewError("exec: Stdin already set")
	}
	if c.Process != nil {
		return nil, os.NewError("exec: StdinPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stdin = pr
	c.closeAfterStart = append(c.closeAfterStart, pr)
	c.closeAfterWait = append(c.closeAfterWait, pw)
	return pw, nil
}

// StdoutPipe returns a pipe that will be connected to the command's
// standard output when the command starts.
func (c *Cmd) StdoutPipe() (io.Reader, os.Error) {
	if c.Stdout != nil {
		return nil, os.NewError("exec: Stdout already set")
	}
	if c.Process != nil {
		return nil, os.NewError("exec: StdoutPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stdout = pw
	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	return pr, nil
}

// StderrPipe returns a pipe that will be connected to the command's
// standard error when the command starts.
func (c *Cmd) StderrPipe() (io.Reader, os.Error) {
	if c.Stderr != nil {
		return nil, os.NewError("exec: Stderr already set")
	}
	if c.Process != nil {
		return nil, os.NewError("exec: StderrPipe after process started")
	}
	pr, pw, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	c.Stderr = pw
	c.closeAfterStart = append(c.closeAfterStart, pw)
	c.closeAfterWait = append(c.closeAfterWait, pr)
	return pr, nil
}
<|endoftext|>


<commit_before>package itest

import (
	"testing"

	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/flavors/generic"
	"github.com/ligato/cn-infra/flavors/local"
	"github.com/ligato/cn-infra/httpmux"
	"github.com/ligato/cn-infra/httpmux/mock"
	"github.com/onsi/gomega"
)

type suiteGenericFlavor struct {
	T *testing.T
	AgentT
	Given
	When
	Then
	mock.HttpMock
}

// MockGenericFlavor initializes generic flavor with HTTP mock
func MockGenericFlavor(mock *mock.HttpMock) *generic.FlavorGeneric {
	return &generic.FlavorGeneric{
		HTTP: *httpmux.FromExistingServer(mock.SetHandler),
	}
}

// TC01 asserts that injection works fine and agent starts & stops
func (t *suiteGenericFlavor) TC01StartStop() {
	flavor := MockGenericFlavor(&t.HttpMock)
	t.Setup(flavor, t.T)

	gomega.Expect(t.agent).ShouldNot(gomega.BeNil(), "agent is not initialized")

	defer t.Teardown()
}

// TC03 check that status check in flavor works
func (t *suiteGenericFlavor) TC03StatusCheck() {
	flavor := &local.FlavorLocal{}
	t.Setup(flavor, t.T)

	tstPlugin := core.PluginName("tstPlugin")
	flavor.StatusCheck.Register(tstPlugin, nil)
	flavor.StatusCheck.ReportStateChange(tstPlugin, "tst", nil)

	result, err := t.HttpMock.NewRequest("GET", flavor.ServiceLabel.GetAgentPrefix()+
		"/check/status/v1/agent", nil)
	gomega.Expect(err).Should(gomega.BeNil(), "logger is not initialized")
	gomega.Expect(result).ShouldNot(gomega.BeNil(), "http result is not initialized")
	gomega.Expect(result).Should(gomega.BeEquivalentTo(200))

	defer t.Teardown()
}
<commit_msg> ODPM-361 fix golint & go coverage in Makefile<commit_after>package itest

import (
	"testing"

	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/flavors/generic"
	"github.com/ligato/cn-infra/flavors/local"
	"github.com/ligato/cn-infra/httpmux"
	"github.com/ligato/cn-infra/httpmux/mock"
	"github.com/onsi/gomega"
)

type suiteGenericFlavor struct {
	T *testing.T
	AgentT
	Given
	When
	Then
	mock.HTTPMock
}

// MockGenericFlavor initializes generic flavor with HTTP mock
func MockGenericFlavor(mock *mock.HTTPMock) *generic.FlavorGeneric {
	return &generic.FlavorGeneric{
		HTTP: *httpmux.FromExistingServer(mock.SetHandler),
	}
}

// TC01 asserts that injection works fine and agent starts & stops
func (t *suiteGenericFlavor) TC01StartStop() {
	flavor := MockGenericFlavor(&t.HTTPMock)
	t.Setup(flavor, t.T)

	gomega.Expect(t.agent).ShouldNot(gomega.BeNil(), "agent is not initialized")

	defer t.Teardown()
}

// TC03 check that status check in flavor works
func (t *suiteGenericFlavor) TC03StatusCheck() {
	flavor := &local.FlavorLocal{}
	t.Setup(flavor, t.T)

	tstPlugin := core.PluginName("tstPlugin")
	flavor.StatusCheck.Register(tstPlugin, nil)
	flavor.StatusCheck.ReportStateChange(tstPlugin, "tst", nil)

	result, err := t.HTTPMock.NewRequest("GET", flavor.ServiceLabel.GetAgentPrefix()+
		"/check/status/v1/agent", nil)
	gomega.Expect(err).Should(gomega.BeNil(), "logger is not initialized")
	gomega.Expect(result).ShouldNot(gomega.BeNil(), "http result is not initialized")
	gomega.Expect(result).Should(gomega.BeEquivalentTo(200))

	defer t.Teardown()
}
<|endoftext|>