<commit_before>package apns

import (
	"crypto/tls"
	"encoding/binary"
	"log"
	"time"
)

//ResponseQueueSize indicates how many APNS responses may be buffered.
var ResponseQueueSize = 10000

//SentBufferSize is the maximum number of sent notifications which may be buffered.
var SentBufferSize = 10000

var maxBackoff = 20 * time.Second

//Connection represents a single connection to APNS.
type Connection struct {
	Client
	conn            *tls.Conn
	queue           chan PushNotification
	errors          chan BadPushNotification
	responses       chan Response
	shouldReconnect chan bool
	stopping        chan bool
	stopped         chan bool
	senderFinished  chan bool
	ackFinished     chan bool
}

//NewConnection initializes an APNS connection. Use Connection.Start() to actually start sending notifications.
func NewConnection(client *Client) *Connection {
	c := new(Connection)
	c.Client = *client
	c.queue = make(chan PushNotification)
	c.errors = make(chan BadPushNotification)
	c.responses = make(chan Response, ResponseQueueSize)
	c.shouldReconnect = make(chan bool)
	c.stopping = make(chan bool)
	c.stopped = make(chan bool)

	c.senderFinished = make(chan bool)
	c.ackFinished = make(chan bool)

	return c
}

//Response is a reply from APNS - see apns.ApplePushResponses.
type Response struct {
	Status     uint8
	Identifier uint32
}

func newResponse() Response {
	r := Response{}
	return r
}

//BadPushNotification represents a notification which APNS didn't like.
type BadPushNotification struct {
	PushNotification
	Status uint8
}

type timedPushNotification struct {
	PushNotification
	time.Time
}

func (pn PushNotification) timed() timedPushNotification {
	return timedPushNotification{PushNotification: pn, Time: time.Now()}
}

//Enqueue adds a push notification to the end of the "sending" queue.
func (conn *Connection) Enqueue(pn *PushNotification) {
	go func(pn *PushNotification) {
		conn.queue <- *pn
	}(pn)
}

//Errors gives you a channel of the push notifications Apple rejected.
func (conn *Connection) Errors() (errors <-chan BadPushNotification) {
	return conn.errors
}

//Start initiates a connection to APNS and asnchronously sends notifications which have been queued.
func (conn *Connection) Start() error {
	//Connect to APNS. The reason this is here as well as in sender is that this probably catches any unavoidable errors in a synchronous fashion, while in sender it can reconnect after temporary errors (which should work most of the time.)
	err := conn.connect()
	if err != nil {
		return err
	}
	//Start sender goroutine
	sent := make(chan PushNotification)
	go conn.sender(conn.queue, sent)
	//Start limbo goroutine
	go conn.limbo(sent, conn.responses, conn.errors, conn.queue)
	return nil
}

//Stop gracefully closes the connection - it waits for the sending queue to clear, and then shuts down.
func (conn *Connection) Stop() chan bool {
	log.Println("apns: shutting down.")
	conn.stopping <- true
	return conn.stopped
	//Thought: Don't necessarily need a channel here. Could signal finishing by closing errors?
}

func (conn *Connection) sender(queue <-chan PushNotification, sent chan PushNotification) {
	i := 0
	stopping := false
	defer conn.conn.Close()
	var backoff = time.Duration(100)
	for {
		select {
		case pn, ok := <-conn.queue:
			if !ok {
				log.Println("Not okay; queue closed.")
				//That means the Connection is stopped
				//close sent?
				return
			}
			//This means we saw a response; connection is over.
			select {
			case <-conn.shouldReconnect:
				conn.conn.Close()
				conn.conn = nil
				for {
					log.Println("Connection lost; reconnecting.")
					err := conn.connect()
					if err != nil {
						//Exponential backoff up to a limit
						log.Println("APNS: Error connecting to server: ", err)
						backoff = backoff * 2
						if backoff > maxBackoff {
							backoff = maxBackoff
						}
						time.Sleep(backoff)
					} else {
						backoff = 100
						log.Println("Connected...")
						break
					}
				}
			default:
			}
			//Then send the push notification
			payload, err := pn.ToBytes()
			if err != nil {
				log.Println(err)
				//Should report this on the bad notifications channel probably
			} else {
				n, err := conn.conn.Write(payload)
				if err != nil {
					log.Println(err)
					go func() {
						conn.shouldReconnect <- true
					}()
					//Disconnect?
				} else {
					i++
					log.Println("Sent count:", i)
					log.Println("Wrote bytes:", n, "of notification:", pn.Identifier)
					sent <- pn
					if stopping && len(queue) == 0 {
						log.Println("sender: I'm stopping and I've run out of things to send. Let's see if limbo is empty.")
						conn.senderFinished <- true
					}
				}
			}
		case <-conn.stopping:
			log.Println("sender: Got a stop message!")
			stopping = true
			if len(queue) == 0 {
				log.Println("sender: I'm stopping and I've run out of things to send. Let's see if limbo is empty.")
				conn.senderFinished <- true
			}
		case <-conn.ackFinished:
			log.Println("sender: limbo is empty!")
			if len(queue) == 0 {
				log.Println("sender: limbo is empty and so am I!")
				close(sent)
				return
			}
		}
	}
}

func (conn *Connection) reader(responses chan<- Response) {
	buffer := make([]byte, 6)
	for {
		n, err := conn.conn.Read(buffer)
		if err != nil && n < 6 {
			log.Println("APNS: Error before reading complete response", n, err)
			conn.conn.Close()
			conn.conn = nil
			return
		}
		command := uint8(buffer[0])
		if command != 8 {
			log.Println("Something went wrong: command should have been 8; it was actually", command)
		}
		resp := newResponse()
		resp.Identifier = binary.BigEndian.Uint32(buffer[2:6])
		resp.Status = uint8(buffer[1])
		responses <- resp
		conn.shouldReconnect <- true
		return
	}
}

func (conn *Connection) limbo(sent <-chan PushNotification, responses chan Response, errors chan BadPushNotification, queue chan PushNotification) {
	stopping := false
	limbo := make([]timedPushNotification, 0, SentBufferSize)
	ticker := time.NewTicker(1 * time.Second)
	for {
		select {
		case pn, ok := <-sent:
			//Drop it into the array
			limbo = append(limbo, pn.timed())
			stopping = false
			if !ok {
				log.Println("limbo: sent is closed, so sender is done. So am I, then!")
				close(errors)
				conn.stopped <- true
				return
			}
		case <-conn.senderFinished:
			//senderFinished means the sender thinks it's done.
			//However, sender might not be - limbo could resend some, if there are any left here.
			//So we just take note of this until limbo is empty too.
			stopping = true
		case resp, ok := <-responses:
			if !ok {
				//If the responses channel is closed,
				//that means we're shutting down the connection.
			}
			log.Println("Saw an error response; flushing up to", resp.Identifier)
			log.Println("PNs in limbo:", len(limbo))
			for i, pn := range limbo {
				if pn.Identifier == resp.Identifier {
					log.Println("Got the bad one!!! At index:", i, "identifier:", pn.Identifier)
					if resp.Status != 10 {
						//It was an error, we should report this on the error channel
						bad := BadPushNotification{PushNotification: pn.PushNotification, Status: resp.Status}
						go func(bad BadPushNotification) {
							errors <- bad
						}(bad)
					}
					if len(limbo) > i {
						log.Printf("Requeueing %d notifications\n", len(limbo)-(i+1))
						toRequeue := len(limbo) - (i + 1)
						if toRequeue > 0 {
							conn.requeue(limbo[i+1:])
							//We resent some notifications: that means we should wait for sender to tell us it's done, again.
							stopping = false
						}
					}
				}
			}
			limbo = make([]timedPushNotification, 0, SentBufferSize)
		case <-ticker.C:
			flushed := false
			log.Println("Notifications in limbo:", len(limbo))
			for i := range limbo {
				if limbo[i].After(time.Now().Add(-TimeoutSeconds * time.Second)) {
					log.Printf("The first %d notifications timed out ok.\n", i)
					newLimbo := make([]timedPushNotification, len(limbo[i:]), SentBufferSize)
					copy(newLimbo, limbo[i:])
					limbo = newLimbo
					log.Println("Size of limbo is now:", len(limbo))
					flushed = true
					break
				}
			}
			if !flushed {
				log.Println("Looks like every notification has timed out.")
				limbo = make([]timedPushNotification, 0, SentBufferSize)
			}
			if stopping && len(limbo) == 0 {
				//sender() is finished and so is limbo - so the connection is done.
				log.Println("limbo: I've flushed all my notifications. Tell sender I'm done.")
				conn.ackFinished <- true
			}
		}
	}
}

func (conn *Connection) requeue(queue []timedPushNotification) {
	for _, pn := range queue {
		conn.Enqueue(&pn.PushNotification)
	}
}

func (conn *Connection) connect() error {
	if conn.conn != nil {
		conn.conn.Close()
	}

	var cert tls.Certificate
	var err error
	if len(conn.CertificateBase64) == 0 && len(conn.KeyBase64) == 0 {
		// The user did not specify raw block contents, so check the filesystem.
		cert, err = tls.LoadX509KeyPair(conn.CertificateFile, conn.KeyFile)
	} else {
		// The user provided the raw block contents, so use that.
		cert, err = tls.X509KeyPair([]byte(conn.CertificateBase64), []byte(conn.KeyBase64))
	}

	if err != nil {
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	tlsConn, err := tls.Dial("tcp", conn.Gateway, conf)
	if err != nil {
		return err
	}
	err = tlsConn.Handshake()
	if err != nil {
		_ = tlsConn.Close()
		return err
	}
	conn.conn = tlsConn
	//Start reader goroutine
	go conn.reader(conn.responses)
	return nil
}
<commit_msg>More logging to find out where these notifications are going.<commit_after>package apns

import (
	"crypto/tls"
	"encoding/binary"
	"log"
	"time"
)

//ResponseQueueSize indicates how many APNS responses may be buffered.
var ResponseQueueSize = 10000

//SentBufferSize is the maximum number of sent notifications which may be buffered.
var SentBufferSize = 10000

var maxBackoff = 20 * time.Second

//Connection represents a single connection to APNS.
type Connection struct {
	Client
	conn            *tls.Conn
	queue           chan PushNotification
	errors          chan BadPushNotification
	responses       chan Response
	shouldReconnect chan bool
	stopping        chan bool
	stopped         chan bool
	senderFinished  chan bool
	ackFinished     chan bool
}

//NewConnection initializes an APNS connection. Use Connection.Start() to actually start sending notifications.
func NewConnection(client *Client) *Connection {
	c := new(Connection)
	c.Client = *client
	c.queue = make(chan PushNotification)
	c.errors = make(chan BadPushNotification)
	c.responses = make(chan Response, ResponseQueueSize)
	c.shouldReconnect = make(chan bool)
	c.stopping = make(chan bool)
	c.stopped = make(chan bool)

	c.senderFinished = make(chan bool)
	c.ackFinished = make(chan bool)

	return c
}

//Response is a reply from APNS - see apns.ApplePushResponses.
type Response struct {
	Status     uint8
	Identifier uint32
}

func newResponse() Response {
	r := Response{}
	return r
}

//BadPushNotification represents a notification which APNS didn't like.
type BadPushNotification struct {
	PushNotification
	Status uint8
}

type timedPushNotification struct {
	PushNotification
	time.Time
}

func (pn PushNotification) timed() timedPushNotification {
	return timedPushNotification{PushNotification: pn, Time: time.Now()}
}

//Enqueue adds a push notification to the end of the "sending" queue.
func (conn *Connection) Enqueue(pn *PushNotification) {
	go func(pn *PushNotification) {
		conn.queue <- *pn
		log.Println("enqueued")
	}(pn)
}

//Errors gives you a channel of the push notifications Apple rejected.
func (conn *Connection) Errors() (errors <-chan BadPushNotification) {
	return conn.errors
}

//Start initiates a connection to APNS and asnchronously sends notifications which have been queued.
func (conn *Connection) Start() error {
	//Connect to APNS. The reason this is here as well as in sender is that this probably catches any unavoidable errors in a synchronous fashion, while in sender it can reconnect after temporary errors (which should work most of the time.)
	err := conn.connect()
	if err != nil {
		return err
	}
	//Start sender goroutine
	sent := make(chan PushNotification)
	go conn.sender(conn.queue, sent)
	//Start limbo goroutine
	go conn.limbo(sent, conn.responses, conn.errors, conn.queue)
	return nil
}

//Stop gracefully closes the connection - it waits for the sending queue to clear, and then shuts down.
func (conn *Connection) Stop() chan bool {
	log.Println("apns: shutting down.")
	conn.stopping <- true
	return conn.stopped
	//Thought: Don't necessarily need a channel here. Could signal finishing by closing errors?
}

func (conn *Connection) sender(queue <-chan PushNotification, sent chan PushNotification) {
	i := 0
	stopping := false
	defer conn.conn.Close()
	var backoff = time.Duration(100)
	for {
		select {
		case pn, ok := <-conn.queue:
			log.Println("Got a PN to send")
			if !ok {
				log.Println("Not okay; queue closed.")
				//That means the Connection is stopped
				//close sent?
				return
			}
			//This means we saw a response; connection is over.
			select {
			case <-conn.shouldReconnect:
				conn.conn.Close()
				conn.conn = nil
				for {
					log.Println("Connection lost; reconnecting.")
					err := conn.connect()
					if err != nil {
						//Exponential backoff up to a limit
						log.Println("APNS: Error connecting to server: ", err)
						backoff = backoff * 2
						if backoff > maxBackoff {
							backoff = maxBackoff
						}
						time.Sleep(backoff)
					} else {
						backoff = 100
						log.Println("Connected...")
						break
					}
				}
			default:
			}
			//Then send the push notification
			payload, err := pn.ToBytes()
			if err != nil {
				log.Println(err)
				//Should report this on the bad notifications channel probably
			} else {
				n, err := conn.conn.Write(payload)
				if err != nil {
					log.Println(err)
					go func() {
						conn.shouldReconnect <- true
					}()
					//Disconnect?
				} else {
					i++
					log.Println("Sent count:", i)
					log.Println("Wrote bytes:", n, "of notification:", pn.Identifier)
					sent <- pn
					if stopping && len(queue) == 0 {
						log.Println("sender: I'm stopping and I've run out of things to send. Let's see if limbo is empty.")
						conn.senderFinished <- true
					}
				}
			}
		case <-conn.stopping:
			log.Println("sender: Got a stop message!")
			stopping = true
			if len(queue) == 0 {
				log.Println("sender: I'm stopping and I've run out of things to send. Let's see if limbo is empty.")
				conn.senderFinished <- true
			}
		case <-conn.ackFinished:
			log.Println("sender: limbo is empty!")
			if len(queue) == 0 {
				log.Println("sender: limbo is empty and so am I!")
				close(sent)
				return
			}
		}
	}
}

func (conn *Connection) reader(responses chan<- Response) {
	buffer := make([]byte, 6)
	for {
		n, err := conn.conn.Read(buffer)
		if err != nil && n < 6 {
			log.Println("APNS: Error before reading complete response", n, err)
			conn.conn.Close()
			conn.conn = nil
			return
		}
		command := uint8(buffer[0])
		if command != 8 {
			log.Println("Something went wrong: command should have been 8; it was actually", command)
		}
		resp := newResponse()
		resp.Identifier = binary.BigEndian.Uint32(buffer[2:6])
		resp.Status = uint8(buffer[1])
		responses <- resp
		conn.shouldReconnect <- true
		return
	}
}

func (conn *Connection) limbo(sent <-chan PushNotification, responses chan Response, errors chan BadPushNotification, queue chan PushNotification) {
	stopping := false
	limbo := make([]timedPushNotification, 0, SentBufferSize)
	ticker := time.NewTicker(1 * time.Second)
	for {
		select {
		case pn, ok := <-sent:
			//Drop it into the array
			limbo = append(limbo, pn.timed())
			stopping = false
			if !ok {
				log.Println("limbo: sent is closed, so sender is done. So am I, then!")
				close(errors)
				conn.stopped <- true
				return
			}
		case <-conn.senderFinished:
			//senderFinished means the sender thinks it's done.
			//However, sender might not be - limbo could resend some, if there are any left here.
			//So we just take note of this until limbo is empty too.
			stopping = true
		case resp, ok := <-responses:
			if !ok {
				//If the responses channel is closed,
				//that means we're shutting down the connection.
			}
			log.Println("Saw an error response; flushing up to", resp.Identifier)
			log.Println("PNs in limbo:", len(limbo))
			for i, pn := range limbo {
				if pn.Identifier == resp.Identifier {
					log.Println("Got the bad one!!! At index:", i, "identifier:", pn.Identifier)
					if resp.Status != 10 {
						//It was an error, we should report this on the error channel
						bad := BadPushNotification{PushNotification: pn.PushNotification, Status: resp.Status}
						go func(bad BadPushNotification) {
							errors <- bad
						}(bad)
					}
					if len(limbo) > i {
						log.Printf("Requeueing %d notifications\n", len(limbo)-(i+1))
						toRequeue := len(limbo) - (i + 1)
						if toRequeue > 0 {
							conn.requeue(limbo[i+1:])
							//We resent some notifications: that means we should wait for sender to tell us it's done, again.
							stopping = false
						}
					}
				}
			}
			limbo = make([]timedPushNotification, 0, SentBufferSize)
		case <-ticker.C:
			flushed := false
			log.Println("Notifications in limbo:", len(limbo))
			for i := range limbo {
				if limbo[i].After(time.Now().Add(-TimeoutSeconds * time.Second)) {
					log.Printf("The first %d notifications timed out ok.\n", i)
					newLimbo := make([]timedPushNotification, len(limbo[i:]), SentBufferSize)
					copy(newLimbo, limbo[i:])
					limbo = newLimbo
					log.Println("Size of limbo is now:", len(limbo))
					flushed = true
					break
				}
			}
			if !flushed {
				log.Println("Looks like every notification has timed out.")
				limbo = make([]timedPushNotification, 0, SentBufferSize)
			}
			if stopping && len(limbo) == 0 {
				//sender() is finished and so is limbo - so the connection is done.
				log.Println("limbo: I've flushed all my notifications. Tell sender I'm done.")
				conn.ackFinished <- true
			}
		}
	}
}

func (conn *Connection) requeue(queue []timedPushNotification) {
	for _, pn := range queue {
		conn.Enqueue(&pn.PushNotification)
	}
}

func (conn *Connection) connect() error {
	if conn.conn != nil {
		conn.conn.Close()
	}

	var cert tls.Certificate
	var err error
	if len(conn.CertificateBase64) == 0 && len(conn.KeyBase64) == 0 {
		// The user did not specify raw block contents, so check the filesystem.
		cert, err = tls.LoadX509KeyPair(conn.CertificateFile, conn.KeyFile)
	} else {
		// The user provided the raw block contents, so use that.
		cert, err = tls.X509KeyPair([]byte(conn.CertificateBase64), []byte(conn.KeyBase64))
	}

	if err != nil {
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	tlsConn, err := tls.Dial("tcp", conn.Gateway, conf)
	if err != nil {
		return err
	}
	err = tlsConn.Handshake()
	if err != nil {
		_ = tlsConn.Close()
		return err
	}
	conn.conn = tlsConn
	//Start reader goroutine
	go conn.reader(conn.responses)
	return nil
}
<|endoftext|>


<commit_before>package cons

import (
	"fmt"
	"strings"
)

const (
	start = "\033["
	Reset = "\033[0m"
)

var (
	plain  = false
	colors = map[string][2]string{
		"k": {"30", "40"},
		"r": {"31", "41"},
		"g": {"32", "42"},
		"y": {"33", "43"},
		"b": {"34", "44"},
		"m": {"35", "45"},
		"c": {"36", "46"},
		"w": {"37", "47"},
	}
	styles = map[string]string{
		"b": "1",
		"B": "5",
		"u": "4",
		"i": "7",
	}
	// Three diagnostics set after each call to Color()
	// Tracers[0] is three indexes used in parsing the arg to Color():
	//     the first +, the :, and the second +
	// Tracers[1] gives the parsed colors and styles as foreground color, style, background color, style
	// Tracers[2] gives the final ansi control string
	Tracers [3]string
)

func append_code(base string, code string) string {
	if len(code) == 0 {
		return base
	}
	appended := base
	if len(appended) > 0 {
		appended += ";"
	}
	appended += code
	return appended
}

type style_spec struct {
	fg_color string
	fg_style string
	bg_color string
	bg_style string
}

func (spec style_spec) get_string() string {
	var result string
	result = append_code(result, spec.fg_color)
	result = append_code(result, spec.fg_style)
	result = append_code(result, spec.bg_color)
	result = append_code(result, spec.bg_style)
	return result
}

// ColorCode returns the ansi control chars for coloring and styling console text
func ColorCode(code string) string {
	if plain || code == "" {
		return ""
	}
	if code == "reset" {
		return Reset
	}
	var spec style_spec
	ix_plus1 := strings.Index(code, "+")
	ix_plus2 := strings.LastIndex(code, "+")
	ix_colon := strings.Index(code, ":")
	Tracers[0] = fmt.Sprintf("%d %d %d", ix_plus1, ix_colon, ix_plus2)

	if ix_colon == -1 && ix_plus1 == -1 {
		spec.fg_color = code
	} else if ix_colon == -1 {
		spec.fg_color = code[:ix_plus1]
		spec.fg_style = code[ix_plus1+1 : len(code)]
	} else if ix_plus1 == -1 {
		spec.fg_color = code[:ix_colon]
		spec.bg_color = code[ix_colon+1 : len(code)]
	} else if ix_plus1 == ix_plus2 {
		if ix_plus1 < ix_colon {
			spec.fg_color = code[:ix_plus1]
			spec.fg_style = code[ix_plus1+1 : ix_colon]
			spec.bg_color = code[ix_colon+1 : len(code)]
		} else {
			spec.fg_color = code[:ix_colon]
			spec.bg_color = code[ix_colon+1 : ix_plus1]
			spec.bg_style = code[ix_plus1+1 : len(code)]
		}
	} else { // there is at least one colon and at least 2 plusses
		if ix_plus1 < ix_colon && ix_colon < ix_plus2 {
			spec.fg_color = code[:ix_plus1]
			spec.fg_style = code[ix_plus1+1 : ix_colon]
			spec.bg_color = code[ix_colon+1 : ix_plus2]
			spec.bg_style = code[ix_plus2+1 : len(code)]
		}
	}
	Tracers[1] = fmt.Sprintf("%s %s %s %s",
		spec.fg_color, spec.fg_style, spec.bg_color, spec.bg_style)

	// now map to the real styles
	spec.fg_color = colors[spec.fg_color][0]
	spec.fg_style = styles[spec.fg_style]
	spec.bg_color = colors[spec.bg_color][1]
	spec.bg_style = styles[spec.bg_style]
	// get the ansi codes without the start and end escapes
	// (useful for printing the codes without sending escapes)
	codes := spec.get_string()
	Tracers[2] = fmt.Sprintf("%s", codes)

	if len(codes) == 0 {
		return ""
	}
	return fmt.Sprintf("%s%sm", start, codes)
}

func resetIfNeeded(code string) string {
	if len(code) > 0 {
		return Reset
	}
	return ""
}

// Color(s, style) Surrounds `s` with ANSI color and reset code.
func Color(s, style string) string {
	code := ColorCode(style)
	return code + s + resetIfNeeded(code)
}

// ColorFunc Creates a fast closure.
//
// Prefer ColorFunc over Color as it does not recompute ANSI codes.
func ColorFunc(style string) func(string) string {
	if style == "" {
		return func(s string) string {
			return s
		}
	} else {
		code := ColorCode(style)
		return func(s string) string {
			return code + s + resetIfNeeded(code)
		}
	}
}

var ShowRed = ColorFunc("r")
var ShowMagenta = ColorFunc("m")
var ShowGreen = ColorFunc("g")

// DisableColors disables ANSI color codes. On by default.
func DisableColors(disable bool) {
	plain = disable
}
<commit_msg>added comments<commit_after>package cons

import (
	"fmt"
	"strings"
)

const (
	Start = "\033["
	Reset = "\033[0m"
)

var (
	plain  = false
	colors = map[string][2]string{
		"k": {"30", "40"}, // black
		"r": {"31", "41"}, // red
		"g": {"32", "42"}, // green
		"y": {"33", "43"}, // yellow
		"b": {"34", "44"}, // blue
		"m": {"35", "45"}, // magenta
		"c": {"36", "46"}, // cyan
		"w": {"37", "47"}, // white
	}
	styles = map[string]string{
		"b": "1", // bold
		"B": "5", // blink
		"u": "4", // underline
		"i": "7", // italic
	}
	// Three diagnostics set after each call to Color()
	// Tracers[0] is three indexes used in parsing the arg to Color():
	//     the first +, the :, and the second +
	// Tracers[1] gives the parsed colors and styles as foreground color, style, background color, style
	// Tracers[2] gives the final ansi control string
	Tracers [3]string
)

func append_code(base string, code string) string {
	if len(code) == 0 {
		return base
	}
	appended := base
	if len(appended) > 0 {
		appended += ";"
	}
	appended += code
	return appended
}

type style_spec struct {
	fg_color string
	fg_style string
	bg_color string
	bg_style string
}

func (spec style_spec) String() string {
	var result string
	result = append_code(result, spec.fg_color)
	result = append_code(result, spec.fg_style)
	result = append_code(result, spec.bg_color)
	result = append_code(result, spec.bg_style)
	return result
}

// ColorCode returns the ansi control chars for coloring and styling console text
func ColorCode(code string) string {
	if plain || code == "" {
		return ""
	}
	if code == "reset" {
		return Reset
	}
	var spec style_spec
	ix_plus1 := strings.Index(code, "+")
	ix_plus2 := strings.LastIndex(code, "+")
	ix_colon := strings.Index(code, ":")
	Tracers[0] = fmt.Sprintf("%d %d %d", ix_plus1, ix_colon, ix_plus2)

	if ix_colon == -1 && ix_plus1 == -1 {
		spec.fg_color = code
	} else if ix_colon == -1 {
		spec.fg_color = code[:ix_plus1]
		spec.fg_style = code[ix_plus1+1 : len(code)]
	} else if ix_plus1 == -1 {
		spec.fg_color = code[:ix_colon]
		spec.bg_color = code[ix_colon+1 : len(code)]
	} else if ix_plus1 == ix_plus2 {
		if ix_plus1 < ix_colon {
			spec.fg_color = code[:ix_plus1]
			spec.fg_style = code[ix_plus1+1 : ix_colon]
			spec.bg_color = code[ix_colon+1 : len(code)]
		} else {
			spec.fg_color = code[:ix_colon]
			spec.bg_color = code[ix_colon+1 : ix_plus1]
			spec.bg_style = code[ix_plus1+1 : len(code)]
		}
	} else { // there is at least one colon and at least 2 plusses
		if ix_plus1 < ix_colon && ix_colon < ix_plus2 {
			spec.fg_color = code[:ix_plus1]
			spec.fg_style = code[ix_plus1+1 : ix_colon]
			spec.bg_color = code[ix_colon+1 : ix_plus2]
			spec.bg_style = code[ix_plus2+1 : len(code)]
		}
	}
	Tracers[1] = fmt.Sprintf("%s %s %s %s",
		spec.fg_color, spec.fg_style, spec.bg_color, spec.bg_style)

	// now map to the real styles
	spec.fg_color = colors[spec.fg_color][0]
	spec.fg_style = styles[spec.fg_style]
	spec.bg_color = colors[spec.bg_color][1]
	spec.bg_style = styles[spec.bg_style]
	// get the ansi codes without the start and end escapes
	// (useful for printing the codes without sending escapes)
	Tracers[2] = fmt.Sprintf("%s", spec)

	if len(spec.String()) == 0 {
		return ""
	}
	return fmt.Sprintf("%s%sm", Start, spec)
}

func resetIfNeeded(code string) string {
	if len(code) > 0 {
		return Reset
	}
	return ""
}

// Color(s, style) Surrounds `s` with ANSI color and reset code.
func Color(s, style string) string {
	code := ColorCode(style)
	return code + s + resetIfNeeded(code)
}

// ColorFunc Creates a fast closure.
//
// Prefer ColorFunc over Color as it does not recompute ANSI codes.
func ColorFunc(style string) func(string) string {
	if style == "" {
		return func(s string) string {
			return s
		}
	} else {
		code := ColorCode(style)
		return func(s string) string {
			return code + s + resetIfNeeded(code)
		}
	}
}

var ShowRed = ColorFunc("r")
var ShowMagenta = ColorFunc("m")
var ShowGreen = ColorFunc("g")

// DisableColors disables ANSI color codes. On by default.
func DisableColors(disable bool) {
	plain = disable
}
<|endoftext|>


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

package virtcontainers

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"strconv"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/vishvananda/netlink"
)

const fileMode0640 = os.FileMode(0640)

func TestVhostUserSocketPath(t *testing.T) {

	// First test case: search for existing:
	addresses := []netlink.Addr{
		{
			IPNet: &net.IPNet{
				IP:   net.IPv4(192, 168, 0, 2),
				Mask: net.IPv4Mask(192, 168, 0, 2),
			},
		},
		{
			IPNet: &net.IPNet{
				IP:   net.IPv4(192, 168, 0, 1),
				Mask: net.IPv4Mask(192, 168, 0, 1),
			},
		},
	}

	expectedPath := "/tmp/vhostuser_192.168.0.1"
	expectedFileName := "vhu.sock"
	expectedResult := fmt.Sprintf("%s/%s", expectedPath, expectedFileName)

	err := os.Mkdir(expectedPath, 0777)
	if err != nil {
		t.Fatal(err)
	}

	_, err = os.Create(expectedResult)
	if err != nil {
		t.Fatal(err)
	}
	netinfo := NetworkInfo{
		Addrs: addresses,
	}

	path, _ := vhostUserSocketPath(netinfo)

	if path != expectedResult {
		t.Fatalf("Got %+v\nExpecting %+v", path, expectedResult)
	}

	// Second test case: search doesn't include matching vsock:
	addressesFalse := []netlink.Addr{
		{
			IPNet: &net.IPNet{
				IP:   net.IPv4(192, 168, 0, 4),
				Mask: net.IPv4Mask(192, 168, 0, 4),
			},
		},
	}
	netinfoFail := NetworkInfo{
		Addrs: addressesFalse,
	}

	path, _ = vhostUserSocketPath(netinfoFail)
	if path != "" {
		t.Fatalf("Got %+v\nExpecting %+v", path, "")
	}

	err = os.Remove(expectedResult)
	if err != nil {
		t.Fatal(err)
	}

	err = os.Remove(expectedPath)
	if err != nil {
		t.Fatal(err)
	}

}

func TestIsVFIO(t *testing.T) {
	type testData struct {
		path     string
		expected bool
	}

	data := []testData{
		{"/dev/vfio/16", true},
		{"/dev/vfio/1", true},
		{"/dev/vfio/", false},
		{"/dev/vfio", false},
		{"/dev/vf", false},
		{"/dev", false},
		{"/dev/vfio/vfio", false},
		{"/dev/vfio/vfio/12", false},
	}

	for _, d := range data {
		isVFIO := isVFIO(d.path)
		assert.Equal(t, d.expected, isVFIO)
	}
}

func TestIsBlock(t *testing.T) {
	type testData struct {
		devType  string
		expected bool
	}

	data := []testData{
		{"b", true},
		{"c", false},
		{"u", false},
	}

	for _, d := range data {
		isBlock := isBlock(DeviceInfo{DevType: d.devType})
		assert.Equal(t, d.expected, isBlock)
	}
}

func TestCreateDevice(t *testing.T) {
	devInfo := DeviceInfo{
		HostPath: "/dev/vfio/8",
		DevType:  "b",
	}

	device := createDevice(devInfo)
	_, ok := device.(*VFIODevice)
	assert.True(t, ok)

	devInfo.HostPath = "/dev/sda"
	device = createDevice(devInfo)
	_, ok = device.(*BlockDevice)
	assert.True(t, ok)

	devInfo.HostPath = "/dev/tty"
	devInfo.DevType = "c"
	device = createDevice(devInfo)
	_, ok = device.(*GenericDevice)
	assert.True(t, ok)
}

func TestNewDevices(t *testing.T) {
	savedSysDevPrefix := sysDevPrefix

	major := int64(252)
	minor := int64(3)

	tmpDir, err := ioutil.TempDir("", "")
	assert.Nil(t, err)

	sysDevPrefix = tmpDir
	defer func() {
		os.RemoveAll(tmpDir)
		sysDevPrefix = savedSysDevPrefix
	}()

	path := "/dev/vfio/2"
	deviceInfo := DeviceInfo{
		ContainerPath: "",
		Major:         major,
		Minor:         minor,
		UID:           2,
		GID:           2,
		DevType:       "c",
	}

	_, err = newDevices([]DeviceInfo{deviceInfo})
	assert.NotNil(t, err)

	format := strconv.FormatInt(major, 10) + ":" + strconv.FormatInt(minor, 10)
	ueventPathPrefix := filepath.Join(sysDevPrefix, "char", format)
	ueventPath := filepath.Join(ueventPathPrefix, "uevent")

	// Return true for non-existent /sys/dev path.
	deviceInfo.ContainerPath = path
	_, err = newDevices([]DeviceInfo{deviceInfo})
	assert.Nil(t, err)

	err = os.MkdirAll(ueventPathPrefix, dirMode)
	assert.Nil(t, err)

	// Should return error for bad data in uevent file
	content := []byte("nonkeyvaluedata")
	err = ioutil.WriteFile(ueventPath, content, fileMode0640)
	assert.Nil(t, err)

	_, err = newDevices([]DeviceInfo{deviceInfo})
	assert.NotNil(t, err)

	content = []byte("MAJOR=252\nMINOR=3\nDEVNAME=vfio/2")
	err = ioutil.WriteFile(ueventPath, content, fileMode0640)
	assert.Nil(t, err)

	devices, err := newDevices([]DeviceInfo{deviceInfo})
	assert.Nil(t, err)

	assert.Equal(t, len(devices), 1)
	vfioDev, ok := devices[0].(*VFIODevice)
	assert.True(t, ok)
	assert.Equal(t, vfioDev.DeviceInfo.HostPath, path)
	assert.Equal(t, vfioDev.DeviceInfo.ContainerPath, path)
	assert.Equal(t, vfioDev.DeviceInfo.DevType, "c")
	assert.Equal(t, vfioDev.DeviceInfo.Major, major)
	assert.Equal(t, vfioDev.DeviceInfo.Minor, minor)
	assert.Equal(t, vfioDev.DeviceInfo.UID, uint32(2))
	assert.Equal(t, vfioDev.DeviceInfo.GID, uint32(2))
}

func TestGetBDF(t *testing.T) {
	type testData struct {
		deviceStr   string
		expectedBDF string
	}

	data := []testData{
		{"0000:02:10.0", "02:10.0"},
		{"0000:0210.0", ""},
		{"test", ""},
		{"", ""},
	}

	for _, d := range data {
		deviceBDF, err := getBDF(d.deviceStr)
		assert.Equal(t, d.expectedBDF, deviceBDF)
		if d.expectedBDF == "" {
			assert.NotNil(t, err)
		} else {
			assert.Nil(t, err)
		}
	}
}

func TestAttachVFIODevice(t *testing.T) {
	tmpDir, err := ioutil.TempDir("", "")
	assert.Nil(t, err)
	os.RemoveAll(tmpDir)

	testFDIOGroup := "2"
	testDeviceBDFPath := "0000:00:1c.0"

	devicesDir := filepath.Join(tmpDir, testFDIOGroup, "devices")
	err = os.MkdirAll(devicesDir, dirMode)
	assert.Nil(t, err)

	deviceFile := filepath.Join(devicesDir, testDeviceBDFPath)
	_, err = os.Create(deviceFile)
	assert.Nil(t, err)

	savedIOMMUPath := sysIOMMUPath
	sysIOMMUPath = tmpDir

	defer func() {
		sysIOMMUPath = savedIOMMUPath
	}()

	path := filepath.Join(vfioPath, testFDIOGroup)
	deviceInfo := DeviceInfo{
		HostPath:      path,
		ContainerPath: path,
		DevType:       "c",
	}

	device := createDevice(deviceInfo)
	_, ok := device.(*VFIODevice)
	assert.True(t, ok)

	hypervisor := &mockHypervisor{}
	err = device.attach(hypervisor, &Container{})
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)
}

func TestAttachGenericDevice(t *testing.T) {
	path := "/dev/tty2"
	deviceInfo := DeviceInfo{
		HostPath:      path,
		ContainerPath: path,
		DevType:       "c",
	}

	device := createDevice(deviceInfo)
	_, ok := device.(*GenericDevice)
	assert.True(t, ok)

	hypervisor := &mockHypervisor{}
	err := device.attach(hypervisor, &Container{})
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)
}

func TestAttachBlockDevice(t *testing.T) {
	fs := &filesystem{}
	hypervisor := &mockHypervisor{}

	pod := &Pod{
		id:         testPodID,
		storage:    fs,
		hypervisor: hypervisor,
	}

	contID := "100"
	container := Container{
		pod: pod,
		id:  contID,
	}

	// create state file
	path := filepath.Join(runStoragePath, testPodID, container.ID())
	err := os.MkdirAll(path, dirMode)
	if err != nil {
		t.Fatal(err)
	}

	defer os.RemoveAll(path)

	stateFilePath := filepath.Join(path, stateFile)
	os.Remove(stateFilePath)

	_, err = os.Create(stateFilePath)
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove(stateFilePath)

	path = "/dev/hda"
	deviceInfo := DeviceInfo{
		HostPath:      path,
		ContainerPath: path,
		DevType:       "b",
	}

	device := createDevice(deviceInfo)
	_, ok := device.(*BlockDevice)
	assert.True(t, ok)

	container.state.State = ""
	err = device.attach(hypervisor, &container)
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)

	container.state.State = StateReady
	err = device.attach(hypervisor, &container)
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)
}
<commit_msg>test: Modify block device test to test for SCSI as well<commit_after>//
// Copyright (c) 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package virtcontainers

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"strconv"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/vishvananda/netlink"
)

const fileMode0640 = os.FileMode(0640)

func TestVhostUserSocketPath(t *testing.T) {

	// First test case: search for existing:
	addresses := []netlink.Addr{
		{
			IPNet: &net.IPNet{
				IP:   net.IPv4(192, 168, 0, 2),
				Mask: net.IPv4Mask(192, 168, 0, 2),
			},
		},
		{
			IPNet: &net.IPNet{
				IP:   net.IPv4(192, 168, 0, 1),
				Mask: net.IPv4Mask(192, 168, 0, 1),
			},
		},
	}

	expectedPath := "/tmp/vhostuser_192.168.0.1"
	expectedFileName := "vhu.sock"
	expectedResult := fmt.Sprintf("%s/%s", expectedPath, expectedFileName)

	err := os.Mkdir(expectedPath, 0777)
	if err != nil {
		t.Fatal(err)
	}

	_, err = os.Create(expectedResult)
	if err != nil {
		t.Fatal(err)
	}
	netinfo := NetworkInfo{
		Addrs: addresses,
	}

	path, _ := vhostUserSocketPath(netinfo)

	if path != expectedResult {
		t.Fatalf("Got %+v\nExpecting %+v", path, expectedResult)
	}

	// Second test case: search doesn't include matching vsock:
	addressesFalse := []netlink.Addr{
		{
			IPNet: &net.IPNet{
				IP:   net.IPv4(192, 168, 0, 4),
				Mask: net.IPv4Mask(192, 168, 0, 4),
			},
		},
	}
	netinfoFail := NetworkInfo{
		Addrs: addressesFalse,
	}

	path, _ = vhostUserSocketPath(netinfoFail)
	if path != "" {
		t.Fatalf("Got %+v\nExpecting %+v", path, "")
	}

	err = os.Remove(expectedResult)
	if err != nil {
		t.Fatal(err)
	}

	err = os.Remove(expectedPath)
	if err != nil {
		t.Fatal(err)
	}

}

func TestIsVFIO(t *testing.T) {
	type testData struct {
		path     string
		expected bool
	}

	data := []testData{
		{"/dev/vfio/16", true},
		{"/dev/vfio/1", true},
		{"/dev/vfio/", false},
		{"/dev/vfio", false},
		{"/dev/vf", false},
		{"/dev", false},
		{"/dev/vfio/vfio", false},
		{"/dev/vfio/vfio/12", false},
	}

	for _, d := range data {
		isVFIO := isVFIO(d.path)
		assert.Equal(t, d.expected, isVFIO)
	}
}

func TestIsBlock(t *testing.T) {
	type testData struct {
		devType  string
		expected bool
	}

	data := []testData{
		{"b", true},
		{"c", false},
		{"u", false},
	}

	for _, d := range data {
		isBlock := isBlock(DeviceInfo{DevType: d.devType})
		assert.Equal(t, d.expected, isBlock)
	}
}

func TestCreateDevice(t *testing.T) {
	devInfo := DeviceInfo{
		HostPath: "/dev/vfio/8",
		DevType:  "b",
	}

	device := createDevice(devInfo)
	_, ok := device.(*VFIODevice)
	assert.True(t, ok)

	devInfo.HostPath = "/dev/sda"
	device = createDevice(devInfo)
	_, ok = device.(*BlockDevice)
	assert.True(t, ok)

	devInfo.HostPath = "/dev/tty"
	devInfo.DevType = "c"
	device = createDevice(devInfo)
	_, ok = device.(*GenericDevice)
	assert.True(t, ok)
}

func TestNewDevices(t *testing.T) {
	savedSysDevPrefix := sysDevPrefix

	major := int64(252)
	minor := int64(3)

	tmpDir, err := ioutil.TempDir("", "")
	assert.Nil(t, err)

	sysDevPrefix = tmpDir
	defer func() {
		os.RemoveAll(tmpDir)
		sysDevPrefix = savedSysDevPrefix
	}()

	path := "/dev/vfio/2"
	deviceInfo := DeviceInfo{
		ContainerPath: "",
		Major:         major,
		Minor:         minor,
		UID:           2,
		GID:           2,
		DevType:       "c",
	}

	_, err = newDevices([]DeviceInfo{deviceInfo})
	assert.NotNil(t, err)

	format := strconv.FormatInt(major, 10) + ":" + strconv.FormatInt(minor, 10)
	ueventPathPrefix := filepath.Join(sysDevPrefix, "char", format)
	ueventPath := filepath.Join(ueventPathPrefix, "uevent")

	// Return true for non-existent /sys/dev path.
	deviceInfo.ContainerPath = path
	_, err = newDevices([]DeviceInfo{deviceInfo})
	assert.Nil(t, err)

	err = os.MkdirAll(ueventPathPrefix, dirMode)
	assert.Nil(t, err)

	// Should return error for bad data in uevent file
	content := []byte("nonkeyvaluedata")
	err = ioutil.WriteFile(ueventPath, content, fileMode0640)
	assert.Nil(t, err)

	_, err = newDevices([]DeviceInfo{deviceInfo})
	assert.NotNil(t, err)

	content = []byte("MAJOR=252\nMINOR=3\nDEVNAME=vfio/2")
	err = ioutil.WriteFile(ueventPath, content, fileMode0640)
	assert.Nil(t, err)

	devices, err := newDevices([]DeviceInfo{deviceInfo})
	assert.Nil(t, err)

	assert.Equal(t, len(devices), 1)
	vfioDev, ok := devices[0].(*VFIODevice)
	assert.True(t, ok)
	assert.Equal(t, vfioDev.DeviceInfo.HostPath, path)
	assert.Equal(t, vfioDev.DeviceInfo.ContainerPath, path)
	assert.Equal(t, vfioDev.DeviceInfo.DevType, "c")
	assert.Equal(t, vfioDev.DeviceInfo.Major, major)
	assert.Equal(t, vfioDev.DeviceInfo.Minor, minor)
	assert.Equal(t, vfioDev.DeviceInfo.UID, uint32(2))
	assert.Equal(t, vfioDev.DeviceInfo.GID, uint32(2))
}

func TestGetBDF(t *testing.T) {
	type testData struct {
		deviceStr   string
		expectedBDF string
	}

	data := []testData{
		{"0000:02:10.0", "02:10.0"},
		{"0000:0210.0", ""},
		{"test", ""},
		{"", ""},
	}

	for _, d := range data {
		deviceBDF, err := getBDF(d.deviceStr)
		assert.Equal(t, d.expectedBDF, deviceBDF)
		if d.expectedBDF == "" {
			assert.NotNil(t, err)
		} else {
			assert.Nil(t, err)
		}
	}
}

func TestAttachVFIODevice(t *testing.T) {
	tmpDir, err := ioutil.TempDir("", "")
	assert.Nil(t, err)
	os.RemoveAll(tmpDir)

	testFDIOGroup := "2"
	testDeviceBDFPath := "0000:00:1c.0"

	devicesDir := filepath.Join(tmpDir, testFDIOGroup, "devices")
	err = os.MkdirAll(devicesDir, dirMode)
	assert.Nil(t, err)

	deviceFile := filepath.Join(devicesDir, testDeviceBDFPath)
	_, err = os.Create(deviceFile)
	assert.Nil(t, err)

	savedIOMMUPath := sysIOMMUPath
	sysIOMMUPath = tmpDir

	defer func() {
		sysIOMMUPath = savedIOMMUPath
	}()

	path := filepath.Join(vfioPath, testFDIOGroup)
	deviceInfo := DeviceInfo{
		HostPath:      path,
		ContainerPath: path,
		DevType:       "c",
	}

	device := createDevice(deviceInfo)
	_, ok := device.(*VFIODevice)
	assert.True(t, ok)

	hypervisor := &mockHypervisor{}
	err = device.attach(hypervisor, &Container{})
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)
}

func TestAttachGenericDevice(t *testing.T) {
	path := "/dev/tty2"
	deviceInfo := DeviceInfo{
		HostPath:      path,
		ContainerPath: path,
		DevType:       "c",
	}

	device := createDevice(deviceInfo)
	_, ok := device.(*GenericDevice)
	assert.True(t, ok)

	hypervisor := &mockHypervisor{}
	err := device.attach(hypervisor, &Container{})
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)
}

func TestAttachBlockDevice(t *testing.T) {
	fs := &filesystem{}
	hypervisor := &mockHypervisor{}

	hConfig := HypervisorConfig{
		BlockDeviceDriver: VirtioBlock,
	}

	config := &PodConfig{
		HypervisorConfig: hConfig,
	}

	pod := &Pod{
		id:         testPodID,
		storage:    fs,
		hypervisor: hypervisor,
		config:     config,
	}

	contID := "100"
	container := Container{
		pod: pod,
		id:  contID,
	}

	// create state file
	path := filepath.Join(runStoragePath, testPodID, container.ID())
	err := os.MkdirAll(path, dirMode)
	if err != nil {
		t.Fatal(err)
	}

	defer os.RemoveAll(path)

	stateFilePath := filepath.Join(path, stateFile)
	os.Remove(stateFilePath)

	_, err = os.Create(stateFilePath)
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove(stateFilePath)

	path = "/dev/hda"
	deviceInfo := DeviceInfo{
		HostPath:      path,
		ContainerPath: path,
		DevType:       "b",
	}

	device := createDevice(deviceInfo)
	_, ok := device.(*BlockDevice)
	assert.True(t, ok)

	container.state.State = ""
	err = device.attach(hypervisor, &container)
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)

	container.state.State = StateReady
	err = device.attach(hypervisor, &container)
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)

	container.pod.config.HypervisorConfig.BlockDeviceDriver = VirtioSCSI
	err = device.attach(hypervisor, &container)
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)

	container.state.State = StateReady
	err = device.attach(hypervisor, &container)
	assert.Nil(t, err)

	err = device.detach(hypervisor)
	assert.Nil(t, err)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	_ "devops/routers"
	"github.com/astaxie/beego"
)

func main() {
	beego.Run()
}
<commit_msg>Simplify main.go not to use beego<commit_after>/*
Copyright 2019 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"context"
	"fmt"
	"html/template"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"time"

	"cloud.google.com/go/profiler"
	"contrib.go.opencensus.io/exporter/stackdriver"
	log "github.com/sirupsen/logrus"
	"go.opencensus.io/trace"
	"golang.org/x/oauth2/google"
)

var projectID = ""

const (
	service        = "devops-demo"
	serviceVersion = "1.0.1"
	metricPrefix   = "devops-"
)

// A IndexVariables represents variables used in a template (index.html)
type IndexVariables struct {
	WebsiteTitle string
	RandomNumber string
}

func logRequest(r *http.Request, traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"UserAgent":                     r.UserAgent(),
		"RequestURL":                    r.Host,
		"RequestURI":                    r.RequestURI,
		"RequestMethod":                 r.Method,
		"Host":                          r.Host,
		"Proto":                         r.Proto,
		"ProtoMajor":                    r.ProtoMajor,
		"ProtoMinor":                    r.ProtoMinor,
		"RemoteAddr":                    r.RemoteAddr,
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func logMethod(traceID string, spanID string, msg string) {
	log.WithFields(log.Fields{
		"logging.googleapis.com/trace":  "projects/" + projectID + "/traces/" + traceID,
		"logging.googleapis.com/spanId": spanID,
	}).Info(msg)
}

func mainHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, span := trace.StartSpan(context.Background(), "/")
		defer span.End()
		s := span.SpanContext()

		addAttributesToSpan(span, r)
		logRequest(r, s.TraceID.String(), s.SpanID.String(), "Hello from mainHandler")

		iv := &IndexVariables{
			WebsiteTitle: "Main",
			RandomNumber: strconv.Itoa(rand.Intn(100)),
		}

		renderTemplate(w, iv)
	})
}

func benchHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx, span := trace.StartSpan(context.Background(), "/bench1")
		defer span.End()
		s := span.SpanContext()

		addAttributesToSpan(span, r)
		logRequest(r, s.TraceID.String(), s.SpanID.String(), "Hello from benchHandler")

		// Stress
		fibonacci(ctx, rand.Intn(3000000000))
		fibonacci(ctx, rand.Intn(3000000000))
		fibonacci(ctx, rand.Intn(3000000000))

		iv := &IndexVariables{
			WebsiteTitle: "Bench",
			RandomNumber: strconv.Itoa(rand.Intn(100)),
		}
		renderTemplate(w, iv)
	})
}

func addAttributesToSpan(span *trace.Span, r *http.Request) {
	span.AddAttributes(
		trace.StringAttribute("Method", r.Method),
		trace.StringAttribute("Host", r.Host),
		trace.StringAttribute("Proto", r.Proto),
		trace.Int64Attribute("ProtoMajor", int64(r.ProtoMajor)),
		trace.Int64Attribute("ProtoMinor", int64(r.ProtoMinor)),
		trace.Int64Attribute("ContentLength", int64(r.ContentLength)),
		trace.StringAttribute("RequestURI", r.RequestURI),
		trace.StringAttribute("RemoteAddr", r.RemoteAddr),
		trace.StringAttribute("UserAgent", r.UserAgent()),
		trace.StringAttribute("Referer", r.Referer()),
	)
}

func waitRandomMilliseconds(ctx context.Context) {
	_, span := trace.StartSpan(ctx, "waitRandomMilliseconds")
	defer span.End()
	time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
}

func fibonacci(ctx context.Context, loopNum int) {
	_, span := trace.StartSpan(ctx, "fibonacci")
	s := span.SpanContext()
	defer span.End()
	prev, next := 0, 1
	for i := 0; i < loopNum; i++ {
		prev, next = next, prev+next
	}
	span.AddAttributes(trace.Int64Attribute("loopNum", int64(loopNum)))

	logMethod(s.TraceID.String(), s.SpanID.String(), fmt.Sprintf("Fibonacci calculation completed: %v loops", loopNum))
}

var templates = template.Must(template.ParseFiles("./template/index.html"))

func renderTemplate(w http.ResponseWriter, iv *IndexVariables) {
	err := templates.Execute(w, iv)
	if err != nil {
		log.Printf("Failed to render a template: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func initLogSettings() {
	log.SetFormatter(&log.JSONFormatter{
		FieldMap: log.FieldMap{
			log.FieldKeyTime:  "time",
			log.FieldKeyLevel: "severity",
			log.FieldKeyMsg:   "message",
		},
		TimestampFormat: time.RFC3339Nano,
	})
	log.SetOutput(os.Stdout)
	log.SetLevel(log.InfoLevel)
}

func main() {
	rand.Seed(time.Now().UnixNano())

	initLogSettings()

	// Initialize the credential and projectID with Application Default Credentials (ADC)
	ctx := context.Background()
	cred, err := google.FindDefaultCredentials(ctx)
	if err != nil {
		log.Fatal(err.Error())
	}
	projectID = cred.ProjectID
	log.Infof("Successfully retrieved GCP Project ID: %v", projectID)

	// Initialize Profiler
	if err := profiler.Start(profiler.Config{
		Service:        service,
		ServiceVersion: serviceVersion,
		ProjectID:      projectID,
	}); err != nil {
		log.Fatal(err.Error())
	}
	log.Info("Successfully initialized profiler")

	// Initialize exporter
	exporter, err := stackdriver.NewExporter(stackdriver.Options{
		ProjectID:    projectID,
		MetricPrefix: metricPrefix,
	})
	if err != nil {
		log.Fatal(err.Error())
	}
	log.Info("Successfully initialized exporter")
	defer exporter.Flush()
	trace.RegisterExporter(exporter)
	trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})

	// Serve static files under /static/ directory
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))

	// Register handlers
	http.Handle("/", mainHandler())
	http.Handle("/bench1", benchHandler())

	log.Info("Start listening : 8080...")
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package custom

import (
    "hyrax/types"
    "hyrax/storage"
    "hyrax/router"
    "hyrax/parse"
    "strconv"
    "log"
    "errors"
)

// AMon is available publicly as a command, but is also used internally, as
// all other *Mon commands wrap around it. It adds the connection's id to the
// set of connections that are monitoring the domain/id in redis (so it can
// receive alerts) and adds the domain/id to the set of domain/ids that the
// connection is monitoring in redis (so it can clean up when the connection
// closes).
func AMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    monkey := storage.MonKey(pay.Domain,pay.Id)
    connmonkey := storage.ConnMonKey(cid)
    connmonval := storage.ConnMonVal(pay.Domain,pay.Id)

    _,err := storage.CmdPretty("SADD",connmonkey,connmonval)
    if err != nil { return nil,err }

    _,err = storage.CmdPretty("SADD",monkey,cid)
    return "OK",err
}

// Mon sets up monitoring on a value and returns it, assuming it's a
// string
func Mon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)
    return storage.CmdPretty("GET",dirkey)
}

// HMon sets up monitoring on a value and returns it, assuming it's a
// hash
func HMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)

    r,err := storage.CmdPretty("HGETALL",dirkey)
    if err != nil { return nil,err }

    return storage.RedisListToMap(r.([]string))
}

// LMon sets up monitoring on a value and returns it, assuming it's a
// list
func LMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)
    return storage.CmdPretty("LRANGE",dirkey,0,-1)
}

// SMon sets up monitoring on a value and returns it, assuming it's a
// set
func SMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)
    return storage.CmdPretty("SMEMBERS",dirkey)
}

// ZMon sets up monitoring on a value and returns it, assuming it's a
// sorted set
func ZMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)

    // BUG(mediocregopher): what is this I don't even? SMEMBERS /= sorted set
    r,err := storage.CmdPretty("SMEMBERS",dirkey)
    if err != nil { return nil,err }

    return storage.RedisListToIntMap(r.([]string))
}

// EMon sets up monitoring on a value and returns it, assuming it's an
// ekg
func EMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }

    return EMembers(cid,pay)
}

// CleanConnMon takes in a connection id and cleans up all of its
// monitors, and the set which keeps track of those monitors
func CleanConnMon(cid types.ConnId) error {
    connmonkey := storage.ConnMonKey(cid)
    r,err := storage.CmdPretty("SMEMBERS",connmonkey)
    if err != nil { return err }

    mons := r.([]string)

    for i := range mons {
        domain,id := storage.DeconstructConnMonVal(mons[i])
        monkey := storage.MonKey(domain,id)
        _,err = storage.CmdPretty("SREM",monkey,cid)
        if err != nil { return err }
    }

    _,err = storage.CmdPretty("DEL",connmonkey)
    return err
}

var monCh chan *types.Command

// monPushPayload is the payload for push notifications. It is basically
// the standard payload object but without the secret, and with a command
// string field instead
type monPushPayload struct {
    Domain  string   `json:"domain"`
    Id      string   `json:"id"`
    Name    string   `json:"name"`
    Command string   `json:"command"`
    Values  []string `json:"values"`
}

// MonMakeAlert takes in a command that's being performed and sends
// out alerts to anyone monitoring that command
func MonMakeAlert(cmd *types.Command) {
    monCh <- cmd
}

// monHandleAlert actually does the fetching of monitors on a value and
// and sends them alerts
func monHandleAlert(cmd *types.Command) error {
    monkey := storage.MonKey(cmd.Payload.Domain,cmd.Payload.Id)
    r,err := storage.CmdPretty("SMEMBERS",monkey)
    if err != nil { return err }
    idstrs := r.([]string)

    if len(idstrs) == 0 { return nil }
    var pay monPushPayload
    pay.Domain = cmd.Payload.Domain
    pay.Id = cmd.Payload.Id
    pay.Name = cmd.Payload.Name
    pay.Command = cmd.Command
    pay.Values = cmd.Payload.Values

    for i := range idstrs {
        id,err := strconv.Atoi(idstrs[i])
        if err != nil {
            return errors.New(err.Error()+" when converting "+idstrs[i]+" to int")
        }

        msg,err := parse.EncodeMessage("mon-push",pay)
        if err != nil {
            return errors.New(err.Error()+" when encoding mon push message")
        }

        router.SendPushMessage(types.ConnId(id),msg)
    }

    return nil

}

// init creates a bunch of routines that will read in commands that require alerts
// and call monHandleAlert on them
func init() {
    monCh = make(chan *types.Command)

    for i:=0; i<10; i++ {
        go func(){
            for {
                cmd := <-monCh
                err := monHandleAlert(cmd)
                if err != nil {
                    log.Printf("%s when calling monHandleAlert(%v)\n",err.Error(),cmd)
                }
            }
        }()
    }

}
<commit_msg>made zmon properly return the current value of the sorted set<commit_after>package custom

import (
    "hyrax/types"
    "hyrax/storage"
    "hyrax/router"
    "hyrax/parse"
    "strconv"
    "log"
    "errors"
)

// AMon is available publicly as a command, but is also used internally, as
// all other *Mon commands wrap around it. It adds the connection's id to the
// set of connections that are monitoring the domain/id in redis (so it can
// receive alerts) and adds the domain/id to the set of domain/ids that the
// connection is monitoring in redis (so it can clean up when the connection
// closes).
func AMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    monkey := storage.MonKey(pay.Domain,pay.Id)
    connmonkey := storage.ConnMonKey(cid)
    connmonval := storage.ConnMonVal(pay.Domain,pay.Id)

    _,err := storage.CmdPretty("SADD",connmonkey,connmonval)
    if err != nil { return nil,err }

    _,err = storage.CmdPretty("SADD",monkey,cid)
    return "OK",err
}

// Mon sets up monitoring on a value and returns it, assuming it's a
// string
func Mon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)
    return storage.CmdPretty("GET",dirkey)
}

// HMon sets up monitoring on a value and returns it, assuming it's a
// hash
func HMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)

    r,err := storage.CmdPretty("HGETALL",dirkey)
    if err != nil { return nil,err }

    return storage.RedisListToMap(r.([]string))
}

// LMon sets up monitoring on a value and returns it, assuming it's a
// list
func LMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)
    return storage.CmdPretty("LRANGE",dirkey,0,-1)
}

// SMon sets up monitoring on a value and returns it, assuming it's a
// set
func SMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)
    return storage.CmdPretty("SMEMBERS",dirkey)
}

// ZMon sets up monitoring on a value and returns it, assuming it's a
// sorted set
func ZMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }
    dirkey := storage.DirectKey(pay.Domain,pay.Id)

    r,err := storage.CmdPretty("ZRANGE",dirkey,0,-1,"WITHSCORES")
    if err != nil { return nil,err }

    return storage.RedisListToIntMap(r.([]string))
}

// EMon sets up monitoring on a value and returns it, assuming it's an
// ekg
func EMon(cid types.ConnId, pay *types.Payload) (interface{},error) {
    _,err := AMon(cid,pay)
    if err != nil { return nil,err }

    return EMembers(cid,pay)
}

// CleanConnMon takes in a connection id and cleans up all of its
// monitors, and the set which keeps track of those monitors
func CleanConnMon(cid types.ConnId) error {
    connmonkey := storage.ConnMonKey(cid)
    r,err := storage.CmdPretty("SMEMBERS",connmonkey)
    if err != nil { return err }

    mons := r.([]string)

    for i := range mons {
        domain,id := storage.DeconstructConnMonVal(mons[i])
        monkey := storage.MonKey(domain,id)
        _,err = storage.CmdPretty("SREM",monkey,cid)
        if err != nil { return err }
    }

    _,err = storage.CmdPretty("DEL",connmonkey)
    return err
}

var monCh chan *types.Command

// monPushPayload is the payload for push notifications. It is basically
// the standard payload object but without the secret, and with a command
// string field instead
type monPushPayload struct {
    Domain  string   `json:"domain"`
    Id      string   `json:"id"`
    Name    string   `json:"name"`
    Command string   `json:"command"`
    Values  []string `json:"values"`
}

// MonMakeAlert takes in a command that's being performed and sends
// out alerts to anyone monitoring that command
func MonMakeAlert(cmd *types.Command) {
    monCh <- cmd
}

// monHandleAlert actually does the fetching of monitors on a value and
// and sends them alerts
func monHandleAlert(cmd *types.Command) error {
    monkey := storage.MonKey(cmd.Payload.Domain,cmd.Payload.Id)
    r,err := storage.CmdPretty("SMEMBERS",monkey)
    if err != nil { return err }
    idstrs := r.([]string)

    if len(idstrs) == 0 { return nil }
    var pay monPushPayload
    pay.Domain = cmd.Payload.Domain
    pay.Id = cmd.Payload.Id
    pay.Name = cmd.Payload.Name
    pay.Command = cmd.Command
    pay.Values = cmd.Payload.Values

    for i := range idstrs {
        id,err := strconv.Atoi(idstrs[i])
        if err != nil {
            return errors.New(err.Error()+" when converting "+idstrs[i]+" to int")
        }

        msg,err := parse.EncodeMessage("mon-push",pay)
        if err != nil {
            return errors.New(err.Error()+" when encoding mon push message")
        }

        router.SendPushMessage(types.ConnId(id),msg)
    }

    return nil

}

// init creates a bunch of routines that will read in commands that require alerts
// and call monHandleAlert on them
func init() {
    monCh = make(chan *types.Command)

    for i:=0; i<10; i++ {
        go func(){
            for {
                cmd := <-monCh
                err := monHandleAlert(cmd)
                if err != nil {
                    log.Printf("%s when calling monHandleAlert(%v)\n",err.Error(),cmd)
                }
            }
        }()
    }

}
<|endoftext|>


<commit_before>package custom

import (
	"fmt"
	"io/ioutil"
	"log"
	"strconv"
	"time"

	"gopkg.in/rana/ora.v4"
)

type Number string

func (n *Number) Set(num ora.OCINum) {
	*n = Number(num.String())
}
func (n Number) Get() ora.OCINum {
	var num ora.OCINum
	num.SetString(string(n))
	return num
}

type Date string

const timeFormat = "2006-01-02 15:04:05 -0700"

func NewDate(date ora.Date) Date {
	t := date.Get()
	if t.IsZero() {
		return Date("")
	}
	return Date(t.Format(timeFormat))
}
func (d *Date) Set(date ora.Date) {
	if date.IsNull() {
		*d = Date("")
	}
	*d = NewDate(date)
}
func (d Date) Get() (od ora.Date) {
	if d == "" {
		return
	}
	t, err := time.Parse(timeFormat[:len(d)], string(d)) // TODO(tgulacsi): more robust parser
	if err != nil || t.IsZero() {
		return
	}
	od.Set(t)
	return
}

type Lob struct {
	ora.Lob
	data []byte
	err  error
}

func (L *Lob) read() error {
	if L.err != nil {
		return L.err
	}
	if L.data == nil {
		L.data, L.err = ioutil.ReadAll(L.Lob)
	}
	return L.err
}
func (L *Lob) Size() int {
	if L.read() != nil {
		return 0
	}
	return len(L.data)
}
func (L *Lob) Marshal() ([]byte, error) {
	err := L.read()
	return L.data, err
}
func (L *Lob) MarshalTo(p []byte) (int, error) {
	err := L.read()
	i := copy(p, L.data)
	return i, err
}
func (L *Lob) Unmarshal(p []byte) error {
	L.data = p
	return nil
}

func AsString(v interface{}) string {
	if v == nil {
		return ""
	}
	switch x := v.(type) {
	case string:
		return x
	case ora.String:
		return x.Value
	}
	return fmt.Sprintf("%v", v)
}

func AsFloat64(v interface{}) float64 {
	if v == nil {
		return 0
	}
	switch x := v.(type) {
	case float64:
		return x
	case float32:
		return float64(x)
	case int64:
		return float64(x)
	case int32:
		return float64(x)
	case ora.Float64:
		return x.Value
	case ora.Float32:
		return float64(x.Value)
	case string:
		if x == "" {
			return 0
		}
		f, err := strconv.ParseFloat(x, 64)
		if err != nil {
			log.Printf("ERROR parsing %q as Float64", x)
		}
		return f
	default:
		log.Printf("WARN: unknown Int64 type %T", v)
	}
	return 0
}
func AsInt32(v interface{}) int32 {
	if v == nil {
		return 0
	}
	switch x := v.(type) {
	case int32:
		return x
	case int64:
		return int32(x)
	case float64:
		return int32(x)
	case float32:
		return int32(x)
	case ora.Int32:
		return x.Value
	case ora.Int64:
		return int32(x.Value)
	case string:
		if x == "" {
			return 0
		}
		i, err := strconv.ParseInt(x, 10, 32)
		if err != nil {
			log.Printf("ERROR parsing %q as Int32", x)
		}
		return int32(i)
	default:
		log.Printf("WARN: unknown Int32 type %T", v)
	}
	return 0
}
func AsInt64(v interface{}) int64 {
	switch x := v.(type) {
	case int64:
		return x
	case int32:
		return int64(x)
	case float64:
		return int64(x)
	case float32:
		return int64(x)
	case ora.Int64:
		return x.Value
	case ora.Int32:
		return int64(x.Value)
	case string:
		if x == "" {
			return 0
		}
		i, err := strconv.ParseInt(x, 10, 64)
		if err != nil {
			log.Printf("ERROR parsing %q as Int64", x)
		}
		return i
	default:
		log.Printf("WARN: unknown Int64 type %T", v)
	}
	return 0
}
func AsDate(v interface{}) Date {
	if v == nil {
		return ""
	}
	switch x := v.(type) {
	case Date:
		return x
	case time.Time:
		return Date(x.Format(timeFormat))
	case string:
		return Date(x)
	case ora.Date:
		var d Date
		d.Set(x)
		return d
	default:
		log.Printf("WARN: unknown Date type %T", v)
	}

	return Date("")
}
<commit_msg>ora.Lob needs pointer receiver<commit_after>package custom

import (
	"fmt"
	"io/ioutil"
	"log"
	"strconv"
	"time"

	"gopkg.in/rana/ora.v4"
)

type Number string

func (n *Number) Set(num ora.OCINum) {
	*n = Number(num.String())
}
func (n Number) Get() ora.OCINum {
	var num ora.OCINum
	num.SetString(string(n))
	return num
}

type Date string

const timeFormat = "2006-01-02 15:04:05 -0700"

func NewDate(date ora.Date) Date {
	t := date.Get()
	if t.IsZero() {
		return Date("")
	}
	return Date(t.Format(timeFormat))
}
func (d *Date) Set(date ora.Date) {
	if date.IsNull() {
		*d = Date("")
	}
	*d = NewDate(date)
}
func (d Date) Get() (od ora.Date) {
	if d == "" {
		return
	}
	t, err := time.Parse(timeFormat[:len(d)], string(d)) // TODO(tgulacsi): more robust parser
	if err != nil || t.IsZero() {
		return
	}
	od.Set(t)
	return
}

type Lob struct {
	*ora.Lob
	data []byte
	err  error
}

func (L *Lob) read() error {
	if L.err != nil {
		return L.err
	}
	if L.data == nil {
		L.data, L.err = ioutil.ReadAll(L.Lob)
	}
	return L.err
}
func (L *Lob) Size() int {
	if L.read() != nil {
		return 0
	}
	return len(L.data)
}
func (L *Lob) Marshal() ([]byte, error) {
	err := L.read()
	return L.data, err
}
func (L *Lob) MarshalTo(p []byte) (int, error) {
	err := L.read()
	i := copy(p, L.data)
	return i, err
}
func (L *Lob) Unmarshal(p []byte) error {
	L.data = p
	return nil
}

func AsString(v interface{}) string {
	if v == nil {
		return ""
	}
	switch x := v.(type) {
	case string:
		return x
	case ora.String:
		return x.Value
	}
	return fmt.Sprintf("%v", v)
}

func AsFloat64(v interface{}) float64 {
	if v == nil {
		return 0
	}
	switch x := v.(type) {
	case float64:
		return x
	case float32:
		return float64(x)
	case int64:
		return float64(x)
	case int32:
		return float64(x)
	case ora.Float64:
		return x.Value
	case ora.Float32:
		return float64(x.Value)
	case string:
		if x == "" {
			return 0
		}
		f, err := strconv.ParseFloat(x, 64)
		if err != nil {
			log.Printf("ERROR parsing %q as Float64", x)
		}
		return f
	default:
		log.Printf("WARN: unknown Int64 type %T", v)
	}
	return 0
}
func AsInt32(v interface{}) int32 {
	if v == nil {
		return 0
	}
	switch x := v.(type) {
	case int32:
		return x
	case int64:
		return int32(x)
	case float64:
		return int32(x)
	case float32:
		return int32(x)
	case ora.Int32:
		return x.Value
	case ora.Int64:
		return int32(x.Value)
	case string:
		if x == "" {
			return 0
		}
		i, err := strconv.ParseInt(x, 10, 32)
		if err != nil {
			log.Printf("ERROR parsing %q as Int32", x)
		}
		return int32(i)
	default:
		log.Printf("WARN: unknown Int32 type %T", v)
	}
	return 0
}
func AsInt64(v interface{}) int64 {
	switch x := v.(type) {
	case int64:
		return x
	case int32:
		return int64(x)
	case float64:
		return int64(x)
	case float32:
		return int64(x)
	case ora.Int64:
		return x.Value
	case ora.Int32:
		return int64(x.Value)
	case string:
		if x == "" {
			return 0
		}
		i, err := strconv.ParseInt(x, 10, 64)
		if err != nil {
			log.Printf("ERROR parsing %q as Int64", x)
		}
		return i
	default:
		log.Printf("WARN: unknown Int64 type %T", v)
	}
	return 0
}
func AsDate(v interface{}) Date {
	if v == nil {
		return ""
	}
	switch x := v.(type) {
	case Date:
		return x
	case time.Time:
		return Date(x.Format(timeFormat))
	case string:
		return Date(x)
	case ora.Date:
		var d Date
		d.Set(x)
		return d
	default:
		log.Printf("WARN: unknown Date type %T", v)
	}

	return Date("")
}
<|endoftext|>


<commit_before>package ethminer

import (
	"bytes"
	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethwire"
	"log"
)

type Miner struct {
	pow       ethchain.PoW
	ethereum  ethchain.EthManager
	coinbase  []byte
	reactChan chan ethutil.React
	txs       []*ethchain.Transaction
	uncles    []*ethchain.Block
	block     *ethchain.Block
	powChan   chan []byte
	quitChan  chan ethutil.React
}

func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
	reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
	powChan := make(chan []byte, 1)          // This is the channel that receives valid sha hases for a given block
	quitChan := make(chan ethutil.React, 1)  // This is the channel that can exit the miner thread

	ethereum.Reactor().Subscribe("newBlock", reactChan)
	ethereum.Reactor().Subscribe("newTx", reactChan)

	// We need the quit chan to be a Reactor event.
	// The POW search method is actually blocking and if we don't
	// listen to the reactor events inside of the pow itself
	// The miner overseer will never get the reactor events themselves
	// Only after the miner will find the sha
	ethereum.Reactor().Subscribe("newBlock", quitChan)
	ethereum.Reactor().Subscribe("newTx", quitChan)

	miner := Miner{
		pow:       &ethchain.EasyPow{},
		ethereum:  ethereum,
		coinbase:  coinbase,
		reactChan: reactChan,
		powChan:   powChan,
		quitChan:  quitChan,
	}

	// Insert initial TXs in our little miner 'pool'
	miner.txs = ethereum.TxPool().Flush()
	miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)

	return miner
}
func (miner *Miner) Start() {
	// Prepare inital block
	miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
	go func() { miner.listener() }()
}
func (miner *Miner) listener() {
	for {
		select {
		case chanMessage := <-miner.reactChan:
			if block, ok := chanMessage.Resource.(*ethchain.Block); ok {
				log.Println("[MINER] Got new block via Reactor")
				if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 {
					// TODO: Perhaps continue mining to get some uncle rewards
					log.Println("[MINER] New top block found resetting state")

					// Filter out which Transactions we have that were not in this block
					var newtxs []*ethchain.Transaction
					for _, tx := range miner.txs {
						found := false
						for _, othertx := range block.Transactions() {
							if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 {
								found = true
							}
						}
						if found == false {
							newtxs = append(newtxs, tx)
						}
					}
					miner.txs = newtxs

					// Setup a fresh state to mine on
					miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)

				} else {
					if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
						log.Println("[MINER] Adding uncle block")
						miner.uncles = append(miner.uncles, block)
						miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
					}
				}
			}

			if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok {
				log.Println("[MINER] Got new transaction from Reactor", tx)
				found := false
				for _, ctx := range miner.txs {
					if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found {
						break
					}

				}
				if found == false {
					log.Println("[MINER] We did not know about this transaction, adding")
					miner.txs = append(miner.txs, tx)
					miner.block.SetTransactions(miner.txs)
				} else {
					log.Println("[MINER] We already had this transaction, ignoring")
				}
			}
		default:
			log.Println("[MINER] Mining on block. Includes", len(miner.txs), "transactions")

			// Apply uncles
			if len(miner.uncles) > 0 {
				miner.block.SetUncles(miner.uncles)
			}

			// Apply all transactions to the block
			miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions())
			miner.ethereum.StateManager().AccumelateRewards(miner.block)

			// Search the nonce
			log.Println("[MINER] Initialision complete, starting mining")
			miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan)
			if miner.block.Nonce != nil {
				miner.ethereum.StateManager().PrepareDefault(miner.block)
				err := miner.ethereum.StateManager().ProcessBlock(miner.block, true)
				if err != nil {
					log.Println("Error result from process block:", err)
				} else {

					if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) {
						log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce))
					}
					miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val})
					log.Printf("[MINER] 🔨  Mined block %x\n", miner.block.Hash())

					miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
					miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
				}
			}
		}
	}
}
<commit_msg>Fix transaction on new blocks<commit_after>package ethminer

import (
	"bytes"
	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethwire"
	"log"
)

type Miner struct {
	pow       ethchain.PoW
	ethereum  ethchain.EthManager
	coinbase  []byte
	reactChan chan ethutil.React
	txs       []*ethchain.Transaction
	uncles    []*ethchain.Block
	block     *ethchain.Block
	powChan   chan []byte
	quitChan  chan ethutil.React
}

func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
	reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
	powChan := make(chan []byte, 1)          // This is the channel that receives valid sha hases for a given block
	quitChan := make(chan ethutil.React, 1)  // This is the channel that can exit the miner thread

	ethereum.Reactor().Subscribe("newBlock", reactChan)
	ethereum.Reactor().Subscribe("newTx", reactChan)

	// We need the quit chan to be a Reactor event.
	// The POW search method is actually blocking and if we don't
	// listen to the reactor events inside of the pow itself
	// The miner overseer will never get the reactor events themselves
	// Only after the miner will find the sha
	ethereum.Reactor().Subscribe("newBlock", quitChan)
	ethereum.Reactor().Subscribe("newTx", quitChan)

	miner := Miner{
		pow:       &ethchain.EasyPow{},
		ethereum:  ethereum,
		coinbase:  coinbase,
		reactChan: reactChan,
		powChan:   powChan,
		quitChan:  quitChan,
	}

	// Insert initial TXs in our little miner 'pool'
	miner.txs = ethereum.TxPool().Flush()
	miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)

	return miner
}
func (miner *Miner) Start() {
	// Prepare inital block
	miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
	go func() { miner.listener() }()
}
func (miner *Miner) listener() {
	for {
		select {
		case chanMessage := <-miner.reactChan:
			if block, ok := chanMessage.Resource.(*ethchain.Block); ok {
				log.Println("[MINER] Got new block via Reactor")
				if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 {
					// TODO: Perhaps continue mining to get some uncle rewards
					log.Println("[MINER] New top block found resetting state")

					// Filter out which Transactions we have that were not in this block
					var newtxs []*ethchain.Transaction
					for _, tx := range miner.txs {
						found := false
						for _, othertx := range block.Transactions() {
							if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 {
								found = true
							}
						}
						if found == false {
							newtxs = append(newtxs, tx)
						}
					}
					miner.txs = newtxs

					// Setup a fresh state to mine on
					miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)

				} else {
					if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
						log.Println("[MINER] Adding uncle block")
						miner.uncles = append(miner.uncles, block)
						miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
					}
				}
			}

			if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok {
				log.Println("[MINER] Got new transaction from Reactor", tx)
				found := false
				for _, ctx := range miner.txs {
					if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found {
						break
					}

				}
				if found == false {
					log.Println("[MINER] We did not know about this transaction, adding")
					miner.txs = append(miner.txs, tx)
					miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
					miner.block.SetTransactions(miner.txs)
				} else {
					log.Println("[MINER] We already had this transaction, ignoring")
				}
			}
		default:
			log.Println("[MINER] Mining on block. Includes", len(miner.txs), "transactions")

			// Apply uncles
			if len(miner.uncles) > 0 {
				miner.block.SetUncles(miner.uncles)
			}

			// Apply all transactions to the block
			miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions())
			miner.ethereum.StateManager().AccumelateRewards(miner.block)

			// Search the nonce
			log.Println("[MINER] Initialision complete, starting mining")
			miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan)
			if miner.block.Nonce != nil {
				miner.ethereum.StateManager().PrepareDefault(miner.block)
				err := miner.ethereum.StateManager().ProcessBlock(miner.block, true)
				if err != nil {
					log.Println("Error result from process block:", err)
				} else {

					if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) {
						log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce))
					}
					miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val})
					log.Printf("[MINER] 🔨  Mined block %x\n", miner.block.Hash())

					miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
					miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package event

import "fmt"

// Absolute is a metric that is not averaged/aggregated.
// We keep each value distinct and then we flush them all individually.
type Absolute struct {
	Name   string
	Values []int64
}

// Update the event with metrics coming from a new one of the same type and with the same key
func (e *Absolute) Update(e2 Event) error {
	if e.Type() != e2.Type() {
		return fmt.Errorf("statsd event type conflict: %s vs %s ", e.String(), e2.String())
	}
	e.Values = append(e.Values, e2.Payload().([]int64)...)
	return nil
}

// Payload returns the aggregated value for this event
func (e Absolute) Payload() interface{} {
	return e.Values
}

// Stats returns an array of StatsD events as they travel over UDP
func (e Absolute) Stats() []string {
	ret := make([]string, 0)
	for v := range e.Values {
		ret = append(ret, fmt.Sprintf("%s:%d|a", e.Name, v))
	}
	return ret
}

// Key returns the name of this metric
func (e Absolute) Key() string {
	return e.Name
}

// Type returns an integer identifier for this type of metric
func (e Absolute) Type() int {
	return EventAbsolute
}

// TypeString returns a name for this type of metric
func (e Absolute) TypeString() string {
	return "Absolute"
}

// String returns a debug-friendly representation of this metric
func (e Absolute) String() string {
	return fmt.Sprintf("{Type: %s, Key: %s, Values: %v}", e.TypeString(), e.Name, e.Values)
}
<commit_msg>might as well preallocate the exact slice len we need, since we know it<commit_after>package event

import "fmt"

// Absolute is a metric that is not averaged/aggregated.
// We keep each value distinct and then we flush them all individually.
type Absolute struct {
	Name   string
	Values []int64
}

// Update the event with metrics coming from a new one of the same type and with the same key
func (e *Absolute) Update(e2 Event) error {
	if e.Type() != e2.Type() {
		return fmt.Errorf("statsd event type conflict: %s vs %s ", e.String(), e2.String())
	}
	e.Values = append(e.Values, e2.Payload().([]int64)...)
	return nil
}

// Payload returns the aggregated value for this event
func (e Absolute) Payload() interface{} {
	return e.Values
}

// Stats returns an array of StatsD events as they travel over UDP
func (e Absolute) Stats() []string {
	ret := make([]string, len(e.Values))
	for v := range e.Values {
		ret = append(ret, fmt.Sprintf("%s:%d|a", e.Name, v))
	}
	return ret
}

// Key returns the name of this metric
func (e Absolute) Key() string {
	return e.Name
}

// Type returns an integer identifier for this type of metric
func (e Absolute) Type() int {
	return EventAbsolute
}

// TypeString returns a name for this type of metric
func (e Absolute) TypeString() string {
	return "Absolute"
}

// String returns a debug-friendly representation of this metric
func (e Absolute) String() string {
	return fmt.Sprintf("{Type: %s, Key: %s, Values: %v}", e.TypeString(), e.Name, e.Values)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
)

func buy(args []string) error {
	os.Args = args

	var (
		amt string = "100"
		serv = flag.String("s", "localhost:8088", "path to the factomclient")
	)
	flag.Parse()
	args = flag.Args()
	if len(args) > 0 {
		amt = args[1]
	}
	server := "http://" + *serv + "/v1/buycredit"
	data := url.Values{
		"to":      {"wallet"},
		"ammount": {amt},
	}

	resp, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	p, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	fmt.Println(string(p))

	return nil
}
<commit_msg>buy.go changed default send amount<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
)

func buy(args []string) error {
	os.Args = args

	var (
		amt string = "0"
		serv = flag.String("s", "localhost:8088", "path to the factomclient")
	)
	flag.Parse()
	args = flag.Args()
	if len(args) > 0 {
		amt = args[1]
	}
	server := "http://" + *serv + "/v1/buycredit"
	data := url.Values{
		"to":      {"wallet"},
		"ammount": {amt},
	}

	resp, err := http.PostForm(server, data)
	if err != nil {
		return err
	}
	p, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	fmt.Println(string(p))

	return nil
}
<|endoftext|>