<commit_before>package display

import (
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/nanobox-io/nanobox/util"
	"github.com/lyondhill/vtclean"
)

// ...
var (
	EscSeqRegex   = regexp.MustCompile("\\x1b[[][?0123456789]*;?[?0123456789]*[ABEFHJRSTfminsulhp]")
	LogStripRegex = regexp.MustCompile("^[ \t-]*")
	termWidth     = 0
)

type (

	// Summarizer ...
	Summarizer struct {
		Label  string    // the task label to print as the header
		Prefix string    // the prefix to prepend to the summary
		Out    io.Writer // writer to send output to

		// internal
		chEvent     chan *sEventOp // channel to receive stop/error/tick events
		chLog       chan string    // channel to receive logs
		spinIdx     int            // track the current spinner index
		ticker      *time.Ticker   // timer to send tick events at an interval
		detail      string         // the current line of detail to print
		shutdown    bool           // toggle to inform the run loop to exit
		windowWidth int
		leftover    string
	}

	// Sending events to the summarizer needs to block the caller until
	// the event handler has completed. To do this we need to create
	// a stateful event with an ad-hoc channel to receive the response
	sEventOp struct {
		action string    // the requested action (stop/error/tick/etc)
		res    chan bool // the response channel to syncronize state
	}
)

// NewSummarizer returns a new Summarizer
func NewSummarizer(label string, prefix string) *Summarizer {
	if termWidth == 0 {
		_, termWidth = util.GetTerminalSize()
	}

	return &Summarizer{
		Label:  label,
		Prefix: prefix,
		Out:    os.Stdout,

		chEvent:     make(chan *sEventOp),   // no buffering, block the sending process
		chLog:       make(chan string, 100), // buffer up to 100 log messages before blocking
		windowWidth: termWidth,
	}
}

// Start starts the summary process in a goroutine
func (s *Summarizer) Start() {
	go s.run()
}

// Pause ...
func (s *Summarizer) Pause() {
	// create the 'stop' event
	event := &sEventOp{
		action: "pause",
		res:    make(chan bool),
	}

	// send the event
	s.chEvent <- event

	// now wait until we get a response back
	<-event.res
}

// Resume prints the "complete" label and toggles shutdown
func (s *Summarizer) Resume() {
	// generate and print the complete header
	s.Label = s.Label

	// turn the ticker back on
	s.shutdown = false
	go s.run()
}

// Stop stops the summary process
func (s *Summarizer) Stop() {
	// create the 'stop' event
	event := &sEventOp{
		action: "stop",
		res:    make(chan bool),
	}

	// send the event
	s.chEvent <- event

	// now wait until we get a response back
	<-event.res
}

// Error will stop the summary process and print an error header
func (s *Summarizer) Error() {
	// create the 'error' event
	event := &sEventOp{
		action: "error",
		res:    make(chan bool),
	}

	// send the event
	s.chEvent <- event

	// now wait until we get a response back
	<-event.res
}

// Log sends a log message to the summary process
func (s *Summarizer) Log(msg string) {
	// send the message to the log channel
	s.chLog <- msg
}

// run runs the main loop to wait for events or timers
func (s *Summarizer) run() {

	// to kick things off, we need to print the first summary
	s.print()

	// start a ticker to send a "tick" event every 80 milliseconds
	s.startTicker()

	for !s.shutdown {
		select {
		case event := <-s.chEvent:
			s.handleEvent(event)
		case msg := <-s.chLog:
			s.handleLog(msg)
		}
	}

	// stop the ticker
	s.stopTicker()
}

// startTicker starts a ticker to send a tick event
func (s *Summarizer) startTicker() {
	s.ticker = time.NewTicker(time.Millisecond * 80)

	// send a "tick" event at each interval
	go func() {
		for range s.ticker.C {
			// create the 'tick' event
			event := &sEventOp{
				action: "tick",
				res:    make(chan bool),
			}

			// send the event
			s.chEvent <- event

			// now wait until we get a response back
			<-event.res
		}
	}()
}

// stopTicker stops the tick event ticker
func (s *Summarizer) stopTicker() {
	s.ticker.Stop()
}

// handleEvent dispatches actions for events received on the event channel
func (s *Summarizer) handleEvent(event *sEventOp) {

	switch event.action {
	case "tick":
		s.tick()
	case "stop":
		s.stop()
	case "pause":
		s.pause()
	case "error":
		s.error()
	}

	// send the response so the caller can continue on
	event.res <- true
}

// handleLog sets the detail line and refreshes the summary
func (s *Summarizer) handleLog(data string) {

	msg := s.leftover
	s.leftover = ""

	// a function to decide where to split
	f := func(c rune) bool {
		return c == '\n' || c == '\r'
	}
	printLogFile("data " + data)

	// iterate through the lines, we'll keep the last line that has data
	lines := strings.FieldsFunc(msg+data, f)
	for _, line := range lines {

		// first we need to remove escape sequences
		line = EscSeqRegex.ReplaceAllString(line, "")

		// then use vtclean to organize the output
		line = vtclean.Clean(line, true)

		// then we need to remove any leading whitespace
		line = LogStripRegex.ReplaceAllString(line, "")

		if len(line) == 0 {
			continue
		}

		s.detail = line
		s.reset()
		s.print()
	}

	// if there is any data and it doesnt end with a newline
	if len(lines) > 0 && !(strings.HasSuffix(data, "\n") || strings.HasSuffix(data, "\r")) {
		// place it in the leftovers
		s.leftover = lines[len(lines)-1]
	}

}

// tick updates the spinner index and refreshes the summary
func (s *Summarizer) tick() {
	// update the spinner index
	s.spinIdx++

	// reset the index back to 0 if we've reached the top
	if s.spinIdx == len(TaskSpinner) {
		s.spinIdx = 0
	}

	// reset and print the screen
	s.reset()
	s.print()
}

// stop prints the "complete" label and toggles shutdown
func (s *Summarizer) stop() {
	// reset the screen
	s.reset()

	// generate and print the complete header
	header := fmt.Sprintf("%s%s %s\n", s.Prefix, TaskComplete, s.Label)
	io.WriteString(s.Out, header)

	// set the shutdown flag to ensure the loop ends
	s.shutdown = true
}

// stop prints the "complete" label and toggles shutdown
func (s *Summarizer) pause() {
	// reset the screen
	s.reset()

	// generate and print the complete header
	header := fmt.Sprintf("%s%s %s\n", s.Prefix, TaskPause, s.Label)
	io.WriteString(s.Out, header)

	// set the shutdown flag to ensure the loop ends
	s.shutdown = true
}

// error prints the "error" label and toggles shutdown
func (s *Summarizer) error() {
	// reset the screen
	s.reset()

	// generate and print the complete header
	header := fmt.Sprintf("%s! %s\n", s.Prefix, s.Label)
	io.WriteString(s.Out, header)

	// set the shutdown flag to ensure the loop ends
	s.shutdown = true
}

// reset will reset the screen using escape sequences
func (s *Summarizer) reset() {
	// http://bluesock.org/~willg/dev/ansi.html

	// todo: make this conditional on the progress estimator
	lines := 2

	// create escape sequence to move up a line and clear the line for each line
	reset := strings.Repeat("\x1b[1A\x1b[K", lines)

	io.WriteString(s.Out, reset)
}

// print prints the current summary
func (s *Summarizer) print() {

	header := fmt.Sprintf("%s%s %s :\n", s.Prefix, TaskSpinner[s.spinIdx], s.Label)

	// truncate the header
	availableLen := s.windowWidth - 5
	if s.windowWidth > 0 && len(header) > availableLen {
		header = header[:availableLen] + "...\n"
	}

	detail := fmt.Sprintf("%s  %s\n", s.Prefix, s.detail)

	// truncate the details
	if s.windowWidth > 0 && len(detail) > availableLen {
		detail = detail[:availableLen] + "..."
	}

	// todo: add progress estimator

	io.WriteString(s.Out, header)
	io.WriteString(s.Out, detail)
}
<commit_msg>update the summary to include newlines<commit_after>package display

import (
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/nanobox-io/nanobox/util"
	"github.com/lyondhill/vtclean"
)

// ...
var (
	EscSeqRegex   = regexp.MustCompile("\\x1b[[][?0123456789]*;?[?0123456789]*[ABEFHJRSTfminsulhp]")
	LogStripRegex = regexp.MustCompile("^[ \t-]*")
	termWidth     = 0
)

type (

	// Summarizer ...
	Summarizer struct {
		Label  string    // the task label to print as the header
		Prefix string    // the prefix to prepend to the summary
		Out    io.Writer // writer to send output to

		// internal
		chEvent     chan *sEventOp // channel to receive stop/error/tick events
		chLog       chan string    // channel to receive logs
		spinIdx     int            // track the current spinner index
		ticker      *time.Ticker   // timer to send tick events at an interval
		detail      string         // the current line of detail to print
		shutdown    bool           // toggle to inform the run loop to exit
		windowWidth int
		leftover    string
	}

	// Sending events to the summarizer needs to block the caller until
	// the event handler has completed. To do this we need to create
	// a stateful event with an ad-hoc channel to receive the response
	sEventOp struct {
		action string    // the requested action (stop/error/tick/etc)
		res    chan bool // the response channel to syncronize state
	}
)

// NewSummarizer returns a new Summarizer
func NewSummarizer(label string, prefix string) *Summarizer {
	if termWidth == 0 {
		_, termWidth = util.GetTerminalSize()
	}

	return &Summarizer{
		Label:  label,
		Prefix: prefix,
		Out:    os.Stdout,

		chEvent:     make(chan *sEventOp),   // no buffering, block the sending process
		chLog:       make(chan string, 100), // buffer up to 100 log messages before blocking
		windowWidth: termWidth,
	}
}

// Start starts the summary process in a goroutine
func (s *Summarizer) Start() {
	go s.run()
}

// Pause ...
func (s *Summarizer) Pause() {
	// create the 'stop' event
	event := &sEventOp{
		action: "pause",
		res:    make(chan bool),
	}

	// send the event
	s.chEvent <- event

	// now wait until we get a response back
	<-event.res
}

// Resume prints the "complete" label and toggles shutdown
func (s *Summarizer) Resume() {
	// generate and print the complete header
	s.Label = s.Label

	// turn the ticker back on
	s.shutdown = false
	go s.run()
}

// Stop stops the summary process
func (s *Summarizer) Stop() {
	// create the 'stop' event
	event := &sEventOp{
		action: "stop",
		res:    make(chan bool),
	}

	// send the event
	s.chEvent <- event

	// now wait until we get a response back
	<-event.res
}

// Error will stop the summary process and print an error header
func (s *Summarizer) Error() {
	// create the 'error' event
	event := &sEventOp{
		action: "error",
		res:    make(chan bool),
	}

	// send the event
	s.chEvent <- event

	// now wait until we get a response back
	<-event.res
}

// Log sends a log message to the summary process
func (s *Summarizer) Log(msg string) {
	// send the message to the log channel
	s.chLog <- msg
}

// run runs the main loop to wait for events or timers
func (s *Summarizer) run() {

	// to kick things off, we need to print the first summary
	s.print()

	// start a ticker to send a "tick" event every 80 milliseconds
	s.startTicker()

	for !s.shutdown {
		select {
		case event := <-s.chEvent:
			s.handleEvent(event)
		case msg := <-s.chLog:
			s.handleLog(msg)
		}
	}

	// stop the ticker
	s.stopTicker()
}

// startTicker starts a ticker to send a tick event
func (s *Summarizer) startTicker() {
	s.ticker = time.NewTicker(time.Millisecond * 80)

	// send a "tick" event at each interval
	go func() {
		for range s.ticker.C {
			// create the 'tick' event
			event := &sEventOp{
				action: "tick",
				res:    make(chan bool),
			}

			// send the event
			s.chEvent <- event

			// now wait until we get a response back
			<-event.res
		}
	}()
}

// stopTicker stops the tick event ticker
func (s *Summarizer) stopTicker() {
	s.ticker.Stop()
}

// handleEvent dispatches actions for events received on the event channel
func (s *Summarizer) handleEvent(event *sEventOp) {

	switch event.action {
	case "tick":
		s.tick()
	case "stop":
		s.stop()
	case "pause":
		s.pause()
	case "error":
		s.error()
	}

	// send the response so the caller can continue on
	event.res <- true
}

// handleLog sets the detail line and refreshes the summary
func (s *Summarizer) handleLog(data string) {

	msg := s.leftover
	s.leftover = ""

	// a function to decide where to split
	f := func(c rune) bool {
		return c == '\n' || c == '\r'
	}
	printLogFile("data " + data)

	// iterate through the lines, we'll keep the last line that has data
	lines := strings.FieldsFunc(msg+data, f)
	for _, line := range lines {

		// first we need to remove escape sequences
		line = EscSeqRegex.ReplaceAllString(line, "")

		// then use vtclean to organize the output
		line = vtclean.Clean(line, true)

		// then we need to remove any leading whitespace
		line = LogStripRegex.ReplaceAllString(line, "")

		if len(line) == 0 {
			continue
		}

		s.detail = line
		s.reset()
		s.print()
	}

	// if there is any data and it doesnt end with a newline
	if len(lines) > 0 && !(strings.HasSuffix(data, "\n") || strings.HasSuffix(data, "\r")) {
		// place it in the leftovers
		s.leftover = lines[len(lines)-1]
	}

}

// tick updates the spinner index and refreshes the summary
func (s *Summarizer) tick() {
	// update the spinner index
	s.spinIdx++

	// reset the index back to 0 if we've reached the top
	if s.spinIdx == len(TaskSpinner) {
		s.spinIdx = 0
	}

	// reset and print the screen
	s.reset()
	s.print()
}

// stop prints the "complete" label and toggles shutdown
func (s *Summarizer) stop() {
	// reset the screen
	s.reset()

	// generate and print the complete header
	header := fmt.Sprintf("%s%s %s\n", s.Prefix, TaskComplete, s.Label)
	io.WriteString(s.Out, header)

	// set the shutdown flag to ensure the loop ends
	s.shutdown = true
}

// stop prints the "complete" label and toggles shutdown
func (s *Summarizer) pause() {
	// reset the screen
	s.reset()

	// generate and print the complete header
	header := fmt.Sprintf("%s%s %s\n", s.Prefix, TaskPause, s.Label)
	io.WriteString(s.Out, header)

	// set the shutdown flag to ensure the loop ends
	s.shutdown = true
}

// error prints the "error" label and toggles shutdown
func (s *Summarizer) error() {
	// reset the screen
	s.reset()

	// generate and print the complete header
	header := fmt.Sprintf("%s! %s\n", s.Prefix, s.Label)
	io.WriteString(s.Out, header)

	// set the shutdown flag to ensure the loop ends
	s.shutdown = true
}

// reset will reset the screen using escape sequences
func (s *Summarizer) reset() {
	// http://bluesock.org/~willg/dev/ansi.html

	// todo: make this conditional on the progress estimator
	lines := 2

	// create escape sequence to move up a line and clear the line for each line
	reset := strings.Repeat("\x1b[1A\x1b[K", lines)

	io.WriteString(s.Out, reset)
}

// print prints the current summary
func (s *Summarizer) print() {

	header := fmt.Sprintf("%s%s %s :\n", s.Prefix, TaskSpinner[s.spinIdx], s.Label)

	// truncate the header
	availableLen := s.windowWidth - 5
	if s.windowWidth > 0 && len(header) > availableLen {
		header = header[:availableLen] + "...\n"
	}

	detail := fmt.Sprintf("%s  %s\n", s.Prefix, s.detail)

	// truncate the details
	if s.windowWidth > 0 && len(detail) > availableLen {
		detail = detail[:availableLen] + "...\n"
	}

	// todo: add progress estimator

	io.WriteString(s.Out, header)
	io.WriteString(s.Out, detail)
}
<|endoftext|>


<commit_before>package main

// TODO:
// -Support more complex interleave of multiple hits besides line color?
// -Fix Color priority order hard coded for lines?
// -support more colors and hi-colors and bold
// -support -s or -v to do grep -v like behavior (supress/skip line)?

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

type arrayFlags []string

// Implements needed method for flag.Value (String) - used as default value
// or at least in help text it does
func (s *arrayFlags) String() string {
	// Empty string for default
	return "[string]"
}

func (s *arrayFlags) Set(value string) error {
	*s = append(*s, value)
	return nil
}

const (
	// http://pueblo.sourceforge.net/doc/manual/ansi_color_codes.html
	// non-bold color codes for the lines include turning off bold, so that mid-line strings
	// can reset from bold to standard (or vice versa) as needed

	ansi_bold        = "\033[1m"
	ansi_red         = "\033[0;31m"
	ansi_bold_red    = "\033[1;31m"
	ansi_yellow      = "\033[0;33m"
	ansi_bold_yellow = "\033[1;33m"

	ansi_reset = "\033[0m"
)

func register_trigger(m map[*arrayFlags]string, style string, flag_name string, code string) {
	var af arrayFlags
	flag.Var(&af, flag_name, "String to trigger "+style)
	m[&af] = code
}

func main() {

	line_triggers := make(map[*arrayFlags]string)
	item_triggers := make(map[*arrayFlags]string)

	register_trigger(line_triggers, "yellow line", "yl", ansi_yellow)
	register_trigger(item_triggers, "yellow item", "ys", ansi_yellow)
	register_trigger(item_triggers, "bold yellow item", "bys", ansi_bold_yellow)
	register_trigger(line_triggers, "red line", "rl", ansi_red)
	register_trigger(item_triggers, "red item", "rs", ansi_red)

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: tail -f <log> | grep stuff | %s [flags]\n",
			filepath.Base(os.Args[0]))
		flag.PrintDefaults()
	}

	flag.Parse()

	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		line := scanner.Text()

		// Save for strings in multiple colors: If whole line is modified, don't print ansi_reset, revert to line
		line_color := ansi_reset

		// Note that ranging over maps is random order so multiple runs of multiple hits is too

		for line_trigger_strings, line_style_code := range line_triggers {
			for _, line_trigger_string := range *line_trigger_strings {
				if strings.Contains(line, line_trigger_string) {
					line = line_style_code + line + ansi_reset
					line_color = line_style_code
				}
			}
		}

		for item_trigger_strings, item_style_code := range item_triggers {
			for _, item_trigger_string := range *item_trigger_strings {
				// Faster or slower to do strings.Contains check first?
				line = strings.Replace(line, item_trigger_string, item_style_code+item_trigger_string+line_color, -1)
			}
		}

		fmt.Println(line)
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "ERROR:", err)
		os.Exit(1)
	}

}
<commit_msg>Keep order of triggers as added<commit_after>package main

// TODO:
// -Support more complex interleave of multiple hits besides line color?
// -Fix Color priority order hard coded for lines?
// -support more colors and hi-colors and bold
// -support -s or -v to do grep -v like behavior (supress/skip line)?

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

type arrayFlags []string

// Implements needed method for flag.Value (String) - used as default value
// or at least in help text it does
func (s *arrayFlags) String() string {
	// Empty string for default
	return "[string]"
}

func (s *arrayFlags) Set(value string) error {
	*s = append(*s, value)
	return nil
}

const (
	// http://pueblo.sourceforge.net/doc/manual/ansi_color_codes.html
	// non-bold color codes for the lines include turning off bold, so that mid-line strings
	// can reset from bold to standard (or vice versa) as needed

	ansi_bold        = "\033[1m"
	ansi_red         = "\033[0;31m"
	ansi_bold_red    = "\033[1;31m"
	ansi_yellow      = "\033[0;33m"
	ansi_bold_yellow = "\033[1;33m"

	ansi_reset = "\033[0m"
)

func register_trigger(m map[*arrayFlags]string, o *[]*arrayFlags, style string, flag_name string, code string) {
	var af arrayFlags
	flag.Var(&af, flag_name, "String to trigger "+style)
	m[&af] = code
	// Store the order that we received the trigger in for priority
	// and because range over maps is always randomized
	*o = append(*o, &af)
}

//type Triggers struct {

func main() {

	line_triggers := make(map[*arrayFlags]string)
	var line_trigger_order []*arrayFlags
	item_triggers := make(map[*arrayFlags]string)
	var item_trigger_order []*arrayFlags

	register_trigger(line_triggers, &line_trigger_order, "yellow line", "yl", ansi_yellow)
	register_trigger(item_triggers, &item_trigger_order, "yellow item", "ys", ansi_yellow)
	register_trigger(item_triggers, &item_trigger_order, "bold yellow item", "bys", ansi_bold_yellow)
	register_trigger(line_triggers, &line_trigger_order, "red line", "rl", ansi_red)
	register_trigger(item_triggers, &item_trigger_order, "red item", "rs", ansi_red)

	//fmt.Println("lt:", len(line_triggers), "lto:", len(line_trigger_order))

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: tail -f <log> | grep stuff | %s [flags]\n",
			filepath.Base(os.Args[0]))
		flag.PrintDefaults()
	}

	flag.Parse()

	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		line := scanner.Text()

		// Save for strings in multiple colors: If whole line is modified, don't print ansi_reset, revert to line
		line_color := ansi_reset

		for _, line_trigger_strings := range line_trigger_order {
			line_style_code := line_triggers[line_trigger_strings]
			for _, line_trigger_string := range *line_trigger_strings {
				if strings.Contains(line, line_trigger_string) {
					line = line_style_code + line + ansi_reset
					line_color = line_style_code
				}
			}
		}

		for _, item_trigger_strings := range item_trigger_order {
			item_style_code := item_triggers[item_trigger_strings]
			for _, item_trigger_string := range *item_trigger_strings {
				// Faster or slower to do strings.Contains check first?
				line = strings.Replace(line, item_trigger_string, item_style_code+item_trigger_string+line_color, -1)
			}
		}

		fmt.Println(line)
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "ERROR:", err)
		os.Exit(1)
	}

}
<|endoftext|>


<commit_before>package kite

import (
	"github.com/streadway/amqp"
	"io"
	"koding/tools/dnode"
	"koding/tools/log"
	"strings"
	"time"
)

type connection struct {
	messageStream   <-chan amqp.Delivery
	publishChannel  *amqp.Channel
	exchange        string
	replyKey        string
	bufferedMessage []byte
}

func (conn *connection) Read(p []byte) (int, error) {
	if len(conn.bufferedMessage) == 0 {
		message, ok := <-conn.messageStream
		if !ok {
			return 0, io.EOF
		}
		conn.replyKey = "reply-" + message.RoutingKey
		conn.bufferedMessage = message.Body
		log.Debug("Read", message.Body)
	}
	n := copy(p, conn.bufferedMessage)
	conn.bufferedMessage = conn.bufferedMessage[n:]
	return n, nil
}

func (conn *connection) Write(p []byte) (int, error) {
	log.Debug("Write", p)
	err := conn.publishChannel.Publish(conn.exchange, conn.replyKey, false, false, amqp.Publishing{Body: p})
	if err != nil {
		return 0, err
	}
	return len(p), nil
}

func Start(uri, name string, onRootMethod func(user, method string, args interface{}) interface{}) {
	for {
		func() {
			defer time.Sleep(10 * time.Second)
			defer log.RecoverAndLog()

			log.Info("Connecting to AMQP server...")

			consumeConn, err := amqp.Dial(uri)
			if err != nil {
				panic(err)
			}
			defer consumeConn.Close()

			publishConn, err := amqp.Dial(uri)
			if err != nil {
				panic(err)
			}
			defer publishConn.Close()

			log.Info("Successfully connected to AMQP server.")

			joinStream, joinChannel := declareBindConsumeQueue(consumeConn, "kite-"+name, "join", "private-kite-"+name)
			defer joinChannel.Close()

			for join := range joinStream {
				go func() {
					defer log.RecoverAndLog()

					exchange := string(join.Body)
					user := strings.Split(exchange, ".")[1]

					log.Info("Client connected: " + user)

					messageStream, messageChannel := declareBindConsumeQueue(consumeConn, "", "client-message.*", exchange)
					defer messageChannel.Close()

					publishChannel, err := publishConn.Channel()
					if err != nil {
						panic(err)
					}
					defer publishChannel.Close()

					node := dnode.New(&connection{messageStream, publishChannel, exchange, "", make([]byte, 0)})
					node.OnRootMethod = func(method string, args []interface{}) {
						if method == "connectionInitializationDummy" {
							return
						}
						result := onRootMethod(user, method, args[0].(map[string]interface{})["withArgs"])
						if result != nil {
							args[1].(dnode.Callback)(result)
						}
					}
					node.Run()
				}()
			}

			log.Warn("Connection to AMQP server lost.")
		}()
	}
}

func declareBindConsumeQueue(conn *amqp.Connection, queue, key, exchange string) (<-chan amqp.Delivery, *amqp.Channel) {
	channel, err := conn.Channel()
	if err != nil {
		panic(err)
	}

	err = channel.ExchangeDeclare(exchange, "topic", true, true, false, false, nil)
	if err != nil {
		panic(err)
	}

	_, err = channel.QueueDeclare(queue, false, true, false, false, nil)
	if err != nil {
		panic(err)
	}

	err = channel.QueueBind(queue, key, exchange, false, nil)
	if err != nil {
		panic(err)
	}

	stream, err := channel.Consume(queue, "", true, false, false, false, nil)
	if err != nil {
		panic(err)
	}

	return stream, channel
}
<commit_msg>go kites: Protocol changes.<commit_after>package kite

import (
	"github.com/streadway/amqp"
	"io"
	"koding/tools/dnode"
	"koding/tools/log"
	"strings"
	"time"
)

type connection struct {
	messageStream   <-chan amqp.Delivery
	publishChannel  *amqp.Channel
	replyExchange   string
	bufferedMessage []byte
}

func (conn *connection) Read(p []byte) (int, error) {
	if len(conn.bufferedMessage) == 0 {
		message, ok := <-conn.messageStream
		if !ok {
			return 0, io.EOF
		}
		conn.bufferedMessage = message.Body
		log.Debug("Read", message.Body)
	}
	n := copy(p, conn.bufferedMessage)
	conn.bufferedMessage = conn.bufferedMessage[n:]
	return n, nil
}

func (conn *connection) Write(p []byte) (int, error) {
	log.Debug("Write", p)
	err := conn.publishChannel.Publish(conn.replyExchange, "reply-client-message", false, false, amqp.Publishing{Body: p})
	if err != nil {
		return 0, err
	}
	return len(p), nil
}

func Start(uri, name string, onRootMethod func(user, method string, args interface{}) interface{}) {
	for {
		func() {
			defer time.Sleep(10 * time.Second)
			defer log.RecoverAndLog()

			log.Info("Connecting to AMQP server...")

			consumeConn := createConn(uri)
			defer consumeConn.Close()

			publishConn := createConn(uri)
			defer publishConn.Close()

			log.Info("Successfully connected to AMQP server.")

			joinStream, joinChannel := declareBindConsumeQueue(consumeConn, "kite-"+name, "join", "private-kite-"+name)
			defer joinChannel.Close()

			for join := range joinStream {
				go func() {
					defer log.RecoverAndLog()

					secretName := string(join.Body)
					user := strings.Split(secretName, ".")[1]

					log.Info("Client connected: " + user)

					messageChannel := createChannel(consumeConn)
					defer messageChannel.Close()
					messageStream, err := messageChannel.Consume(secretName, "", true, false, false, false, nil)
					if err != nil {
						panic(err)
					}

					publishChannel := createChannel(consumeConn)
					defer publishChannel.Close()

					node := dnode.New(&connection{messageStream, publishChannel, "reply-" + secretName, make([]byte, 0)})
					node.OnRootMethod = func(method string, args []interface{}) {
						if method == "connectionInitializationDummy" {
							return
						}
						result := onRootMethod(user, method, args[0].(map[string]interface{})["withArgs"])
						if result != nil {
							args[1].(dnode.Callback)(result)
						}
					}
					node.Run()
				}()
			}

			log.Warn("Connection to AMQP server lost.")
		}()
	}
}

func createConn(uri string) *amqp.Connection {
	conn, err := amqp.Dial(uri)
	if err != nil {
		panic(err)
	}
	return conn
}

func createChannel(conn *amqp.Connection) *amqp.Channel {
	channel, err := conn.Channel()
	if err != nil {
		panic(err)
	}
	return channel
}

func declareBindConsumeQueue(conn *amqp.Connection, queue, key, exchange string) (<-chan amqp.Delivery, *amqp.Channel) {
	channel := createChannel(conn)

	err := channel.ExchangeDeclare(exchange, "topic", true, true, false, false, nil)
	if err != nil {
		panic(err)
	}

	_, err = channel.QueueDeclare(queue, false, true, false, false, nil)
	if err != nil {
		panic(err)
	}

	err = channel.QueueBind(queue, key, exchange, false, nil)
	if err != nil {
		panic(err)
	}

	stream, err := channel.Consume(queue, "", true, false, false, false, nil)
	if err != nil {
		panic(err)
	}

	return stream, channel
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
)

// Page contains the fields used for a Page model
type Page struct {
	Id                 int64     `json:"id" gorm:"column:id; primary_key:yes"`
	UserId             int64     `json:"-" gorm:"column:user_id"`
	Name               string    `json:"name"`
	HTML               string    `json:"html" gorm:"column:html"`
	CaptureCredentials bool      `json:"capture_credentials" gorm:"column:capture_credentials"`
	CapturePasswords   bool      `json:"capture_passwords" gorm:"column:capture_passwords"`
	RedirectURL        string    `json:"redirect_url" gorm:"column:redirect_url"`
	ModifiedDate       time.Time `json:"modified_date"`
}

// ErrPageNameNotSpecified is thrown if the name of the landing page is blank.
var ErrPageNameNotSpecified = errors.New("Page Name not specified")

// parseHTML parses the page HTML on save to handle the
// capturing (or lack thereof!) of credentials and passwords
func (p *Page) parseHTML() error {
	d, err := goquery.NewDocumentFromReader(strings.NewReader(p.HTML))
	if err != nil {
		return err
	}
	forms := d.Find("form")
	forms.Each(func(i int, f *goquery.Selection) {
		// We always want the submitted events to be
		// sent to our server
		f.SetAttr("action", "")
		if p.CaptureCredentials {
			// If we don't want to capture passwords,
			// find all the password fields and remove the "name" attribute.
			if !p.CapturePasswords {
				passwordFields := f.Find("input[type=\"password\"]")
				passwordFields.Each(func(j int, pass *goquery.Selection) {
					pass.RemoveAttr("name")
				})
			}
		} else {
			// Otherwise, remove the name from all
			// inputs.
			inputFields := f.Find("input")
			inputFields.Each(func(j int, input *goquery.Selection) {
				input.RemoveAttr("name")
			})
		}
	})
	p.HTML, err = d.Html()
	return err
}

// Validate ensures that a page contains the appropriate details
func (p *Page) Validate() error {
	if p.Name == "" {
		return ErrPageNameNotSpecified
	}
	// If the user specifies to capture passwords,
	// we automatically capture credentials
	if p.CapturePasswords && !p.CaptureCredentials {
		p.CaptureCredentials = true
	}
	return p.parseHTML()
}

// GetPages returns the pages owned by the given user.
func GetPages(uid int64) ([]Page, error) {
	ps := []Page{}
	err := db.Where("user_id=?", uid).Find(&ps).Error
	if err != nil {
		Logger.Println(err)
		return ps, err
	}
	return ps, err
}

// GetPage returns the page, if it exists, specified by the given id and user_id.
func GetPage(id int64, uid int64) (Page, error) {
	p := Page{}
	err := db.Where("user_id=? and id=?", uid, id).Find(&p).Error
	if err != nil {
		Logger.Println(err)
	}
	return p, err
}

// GetPageByName returns the page, if it exists, specified by the given name and user_id.
func GetPageByName(n string, uid int64) (Page, error) {
	p := Page{}
	err := db.Where("user_id=? and name=?", uid, n).Find(&p).Error
	if err != nil {
		Logger.Println(err)
	}
	return p, err
}

// PostPage creates a new page in the database.
func PostPage(p *Page) error {
	err := p.Validate()
	if err != nil {
		Logger.Println(err)
		return err
	}
	// Insert into the DB
	err = db.Save(p).Error
	if err != nil {
		Logger.Println(err)
	}
	return err
}

// PutPage edits an existing Page in the database.
// Per the PUT Method RFC, it presumes all data for a page is provided.
func PutPage(p *Page) error {
	err := p.Validate()
	err = db.Where("id=?", p.Id).Save(p).Error
	if err != nil {
		Logger.Println(err)
	}
	return err
}

// DeletePage deletes an existing page in the database.
// An error is returned if a page with the given user id and page id is not found.
func DeletePage(id int64, uid int64) error {
	err = db.Where("user_id=?", uid).Delete(Page{Id: id}).Error
	if err != nil {
		Logger.Println(err)
	}
	return err
}
<commit_msg>Checks for input password fields are now case insensitive. Fixes #613<commit_after>package models

import (
	"errors"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
)

// Page contains the fields used for a Page model
type Page struct {
	Id                 int64     `json:"id" gorm:"column:id; primary_key:yes"`
	UserId             int64     `json:"-" gorm:"column:user_id"`
	Name               string    `json:"name"`
	HTML               string    `json:"html" gorm:"column:html"`
	CaptureCredentials bool      `json:"capture_credentials" gorm:"column:capture_credentials"`
	CapturePasswords   bool      `json:"capture_passwords" gorm:"column:capture_passwords"`
	RedirectURL        string    `json:"redirect_url" gorm:"column:redirect_url"`
	ModifiedDate       time.Time `json:"modified_date"`
}

// ErrPageNameNotSpecified is thrown if the name of the landing page is blank.
var ErrPageNameNotSpecified = errors.New("Page Name not specified")

// parseHTML parses the page HTML on save to handle the
// capturing (or lack thereof!) of credentials and passwords
func (p *Page) parseHTML() error {
	d, err := goquery.NewDocumentFromReader(strings.NewReader(p.HTML))
	if err != nil {
		return err
	}
	forms := d.Find("form")
	forms.Each(func(i int, f *goquery.Selection) {
		// We always want the submitted events to be
		// sent to our server
		f.SetAttr("action", "")
		if p.CaptureCredentials {
			// If we don't want to capture passwords,
			// find all the password fields and remove the "name" attribute.
			if !p.CapturePasswords {
				inputs := f.Find("input")
				inputs.Each(func(j int, input *goquery.Selection) {
					if t, _ := input.Attr("type"); strings.EqualFold(t, "password") {
						input.RemoveAttr("name")
					}
				})
			}
		} else {
			// Otherwise, remove the name from all
			// inputs.
			inputFields := f.Find("input")
			inputFields.Each(func(j int, input *goquery.Selection) {
				input.RemoveAttr("name")
			})
		}
	})
	p.HTML, err = d.Html()
	return err
}

// Validate ensures that a page contains the appropriate details
func (p *Page) Validate() error {
	if p.Name == "" {
		return ErrPageNameNotSpecified
	}
	// If the user specifies to capture passwords,
	// we automatically capture credentials
	if p.CapturePasswords && !p.CaptureCredentials {
		p.CaptureCredentials = true
	}
	return p.parseHTML()
}

// GetPages returns the pages owned by the given user.
func GetPages(uid int64) ([]Page, error) {
	ps := []Page{}
	err := db.Where("user_id=?", uid).Find(&ps).Error
	if err != nil {
		Logger.Println(err)
		return ps, err
	}
	return ps, err
}

// GetPage returns the page, if it exists, specified by the given id and user_id.
func GetPage(id int64, uid int64) (Page, error) {
	p := Page{}
	err := db.Where("user_id=? and id=?", uid, id).Find(&p).Error
	if err != nil {
		Logger.Println(err)
	}
	return p, err
}

// GetPageByName returns the page, if it exists, specified by the given name and user_id.
func GetPageByName(n string, uid int64) (Page, error) {
	p := Page{}
	err := db.Where("user_id=? and name=?", uid, n).Find(&p).Error
	if err != nil {
		Logger.Println(err)
	}
	return p, err
}

// PostPage creates a new page in the database.
func PostPage(p *Page) error {
	err := p.Validate()
	if err != nil {
		Logger.Println(err)
		return err
	}
	// Insert into the DB
	err = db.Save(p).Error
	if err != nil {
		Logger.Println(err)
	}
	return err
}

// PutPage edits an existing Page in the database.
// Per the PUT Method RFC, it presumes all data for a page is provided.
func PutPage(p *Page) error {
	err := p.Validate()
	err = db.Where("id=?", p.Id).Save(p).Error
	if err != nil {
		Logger.Println(err)
	}
	return err
}

// DeletePage deletes an existing page in the database.
// An error is returned if a page with the given user id and page id is not found.
func DeletePage(id int64, uid int64) error {
	err = db.Where("user_id=?", uid).Delete(Page{Id: id}).Error
	if err != nil {
		Logger.Println(err)
	}
	return err
}
<|endoftext|>


<commit_before>// Title：顾问通话详情列表
//
// Description:
//
// Author:black
//
// Createtime:2013-09-26 15:50
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-09-26 15:50 black 创建文档
package server

import (
	"fmt"
	"github.com/hjqhezgh/commonlib"
	"github.com/hjqhezgh/lessgo"
	"math"
	"net/http"
	"strconv"
	"text/template"
)

/*
select a.aid,cons.child,cont.name contName,a.remotephone,,ce.name centerName,a.start_time,a.seconds,a.inout,a.is_upload_finish,b.remark,cons.id,a.filename,a.cid  from audio a
left join contacts cont on a.remotephone=cont.phone
left join consumer_new cons on cont.consumer_id=cons.id
left join employee e on e.phone_in_center=a.localphone and e.center_id=a.cid
left join center ce on ce.cid=cons.center_id
left join (select consumer_id,GROUP_CONCAT(concat(create_time,':',note) remark SEPARATOR "\n") note from consumer_contact_log group by consumer_id) b on b.consumer_id=cons.id
where e.user_id=1 and a.remotephone != '' and  a.remotephone is not null
*/
func ConsultantPhoneDetailListAction(w http.ResponseWriter, r *http.Request) {

	m := make(map[string]interface{})

	employee := lessgo.GetCurrentEmployee(r)

	if employee.UserId == "" {
		lessgo.Log.Warn("用户未登陆")
		m["success"] = false
		m["code"] = 100
		m["msg"] = "用户未登陆"
		commonlib.OutputJson(w, m, " ")
		return
	}

	err := r.ParseForm()

	if err != nil {
		m["success"] = false
		m["code"] = 100
		m["msg"] = "出现错误，请联系IT部门，错误信息:" + err.Error()
		commonlib.OutputJson(w, m, " ")
		return
	}

	pageNoString := r.FormValue("page")
	pageNo := 1
	if pageNoString != "" {
		pageNo, err = strconv.Atoi(pageNoString)
		if err != nil {
			pageNo = 1
			lessgo.Log.Warn("错误的pageNo:", pageNo)
		}
	}

	pageSizeString := r.FormValue("rows")
	pageSize := 10
	if pageSizeString != "" {
		pageSize, err = strconv.Atoi(pageSizeString)
		if err != nil {
			lessgo.Log.Warn("错误的pageSize:", pageSize)
		}
	}

	eid := r.FormValue("eid")
	year := r.FormValue("year-eq")
	month := r.FormValue("month-eq")
	week := r.FormValue("week-eq")
	startTime := r.FormValue("start_time-eq")

	st := ""
	et := ""
	flag := true

	if startTime != "" {
		st = startTime + " 00:00:00"
		et = startTime + " 23:59:59"
	} else {
		if week != "" && month != "" && year != "" {
			st, et, flag = lessgo.FindRangeTimeDim("", "", year+month+week)
		} else if month != "" && year != "" {
			st, et, flag = lessgo.FindRangeTimeDim("", year+month, "")
		} else if year != "" {
			st, et, flag = lessgo.FindRangeTimeDim(year, "", "")
		}
	}

	params := []interface{}{}

	sql := "select a.aid,cons.child,b.remark,cont.name contName,a.remotephone,ce.name centerName,a.start_time,a.seconds,a.inout,a.is_upload_finish,cons.id,a.filename,a.cid,e1.really_name  from audio a "
	sql += " left join contacts cont on a.remotephone=cont.phone "
	sql += " left join consumer_new cons on cont.consumer_id=cons.id "
	sql += " left join employee e on e.phone_in_center=a.localphone and e.center_id=a.cid "
	sql += " left join center ce on ce.cid=cons.center_id "
	sql += " left join (select consumer_id,GROUP_CONCAT(concat(DATE_FORMAT(create_time,'%Y-%m-%d %H:%i'),' ',note) ORDER BY id  SEPARATOR '
') remark from consumer_contact_log group by consumer_id) b on b.consumer_id=cons.id "
	sql += " left join  employee e1 on e1.user_id=cons.current_tmk_id "
	sql += " where e.user_id=? and a.remotephone != '' and  a.remotephone is not null "

	params = append(params, eid)

	if flag {
		if st != "" && et != "" {
			sql += " and a.start_time >= ? and a.start_time<= ?"
			params = append(params, st)
			params = append(params, et)
		}
	} else { //找不到相应的时间区间
		sql += " and a.start_time >= ? and a.start_time<= ?"
		params = append(params, "2000-01-01 00:00:00")
		params = append(params, "2000-01-01 00:00:01")
	}

	countSql := ""

	countSql = "select count(1) from (" + sql + ") num"

	lessgo.Log.Debug(countSql)

	db := lessgo.GetMySQL()
	defer db.Close()

	rows, err := db.Query(countSql, params...)

	if err != nil {
		lessgo.Log.Warn(err.Error())
		m["success"] = false
		m["code"] = 100
		m["msg"] = "系统发生错误，请联系IT部门"
		commonlib.OutputJson(w, m, " ")
		return
	}

	totalNum := 0

	if rows.Next() {
		err := rows.Scan(&totalNum)

		if err != nil {
			lessgo.Log.Warn(err.Error())
			m["success"] = false
			m["code"] = 100
			m["msg"] = "系统发生错误，请联系IT部门"
			commonlib.OutputJson(w, m, " ")
			return
		}
	}

	totalPage := int(math.Ceil(float64(totalNum) / float64(pageSize)))

	currPageNo := pageNo

	if currPageNo > totalPage {
		currPageNo = totalPage
	}

	sql += " order by aid desc,a.start_time desc limit ?,?"

	lessgo.Log.Debug(sql)

	params = append(params, (currPageNo-1)*pageSize)
	params = append(params, pageSize)

	rows, err = db.Query(sql, params...)

	if err != nil {
		lessgo.Log.Warn(err.Error())
		m["success"] = false
		m["code"] = 100
		m["msg"] = "系统发生错误，请联系IT部门"
		commonlib.OutputJson(w, m, " ")
		return
	}

	objects := []interface{}{}

	for rows.Next() {

		model := new(lessgo.Model)

		fillObjects := []interface{}{}

		fillObjects = append(fillObjects, &model.Id)

		for i := 0; i < 13; i++ {
			prop := new(lessgo.Prop)
			prop.Name = fmt.Sprint(i)
			prop.Value = ""
			fillObjects = append(fillObjects, &prop.Value)
			model.Props = append(model.Props, prop)
		}

		err = commonlib.PutRecord(rows, fillObjects...)

		if err != nil {
			lessgo.Log.Warn(err.Error())
			m["success"] = false
			m["code"] = 100
			m["msg"] = "系统发生错误，请联系IT部门"
			commonlib.OutputJson(w, m, " ")
			return
		}

		objects = append(objects, model)
	}

	pageData := commonlib.BulidTraditionPage(currPageNo, pageSize, totalNum, objects)

	m["PageData"] = pageData
	m["DataLength"] = len(pageData.Datas) - 1
	if len(pageData.Datas) > 0 {
		m["FieldLength"] = len(pageData.Datas[0].(*lessgo.Model).Props) - 1
	}

	commonlib.RenderTemplate(w, r, "entity_page.json", m, template.FuncMap{"getPropValue": lessgo.GetPropValue, "compareInt": lessgo.CompareInt, "dealJsonString": lessgo.DealJsonString}, "../lessgo/template/entity_page.json")

}
<commit_msg>通话报表，性能调优<commit_after>// Title：顾问通话详情列表
//
// Description:
//
// Author:black
//
// Createtime:2013-09-26 15:50
//
// Version:1.0
//
// 修改历史:版本号 修改日期 修改人 修改说明
//
// 1.0 2013-09-26 15:50 black 创建文档
package server

import (
	"fmt"
	"github.com/hjqhezgh/commonlib"
	"github.com/hjqhezgh/lessgo"
	"math"
	"net/http"
	"strconv"
	"text/template"
)

/*
select a.aid,cons.child,b.remark,cont.name contName,a.remotephone,ce.name centerName,a.start_time,a.seconds,a.inout,a.is_upload_finish,cons.id,a.filename,a.cid,e1.really_name
from
(
	select au.* from audio au
	left join employee e on e.phone_in_center=au.localphone and e.center_id=au.cid
	where e.user_id=37 and au.remotephone != '' and  au.remotephone is not null order by au.aid desc,au.start_time desc  limit 0,20
) a
left join contacts cont on a.remotephone=cont.phone
left join consumer_new cons on cont.consumer_id=cons.id
left join employee e2 on e2.phone_in_center=a.localphone and e2.center_id=a.cid
left join center ce on ce.cid=cons.center_id
left join (select consumer_id,GROUP_CONCAT(concat(DATE_FORMAT(create_time,'%Y-%m-%d %H:%i'),' ',note) ORDER BY id  SEPARATOR '
') remark from consumer_contact_log group by consumer_id) b on b.consumer_id=cons.id
left join  employee e1 on e1.user_id=cons.current_tmk_id
*/
func ConsultantPhoneDetailListAction(w http.ResponseWriter, r *http.Request) {

	m := make(map[string]interface{})

	employee := lessgo.GetCurrentEmployee(r)

	if employee.UserId == "" {
		lessgo.Log.Warn("用户未登陆")
		m["success"] = false
		m["code"] = 100
		m["msg"] = "用户未登陆"
		commonlib.OutputJson(w, m, " ")
		return
	}

	err := r.ParseForm()

	if err != nil {
		m["success"] = false
		m["code"] = 100
		m["msg"] = "出现错误，请联系IT部门，错误信息:" + err.Error()
		commonlib.OutputJson(w, m, " ")
		return
	}

	pageNoString := r.FormValue("page")
	pageNo := 1
	if pageNoString != "" {
		pageNo, err = strconv.Atoi(pageNoString)
		if err != nil {
			pageNo = 1
			lessgo.Log.Warn("错误的pageNo:", pageNo)
		}
	}

	pageSizeString := r.FormValue("rows")
	pageSize := 10
	if pageSizeString != "" {
		pageSize, err = strconv.Atoi(pageSizeString)
		if err != nil {
			lessgo.Log.Warn("错误的pageSize:", pageSize)
		}
	}

	eid := r.FormValue("eid")
	year := r.FormValue("year-eq")
	month := r.FormValue("month-eq")
	week := r.FormValue("week-eq")
	startTime := r.FormValue("start_time-eq")

	st := ""
	et := ""
	flag := true

	if startTime != "" {
		st = startTime + " 00:00:00"
		et = startTime + " 23:59:59"
	} else {
		if week != "" && month != "" && year != "" {
			st, et, flag = lessgo.FindRangeTimeDim("", "", year+month+week)
		} else if month != "" && year != "" {
			st, et, flag = lessgo.FindRangeTimeDim("", year+month, "")
		} else if year != "" {
			st, et, flag = lessgo.FindRangeTimeDim(year, "", "")
		}
	}

	params := []interface{}{}

	sql := `select a.aid,cons.child,b.remark,cont.name contName,a.remotephone,ce.name centerName,a.start_time,a.seconds,a.inout,a.is_upload_finish,cons.id,a.filename,a.cid,e1.really_name
			from
			(
				select au.* from audio au
				left join employee e on e.phone_in_center=au.localphone and e.center_id=au.cid
				where e.user_id=? and au.remotephone != '' and  au.remotephone is not null %v order by au.aid desc,au.start_time desc  limit ?,?
			) a
			left join contacts cont on a.remotephone=cont.phone
			left join consumer_new cons on cont.consumer_id=cons.id
			left join employee e2 on e2.phone_in_center=a.localphone and e2.center_id=a.cid
			left join center ce on ce.cid=cons.center_id
			%v
			left join  employee e1 on e1.user_id=cons.current_tmk_id`

	params = append(params, eid)

	whereSql := ""

	if flag {
		if st != "" && et != "" {
			whereSql += " and au.start_time >= ? and au.start_time<= ?"
			params = append(params, st)
			params = append(params, et)
		}
	} else { //找不到相应的时间区间
		whereSql += " and au.start_time >= ? and au.start_time<= ?"
		params = append(params, "2000-01-01 00:00:00")
		params = append(params, "2000-01-01 00:00:01")
	}

	countSql := `select count(1) from (
			select au.* from audio au
			left join employee e on e.phone_in_center=au.localphone and e.center_id=au.cid
			where e.user_id=? and au.remotephone != '' and  au.remotephone is not null %v) num`

	lessgo.Log.Debug(fmt.Sprintf(countSql,whereSql))

	db := lessgo.GetMySQL()
	defer db.Close()

	rows, err := db.Query(fmt.Sprintf(countSql,whereSql), params...)

	if err != nil {
		lessgo.Log.Warn(err.Error())
		m["success"] = false
		m["code"] = 100
		m["msg"] = "系统发生错误，请联系IT部门"
		commonlib.OutputJson(w, m, " ")
		return
	}

	totalNum := 0

	if rows.Next() {
		err := rows.Scan(&totalNum)

		if err != nil {
			lessgo.Log.Warn(err.Error())
			m["success"] = false
			m["code"] = 100
			m["msg"] = "系统发生错误，请联系IT部门"
			commonlib.OutputJson(w, m, " ")
			return
		}
	}

	totalPage := int(math.Ceil(float64(totalNum) / float64(pageSize)))

	currPageNo := pageNo

	if currPageNo > totalPage {
		currPageNo = totalPage
	}

	lessgo.Log.Debug(fmt.Sprintf(sql,whereSql,"left join (select consumer_id,GROUP_CONCAT(concat(DATE_FORMAT(create_time,'%Y-%m-%d %H:%i'),' ',note) ORDER BY id  SEPARATOR '
') remark from consumer_contact_log group by consumer_id) b on b.consumer_id=cons.id"))

	params = append(params, (currPageNo-1)*pageSize)
	params = append(params, pageSize)

	rows, err = db.Query(fmt.Sprintf(sql,whereSql,"left join (select consumer_id,GROUP_CONCAT(concat(DATE_FORMAT(create_time,'%Y-%m-%d %H:%i'),' ',note) ORDER BY id  SEPARATOR '
') remark from consumer_contact_log group by consumer_id) b on b.consumer_id=cons.id"), params...)

	if err != nil {
		lessgo.Log.Warn(err.Error())
		m["success"] = false
		m["code"] = 100
		m["msg"] = "系统发生错误，请联系IT部门"
		commonlib.OutputJson(w, m, " ")
		return
	}

	objects := []interface{}{}

	for rows.Next() {

		model := new(lessgo.Model)

		fillObjects := []interface{}{}

		fillObjects = append(fillObjects, &model.Id)

		for i := 0; i < 13; i++ {
			prop := new(lessgo.Prop)
			prop.Name = fmt.Sprint(i)
			prop.Value = ""
			fillObjects = append(fillObjects, &prop.Value)
			model.Props = append(model.Props, prop)
		}

		err = commonlib.PutRecord(rows, fillObjects...)

		if err != nil {
			lessgo.Log.Warn(err.Error())
			m["success"] = false
			m["code"] = 100
			m["msg"] = "系统发生错误，请联系IT部门"
			commonlib.OutputJson(w, m, " ")
			return
		}

		objects = append(objects, model)
	}

	pageData := commonlib.BulidTraditionPage(currPageNo, pageSize, totalNum, objects)

	m["PageData"] = pageData
	m["DataLength"] = len(pageData.Datas) - 1
	if len(pageData.Datas) > 0 {
		m["FieldLength"] = len(pageData.Datas[0].(*lessgo.Model).Props) - 1
	}

	commonlib.RenderTemplate(w, r, "entity_page.json", m, template.FuncMap{"getPropValue": lessgo.GetPropValue, "compareInt": lessgo.CompareInt, "dealJsonString": lessgo.DealJsonString}, "../lessgo/template/entity_page.json")

}
<|endoftext|>


<commit_before>package query

import (
	"github.com/domain-query-language/dql-server/src/server/domain/vm/projection"
	"github.com/domain-query-language/dql-server/src/server/domain/vm"
	"errors"
)

type QueryHandler func(query vm.Query, queryable Queryable) Result

var (
	QUERY_HANDLER_NOT_EXISTS = errors.New("The query handler does not exist.")
)

type Handler interface {

	Handle(query Query) (result Result, err error)
}

type Handler_ struct {

	handlers map[vm.Identifier]QueryHandler
	repository_projection projection.Repository
}

func (self *Handler_) Add(id vm.Identifier, query_handler QueryHandler) {
	self.handlers[id] = query_handler
}

func (self *Handler_) Handle(query Query) (result Result, err error) {

	handler, ok := self.handlers[query.Id()]

	if !ok {
		return nil, QUERY_HANDLER_NOT_EXISTS
	}

	projection, err := self.repository_projection.Get(query.Id())

	return handler(query, projection), nil
}

func CreateHandler(repository projection.Repository) *Handler_ {

	return &Handler_ {
		handlers: map[vm.Identifier]QueryHandler{},
		repository_projection: repository,
	}
}
<commit_msg>Moving to vm.Query.<commit_after>package query

import (
	"github.com/domain-query-language/dql-server/src/server/domain/vm/projection"
	"github.com/domain-query-language/dql-server/src/server/domain/vm"
	"errors"
)

type QueryHandler func(query vm.Query, queryable Queryable) Result

var (
	QUERY_HANDLER_NOT_EXISTS = errors.New("The query handler does not exist.")
)

type Handler interface {

	Handle(query vm.Query) (result Result, err error)
}

type Handler_ struct {

	handlers map[vm.Identifier]QueryHandler
	repository_projection projection.Repository
}

func (self *Handler_) Add(id vm.Identifier, query_handler QueryHandler) {
	self.handlers[id] = query_handler
}

func (self *Handler_) Handle(query vm.Query) (result Result, err error) {

	handler, ok := self.handlers[query.Id()]

	if !ok {
		return nil, QUERY_HANDLER_NOT_EXISTS
	}

	projection, err := self.repository_projection.Get(query.Id())

	return handler(query, projection), nil
}

func CreateHandler(repository projection.Repository) *Handler_ {

	return &Handler_ {
		handlers: map[vm.Identifier]QueryHandler{},
		repository_projection: repository,
	}
}
<|endoftext|>


<commit_before>package cliutils

import (
	"bytes"
	"github.com/codegangsta/cli"
	"encoding/json"
	"os"
	"strconv"
	"strings"
	"runtime"
	"regexp"
	"github.com/jfrogdev/jfrog-cli-go/utils/cliutils/logger"
)

const CliAgent = "jfrog-cli-go"

// CLI base commands constants:
const CmdArtifactory = "rt"
const CmdBintray = "bt"
const CmdMissionControl = "mc"
const CmdXray = "xr"

// Error modes (how should the application behave when the CheckError function is invoked):
type OnError string
const (
    OnErrorPanic OnError = "panic"
    OnErrorReturnError OnError = "return"
)
var onError OnError

func init() {
	onError = OnErrorReturnError
	if os.Getenv("JFROG_CLI_ERROR_HANDLING") == string(OnErrorPanic) {
		onError = OnErrorPanic
	}
}

// Exit codes:
type ExitCode struct {
	Code int
}
var ExitCodeError ExitCode = ExitCode{1}
var ExitCodeWarning ExitCode = ExitCode{2}

func CheckError(err error) error {
    return handleError(err, ExitCodeError)
}

func CheckWarning(err error) error {
    return handleError(err, ExitCodeWarning)
}

func handleError(err error, exitCode ExitCode) error {
    if err != nil {
        if onError == OnErrorPanic {
            panic(err)
        }
        logger.Logger.Error(err.Error())
    }
    return err
}

func CheckErrorWithMessage(err error, message string) error {
	if err != nil {
		logger.Logger.Error(message)
		err = CheckError(err)
	}
	return err
}

func Exit(exitCode ExitCode, msg string) {
	if msg != "" {
		logger.Logger.Error(msg)
	}
	os.Exit(exitCode.Code)
}

func AddTrailingSlashIfNeeded(url string) string {
	if url != "" && !strings.HasSuffix(url, "/") {
		url += "/"
	}
	return url
}

func IndentJson(jsonStr []byte) string {
	var content bytes.Buffer
	err := json.Indent(&content, jsonStr, "", "  ")
	if err == nil {
		return content.String()
	}
	return string(jsonStr)
}

// Creates a string in the form of ["item-1","item-2","item-3"...] from an input
// in the form of item-1,item-1,item-1...
func BuildListString(listStr string) string {
	if listStr == "" {
		return ""
	}
	split := strings.Split(listStr, ",")
	size := len(split)
	str := "[\""
	for i := 0; i < size; i++ {
		str += split[i]
		if i + 1 < size {
			str += "\",\""
		}
	}
	str += "\"]"
	return str
}

func MapToJson(m map[string]string) string {
	first := true
	json := "{"

	for key := range m {
		val := m[key]
		if val != "" {
			if !first {
				json += ","
			}
			first = false
			if !strings.HasPrefix(val, "[") || !strings.HasSuffix(val, "]") {
				val = "\"" + val + "\""
			}
			json += "\"" + key + "\": " + val
		}
	}
	if first {
		return ""
	}
	json += "}"
	return json
}

func ConfirmAnswer(answer string) bool {
	answer = strings.ToLower(answer)
	return answer == "y" || answer == "yes"
}

func GetLogMsgPrefix(threadId int, dryRun bool) string {
	var strDryRun string
	if dryRun {
		strDryRun = " [Dry run] "
	} else {
		strDryRun = " "
	}
	return "[Thread " + strconv.Itoa(threadId) + "]" + strDryRun
}

func GetVersion() string {
	return "1.5.0-dev"
}

func GetUserHomeDir() string {
	if runtime.GOOS == "windows" {
		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return home
	}
	return os.Getenv("HOME")
}

func ReplaceTildeWithUserHome(path string) string {
	if len(path) > 1 && path[0:1] == "~" {
		return GetUserHomeDir() + path[1:len(path)]
	}
	return path
}

// Get the local root path, from which to start collecting artifacts to be uploaded to Artifactory.
func GetRootPathForUpload(path string, useRegExp bool) string {
	// The first step is to split the local path pattern into sections, by the file seperator.
	seperator := "/"
	sections := strings.Split(path, seperator)
	if len(sections) == 1 {
		seperator = "\\"
		sections = strings.Split(path, seperator)
	}

	// Now we start building the root path, making sure to leave out the sub-directory that includes the pattern.
	rootPath := ""
	for _, section := range sections {
		if section == "" {
			continue
		}
		if useRegExp {
			if strings.Index(section, "(") != -1 {
				break
			}
		} else {
			if strings.Index(section, "*") != -1 {
				break
			}
		}
		if rootPath != "" {
			rootPath += seperator
		}
		if section == "~" {
			rootPath += GetUserHomeDir()
		} else {
			rootPath += section
		}
	}
	if len(sections) > 0 && sections[0] == "" {
		rootPath = seperator + rootPath
	}
	if rootPath == "" {
		return "."
	}
	return rootPath
}

func PrepareLocalPathForUpload(localpath string, useRegExp bool) string {
	if localpath == "./" || localpath == ".\\" {
		return "^.*$"
	}
	if strings.HasPrefix(localpath, "./") {
		localpath = localpath[2:]
	} else if strings.HasPrefix(localpath, ".\\") {
		localpath = localpath[3:]
	}
	if !useRegExp {
		localpath = PathToRegExp(localpath)
	}
	return localpath
}

func TrimPath(path string) string {
	path = strings.Replace(path, "\\", "/", -1)
	path = strings.Replace(path, "//", "/", -1)
	path = strings.Replace(path, "../", "", -1)
	path = strings.Replace(path, "./", "", -1)
	return path
}

func GetBoolFlagValue(c *cli.Context, flagName string, defValue bool) bool {
	if c.IsSet(flagName) {
		return c.Bool(flagName)
	}
	return defValue
}

func GetBoolEnvValue(flagName string, defValue bool) (bool, error) {
	envVarValue := os.Getenv(flagName)
	if envVarValue == "" {
		return defValue, nil
	}
	val, err := strconv.ParseBool(envVarValue)
	err = CheckErrorWithMessage(err, "can't parse environment variable " + flagName)
    return val, err
}

func StringToBool(boolVal string, defaultValue bool) (bool, error) {
	if len(boolVal) > 0 {
		result, err := strconv.ParseBool(boolVal)
		CheckError(err)
		return result, err
	}
	return defaultValue, nil
}

func GetDocumentationMessage() string {
	return "You can read the documentation at https://github.com/jfrogdev/jfrog-cli-go/blob/master/README.md"
}

func PathToRegExp(localpath string) string {
	var wildcard = ".*"

	localpath = strings.Replace(localpath, ".", "\\.", -1)
	localpath = strings.Replace(localpath, "*", wildcard, -1)
	if strings.HasSuffix(localpath, "/") || strings.HasSuffix(localpath, "\\") {
		localpath += wildcard
	}
	localpath = "^" + localpath + "$"
	return localpath
}

// Replaces matched regular expression from sourceString to corresponding {i} at destString.
// For example:
//      regexpString = "1(.*)234" ; sourceString = "1hello234" ; destString = "{1}"
//      returns "hello"
func ReformatRegexp(regexpString, sourceString, destString string) (string, error) {
	r, err := regexp.Compile(regexpString)
	err = CheckError(err)
	if err != nil {
	    return "", err
	}

	groups := r.FindStringSubmatch(sourceString)
	size := len(groups)
	target := destString
	if size > 0 {
		for i := 1; i < size; i++ {
			group := strings.Replace(groups[i], "\\", "/", -1)
			target = strings.Replace(target, "{" + strconv.Itoa(i) + "}", group, -1)
		}
	}
	return target, nil
}

func GetTestsFileSeperator() string {
	if runtime.GOOS == "windows" {
		return "\\\\"
	}
	return "/"
}

// Remove all chars from the given string.
func StripChars(str, chr string) string {
	return strings.Map(func(r rune) rune {
		if strings.IndexRune(chr, r) < 0 {
			return r
		}
		return -1
	}, str)
}

func MergeMaps(src map[string]string, dst map[string]string) {
	for k, v := range src {
		dst[k] = v
	}
}

func Bool2Int(b bool) int {
	if b {
		return 1
	}
	return 0
}

func SumTrueValues(boolArr []bool) int {
	counter := 0
	for _, val := range boolArr {
		counter += Bool2Int(val)
	}
	return counter
}

type Credentials interface {
	SetUser(string)
	SetPassword(string)
	GetUser() string
	GetPassword() string
}

type Artifact struct {
	LocalPath  string
	TargetPath string
}

<commit_msg>Promote version to 1.5.0<commit_after>package cliutils

import (
	"bytes"
	"github.com/codegangsta/cli"
	"encoding/json"
	"os"
	"strconv"
	"strings"
	"runtime"
	"regexp"
	"github.com/jfrogdev/jfrog-cli-go/utils/cliutils/logger"
)

const CliAgent = "jfrog-cli-go"

// CLI base commands constants:
const CmdArtifactory = "rt"
const CmdBintray = "bt"
const CmdMissionControl = "mc"
const CmdXray = "xr"

// Error modes (how should the application behave when the CheckError function is invoked):
type OnError string
const (
    OnErrorPanic OnError = "panic"
    OnErrorReturnError OnError = "return"
)
var onError OnError

func init() {
	onError = OnErrorReturnError
	if os.Getenv("JFROG_CLI_ERROR_HANDLING") == string(OnErrorPanic) {
		onError = OnErrorPanic
	}
}

// Exit codes:
type ExitCode struct {
	Code int
}
var ExitCodeError ExitCode = ExitCode{1}
var ExitCodeWarning ExitCode = ExitCode{2}

func CheckError(err error) error {
    return handleError(err, ExitCodeError)
}

func CheckWarning(err error) error {
    return handleError(err, ExitCodeWarning)
}

func handleError(err error, exitCode ExitCode) error {
    if err != nil {
        if onError == OnErrorPanic {
            panic(err)
        }
        logger.Logger.Error(err.Error())
    }
    return err
}

func CheckErrorWithMessage(err error, message string) error {
	if err != nil {
		logger.Logger.Error(message)
		err = CheckError(err)
	}
	return err
}

func Exit(exitCode ExitCode, msg string) {
	if msg != "" {
		logger.Logger.Error(msg)
	}
	os.Exit(exitCode.Code)
}

func AddTrailingSlashIfNeeded(url string) string {
	if url != "" && !strings.HasSuffix(url, "/") {
		url += "/"
	}
	return url
}

func IndentJson(jsonStr []byte) string {
	var content bytes.Buffer
	err := json.Indent(&content, jsonStr, "", "  ")
	if err == nil {
		return content.String()
	}
	return string(jsonStr)
}

// Creates a string in the form of ["item-1","item-2","item-3"...] from an input
// in the form of item-1,item-1,item-1...
func BuildListString(listStr string) string {
	if listStr == "" {
		return ""
	}
	split := strings.Split(listStr, ",")
	size := len(split)
	str := "[\""
	for i := 0; i < size; i++ {
		str += split[i]
		if i + 1 < size {
			str += "\",\""
		}
	}
	str += "\"]"
	return str
}

func MapToJson(m map[string]string) string {
	first := true
	json := "{"

	for key := range m {
		val := m[key]
		if val != "" {
			if !first {
				json += ","
			}
			first = false
			if !strings.HasPrefix(val, "[") || !strings.HasSuffix(val, "]") {
				val = "\"" + val + "\""
			}
			json += "\"" + key + "\": " + val
		}
	}
	if first {
		return ""
	}
	json += "}"
	return json
}

func ConfirmAnswer(answer string) bool {
	answer = strings.ToLower(answer)
	return answer == "y" || answer == "yes"
}

func GetLogMsgPrefix(threadId int, dryRun bool) string {
	var strDryRun string
	if dryRun {
		strDryRun = " [Dry run] "
	} else {
		strDryRun = " "
	}
	return "[Thread " + strconv.Itoa(threadId) + "]" + strDryRun
}

func GetVersion() string {
	return "1.5.0"
}

func GetUserHomeDir() string {
	if runtime.GOOS == "windows" {
		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return home
	}
	return os.Getenv("HOME")
}

func ReplaceTildeWithUserHome(path string) string {
	if len(path) > 1 && path[0:1] == "~" {
		return GetUserHomeDir() + path[1:len(path)]
	}
	return path
}

// Get the local root path, from which to start collecting artifacts to be uploaded to Artifactory.
func GetRootPathForUpload(path string, useRegExp bool) string {
	// The first step is to split the local path pattern into sections, by the file seperator.
	seperator := "/"
	sections := strings.Split(path, seperator)
	if len(sections) == 1 {
		seperator = "\\"
		sections = strings.Split(path, seperator)
	}

	// Now we start building the root path, making sure to leave out the sub-directory that includes the pattern.
	rootPath := ""
	for _, section := range sections {
		if section == "" {
			continue
		}
		if useRegExp {
			if strings.Index(section, "(") != -1 {
				break
			}
		} else {
			if strings.Index(section, "*") != -1 {
				break
			}
		}
		if rootPath != "" {
			rootPath += seperator
		}
		if section == "~" {
			rootPath += GetUserHomeDir()
		} else {
			rootPath += section
		}
	}
	if len(sections) > 0 && sections[0] == "" {
		rootPath = seperator + rootPath
	}
	if rootPath == "" {
		return "."
	}
	return rootPath
}

func PrepareLocalPathForUpload(localpath string, useRegExp bool) string {
	if localpath == "./" || localpath == ".\\" {
		return "^.*$"
	}
	if strings.HasPrefix(localpath, "./") {
		localpath = localpath[2:]
	} else if strings.HasPrefix(localpath, ".\\") {
		localpath = localpath[3:]
	}
	if !useRegExp {
		localpath = PathToRegExp(localpath)
	}
	return localpath
}

func TrimPath(path string) string {
	path = strings.Replace(path, "\\", "/", -1)
	path = strings.Replace(path, "//", "/", -1)
	path = strings.Replace(path, "../", "", -1)
	path = strings.Replace(path, "./", "", -1)
	return path
}

func GetBoolFlagValue(c *cli.Context, flagName string, defValue bool) bool {
	if c.IsSet(flagName) {
		return c.Bool(flagName)
	}
	return defValue
}

func GetBoolEnvValue(flagName string, defValue bool) (bool, error) {
	envVarValue := os.Getenv(flagName)
	if envVarValue == "" {
		return defValue, nil
	}
	val, err := strconv.ParseBool(envVarValue)
	err = CheckErrorWithMessage(err, "can't parse environment variable " + flagName)
    return val, err
}

func StringToBool(boolVal string, defaultValue bool) (bool, error) {
	if len(boolVal) > 0 {
		result, err := strconv.ParseBool(boolVal)
		CheckError(err)
		return result, err
	}
	return defaultValue, nil
}

func GetDocumentationMessage() string {
	return "You can read the documentation at https://github.com/jfrogdev/jfrog-cli-go/blob/master/README.md"
}

func PathToRegExp(localpath string) string {
	var wildcard = ".*"

	localpath = strings.Replace(localpath, ".", "\\.", -1)
	localpath = strings.Replace(localpath, "*", wildcard, -1)
	if strings.HasSuffix(localpath, "/") || strings.HasSuffix(localpath, "\\") {
		localpath += wildcard
	}
	localpath = "^" + localpath + "$"
	return localpath
}

// Replaces matched regular expression from sourceString to corresponding {i} at destString.
// For example:
//      regexpString = "1(.*)234" ; sourceString = "1hello234" ; destString = "{1}"
//      returns "hello"
func ReformatRegexp(regexpString, sourceString, destString string) (string, error) {
	r, err := regexp.Compile(regexpString)
	err = CheckError(err)
	if err != nil {
	    return "", err
	}

	groups := r.FindStringSubmatch(sourceString)
	size := len(groups)
	target := destString
	if size > 0 {
		for i := 1; i < size; i++ {
			group := strings.Replace(groups[i], "\\", "/", -1)
			target = strings.Replace(target, "{" + strconv.Itoa(i) + "}", group, -1)
		}
	}
	return target, nil
}

func GetTestsFileSeperator() string {
	if runtime.GOOS == "windows" {
		return "\\\\"
	}
	return "/"
}

// Remove all chars from the given string.
func StripChars(str, chr string) string {
	return strings.Map(func(r rune) rune {
		if strings.IndexRune(chr, r) < 0 {
			return r
		}
		return -1
	}, str)
}

func MergeMaps(src map[string]string, dst map[string]string) {
	for k, v := range src {
		dst[k] = v
	}
}

func Bool2Int(b bool) int {
	if b {
		return 1
	}
	return 0
}

func SumTrueValues(boolArr []bool) int {
	counter := 0
	for _, val := range boolArr {
		counter += Bool2Int(val)
	}
	return counter
}

type Credentials interface {
	SetUser(string)
	SetPassword(string)
	GetUser() string
	GetPassword() string
}

type Artifact struct {
	LocalPath  string
	TargetPath string
}

<|endoftext|>


<commit_before>// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package msg

import (
	"net"
	"path"
	"strings"

	"github.com/miekg/dns"
)

// This *is* the rdata from a SRV record, but with a twist.
// Host (Target in SRV) must be a domain name, but if it looks like an IP
// address (4/6), we will treat it like an IP address.
type Service struct {
	Host     string `json:"host,omitempty"`
	Port     int    `json:"port,omitempty"`
	Priority int    `json:"priority,omitempty"`
	Weight   int    `json:"weight,omitempty"`
	Ttl      uint32 `json:"ttl,omitempty"`

	Key string // etcd key where we found this service
}

// NewSRV returns a new SRV record based on the Service.
func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
	return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.Ttl},
		Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: dns.Fqdn(s.Host)}
}

// NewA returns a new A record based on the Service.
func (s *Service) NewA(name string, ip net.IP) *dns.A {
	return &dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.Ttl}, A: ip}
}

// NewAAAA returns a new AAAA record based on the Service.
func (s *Service) NewAAAA(name string, ip net.IP) *dns.AAAA {
	return &dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.Ttl}, AAAA: ip}
}

// NewCNAME returns a new CNAME record based on the Service.
func (s *Service) NewCNAME(name string, target string) *dns.CNAME {
	return &dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: s.Ttl}, Target: target}
}

// NewNS returns a new NS record based on the Service.
func (s *Service) NewNS(name string, target string) *dns.NS {
	return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.Ttl}, Ns: target}
}

// NewPTR returns a new PTR record based on the Service.
func (s *Service) NewPTR(name string, ttl uint32) *dns.PTR {
	return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: ttl}, Ptr: dns.Fqdn(s.Host)}
}

// As Path, but
// if a name contains wildcards (*), the name will be chopped of before the (first) wildcard, and
// we do a highler evel search and later find the matching names in loopNodes.
// So service.*.skydns.local, will look for all servics under skydns.local and will later check
// for names that match service.*.skydns.local.  If a wildcard is found the bool is true.
func PathWithWildcard(s string) (string, bool) {
	l := dns.SplitDomainName(s)
	for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
		l[i], l[j] = l[j], l[i]
	}
	for i, k := range l {
		if k == "*" {
			return path.Join(append([]string{"/skydns/"}, l[:i]...)...), true
		}
	}
	return path.Join(append([]string{"/skydns/"}, l...)...), false
}

// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local.,
// the resulting key will be /skydns/local/skydns/staging/service .
func Path(s string) string {
	l := dns.SplitDomainName(s)
	for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
		l[i], l[j] = l[j], l[i]
	}
	return path.Join(append([]string{"/skydns/"}, l...)...)
}

// Domain is the opposite of Path.
func Domain(s string) string {
	l := strings.Split(s, "/")
	// start with 1, to strip /skydns
	for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 {
		l[i], l[j] = l[j], l[i]
	}
	return dns.Fqdn(strings.Join(l[1:len(l)-1], "."))
}
<commit_msg>Key attribute should be omitted<commit_after>// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package msg

import (
	"net"
	"path"
	"strings"

	"github.com/miekg/dns"
)

// This *is* the rdata from a SRV record, but with a twist.
// Host (Target in SRV) must be a domain name, but if it looks like an IP
// address (4/6), we will treat it like an IP address.
type Service struct {
	Host     string `json:"host,omitempty"`
	Port     int    `json:"port,omitempty"`
	Priority int    `json:"priority,omitempty"`
	Weight   int    `json:"weight,omitempty"`
	Ttl      uint32 `json:"ttl,omitempty"`
	// etcd key where we found this service and ignore from json un-/marshalling
	Key 	 string `json:"-"`
}

// NewSRV returns a new SRV record based on the Service.
func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
	return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.Ttl},
		Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: dns.Fqdn(s.Host)}
}

// NewA returns a new A record based on the Service.
func (s *Service) NewA(name string, ip net.IP) *dns.A {
	return &dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.Ttl}, A: ip}
}

// NewAAAA returns a new AAAA record based on the Service.
func (s *Service) NewAAAA(name string, ip net.IP) *dns.AAAA {
	return &dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.Ttl}, AAAA: ip}
}

// NewCNAME returns a new CNAME record based on the Service.
func (s *Service) NewCNAME(name string, target string) *dns.CNAME {
	return &dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: s.Ttl}, Target: target}
}

// NewNS returns a new NS record based on the Service.
func (s *Service) NewNS(name string, target string) *dns.NS {
	return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.Ttl}, Ns: target}
}

// NewPTR returns a new PTR record based on the Service.
func (s *Service) NewPTR(name string, ttl uint32) *dns.PTR {
	return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: ttl}, Ptr: dns.Fqdn(s.Host)}
}

// As Path, but
// if a name contains wildcards (*), the name will be chopped of before the (first) wildcard, and
// we do a highler evel search and later find the matching names in loopNodes.
// So service.*.skydns.local, will look for all servics under skydns.local and will later check
// for names that match service.*.skydns.local.  If a wildcard is found the bool is true.
func PathWithWildcard(s string) (string, bool) {
	l := dns.SplitDomainName(s)
	for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
		l[i], l[j] = l[j], l[i]
	}
	for i, k := range l {
		if k == "*" {
			return path.Join(append([]string{"/skydns/"}, l[:i]...)...), true
		}
	}
	return path.Join(append([]string{"/skydns/"}, l...)...), false
}

// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local.,
// the resulting key will be /skydns/local/skydns/staging/service .
func Path(s string) string {
	l := dns.SplitDomainName(s)
	for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
		l[i], l[j] = l[j], l[i]
	}
	return path.Join(append([]string{"/skydns/"}, l...)...)
}

// Domain is the opposite of Path.
func Domain(s string) string {
	l := strings.Split(s, "/")
	// start with 1, to strip /skydns
	for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 {
		l[i], l[j] = l[j], l[i]
	}
	return dns.Fqdn(strings.Join(l[1:len(l)-1], "."))
}
<|endoftext|>


<commit_before>package qingcloud

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

func modifyRouterAttributes(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.ModifyRouterAttributesInput)
	input.Router = qc.String(d.Id())
	attributeUpdate := false
	if d.HasChange("name") && !d.IsNewResource() {
		if d.Get("name") != "" {
			input.RouterName = qc.String(d.Get("name").(string))
		} else {
			input.RouterName = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("description") {
		if d.Get("description") != "" {
			input.Description = qc.String(d.Get("description").(string))
		} else {
			input.Description = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("eip_id") {
		if d.Get("eip_id") != "" {
			input.EIP = qc.String(d.Get("eip_id").(string))
		} else {
			input.EIP = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("security_group_id") && !d.IsNewResource() {
		if d.Get("security_group_id") != "" {
			input.SecurityGroup = qc.String(d.Get("security_group_id").(string))
		} else {
			input.SecurityGroup = qc.String(" ")
		}
		attributeUpdate = true
	}

	if attributeUpdate {
		var output *qc.ModifyRouterAttributesOutput
		var err error
		simpleRetry(func() error {
			output, err = clt.ModifyRouterAttributes(input)
			if err == nil {
				if output.RetCode != nil && IsServerBusy(*output.RetCode) {
					return fmt.Errorf("allocate EIP Server Busy")
				}
			}
			return nil
		})
		if err != nil {
			return fmt.Errorf("Error modify router attributes: %s", err)
		}
		if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
			return fmt.Errorf("Error modify router attrubites: %s", *output.Message)
		}
		return nil
	}
	return nil
}

func applyRouterUpdate(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.UpdateRoutersInput)
	input.Routers = []*string{qc.String(d.Id())}
	var output *qc.UpdateRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.UpdateRouters(input)
		if err == nil {
			if output.RetCode != nil && IsServerBusy(*output.RetCode) {
				return fmt.Errorf("allocate EIP Server Busy")
			}
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Error update router: %s", err.Error())
	}
	if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
		return fmt.Errorf("Error update router: %s", *output.Message)
	}
	_, err = RouterTransitionStateRefresh(clt, d.Id())
	if err != nil {
		return fmt.Errorf("Error waiting for router (%s) to start: %s", d.Id(), err.Error())
	}

	return nil
}

func waitRouterLease(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.DescribeRoutersInput)
	input.Routers = []*string{qc.String(d.Id())}
	input.Verbose = qc.Int(1)
	var output *qc.DescribeRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.DescribeRouters(input)
		if err == nil {
			if output.RetCode != nil && IsServerBusy(*output.RetCode) {
				return fmt.Errorf("allocate EIP Server Busy")
			}
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Error describe router: %s", err)
	}
	if *output.RetCode != 0 {
		return fmt.Errorf("Error describe router: %s", *output.Message)
	}
	//wait for lease info
	WaitForLease(output.RouterSet[0].CreateTime)
	return nil
}

<commit_msg>reformat code<commit_after>package qingcloud

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

func modifyRouterAttributes(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.ModifyRouterAttributesInput)
	input.Router = qc.String(d.Id())
	attributeUpdate := false
	if d.HasChange("name") && !d.IsNewResource() {
		if d.Get("name") != "" {
			input.RouterName = qc.String(d.Get("name").(string))
		} else {
			input.RouterName = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("description") {
		if d.Get("description") != "" {
			input.Description = qc.String(d.Get("description").(string))
		} else {
			input.Description = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("eip_id") {
		if d.Get("eip_id") != "" {
			input.EIP = qc.String(d.Get("eip_id").(string))
		} else {
			input.EIP = qc.String(" ")
		}
		attributeUpdate = true
	}
	if d.HasChange("security_group_id") && !d.IsNewResource() {
		if d.Get("security_group_id") != "" {
			input.SecurityGroup = qc.String(d.Get("security_group_id").(string))
		} else {
			input.SecurityGroup = qc.String(" ")
		}
		attributeUpdate = true
	}

	if attributeUpdate {
		var output *qc.ModifyRouterAttributesOutput
		var err error
		simpleRetry(func() error {
			output, err = clt.ModifyRouterAttributes(input)
			if err == nil {
				if output.RetCode != nil && IsServerBusy(*output.RetCode) {
					return fmt.Errorf("allocate EIP Server Busy")
				}
			}
			return nil
		})
		if err != nil {
			return fmt.Errorf("Error modify router attributes: %s", err)
		}
		if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
			return fmt.Errorf("Error modify router attrubites: %s", *output.Message)
		}
		return nil
	}
	return nil
}

func applyRouterUpdate(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.UpdateRoutersInput)
	input.Routers = []*string{qc.String(d.Id())}
	var output *qc.UpdateRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.UpdateRouters(input)
		if err == nil {
			if output.RetCode != nil && IsServerBusy(*output.RetCode) {
				return fmt.Errorf("allocate EIP Server Busy")
			}
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Error update router: %s", err.Error())
	}
	if output.RetCode != nil && qc.IntValue(output.RetCode) != 0 {
		return fmt.Errorf("Error update router: %s", *output.Message)
	}
	_, err = RouterTransitionStateRefresh(clt, d.Id())
	if err != nil {
		return fmt.Errorf("Error waiting for router (%s) to start: %s", d.Id(), err.Error())
	}

	return nil
}

func waitRouterLease(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.DescribeRoutersInput)
	input.Routers = []*string{qc.String(d.Id())}
	input.Verbose = qc.Int(1)
	var output *qc.DescribeRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.DescribeRouters(input)
		if err == nil {
			if output.RetCode != nil && IsServerBusy(*output.RetCode) {
				return fmt.Errorf("allocate EIP Server Busy")
			}
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Error describe router: %s", err)
	}
	if *output.RetCode != 0 {
		return fmt.Errorf("Error describe router: %s", *output.Message)
	}
	//wait for lease info
	WaitForLease(output.RouterSet[0].CreateTime)
	return nil
}
<|endoftext|>


<commit_before>package testStrategies

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/xtracdev/automated-perf-test/perfTestUtils"
	"sync"
	"sync/atomic"
	"time"
)

//----- ExecuteTestSuiteWrapper ----------------------------------------------
func ExecuteTestSuiteWrapper(
			testSuite *TestSuite,
			configurationSettings *perfTestUtils.Config,
			startTime time.Time,
) map[string][]int64 {
	allServicesResponseTimesMap := make(map[string][]int64, 0)
	testSuiteResponseTimesChan := make(chan []map[string]int64, 1)
	var suiteWaitGroup sync.WaitGroup

	// Variables to track total current TPS across all threads.
	// We'll use an unsigned integer to represent our (always-positive) counter,
	// and use a wait group from the sync package to track a concurrent counter.
	var curOps uint64 = 0
	quitShowTPSChan := make(chan bool)

	suiteWaitGroup.Add(configurationSettings.ConcurrentUsers)
	for i := 0; i < configurationSettings.ConcurrentUsers; i++ {
		go executeTestSuite(testSuiteResponseTimesChan, testSuite, configurationSettings, i, GlobalsLockCounter, &curOps)
		go aggregateSuiteResponseTimes(testSuiteResponseTimesChan, allServicesResponseTimesMap, &suiteWaitGroup)
	}

	// Display the ongoing TPS to log.Info based on period specified in configurationSettings.TPSFreq:
	go showCurrentTPS(quitShowTPSChan, &curOps, startTime, configurationSettings)

	suiteWaitGroup.Wait()
	quitShowTPSChan <- true

	return allServicesResponseTimesMap
}

//----- executeTestSuite ------------------------------------------------------
func executeTestSuite(
			testSuiteResponseTimesChan chan []map[string]int64,
			testSuite *TestSuite,
			configurationSettings *perfTestUtils.Config,
			userId int,
			globalsMap GlobalsMaps,
			curOps *uint64,
) {
	log.Info("Test Suite started")

	allSuiteResponseTimes := make([]map[string]int64, 0)
	uniqueTestRunId := ""
	for i := 0; i < configurationSettings.NumIterations; i++ {
		// Run all services of the test suite NumIterations of times.
		uniqueTestRunId = fmt.Sprintf("User%dIter%d", userId, i)
		testSuiteResponseTimes := make(map[string]int64)

		for _, testDefinition := range testSuite.TestCases {
			log.Info("Test case: [", testDefinition.TestName, "] UniqueRunID: [", uniqueTestRunId, "]")

			targetHost, targetPort := determineHostandPortforRequest(testDefinition, configurationSettings)
			responseTime := testDefinition.BuildAndSendRequest(configurationSettings.RequestDelay, targetHost, targetPort, uniqueTestRunId, globalsMap)
			testSuiteResponseTimes[testDefinition.TestName] = responseTime

			// Increment the global ops counter
			atomic.AddUint64( curOps, 1 )
		}

		allSuiteResponseTimes = append(allSuiteResponseTimes, testSuiteResponseTimes)

		globalsMap.Lock()
		globalsMap.m[uniqueTestRunId] = nil
		globalsMap.Unlock()
	}
	testSuiteResponseTimesChan <- allSuiteResponseTimes
	log.Infof("Test Suite [%s::%s] Finished", testSuite.Name, uniqueTestRunId)
}

//----- aggregateSuiteResponseTimes -------------------------------------------
func aggregateSuiteResponseTimes(
		testSuiteResponseTimesChan chan []map[string]int64,
		allServicesResponseTimesMap map[string][]int64,
		suiteWaitGroup *sync.WaitGroup,
) {
	perUserSuiteResponseTimes := <-testSuiteResponseTimesChan
	for _, singleSuiteRunResponseTimes := range perUserSuiteResponseTimes {
		for serviceName, serviceResponseTime := range singleSuiteRunResponseTimes {
			if allServicesResponseTimesMap[serviceName] == nil {
				serviceResponseSlice := make([]int64, 0)
				allServicesResponseTimesMap[serviceName] = serviceResponseSlice
			}
			allServicesResponseTimesMap[serviceName] = append(allServicesResponseTimesMap[serviceName], serviceResponseTime)
		}
	}
	suiteWaitGroup.Done()
}

//----- showCurrentTPS -------------------------------------------------------------------------------------------------
// Print current TPS progress every period of time defined by configurationSettings.TPSFREQ.
func showCurrentTPS( chQuit chan bool, curOps *uint64, startTime time.Time, configurationSettings *perfTestUtils.Config ) {
	for {
		// Concurrent controls:
		select {
		case <-chQuit:
			return
		default:
			// We only want one output line during any given second.
			// This effectively sets the lower bound for TPSFreq.
			time.Sleep(time.Second)

			// No need to display until at least one operation has completed.
			if (*curOps < uint64(1)) {
				break
			}

			elapsedTime := time.Since(startTime)
			// No need to display if not within the period set in config:
			if (int64(elapsedTime.Seconds()) % int64(configurationSettings.TPSFreq) != 0) {
				break
			}

			// Print the display.
			num_ops := atomic.LoadUint64(curOps)
			tps := 0.0
			if (int(elapsedTime.Seconds()) > 0) {
				tps = (float64(num_ops) / elapsedTime.Seconds())
			}
			log.Infof("[showCurrentTPS] {\"curOps\":\"%d\",\"elapsedTime\":\"%f\",\"TPS\":\"%f\"}",
				num_ops,
				elapsedTime.Seconds(),
				tps,
			)
		}
	}
}
<commit_msg>Fixed indent mistake.<commit_after>package testStrategies

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/xtracdev/automated-perf-test/perfTestUtils"
	"sync"
	"sync/atomic"
	"time"
)

//----- ExecuteTestSuiteWrapper ----------------------------------------------
func ExecuteTestSuiteWrapper(
		testSuite *TestSuite,
		configurationSettings *perfTestUtils.Config,
		startTime time.Time,
) map[string][]int64 {
	allServicesResponseTimesMap := make(map[string][]int64, 0)
	testSuiteResponseTimesChan := make(chan []map[string]int64, 1)
	var suiteWaitGroup sync.WaitGroup

	// Variables to track total current TPS across all threads.
	// We'll use an unsigned integer to represent our (always-positive) counter,
	// and use a wait group from the sync package to track a concurrent counter.
	var curOps uint64 = 0
	quitShowTPSChan := make(chan bool)

	suiteWaitGroup.Add(configurationSettings.ConcurrentUsers)
	for i := 0; i < configurationSettings.ConcurrentUsers; i++ {
		go executeTestSuite(testSuiteResponseTimesChan, testSuite, configurationSettings, i, GlobalsLockCounter, &curOps)
		go aggregateSuiteResponseTimes(testSuiteResponseTimesChan, allServicesResponseTimesMap, &suiteWaitGroup)
	}

	// Display the ongoing TPS to log.Info based on period specified in configurationSettings.TPSFreq:
	go showCurrentTPS(quitShowTPSChan, &curOps, startTime, configurationSettings)

	suiteWaitGroup.Wait()
	quitShowTPSChan <- true

	return allServicesResponseTimesMap
}

//----- executeTestSuite ------------------------------------------------------
func executeTestSuite(
		testSuiteResponseTimesChan chan []map[string]int64,
		testSuite *TestSuite,
		configurationSettings *perfTestUtils.Config,
		userId int,
		globalsMap GlobalsMaps,
		curOps *uint64,
) {
	log.Info("Test Suite started")

	allSuiteResponseTimes := make([]map[string]int64, 0)
	uniqueTestRunId := ""
	for i := 0; i < configurationSettings.NumIterations; i++ {
		// Run all services of the test suite NumIterations of times.
		uniqueTestRunId = fmt.Sprintf("User%dIter%d", userId, i)
		testSuiteResponseTimes := make(map[string]int64)

		for _, testDefinition := range testSuite.TestCases {
			log.Info("Test case: [", testDefinition.TestName, "] UniqueRunID: [", uniqueTestRunId, "]")

			targetHost, targetPort := determineHostandPortforRequest(testDefinition, configurationSettings)
			responseTime := testDefinition.BuildAndSendRequest(configurationSettings.RequestDelay, targetHost, targetPort, uniqueTestRunId, globalsMap)
			testSuiteResponseTimes[testDefinition.TestName] = responseTime

			// Increment the global ops counter
			atomic.AddUint64( curOps, 1 )
		}

		allSuiteResponseTimes = append(allSuiteResponseTimes, testSuiteResponseTimes)

		globalsMap.Lock()
		globalsMap.m[uniqueTestRunId] = nil
		globalsMap.Unlock()
	}
	testSuiteResponseTimesChan <- allSuiteResponseTimes
	log.Infof("Test Suite [%s::%s] Finished", testSuite.Name, uniqueTestRunId)
}

//----- aggregateSuiteResponseTimes -------------------------------------------
func aggregateSuiteResponseTimes(
		testSuiteResponseTimesChan chan []map[string]int64,
		allServicesResponseTimesMap map[string][]int64,
		suiteWaitGroup *sync.WaitGroup,
) {
	perUserSuiteResponseTimes := <-testSuiteResponseTimesChan
	for _, singleSuiteRunResponseTimes := range perUserSuiteResponseTimes {
		for serviceName, serviceResponseTime := range singleSuiteRunResponseTimes {
			if allServicesResponseTimesMap[serviceName] == nil {
				serviceResponseSlice := make([]int64, 0)
				allServicesResponseTimesMap[serviceName] = serviceResponseSlice
			}
			allServicesResponseTimesMap[serviceName] = append(allServicesResponseTimesMap[serviceName], serviceResponseTime)
		}
	}
	suiteWaitGroup.Done()
}

//----- showCurrentTPS -------------------------------------------------------------------------------------------------
// Print current TPS progress every period of time defined by configurationSettings.TPSFREQ.
func showCurrentTPS( chQuit chan bool, curOps *uint64, startTime time.Time, configurationSettings *perfTestUtils.Config ) {
	for {
		// Concurrent controls:
		select {
		case <-chQuit:
			return
		default:
			// We only want one output line during any given second.
			// This effectively sets the lower bound for TPSFreq.
			time.Sleep(time.Second)

			// No need to display until at least one operation has completed.
			if (*curOps < uint64(1)) {
				break
			}

			elapsedTime := time.Since(startTime)
			// No need to display if not within the period set in config:
			if (int64(elapsedTime.Seconds()) % int64(configurationSettings.TPSFreq) != 0) {
				break
			}

			// Print the display.
			num_ops := atomic.LoadUint64(curOps)
			tps := 0.0
			if (int(elapsedTime.Seconds()) > 0) {
				tps = (float64(num_ops) / elapsedTime.Seconds())
			}
			log.Infof("[showCurrentTPS] {\"curOps\":\"%d\",\"elapsedTime\":\"%f\",\"TPS\":\"%f\"}",
				num_ops,
				elapsedTime.Seconds(),
				tps,
			)
		}
	}
}
<|endoftext|>